// DTO interfaces matching the API responses interface RaceDetailDTO { race: { id: string; track: string; scheduledAt: string; status: string; } | null; league: { id: string; name: string; } | null; } interface RaceProtestsDTO { protests: Array<{ id: string; protestingDriverId: string; accusedDriverId: string; incident: { lap: number; description: string; }; filedAt: string; status: string; decisionNotes?: string; proofVideoUrl?: string; }>; driverMap: Record; } interface RacePenaltiesDTO { penalties: Array<{ id: string; driverId: string; type: string; value: number; reason: string; notes?: string; }>; driverMap: Record; } interface RaceStewardingDTO { raceDetail: RaceDetailDTO; protests: RaceProtestsDTO; penalties: RacePenaltiesDTO; } /** * Race Stewarding View Model * Represents all data needed for race stewarding (protests, penalties, race info) */ export class RaceStewardingViewModel { race: RaceDetailDTO['race']; league: RaceDetailDTO['league']; protests: RaceProtestsDTO['protests']; penalties: RacePenaltiesDTO['penalties']; driverMap: Record; constructor(dto: RaceStewardingDTO) { this.race = dto.raceDetail.race; this.league = dto.raceDetail.league; this.protests = dto.protests.protests; this.penalties = dto.penalties.penalties; // Merge driver maps from protests and penalties this.driverMap = { ...dto.protests.driverMap, ...dto.penalties.driverMap }; } /** UI-specific: Pending protests */ get pendingProtests() { return this.protests.filter(p => p.status === 'pending' || p.status === 'under_review'); } /** UI-specific: Resolved protests */ get resolvedProtests() { return this.protests.filter(p => p.status === 'upheld' || p.status === 'dismissed' || p.status === 'withdrawn' ); } /** UI-specific: Total pending protests count */ get pendingCount(): number { return this.pendingProtests.length; } /** UI-specific: Total resolved protests count */ get resolvedCount(): number { return this.resolvedProtests.length; } /** UI-specific: Total penalties count */ get penaltiesCount(): number { return this.penalties.length; } }