2026-07-12 18:09:43 -04:00
|
|
|
import { useEffect, useMemo, useState } from 'react'
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
import { useQuery } from '@tanstack/react-query'
|
|
|
|
|
import { fetchChampionshipHub, fetchNews, fetchWeekendContext } from '../api'
|
|
|
|
|
import { championshipImpact, briefingItems } from '../lib/weekendContext'
|
|
|
|
|
import type {
|
|
|
|
|
WeekendChampionshipImpact,
|
|
|
|
|
WeekendBriefingItem,
|
|
|
|
|
WeekendContext,
|
|
|
|
|
} from '../types'
|
|
|
|
|
|
|
|
|
|
export type WeekendLoadState = 'loading' | 'error' | 'ready'
|
2026-07-12 18:09:43 -04:00
|
|
|
|
|
|
|
|
export interface UseWeekendContextResult {
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
/** Canonical context, present only when loadState === 'ready'. */
|
|
|
|
|
context: WeekendContext | null
|
|
|
|
|
loadState: WeekendLoadState
|
|
|
|
|
error?: Error
|
|
|
|
|
/** Supplementary championship movers (not part of the #72 contract). */
|
|
|
|
|
championship?: WeekendChampionshipImpact
|
|
|
|
|
/** Supplementary briefing items (not part of the #72 contract). */
|
|
|
|
|
briefing: WeekendBriefingItem[]
|
2026-07-12 18:09:43 -04:00
|
|
|
now: Date
|
2026-07-12 18:00:37 -04:00
|
|
|
/** Refetch the canonical weekend-context read. */
|
|
|
|
|
refetch: () => void
|
|
|
|
|
/** True while a canonical refetch is in flight. */
|
|
|
|
|
isFetching: boolean
|
2026-07-12 18:09:43 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
* useWeekendContext reads the canonical /api/v1/weekend-context endpoint as the
|
|
|
|
|
* single source of truth for the Weekend home. When the canonical read succeeds
|
|
|
|
|
* it layers on two pieces of supplementary data that the contract intentionally
|
|
|
|
|
* omits — championship movers and the paddock briefing — and nothing else.
|
|
|
|
|
*
|
|
|
|
|
* It deliberately does NOT fan out to season / meetings / per-weekend / OpenF1
|
|
|
|
|
* session / live-state queries: those would defeat the local-first canonical read
|
|
|
|
|
* model and can hit the rate-limited OpenF1 REST surface during active sessions.
|
|
|
|
|
* Supplementary queries are gated on a successful canonical read so a failing or
|
|
|
|
|
* pending endpoint issues no extra requests.
|
2026-07-12 18:09:43 -04:00
|
|
|
*/
|
|
|
|
|
export function useWeekendContext(): UseWeekendContextResult {
|
|
|
|
|
const [now, setNow] = useState(() => Date.now())
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const timer = window.setInterval(() => setNow(Date.now()), 1000)
|
|
|
|
|
return () => window.clearInterval(timer)
|
|
|
|
|
}, [])
|
|
|
|
|
const nowDate = useMemo(() => new Date(now), [now])
|
|
|
|
|
|
|
|
|
|
const contextQuery = useQuery({
|
|
|
|
|
queryKey: ['weekend-context'],
|
2026-07-12 18:00:37 -04:00
|
|
|
queryFn: ({ signal }) => fetchWeekendContext(signal),
|
2026-07-12 18:09:43 -04:00
|
|
|
staleTime: 30_000,
|
|
|
|
|
})
|
|
|
|
|
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
const canonical = contextQuery.data ?? null
|
|
|
|
|
const canonicalReady = canonical != null
|
|
|
|
|
const season = canonical?.season
|
2026-07-12 18:09:43 -04:00
|
|
|
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
// Supplementary data — only fetched once the canonical context has resolved,
|
|
|
|
|
// so a pending/failed canonical read never triggers a request fan-out.
|
2026-07-12 18:09:43 -04:00
|
|
|
const championshipQuery = useQuery({
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
queryKey: ['championship-hub', season ?? 'current'],
|
2026-07-12 18:00:37 -04:00
|
|
|
queryFn: ({ signal }) => fetchChampionshipHub(season, signal),
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
enabled: canonicalReady,
|
|
|
|
|
staleTime: 60_000,
|
2026-07-12 18:09:43 -04:00
|
|
|
})
|
|
|
|
|
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
const newsQuery = useQuery({
|
|
|
|
|
queryKey: ['news', 6],
|
2026-07-12 18:00:37 -04:00
|
|
|
queryFn: ({ signal }) => fetchNews(6, undefined, signal),
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
enabled: canonicalReady,
|
2026-07-12 18:09:43 -04:00
|
|
|
staleTime: 60_000,
|
|
|
|
|
})
|
|
|
|
|
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
const championship = useMemo(
|
|
|
|
|
() => championshipImpact(championshipQuery.data),
|
|
|
|
|
[championshipQuery.data],
|
2026-07-12 18:09:43 -04:00
|
|
|
)
|
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 <cursoragent@cursor.com>
2026-07-12 18:38:08 -04:00
|
|
|
const briefing = useMemo(() => briefingItems(newsQuery.data ?? []), [newsQuery.data])
|
|
|
|
|
|
|
|
|
|
let loadState: WeekendLoadState = 'loading'
|
|
|
|
|
if (contextQuery.isError) loadState = 'error'
|
|
|
|
|
else if (canonicalReady) loadState = 'ready'
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
context: canonical,
|
|
|
|
|
loadState,
|
|
|
|
|
error: contextQuery.error instanceof Error ? contextQuery.error : undefined,
|
|
|
|
|
championship,
|
|
|
|
|
briefing,
|
|
|
|
|
now: nowDate,
|
2026-07-12 18:00:37 -04:00
|
|
|
refetch: () => {
|
|
|
|
|
if (!contextQuery.isFetching) void contextQuery.refetch()
|
|
|
|
|
},
|
|
|
|
|
isFetching: contextQuery.isFetching,
|
2026-07-12 18:09:43 -04:00
|
|
|
}
|
|
|
|
|
}
|