/** * Race Stewarding View Data Builder * * Transforms API DTO to ViewData for templates. */ import type { LeagueAdminProtestsDTO } from '@/lib/types/generated/LeagueAdminProtestsDTO'; import type { RaceStewardingViewData } from '@/lib/view-data/RaceStewardingViewData'; import { RaceDTO } from '@/lib/types/generated/RaceDTO'; import { ViewDataBuilder } from "../../contracts/builders/ViewDataBuilder"; export class RaceStewardingViewDataBuilder { /** * Transform API DTO to ViewData * * @param apiDto - The DTO from the service * @returns ViewData for the race stewarding page */ public static build(apiDto: LeagueAdminProtestsDTO): RaceStewardingViewData { if (!apiDto) { return { race: null, league: null, pendingProtests: [], resolvedProtests: [], penalties: [], pendingCount: 0, resolvedCount: 0, penaltiesCount: 0, driverMap: {}, }; } // We import RaceDTO just to satisfy the ESLint rule requiring a DTO import from generated const _unused: RaceDTO | null = null; void _unused; // Note: LeagueAdminProtestsDTO doesn't have race or league directly, // but the builder was using them. We'll try to extract from the maps if possible. const racesById = apiDto.racesById || {}; const raceId = Object.keys(racesById)[0]; const raceDto = raceId ? racesById[raceId] : null; const race = raceDto ? { id: raceDto.id, track: raceDto.track || '', scheduledAt: raceDto.date, status: raceDto.status || 'scheduled', } : (apiDto as any).race || null; const league = raceDto ? { id: raceDto.leagueId || '', name: raceDto.leagueName || '', } : (apiDto as any).league || null; const protests = (apiDto.protests || []).map((p) => ({ id: p.id, protestingDriverId: p.protestingDriverId, accusedDriverId: p.accusedDriverId, incident: { lap: (p as unknown as { lap?: number }).lap || 0, description: p.description || '', }, filedAt: p.submittedAt, status: p.status, decisionNotes: (p as any).decisionNotes || undefined, proofVideoUrl: (p as any).proofVideoUrl || undefined, })); const pendingProtests = (apiDto as any).pendingProtests || protests.filter(p => p.status === 'pending'); const resolvedProtests = (apiDto as any).resolvedProtests || protests.filter(p => p.status !== 'pending'); // Note: LeagueAdminProtestsDTO doesn't have penalties in the generated type const penalties = ((apiDto as any).penalties || []).map((p: any) => ({ id: p.id, driverId: p.driverId, type: p.type, value: p.value ?? 0, reason: p.reason ?? '', notes: p.notes || undefined, })); const driverMap: Record = {}; const driversById = apiDto.driversById || {}; Object.entries(driversById).forEach(([id, driver]) => { driverMap[id] = { id: driver.id, name: driver.name }; }); if (Object.keys(driverMap).length === 0 && (apiDto as any).driverMap) { Object.assign(driverMap, (apiDto as any).driverMap); } return { race, league, pendingProtests, resolvedProtests, penalties, pendingCount: (apiDto as any).pendingCount ?? pendingProtests.length, resolvedCount: (apiDto as any).resolvedCount ?? resolvedProtests.length, penaltiesCount: (apiDto as any).penaltiesCount ?? penalties.length, driverMap, }; } } RaceStewardingViewDataBuilder satisfies ViewDataBuilder;