197 lines
16 KiB
Markdown
197 lines
16 KiB
Markdown
# UI phases — giving Balinyaar the interface its product deserves
|
||
|
||
**Created:** 2026-07-16 · **Scope:** `client/` only (frontend track) ·
|
||
**Method:** a 15-agent parallel design audit over every UI surface of the client (theme/tokens, shells,
|
||
component primitives, feature widgets, auth, storefront, booking, checkout/money, account, nurse workspace,
|
||
nurse trust/ops, admin/partner, messaging/notifications, cross-cutting UX patterns, fa/en microcopy).
|
||
The full per-area findings — with file/line evidence — live in [`audit/`](audit/).
|
||
|
||
This directory is a **runnable chain of 14 UI phases** (0–13) that takes the client from *"feature-complete
|
||
but visually a default-MUI starter"* to *"a designed, branded, Persian-native product."* The functionality is
|
||
already there — this chain is about **look, feel, hierarchy, trust presentation, mobile/RTL/Persian
|
||
nativeness, and the UX defects the audit surfaced along the way.** Run the phases **in order, one at a time**,
|
||
pointing a fresh agent at one phase file (*"Execute `dev/post-phase/ui/ui-phase-0-design-language.md` end to
|
||
end"*). After phases 0–2, most later phases touch disjoint route trees and can be parallelized if you accept
|
||
some risk; the recommended path is sequential.
|
||
|
||
> **Relation to the other chains.** The [refinement chain](../refinement/README.md) made the app *work* as one
|
||
> integrated system (it is complete). This chain makes it *feel* like a product. It deliberately does **not**
|
||
> touch `server/` — where a UI improvement needs a backend change, the phase files a REQ in
|
||
> [`for-backend.md`](../../shared-working-context/frontend/requests/for-backend.md) and builds mock-tolerant
|
||
> UI behind the existing `services/{domain}` seams (REQ-001…038 are taken; number onward from there).
|
||
|
||
---
|
||
|
||
## What is already good (do not regress it)
|
||
|
||
The audit found the feature layer unusually disciplined. Every phase must preserve:
|
||
|
||
1. **Token discipline** — 331 `var(--bal-*)` usages across 103 files, effectively **zero hard-coded hexes**
|
||
in feature code. The two-layer token system (`tokens.css` ↔ `colors.ts`) works; extend it, never bypass it.
|
||
2. **The four-state data pattern** — skeleton → error-with-retry → empty → data is genuinely implemented on
|
||
most feature pages (search results, earnings, verification, tickets…). The gaps are enumerated per phase.
|
||
3. **RTL as a habit** — logical properties (`borderInlineStart`, `textAlign: 'start'`, `marginInline*`),
|
||
deliberate `dir="ltr"` islands for phone numbers/IBANs/clocks, RTL-mirrored message bubbles.
|
||
4. **Persian correctness plumbing** — `utils/money.ts` (BigInt IRR, Toman-at-the-boundary, fa digit
|
||
grouping), `utils/date.ts` (Shamsi via `Intl` `fa-IR-u-ca-persian`), locale digits in counts and pagers.
|
||
5. **Product-honesty components** — `EscrowNotice` (product-mandated verbatim copy), `RefundEtaBanner`'s
|
||
honest BNPL 7–10-day window, `TrustBadge`'s three honest states, EVV's advisory-never-blocking semantics,
|
||
the two-stage clinical/address disclosure gates, negative-balance "owed back" rendering.
|
||
6. **The architecture seams design work needs** — the `AppIcon` string registry (one-file icon swap), the
|
||
per-actor shell split (`CustomerLayout`/`NurseLayout`/`AdminLayout`/`PartnerLayout`), component defaults in
|
||
`components/config.ts`, the `services/{domain}` mock seams, the admin composite layer
|
||
(`AdminDataTable`/`ConfirmDialog`/…), optimistic ticket send with `clientMessageId` reconciliation.
|
||
7. **Copy that is already right** — the escrow/payout/refund explainers, the culturally-tuned gender copy,
|
||
the formal-شما register, specific actionable verification-failure reasons.
|
||
|
||
---
|
||
|
||
## What is actually wrong (the problem inventory)
|
||
|
||
Every item is verified in code; file/line evidence is in [`audit/`](audit/) and repeated in the phase files.
|
||
|
||
### A. The starter is still the face of the app
|
||
- `createTheme` has **zero `components` overrides** (`theme/theme.ts`) — every Button/Card/TextField/AppBar/
|
||
Chip/Dialog/Stepper renders stock Material with recolored primaries. This alone is most of the
|
||
"old MUI beginner example" feel.
|
||
- The **brand logo is the starter's Twemoji cartoon pencil** (`AppIcon/icons/PencilIcon.tsx`), rendered at
|
||
56px on the auth screens and in every top bar. The seed-deck mark (deep-teal square, cream glyph,
|
||
terracotta dot) was never built.
|
||
- The nurse/admin/partner chrome is the untouched starter shell: solid-primary fixed `TopBar` with a static
|
||
centered label, flat 10-item sidebar whose **active highlight never fires** (locale-prefix bug in
|
||
`SideBarNavItem`), a permanent `UserInfo` placeholder ("Current User" / "Loading..." in English), physical
|
||
`paddingLeft/Right` RTL hazards, and a desktop SSR mobile-first flash.
|
||
- The login page — the only front door — is wrapped in starter dashboard chrome titled **"Unauthorized -
|
||
Balinyaar"** in English; `ErrorBoundary` is unstyled English with a raw stack dump; `globals.css` is the
|
||
starter reset; `light.ts`/`dark.ts` are dead starter themes still exported.
|
||
|
||
### B. The design system is missing a layer
|
||
- MUI palette has **no success/error/warning/info**, so inline alerts show stock MUI green/red while toasts
|
||
show brand `--bal-*` colors — two feedback systems for one semantic state.
|
||
- **Persian typography is Roboto metrics**: non-zero letter-spacing on a joined script, tight heading
|
||
line-heights that clip Persian ascenders, requested weight 600 that Mikhak doesn't load (renders 700), an
|
||
EN brand font declared but never wired.
|
||
- Tokens cover **color only** — no elevation/shadow (grey MUI shadows on warm cream), radius scale, motion,
|
||
or focus-ring tokens; exactly **one** `:focus-visible` style exists in the whole app.
|
||
- The icon registry mixes filled/outlined generations, has **no back/chevron icon at all**, and `AppIcon`'s
|
||
`size` prop is silently broken for MUI icons. `AppButton` ships a starter `margin: 1` default that 213
|
||
call-sites in 82 files neutralize with `sx={{ m: 0 }}`.
|
||
- Missing primitives pages keep hand-rolling: EmptyState/ErrorState (29 dashed-Paper copies in 23 files),
|
||
PageHeader, Money display, card anatomy (~12 hand-rolled Paper recipes), skeleton twins, relative time,
|
||
a `formatNumber` helper (the `fa-IR` ternary is copy-pasted 25+ times) — and **no Jalali date picker**,
|
||
so every date input in a Shamsi-displaying product is a native Gregorian `type="date"`.
|
||
- No route-level `loading.tsx`/`error.tsx`/`not-found.tsx` anywhere; one static `<title>` for ~60 routes.
|
||
|
||
### C. Trust surfaces undersell the product
|
||
Trust *is* the product, and the UI treats it generically: a bare login card with no trust presence; a static
|
||
✓ chip that never explains **what** was verified; a checkout whose total is a `subtitle2` row; a payment
|
||
confirmation with **no reference code**; a nurse verification journey with two competing progress metaphors;
|
||
a nurse public profile that doesn't answer "would I let this person into my mother's home?".
|
||
|
||
### D. Real UX defects found along the way (fixed by their area's phase)
|
||
The audit found genuine bugs beyond styling — the worst: a cancel-request dialog whose **dismiss button is
|
||
labeled with the destructive action**; the error→false-empty pattern (a failed query renders "you have no
|
||
patients/services/requests"); **no route to a customer's pending requests** (`useCustomerRequests` is wired
|
||
to nothing); **no sign-out anywhere in the customer shell**; `PublishGate`'s **fake success snackbar**;
|
||
bookings list unpaginated (booking #21 unreachable); the nurse day-of flow has **no address, no contact, no
|
||
navigation affordance**; `DocumentUpload`'s rejected-state re-upload shows no progress; partner booking
|
||
statuses render as raw English `snake_case`; admin actions target users by hand-typed numeric ID.
|
||
|
||
### E. Mobile-native and Persian-native gaps
|
||
No safe-area handling under the customer/nurse bottom navs; OTP inputs without `autocomplete="one-time-code"`
|
||
/ WebOTP in an OTP-first market; Gregorian date pickers everywhere; Latin digits in timers; fa catalog missing
|
||
ICU plural/zero forms («مشاهده ۰ پرستار»); desktop rendered as an 800px phone column with a mobile tab bar.
|
||
|
||
### F. Copy defects on trust-critical strings
|
||
The brand name is spelled two ways («بالین یار» vs «بالینیار»); تأیید appears with and without hamza (63
|
||
occurrences, both forms); grammar bugs sit on nurse-facing EVV errors and customer address hints; BNPL copy
|
||
uses banker's jargon (نکول) and one sentence states the **inverse** of the intended risk allocation;
|
||
policy numbers (72h dispute window, cancellation tiers) are hard-coded into copy the admin config can change.
|
||
|
||
---
|
||
|
||
## The 14 UI phases
|
||
|
||
Phases 0–2 build the foundation everything else composes from. Phases 3–11 are area redesigns over disjoint
|
||
route trees. Phase 12 is the closing sweep; phase 13 is optional and product-gated.
|
||
|
||
| # | Phase | Delivers | Depends on |
|
||
| --- | --- | --- | --- |
|
||
| **0** | [Design language & theme foundation](ui-phase-0-design-language.md) | brand mark, `theme.components` pass, semantic palette, Persian type scale, one icon family, token extension (elevation/motion/focus/rating/trust/money), starter purge | — |
|
||
| **1** | [Shared primitives & app-wide states](ui-phase-1-primitives-and-states.md) | EmptyState/ErrorState kit (+ error→false-empty fixes), PageHeader, card kit, `<Money>`, Jalali date picker, StatusChip v2, StatusTimeline, CountdownTimer v2, RatingInput v2, skeleton twins, route-level loading/error/404, per-route metadata, formatting utils | 0 |
|
||
| **2** | [Shells & navigation](ui-phase-2-shells-and-navigation.md) | locale-aware nav (`createNavigation`), contextual customer header + safe-area bottom bar, grouped nurse sidebar + nurse bottom nav + identity card, dense admin chrome, de-startered public shell, sign-out / role / locale switchers | 0, 1 |
|
||
| **3** | [Auth & first-run](ui-phase-3-auth-and-first-run.md) | trust-forward login hero, OTP autofill (WebOTP), terms/privacy consent + pages, illustrated select-role, focused onboarding wizard, returnUrl | 0–2 |
|
||
| **4** | [Customer storefront](ui-phase-4-customer-storefront.md) | home that sells, Shamsi date filter, sticky search CTA, honest results header + NurseResultCard v2, nurse profile as trust dossier + verification explainer | 0–2 |
|
||
| **5** | [Booking lifecycle](ui-phase-5-booking-lifecycle.md) | C4 trust-anchored request form, C5 countdown ring + recovery, customer requests tabs on /bookings, booking-detail hero + vertical timeline, cancel-flow fixes, review context | 0–2 (4 recommended) |
|
||
| **6** | [Checkout & money](ui-phase-6-checkout-and-money.md) | checkout hierarchy + sticky pay bar, receipt-grade confirmation, wallet as money hub, honest BNPL comparison, fiscal-grade invoice, designed wait states | 0–2 (5 recommended) |
|
||
| **7** | [Nurse daily ops](ui-phase-7-nurse-daily-ops.md) | the real nurse dashboard, visit workspace (address/contact/EVV-first), decision-first request inbox + urgency system, earnings clarity | 0–2 |
|
||
| **8** | [Nurse business & verification](ui-phase-8-nurse-business-and-verification.md) | activation checklist (honest PublishGate), unified verification journey, DocumentUpload fixes, variant-builder preview, coverage viz, bank flows, public-profile preview | 0–2 (4 for trust components) |
|
||
| **9** | [Customer account & care circle](ui-phase-9-customer-account-and-care-circle.md) | profile as account hub (+ sign-out entry), care-circle reframe with avatars, per-item care-record editing, real map picker, mobile full-screen forms | 0–2 |
|
||
| **10** | [Messaging & notifications](ui-phase-10-messaging-and-notifications.md) | chat-grade ticket threads (live, scrolled, grouped), inbox pagination/filters, right-sized emergency affordance, notification center grouping + bell popover | 0–2 |
|
||
| **11** | [Admin & partner console](ui-phase-11-admin-and-partner-console.md) | URL-synced list state, user/nurse pickers (no raw IDs), verification desk, ticket console lifecycle, AdminDataTable v2, Jalali inputs, partner localization | 0–2 |
|
||
| **12** | [Copy, motion & final polish](ui-phase-12-copy-motion-and-polish.md) | Persian style guide + catalog sweep, ICU plurals, trust-moments copy, config-served policy numbers (REQ), motion pass, a11y sweep, 4-axes QA | all prior |
|
||
| **13** | [Public front door](ui-phase-13-public-front-door.md) *(optional)* | public landing, how-it-works, SEO/metadata/OG, guest-browse decision (+ public-endpoint REQs) | 0–2 · product decision |
|
||
|
||
### Dependency & sequencing
|
||
|
||
```
|
||
Foundation (strictly in order):
|
||
0 design language ──► 1 primitives & states ──► 2 shells & navigation
|
||
|
||
Area redesigns (after 0–2; sequential recommended, parallel possible across disjoint trees):
|
||
3 auth/first-run
|
||
4 storefront ──► 5 booking ──► 6 checkout/money (the customer funnel, in funnel order)
|
||
4 ──────────────► 8 nurse business & verification (reuses phase 4's trust components)
|
||
7 nurse daily ops
|
||
9 customer account · 10 messaging/notifications · 11 admin/partner
|
||
|
||
Closing:
|
||
12 copy, motion & polish (last — sweeps everything the earlier phases touched)
|
||
13 public front door (any time after 0–2; needs a product decision on guest browse)
|
||
```
|
||
|
||
**Ownership rules that keep parallel runs safe:** phase 0 owns `theme/`, `AppIcon`, `AppButton`, the brand
|
||
mark; phase 1 owns every *shared* primitive (`StatusChip`, `CountdownTimer`, `RatingInput`, `StepperHeader`
|
||
usage, state views, `<Money>`, the Jalali picker); phase 2 owns `layout/`. Later phases **consume** these and
|
||
own only their route tree plus the feature components that belong to it (e.g. `NurseResultCard` → 4,
|
||
`BookingRequestSummaryCard` → 5, messaging composites → 10). If a later phase finds a foundation gap, it
|
||
extends the foundation file *minimally* and notes it in its report — it does not fork a local variant.
|
||
|
||
**Minimum path to "the app suddenly looks designed":** phases **0 → 1 → 2**. Those three de-starter every
|
||
screen at once (theme pass + primitives + chrome); phases 3–11 are then per-area redesigns on a system that
|
||
already looks right.
|
||
|
||
---
|
||
|
||
## How the phase files are written
|
||
|
||
Each file follows the repo's [phase template](../../phases/_shared/phase-template.md): a one-paragraph
|
||
mission, context (what already exists — don't rebuild), required reading (including the relevant
|
||
[`audit/`](audit/) files, which carry the full evidence), enumerated scope with file paths, the mocks/REQ
|
||
posture, the invariants it must not break (including the area's **do-not-regress** list), a Definition of
|
||
Done, concrete how-to-test steps across the four axes (`/fa` + `/en` × light + dark, mobile + desktop), and a
|
||
close-out (docs + report + memory).
|
||
|
||
Non-negotiables for every phase (they restate them, but for the human reader):
|
||
|
||
- **Invoke the `frontend-designer` skill before any UI work** — it is the design contract (brand palette,
|
||
token rules, `App*` wrappers, icon registry, RTL/dark-mode/i18n rules).
|
||
- **`npm run check` green + `npm run test:ci`** when shared components change; new shared components get
|
||
co-located tests; `en.json`/`fa.json` stay in sync.
|
||
- **Frontend lane only.** Backend gaps become REQ entries in
|
||
[`for-backend.md`](../../shared-working-context/frontend/requests/for-backend.md), never edits to `server/`.
|
||
- **Verify visually on `/fa` first** — it is the default locale and RTL.
|
||
|
||
## Related documents
|
||
|
||
- [`audit/`](audit/) — the 15 per-area audit reports (current state, problems with evidence, opportunities,
|
||
keep-lists) this chain was synthesized from.
|
||
- [../refinement/README.md](../refinement/README.md) — the integration/production chain that preceded this
|
||
one (complete).
|
||
- [../../phases/_shared/agent-operating-rules.md](../../phases/_shared/agent-operating-rules.md) — how an
|
||
executing agent works a phase; every phase file links it.
|
||
- [.claude/skills/frontend-designer/SKILL.md](../../../.claude/skills/frontend-designer/SKILL.md) — the
|
||
design contract this chain builds on (and extends: phase 0 updates it when tokens/icons change).
|
||
- [../../shared-working-context/frontend/requests/for-backend.md](../../shared-working-context/frontend/requests/for-backend.md)
|
||
— the REQ tracker; UI phases append REQ-039+ here.
|