fix(rd21): expose committed revisions and refresh answer sources

This commit is contained in:
cesnimda
2026-10-23 12:51:36 +02:00
parent 05a738693e
commit 1b89a779d0
4 changed files with 141 additions and 6 deletions
@@ -78,6 +78,9 @@ export function ApplicationWorkspace({
const [overlaySubsection, setOverlaySubsection] = useState<{ section: WorkspaceSectionKey; value: string } | null>(null);
const subsection = onSectionChange && overlaySubsection?.section === section
? overlaySubsection.value : workspaceSubsection(sectionOverride ?? params.get("section"), params.get("sub"));
const answersActive = section === "application" && subsection === "answers";
const answersEntry = useMemo(() => ({ jobId, answersActive }), [jobId, answersActive]);
const [readyAnswersEntry, setReadyAnswersEntry] = useState<object | null>(null);
const sectionId = useId();
const secondaryId = useId();
const panelRef = useRef<HTMLDivElement>(null);
@@ -85,6 +88,7 @@ export function ApplicationWorkspace({
const [loadedOverview, setOverview] = useState<WorkspaceOverview | null>(null);
const overview = loadedOverview?.id === jobId ? loadedOverview : null;
const overviewRequest = useRef(0);
const overviewLoadedJob = useRef<number | null>(null);
const [error, setError] = useState<ViewResourceError | null>(null);
const [loading, setLoading] = useState(true);
const [editOpen, setEditOpen] = useState(false);
@@ -136,7 +140,11 @@ export function ApplicationWorkspace({
setError(null);
setLoading(true);
const next = await applicationWorkspaceApi.overview(jobId);
if (request === overviewRequest.current) setOverview(next);
if (request === overviewRequest.current) {
setOverview(next);
overviewLoadedJob.current = next.id;
setReadyAnswersEntry(answersEntry);
}
} catch (err) {
if (request !== overviewRequest.current) return;
const status = (err as { response?: { status?: number } })?.response?.status;
@@ -144,12 +152,17 @@ export function ApplicationWorkspace({
} finally {
if (request === overviewRequest.current) setLoading(false);
}
}, [jobId, t]);
}, [jobId, t, answersEntry]);
const previousOverviewSource = useRef<{ jobId: number; t: typeof t; answersActive: boolean } | null>(null);
useEffect(() => {
void load();
const previous = previousOverviewSource.current;
previousOverviewSource.current = { jobId, t, answersActive };
// Each Answers entry needs a coherent source; leaving it does not need another aggregate read.
if (answersActive || !previous?.answersActive || previous.jobId !== jobId || previous.t !== t || overviewLoadedJob.current !== jobId) void load();
else setLoading(false);
return () => { overviewRequest.current += 1; };
}, [load]);
}, [load, answersActive, jobId, t]);
useEffect(() => {
// Direct entry gets a named target; keyboard tab activation keeps tab focus.
@@ -261,7 +274,7 @@ export function ApplicationWorkspace({
<Box role="tabpanel" id={`${secondaryId}-panel`} aria-labelledby={`${secondaryId}-${subsection}`} tabIndex={0} sx={{ display: "grid", gap: 2, minWidth: 0 }}>
{section === "application" && subsection === "cv" && jobId > 0 && <ApplicationCvSection key={jobId} jobId={jobId} includePackages={false} />}
{section === "application" && subsection === "letter" && jobId > 0 && <ApplicationCoverLetterSection key={jobId} jobId={jobId} onDirtyChange={setCoverLetterDirty} />}
{section === "application" && subsection === "answers" && overview && jobId > 0 && <ApplicationPackageDraftsSection
{answersActive && readyAnswersEntry === answersEntry && overview && jobId > 0 && <ApplicationPackageDraftsSection
key={jobId}
jobId={jobId}
initialRevision={overview.revision}