Files
baya-monorepo/dev/post-phase/ui/README.md
T
2026-07-17 13:22:04 +03:30

197 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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** (013) 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 02, 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 710-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 02 build the foundation everything else composes from. Phases 311 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 | 02 |
| **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 | 02 |
| **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 | 02 (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 | 02 (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 | 02 |
| **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 | 02 (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 | 02 |
| **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 | 02 |
| **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 | 02 |
| **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) | 02 · product decision |
### Dependency & sequencing
```
Foundation (strictly in order):
0 design language ──► 1 primitives & states ──► 2 shells & navigation
Area redesigns (after 02; 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 02; 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 311 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.