frontend phase 2: onboarding & profiles — customer/patient, nurse profile & bank
Turns a logged-in user into a usable account, consuming the b3 identity-profiles
contract behind the services/{domain} seam.
Services (mock default true; real HTTP clients wired for a one-line flip):
- services/patients: rewritten to b3 PatientDto + client-augmented relation/conditions;
full CRUD, optimistic soft-archive, cache-splice on create, age<->birthDate helper.
- services/profiles: customer + nurse profile get/upsert + avatar (404->null mapping).
- services/nurse: payout bank accounts + IBAN(Sheba) util + pending-only polling.
Screens: A3->A4 onboarding wizard, E1 patients list/CRUD, A5 home (first-login gate +
nudge), customer profile (no national-ID), nurse profile bootstrap (unverified
placeholder), nurse bank settings (pending/verified/mismatch + make-primary).
Shared composites (each tested): GenderToggle, ConditionChips, RelationSelect,
PatientForm, PatientCard, BankStatusPanel; reuses f0 StepperHeader/StatusChip/PhoneField.
Adds onboarding/home/profile/nurseProfile/bank i18n namespaces (both locales, in sync),
the --bal-primary-soft token, and nurse sidebar Profile + Bank entries.
Contract gaps filed: REQ-005 (patient relation/conditions), REQ-006 (avatar route),
REQ-007 (customer name/language). Gate: check + 112 tests + build all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Age ↔ birth-date helpers. The A4 form collects a whole-year **age** (per the wireframe)
|
||||
* while the contract stores a `birthDate` (`YYYY-MM-DD`) — we map between them here. Birth
|
||||
* date is approximated as 1 January of the birth year; that round-trips back to the same age.
|
||||
*/
|
||||
|
||||
/** Approximate ISO birth date (`YYYY-MM-01-01`) for a whole-year age. */
|
||||
export function ageToBirthDate(age: number, now: Date = new Date()): string {
|
||||
const year = now.getUTCFullYear() - Math.max(0, Math.floor(age));
|
||||
return `${year}-01-01`;
|
||||
}
|
||||
|
||||
/** Whole-year age from an ISO birth date (floored); null for an empty/invalid date. */
|
||||
export function birthDateToAge(birthDate: string | null | undefined, now: Date = new Date()): number | null {
|
||||
if (!birthDate) return null;
|
||||
const date = new Date(birthDate);
|
||||
if (Number.isNaN(date.getTime())) return null;
|
||||
let age = now.getUTCFullYear() - date.getUTCFullYear();
|
||||
const monthDelta = now.getUTCMonth() - date.getUTCMonth();
|
||||
if (monthDelta < 0 || (monthDelta === 0 && now.getUTCDate() < date.getUTCDate())) age -= 1;
|
||||
return age < 0 ? null : age;
|
||||
}
|
||||
Reference in New Issue
Block a user