/** * League Stewarding View Model * Represents all data needed for league stewarding across all races */ import { ViewModel } from "../contracts/view-models/ViewModel"; /** * ViewData for LeagueStewarding * This is the JSON-serializable input for the Template. */ export interface LeagueStewardingViewData { racesWithData: RaceWithProtests[]; driverMap: Record; } export class LeagueStewardingViewModel extends ViewModel { private readonly data: LeagueStewardingViewData; constructor(data: LeagueStewardingViewData) { super(); this.data = data; } get racesWithData(): RaceWithProtests[] { return this.data.racesWithData; } get driverMap() { return this.data.driverMap; } /** UI-specific: Total pending protests count */ get totalPending(): number { return this.racesWithData.reduce((sum, r) => sum + r.pendingProtests.length, 0); } /** UI-specific: Total resolved protests count */ get totalResolved(): number { return this.racesWithData.reduce((sum, r) => sum + r.resolvedProtests.length, 0); } /** UI-specific: Total penalties count */ get totalPenalties(): number { return this.racesWithData.reduce((sum, r) => sum + r.penalties.length, 0); } /** UI-specific: Filtered races for pending tab */ get pendingRaces(): RaceWithProtests[] { return this.racesWithData.filter(r => r.pendingProtests.length > 0); } /** UI-specific: Filtered races for history tab */ get historyRaces(): RaceWithProtests[] { return this.racesWithData.filter(r => r.resolvedProtests.length > 0 || r.penalties.length > 0); } /** UI-specific: All drivers for quick penalty modal */ get allDrivers(): Array<{ id: string; name: string; avatarUrl?: string; iracingId?: string; rating?: number }> { return Object.values(this.driverMap); } } export interface RaceWithProtests { race: { id: string; track: string; scheduledAt: Date; }; pendingProtests: Protest[]; resolvedProtests: Protest[]; penalties: Penalty[]; } export interface Protest { id: string; protestingDriverId: string; accusedDriverId: string; incident: { lap: number; description: string; }; filedAt: string; status: string; decisionNotes?: string; proofVideoUrl?: string; } export interface Penalty { id: string; driverId: string; type: string; value: number; reason: string; notes?: string; }