diff --git a/frontend/src/components/treatment/voiceReviewRows.spec.ts b/frontend/src/components/treatment/voiceReviewRows.spec.ts index e6929d3..8a100cb 100644 --- a/frontend/src/components/treatment/voiceReviewRows.spec.ts +++ b/frontend/src/components/treatment/voiceReviewRows.spec.ts @@ -232,6 +232,16 @@ describe('joblessProsthesisTargets', () => { expect(joblessProsthesisTargets(result)).toEqual(['13']); }); + it('does not call a target jobless when another assignment already gave it a job', () => { + const result = baseResult({ + prosthesisAssignments: [ + { targets: ['13'], types: [], spoken: '' }, + { targets: ['13'], types: ['pfm_crown'], spoken: '' }, + ], + }); + expect(joblessProsthesisTargets(result)).toEqual([]); + }); + it('does not call a target jobless while it is pending a material pick', () => { const result = baseResult({ prosthesisAssignments: [{ targets: ['13'], types: [], spoken: 'روکش' }], diff --git a/frontend/src/components/treatment/voiceReviewRows.ts b/frontend/src/components/treatment/voiceReviewRows.ts index 6170c29..78df511 100644 --- a/frontend/src/components/treatment/voiceReviewRows.ts +++ b/frontend/src/components/treatment/voiceReviewRows.ts @@ -239,7 +239,11 @@ export function joblessProsthesisTargets(result: VoiceExtractionResult): string[ if (!covered.has(tooth) && !pending.has(tooth)) jobless.add(tooth); } - return [...jobless]; + // A target named twice — once with a job, once bare — is not jobless. Without this the + // sheet shows the same tooth with its crown AND struck through as "no prosthesis heard". + return [...jobless].filter( + (target) => !covered.has(target) && !pending.has(target), + ); } export type VoiceProsthesisChartData = { diff --git a/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx b/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx index 7f49925..54a12e9 100644 --- a/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx +++ b/frontend/src/components/ui/treatment/TreatmentWorkspace.tsx @@ -2191,7 +2191,9 @@ export function TreatmentWorkspace({ setActiveDetailId(detail.clientId); if (labCaseDraft) { - const updatedLabCases = [...labCaseDrafts, labCaseDraft]; + // The ref, not the state: every other handler now writes the ref beside + // setLabCaseDrafts, so a draft added earlier in the same tick is only there. + const updatedLabCases = [...labCaseDraftsRef.current, labCaseDraft]; labCaseDraftsRef.current = updatedLabCases; setLabCaseDrafts(updatedLabCases); @@ -2215,7 +2217,6 @@ export function TreatmentWorkspace({ setVoiceResult(null); }, [ - labCaseDrafts, labDependentCodes, persistDraft, persistLabCases, diff --git a/frontend/src/components/ui/treatment/VoiceReviewSheet.tsx b/frontend/src/components/ui/treatment/VoiceReviewSheet.tsx index ccb978d..ef001e3 100644 --- a/frontend/src/components/ui/treatment/VoiceReviewSheet.tsx +++ b/frontend/src/components/ui/treatment/VoiceReviewSheet.tsx @@ -106,6 +106,13 @@ export function VoiceReviewSheet({ [effective, prosthesisCatalog], ); const joblessTargets = useMemo(() => joblessProsthesisTargets(effective), [effective]); + // A target whose assignment named no usable job still produces a line, and the jobless list + // already names it. Rendering both printed a dangling "13: " beside "13: no prosthesis + // heard". The unfiltered list still feeds the chart, so a pending target stays selected. + const shownLines = useMemo( + () => prosthesisLines.filter((line) => line.applied.length > 0 || line.refused.length > 0), + [prosthesisLines], + ); const chartData = useMemo( () => prosthesisChartData(prosthesisLines, joblessTargets, prosthesisCatalog), [prosthesisLines, joblessTargets, prosthesisCatalog], @@ -269,7 +276,7 @@ export function VoiceReviewSheet({ />
- {prosthesisLines.map((line, i) => ( + {shownLines.map((line, i) => ( {i > 0 ? ' · ' : ''} {targetLabel(line.target)}:{' '} @@ -279,13 +286,13 @@ export function VoiceReviewSheet({ {labelFor(code, prosthesisCatalog)} ))} - {line.refused.map((code) => ( + {line.refused.map((code, j) => ( - {' + '} + {line.applied.length > 0 || j > 0 ? ' + ' : ''} {labelFor(code, prosthesisCatalog)} ))} @@ -296,7 +303,7 @@ export function VoiceReviewSheet({ key={`jobless-${target}`} className="text-text-muted line-through" > - {prosthesisLines.length > 0 || i > 0 ? ' · ' : ''} + {shownLines.length > 0 || i > 0 ? ' · ' : ''} {targetLabel(target)}: {t('voiceNoProsthesisHeard')} ))}