Files
gridpilot.gg/apps/website/lib/view-models/LeagueStewardingViewModel.ts
2026-01-23 15:30:23 +01:00

90 lines
2.4 KiB
TypeScript

/**
* 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<string, { id: string; name: string; avatarUrl?: string; iracingId?: string; rating?: number }>;
}
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;
}