diff --git a/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx b/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx index dd659c9..ce4ac0d 100644 --- a/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx +++ b/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx @@ -551,6 +551,13 @@ export function TreatmentWorkspace({ const draftHydratingRef = useRef(false); const workspaceModeRef = useRef(workspaceMode); workspaceModeRef.current = workspaceMode; + /** + * `persistDraft` prunes a lab-dependent detail down to the teeth its jobs cover, and it reads + * this ref — not React state. So any handler that changes the drafts and then saves in the + * same tick must write the ref beside `setLabCaseDrafts`; the render-time assignment below has + * not run yet. Skipping it saves the detail with no teeth, and the lab-case request that + * follows is then rejected with TREATMENT_TOOTH_NOT_ON_DETAIL. + */ const labCaseDraftsRef = useRef(labCaseDrafts); labCaseDraftsRef.current = labCaseDrafts; const skipNextGetDraftRef = useRef(false); @@ -2278,6 +2285,7 @@ export function TreatmentWorkspace({ })); }); const updatedLabCases = [...labCaseDrafts, draft]; + labCaseDraftsRef.current = updatedLabCases; setLabCaseDrafts(updatedLabCases); // Persist the new detail first so lab-case rows can use real treatmentDetailIds. @@ -2432,6 +2440,7 @@ export function TreatmentWorkspace({ const updatedLabCases = cleaned.map((lc) => lc.clientId === orphan.clientId ? { ...lc, detailClientId: activeDetailId } : lc, ); + labCaseDraftsRef.current = updatedLabCases; setLabCaseDrafts(updatedLabCases); setActiveLabCaseId(orphan.clientId); @@ -2450,6 +2459,7 @@ export function TreatmentWorkspace({ attachmentIds: activeDetail?.attachmentMetas.map((a) => a.id) ?? [], }; const updatedLabCases = [...cleaned, next]; + labCaseDraftsRef.current = updatedLabCases; setLabCaseDrafts(updatedLabCases); setActiveLabCaseId(next.clientId);