import { useEffect, useMemo, useState } from 'react' import { useQueries, useQuery } from '@tanstack/react-query' import { Link } from '@tanstack/react-router' import { fetchLiveState, fetchLocalMeetings, fetchSeasons, fetchWeekend } from '../api' import { countWeekendStats, formatCoverageHint, sessionTypeAbbrev } from '../lib/coverage' import { currentAndNextSession, focusMeetingKind, focusMeetingLabel, formatCountdown, formatSessionScheduleTime, meetingHasStarted, pickFocusMeeting, sessionStartTime, sortSessionsByStart, } from '../lib/schedule' import { SourceBadge, weekendStatusLabel } from '../components/SourceBadge' import { CliCommands } from '../components/CliCommands' import type { Meeting, Weekend, WeekendSession } from '../types' function formatMeetingDates(meeting: Meeting): string { const start = meeting.date_start?.slice(0, 10) const end = meeting.date_end?.slice(0, 10) if (start && end && start !== end) return `${start} – ${end}` return start || end || '—' } function countSessionStats(weekends: (Weekend | undefined)[]) { let local = 0 let partial = 0 let total = 0 for (const weekend of weekends) { if (!weekend) continue for (const entry of weekend.sessions) { total++ if (entry.source === 'local') local++ else if (entry.source === 'partial') partial++ } } return { local, partial, total } } function collectRecentSessions(weekends: (Weekend | undefined)[], limit = 8) { const rows: Array = [] for (const weekend of weekends) { if (!weekend) continue for (const entry of weekend.sessions) { rows.push({ ...entry, meeting: weekend.meeting }) } } return rows .sort((a, b) => { const left = Date.parse(a.session.date_start) const right = Date.parse(b.session.date_start) return right - left }) .slice(0, limit) } export function CommandCenterPage() { const [now, setNow] = useState(() => Date.now()) const seasonsQuery = useQuery({ queryKey: ['seasons'], queryFn: fetchSeasons, }) const latestSeason = seasonsQuery.data?.[0] ?? null const meetingsQuery = useQuery({ queryKey: ['meetings', latestSeason], queryFn: () => fetchLocalMeetings(latestSeason!), enabled: latestSeason != null, }) const meetings = meetingsQuery.data ?? [] const weekendQueries = useQueries({ queries: meetings.map((meeting) => ({ queryKey: ['weekend', meeting.meeting_key], queryFn: () => fetchWeekend(meeting.meeting_key), enabled: meetings.length > 0, staleTime: 60_000, })), }) const liveQuery = useQuery({ queryKey: ['live-state'], queryFn: fetchLiveState, staleTime: 5_000, }) useEffect(() => { const timer = window.setInterval(() => setNow(Date.now()), 1000) return () => window.clearInterval(timer) }, []) const nowDate = useMemo(() => new Date(now), [now]) const weekendsByKey = useMemo(() => { const map = new Map() meetings.forEach((meeting, i) => { const data = weekendQueries[i]?.data if (data) map.set(meeting.meeting_key, data) }) return map }, [meetings, weekendQueries]) const weekendList = useMemo(() => weekendQueries.map((q) => q.data), [weekendQueries]) const meetingStats = countWeekendStats(weekendList) const sessionStats = countSessionStats(weekendList) const focusMeeting = pickFocusMeeting(meetings, nowDate) const focusWeekend = focusMeeting ? weekendsByKey.get(focusMeeting.meeting_key) : undefined const focusKind = focusMeeting ? focusMeetingKind(focusMeeting, nowDate) : null const focusSessions = focusWeekend ? sortSessionsByStart(focusWeekend.sessions.map((s) => s.session)) : [] const { current: currentSession, next: nextSession } = currentAndNextSession(focusSessions, nowDate) const defaultSessionKey = focusWeekend?.default_session_key ?? focusWeekend?.sessions[0]?.session.session_key const recentSessions = collectRecentSessions(weekendList) const weekendsLoading = weekendQueries.some((q) => q.isLoading) if (seasonsQuery.isLoading) { return
loading command center…
} if (seasonsQuery.isError) { return (
{seasonsQuery.error instanceof Error ? seasonsQuery.error.message : 'Failed to load seasons'}
) } const seasons = seasonsQuery.data ?? [] if (seasons.length === 0) { return (

Command Center

Local-first F1 operations
No ingested seasons yet
Ingest a season or session from the CLI, then return here for coverage and navigation.
Get Started
' }, ]} />
) } const liveActive = liveQuery.data?.is_live === true return (

Command Center

{latestSeason} season · {seasons.length} season{seasons.length === 1 ? '' : 's'} local
{liveActive ? 'Live session active' : 'No live session'}
Seasons {seasons.length}
Weekends Full {meetingStats.full}
Partial {meetingStats.partial}
Missing {meetingStats.missing}
Sessions Local {sessionStats.local}/{sessionStats.total || '—'}
{focusKind ? focusMeetingLabel(focusKind) : 'Weekend'} {focusWeekend && ( )}
{meetingsQuery.isLoading &&
loading meetings…
} {meetingsQuery.isError && (
{meetingsQuery.error instanceof Error ? meetingsQuery.error.message : 'Failed to load meetings'}
)} {!meetingsQuery.isLoading && !meetingsQuery.isError && focusMeeting && ( <>
{focusMeeting.meeting_name}
{focusMeeting.location} {focusMeeting.country_code ? ` · ${focusMeeting.country_code}` : ''} {' · '} {formatMeetingDates(focusMeeting)}
{focusMeeting.circuit_short_name && ( {focusMeeting.circuit_short_name} )}
{liveActive && (
LIVE SignalR feed connected — open Live Timing
)} {currentSession && (
ON TRACK {currentSession.session_name}
)} {!currentSession && nextSession && sessionStartTime(nextSession) && (
Next session {nextSession.session_name} {formatCountdown(sessionStartTime(nextSession)!, nowDate)}
)} {!currentSession && !nextSession && focusMeeting && meetingHasStarted(focusMeeting, nowDate) && (
Weekend finished
)} {!currentSession && !nextSession && focusKind === 'recent' && (
Historical weekend — local data available
)}
{weekendsLoading && !focusWeekend && (
loading weekend schedule…
)} {focusWeekend && focusWeekend.sessions.length > 0 && (
{focusWeekend.sessions.map(({ session, source, datasets }) => { const isCurrent = currentSession?.session_key === session.session_key const isNext = nextSession?.session_key === session.session_key return ( ) })}
Session Start Coverage Open
{sessionTypeAbbrev(session.session_type, session.session_name)} {session.session_name} {session.session_key === focusWeekend.default_session_key && ( default )} {formatSessionScheduleTime(session.date_start)} {formatCoverageHint(datasets)} Race Hub
)} )} {!meetingsQuery.isLoading && meetings.length === 0 && (
No meetings ingested for {latestSeason}. Run{' '} box-box --ingest-year {latestSeason}
)}
) }