feat(#76): bound primary-route fetches and local-first driver summary

Add shared apiFetch timeouts/abort/typed errors with in-flight dedupe, a
RouteState UI for loading/empty/timeout/error+retry, and wire it through
Weekend (Data Health), Championship, Driver Profile, Briefing, Live, and
Race Hub. Driver summary is local-first with bounded optional OpenF1
enrichment so a hung remote call cannot block the profile.

Spike note: parseSourceMode defaults to openf1; driver summary now treats
omitted ?source= as auto so local season data is preferred.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-12 18:00:37 -04:00
parent e8a1f15f8b
commit b3d1730324
29 changed files with 1636 additions and 241 deletions

View File

@@ -24,6 +24,7 @@ import {
} from '../lib/digest'
import { stripHtml, timeAgo } from '../utils'
import type { ArticleContent, NewsItem } from '../types'
import { RouteState } from '../components/RouteState'
import '../styles/digest.css'
type Category = 'all' | 'official' | 'news' | 'video'
@@ -406,27 +407,27 @@ export function BriefingPage() {
const queryClient = useQueryClient()
const now = useMemo(() => new Date(), [])
const { data: allNews = [], isLoading, isError } = useQuery({
const { data: allNews = [], isLoading, isError, error, refetch, isFetching } = useQuery({
queryKey: ['news'],
queryFn: () => fetchNews(100),
queryFn: ({ signal }) => fetchNews(100, undefined, signal),
staleTime: 60_000,
})
const seasonsQuery = useQuery({
queryKey: ['seasons'],
queryFn: fetchSeasons,
queryFn: ({ signal }) => fetchSeasons(signal),
})
const latestSeason = seasonsQuery.data?.[0] ?? null
const meetingsQuery = useQuery({
queryKey: ['season-meetings', latestSeason],
queryFn: () => fetchSeasonMeetings(latestSeason!),
queryFn: ({ signal }) => fetchSeasonMeetings(latestSeason!, signal),
enabled: latestSeason != null,
})
const hubQuery = useQuery({
queryKey: ['championship-hub', latestSeason],
queryFn: () => fetchChampionshipHub(latestSeason!),
queryFn: ({ signal }) => fetchChampionshipHub(latestSeason!, signal),
enabled: latestSeason != null,
})
@@ -524,8 +525,21 @@ export function BriefingPage() {
</span>
</div>
{isLoading && <div className="loading-state">loading briefing</div>}
{isError && <div className="error-box">Failed to load paddock briefing.</div>}
{isLoading && (
<RouteState kind="loading" title="loading briefing…" testId="briefing-loading" />
)}
{isError && (
<RouteState
kind="error"
title="Briefing unavailable"
error={error}
onRetry={() => {
if (!isFetching) void refetch()
}}
retrying={isFetching}
testId="briefing-error"
/>
)}
{!isLoading && !isError && (
<>