From 07e585776098b23ce69a53b65c22e1ae6ebc1afa Mon Sep 17 00:00:00 2001 From: AmanTahiliani Date: Sun, 12 Jul 2026 18:38:08 -0400 Subject: [PATCH] fix(#73): consume canonical Weekend Context contract and repair navigation Address the independent review blockers on PR #80 after rebasing onto the authoritative #72 Weekend Context API. - Replace the invented frontend WeekendContext with the exact backend contract (temporal_state, previous/focus/next meetings, previous_completed/active/next/ default_analysis sessions with availability). Every valid canonical payload now maps to a designed state via a total resolveViewState; a well-formed response can never fall through to the limited-data placeholder. - Make the canonical read the single source of truth: useWeekendContext no longer fans out to season/meetings/per-weekend/OpenF1/live queries. Only supplementary championship + news reads run, and only once the canonical context resolves. - Fix the Prepare/analysis flow: /preview is a stable alias that renders the preparation surface (PreSessionView) instead of redirecting back to the same between-races screen. - One primary navigation system per breakpoint: the mobile top-bar links are hidden so the bottom bar is the sole primary nav, and Admin is moved out of every Primary landmark into an operator-utilities toolbar. - Add Vitest coverage for the contract mapping, every temporal state, loading/ error/limited surfaces, the no-fanout guarantee, the /preview CTA, and the nav hierarchy; add hermetic Playwright journeys (seeded + injected canonical payloads), 390/768/1440 overflow checks, and Weekend visual snapshots. Retire the stale Command Center specs/snapshots. Co-authored-by: Cursor --- frontend/src/api.ts | 17 +- frontend/src/components/Nav.tsx | 21 +- .../components/weekend/BetweenRacesView.tsx | 95 +++-- .../weekend/BetweenSessionsView.tsx | 58 ++- .../components/weekend/LiveHandoffView.tsx | 31 +- .../src/components/weekend/PreSessionView.tsx | 37 +- .../src/components/weekend/StatusViews.tsx | 2 +- frontend/src/components/weekend/shared.tsx | 153 ++++--- frontend/src/hooks/useWeekendContext.ts | 173 +++----- frontend/src/lib/weekendContext.ts | 399 +++++------------- frontend/src/pages/WeekendPage.tsx | 84 +++- frontend/src/router.tsx | 12 +- frontend/src/styles/app.css | 7 + frontend/src/styles/weekend.css | 53 +-- frontend/src/test/Nav.test.tsx | 67 +++ frontend/src/test/WeekendPage.test.tsx | 309 ++++++++++++++ frontend/src/test/weekendContext.test.ts | 223 ++++++++++ frontend/src/types.ts | 137 +++--- tests/command-center.spec.ts | 77 ---- tests/production-smoke.spec.ts | 27 +- .../__snapshots__/desktop/command-center.png | Bin 151309 -> 0 bytes .../visual/__snapshots__/desktop/weekend.png | Bin 0 -> 48505 bytes .../__snapshots__/mobile/command-center.png | Bin 98722 -> 0 bytes tests/visual/__snapshots__/mobile/weekend.png | Bin 0 -> 45507 bytes .../__snapshots__/tablet/command-center.png | Bin 131740 -> 0 bytes tests/visual/__snapshots__/tablet/weekend.png | Bin 0 -> 48878 bytes tests/visual/helpers.ts | 15 +- tests/visual/mvp-screens.spec.ts | 8 +- tests/weekend-states.spec.ts | 156 +++++++ tests/weekend.spec.ts | 118 ++++++ 30 files changed, 1468 insertions(+), 811 deletions(-) create mode 100644 frontend/src/test/Nav.test.tsx create mode 100644 frontend/src/test/WeekendPage.test.tsx create mode 100644 frontend/src/test/weekendContext.test.ts delete mode 100644 tests/command-center.spec.ts delete mode 100644 tests/visual/__snapshots__/desktop/command-center.png create mode 100644 tests/visual/__snapshots__/desktop/weekend.png delete mode 100644 tests/visual/__snapshots__/mobile/command-center.png create mode 100644 tests/visual/__snapshots__/mobile/weekend.png delete mode 100644 tests/visual/__snapshots__/tablet/command-center.png create mode 100644 tests/visual/__snapshots__/tablet/weekend.png create mode 100644 tests/weekend-states.spec.ts create mode 100644 tests/weekend.spec.ts diff --git a/frontend/src/api.ts b/frontend/src/api.ts index 6ef9f70..de201cd 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -116,17 +116,12 @@ export async function fetchWeekend(meetingKey: number): Promise { } // fetchWeekendContext consumes the canonical /api/v1/weekend-context endpoint -// (sibling backend story #72). It resolves to null when the endpoint is not yet -// available (404 / server without the handler) so the Weekend page can fall back -// to client-side derivation from existing endpoints. Any other HTTP error throws. -export async function fetchWeekendContext(): Promise { - let res: Response - try { - res = await fetch('/api/v1/weekend-context') - } catch { - return null - } - if (res.status === 404) return null +// (backend story #72). The response is the authoritative WeekendContext shape and +// is used verbatim as the Weekend home's source of truth. Any HTTP error throws +// so the hook can surface an explicit error state; there is no client-side +// re-derivation of the contract. +export async function fetchWeekendContext(): Promise { + const res = await fetch('/api/v1/weekend-context') if (!res.ok) { throw new Error(`API ${res.status}: ${res.statusText}`) } diff --git a/frontend/src/components/Nav.tsx b/frontend/src/components/Nav.tsx index 0ef2d82..2946848 100644 --- a/frontend/src/components/Nav.tsx +++ b/frontend/src/components/Nav.tsx @@ -8,14 +8,23 @@ const PRIMARY = [ { to: '/explore', label: 'Explore', icon: Compass, exact: false }, ] as const +/** + * Nav renders one primary navigation system per breakpoint: + * - Desktop/tablet: the top bar's `aria-label="Primary"` links. + * - Mobile (≤640px): the bottom `aria-label="Primary"` bar; the top bar's links + * are hidden via CSS so the two are never both active at once. + * + * Admin is an operator utility, deliberately outside every Primary landmark — it + * lives in a plain toolbar slot and never appears in the mobile bottom nav. + */ export function Nav() { return ( <> - +
- + -