Files
baya-monorepo/dev/shared-working-context/frontend/STATUS.md
T
hamid 99ebf5d881 frontend phase 4: catalog browse (Home A5) & nurse service builder (B7)
Light up the two faces of the configurable service catalog over a new cached
services/catalog domain (consumes the b5 contract; unlocks f6 search).

- services/catalog: types/keys/constants/apis(client+mock+seam)/hooks/index +
  names.ts. Categories & option groups are session-cached reference data
  (Infinity staleTime, like geography); variant mutations invalidate
  myVariantsLists() and setQueryData the edited row. Mock-primary
  (USE_CATALOG_MOCK), one-line swap; mock reproduces the 400 missing-required
  and (nurse,category,option-set) 409 duplicate rules.
- Customer Home (A5): greeting+avatar, search bar (navigates toward f6),
  data-driven category grid (loading/empty/error), patient nudge from the
  cached f2 query. Deferred /search placeholder stub.
- Nurse Services & prices (B7) at /nurse/services: offerings list (active vs
  deactivated, edit, soft-deactivate w/ confirm, reactivate, no delete) and a
  3-step variant builder (category -> required/optional options -> price+unit+
  duration). Required-group gate; Toman->IRR digit-string at the field
  boundary (no float); live unit-aware estimated total (never from price
  alone); editable auto display_name; inline 409 duplicate warning; locked
  category edit form.
- Shared, tested components: CategoryTile, PriceDisplay, VariantCard. Money
  util: tomanToRial + multiplyIrr (integer-safe) + tests.
- i18n: catalog/services/search namespaces + home additions + nav.services
  (both locales, in sync). Icons, routes (SEARCH, NURSE_SERVICES), nurse nav.

Gate: npm run check green; npm run test:ci green (147 tests, +18 across 4
suites); npm run build green with NEXT_PUBLIC_API_URL set.

Docs: client/CLAUDE.md (Project Structure, caching note, namespaces), STATUS,
for-backend REQ-010 (pagination param casing), phase report, mocks registry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 17:33:44 +03:30

12 KiB

Frontend status log (append-only)

One block per completed frontend phase. Newest at the top. Frontend lane writes here; backend reads for awareness.

