import { useMemo } from 'react' import { useQuery } from '@tanstack/react-query' import { Link } from '@tanstack/react-router' import { fetchChampionshipHub, fetchNews, fetchSeasonMeetings, fetchSeasons, } from '../api' import { activeDigestWindow, gpWindows, itemsForWindow, sinceLastLabel, tagColour, tagItems, topTags, } from '../lib/digest' import { timeAgo } from '../utils' import '../styles/digest.css' const SOURCE_DISPLAY: Record = { 'fia': 'FIA', 'bbc-f1': 'BBC Sport', 'autosport-f1': 'Autosport', 'racefans-f1': 'RaceFans', 'guardian-f1': 'Guardian', 'racer-f1': 'RACER', 'f1-youtube': 'F1 YouTube', } export function PaddockBriefing() { const now = useMemo(() => new Date(), []) const { data: news, isLoading, isError } = useQuery({ queryKey: ['news'], queryFn: () => fetchNews(100), staleTime: 60_000, }) const seasonsQuery = useQuery({ queryKey: ['seasons'], queryFn: fetchSeasons, }) const latestSeason = seasonsQuery.data?.[0] ?? null const meetingsQuery = useQuery({ queryKey: ['season-meetings', latestSeason], queryFn: () => fetchSeasonMeetings(latestSeason!), enabled: latestSeason != null, }) const hubQuery = useQuery({ queryKey: ['championship-hub', latestSeason], queryFn: () => fetchChampionshipHub(latestSeason!), enabled: latestSeason != null, }) const meetings = meetingsQuery.data ?? [] const hub = hubQuery.data const tagged = useMemo( () => tagItems(news ?? [], hub?.drivers ?? [], hub?.teams ?? []), [news, hub], ) const windows = useMemo(() => gpWindows(meetings, now), [meetings, now]) const activeWindow = useMemo( () => activeDigestWindow(windows, meetings, now), [windows, meetings, now], ) const sinceItems = useMemo( () => itemsForWindow(tagged, activeWindow), [tagged, activeWindow], ) const sinceTags = useMemo(() => topTags(sinceItems, 4), [sinceItems]) const sinceLabel = sinceLastLabel(meetings, now) const unreadCount = news?.filter((i) => !i.read_at).length ?? 0 const preview = sinceItems.length > 0 ? sinceItems.slice(0, 5) : (tagged.slice(0, 5)) return (
Paddock Briefing {unreadCount > 0 && ( {unreadCount} )} View all →
{meetings.length > 0 && (
Since {sinceLabel} · {sinceItems.length} items {sinceTags.length > 0 && (
{sinceTags.map((tag) => ( {tag.label} ))}
)}
)} {isLoading &&
loading…
} {isError &&
Failed to load briefing
} {!isLoading && !isError && preview.length === 0 && (
No items. Run box-box --ingest-news to populate.
)} {preview.length > 0 && (
{preview.map((item) => (
{SOURCE_DISPLAY[item.source] ?? item.source} {timeAgo(item.published_at ?? item.fetched_at)}
{item.title} ))}
)}
) }