improvement: all demo bugs fixed. give me more baby.

This commit is contained in:
2026-07-08 02:53:47 +03:30
parent 86b1e3afff
commit 8d334833ff
23 changed files with 876 additions and 626 deletions

View File

@@ -33,7 +33,7 @@ interface LabCasesDispatchPanelProps {
onRecentOrganizationPick: (orgId: string) => void;
sendBusyId: string | null;
onAddLabCase: () => void;
onSendLabCase: (labCase: LabCaseDraft) => void;
onSendLabCase: (labCase: LabCaseDraft, comment?: string) => void;
onCommentError?: (message: string) => void;
}
@@ -133,6 +133,7 @@ export function LabCasesDispatchPanel({
const t = useTranslations('treatment');
const [prosthesisOptions, setProsthesisOptions] = useState<ProsthesisCatalogEntry[]>([]);
const [applyAllProsthesis, setApplyAllProsthesis] = useState('');
const [pendingComment, setPendingComment] = useState('');
const activeLinkedOrganizations = orgs.filter((o) => o.active);
const filteredOrganizations = (() => {
@@ -196,6 +197,11 @@ export function LabCasesDispatchPanel({
};
}, [activeLabCase?.destinationOrganizationId]);
// Reset the pending (unposted) comment when switching to another shipment.
useEffect(() => {
setPendingComment('');
}, [activeLabCase?.clientId]);
// Hide dispatch when the selected treatment detail is not lab-dependent.
if (!activeDetail || !isLabDependentDetail) {
return null;
@@ -428,6 +434,9 @@ export function LabCasesDispatchPanel({
caseId={activeLabCase.id}
canPost={canEdit && !disabled}
canToggleVisibility={false}
deferSubmit
composerValue={pendingComment}
onComposerValueChange={setPendingComment}
loadComments={async () => {
const r = await treatmentsApi.listLabCaseComments(activeLabCase.id!);
return r.data;
@@ -578,7 +587,7 @@ export function LabCasesDispatchPanel({
!prosthesisComplete
}
isLoading={sendBusyId === activeLabCase.clientId}
onClick={() => onSendLabCase(activeLabCase)}
onClick={() => onSendLabCase(activeLabCase, pendingComment.trim())}
>
{t('sendToLab')}
</Button>

View File

@@ -109,13 +109,24 @@ function buildWorkspaceSnapshot(
};
}
function newDetail(): TreatmentDetailDraft {
function defaultTreatmentTypeForAppointment(
purpose: string | undefined,
catalog: TreatmentCatalogEntry[],
): TreatmentDetailDraft['treatmentType'] {
const treatmentOptions = catalog.filter((entry) => entry.availableInTreatment);
if (purpose && treatmentOptions.some((entry) => entry.code === purpose)) {
return purpose as TreatmentDetailDraft['treatmentType'];
}
return (treatmentOptions[0]?.code ?? 'restoration') as TreatmentDetailDraft['treatmentType'];
}
function newDetail(defaultTreatmentType?: TreatmentDetailDraft['treatmentType']): TreatmentDetailDraft {
return {
clientId:
typeof crypto !== 'undefined' && 'randomUUID' in crypto
? crypto.randomUUID()
: `detail-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
treatmentType: 'restoration',
treatmentType: defaultTreatmentType ?? 'restoration',
teeth: [],
comment: '',
attachmentMetas: [],
@@ -502,9 +513,13 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
}, [showError, t]);
useEffect(() => {
if (selectedAppointment?.patientId) {
setHistoryPatientId(selectedAppointment.patientId);
if (!selectedAppointment?.patientId) {
setHistoryPatientId(null);
setHistory([]);
setHistoryLoading(false);
return;
}
setHistoryPatientId(selectedAppointment.patientId);
}, [selectedAppointment?.patientId]);
useEffect(() => {
@@ -558,7 +573,9 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
});
setSavedSnapshot(serializeDetails(mapped));
} else {
const first = newDetail();
const first = newDetail(
defaultTreatmentTypeForAppointment(selectedAppointment?.purpose, treatmentCatalog),
);
setDetails([first]);
setActiveDetailId(first.clientId);
setSavedSnapshot(serializeDetails([first]));
@@ -583,7 +600,7 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
cancelled = true;
draftHydratingRef.current = false;
};
}, [selectedAppointment?.id, workspaceMode, showError, t]);
}, [selectedAppointment?.id, selectedAppointment?.purpose, workspaceMode, treatmentCatalog, showError, t]);
const persistDraft = useCallback(
async (options?: { force?: boolean }) => {
@@ -905,7 +922,7 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
]);
const handleSendLabCase = useCallback(
async (labCase: LabCaseDraft) => {
async (labCase: LabCaseDraft, comment?: string) => {
if (!canEditTreatmentForDay || !selectedAppointment) return;
if (!labCase.destinationOrganizationId) {
showError(t('errorChooseOrg'));
@@ -934,6 +951,11 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
);
if (!refreshedLabCase?.id) throw new Error(t('errorSendCase'));
const trimmedComment = comment?.trim();
if (trimmedComment) {
await treatmentsApi.addLabCaseComment(refreshedLabCase.id, { body: trimmedComment });
}
const response = await treatmentsApi.sendLabCase(refreshedLabCase.id);
const sentDetailClientIds = new Set(labCase.detailClientIds);
@@ -1117,7 +1139,9 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
saveStatus={saveStatus}
uploadBusy={uploadBusyDetailId === activeDetailId}
onAddDetail={() => {
const next = newDetail();
const next = newDetail(
defaultTreatmentTypeForAppointment(selectedAppointment?.purpose, treatmentCatalog),
);
setDetails((prev) => [...prev, next]);
setActiveDetailId(next.clientId);
}}
@@ -1151,7 +1175,7 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
}}
sendBusyId={sendBusyId}
onAddLabCase={() => void handleAddLabCase()}
onSendLabCase={(lc) => void handleSendLabCase(lc)}
onSendLabCase={(lc, comment) => void handleSendLabCase(lc, comment)}
onCommentError={showError}
/>
</div>