'use client'; import { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { useEffectiveDriverId } from '@/lib/currentDriver'; import { createLeagueSchedulePresenter } from '@/lib/presenters/factories'; import type { LeagueScheduleRaceItemViewModel } from '@/lib/presenters/LeagueSchedulePresenter'; interface LeagueScheduleProps { leagueId: string; } export default function LeagueSchedule({ leagueId }: LeagueScheduleProps) { const router = useRouter(); const [races, setRaces] = useState([]); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState<'all' | 'upcoming' | 'past'>('upcoming'); const [registrationStates, setRegistrationStates] = useState>({}); const [processingRace, setProcessingRace] = useState(null); const currentDriverId = useEffectiveDriverId(); const loadRacesCallback = useCallback(async () => { setLoading(true); try { const viewModel = await loadLeagueSchedule(leagueId, currentDriverId); setRaces(viewModel.races); const states: Record = {}; for (const race of viewModel.races) { states[race.id] = race.isRegistered; } setRegistrationStates(states); } catch (error) { console.error('Failed to load races:', error); } finally { setLoading(false); } }, [leagueId, currentDriverId]); useEffect(() => { void loadRacesCallback(); }, [loadRacesCallback]); const handleRegister = async (race: LeagueScheduleRaceItemViewModel, e: React.MouseEvent) => { e.stopPropagation(); const confirmed = window.confirm(`Register for ${race.track}?`); if (!confirmed) return; setProcessingRace(race.id); try { await registerForRace(race.id, leagueId, currentDriverId); setRegistrationStates((prev) => ({ ...prev, [race.id]: true })); } catch (err) { alert(err instanceof Error ? err.message : 'Failed to register'); } finally { setProcessingRace(null); } }; const handleWithdraw = async (race: LeagueScheduleRaceItemViewModel, e: React.MouseEvent) => { e.stopPropagation(); const confirmed = window.confirm('Withdraw from this race?'); if (!confirmed) return; setProcessingRace(race.id); try { await withdrawFromRace(race.id, currentDriverId); setRegistrationStates((prev) => ({ ...prev, [race.id]: false })); } catch (err) { alert(err instanceof Error ? err.message : 'Failed to withdraw'); } finally { setProcessingRace(null); } }; const upcomingRaces = races.filter((race) => race.isUpcoming); const pastRaces = races.filter((race) => race.isPast); const getDisplayRaces = () => { switch (filter) { case 'upcoming': return upcomingRaces; case 'past': return [...pastRaces].reverse(); case 'all': return [...upcomingRaces, ...[...pastRaces].reverse()]; default: return races; } }; const displayRaces = getDisplayRaces(); if (loading) { return (
Loading schedule...
); } return (
{/* Filter Controls */}

{displayRaces.length} {displayRaces.length === 1 ? 'race' : 'races'}

{/* Race List */} {displayRaces.length === 0 ? (

No {filter} races

{filter === 'upcoming' && (

Schedule your first race to get started

)}
) : (
{displayRaces.map((race) => { const isPast = race.isPast; const isUpcoming = race.isUpcoming; return (
router.push(`/races/${race.id}`)} >

{race.track}

{isUpcoming && !registrationStates[race.id] && ( Upcoming )} {isUpcoming && registrationStates[race.id] && ( ✓ Registered )} {isPast && ( Completed )}

{race.car}

{race.sessionType}

{race.scheduledAt.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric', })}

{race.scheduledAt.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', })}

{isPast && race.status === 'completed' && (

View Results →

)}
{/* Registration Actions */} {isUpcoming && (
e.stopPropagation()}> {!registrationStates[race.id] ? ( ) : ( )}
)}
); })}
)}
); }