'use client'; import { useLeagueStewardingMutations } from "@/hooks/league/useLeagueStewardingMutations"; import { ClientWrapperProps } from '@/lib/contracts/components/ComponentContracts'; import type { StewardingViewData } from '@/lib/view-data/StewardingViewData'; import { DriverViewModel } from '@/lib/view-models/DriverViewModel'; import { ProtestViewModel } from '@/lib/view-models/ProtestViewModel'; import { RaceViewModel } from '@/lib/view-models/RaceViewModel'; import { StewardingTemplate } from '@/templates/StewardingTemplate'; import { useMemo, useState } from 'react'; interface StewardingPageClientProps extends ClientWrapperProps { leagueId: string; currentDriverId: string; onRefetch: () => void; } export function StewardingPageClient({ viewData, currentDriverId, onRefetch }: StewardingPageClientProps) { const [activeTab, setActiveTab] = useState<'pending' | 'history'>('pending'); const [selectedProtest, setSelectedProtest] = useState(null); const [showQuickPenaltyModal, setShowQuickPenaltyModal] = useState(false); // Mutations using domain hook const { acceptProtestMutation, rejectProtestMutation } = useLeagueStewardingMutations(onRefetch); // Flatten protests for the specialized list components const allPendingProtests = useMemo(() => { return viewData.races.flatMap(r => r.pendingProtests.map(p => ({ id: p.id, raceName: r.track || 'Unknown Track', protestingDriver: viewData.drivers.find(d => d.id === p.protestingDriverId)?.name || 'Unknown', accusedDriver: viewData.drivers.find(d => d.id === p.accusedDriverId)?.name || 'Unknown', description: p.incident.description, submittedAt: p.filedAt, status: p.status as 'pending' | 'under_review' | 'resolved' | 'rejected', }))); }, [viewData.races, viewData.drivers]); const allResolvedProtests = useMemo(() => { return viewData.races.flatMap(r => r.resolvedProtests.map(p => new ProtestViewModel({ id: p.id, protestingDriverId: p.protestingDriverId, accusedDriverId: p.accusedDriverId, description: p.incident.description, submittedAt: p.filedAt, status: p.status, raceId: r.id, incident: p.incident, proofVideoUrl: p.proofVideoUrl, decisionNotes: p.decisionNotes, } as never))); }, [viewData.races]); const racesMap = useMemo(() => { const map: Record = {}; viewData.races.forEach(r => { map[r.id] = new RaceViewModel({ id: r.id, name: '', date: r.scheduledAt, track: r.track, } as never); }); return map; }, [viewData.races]); const driverMap = useMemo(() => { const map: Record = {}; viewData.drivers.forEach(d => { map[d.id] = new DriverViewModel({ id: d.id, name: d.name, iracingId: '', country: '', joinedAt: '', avatarUrl: null, }); }); return map; }, [viewData.drivers]); const handleAcceptProtest = async ( protestId: string, penaltyType: string, penaltyValue: number, stewardNotes: string ) => { // Find the protest to get details for penalty let foundProtest: { raceId: string; accusedDriverId: string; incident: { description: string } } | undefined; viewData.races.forEach((raceData) => { const p = raceData.pendingProtests.find((pr) => pr.id === protestId) || raceData.resolvedProtests.find((pr) => pr.id === protestId); if (p) foundProtest = { raceId: raceData.id, accusedDriverId: p.accusedDriverId, incident: { description: p.incident.description } }; }); if (foundProtest) { await acceptProtestMutation.mutateAsync({ protestId, penaltyType, penaltyValue, stewardNotes, raceId: foundProtest.raceId, accusedDriverId: foundProtest.accusedDriverId, reason: foundProtest.incident.description, }); } }; const handleRejectProtest = async (protestId: string, stewardNotes: string) => { await rejectProtestMutation.mutateAsync({ protestId, stewardNotes, }); }; const handleReviewProtest = (id: string) => { // Find the protest in the data let foundProtest: ProtestViewModel | null = null; viewData.races.forEach(r => { const p = r.pendingProtests.find(p => p.id === id); if (p) { foundProtest = new ProtestViewModel({ id: p.id, protestingDriverId: p.protestingDriverId, accusedDriverId: p.accusedDriverId, description: p.incident.description, submittedAt: p.filedAt, status: p.status, raceId: r.id, incident: p.incident, proofVideoUrl: p.proofVideoUrl, decisionNotes: p.decisionNotes, } as never); } }); if (foundProtest) setSelectedProtest(foundProtest); }; return ( setSelectedProtest(null)} onAcceptProtest={handleAcceptProtest} onRejectProtest={handleRejectProtest} showQuickPenaltyModal={showQuickPenaltyModal} setShowQuickPenaltyModal={setShowQuickPenaltyModal} allPendingProtests={allPendingProtests} allResolvedProtests={allResolvedProtests} racesMap={racesMap} driverMap={driverMap} currentDriverId={currentDriverId} /> ); }