mirror of
https://github.com/AmanTahiliani/box-box.git
synced 2026-08-08 04:06:18 -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>
This commit is contained in:
@@ -449,67 +449,73 @@ export interface DriverSummary {
|
||||
}
|
||||
|
||||
// ── Weekend Context ──
|
||||
// Canonical contract for the adaptive Weekend home. Served by
|
||||
// /api/v1/weekend-context (sibling backend story #72) and, until that endpoint
|
||||
// ships, derived client-side from existing endpoints (see lib/weekendContext.ts).
|
||||
export type WeekendState =
|
||||
| 'loading'
|
||||
| 'error'
|
||||
| 'limited_data'
|
||||
| 'between_races'
|
||||
// Canonical local-first contract for the adaptive Weekend home, served verbatim
|
||||
// by /api/v1/weekend-context (backend story #72, internal/query/context.go).
|
||||
// The frontend consumes this shape as the single source of truth; view-model
|
||||
// derivation lives in lib/weekendContext.ts.
|
||||
|
||||
// TemporalState mirrors query.TemporalState exactly (the JSON `temporal_state`).
|
||||
export type TemporalState =
|
||||
| 'no_season'
|
||||
| 'between_weekends'
|
||||
| 'pre_session'
|
||||
| 'between_sessions'
|
||||
| 'session_live'
|
||||
| 'session_settling'
|
||||
| 'between_sessions'
|
||||
| 'post_weekend'
|
||||
| 'season_complete'
|
||||
|
||||
export interface WeekendPodiumEntry {
|
||||
position: number
|
||||
driver_number: number
|
||||
name_acronym: string
|
||||
team_name: string
|
||||
team_colour: string
|
||||
gap: string
|
||||
// ContextAvailability mirrors query.ContextAvailability. Every field is present
|
||||
// in a canonical payload except the optional `observed_at`.
|
||||
export interface ContextAvailability {
|
||||
schedule: string
|
||||
live_transport: string
|
||||
live_session: string
|
||||
archive: string
|
||||
local_analysis: string
|
||||
freshness: string
|
||||
observed_at?: string
|
||||
limitations: string[]
|
||||
}
|
||||
|
||||
export type WeekendSessionStatus = 'done' | 'live' | 'next' | 'upcoming'
|
||||
|
||||
export interface WeekendTimelineSession {
|
||||
session_key: number
|
||||
session_name: string
|
||||
session_type: string
|
||||
date_start: string
|
||||
date_end: string
|
||||
status: WeekendSessionStatus
|
||||
// ContextSession mirrors query.ContextSession: a session identity coupled with
|
||||
// its meeting and structured availability contract.
|
||||
export interface ContextSession {
|
||||
session: Session
|
||||
meeting?: Meeting
|
||||
availability: ContextAvailability
|
||||
}
|
||||
|
||||
export interface WeekendCompletedEvent {
|
||||
meeting_key: number
|
||||
meeting_name: string
|
||||
country_code: string
|
||||
country_flag: string
|
||||
circuit_short_name: string
|
||||
round?: number
|
||||
analysis_session_key: number
|
||||
analysis_session_name: string
|
||||
label: string
|
||||
podium: WeekendPodiumEntry[]
|
||||
story?: string
|
||||
// WeekendContext mirrors query.WeekendContext (the canonical endpoint body).
|
||||
export interface WeekendContext {
|
||||
season?: number
|
||||
temporal_state: TemporalState
|
||||
previous_meeting?: Meeting
|
||||
focus_meeting?: Meeting
|
||||
next_meeting?: Meeting
|
||||
previous_completed_session?: ContextSession
|
||||
active_session?: ContextSession
|
||||
next_session?: ContextSession
|
||||
default_analysis_session?: ContextSession
|
||||
championship_round: number
|
||||
total_championship_rounds: number
|
||||
}
|
||||
|
||||
export interface WeekendUpcomingEvent {
|
||||
meeting_key: number
|
||||
meeting_name: string
|
||||
country_code: string
|
||||
country_flag: string
|
||||
circuit_short_name: string
|
||||
circuit_key?: number
|
||||
round?: number
|
||||
date_start?: string
|
||||
next_session_name?: string
|
||||
next_session_start?: string
|
||||
}
|
||||
// ── Weekend view model (client-only) ──
|
||||
// The rendered Weekend home layers a small set of non-canonical UI states
|
||||
// (loading/error) plus supplementary data (championship movers, briefing) on top
|
||||
// of the canonical context. None of these are part of the #72 contract.
|
||||
export type WeekendViewState =
|
||||
| 'loading'
|
||||
| 'error'
|
||||
| 'no_season'
|
||||
| 'between_weekends'
|
||||
| 'pre_session'
|
||||
| 'session_live'
|
||||
| 'session_settling'
|
||||
| 'between_sessions'
|
||||
| 'post_weekend'
|
||||
| 'season_complete'
|
||||
|
||||
export interface WeekendChampionshipMover {
|
||||
position: number
|
||||
@@ -534,32 +540,13 @@ export interface WeekendBriefingItem {
|
||||
image_url?: string
|
||||
}
|
||||
|
||||
export type WeekendRoundStatus = 'completed' | 'next' | 'upcoming'
|
||||
|
||||
export interface WeekendSeasonRound {
|
||||
round: number
|
||||
meeting_key: number
|
||||
country_code: string
|
||||
country_flag: string
|
||||
status: WeekendRoundStatus
|
||||
analysis_session_key?: number
|
||||
}
|
||||
|
||||
export interface WeekendContext {
|
||||
state: WeekendState
|
||||
season: number
|
||||
message?: string
|
||||
live?: boolean
|
||||
active_meeting_name?: string
|
||||
active_circuit_short_name?: string
|
||||
last_event?: WeekendCompletedEvent
|
||||
next_event?: WeekendUpcomingEvent
|
||||
last_session?: WeekendCompletedEvent
|
||||
next_session?: WeekendTimelineSession
|
||||
sessions?: WeekendTimelineSession[]
|
||||
championship_impact?: WeekendChampionshipImpact
|
||||
season_rounds?: WeekendSeasonRound[]
|
||||
briefing?: WeekendBriefingItem[]
|
||||
export interface WeekendPodiumEntry {
|
||||
position: number
|
||||
driver_number: number
|
||||
name_acronym: string
|
||||
team_name: string
|
||||
team_colour: string
|
||||
gap: string
|
||||
}
|
||||
|
||||
export interface NewsItem {
|
||||
|
||||
Reference in New Issue
Block a user