frontend-phase-4-b5 — Catalog browse (Home A5) & nurse service builder (B7) — 2026-07-05

  • Shipped: services/catalog domain (types/keys/constants/apis[client+mock+seam]/hooks/index) — the b5 catalog skeleton + nurse pricing layer. Hooks: useServiceCategories, useCategoryOptionGroups (both session-cached reference data, Infinite staleTime), useMyVariants (paginated, self-scoped), useCreateVariant/useUpdateVariant/useSetVariantActive (mutations invalidate catalogKeys.myVariantsLists(); update setQueryDatas the row). Shared composites (each tested): CategoryTile (data-driven Home tile + builder selected state), PriceDisplay (money-util Toman + i18n unit label + unit-aware estimated total), VariantCard (offering card, active/deactivated distinction, no delete). Money util gained tomanToRial (field-boundary Toman→IRR) + multiplyIrr (integer-safe estimate). Screens: customer Home (A5) — greeting + avatar, search bar (navigates toward f6 /search, results deferred), data-driven category grid (loading/empty/error), patient nudge (reuses cached f2 usePatients, no new fetch); nurse Services & prices (B7) at /nurse/services (new sidebar tab) — offerings list (active/inactive, edit, soft deactivate w/ confirm, reactivate, empty/skeleton) + 3-step variant builder (category → required/optional options → price+unit+duration; required-group gate; Toman→IRR digit-string submit; live unit-aware total; editable auto displayName; inline 409 duplicate warning; locked-category edit form). Added catalog/services/search i18n namespaces + home additions + nav.services (both locales); 7 icons (services,category,elderly,post_surgery,infant, chronic,companionship); routes SEARCH,NURSE_SERVICES; deferred /search placeholder stub (→ f6).
  • Consumes: dev/contracts/domains/catalog.md (backend-phase-5). Routes api/v1/catalog/{categories,option_groups}, api/v1/nurse_variants/{create,update/{id},set_active/{id},list,get/{id}}. Wire camelCase; price_unit enum; IRR-string money; 409 duplicate listing / 400 missing required dimension.
  • Mocked client-side: services/catalog via catalogMockApi behind USE_CATALOG_MOCK (default true) — seeds the 5 real b5 categories + representative option groups (incl. a cross-category one) + the 409/400 rules; variant store seeded empty so the offerings empty-state demos. Real catalogClientApi wired for a one-line flip. See mocks-registry + the report (note: the mock seeds option groups the fresh backend does not — an admin authors them).
  • Gate: npm run check green · npm run test:ci green (147 tests, +18 across 4 suites: catalog components + money) · npm run build green with NEXT_PUBLIC_API_URL set (routes /nurse/services, /search generated; home prerenders).
  • Requests filed: frontend/requests/for-backend.md — yes (REQ-010 confirm the list pagination query-param name pageSize vs the doc's page_size).

frontend-phase-3-b4 — Addresses, map picker & nurse coverage areas — 2026-07-03

  • Shipped: three domain services — services/geography (cached province→city→district reference lookups; Infinity staleTime + shared geographyKeys; useProvinces/useCities/useDistricts; seam+mock+client), services/addresses (address book CRUD + set-primary; single-primary invariant; every mutation invalidates the list; useAddresses/useCreateAddress/useUpdateAddress/useDeleteAddress/useSetPrimaryAddress), services/serviceAreas (coverage add/remove; areaExists dup-guard; useServiceAreas/useAddServiceArea/ useRemoveServiceArea). Shared composites (src/components/geography/, each tested): CascadingRegionSelect (drives the cached cascade), AddressMapPicker (map-pin stand-in emitting real lat/lng), AddressForm, AddressCard. Screens: customer address book (/addresses, reached from a profile-hub link — cascade + map pin dialog, set-primary, delete, empty/skeleton), nurse coverage editor (/nurse/coverage, new sidebar tab — chips, whole-city/specific-district scope toggle, inline duplicate block + 409, "won't appear in search" empty warning). Added geo/address/coverage i18n namespaces + nav.coverage (both locales); location/delete/coverage icons; routes ADDRESSES/NURSE_COVERAGE.
  • Consumes: dev/contracts/domains/geography-addresses.md (backend-phase-4). Routes api/v1/geo/{provinces, cities,districts}, api/v1/customer_addresses/{list,create,update,set_primary,delete}, api/v1/ nurse_service_areas/{list,add,remove}. Wire camelCase; geo query params snake_case; 409 on duplicate coverage.
  • Mocked client-side: services/geography (USE_GEOGRAPHY_MOCK), services/addresses (USE_ADDRESSES_MOCK), services/serviceAreas (USE_SERVICE_AREAS_MOCK) — all default true; real clients wired for a one-line flip. The AddressMapPicker is a stand-in (no real map tiles). See mocks-registry + the report.
  • Reviewed: 5-dimension adversarial review → 3 findings fixed (map marker RTL transform; page_sizepageSize pagination casing on the real list calls; coverage "districts" dead-end on a district-less city).
  • Gate: npm run check green · npm run test:ci green (129 tests, +17 across 5 suites) · npm run build green with NEXT_PUBLIC_API_URL set (routes /addresses, /nurse/coverage generated).
  • Requests filed: frontend/requests/for-backend.md — yes (REQ-008 accept the map pin on address create/update, REQ-009 provinceId on CustomerAddressDto for edit prefill).

frontend-phase-2-b3 — Onboarding & profiles (customer, patient, nurse, bank) — 2026-07-02

  • Shipped: three domain services — services/patients (rewritten to the b3 PatientDto + client-augmented relation/conditions; full CRUD seam + mock + real client; usePatients/useCreatePatient/ useUpdatePatient/useArchivePatient with optimistic soft-archive), services/profiles (customer + nurse profile get/upsert + avatar; useCustomerProfile/useUpsertCustomerProfile/useNurseProfile/ useUpsertNurseProfile/useUploadAvatar), services/nurse (bank accounts; useNurseBankAccounts with pending-only refetchInterval, useAddNurseBankAccount, useSetPrimaryBankAccount; iban.ts Sheba validate/normalize/bank-name). Screens: A3→A4 onboarding wizard ((customer)/onboarding), E1 patients list/CRUD (add/edit dialog reusing the A4 form, soft-archive confirm, empty + skeleton states), A5 Home (first-login redirect into onboarding when 0 patients + "complete patient record" nudge), customer profile (name + preferred language + emergency contact, no national-ID), nurse profile bootstrap (avatar + bio + years, unverified "not bookable" placeholder → verification), nurse bank settings (IBAN form + the three ownership states pending/verified/mismatch). Shared composites GenderToggle/ConditionChips/RelationSelect/ PatientForm/PatientCard/BankStatusPanel (each tested); reused the f0 StepperHeader/StatusChip/ PhoneNumberField. Added onboarding/home/profile/nurseProfile/bank i18n namespaces + patients extensions (both locales); --bal-primary-soft token (both schemes); nurse sidebar gains Profile + Bank.
  • Consumes: dev/contracts/domains/identity-profiles.md (backend-phase-3). Routes api/v1/{customer_profiles, nurse_profiles}/{me,upsert}, api/v1/patients/{list,get,create,update,archive}, api/v1/nurse_bank_accounts/ {list,add,set_primary,verify_ownership}.
  • Mocked client-side: services/patients (USE_PATIENTS_MOCK), services/profiles (USE_PROFILES_MOCK), services/nurse (USE_NURSE_BANK_MOCK) — all default true; real clients wired for a one-line flip. See mocks-registry + the report for exactly what/why (relation/conditions, avatar, customer name/language gaps).
  • Gate: npm run check green · npm run test:ci green (112 tests, +17) · npm run build green with NEXT_PUBLIC_API_URL set (routes /onboarding, /nurse/profile, /nurse/bank generated).
  • Requests filed: frontend/requests/for-backend.md — yes (REQ-005 patient relation/conditions, REQ-006 avatar upload route, REQ-007 customer name/preferred-language).

frontend-phase-1-b2 — Auth: phone-OTP login & role routing — 2026-07-02

  • Shipped: services/auth rewritten for phone-OTP (types/keys/apis[client+mock+seam]/hooks: useRequestOtp/useVerifyOtp/useMe/useRefresh/useLogout/useSelectRole/useSessionRoleSync) — the username/password stub is gone; A1/A2 customer login + B1/B2 nurse switch (one OTP flow parameterised by intended role) at /login; the role router (RoleRouter + pure resolveRoleDestination) → customer→family, nurse→nurse app, no-role→/select-role, admin→admin console (splash while /me loads, no wrong-shell flash); SelectRole screen at /select-role; silent token refresh in the fetch layer (single-flight attemptTokenRefresh, one retry on 401); widened AuthState (roles via SessionUser, hydrated from /me by useSessionRoleSync in the private layout); auth i18n namespace + common.brand* in both locales.
  • Consumes: dev/contracts/domains/identity-auth.md + openapi/swagger.v1.json (backend-phase-2). Wire is camelCase; routes api/v1/auth/{request_otp,verify_otp,refresh,logout}, api/v1/me, api/v1/me/select_role.
  • Mocked client-side: services/auth via authMockApi behind USE_AUTH_MOCK (default false — b2 is live; flip true for offline dev, dev code 123456). See mocks-registry.
  • Gate: npm run check green · npm run test:ci green (95 tests, +23) · npm run build green with NEXT_PUBLIC_API_URL set. Fixed the jest @/src alias (was <rootDir>/$1).
  • Requests filed: frontend/requests/for-backend.md — yes (REQ-002 OTP length/expiry, REQ-003 verify error codes + lockout retry-after, REQ-004 multi-role activeRole?).

frontend-phase-0 — Foundations: app shells, design system & data/contract patterns — 2026-07-02

  • Shipped: 3 actor shells (customer bottom-nav / nurse / admin sidebar) + role-aware routing under (private-routes); useActorRole; the services/{domain} reference (patients, mocked behind a seam) with deliberate Query caching + invalidation; lib/api/types.ts (envelope/pagination); money + Shamsi-date utils; shared composites OtpInput/PhoneNumberField/StepperHeader/StatusChip/ PlaceholderScreen (each tested); i18n nav/common/shell/patients in both locales. Removed the demo scaffolding; fixed the BottomBar pathname bug.
  • Consumes: dev/contracts/conventions/* + openapi/swagger.v1.json (b0 = ping only). No feature contract consumed yet.
  • Mocked client-side: services/patients via patientsMockApi (USE_PATIENTS_MOCK=true) — template for f1+. Swap is one line once real endpoints land.
  • Gate: npm run check green · npm run test:ci green (72 tests) · npm run build green with NEXT_PUBLIC_API_URL set.
  • Requests filed: frontend/requests/for-backend.md — yes (REQ-001).