frontend phase 12

This commit is contained in:
hamid
2026-07-10 14:48:15 +03:30
parent 67c028562e
commit 6186f54294
34 changed files with 2363 additions and 1 deletions
@@ -12,6 +12,31 @@ for awareness.
- **Requests filed:** frontend/requests/for-backend.md (yes/no)
-->
## frontend-phase-12-b13 — Nurse earnings & payout history — 2026-07-10
- **Shipped:** the **last money-path frontend phase** — the read-only **nurse earnings** surface. A **new
`services/payouts` domain** (types/keys/constants/apis[client+mock]/4 read-only hooks + hooks-only barrel)
and three nurse screens under the nurse shell: **`/nurse/earnings`** (net payable balance + four-bucket
breakdown + a plain-Persian cadence/dispute-window explainer + a state-segmented earnings list), **`/nurse/
earnings/payouts`** (payout history list), and **`/nurse/earnings/payouts/[id]`** (payout/batch reconciliation
detail — money decomposition + masked IBAN + transfer ref + the exact bookings covered). Three shared tested
composites: **`EarningsBalanceHeader`** (net balance with an explicit **negative "owed back"** state — never a
bare minus), **`EarningsRow`** (three-amount `gross commission = your payout` breakdown via `PriceBreakdown`
+ one of four visually-distinct state chips + state affordance: pending shows a **display-only** dispute-window
countdown reusing `CountdownTimer`), **`PayoutHistoryRow`** (net transferred + status chip + masked IBAN +
failure banner). Deep-links to the f8 booking detail (`/nurse/visits/{id}`); the `earnings` nav item +
`PaidOutlined` icon + a `payouts` i18n namespace (82 keys, both locales in sync) added. **Strictly read-only**
— no transfer/retry/batch/mutation; a failed payout shows its reason with **no retry** (admin action). Money is
IRR digit-strings via the f0 money util (`gross = commission + payout`; the BNPL provider commission never
appears); eligibility/dates/amounts are server truth (never computed client-side).
- **Consumes:** dev/contracts/domains/payouts.md (backend phase b13) — only `GET api/v1/nurse_payouts/history`
maps a live nurse route; the summary/earnings-list/nurse-payout-detail are contract gaps (REQ-025).
- **Mocked client-side:** `services/payouts` via `payoutsMockApi` (`USE_PAYOUTS_MOCK=true`) — self-contained,
money-correct fixtures covering all four earnings states + all four payout statuses + a `failed` payout + a
**negative net balance** (`MOCK_SCENARIO='clawback_heavy'`). Swap is one flip once REQ-025 lands.
- **Gate:** npm run check green · npm run test:ci green (242 tests, +3 suites) · npm run build green with
NEXT_PUBLIC_API_URL set.
- **Requests filed:** frontend/requests/for-backend.md — yes (REQ-025).
## frontend-phase-11-b12 — BNPL installment checkout (D1D5) — 2026-07-10
- **Shipped:** the **alternate checkout branch** off C6 — a **new `services/bnpl` domain** (types/keys/
constants/invalidations/apis[client+mock]/7 hooks + barrel) and the five wireframe screens under the
@@ -379,3 +379,37 @@ delivers fixes in its own change. **Frontend never edits backend code to "fix" a
behind the `services/bnpl` seam (seeded plan + a plan pushed on each settled checkout). When it lands the
swap is one config flip.
- **Status:** open
## REQ-025 — Nurse-read earnings surface: four-bucket balance + per-booking earnings list + nurse payout detail — filed by frontend-phase-12-b13 — 2026-07-10
- **Need:** b13 serves the nurse exactly one endpoint (`GET api/v1/nurse_payouts/history``NursePayoutHistoryDto`).
The f12 earnings screen needs three more **nurse-scoped, read-only** reads (all tenancy-scoped to the caller):
1. **Earnings balance (four buckets + signed net)** — proposed `GET api/v1/nurse_payouts/earnings_balance`
`{ pendingTotalIrr, eligibleTotalIrr, paidTotalIrr, clawbackOutstandingIrr, netPayableBalanceIrr }`.
`netPayableBalanceIrr` is the **ledger-derived, SIGNED** payable balance (may be **negative** = "owed back";
never clamp). `paidTotalIrr` is a lifetime total and does **not** enter the net balance.
2. **Per-booking earnings list + money-state** — proposed
`GET api/v1/nurse_payouts/earnings?state=&page=&pageSize=``PagedResult<NurseEarningsItem>` where
`NurseEarningsItem = { bookingId, patientName, scheduledDate, grossPriceIrr, balinyaarCommissionIrr,
nursePayoutAmount, state: 'pending'|'eligible'|'paid'|'clawback_applied', disputeWindowEndsAt?,
payoutEligibleAt?, paidAt?, transferReference?, nursePayoutId?, batchId?, clawbackAppliedIrr?, netAmountIrr? }`.
`state` is derived **server-side** from `bookings.status` + `dispute_window_ends_at < now` + the payout link +
any clawback (the client must never compute eligibility). Filterable by `state`.
3. **Nurse-readable payout detail (batch context + booking links)** — proposed
`GET api/v1/nurse_payouts/{id}` → a nurse-scoped analogue of the admin `PayoutBatchDetailDto`/`PayoutDto`:
`{ id, batchId, status, grossEarningsIrr, clawbackAppliedIrr, netAmountIrr, amountIrr, maskedIban,
transferReference?, paidAt?, failureReason?, batch: { id, periodStart, periodEnd, processingDate, status,
totalAmount, payoutCount, processedAt? }, bookings: PayoutBookingLinkDto[] }`. The admin `batches/{id}` detail
is admin-only; a nurse needs to reach **their own** payout's batch window + covered bookings for reconciliation.
4. **`failureReason` on the nurse history DTO** — `NursePayoutHistoryDto` has no `failureReason` (it's on the
admin `PayoutDto`). A `failed` payout in the nurse history should carry its reason so the read-only failure
banner can show it (the nurse cannot retry — retry stays an admin action).
- **Why:** the f12 nurse earnings screen (`services/payouts`) renders the net payable balance + four-bucket
breakdown, the state-segmented earnings list (pending/eligible/paid/clawback_applied), and the payout/batch
reconciliation detail. Only `getNursePayoutHistory` maps a live route; the other three are mocked behind the
`PayoutsApi` seam (real-shaped fixtures covering all four states + a negative net balance + a failed payout).
`payoutsClientApi` already targets the proposed slugs — when these land the swap is a single
`USE_PAYOUTS_MOCK=false` flip; no hook/component change.
- **Note (money invariants the server owns):** `gross_price_irr = balinyaar_commission_irr + nurse_payout_amount`;
`net_amount = gross_earnings clawback_applied`; a payout's booking-link `payout_amount_irr` sum = its
`gross_earnings_irr`; the nurse amount is **payment-method-invariant** (BNPL provider commission never deducted).
- **Status:** open