Files
gridpilot.gg/apps/website/components/leagues/RaceDetailModal.tsx
2026-01-24 01:07:43 +01:00

254 lines
8.2 KiB
TypeScript

'use client';
import { DateFormatter } from '@/lib/formatters/DateFormatter';
import { Badge } from '@/ui/Badge';
import { Box } from '@/ui/Box';
import { Button } from '@/ui/Button';
import { Group } from '@/ui/Group';
import { Icon } from '@/ui/Icon';
import { Stack } from '@/ui/Stack';
import { Surface } from '@/ui/Surface';
import { Text } from '@/ui/Text';
import {
Calendar,
Car,
CheckCircle,
Clock,
Cloud,
Droplets,
MapPin,
Thermometer,
Trophy,
Wind,
X
} from 'lucide-react';
interface RaceDetailModalProps {
race: {
id: string;
name: string;
track?: string;
car?: string;
sessionType?: string;
scheduledAt: string;
status: 'scheduled' | 'completed';
strengthOfField?: number;
isUserRegistered?: boolean;
canRegister?: boolean;
};
isOpen: boolean;
onClose: () => void;
onRegister?: () => void;
onWithdraw?: () => void;
onResultsClick?: () => void;
}
export function RaceDetailModal({
race,
isOpen,
onClose,
onRegister,
onWithdraw,
onResultsClick,
}: RaceDetailModalProps) {
if (!isOpen) return null;
const formatTime = (scheduledAt: string) => {
return DateFormatter.formatDateTime(scheduledAt);
};
const getStatusBadge = (status: 'scheduled' | 'completed') => {
if (status === 'completed') {
return <Badge variant="success" size="sm">Completed</Badge>;
}
return <Badge variant="primary" size="sm">Scheduled</Badge>;
};
return (
<Box
position="fixed"
top={0}
left={0}
right={0}
bottom={0}
bg="bg-base-black/80"
display="flex"
alignItems="center"
justifyContent="center"
zIndex={1000}
onClick={onClose}
>
<Box
maxWidth="lg"
width="100%"
mx={4}
onClick={(e) => e.stopPropagation()}
>
<Surface variant="precision" overflow="hidden" data-testid="race-detail-modal">
{/* Header */}
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
p={4}
bg="bg-surface"
borderBottom
borderColor="border-default"
>
<Group gap={3}>
<Text size="lg" weight="bold" variant="high">
{race.name || `Race ${race.id.substring(0, 4)}`}
</Text>
{getStatusBadge(race.status)}
</Group>
<Button
variant="ghost"
size="sm"
onClick={onClose}
icon={<Icon icon={X} size={4} />}
>
Close
</Button>
</Box>
{/* Content */}
<Box p={4}>
<Stack gap={4}>
{/* Basic Info */}
<Surface variant="precision" p={4}>
<Text as="h3" size="sm" weight="bold" variant="low" uppercase letterSpacing="widest" mb={3}>
Race Details
</Text>
<Stack gap={3}>
<Group gap={2} align="center" data-testid="race-track">
<Icon icon={MapPin} size={4} intent="primary" />
<Text size="md" variant="high" weight="bold">
{race.track || 'TBA'}
</Text>
</Group>
<Group gap={2} align="center" data-testid="race-car">
<Icon icon={Car} size={4} intent="primary" />
<Text size="md" variant="high">
{race.car || 'TBA'}
</Text>
</Group>
<Group gap={2} align="center" data-testid="race-date">
<Icon icon={Calendar} size={4} intent="primary" />
<Text size="md" variant="high">
{formatTime(race.scheduledAt)}
</Text>
</Group>
{race.sessionType && (
<Group gap={2} align="center">
<Icon icon={Clock} size={4} intent="primary" />
<Text size="md" variant="high">
{race.sessionType}
</Text>
</Group>
)}
</Stack>
</Surface>
{/* Weather Info (Mock Data) */}
<Surface variant="precision" p={4}>
<Text as="h3" size="sm" weight="bold" variant="low" uppercase letterSpacing="widest" mb={3}>
Weather Conditions
</Text>
<Stack gap={3}>
<Group gap={2} align="center">
<Icon icon={Thermometer} size={4} intent="primary" />
<Text size="md" variant="high">Air: 24°C</Text>
</Group>
<Group gap={2} align="center">
<Icon icon={Thermometer} size={4} intent="primary" />
<Text size="md" variant="high">Track: 31°C</Text>
</Group>
<Group gap={2} align="center">
<Icon icon={Droplets} size={4} intent="primary" />
<Text size="md" variant="high">Humidity: 45%</Text>
</Group>
<Group gap={2} align="center">
<Icon icon={Wind} size={4} intent="primary" />
<Text size="md" variant="high">Wind: 12 km/h NW</Text>
</Group>
<Group gap={2} align="center">
<Icon icon={Cloud} size={4} intent="primary" />
<Text size="md" variant="high">Partly Cloudy</Text>
</Group>
</Stack>
</Surface>
{/* Car Classes */}
<Surface variant="precision" p={4}>
<Text as="h3" size="sm" weight="bold" variant="low" uppercase letterSpacing="widest" mb={3}>
Car Classes
</Text>
<Group gap={2} wrap>
<Badge variant="outline" size="sm">GT3</Badge>
<Badge variant="outline" size="sm">GT4</Badge>
<Badge variant="outline" size="sm">TCR</Badge>
</Group>
</Surface>
{/* Strength of Field */}
{race.strengthOfField && (
<Surface variant="precision" p={4}>
<Text as="h3" size="sm" weight="bold" variant="low" uppercase letterSpacing="widest" mb={3}>
Strength of Field
</Text>
<Group gap={2} align="center">
<Icon icon={Trophy} size={4} intent="primary" />
<Text size="md" variant="high">
{race.strengthOfField.toFixed(1)} / 10.0
</Text>
</Group>
</Surface>
)}
{/* Action Buttons */}
{race.status === 'scheduled' && (
<Box display="flex" gap={2} flexWrap="wrap">
{!race.isUserRegistered && race.canRegister && onRegister && (
<Button
variant="primary"
size="md"
onClick={onRegister}
icon={<Icon icon={CheckCircle} size={4} />}
fullWidth
>
Register
</Button>
)}
{race.isUserRegistered && onWithdraw && (
<Button
variant="secondary"
size="md"
onClick={onWithdraw}
icon={<Icon icon={X} size={4} />}
fullWidth
>
Withdraw
</Button>
)}
</Box>
)}
{race.status === 'completed' && onResultsClick && (
<Button
variant="primary"
size="md"
onClick={onResultsClick}
icon={<Icon icon={Trophy} size={4} />}
fullWidth
>
View Results
</Button>
)}
</Stack>
</Box>
</Surface>
</Box>
</Box>
);
}