website refactor
This commit is contained in:
254
apps/website/components/leagues/RaceDetailModal.tsx
Normal file
254
apps/website/components/leagues/RaceDetailModal.tsx
Normal file
@@ -0,0 +1,254 @@
|
||||
'use client';
|
||||
|
||||
import React from 'react';
|
||||
import { Box } from '@/ui/Box';
|
||||
import { Text } from '@/ui/Text';
|
||||
import { Stack } from '@/ui/Stack';
|
||||
import { Group } from '@/ui/Group';
|
||||
import { Surface } from '@/ui/Surface';
|
||||
import { Icon } from '@/ui/Icon';
|
||||
import { Button } from '@/ui/Button';
|
||||
import { Badge } from '@/ui/Badge';
|
||||
import {
|
||||
Calendar,
|
||||
Clock,
|
||||
Car,
|
||||
MapPin,
|
||||
Thermometer,
|
||||
Droplets,
|
||||
Wind,
|
||||
Cloud,
|
||||
X,
|
||||
Trophy,
|
||||
CheckCircle
|
||||
} from 'lucide-react';
|
||||
import { DateDisplay } from '@/lib/display-objects/DateDisplay';
|
||||
|
||||
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 DateDisplay.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 border borderColor="border-outline-steel" overflow="hidden">
|
||||
{/* Header */}
|
||||
<Box
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="space-between"
|
||||
p={4}
|
||||
bg="bg-surface-charcoal"
|
||||
borderBottom
|
||||
borderColor="border-outline-steel"
|
||||
>
|
||||
<Group gap={3}>
|
||||
<Text size="lg" weight="bold" color="text-white">
|
||||
{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 border borderColor="border-outline-steel" p={4}>
|
||||
<Text as="h3" size="sm" weight="bold" color="text-gray-500" uppercase letterSpacing="widest" mb={3}>
|
||||
Race Details
|
||||
</Text>
|
||||
<Stack gap={3}>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={MapPin} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white" weight="bold">
|
||||
{race.track || 'TBA'}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Car} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">
|
||||
{race.car || 'TBA'}
|
||||
</Text>
|
||||
</Group>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Calendar} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">
|
||||
{formatTime(race.scheduledAt)}
|
||||
</Text>
|
||||
</Group>
|
||||
{race.sessionType && (
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Clock} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">
|
||||
{race.sessionType}
|
||||
</Text>
|
||||
</Group>
|
||||
)}
|
||||
</Stack>
|
||||
</Surface>
|
||||
|
||||
{/* Weather Info (Mock Data) */}
|
||||
<Surface border borderColor="border-outline-steel" p={4}>
|
||||
<Text as="h3" size="sm" weight="bold" color="text-gray-500" uppercase letterSpacing="widest" mb={3}>
|
||||
Weather Conditions
|
||||
</Text>
|
||||
<Stack gap={3}>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Thermometer} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">Air: 24°C</Text>
|
||||
</Group>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Thermometer} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">Track: 31°C</Text>
|
||||
</Group>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Droplets} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">Humidity: 45%</Text>
|
||||
</Group>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Wind} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">Wind: 12 km/h NW</Text>
|
||||
</Group>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Cloud} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">Partly Cloudy</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Surface>
|
||||
|
||||
{/* Car Classes */}
|
||||
<Surface border borderColor="border-outline-steel" p={4}>
|
||||
<Text as="h3" size="sm" weight="bold" color="text-gray-500" 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 border borderColor="border-outline-steel" p={4}>
|
||||
<Text as="h3" size="sm" weight="bold" color="text-gray-500" uppercase letterSpacing="widest" mb={3}>
|
||||
Strength of Field
|
||||
</Text>
|
||||
<Group gap={2} align="center">
|
||||
<Icon icon={Trophy} size={4} color="text-primary-blue" />
|
||||
<Text size="md" color="text-white">
|
||||
{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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user