ui phase 7

This commit is contained in:
hamid
2026-07-19 11:56:59 +03:30
parent a438edeeaa
commit edc38543fd
39 changed files with 1538 additions and 208 deletions
@@ -776,3 +776,87 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
- **Proposed shape:** as above.
- **Status:** open — invoice renders the reconciling money breakdown + مودیان status unconditionally; the
three new rows render only when served.
## REQ-050 — Nurse inbox decision data: `variantLabel`/`variantPrice`/`variantPriceUnit` on `BookingRequestListItemDto` + an `answered` status-group filter — filed by ui-phase-7 — 2026-07-19
- **Need:** Two additions to the nurse's `booking_requests/list` row:
1. `variantLabel: string`, `variantPrice: string` (IRR digit-string), `variantPriceUnit: PriceUnit` — the
same three fields the single-request `BookingRequestDto` already carries, just missing from the list
row.
2. Optionally, a status-**group** filter value (e.g. `status=answered`) that server-side unions
`accepted_awaiting_payment | converted | rejected_by_nurse` in one paginated query.
- **Why:** The redesigned inbox (phase §3.4) leads every card with the service + price — the decision-critical
facts — instead of only patient/time/gender. The list DTO has neither field today (confirmed against
`services/bookingRequests/types.ts`), so the client falls back to the patient-name headline when absent
(mock-tolerant; only the mock's `toListItem` stamps them for now). Separately, the «پاسخ‌داده» tab wants
"every request I've already acted on" in one page, but the API filters by a *single* status — the client
currently works around this by firing three page-1 queries (`accepted_awaiting_payment`/`converted`/
`rejected_by_nurse`) and concatenating them client-side, which is both an N+1-ish fan-out and page-1-only
(a nurse with >20 answered-per-status rows can't page into the rest). A `status=answered` value would
collapse this to one real paginated query.
- **Proposed shape:** `BookingRequestListItemDto { …, variantLabel: string, variantPrice: string,
variantPriceUnit: PriceUnit }`; `booking_requests/list?status=answered` as an accepted alias alongside the
existing single-status values.
- **Status:** open — the mock demonstrates the redesigned card (flip `USE_BOOKING_REQUESTS_MOCK=true`); the
real path degrades to the patient-name headline and the three-query «پاسخ‌داده» workaround (documented,
page-1-only) until delivered.
## REQ-051 — Nurse-view address on confirmed+ bookings — filed by ui-phase-7 — 2026-07-19
- **Need:** Serve `addressSnapshotJson` (or a nurse-shaped subset including `latitude`/`longitude`) to the
**assigned nurse** on `BookingDetailDto` once `status ∈ {confirmed, in_progress, completed, disputed,
closed}` — today it is unconditionally masked to `null` for the nurse view (two-stage disclosure correctly
keeps it masked pre-confirmation, but the mask never lifts post-confirmation either).
- **Why:** The visit-detail address card (phase §3.3) — the "where do I go" a field nurse needs on a
confirmed visit, with a `geo:`-URI map deep-link — has nothing to render on the real path once the booking
is paid and assigned. The mock now simulates the delivered behavior (`isBookingConfirmedOrBeyond` gates the
masking instead of an unconditional nurse-view null) so the card is demonstrable
(`USE_BOOKINGS_MOCK=true`); the real `bookingsClientApi` still receives `null` from the server regardless
of status, so the nurse UI shows a quiet "available after confirmation" note instead of a hard error or a
fabricated address. Also open: whether `recipientPhone` should join the same post-confirmation nurse view
(a "call the family" affordance beyond the emergency-contact `tel:` the care-instructions read already
provides via `BookingSupportEntry`/`EmergencyBanner`) — flagging for a product decision, not assuming yes.
- **Proposed shape:** no DTO shape change — just relax the server-side masking rule on the existing
`addressSnapshotJson` field, conditioned on `status` + assigned-nurse tenancy. If a typed shape lands per
REQ-045, include `latitude`/`longitude` in it (the map link is presently a best-effort parse of whatever
keys the snapshot JSON happens to carry).
- **Status:** open — mock-verified only; the real nurse view stays masked (quiet fallback note, no crash)
until delivered.
## REQ-052 — Service label on the today feed — filed by ui-phase-7 — 2026-07-19
- **Need:** A `variantLabel: string` field on each `booking_sessions/today` row (`BookingSessionListItemDto`).
- **Why:** The day surface (phase §3.2) now renders the service under the patient name on every session card
— the "what job is this" a nurse currently only learns by opening the full booking detail. The row has no
service/variant field today (confirmed against `services/bookings/types.ts`); the client renders it only
when present (mock-tolerant) and deliberately does **not** fetch the booking detail per row to fake it (that
would be an N+1 against a list endpoint). The mock stamps it from the seeded booking's frozen variant
snapshot.
- **Proposed shape:** `BookingSessionListItemDto { …, variantLabel: string }`.
- **Status:** open — the mock demonstrates it; the real today feed renders patient name + visit index only
until delivered.
## REQ-053 — Payout forecast: next batch date + expected eligible amount — filed by ui-phase-7 — 2026-07-19
- **Need:** Two additions to the nurse earnings-balance read (the REQ-025 summary shape, or a new field on
whichever endpoint eventually serves it): `nextPayoutDate: string` (`YYYY-MM-DD`, holiday-shifted
server-side) and `nextPayoutEligibleAmountIrr: string` (the amount that batch would pay, ledger-derived).
- **Why:** The earnings screen's «برداشت بعدی» line (phase §3.5) and the dashboard's earnings snapshot answer
the one question nurses actually ask ("when do I get paid, how much") instead of only the four abstract
buckets. Holiday shifting and eligibility are backend truth (per the domain's own load-bearing rule — the
client must never compute them); the mock picks a plausible next-batch date (+3 days) and reuses the
currently-`eligible` bucket as the forecast amount, both marked optional on the type so the real path
(which doesn't serve them yet) renders nothing rather than a fabricated forecast.
- **Proposed shape:** `NurseEarningsSummaryDto { …, nextPayoutDate: string, nextPayoutEligibleAmountIrr:
string }` (nullable until the first batch is computed, e.g. a brand-new nurse with no eligible earnings).
- **Status:** open — mock-only; the forecast line renders nothing on the real path (never computed
client-side) until delivered. Folds into REQ-025's existing summary gap.
## REQ-054 — Web-push for new requests (DEFERRED, non-blocking) — filed by ui-phase-7 — 2026-07-19
- **Need:** Push-notification infrastructure (a service worker + a backend push rail behind
`INotificationDispatcher`'s deferred SMS/push channels) so a new booking request reaches a nurse whose tab
isn't open.
- **Why:** The nurse inbox polls every 15s (`BOOKING_REQUEST_POLL_MS`) but the response window is measured in
hours — a nurse who isn't looking at the tab when a request arrives can miss it entirely. This is a real,
acknowledged product gap (deadline-driven marketplaces live or die on this), but push infra (service-worker
registration, VAPID/FCM keys, the backend dispatch rail) is a substantial cross-cutting build in its own
right and explicitly out of scope for this phase.
- **Proposed shape:** n/a — filed to put the need on record, not to propose an endpoint shape yet.
- **Status:** deferred, non-blocking — build nothing for it this phase; the 15s poll remains the only
freshness mechanism.