# Scout B — FE Patient Registration + Doctors Screens (م3 prep)

Repo: `/home/moonui/public_html/moon-erp` (FE root), clinic features at
`src/app/features/clinic`.

---

## 1. Where does a user REGISTER/create a patient?

**There is NO dedicated patients screen/route in the clinic module.** No
`clinic/patients` route exists in
`src/app/features/clinic/clinic.routes.ts` (full route list read,
lines 1-183 — only: dashboard, appointments, booking, schedule,
encounter/:id, doctors, doctor-grades, departments, rooms, services,
service-categories, pricing, reception, cashier, revenue-split,
radiology/*, insurance/*, reports, settings). No "patients" entry.

Patient creation is **inline, quick-add-only**, inside the visit-booking
screen:

- **Component**: `CreateVisitComponent`
  `src/app/features/clinic/booking/create-visit.component.ts`
- **Route**: `clinic/booking` → gated on `clinic.appointment.create`
  (`src/app/features/clinic/clinic.routes.ts:27-33`)
- **Trigger**: "＋ Add Patient" button
  `src/app/features/clinic/booking/create-visit.component.html:33`
- **Dialog fields rendered** (`create-visit.component.html:521-541`):
  - `newPatientName` (required) — line 528-529
  - `newPatientNameAr` (optional) — line 530-531
  - `newPatientPhone` (required) — line 532-533
  - `newPatientGender` (required, p-select male/female) — line 534-535
  - **That's it — 4 fields total.**
- **Submit handler**: `saveNewPatient()`
  `create-visit.component.ts:446-477`
- **Endpoint posted to**: `POST {apiUrl}/clinic/patients`
  (`create-visit.component.ts:449-455`), raw `HttpClient.post` call
  (bypasses `ClinicPatientService` entirely — that service has no
  `create()` method, see §2below), payload:
  ```ts
  { name, name_ar, phone, gender }
  ```
- On success, the created patient becomes `selectedPatient` immediately
  (`create-visit.component.ts:460-461`) — no navigation to a patient
  file, no MRN/file-number shown to the user in this flow.

There is also a mini "Add Doctor" dialog on the same screen
(`create-visit.component.html:543-560`, handler
`saveNewDoctor()` at `create-visit.component.ts:481-514`, posts to
`ClinicDoctorService.create()` → `POST lis/doctors`) — fields: name,
name_ar, phone (required), department_id. Same "quick-add, minimal
fields" pattern as the patient dialog.

**Dead code found**: `ReceptionBookingComponent`
(`src/app/features/clinic/booking/reception-booking.component.ts`,
427 lines) implements a full booking screen with patient search but
**no "add patient" capability** and — confirmed via
`grep -rn "reception-booking\|ReceptionBookingComponent"` across
`src/app` — **is not referenced by any route file**. It is orphaned,
unrouted code. Do not confuse it with the live `create-visit` booking
screen.

---

## 2. Patient fields: form today vs م3 targets

### `ClinicPatientService` (`src/app/features/clinic/services/clinic-patient.service.ts`)
- `ClinicPatient` interface (lines 56-67): `id, mrn, name, name_ar,
  name_en?, gender, date_of_birth?, phone, blood_group?, national_id?`
- `ClinicPatientDemographics` (lines 8-19, used by the sticky header,
  §5): adds `age`, `nationality?`
- **This service has NO `create()`/`update()`/`delete()` method at
  all** — only `search(q)` (line 75), `listAll()` (line 81),
  `list()` (line 112, private), `get(id)` (line 118), `header(id)`
  (line 123, the sticky-summary payload). Patient creation is done via
  a raw `HttpClient.post` directly inside `create-visit.component.ts`
  (see §1), not through this service — an architecture smell if م3
  wants a canonical patient-write path.

### What the Add-Patient dialog renders today (the ONLY write path)
`name`, `name_ar`, `phone`, `gender` — 4 fields, mapped 1:1 to
`saveNewPatient()`'s POST body
(`create-visit.component.ts:450-455`).

### What's missing vs م3 targets (NID+auto-DOB, file number,
spouse/gyna fields, draft-resume, per-company hidden/required fields)
- **National ID**: not rendered anywhere in the clinic FE write path.
  `ClinicPatient.national_id?` exists as a read field (used in the
  patient-header display, `clinic-patient.service.ts:16`) but is never
  submitted on create.
- **Auto-DOB (presumably derived from Saudi NID digits)**: no DOB field
  in the add-patient dialog at all; `date_of_birth?` exists on the
  model/header only, never editable from clinic FE.
- **File number / MRN**: `mrn` is read-only, returned by the BE
  (`ClinicPatient.mrn`, line 58) and shown in the header summary
  (`ClinicPatientHeaderSummary.mrn`, line 35) — no FE field to set or
  edit it; presumably BE auto-generates it. No "file number" concept
  beyond `mrn` found anywhere in clinic FE.
- **Spouse / gynecology fields**: none exist. The only
  pregnancy-related field found is `pregnancy_gpa?: string` on
  `ClinicPatientHeaderSummary` (line 45), which is **display-only**
  (part of the read summary, not part of any create/edit form).
- **Draft-resume**: no localStorage/draft persistence logic found
  anywhere in `create-visit.component.ts` or the add-patient dialog —
  if the operator navigates away mid-fill, the quick-add form state is
  lost.
- **Per-company hidden/required fields**: no dynamic-field/config-driven
  form logic found in the clinic add-patient dialog (it's a fixed
  4-field reactive... actually plain `ngModel`-bound template form, not
  even a `FormGroup` — see `create-visit.component.ts:180-183`, plain
  component properties, not a reactive form). No per-company
  visibility/requiredness config wired in.
- **For comparison — the BE/entity clearly supports much richer data**:
  the sibling LIS patient model
  (`src/app/core/models/lis-patient.model.ts`, `CreateLisPatient`
  interface) accepts `name, name_ar, date_of_birth, gender, national_id,
  national_id_type, passport_country, phone, phone_country_code, email,
  address, address_ar, blood_group, insurance_info, medical_history,
  partner_id, is_active` via `POST lis/patients`
  (`src/app/core/services/lis-patient.service.ts:68`). Since clinic and
  LIS share the "core=one" patient entity (per project memory:
  patient=shim), the gap is purely in the **clinic FE's** quick-add
  dialog exposing only 4 of ~16 supported fields — not a BE limitation.
  م3 should very likely reuse `POST clinic/patients` (or route through
  the LIS-equivalent richer payload) with a properly expanded form.

---

## 3. Patient-search typeaheads — duplicated, NOT unified

**Three separate, independently-implemented typeahead components**
across clinic screens, each with its own signals/subject/debounce
wiring (no shared "patient-search" component or service call
convention):

1. **`CreateVisitComponent`** (routed, live, `clinic/booking`)
   `src/app/features/clinic/booking/create-visit.component.ts`
   - State: `patientSearchQuery` (136), `patientResults` (137),
     `patientSearching` (138), `patientSearch$` Subject (139)
   - Debounce wiring: lines 380-397 (350ms, `distinctUntilChanged`)
   - Calls: **`ClinicBookingService.searchPatients(q)`** (line 388)
   - Input binding:
     `create-visit.component.html:19-20`
   - Selection: `selectPatient()` (434), `clearPatient()` (440)

2. **`ReceptionBookingComponent`** (⚠️ **unrouted/dead**, see §1)
   `src/app/features/clinic/booking/reception-booking.component.ts`
   - State: `patientQuery` (76), `patientSuggestions` (77),
     `patientSearchLoading` (78), `patientPanelOpen` (79),
     `patientSearch$` (84)
   - Debounce wiring: lines 168-174 (300ms)
   - Calls: **`ClinicBookingService.searchPatients(q)`**
     (`reception-booking.component.ts:195`) — same service as #1, but
     re-implements its own subject/debounce/signal plumbing from
     scratch.
   - Input binding: `reception-booking.component.html:22-23`
   - Selection: `pickPatient()` (line 191)

3. **`ReceptionOrderComponent`** (routed, live, `clinic/reception`,
   gated `clinic.orders.view`)
   `src/app/features/clinic/reception/reception-order.component.ts`
   - State: `patientQuery` (104), `patientSuggestions` (105),
     `patientSearchLoading` (106), `patientPanelOpen` (107),
     `patientSearch$` (110) — near-identical signal names to #2 (likely
     copy-pasted) but a **third, independent implementation**.
   - Debounce wiring: lines 174-179 (300ms)
   - Calls: **`ClinicPatientService.search(q)`** (line 220) — a
     *different* service than #1/#2 (`ClinicPatientService.search()`
     vs `ClinicBookingService.searchPatients()`), even though both hit
     effectively the same `GET clinic/patients?q=` endpoint
     (`clinic-patient.service.ts:75-78` vs
     `clinic-booking.service.ts:85-88` — both construct
     `HttpParams().set('q', q).set('per_page', 25)` against the same
     base URL, duplicated verbatim).
   - Input binding: `reception-order.component.html:31-32`
   - Selection: `pickPatient()` (231)

**Summary**: 3 component-level implementations, 2 different backing
services (`ClinicBookingService.searchPatients` vs
`ClinicPatientService.search`) that both call the identical
`GET clinic/patients?q=&per_page=25` endpoint with duplicated query-param
code. One of the three call sites (`ReceptionBookingComponent`) isn't
even reachable via routing. م3's "unify the typeaheads" goal should:
(a) delete or resurrect+dedupe `reception-booking.component.ts`, (b)
collapse the two services down to one (`ClinicPatientService.search`
looks like the more focused/correct home — keep it, delete
`ClinicBookingService.searchPatients`), (c) extract a shared
`<app-patient-search>` component so booking + reception don't hand-roll
signal/debounce/subject plumbing 3x.

---

## 4. Doctors screen (`clinic-doctors.component`) — CRUD today

`src/app/features/clinic/doctors/clinic-doctors.component.ts` +
`.html`, routed at `clinic/doctors`
(`clinic.routes.ts:48-54`, gated `clinic.doctors.view`).

**Confirmed: Add + Edit-Identity ONLY. No full edit, no delete, no
disable/enable toggle.**

- **Create** — `openAddDialog()` (177-187) → `onAddSave()` (189-228)
  → `ClinicDoctorService.create()` → `POST lis/doctors`
  (`clinic-doctor.service.ts:129-131`). Form fields
  (`initAddForm()`, lines 102-113): `name_ar, name_en, phone
  (required), specialization, email, license_number, code,
  department_id`. Code auto-suggested via `GET lis/doctors/next-code`
  (`openAddDialog()` line 180, `doctorService.nextCode()`).
- **Edit — IDENTITY ONLY** — `openIdentityDialog(doctor)` (234-242) →
  `onIdentitySave()` (244-284) → `ClinicDoctorService.updateIdentity()`
  → `PUT clinic/doctors/{id}/identity`
  (`clinic-doctor.service.ts:141-146`). Form fields
  (`initIdentityForm()`, lines 115-121): **only** `grade_id,
  employee_id, department_id`. Cannot edit name, phone, specialization,
  email, license_number, or code once created.
- **No delete**: `ClinicDoctorService` (full file read,
  `services/clinic-doctor.service.ts`) exposes **no `delete()` method
  at all** — only `listAll`, `create`, `nextCode`, `updateIdentity`,
  `grades`, `employees`, `departments`. Nothing to call even if a UI
  button existed.
- **No disable/deactivate**: `ClinicDoctor.is_active` (model field,
  `clinic-doctor.service.ts:41`) is rendered **read-only** as a
  `p-tag` status badge in the table
  (`clinic-doctors.component.html:99-103`) — confirmed via
  `grep -n "pButton\|Delete\|Deactivate\|is_active\|(click)"` over the
  full HTML: the only interactive row action is the identity-edit
  button (`clinic-doctors.component.html:105-118`, single
  `<p-button icon="pi pi-id-card">` gated `*appCan="'clinic.doctors.update'"`
  calling `openIdentityDialog(doctor)`). No action toggles
  `is_active`, no delete icon, no row menu.
- Table columns present (`clinic-doctors.component.html:44-55`): #,
  code, name (+secondary bilingual name), specialization, grade,
  department, linked employee, status, actions.

**م3 "doctors file" gap = full CRUD**: needs (1) a full-edit dialog
covering name/phone/specialization/email/license_number/code (currently
locked after create), (2) delete or soft-delete/deactivate action wired
to a new BE endpoint + FE service method, (3) possibly a dedicated
doctor-file/profile view (the memory note calls this "ملف الدكتور").

---

## 5. Design identity — shared components + reference to clone

- **`PageHeaderComponent`** — `src/app/shared/components/page-header/`
  (exported via `src/app/shared/index.ts:1`). Used as
  `<app-page-header title="..." subtitle="..." (refresh)="...">` with
  a projected action button, e.g.
  `clinic-doctors.component.html:6-16`.
- **`FormDialogComponent`** — `src/app/shared/components/form-dialog/`
  (exported `src/app/shared/index.ts:3`). Used as
  `<app-form-dialog [(visible)]="..." [header]="..." [saving]="..."
  [width]="'600px'" (save)="...">` wrapping a `[formGroup]` reactive
  form with `.form-row` / `.form-field` layout classes — see the doctors
  Add dialog (`clinic-doctors.component.html:136-203`) and Edit-Identity
  dialog (lines 208-onward). This is the standard dialog shell to reuse
  for any patient-file add/edit form in م3 (note: `create-visit`'s
  quick-add patient dialog does NOT use `app-form-dialog` — it uses a
  raw `<p-dialog>` with plain `ngModel` fields, a lighter/older pattern;
  `app-form-dialog` + reactive `FormGroup` is the more current,
  preferred convention per the doctors screen).
- **Teal theme**: defined as CSS custom properties in
  `src/app/features/clinic/shared/clinic-patient-header/clinic-patient-header.component.scss:11-13`:
  `--teal: #0f766e; --teal-d: #0b5a53; --teal-l: #14b8a6;`. Same
  palette is reused across `clinic-layout`, `create-visit`,
  `cashier-collect`, `pricing-matrix`, `revenue-split`,
  `clinic-reports`, `dashboard`, encounter sub-panels
  (diagnosis/history/vitals/prescription/orders), etc. — confirmed via
  `grep -rln teal features/clinic/` (20 files).
- **Best reference component to clone for a patient-file screen**:
  **`ClinicPatientHeaderComponent`**
  (`src/app/features/clinic/shared/clinic-patient-header/`,
  91-line TS / 186-line HTML / 334-line SCSS). It's the existing
  "sticky patient summary" surfaced on `reception-order` and
  `consultation` (encounter) screens, already rendering demographics,
  chronic conditions, allergies, current meds, insurance, balance,
  last-visit, last-labs, pregnancy GPA, and active-visit state, styled
  in the teal palette. A full patient-file screen for م3 is a natural
  superset of this component — same visual language, same
  `ClinicPatientHeaderSummary` data shape
  (`clinic-patient.service.ts:33-54`) to start from, extended with
  edit capability.

---

## File index (all paths absolute, repo root
`/home/moonui/public_html/moon-erp`)

- `src/app/features/clinic/clinic.routes.ts`
- `src/app/features/clinic/booking/create-visit.component.ts` (+ .html)
- `src/app/features/clinic/booking/reception-booking.component.ts` (+ .html) — dead/unrouted
- `src/app/features/clinic/reception/reception-order.component.ts` (+ .html)
- `src/app/features/clinic/services/clinic-patient.service.ts`
- `src/app/features/clinic/services/clinic-booking.service.ts`
- `src/app/features/clinic/services/clinic-doctor.service.ts`
- `src/app/features/clinic/doctors/clinic-doctors.component.ts` (+ .html)
- `src/app/features/clinic/shared/clinic-patient-header/clinic-patient-header.component.ts` (+ .html/.scss)
- `src/app/shared/components/page-header/`
- `src/app/shared/components/form-dialog/`
- `src/app/shared/index.ts`
- `src/app/core/models/lis-patient.model.ts` (comparison — richer entity fields already supported BE-side)
- `src/app/core/services/lis-patient.service.ts` (comparison — full CRUD incl. delete)
