'use client'; import { useState, useMemo } from 'react'; import { useRouter } from 'next/navigation'; import { RacesIndexTemplate } from '@/templates/RacesIndexTemplate'; import type { RacesViewData } from '@/lib/view-data/RacesViewData'; import { ClientWrapperProps } from '@/lib/contracts/components/ComponentContracts'; export function RacesPageClient({ viewData }: ClientWrapperProps) { const router = useRouter(); const [statusFilter, setStatusFilter] = useState('all'); const [leagueFilter, setLeagueFilter] = useState('all'); const [timeFilter, setTimeFilter] = useState('upcoming'); const [showFilterModal, setShowFilterModal] = useState(false); const filteredRaces = useMemo(() => { const now = new Date(); return viewData.races.filter((race) => { // Status filter: case-insensitive match if (statusFilter !== 'all' && race.status.toLowerCase() !== statusFilter.toLowerCase()) return false; // League filter if (leagueFilter !== 'all' && race.leagueId !== leagueFilter) return false; // Time filter: ensure we are checking the correct flags // Note: we also check the actual date to be safe against stale API flags const scheduledAt = new Date(race.scheduledAt); const isActuallyUpcoming = scheduledAt > now && race.status.toLowerCase() === 'scheduled'; const isActuallyLive = race.status.toLowerCase() === 'running'; const isActuallyPast = scheduledAt < now || race.status.toLowerCase() === 'completed' || race.status.toLowerCase() === 'cancelled'; if (timeFilter === 'upcoming' && !isActuallyUpcoming) return false; if (timeFilter === 'live' && !isActuallyLive) return false; if (timeFilter === 'past' && !isActuallyPast) return false; return true; }); }, [viewData.races, statusFilter, leagueFilter, timeFilter]); const nextUpRace = useMemo(() => { const now = new Date(); // Find the first upcoming race in the filtered list return filteredRaces.find(r => new Date(r.scheduledAt) > now && r.status.toLowerCase() === 'scheduled'); }, [filteredRaces]); const racesByDate = useMemo(() => { const grouped = new Map(); // If we have a "Next Up" race and we are in upcoming view, we might want to exclude it from the list // to avoid duplication, but usually it's better to keep the list complete. // For this redesign, we keep the list complete for scanning. filteredRaces.forEach((race) => { const dateKey = race.scheduledAt.split('T')[0]!; if (!grouped.has(dateKey)) { grouped.set(dateKey, []); } grouped.get(dateKey)!.push(race); }); return Array.from(grouped.entries()) .sort(([a], [b]) => timeFilter === 'past' ? b.localeCompare(a) : a.localeCompare(b)) .map(([dateKey, dayRaces]) => ({ dateKey, dateLabel: dayRaces[0]?.scheduledAtLabel || '', races: dayRaces, })); }, [filteredRaces, timeFilter]); return ( router.push(`/races/${id}`)} /> ); }