import React, { useEffect, useMemo, useState } from "react";
import { Alert, Box, Button, Chip, LinearProgress, Paper, Skeleton, Stack, Typography } from "@mui/material";
import DescriptionOutlinedIcon from "@mui/icons-material/DescriptionOutlined";
import PersonOutlineIcon from "@mui/icons-material/PersonOutline";
import UploadFileOutlinedIcon from "@mui/icons-material/UploadFileOutlined";
import WorkOutlineIcon from "@mui/icons-material/WorkOutline";
import { CvVariantSummary, cvBuilderApi } from "../../cvBuilder";
import type { UserOperation } from "../../types";
import { useI18n } from "../../i18n/I18nProvider";
import { localizeCompletenessLabel } from "./careerCompletenessLabels";
export type CareerWorkspaceCompleteness = {
percent: number;
missing: string[];
};
export type CareerWorkspaceImportRun = {
id: number;
status: string;
errorMessage?: string;
operation?: UserOperation | null;
};
const activeStatuses = new Set(["queued", "running", "waiting_for_retry", "waiting_for_external_fallback"]);
function isActive(run: CareerWorkspaceImportRun) {
return run.operation
? activeStatuses.has(run.operation.status)
: run.status === "queued" || run.status === "running";
}
function ActionCard({ title, body, href, label, icon, onNavigate }: {
title: string;
body: string;
href: string;
label: string;
icon: React.ReactNode;
onNavigate?: () => void;
}) {
return (
{icon}
{title}
{body}
);
}
export default function CareerWorkspaceOverview({ completeness, runs, loading, loadError, onNavigate }: {
completeness: CareerWorkspaceCompleteness | null;
runs: CareerWorkspaceImportRun[];
loading: boolean;
loadError: string | null;
onNavigate?: (section: "profile" | "import") => void;
}) {
const { language, t } = useI18n();
const [recentCvs, setRecentCvs] = useState([]);
const [recentLoading, setRecentLoading] = useState(true);
const [recentError, setRecentError] = useState(false);
useEffect(() => {
let cancelled = false;
cvBuilderApi.list()
.then((items) => {
if (!cancelled) {
setRecentCvs(Array.isArray(items)
? [...items].sort((left, right) => Date.parse(right.updatedAtUtc) - Date.parse(left.updatedAtUtc)).slice(0, 3)
: []);
setRecentError(false);
}
})
.catch(() => {
if (!cancelled) setRecentError(true);
})
.finally(() => {
if (!cancelled) setRecentLoading(false);
});
return () => { cancelled = true; };
}, []);
const importState = useMemo(() => {
const review = runs.filter((run) => run.status === "pending_review");
const active = runs.filter(isActive);
const failed = runs.filter((run) => run.status === "failed" || run.operation?.status === "failed");
if (review.length > 0) return { severity: "warning" as const, label: t("careerOverviewReviewImport"), message: t(review.length === 1 ? "careerOverviewReviewOne" : "careerOverviewReviewMany", { count: review.length }) };
if (active.length > 0) return { severity: "info" as const, label: t("careerOverviewViewProcessing"), message: t(active.length === 1 ? "careerOverviewProcessingOne" : "careerOverviewProcessingMany", { count: active.length }) };
if (failed.length > 0) return { severity: "error" as const, label: t("careerOverviewResolveImport"), message: t(failed.length === 1 ? "careerOverviewFailedOne" : "careerOverviewFailedMany", { count: failed.length }) };
return { severity: "success" as const, label: t("careerOverviewImportCv"), message: t(runs.length > 0 ? "careerOverviewImportComplete" : "careerOverviewNoImport") };
}, [runs, t]);
const isFirstRun = !loading && !recentLoading && !loadError && (completeness?.percent ?? 0) === 0 && runs.length === 0 && recentCvs.length === 0;
return (
{t("careerWorkspaceOverviewTab")}
{t("careerOverviewSubtitle")}
} href="/career/builder">{t("careerOverviewOpenBuilder")}
{isFirstRun ? {t("careerOverviewFirstRun")} : null}
{loadError ? {t("careerOverviewUnavailable")} : null}
{t("careerOverviewCompleteness")}
{loading ? : {completeness?.percent ?? 0}%}
{!loading && completeness?.missing.length ? (
{t("careerOverviewAddNext", { items: completeness.missing.slice(0, 3).map((label) => localizeCompletenessLabel(label, t)).join(", ") })}
) : null}
{t("careerOverviewCvImport")}
{importState.message}
onNavigate("profile") : undefined} label={t("careerOverviewEditProfile")} icon={} />
onNavigate("import") : undefined} label={importState.label} icon={} />
} />
} />
{t("careerOverviewRecentCvs")}
{recentLoading ? (
) : recentError ? (
{t("careerOverviewRecentFailed")}
) : recentCvs.length === 0 ? (
{t("careerOverviewNoCvs")}
) : (
{recentCvs.map((cv) => (
{cv.name}
{t("careerOverviewUpdated", { date: new Date(cv.updatedAtUtc).toLocaleDateString(language === "nb" ? "nb-NO" : "en-GB") })}
{cv.jobApplicationId ? : null}
))}
)}
);
}