feat(career): migrate overview and factual evidence

This commit is contained in:
cesnimda
2026-10-12 07:50:32 +02:00
parent 01281f52d9
commit 8b4d5c2112
16 changed files with 9006 additions and 116 deletions
+22 -4
View File
@@ -150,7 +150,7 @@ export default function CareerProfilePage() {
const cvInputRef = useRef<HTMLInputElement | null>(null);
const avatarInputRef = useRef<HTMLInputElement | null>(null);
const [me, setMe] = useState<MeResponse | null>(null);
const [loading, setLoading] = useState(false);
const [loading, setLoading] = useState(true);
const [loadError, setLoadError] = useState<string | null>(null);
const [uploadingCv, setUploadingCv] = useState(false);
const [improvingCv, setImprovingCv] = useState(false);
@@ -170,9 +170,11 @@ export default function CareerProfilePage() {
// The raw import/section parser remains available as an advanced recovery tool.
const [showAdvancedCvTools, setShowAdvancedCvTools] = useState(false);
const [workspaceSection, setWorkspaceSection] = useState<CareerWorkspaceSection>(initialWorkspaceSection);
const [evidenceVisited, setEvidenceVisited] = useState(() => initialWorkspaceSection() === "evidence");
const navigateWorkspace = useCallback((next: CareerWorkspaceSection) => {
setWorkspaceSection(next);
if (next === "evidence") setEvidenceVisited(true);
if (typeof window === "undefined") return;
const url = new URL(window.location.href);
if (next === "overview") url.searchParams.delete("section");
@@ -205,6 +207,9 @@ export default function CareerProfilePage() {
}
}, [loadVersions, t, toast]);
const [extractionRuns, setExtractionRuns] = useState<ExtractionRun[]>([]);
const [runsLoading, setRunsLoading] = useState(true);
const [runsLoadError, setRunsLoadError] = useState<string | null>(null);
const runsReadId = useRef(0);
const [runDiffs, setRunDiffs] = useState<Record<number, CvImportDiff>>({});
const [reviewingRunId, setReviewingRunId] = useState<number | null>(null);
const [acceptedLowConfidenceIds, setAcceptedLowConfidenceIds] = useState<Record<number, string[]>>({});
@@ -216,11 +221,19 @@ export default function CareerProfilePage() {
}, []);
const loadExtractionRuns = useCallback(async () => {
const readId = ++runsReadId.current;
setRunsLoading(true);
try {
const response = await api.get<ExtractionRun[]>("/profile-cv/runs");
setExtractionRuns(response.data ?? []);
} catch {
if (readId === runsReadId.current) {
setExtractionRuns(response.data ?? []);
setRunsLoadError(null);
}
} catch (error) {
// Polling failure must not clear existing run state or touch unsaved profile edits.
if (readId === runsReadId.current) setRunsLoadError(String(error));
} finally {
if (readId === runsReadId.current) setRunsLoading(false);
}
}, []);
@@ -367,11 +380,16 @@ export default function CareerProfilePage() {
runs={extractionRuns}
loading={loading}
loadError={loadError}
runsLoading={runsLoading}
runsLoadError={runsLoadError}
onRetryRuns={() => void loadExtractionRuns()}
onRetryProfile={() => { if (!profileDirty) void loadProfile(); }}
profileDirty={profileDirty}
onNavigate={navigateWorkspace}
/>
) : null}
{workspaceSection === "evidence" ? <CareerEvidenceBank /> : null}
{evidenceVisited ? <Box hidden={workspaceSection !== "evidence"}><CareerEvidenceBank /></Box> : null}
{workspaceSection === "profile" || workspaceSection === "import" ? <Paper id={workspaceSection === "profile" ? "career-profile-editor" : "career-cv-import"} sx={{ mt: 0, p: { xs: 1.5, sm: 2.5 }, borderRadius: 4, border: "none", boxShadow: "0px 1px 2px 0px rgba(15,23,42,0.04), 0px 8px 24px -12px rgba(15,23,42,0.12)", scrollMarginTop: 96 }}>
<input