# W3-FE-4 — report (in-place screen settings in «✎ تخصيص الشاشة» + element consumers + dental plan/FMX cards)

Status: DONE (FE). Not committed, not deployed. No BE changes, no migrations. `ng build --base-href /app/` green (last run 2026-10-23 17:35, whole tree incl. other agents' work). I18N_VERSION NOT bumped.

## Files

New
- `visit-shell/visit-settings.service.ts` — component-scoped store (provided by the shell): payload, scope (`client`|`doctor`), one rules draft per scope `{fields, elements, features}` + pending «عام للعيادة» values (allow_doctor / facility), resolution per Fable §1 (fields per-key merge, doctor = `input` only and never on a client-locked key; elements doctor ?? client ?? ON unless locked; features default ← client), live preview while editing, dirty flags (scope / per card), PUT bodies (client: registry attributes only; doctor: locked keys left out → no 422), forced rows (insured `diagnosis` required + ICD).
- `visit-shell/card-rules.ts` — which rules each shared card's ⚙ offers (Fable §2.3), dynamic markers `@exam_region` (registry codes) / `@vital` (8 base measures), header rules, notes for history / gyn_cats / gyn_modules; `rulesFor()`, `ruleLabelKey()`.
- `visit-shell/visit-card-settings.component.ts` — the per-card «⚙ إعدادات» popover (and the header's, `variant="hdr"`): fields (ظاهر / إلزامي switches, Select|Text seg, 🔒, source tag, «*»), elements (switch, 🔒, source), doctor read-only rows / grey locked rows, forced row «مفروض: مريض مؤمّن», amber dirty dot, «↺ رجّع الكارت للافتراضي» / «تم» (no save inside), bottom sheet < 640px, Esc / `L` keys, role=dialog/switch/radiogroup.
- `visit-shell/visit-type-settings-sheet.component.ts` — «إعدادات التخصص» side sheet (inline-end, full screen < 640px): feature groups (gyn 6 · dental 8 · general/nutrition «مفيش مجموعات») with «بيقفل: n كارت» + source tag; shell switch (nutrition/dental, else «الشاشة الجديدة هي الأساسية»); collapsed «عام للعيادة» (allow_doctor_override switch + facility radio-cards with the BE preset desc + the 4 resulting values as code chips, «مخصص» → current values + link, inline confirm). Needs clinic.settings.manage, else read-only + «من إعدادات العيادة ↗». Doctor scope = read-only banner.
- `visit-shell/specialties/dental-plan-fmx-cards.component.ts` — `dent_plan` (hosts `DentalPlanPanelComponent`, loads plans/chart/meta itself) and `dent_fmx` (hosts `DentalFmxComponent`, chart images + auth thumbnails, upload/open). The workspace is unchanged.
- `visit-shell/w3-settings.check.ts` — 47 pure checks (esbuild + node).

Changed (mine this wave)
- `visit-shell/visit-layout-editor.component.ts` — rewritten: two intentional rows (Fable §2.1 / P1-8): title · source · n cards … «＋ إضافة كارت (n)» «⚙ إعدادات التخصص» «تلوين بالطبقة» (L1–L4 legend); row 2 «الإعداد لمين؟» seg (only when manage + override) or «بتعدّل نسختك أنت», level strip افتراضي → العيادة ✓ → أنا ✓, ONE primary save following the scope (+ dirty dot), reset of that scope with inline confirm (client confirm says the groups reset too), cancel; inline dirty-switch confirm «احفظ / سيبها / ارجع»; hints «ليك نسخة شخصية… [شيل نسختي]» / «نسختك فوق شكل العيادة…»; Alt+S.
- `visit-shell/visit-layout.service.ts` — total `normalizeLayoutPayload` (elements, doctor fields/elements, effective, registry, facility, can_manage_settings), `saveClient` with all sections optional/nullable, `saveDoctorProfile`, `saveFacilityType` (`PUT visit-layout/facility-type`). `saveDoctor(type, layout)` kept as a wrapper.
- `visit-shell/visit-shell.component.{ts,html}` (after «FE-5 done»; all FE-5 work kept): `VisitSettingsService` provider + sync effect; `fields()` = effective rules (draft while editing); `layoutFeatures` = draft features while editing; `baseFor(scope)` (client scope edits default ← client WITHOUT the doctor's copy; doctor scope default ← client ← doctor); `layoutDirty` (layout sent only when it changed → saving rules never freezes the default as a client layout); `saveScope()` (client: allow_doctor setting → facility type → client PUT, a settings failure stops and keeps the draft; doctor: doctor PUT), `resetScope()`, `dropMyCopy()`, `onScopeChange()`, `onFeatureToggled()` (a group off drops its cards from the draft with the «اتشالت n كروت…» line, back on restores them), `saveFailed()` (403 doctor-off line, 422 key names, global-fail line), dental features re-read after a save. Decision 7 narrowed → `layoutLocked = false` (all 4 types split; nutrition per W2-FE-6, dental tabs/props per review A #45), `saveLocked` removed. Bindings: header `[showInsurance/LastVisit/Doctor]`, header ⚙ on the strip in edit mode, vitals `[hiddenCodes]/[requiredCodes]`, diagnosis `[inputMode]` (`diagnosis.input`, insured → select) + `[allowSecondary]`, lab `[compact]="true"` + `[showHistory]="el('lab.prev')"`, rad `[compact]="true"`, rx `[showAlerts]="el('rx.interact')"`, follow-up `[dateRequired]`, finish panel `(jump)`, the sheet. `finishWarnings` → `{text, cardId}` + client-required soft lines (complaint_duration, diagnosis (cash), followup_date, vital.*). Complaint collapsed line gets «· <duration>».
- `visit-shell/visit-header.component.ts` — `showInsurance / showLastVisit / showDoctor` inputs (default true).
- `visit-shell/visit-finish-panel.component.ts` — `FinishWarning {text, cardId}`; each line with a card gets «افتح المحطة ↗» (`jump` output) (Fable P2-16).
- `visit-shell/visit-card.component.{ts,html,scss}` — the ⚙ (only for cards with rules; never on context placeholders), «إلزامي للمؤمّن — ميتشالش» title on the disabled ✕ of the insured dx, «مجموعة: X» tag in edit mode for feature-bound cards (Fable §2.6), host classes `L{n}` + `layers` (layer colouring of the card edge and its `.inp` fields), `.from.default` colour (P2-14).
- `visit-shell/cards/visit-complaint-card.component.ts` — «مدة الشكوى» (`complaint_duration`, visible/required rule, maxlength 60) + HPI textarea (element `complaint.hpi`), saved like the note: one serialized PATCH of the pending columns, 800 ms debounce, flush-before-sign + on destroy; null clears duration/HPI. Elements `complaint.quick` / `complaint.note` from the settings service (W2-BE-C moved them off `fields`; the legacy field rules still read outside the shell). «*» on the picker when `chief_complaint.required`.
- `visit-shell/cards/visit-exam-card.component.ts` — the rule key is the region CODE (`exam_chest`, what the BE stores) first, then `exam_finding_<code>` / `_<id>`; «*» per required region; `exam.normal` = new «✓ الباقي سليم» (each untouched visible region gets its seeded `*_normal` finding; text region → «سليم»); `exam.notes` off hides an EMPTY notes box (a recorded note is never hidden).
- `visit-shell/cards/visit-followup-card.component.ts` — `dateRequired` input («*» on the date).
- `visit-shell/specialties/dental.cards.ts` — `dent_plan` (sizes M/L/F, perm dental.chart.view) and `dent_fmx` (M/F, feature `imaging`) addable, not in the default; `dent_workspace` (already required) gets a note-only ⚙. `dental-layout.check.ts` default-exclusion list + the 2 new ids (16/16 green).
- `features/gyn/gyn-shell-cards.ts` — `team` collapsed by default in the GYN default (operation/discharge/gyn_followup already were) — orchestrator item (a).
- `services/clinic-encounter.service.ts` — `Encounter.complaint_duration/hpi`, `PatchEncounterPayload` with both (nullable).
- i18n `ar.json` + `en.json`: `VISIT_SHELL.ED.*` (26 new), `VISIT_SHELL.SET.*`, `VISIT_SHELL.RULE.*` (one per key incl. 8 vitals), `VISIT_SHELL.TYPE.*` (incl. `F_<feature>` for the 6 gyn + 8 dental groups), `COMPLAINT.DURATION_*/HPI_*`, `EXAM.REST_NORMAL*`, `FINISH.OPEN_STATION/REQUIRED_MISSING`, `SPEC.DENT_PLAN_TEMPLATE`.

Shared files of W2-FE-2 (committed 0931e8cb) — small inputs only, as asked
- `encounter/diagnosis-panel/diagnosis-panel.component.{ts,html}` — `@Input() allowSecondary = true` (dx.secondary): off + one diagnosis recorded → the pick / free-text add controls hide; recorded rows are never hidden.
- `encounter/prescription/prescription.component.{ts,html}` — `@Input() showAlerts = true` (rx.interact) guarding the ⚠ alert badges on hits/rows and the alert-edit links.
- `encounter/vitals-panel/vitals-panel.component.{ts,html,scss}` (nobody else's) — `hiddenCodes` / `requiredCodes` inputs for the base measures (weight, height, bmi, bp, pulse, random_blood_glucose, temperature, spo2): hidden cells not rendered, «*» on required.

## Checks run
- `ng build --base-href /app/` — green (only pre-existing warnings elsewhere).
- esbuild + node: **w3-settings 47/0 (new)**, resolve-layout 34/0, w4-catalog 50/0, dental-layout 16/0, nutrition-layout 26/0, inpatient.context 41/0.

## Not verified / deviations / decisions
- **Nothing exercised in a browser or against the live API with a user** — token minting was refused by the permission layer (credential materialisation), so no screenshots and no live PUT. The BE contract was read from W2-BE-C's controller/service/registry code. The orchestrator should click through: manager scope save/reset, doctor scope (override on), dirty switch, the sheet (gyn groups, dental write-through, shell switch, facility confirm), header ⚙, layer colouring, finish links, dent_plan / dent_fmx add.
- **Commit note:** my `visit-layout.model.ts` additions (CardRules, ElementRule, DoctorProfile, EffectiveRules, registry types, payload shape) were swept into FE-5's commit 1f7ffdbe; that commit's `visit-layout.service.ts` is still the OLD normalize (my new one is uncommitted), so HEAD alone likely does not type-check until this wave is committed.
- Popover: built as an own fixed-position panel (backdrop + `role=dialog`, bottom sheet < 640px) instead of PrimeNG `Popover`, for the phone bottom-sheet and focus/Esc control; same visual spec (380px, `#c4b5fd` border, 12px radius).
- `rad.prev`: not offered in any ⚙ — the radiology card has no previous-results strip (the BE accepts the key). `lab.prev` drives the lab card's existing «earlier visits' lab orders» strip.
- `rx.interact`: there is no drug-drug interaction engine; the element switches the prescription's existing ⚠ drug alert / interaction notes (per-drug notes the clinic writes). Owner may want a real interaction check later.
- `exam.normal`: the prototype has no explicit button; implemented as «✓ الباقي سليم» using the seeded `ef_*_normal` findings (dev company 1 has one per region).
- `dx.secondary` off does not hide recorded secondary diagnoses (never hide data); it stops adding more than one.
- Required rules are SOFT finish lines (Decision 1: the only hard stop stays the insured coded primary). Exam-region `required` shows «*» but has no finish line (the exam card does not report per-region state); `chief_complaint.required` is covered by the existing NO_COMPLAINT line.
- History / spec-card (nutrition intake, dental today, GYN first visit) history-code fields are not listed in a ⚙ (registry gives codes without labels; history questions are managed in «الحقول السريرية» — the history ⚙ shows that note + link to /clinic/settings). Their existing consumers still read the effective rules via `SpecCardCtx.fields`.
- `dent_plan` «تم» on a plan item completes the planned record directly (`completeRecord`); a procedure that has a note template shows a toast and opens the chart tab (the workspace's template dialog is not reusable without changing the workspace).
- The client PUT sends `features` ONLY when a group / the shell switch changed: the BE writes every `dental.feature.*` row whenever the section is present (even unchanged ones, `getExact === null` branch), so after any features save all 8 dental groups read source «العيادة». Omitting the section otherwise keeps untouched installs at «افتراضي». BE nuance for the FIN pass if the owner cares.
- Customise mode always opens on «للعيادة كلها» for a manager (Fable §2.1), «لي أنا» for a doctor without manage.
- `hdr.*` stored per clinical type (orchestrator decision); the header ⚙ shows the «ده للشاشة دي بس» note.
- Card-head source tag keeps the existing `VISIT_SHELL.FROM.CLIENT` «العميل» wording; the popover/sheet use «العيادة» (Fable LEVEL_CLIENT).
- Fable P2-13 («ملف ناقص» pill style) not touched — the intake badge component is not in my files.
- CHANGELOG `[Unreleased]` bullet not added (orchestrator). Suggested: «شاشة الزيارة: إعدادات كل كارت (ظاهر/إلزامي/Select-Text/🔒 والعناصر) ومجموعات التخصص ونوع المنشأة من جوه «تخصيص الشاشة» للعيادة أو للدكتور؛ مدة الشكوى وHPI؛ زر «الباقي سليم» في الفحص؛ تلوين بالطبقة؛ روابط «افتح المحطة» في الإنهاء؛ كارتي خطة العلاج وFMX للأسنان / Visit screen: per-card field rules and elements, specialty groups and facility type set in place in «Customise screen» for the clinic or the doctor; complaint duration + HPI; «rest normal» in the exam; colour by layer; «open the station» links when finishing; dental treatment-plan and FMX cards».
