90 lines
3.1 KiB
TypeScript
90 lines
3.1 KiB
TypeScript
|
|
|
|
import type { ViewDataBuilder } from '@/lib/contracts/builders/ViewDataBuilder';
|
|
import type { LeagueMemberDTO } from '@/lib/types/generated/LeagueMemberDTO';
|
|
import type { LeagueStandingDTO } from '@/lib/types/generated/LeagueStandingDTO';
|
|
import type { LeagueStandingsViewData } from '@/lib/view-data/LeagueStandingsViewData';
|
|
|
|
interface LeagueStandingsApiDto {
|
|
standings: LeagueStandingDTO[];
|
|
}
|
|
|
|
interface LeagueMembershipsApiDto {
|
|
members: LeagueMemberDTO[];
|
|
}
|
|
|
|
type LeagueStandingsInputDTO = {
|
|
standingsDto: LeagueStandingsApiDto;
|
|
membershipsDto: LeagueMembershipsApiDto;
|
|
leagueId: string;
|
|
isTeamChampionship?: boolean;
|
|
}
|
|
|
|
export class LeagueStandingsViewDataBuilder {
|
|
public static build(apiDto: LeagueStandingsInputDTO): LeagueStandingsViewData {
|
|
const { standingsDto, membershipsDto, leagueId, isTeamChampionship = false } = apiDto;
|
|
const standings = standingsDto.standings || [];
|
|
const members = membershipsDto.members || [];
|
|
|
|
// Convert LeagueStandingDTO to StandingEntryData
|
|
const standingData: LeagueStandingsViewData['standings'] = standings.map(standing => ({
|
|
driverId: standing.driverId,
|
|
position: standing.position,
|
|
points: standing.points,
|
|
totalPoints: standing.points,
|
|
races: standing.races,
|
|
racesFinished: standing.races,
|
|
racesStarted: standing.races,
|
|
avgFinish: 0, // Not in DTO
|
|
penaltyPoints: 0, // Not in DTO
|
|
bonusPoints: 0, // Not in DTO
|
|
leaderPoints: 0, // Not in DTO
|
|
nextPoints: 0, // Not in DTO
|
|
currentUserId: '', // Not in DTO
|
|
// New fields from Phase 3
|
|
positionChange: standing.positionChange || 0,
|
|
lastRacePoints: standing.lastRacePoints || 0,
|
|
droppedRaceIds: standing.droppedRaceIds || [],
|
|
wins: standing.wins || 0,
|
|
podiums: standing.podiums || 0,
|
|
}));
|
|
|
|
// Extract unique drivers from standings
|
|
const driverMap = new Map<string, LeagueStandingsViewData['drivers'][number]>();
|
|
standings.forEach(standing => {
|
|
if (standing.driver && !driverMap.has(standing.driverId)) {
|
|
const driver = standing.driver;
|
|
driverMap.set(standing.driverId, {
|
|
id: standing.driverId,
|
|
name: driver.name,
|
|
avatarUrl: null, // DTO may not have this
|
|
iracingId: driver.iracingId,
|
|
rating: undefined,
|
|
country: driver.country,
|
|
});
|
|
}
|
|
});
|
|
const driverData = Array.from(driverMap.values());
|
|
|
|
// Convert LeagueMemberDTO to LeagueMembershipData
|
|
const membershipData: LeagueStandingsViewData['memberships'] = members.map(member => ({
|
|
driverId: member.driverId,
|
|
leagueId: leagueId,
|
|
role: (member.role as any) || 'member',
|
|
joinedAt: member.joinedAt,
|
|
status: 'active' as const,
|
|
}));
|
|
|
|
return {
|
|
standings: standingData,
|
|
drivers: driverData,
|
|
memberships: membershipData,
|
|
leagueId,
|
|
currentDriverId: '', // Would need to get from auth
|
|
isAdmin: false, // Would need to check permissions
|
|
isTeamChampionship: isTeamChampionship,
|
|
};
|
|
}
|
|
}
|
|
|
|
LeagueStandingsViewDataBuilder satisfies ViewDataBuilder<LeagueStandingsInputDTO, LeagueStandingsViewData>; |