'use client'; import { useState } from 'react'; import Modal from '@/components/ui/Modal'; import Button from '@/components/ui/Button'; import { getFileProtestUseCase } from '@/lib/di-container'; import type { ProtestIncident } from '@gridpilot/racing/domain/entities/Protest'; import { AlertTriangle, Video, MessageSquare, Hash, Clock, User, FileText, CheckCircle2, } from 'lucide-react'; type ProtestParticipant = { id: string; name: string; }; interface FileProtestModalProps { isOpen: boolean; onClose: () => void; raceId: string; leagueId?: string; protestingDriverId: string; participants: ProtestParticipant[]; } export default function FileProtestModal({ isOpen, onClose, raceId, leagueId, protestingDriverId, participants, }: FileProtestModalProps) { const [step, setStep] = useState<'form' | 'submitting' | 'success' | 'error'>('form'); const [errorMessage, setErrorMessage] = useState(null); // Form state const [accusedDriverId, setAccusedDriverId] = useState(''); const [lap, setLap] = useState(''); const [timeInRace, setTimeInRace] = useState(''); const [description, setDescription] = useState(''); const [comment, setComment] = useState(''); const [proofVideoUrl, setProofVideoUrl] = useState(''); const otherParticipants = participants.filter(p => p.id !== protestingDriverId); const handleSubmit = async () => { // Validation if (!accusedDriverId) { setErrorMessage('Please select the driver you are protesting against.'); return; } if (!lap || parseInt(lap, 10) < 0) { setErrorMessage('Please enter a valid lap number.'); return; } if (!description.trim()) { setErrorMessage('Please describe what happened.'); return; } setStep('submitting'); setErrorMessage(null); try { const useCase = getFileProtestUseCase(); const incident: ProtestIncident = { lap: parseInt(lap, 10), description: description.trim(), ...(timeInRace ? { timeInRace: parseInt(timeInRace, 10) } : {}), }; const command = { raceId, protestingDriverId, accusedDriverId, incident, ...(comment.trim() ? { comment: comment.trim() } : {}), ...(proofVideoUrl.trim() ? { proofVideoUrl: proofVideoUrl.trim() } : {}), }; await useCase.execute(command); setStep('success'); } catch (err) { setStep('error'); setErrorMessage(err instanceof Error ? err.message : 'Failed to file protest'); } }; const handleClose = () => { // Reset form state setStep('form'); setErrorMessage(null); setAccusedDriverId(''); setLap(''); setTimeInRace(''); setDescription(''); setComment(''); setProofVideoUrl(''); onClose(); }; if (step === 'success') { return (

Your protest has been submitted

The stewards will review your protest and make a decision. You'll be notified of the outcome.

); } return (
{errorMessage && (

{errorMessage}

)} {/* Driver Selection */}
{/* Lap and Time */}
setLap(e.target.value)} disabled={step === 'submitting'} placeholder="e.g. 5" className="w-full px-3 py-2.5 bg-deep-graphite border border-charcoal-outline rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-primary-blue/50 focus:border-primary-blue disabled:opacity-50" />
setTimeInRace(e.target.value)} disabled={step === 'submitting'} placeholder="Optional" className="w-full px-3 py-2.5 bg-deep-graphite border border-charcoal-outline rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-primary-blue/50 focus:border-primary-blue disabled:opacity-50" />
{/* Incident Description */}