'use client'; import { useState, useEffect, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { StatefulPageWrapper } from '@/components/shared/state/StatefulPageWrapper'; import { RacesAllTemplate } from '@/templates/RacesAllTemplate'; import { RacesAllPageQuery } from '@/lib/page-queries/races/RacesAllPageQuery'; import { type RacesViewData, type RaceViewData } from '@/lib/view-data/RacesViewData'; import { Flag } from 'lucide-react'; import { routes } from '@/lib/routing/RouteConfig'; const ITEMS_PER_PAGE = 10; export function RacesAllPageClient({ initialViewData }: { initialViewData: unknown }) { const router = useRouter(); // Client-side state for filters and pagination const [currentPage, setCurrentPage] = useState(1); const [statusFilter, setStatusFilter] = useState<'scheduled' | 'running' | 'completed' | 'cancelled' | 'all'>('all'); const [leagueFilter, setLeagueFilter] = useState('all'); const [searchQuery, setSearchQuery] = useState(''); const [showFilters, setShowFilters] = useState(false); const [showFilterModal, setShowFilterModal] = useState(false); // Data state const [pageData, setPageData] = useState(initialViewData as RacesViewData); const [isLoading, setIsLoading] = useState(!initialViewData); const [error, setError] = useState(null); // Fetch data const fetchData = useCallback(async () => { if (pageData && !isLoading) return; // Already have data from server setIsLoading(true); setError(null); try { const result = await RacesAllPageQuery.execute(); if (result.isErr()) { throw new globalThis.Error('Failed to fetch races'); } setPageData(result.unwrap() as unknown as RacesViewData); } catch (err) { setError(err instanceof globalThis.Error ? err : new globalThis.Error('Unknown error')); } finally { setIsLoading(false); } }, [pageData, isLoading]); // Fetch on mount if no initial data useEffect(() => { if (!initialViewData) { fetchData(); } }, [initialViewData, fetchData]); // Transform data const races: RaceViewData[] = pageData?.races ?? []; // Filter and paginate (Note: This should be done by API per contract) const filteredRaces = races.filter((race: RaceViewData) => { if (statusFilter !== 'all' && race.status !== statusFilter) { return false; } if (leagueFilter !== 'all' && race.leagueId !== leagueFilter) { return false; } if (searchQuery) { const query = searchQuery.toLowerCase(); const matchesTrack = race.track.toLowerCase().includes(query); const matchesCar = race.car.toLowerCase().includes(query); const matchesLeague = race.leagueName?.toLowerCase().includes(query); if (!matchesTrack && !matchesCar && !matchesLeague) { return false; } } return true; }); const totalPages = Math.ceil(filteredRaces.length / ITEMS_PER_PAGE); const paginatedRaces = filteredRaces.slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE); // Actions const handleRaceClick = (raceId: string) => { router.push(routes.race.detail(raceId)); }; const handleLeagueClick = (leagueId: string) => { router.push(routes.league.detail(leagueId)); }; const handlePageChange = (page: number) => { setCurrentPage(page); }; return ( pageData ? ( ) : null} loading={{ variant: 'skeleton', message: 'Loading races...' }} errorConfig={{ variant: 'full-screen' }} empty={{ icon: Flag, title: 'No races found', description: 'There are no races available at the moment', }} /> ); }