This commit is contained in:
2025-12-13 18:39:20 +01:00
parent bb0497f429
commit e53af6a0e7
20 changed files with 762 additions and 503 deletions

View File

@@ -3,14 +3,21 @@
import React, { useState } from 'react';
import { useRouter } from 'next/navigation';
import { getQuickPenaltyUseCase } from '@/lib/di-container';
import type { Driver } from '@gridpilot/racing/application';
import Button from '@/components/ui/Button';
import { AlertTriangle, Clock, Flag, Zap } from 'lucide-react';
interface DriverOption {
id: string;
name: string;
}
interface QuickPenaltyModalProps {
raceId: string;
drivers: Driver[];
raceId?: string;
drivers: DriverOption[];
onClose: () => void;
preSelectedDriver?: DriverOption;
adminId: string;
races?: { id: string; track: string; scheduledAt: Date }[];
}
const INFRACTION_TYPES = [
@@ -28,8 +35,9 @@ const SEVERITY_LEVELS = [
{ value: 'severe', label: 'Severe', description: 'Heavy penalty' },
] as const;
export default function QuickPenaltyModal({ raceId, drivers, onClose }: QuickPenaltyModalProps) {
const [selectedDriver, setSelectedDriver] = useState<string>('');
export default function QuickPenaltyModal({ raceId, drivers, onClose, preSelectedDriver, adminId, races }: QuickPenaltyModalProps) {
const [selectedRaceId, setSelectedRaceId] = useState<string>(raceId || '');
const [selectedDriver, setSelectedDriver] = useState<string>(preSelectedDriver?.id || '');
const [infractionType, setInfractionType] = useState<string>('');
const [severity, setSeverity] = useState<string>('');
const [notes, setNotes] = useState<string>('');
@@ -39,21 +47,24 @@ export default function QuickPenaltyModal({ raceId, drivers, onClose }: QuickPen
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!selectedDriver || !infractionType || !severity) return;
if (!selectedRaceId || !selectedDriver || !infractionType || !severity) return;
setLoading(true);
setError(null);
try {
const useCase = getQuickPenaltyUseCase();
await useCase.execute({
raceId,
const command: any = {
raceId: selectedRaceId,
driverId: selectedDriver,
adminId: 'driver-1', // TODO: Get from current user context
adminId,
infractionType: infractionType as any,
severity: severity as any,
notes: notes.trim() || undefined,
});
};
if (notes.trim()) {
command.notes = notes.trim();
}
await useCase.execute(command);
// Refresh the page to show updated results
router.refresh();
@@ -72,24 +83,52 @@ export default function QuickPenaltyModal({ raceId, drivers, onClose }: QuickPen
<h2 className="text-xl font-bold text-white mb-4">Quick Penalty</h2>
<form onSubmit={handleSubmit} className="space-y-4">
{/* Race Selection */}
{races && !raceId && (
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Race
</label>
<select
value={selectedRaceId}
onChange={(e) => setSelectedRaceId(e.target.value)}
className="w-full px-3 py-2 bg-deep-graphite border border-charcoal-outline rounded-lg text-white focus:border-primary-blue focus:outline-none"
required
>
<option value="">Select race...</option>
{races.map((race) => (
<option key={race.id} value={race.id}>
{race.track} ({race.scheduledAt.toLocaleDateString()})
</option>
))}
</select>
</div>
)}
{/* Driver Selection */}
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">
Driver
</label>
<select
value={selectedDriver}
onChange={(e) => setSelectedDriver(e.target.value)}
className="w-full px-3 py-2 bg-deep-graphite border border-charcoal-outline rounded-lg text-white focus:border-primary-blue focus:outline-none"
required
>
<option value="">Select driver...</option>
{drivers.map((driver) => (
<option key={driver.id} value={driver.id}>
{driver.name}
</option>
))}
</select>
{preSelectedDriver ? (
<div className="w-full px-3 py-2 bg-deep-graphite border border-charcoal-outline rounded-lg text-white">
{preSelectedDriver.name}
</div>
) : (
<select
value={selectedDriver}
onChange={(e) => setSelectedDriver(e.target.value)}
className="w-full px-3 py-2 bg-deep-graphite border border-charcoal-outline rounded-lg text-white focus:border-primary-blue focus:outline-none"
required
>
<option value="">Select driver...</option>
{drivers.map((driver) => (
<option key={driver.id} value={driver.id}>
{driver.name}
</option>
))}
</select>
)}
</div>
{/* Infraction Type */}
@@ -175,7 +214,7 @@ export default function QuickPenaltyModal({ raceId, drivers, onClose }: QuickPen
type="submit"
variant="primary"
className="flex-1"
disabled={loading || !selectedDriver || !infractionType || !severity}
disabled={loading || !selectedRaceId || !selectedDriver || !infractionType || !severity}
>
{loading ? 'Applying...' : 'Apply Penalty'}
</Button>