website refactor
This commit is contained in:
102
apps/website/ui/RaceList.tsx
Normal file
102
apps/website/ui/RaceList.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
|
||||
|
||||
import { routes } from '@/lib/routing/RouteConfig';
|
||||
import type { RaceViewData } from '@/lib/view-data/RacesViewData';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Card } from '@/ui/Card';
|
||||
import { DateHeader } from '@/ui/DateHeader';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { RaceListItem } from '@/ui/RaceListItem';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Calendar, CheckCircle2, Clock, PlayCircle, XCircle } from 'lucide-react';
|
||||
|
||||
interface RaceListProps {
|
||||
racesByDate: Array<{
|
||||
dateKey: string;
|
||||
dateLabel: string;
|
||||
races: RaceViewData[];
|
||||
}>;
|
||||
totalCount: number;
|
||||
onRaceClick: (raceId: string) => void;
|
||||
}
|
||||
|
||||
export function RaceList({ racesByDate, totalCount, onRaceClick }: RaceListProps) {
|
||||
const statusConfig = {
|
||||
scheduled: {
|
||||
icon: Clock,
|
||||
variant: 'primary' as const,
|
||||
label: 'Scheduled',
|
||||
},
|
||||
running: {
|
||||
icon: PlayCircle,
|
||||
variant: 'success' as const,
|
||||
label: 'LIVE',
|
||||
},
|
||||
completed: {
|
||||
icon: CheckCircle2,
|
||||
variant: 'default' as const,
|
||||
label: 'Completed',
|
||||
},
|
||||
cancelled: {
|
||||
icon: XCircle,
|
||||
variant: 'warning' as const,
|
||||
label: 'Cancelled',
|
||||
},
|
||||
};
|
||||
|
||||
if (racesByDate.length === 0) {
|
||||
return (
|
||||
<Card py={12} textAlign="center">
|
||||
<Stack align="center" gap={4}>
|
||||
<Box p={4} bg="bg-iron-gray" rounded="full">
|
||||
<Icon icon={Calendar} size={8} color="rgb(115, 115, 115)" />
|
||||
</Box>
|
||||
<Box>
|
||||
<Text weight="medium" color="text-white" block mb={1}>No races found</Text>
|
||||
<Text size="sm" color="text-gray-500">
|
||||
{totalCount === 0
|
||||
? 'No races have been scheduled yet'
|
||||
: 'Try adjusting your filters'}
|
||||
</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack gap={4}>
|
||||
{racesByDate.map((group) => (
|
||||
<Stack key={group.dateKey} gap={3}>
|
||||
<DateHeader
|
||||
label={group.dateLabel}
|
||||
count={group.races.length}
|
||||
/>
|
||||
|
||||
<Stack gap={2}>
|
||||
{group.races.map((race) => {
|
||||
const config = statusConfig[race.status as keyof typeof statusConfig] || statusConfig.scheduled;
|
||||
|
||||
return (
|
||||
<RaceListItem
|
||||
key={race.id}
|
||||
track={race.track}
|
||||
car={race.car}
|
||||
timeLabel={race.timeLabel}
|
||||
relativeTimeLabel={race.relativeTimeLabel}
|
||||
status={race.status}
|
||||
leagueName={race.leagueName ?? 'Unknown League'}
|
||||
leagueHref={routes.league.detail(race.leagueId ?? '')}
|
||||
strengthOfField={race.strengthOfField}
|
||||
onClick={() => onRaceClick(race.id)}
|
||||
statusConfig={config}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Stack>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user