Goal
Implement the floorplate-first buyer flow Nadezhda demands — replace dot-on-façade IA with filter-by-shape. Modules: floorplate-selection, layout-detail, unit-detail, plus the shared status-pill component.
Council Review (CONV-30) amendments apply — see
plans/sales-app-react-module-sequence.md§Council Review. Phase 3 amendments: A-BUYUX-1 (CRITICAL — first save = anonymous, NO modal), A-BUYUX-3 (sticky price chip in TopBar via Phase 4), A-BUYUX-4 (building filter chip + Building type), A-DEMO-2 (filter empty state), A-SALESUX-3 (broker-shortlist mode), A-HEALTH-3 (savedUnits hydration default), A-HEALTH-4 (status pill sole consumer of--color-status-*), A-BRAND-2 (status pill via tokens, no hex). State access uses Zustand selectors per A-SCALE-1:useBuyerProfile(s => s.savedUnits),useBuyerProfile(s => s.mode),useBuyerProfile.getState().addSavedUnit(unitId).Per-module 4-step design loop (A-DEVUX-1): FloorplateSelection + UnitDetail + BuyerProfileCaptureModal-stub-trigger are density modules → use
/wireframeto produce 2-3 lo-fi variants BEFORE coding. LayoutDetail is photo-heavy → skip wireframe.
Tasks
Status pill (foundation for the phase)
- [ ]
src/components/status-pill.tsx— consumes--color-status-*token NAMES only (no hex literals — A-BRAND-2). Consumes Project'sanonymiseStatusesflag. Sole consumer of those tokens (A-HEALTH-4 — CI grep guard enforces). - [ ] AU English check on touched files.
FloorplateSelection module (density)
- [ ] PAUSE:
/wireframe2-3 lo-fi variants for FloorplateSelection (A-DEVUX-1 step 2 — density module). Filter rail position, chip vs dropdown, layout-grid card density, price band placement, building selector position when project has >1 building. - [ ] PAUSE: Brief Roman + pick variant before coding.
- [ ]
src/features/floorplate-selection/FloorplateSelection.tsx— Warm Stone surface; left filter rail (beds, baths, building when >1 — A-BUYUX-4, aspect, budget — shadcn ToggleGroup chips + slider/input pair for budget); right layout grid showing matching layouts as cards (image + bed count + size range + price band + "X floors carry this layout" badge); local filter state. A-DEMO-2 empty state: when filtered set empty, render Warm-Stone empty card "No layouts match these criteria — adjust filters, or request a tailored layout" + Reset filters link + "Talk to a sales advisor" CTA wired to BuyerProfile chip. - [ ]
src/features/floorplate-selection/FloorplateSelection.stories.tsx— Interactive render pattern (matches existing TopBar story shape) +README.md - [ ] PAUSE: Live-iterate FloorplateSelection with Roman in browser —
/inspectfor chip sizing/colour/spacing; optional/make-tweakable. - [ ] AU English check on touched files.
LayoutDetail module (photo-heavy)
- [ ] PAUSE: Brief Roman on LayoutDetail module before coding (skip wireframe — photo-heavy).
- [ ]
src/features/layout-detail/LayoutDetail.tsx— opens on layout-card click; large layout plan image + floor list with units; status-coloured chips via<StatusPill>. - [ ]
src/features/layout-detail/LayoutDetail.stories.tsx+README.md - [ ] PAUSE: Live-iterate LayoutDetail with Roman.
- [ ] AU English check on touched files.
UnitDetail module (density)
- [ ] PAUSE:
/wireframe2-3 lo-fi variants for UnitDetail — price treatment (floats vs sits below), info hierarchy (bed/bath/aspect chip ordering), where bay-window note sits, "save" button placement, payment-plan summary block. - [ ] PAUSE: Brief Roman + pick variant before coding.
- [ ]
src/features/unit-detail/UnitDetail.tsx— large unit code (JetBrains Mono), price (Helvetica Neue), bed/bath/aspect chips, "view from window" lightbox slot (<AssetOrPlaceholder kind="render">), bay-window-rooms note from fixture, payment plan summary, "♡ Save to my profile" button. A-BUYUX-1 (CRITICAL) save flow: readuseBuyerProfile.getState().savedUnitsandmode— ifmode === 'broker-shortlist'(Phase 4 sets via?presenter=1), write to session shortlist with no modal + 3-second undo toast (A-SALESUX-3); else if anonymous OR identified, calluseBuyerProfile.getState().addSavedUnit(unitId)and show passive toast "Saved. Add your details to keep these across devices →". NO modal triggered from this button — modal opens only on (a) 2nd+ save when anonymous (Phase 4 logic), (b) topbar chip click, (c) "Email me this offer" CTA. - [ ]
src/features/unit-detail/UnitDetail.stories.tsx+README.md - [ ] PAUSE: Live-iterate UnitDetail with Roman.
- [ ] AU English check on touched files.
Type + fixture additive changes
- [ ] Modify
src/data/riviera.ts— addanonymiseStatuses: falseto Project. (BuyerProfile.savedUnitsandBuildingtypes already added in Phase 1 per amendment A-BUYUX-4 + A-HEALTH-3.) - [ ] Vitest unit test: filter logic — given fixture, applying
beds=['2BR']returns only 2BR layouts; combined filter returning empty set renders A-DEMO-2 empty card. - [ ] Smoke: storybook flow filter chips → layout grid → layout detail → unit detail → save action (no modal, see A-BUYUX-1).
What's Next
Confirm Phase 2 (sales-app-react-anchor) is complete and exterior-360 + hotspot + poi-detail render correctly in Storybook. Then start with src/components/status-pill.tsx (smallest piece; reused by layout-detail + unit-detail). Then FloorplateSelection (the IA-defining filter screen). Then LayoutDetail, then UnitDetail.
Key Context
- Plan:
plans/sales-app-react-module-sequence.mdPhase 3 - Phase 2 must be DONE first. Status-pill needs oxidised tokens which already exist in globals.css.
- Anonymise-statuses flag lives on
Project(Nadezhda flagged this concern about over-saturated unit-status visibility on tall towers) - Save-from-UnitDetail without buyer-profile must trigger a placeholder until Phase 4 lands the modal; stub with toast + console.log so the wiring is clear when Phase 4 connects
- Eval pack: plan §Phase 3 evaluation table (artefact = 3 storybook URLs + screenshot of filter→layout→unit flow; 2-min check = toggle bed-count chips → grid filters live)
Session Log
- CONV-30 (2026-05-09): Workstream created via
/planratification ofsales-app-react-module-sequence - CONV-30 (2026-05-11, buyer-journey track close): Plan integrated post-council (7 CRITICAL + 22 HIGH + 7 MEDIUM amendments inline), renamed from path2- slug to sales-app-react-, parallel brand-language-and-identity track established. State ratified, ready for /build (or /plan plans/brand-language-and-identity.md for the brand track).