'use client'; import { useState, useEffect, useMemo } from 'react'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; import Card from '@/components/ui/Card'; import Button from '@/components/ui/Button'; import Heading from '@/components/ui/Heading'; import { getGetRacesPageDataUseCase } from '@/lib/di-container'; import type { RacesPageViewModel, RaceListItemViewModel, } from '@gridpilot/racing/application/presenters/IRacesPagePresenter'; import { Calendar, Clock, Flag, ChevronRight, Filter, MapPin, Car, Trophy, Users, Zap, PlayCircle, CheckCircle2, XCircle, CalendarDays, ArrowRight, } from 'lucide-react'; type TimeFilter = 'all' | 'upcoming' | 'live' | 'past'; type RaceStatusFilter = RaceListItemViewModel['status']; export default function RacesPage() { const router = useRouter(); const [pageData, setPageData] = useState(null); const [loading, setLoading] = useState(true); // Filters const [statusFilter, setStatusFilter] = useState('all'); const [leagueFilter, setLeagueFilter] = useState('all'); const [timeFilter, setTimeFilter] = useState('upcoming'); const loadRaces = async () => { try { const useCase = getGetRacesPageDataUseCase(); await useCase.execute(); const data = useCase.presenter.getViewModel(); setPageData(data); } catch (err) { console.error('Failed to load races:', err); } finally { setLoading(false); } }; useEffect(() => { loadRaces(); }, []); // Filter races const filteredRaces = useMemo(() => { if (!pageData) return []; return pageData.races.filter((race) => { // Status filter if (statusFilter !== 'all' && race.status !== statusFilter) { return false; } // League filter if (leagueFilter !== 'all' && race.leagueId !== leagueFilter) { return false; } // Time filter if (timeFilter === 'upcoming' && !race.isUpcoming) { return false; } if (timeFilter === 'live' && !race.isLive) { return false; } if (timeFilter === 'past' && !race.isPast) { return false; } return true; }); }, [pageData, statusFilter, leagueFilter, timeFilter]); // Group races by date for calendar view const racesByDate = useMemo(() => { const grouped = new Map(); filteredRaces.forEach((race) => { if (typeof race.scheduledAt !== 'string') { return; } const dateKey = race.scheduledAt.split('T')[0]!; if (!grouped.has(dateKey)) { grouped.set(dateKey, []); } grouped.get(dateKey)!.push(race); }); return grouped; }, [filteredRaces]); const upcomingRaces = pageData?.upcomingThisWeek ?? []; const liveRaces = pageData?.liveRaces ?? []; const recentResults = pageData?.recentResults ?? []; const stats = pageData?.stats ?? { total: 0, scheduled: 0, running: 0, completed: 0 }; const formatDate = (date: Date | string) => { const d = typeof date === 'string' ? new Date(date) : date; return d.toLocaleDateString('en-US', { weekday: 'short', month: 'short', day: 'numeric', }); }; const formatTime = (date: Date | string) => { const d = typeof date === 'string' ? new Date(date) : date; return d.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', }); }; const formatFullDate = (date: Date | string) => { const d = typeof date === 'string' ? new Date(date) : date; return d.toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric', }); }; const getRelativeTime = (date?: Date | string) => { if (!date) return ''; const now = new Date(); const targetDate = typeof date === 'string' ? new Date(date) : date; const diffMs = targetDate.getTime() - now.getTime(); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (diffMs < 0) return 'Past'; if (diffHours < 1) return 'Starting soon'; if (diffHours < 24) return `In ${diffHours}h`; if (diffDays === 1) return 'Tomorrow'; if (diffDays < 7) return `In ${diffDays} days`; return formatDate(targetDate); }; const statusConfig = { scheduled: { icon: Clock, color: 'text-primary-blue', bg: 'bg-primary-blue/10', border: 'border-primary-blue/30', label: 'Scheduled', }, running: { icon: PlayCircle, color: 'text-performance-green', bg: 'bg-performance-green/10', border: 'border-performance-green/30', label: 'LIVE', }, completed: { icon: CheckCircle2, color: 'text-gray-400', bg: 'bg-gray-500/10', border: 'border-gray-500/30', label: 'Completed', }, cancelled: { icon: XCircle, color: 'text-warning-amber', bg: 'bg-warning-amber/10', border: 'border-warning-amber/30', label: 'Cancelled', }, }; if (loading) { return (
{[1, 2, 3, 4].map(i => (
))}
); } return (
{/* Hero Header */}
Race Calendar

Track upcoming races, view live events, and explore results across all your leagues.

{/* Quick Stats */}
Total

{stats.total}

Scheduled

{stats.scheduled}

Live Now

{stats.running}

Completed

{stats.completed}

{/* Live Races Banner */} {liveRaces.length > 0 && (
LIVE NOW
{liveRaces.map((race) => (
router.push(`/races/${race.id}`)} className="flex items-center justify-between p-4 bg-deep-graphite/80 rounded-lg border border-performance-green/20 cursor-pointer hover:border-performance-green/40 transition-all" >

{race.track}

{race.leagueName}

))}
)}
{/* Main Content - Race List */}
{/* Filters */}
{/* Time Filter Tabs */}
{(['upcoming', 'live', 'past', 'all'] as TimeFilter[]).map(filter => ( ))}
{/* League Filter */}
{/* Race List by Date */} {filteredRaces.length === 0 ? (

No races found

{pageData?.races.length === 0 ? 'No races have been scheduled yet' : 'Try adjusting your filters'}

) : (
{Array.from(racesByDate.entries()).map(([dateKey, dayRaces]) => (
{/* Date Header */}
{formatFullDate(new Date(dateKey))} {dayRaces.length} race{dayRaces.length !== 1 ? 's' : ''}
{/* Races for this date */}
{dayRaces.map((race) => { if (!race.scheduledAt) { return null; } const config = statusConfig[race.status]; const StatusIcon = config.icon; return (
router.push(`/races/${race.id}`)} className={`group relative overflow-hidden rounded-xl bg-iron-gray border ${config.border} p-4 cursor-pointer transition-all duration-200 hover:scale-[1.01] hover:border-primary-blue`} > {/* Live indicator */} {race.status === 'running' && (
)}
{/* Time Column */}

{formatTime(race.scheduledAt)}

{race.status === 'running' ? 'LIVE' : getRelativeTime(race.scheduledAt)}

{/* Divider */}
{/* Main Content */}

{race.track}

{race.car} {race.strengthOfField && ( SOF {race.strengthOfField} )}
{/* Status Badge */}
{config.label}
{/* League Link */}
e.stopPropagation()} className="inline-flex items-center gap-2 text-sm text-primary-blue hover:underline" > {race.leagueName}
{/* Arrow */}
); })}
))}
)} {/* View All Link */} {filteredRaces.length > 0 && (
View All Races
)}
{/* Sidebar */}
{/* Upcoming This Week */}

Next Up

This week
{upcomingRaces.length === 0 ? (

No races scheduled this week

) : (
{upcomingRaces.map((race) => { if (!race.scheduledAt) { return null; } const scheduledAtDate = new Date(race.scheduledAt); return (
router.push(`/races/${race.id}`)} className="flex items-center gap-3 p-2 rounded-lg hover:bg-deep-graphite cursor-pointer transition-colors" >
{scheduledAtDate.getDate()}

{race.track}

{formatTime(scheduledAtDate)}

); })}
)}
{/* Recent Results */}

Recent Results

{recentResults.length === 0 ? (

No completed races yet

) : (
{recentResults.map((race) => (
router.push(`/races/${race.id}/results`)} className="flex items-center gap-3 p-2 rounded-lg hover:bg-deep-graphite cursor-pointer transition-colors" >

{race.track}

{formatDate(new Date(race.scheduledAt))}

))}
)}
{/* Quick Actions */}

Quick Actions

Browse Leagues
View Leaderboards
); }