improvement: all confirmed suggestions implemented

This commit is contained in:
2026-09-04 17:04:48 +03:30
parent 7f92e735fb
commit 72f885d9dd
23 changed files with 1070 additions and 679 deletions

View File

@@ -47,8 +47,8 @@ frontend/src/
- Day/mode gate: editable only for live draft on today/future (`canEditTreatmentForDay`). Past day / historical load → read-only form. Patient search sits in the **page header** (workspace-wide). If the patient has a visit on the day strip, that visit opens; else the latest history plan loads. If neither exists, the editor shows an inline empty state (no dialog) pointing to **New treatment** in the rail — do not auto-create. **New treatment** is at the top of the left rail (selected-patient card below it) and opens a picker: Walk-in first, then a matching card for the current named patient (name + mobile/email), then search. It does not auto-copy the appointment cards patient. New treatment seeds one blank detail; a persisted empty plan loads as `[]` until Add.
- **Unscheduled strip cards** use the same treatment-type banner as appointments from the **first details type only** (`unscheduledStripColorCode`; live draft for the open card). Empty first line → chip theming even if later lines are typed. Strip trash only when every line is blank (no type/teeth/notes/attachments, including `[]`); typed cards need chip-delete first. Backend `DELETE /treatments/:id` is empty-only (`TREATMENT_HAS_DETAILS`).
- Sent-to-lab detail locks that line; **Add detail** still OK same day; **Remove detail** = trash on chip (unsent, including last line; day/edit gates apply). Empty details persist as `[]`. Attachment upload blocked when sent (`TREATMENT_DETAIL_SENT`).
- **Entry:** Type dropdown + compact attachments strip (`TreatmentDetailAttachmentsStrip`) on one row, then bordered FDI chart (Cases chrome/scale), then full-width auto-growing **Notes**. Prosthesis types are assigned on the chart (teeth, or Upper/Lower arch labels for jaw products). Lab dispatch sits under chart+notes when the active type is lab-dependent — no Treatment→Lab stepper. Detail chips show type + teeth; lab-dependent chips use colored sent/unsent text (sent date on dispatch). Lab-rail / Go to dispatch **scrolls** to the panel (`pendingScrollToLabRef`). Lab dispatch keeps comments.
- **Tooth selection:** Hit target is the unrotated cell (`pointerdown` only — do not also bind `click`). Glyph is `pointer-events-none`; nest hover/selected scale inside the rotate wrapper. Neighbor empty/filled circles between selected adjacent teeth connect/disconnect bridges; Shift+range selects only (empty circles; overlap absorbs as singles); midline 1121 / 4131 allowed. Plain click selects/deselects (deselect splits bridges). Never a 1-tooth connected. Prosthesis assign chart: Shift = range then assign; Ctrl/Cmd or drag = copy last type-set. Helpers: `toothSelectionGroups.ts`. Connected label: `ConnectedSelectionBadge`. Unconnected teeth stay **one item per tooth** (stacked types on that tooth union their lab steps). **Connected** teeth that share a prosthesis type are **one job** (teeth listed together); an extra type on one unit of the bridge is its own row. `UA`/`LA` → Upper/Lower arch. **Partial denture** is tooth-selected and becomes **one lab job** for all those teeth.
- **Entry:** Type dropdown + compact attachments strip (`TreatmentDetailAttachmentsStrip`) on one row (plus **Lab dispatch** / **Chart** toggle when the type is lab-dependent; dispatch is primary, Chart is outline, same width), then bordered FDI chart (Cases chrome/scale) **or** the lab dispatch panel in that same slot, then full-width auto-growing **Notes**. Prosthesis types are assigned on the chart (teeth, or Upper/Lower arch labels for jaw products — dashed outline + plus). Arch Upper/Lower/Both remaps existing `UA`/`LA` jobs (Both→Upper clears lower). Picker: `4fr` wrapping category grid / `1fr` add-ons; empty crown slot is plus + dashed “Crown can be added”; filled crown slot stays visible so it can be changed. Implant/post & core show a crown suggestion slot; a veneer/inlay/onlay/overlay hides it; Post & core is disabled after crown or implant; Implant is disabled after post & core; screw-retained does not suggest another crown. Prosthesis teeth always have jobs (hydrate/save prune). Lab-rail / Go to dispatch **opens the dispatch view** (`pendingScrollToLabRef`). Detail chips show type + teeth; lab-dependent chips use colored sent/unsent text (sent date on dispatch). Lab dispatch keeps comments.
- **Tooth selection:** Hit target is the unrotated cell (`pointerdown` only — do not also bind `click`). Glyph is `pointer-events-none`; nest hover/selected scale inside the rotate wrapper. Neighbor empty/filled circles between selected adjacent teeth connect/disconnect bridges; midline 1121 / 4131 allowed. Never a 1-tooth connected. On the non-prosthesis chart, Shift+range selects as singles. **Prosthesis assign chart (Exocad-style):** plain click opens the picker (tooth is not selected until a type is picked); **Done** stores that tooths jobs as the copy brush; **Ctrl/Cmd+click** or drag copies those jobs onto one tooth; **Shift+click** copies onto the inclusive same-arch range as **singles** (connect with neighbor circles if it is a bridge). Helpers: `toothSelectionGroups.ts`. Connected label: `ConnectedSelectionBadge`. Unconnected teeth stay **one item per tooth** (stacked types on that tooth union their lab steps). **Connected** teeth that share a prosthesis type are **one job** (teeth listed together); an extra type on one unit of the bridge is its own row. `UA`/`LA` → Upper/Lower arch. **Partial denture** is tooth-selected and becomes **one lab job** for all those teeth.
- **Lab dispatch layout:** due date beside title (`justify-between`, logical start/end for RTL); job rows from `LabCaseToothJobsList` (connected same-type teeth share a row; stacked types on a single tooth stay on that tooth).
- **Schedule date:** Treatment strip and Appointments page headers use `ScheduleDayPicker` `compact` (date centered in a 3-col header; no “Schedule date” label; Today on the navigator).
@@ -57,7 +57,7 @@ frontend/src/
- New prosthesis dispatch lines start **empty** (no default lab). Types are assigned only on the chart (`ProsthesisAssignChart` / `ProsthesisJobPopover`). Recent-lab chips are the last **3 sent** destinations — pick is explicit, never auto-selected.
- Detail treatment type need **not** match appointment purpose — purpose only seeds the **first** line of an empty **appointment** draft (first open, and **Add detail** when the plan is `[]`). Further **Add detail** starts with an empty type. Unscheduled / New treatment still seeds a blank first line.
- **History filters** are client-side only (`treatmentHistoryFilters.ts`): “Not shipped to lab” + single date on already-fetched patient history; includes live current draft when filtering.
- **Lab shipments rail**: unified list with scope toggle **This patient** vs **All updates** (unread across org for **this clinician's cases only**, includes patient name). Opening a case from the rail **scrolls** to the lab dispatch panel.
- **Lab shipments rail**: unified list with scope toggle **This patient** vs **All updates** (unread across org for **this clinician's cases only**, includes patient name). Opening a case from the rail **opens the lab dispatch view** (same slot as the chart).
- **Unread semantics**: Treatment tab badge = count of unread cases **for the user's own treatment plans** (per-case read cursor) and clears when a case is opened/marked read (not on tab visit).
- **Live lab rail**: `notification.created``notifyTabBadgesChanged()` silently refreshes patient lab cases + unread rail (does **not** clear draft/form state).
- **Lab shipment progress + comments**: shown in **Lab dispatch panel** for the active shipment; expanding activity / opening comments marks that case read. Shared UI: `LabCaseCommentsPanel` — newest first; sent = start / received = end (`text-start`/`justify-start`, RTL-safe); pass `viewerSide`.