78 lines
2.1 KiB
TypeScript
78 lines
2.1 KiB
TypeScript
/**
|
|
* League Stewarding View Model
|
|
* Represents all data needed for league stewarding across all races
|
|
*/
|
|
import { ViewModel } from "../contracts/view-models/ViewModel";
|
|
|
|
export class LeagueStewardingViewModel extends ViewModel {
|
|
constructor(
|
|
public readonly racesWithData: RaceWithProtests[],
|
|
public readonly driverMap: Record<string, { id: string; name: string; avatarUrl?: string; iracingId?: string; rating?: number }>
|
|
) {
|
|
super();
|
|
}
|
|
|
|
/** 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;
|
|
} |