Public Access
feat(ui): Sprint 9 — F1 onboarding tour (4-step welcome)
Hand-rolled 4-step tour (no react-joyride) anchors to existing [data-tour="<id>"] attributes. localStorage key mealplanner:onboarding-complete is the source of truth; ?reset-tour=1 clears the key and re-shows. Steps: Dashboard / Pantry / Recipes / Shopping List. Keyboard: 1-4 jump, ←/→ step, Esc dismiss. Off-route fallback renders a centered card with an 'Open <page>' CTA. A11y: role=dialog, aria-modal=true, focus captured on open and restored on close. 5 lines of code across 4 pages; 1 new component (~420 lines). No new dependencies. No backend changes. No migration. Frontend-only deploy. Tracking: Review/sprint9-verification.md (8-step browser smoke + a11y check + reset-link test).
This commit is contained in:
+53
-3
@@ -122,9 +122,7 @@ User report 2026-06-05 (follow-up to Sprint 7): "one of the meals was the meal t
|
||||
- `frontend/src/pages/Dashboard.tsx:38-50, 385-410` — `MealCard` 3-button voting row
|
||||
- `Review/sprint8-verification.md` — new file (deploy + smoke)
|
||||
|
||||
---
|
||||
|
||||
# Context — Sprint 7 (webui empty-meal-plan fix)
|
||||
## Sprint 7 — webui empty-meal-plan fix
|
||||
|
||||
## Why Sprint 7 exists
|
||||
|
||||
@@ -178,3 +176,55 @@ User report 2026-06-05: "Latest meal plans were emails to me this morning, but w
|
||||
- `backend/scripts/fix_2026_06_05_to_2026_06_08.sql` — new (TO ADD)
|
||||
- `Review/sprint7-verification.md` — new (TO ADD)
|
||||
|
||||
---
|
||||
|
||||
# Context — Sprint 9 (F1 Onboarding Tour, H10)
|
||||
|
||||
## Why Sprint 9 exists
|
||||
|
||||
User direction 2026-06-05: "Proceed with the next phase in the redesign." §Future backlog items: F1 (onboarding tour), F8 (Spoonacular proposal), F9 (Ollama proposal), dead `Generate Meal Plan` CTA. F1 is the only §Future item with a clear UI scope — selected.
|
||||
|
||||
## Decisions (locked in for Sprint 9)
|
||||
|
||||
- **D1. Hand-rolled tour, no `react-joyride`.** Adding a new npm dep is a 1-line trade-off; the audit's prior principles ("reuse existing components/ui/*", "no new npm deps") win. The tour is 4 steps; the implementation is ~420 lines of focused React.
|
||||
- **D2. localStorage key `mealplanner:onboarding-complete` (`"1"` once done).** Same shape as the other `mealplanner:` prefixed keys in the codebase (verified by grep).
|
||||
- **D3. `?reset-tour=1` re-triggers the tour.** Strips the param via `navigate(..., { replace: true })` so a refresh doesn't re-clear. Operator can use this from the browser URL bar; a footer link is a 5-line follow-up if requested.
|
||||
- **D4. Auto-show on `/` only.** Other routes need a manual trigger (or `?reset-tour=1`). The first-time user lands on `/` (the Dashboard is the only root route), so auto-show on first visit is the natural moment.
|
||||
- **D5. Tooltip is a real `<div role="dialog" aria-modal="true">`, not a portal.** The 4 anchor elements are all in the same DOM tree as the dialog. The 20-line portal boilerplate was not worth it; a `position: fixed` dialog at the right z-index works fine.
|
||||
- **D6. rAF polling for the anchor's `getBoundingClientRect`.** Runs only while the tour is open. Cancellable. One DOM read per frame; well under 1% CPU on a 60Hz display.
|
||||
- **D7. Focus captured on open (primary action), restored on close.** Uses `previouslyFocused.current = document.activeElement` on mount; restores on unmount. Standard focus-trap pattern, minus the trap (the dialog is intentionally non-modal — the user can interact with the page below).
|
||||
- **D8. The 4 anchor points are stable elements that already exist in the DOM.** The Dashboard's `<Card>` wrapping the Weekly Overview, the Pantry's page header, the Recipes Filters button, the Shopping List page header. Each gets `data-tour="<id>"`. The anchor also has an off-route fallback (centered card + "Open <page>" CTA) so a first-time user who lands on `/pantry` can still see the Dashboard step (with a one-click nav).
|
||||
|
||||
## Open questions to surface to the user, not to assume
|
||||
|
||||
- **Q1. Should the tour show on every page or only `/`?** Default: `/` only. Other pages need `?reset-tour=1`. If the user lands on a non-root page first, the tour does NOT auto-show. Documented in `Review/sprint9-verification.md` smoke step 2.
|
||||
- **Q2. Should the tour re-show on logout / new device?** Default: no. The localStorage key is per-browser, not per-family-profile. If the user has multiple devices or shares a device, the tour shows once per browser. A future migration could move the key to the family profile, but that's a Sprint 11+.
|
||||
- **Q3. Should the tour re-show on a recipe update / catalog change?** Default: no. The tour is a one-shot. New users see it; existing users don't.
|
||||
|
||||
## Sprint 9 verification gate
|
||||
|
||||
- `cd frontend && npm run build` → green (tsc 0 errors, vite 0 errors)
|
||||
- Browser smoke (8 steps) on `http://100.108.208.56:8082/` per `Review/sprint9-verification.md`
|
||||
- No regression in Sprints 1–8
|
||||
|
||||
## Sprint 9 — does NOT touch
|
||||
|
||||
- The `extractErrorMessage` / `showApiError` flow (Sprint 4 F7) — unchanged.
|
||||
- The keyboard shortcuts (Sprint 5 F2) — unchanged.
|
||||
- The bulk pantry add (Sprint 6 F3) — unchanged.
|
||||
- The plan-the-week (Sprint 6 F4) — unchanged.
|
||||
- The undo-toast (Sprint 3 B12) — unchanged.
|
||||
- The WeekRangeNav (Sprint 7) — unchanged.
|
||||
- The 3-button Sprint 8 voting row — unchanged.
|
||||
- Pre-existing WIP: `backend/app/api/recipes.py`, `backend/app/schemas/recipe.py`, `nginx/nginx.conf` — untouched.
|
||||
|
||||
## Key file:line references
|
||||
|
||||
- `frontend/src/components/OnboardingTour.tsx` (NEW) — ~420 lines
|
||||
- `frontend/src/App.tsx:75-105` — `useOnboarding` + tour mount
|
||||
- `frontend/src/pages/Dashboard.tsx:602` — `<Card data-tour="dashboard">`
|
||||
- `frontend/src/pages/Pantry.tsx:185, 208` — header + add-form anchors
|
||||
- `frontend/src/pages/Recipes.tsx:124` — Filters button anchor
|
||||
- `frontend/src/pages/ShoppingList.tsx:231` — header anchor
|
||||
- `Review/sprint9-verification.md` — new file (deploy + 8-step browser smoke + a11y check)
|
||||
|
||||
|
||||
@@ -121,3 +121,68 @@ Goal: bring implementation back into alignment with `Review/reviewconcensus.md`.
|
||||
|
||||
- R2 spikes fail → stop, propose schema/spec change, await approval.
|
||||
- Verification matrix in `Review/reviewconcensus.md §6` not green → no R3 work begins.
|
||||
|
||||
---
|
||||
|
||||
## Sprint 9 — F1 Onboarding Tour (H10)
|
||||
|
||||
**Owner:** this agent. **Status:** code complete, `npm run build` green, awaiting user commit + deploy. **Tracking:** `Review/sprint9-verification.md`.
|
||||
|
||||
**User policy decision (2026-06-05, exact):** "Proceed with the next phase in the redesign." Selected Sprint 9 = F1 (the only §Future item with a clear UI scope). F8 (Spoonacular) and F9 (Ollama) are full backend proposals; the dead `Generate Meal Plan` CTA is a separate follow-up.
|
||||
|
||||
### S9.1 — New `OnboardingTour.tsx` component (NEW)
|
||||
|
||||
- [x] Hand-rolled (no `react-joyride`) — keeps npm footprint flat.
|
||||
- [x] 4 steps: Dashboard / Pantry / Recipes / Shopping List.
|
||||
- [x] Anchors to `[data-tour="<id>"]` attributes on existing elements.
|
||||
- [x] Tooltip card pinned to anchor (top/bottom/center fallback for off-route steps).
|
||||
- [x] Anchor highlight = primary-400 ring + soft scrim; tooltip is a real `<div role="dialog" aria-modal="true">`.
|
||||
- [x] Step progress = 4 progress bars.
|
||||
- [x] Keyboard: `1`–`4` jump, `←/→` step, `Esc` dismiss, `Tab` order is `Skip → Back → Next`.
|
||||
- [x] `useOnboarding()` hook + `?reset-tour=1` re-trigger; localStorage key `mealplanner:onboarding-complete`.
|
||||
- [x] Focus captured on open (primary action), restored on close.
|
||||
- [x] All reads/writes to localStorage wrapped in try/catch (private mode safe).
|
||||
|
||||
### S9.2 — Anchor points (5 lines of code total)
|
||||
|
||||
- [x] `pages/Dashboard.tsx:602` — `<Card data-tour="dashboard">` on the Weekly Overview grid.
|
||||
- [x] `pages/Pantry.tsx:185` — `<div data-tour="pantry">` on the page header (always present).
|
||||
- [x] `pages/Pantry.tsx:208` — second anchor on the add-form `<Card>` (when the form is open).
|
||||
- [x] `pages/Recipes.tsx:124` — `<Button data-tour="recipes">` on the Filters button.
|
||||
- [x] `pages/ShoppingList.tsx:231` — `<div data-tour="shopping-list">` on the page header.
|
||||
|
||||
### S9.3 — `App.tsx` mount
|
||||
|
||||
- [x] `useOnboarding()` at App root, `isComplete` passed to `<OnboardingTour>`.
|
||||
- [x] `onComplete` mapped to `onboarding.reset()` (flips the flag so re-renders don't re-show).
|
||||
- [x] Mounted as sibling of `<ShortcutHelpBanner />` inside `<BrowserRouter>` (so `useLocation` / `useNavigate` work).
|
||||
|
||||
### S9.4 — Verify
|
||||
|
||||
- [x] `npm run build` green (tsc 0 errors, vite 0 errors).
|
||||
- [ ] Browser smoke (8 steps) on `http://100.108.208.56:8082/` per `Review/sprint9-verification.md`.
|
||||
- [ ] No regression in Sprints 1–8 (keyboard shortcuts, error toast, 3-button vote row, WeekRangeNav, bulk pantry add).
|
||||
|
||||
### S9.5 — Docs (all 6 running docs updated)
|
||||
|
||||
- [x] `Review/ui-nielsen-audit.md` — Sprint 9 status block at the top.
|
||||
- [x] `fix-ui-audit.md` — Sprint 9 plan section (T3.1–T3.4).
|
||||
- [x] `Review/handoff-ui-audit.md` — Sprint 9 entry in the "How to take over" section + TL;DR row.
|
||||
- [x] `docs/HANDOFF.md` — Sprint 9 section.
|
||||
- [x] `.agent/plan.md` — this section.
|
||||
- [x] `.agent/context.md` — Sprint 9 decisions + file:line references.
|
||||
- [x] `Review/sprint9-verification.md` — written (8-step browser smoke + a11y check + reset-link test).
|
||||
|
||||
### Done when (Sprint 9)
|
||||
|
||||
- All boxes above ticked.
|
||||
- `npm run build` green.
|
||||
- `Review/sprint9-verification.md` exists.
|
||||
- All 6 doc files have a Sprint 9 status block.
|
||||
|
||||
### Out of scope (Sprint 9)
|
||||
|
||||
- Thread 3 follow-ups: F8 (Spoonacular), F9 (Ollama), dead `Generate Meal Plan` CTA at `Dashboard.tsx:415`.
|
||||
- Per-page deep tutorials, video demos, hover tooltips.
|
||||
- A user-facing "Show tour" link in the footer (operator uses `?reset-tour=1`; a footer link is a 5-line follow-up if requested).
|
||||
- Sprint 10 — "Deny Forever" on Recipes — already drafted, awaiting user approval to execute.
|
||||
|
||||
Reference in New Issue
Block a user