improvement: tasks and cases feature updated based on the new prosthesis types and their steps. the whole assignment proccess removed from the flow.

This commit is contained in:
2026-07-07 15:31:09 +03:30
parent ed7e7b1d8f
commit cb63ced4e3
35 changed files with 1819 additions and 454 deletions

View File

@@ -69,6 +69,27 @@ function labCaseDraftsToPast(
}));
}
function enrichDetailsWithLabSendState(
details: TreatmentDetailDraft[],
labCaseDrafts: LabCaseDraft[],
): TreatmentDetailDraft[] {
return details.map((detail) => {
const sentLabCase = labCaseDrafts.find(
(lc) => lc.sentAt && lc.detailClientIds.includes(detail.clientId),
);
if (!sentLabCase) return detail;
return {
...detail,
labCaseId: sentLabCase.id ?? detail.labCaseId,
sentAt: sentLabCase.sentAt ?? detail.sentAt,
sends: sentLabCase.sends ?? detail.sends,
sendToOrganizationIds: sentLabCase.destinationOrganizationId
? [sentLabCase.destinationOrganizationId]
: detail.sendToOrganizationIds,
};
});
}
function buildWorkspaceSnapshot(
appointment: TreatmentAppointment,
details: TreatmentDetailDraft[],
@@ -76,8 +97,9 @@ function buildWorkspaceSnapshot(
title: string,
id?: string,
): PastTreatment {
const detailsForPreview = enrichDetailsWithLabSendState(details, labCaseDrafts);
return {
...detailsToPreviewTreatment(details, {
...detailsToPreviewTreatment(detailsForPreview, {
id: id ?? `preview-${appointment.id}`,
title,
patientId: appointment.patientId,
@@ -844,6 +866,22 @@ export function TreatmentWorkspace({ userId, currentOrganization }: TreatmentWor
const response = await treatmentsApi.sendLabCase(refreshedLabCase.id);
const sentDetailClientIds = new Set(labCase.detailClientIds);
setDetails((prev) =>
prev.map((detail) => {
if (!sentDetailClientIds.has(detail.clientId)) return detail;
return {
...detail,
labCaseId: response.data.id,
sentAt: response.data.sentAt,
sends: response.data.sends,
sendToOrganizationIds: response.data.destinationOrganizationId
? [response.data.destinationOrganizationId]
: detail.sendToOrganizationIds,
};
}),
);
setLabCaseDrafts((prev) =>
prev.map((lc) =>
lc.clientId === labCase.clientId

View File

@@ -0,0 +1,72 @@
import type { CSSProperties } from 'react';
/**
* Prosthesis-type colors for lab-facing surfaces (Tasks list, Cases detail group
* headers / badges). Grouped by material family, loosely inspired by exocad's
* material color conventions:
* - Zirconia family → pale green/cream
* - PFM / full metal → steel gray
* - Glass-ceramic / IPS (press & CAD) → warm amber
* - Resin / PMMA / PEEK / temporary → mint/teal
* - Abutments / screw-retained → slate blue
* - Smile design / mockup → lavender/pink
*
* Clinic-facing dispatch flows intentionally do NOT use these colors.
*/
const PROSTHESIS_TYPE_COLORS: Record<string, string> = {
// Zirconia family
monolithic_zirconia: '#d9f2e6',
pfz_crown: '#c7ede0',
veneer_zirconia: '#b8e6d5',
zirconia_abutment: '#a7dcc8',
zirconia_overlay: '#cdeede',
// PFM / metal
pfm_crown: '#cbd5e1',
full_metal_crown: '#b8c2cf',
// Glass-ceramic / IPS
glass_ceramic_crown: '#fde3a7',
veneer_ips_press: '#fcd88f',
veneer_ips_cad: '#f9cf9c',
ips_overlay: '#fbe0b0',
// Resin / PMMA / PEEK / temporary
temporary_resin_crown: '#bfeaf0',
pmma: '#a9e2ea',
peek_crown: '#b7e4dd',
soft_structure: '#d4eef0',
// Abutments / screw-retained
customized_abutment: '#aec6e8',
prefabricated_abutment: '#9db8e0',
ti_base_abutment: '#c0d0ec',
multi_unit_abutment: '#b4c4e6',
screw_retained: '#a8bce2',
// Design / mockup
smile_design: '#e9d5ff',
mockup: '#f5d0fe',
};
const FALLBACK_COLORS = ['#ddd6fe', '#fed7aa', '#fecaca', '#bae6fd', '#d9f99d', '#fbcfe8'];
/** Dark ink that stays readable on every pastel in the palette. */
const BADGE_INK = '#14253d';
export function prosthesisTypeColor(code: string, index = 0): string {
return PROSTHESIS_TYPE_COLORS[code] ?? FALLBACK_COLORS[index % FALLBACK_COLORS.length];
}
/** Filled swatch (small indicator dots). */
export function prosthesisTypeSwatchStyle(code: string, index = 0): CSSProperties {
return { backgroundColor: prosthesisTypeColor(code, index), borderColor: 'rgba(0, 0, 0, 0.18)' };
}
/** Pastel pill / banner fill with readable dark text (group headers, badges). */
export function prosthesisTypeBadgeStyle(code: string, index = 0): CSSProperties {
return {
backgroundColor: prosthesisTypeColor(code, index),
borderColor: 'rgba(0, 0, 0, 0.16)',
color: BADGE_INK,
};
}
export function formatToothList(teeth: string[]): string {
return teeth.join(', ');
}