website refactor
This commit is contained in:
@@ -5,8 +5,12 @@ import { ProtestViewModel } from "@/lib/view-models/ProtestViewModel";
|
||||
import { RaceViewModel } from "@/lib/view-models/RaceViewModel";
|
||||
import { DriverViewModel } from "@/lib/view-models/DriverViewModel";
|
||||
import { Card } from "@/ui/Card";
|
||||
import { Button } from "@/ui/Button";
|
||||
import { Clock, Grid3x3, TrendingDown, AlertCircle, Filter, Flag } from "lucide-react";
|
||||
import { Box } from "@/ui/Box";
|
||||
import { Stack } from "@/ui/Stack";
|
||||
import { Text } from "@/ui/Text";
|
||||
import { Heading } from "@/ui/Heading";
|
||||
import { Icon } from "@/ui/Icon";
|
||||
import { AlertCircle, Flag } from "lucide-react";
|
||||
|
||||
interface PenaltyHistoryListProps {
|
||||
protests: ProtestViewModel[];
|
||||
@@ -20,7 +24,6 @@ export function PenaltyHistoryList({
|
||||
drivers,
|
||||
}: PenaltyHistoryListProps) {
|
||||
const [filteredProtests, setFilteredProtests] = useState<ProtestViewModel[]>([]);
|
||||
const [filterType, setFilterType] = useState<"all">("all");
|
||||
|
||||
useEffect(() => {
|
||||
setFilteredProtests(protests);
|
||||
@@ -29,86 +32,108 @@ export function PenaltyHistoryList({
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status) {
|
||||
case "upheld":
|
||||
return "text-red-400 bg-red-500/20";
|
||||
return { text: "text-red-400", bg: "bg-red-500/20" };
|
||||
case "dismissed":
|
||||
return "text-gray-400 bg-gray-500/20";
|
||||
return { text: "text-gray-400", bg: "bg-gray-500/20" };
|
||||
case "withdrawn":
|
||||
return "text-blue-400 bg-blue-500/20";
|
||||
return { text: "text-blue-400", bg: "bg-blue-500/20" };
|
||||
default:
|
||||
return "text-orange-400 bg-orange-500/20";
|
||||
return { text: "text-orange-400", bg: "bg-orange-500/20" };
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<Stack gap={4}>
|
||||
{filteredProtests.length === 0 ? (
|
||||
<Card className="p-12 text-center">
|
||||
<div className="flex flex-col items-center gap-4 text-gray-400">
|
||||
<AlertCircle className="h-12 w-12 opacity-50" />
|
||||
<div>
|
||||
<p className="font-medium text-lg">No Resolved Protests</p>
|
||||
<p className="text-sm mt-1">
|
||||
<Card py={12} textAlign="center">
|
||||
<Stack alignItems="center" gap={4}>
|
||||
<Icon icon={AlertCircle} size={12} color="text-gray-400" opacity={0.5} />
|
||||
<Box>
|
||||
<Text weight="medium" size="lg" color="text-gray-400" block>No Resolved Protests</Text>
|
||||
<Text size="sm" color="text-gray-500" mt={1} block>
|
||||
No protests have been resolved in this league
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Text>
|
||||
</Box>
|
||||
</Stack>
|
||||
</Card>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
<Stack gap={3}>
|
||||
{filteredProtests.map((protest) => {
|
||||
const race = races[protest.raceId];
|
||||
const protester = drivers[protest.protestingDriverId];
|
||||
const accused = drivers[protest.accusedDriverId];
|
||||
const incident = protest.incident;
|
||||
const resolvedDate = protest.reviewedAt || protest.filedAt;
|
||||
const statusColors = getStatusColor(protest.status);
|
||||
|
||||
return (
|
||||
<Card key={protest.id} className="p-4">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className={`h-10 w-10 rounded-full flex items-center justify-center flex-shrink-0 ${getStatusColor(protest.status)}`}>
|
||||
<Flag className="h-5 w-5" />
|
||||
</div>
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h3 className="font-semibold text-white">
|
||||
Protest #{protest.id.substring(0, 8)}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-400">
|
||||
{resolvedDate ? `Resolved ${new Date(resolvedDate).toLocaleDateString()}` : 'Resolved'}
|
||||
</p>
|
||||
</div>
|
||||
<span className={`px-3 py-1 rounded-full text-xs font-medium flex-shrink-0 ${getStatusColor(protest.status)}`}>
|
||||
{protest.status.toUpperCase()}
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-1 text-sm">
|
||||
<p className="text-gray-400">
|
||||
<span className="font-medium">{protester?.name || 'Unknown'}</span> vs <span className="font-medium">{accused?.name || 'Unknown'}</span>
|
||||
</p>
|
||||
{race && incident && (
|
||||
<p className="text-gray-500">
|
||||
{race.track} ({race.car}) - Lap {incident.lap}
|
||||
</p>
|
||||
<Card key={protest.id} p={4}>
|
||||
<Box display="flex" alignItems="start" gap={4}>
|
||||
<Box
|
||||
w="10"
|
||||
h="10"
|
||||
rounded="full"
|
||||
display="flex"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
flexShrink={0}
|
||||
bg={statusColors.bg}
|
||||
color={statusColors.text}
|
||||
>
|
||||
<Icon icon={Flag} size={5} />
|
||||
</Box>
|
||||
<Box flex={1}>
|
||||
<Stack gap={2}>
|
||||
<Box display="flex" alignItems="start" justifyContent="between" gap={4}>
|
||||
<Box>
|
||||
<Heading level={3}>
|
||||
Protest #{protest.id.substring(0, 8)}
|
||||
</Heading>
|
||||
<Text size="sm" color="text-gray-400" block>
|
||||
{resolvedDate ? `Resolved ${new Date(resolvedDate).toLocaleDateString()}` : 'Resolved'}
|
||||
</Text>
|
||||
</Box>
|
||||
<Box
|
||||
px={3}
|
||||
py={1}
|
||||
rounded="full"
|
||||
bg={statusColors.bg}
|
||||
color={statusColors.text}
|
||||
fontSize="12px"
|
||||
weight="medium"
|
||||
flexShrink={0}
|
||||
>
|
||||
{protest.status.toUpperCase()}
|
||||
</Box>
|
||||
</Box>
|
||||
<Box>
|
||||
<Text size="sm" color="text-gray-400" block>
|
||||
<Text weight="medium" color="text-white">{protester?.name || 'Unknown'}</Text> vs <Text weight="medium" color="text-white">{accused?.name || 'Unknown'}</Text>
|
||||
</Text>
|
||||
{race && incident && (
|
||||
<Text size="sm" color="text-gray-500" block>
|
||||
{race.track} ({race.car}) - Lap {incident.lap}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
{incident && (
|
||||
<Text size="sm" color="text-gray-300" block>{incident.description}</Text>
|
||||
)}
|
||||
</div>
|
||||
{incident && (
|
||||
<p className="text-gray-300 text-sm">{incident.description}</p>
|
||||
)}
|
||||
{protest.decisionNotes && (
|
||||
<div className="mt-2 p-2 rounded bg-iron-gray/30 border border-charcoal-outline/50">
|
||||
<p className="text-xs text-gray-400">
|
||||
<span className="font-medium">Steward Notes:</span> {protest.decisionNotes}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{protest.decisionNotes && (
|
||||
<Box mt={2} p={2} rounded="md" bg="bg-iron-gray/30" border borderColor="border-charcoal-outline/50">
|
||||
<Text size="xs" color="text-gray-400" block>
|
||||
<Text weight="medium">Steward Notes:</Text> {protest.decisionNotes}
|
||||
</Text>
|
||||
</Box>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
</Box>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Stack>
|
||||
)}
|
||||
</div>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user