Files
gridpilot.gg/apps/website/lib/view-models/RaceResultsDataTransformer.ts
2026-01-07 14:16:02 +01:00

105 lines
3.5 KiB
TypeScript

import type { LeagueMembershipsViewModel } from '@/lib/view-models/LeagueMembershipsViewModel';
import type { RaceResultsDetailViewModel } from '@/lib/view-models/RaceResultsDetailViewModel';
import type { RaceWithSOFViewModel } from '@/lib/view-models/RaceWithSOFViewModel';
// TODO fucking violating our architecture, it should be a ViewModel
export interface TransformedRaceResultsData {
raceTrack?: string;
raceScheduledAt?: string;
totalDrivers?: number;
leagueName?: string;
raceSOF: number | null;
results: Array<{
position: number;
driverId: string;
driverName: string;
driverAvatar: string;
country: string;
car: string;
laps: number;
time: string;
fastestLap: string;
points: number;
incidents: number;
isCurrentUser: boolean;
}>;
penalties: Array<{
driverId: string;
driverName: string;
type: 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points';
value: number;
reason: string;
notes?: string;
}>;
pointsSystem: Record<string, number>;
fastestLapTime: number;
memberships?: Array<{
driverId: string;
role: string;
}>;
}
export class RaceResultsDataTransformer {
static transform(
resultsData: RaceResultsDetailViewModel | null,
sofData: RaceWithSOFViewModel | null,
currentDriverId: string,
membershipsData?: LeagueMembershipsViewModel
): TransformedRaceResultsData {
if (!resultsData) {
return {
raceSOF: null,
results: [],
penalties: [],
pointsSystem: {},
fastestLapTime: 0,
};
}
// Transform results
const results = resultsData.results.map((result: any) => ({
position: result.position,
driverId: result.driverId,
driverName: result.driverName,
driverAvatar: result.avatarUrl,
country: 'US', // Default since view model doesn't have car
car: 'Unknown', // Default since view model doesn't have car
laps: 0, // Default since view model doesn't have laps
time: '0:00.00', // Default since view model doesn't have time
fastestLap: result.fastestLap.toString(), // Convert number to string
points: 0, // Default since view model doesn't have points
incidents: result.incidents,
isCurrentUser: result.driverId === currentDriverId,
}));
// Transform penalties
const penalties = resultsData.penalties.map((penalty: any) => ({
driverId: penalty.driverId,
driverName: resultsData.results.find((r: any) => r.driverId === penalty.driverId)?.driverName || 'Unknown',
type: penalty.type as 'time_penalty' | 'grid_penalty' | 'points_deduction' | 'disqualification' | 'warning' | 'license_points',
value: penalty.value || 0,
reason: 'Penalty applied', // Default since view model doesn't have reason
notes: undefined, // Default since view model doesn't have notes
}));
// Transform memberships
const memberships = membershipsData?.memberships.map((membership: any) => ({
driverId: membership.driverId,
role: membership.role || 'member',
}));
return {
raceTrack: resultsData.race?.track,
raceScheduledAt: resultsData.race?.scheduledAt,
totalDrivers: resultsData.stats?.totalDrivers,
leagueName: resultsData.league?.name,
raceSOF: sofData?.strengthOfField || null,
results,
penalties,
pointsSystem: resultsData.pointsSystem || {},
fastestLapTime: resultsData.fastestLapTime || 0,
memberships,
};
}
}