/** * Application Layer: Entity to DTO Mappers * * Transforms domain entities to plain objects for crossing architectural boundaries. * These mappers handle the Server Component -> Client Component boundary in Next.js 15. */ import { Driver } from '@/domain/entities/Driver'; import { League } from '@/domain/entities/League'; import { Race } from '@/domain/entities/Race'; import { Result } from '@/domain/entities/Result'; import { Standing } from '@/domain/entities/Standing'; export type DriverDTO = { id: string; iracingId: string; name: string; country: string; bio?: string; joinedAt: string; }; export type LeagueDTO = { id: string; name: string; description: string; ownerId: string; settings: { pointsSystem: 'f1-2024' | 'indycar' | 'custom'; sessionDuration?: number; qualifyingFormat?: 'single-lap' | 'open'; customPoints?: Record; }; createdAt: string; }; export type RaceDTO = { id: string; leagueId: string; scheduledAt: string; track: string; car: string; sessionType: 'practice' | 'qualifying' | 'race'; status: 'scheduled' | 'completed' | 'cancelled'; }; export type ResultDTO = { id: string; raceId: string; driverId: string; position: number; fastestLap: number; incidents: number; startPosition: number; }; export type StandingDTO = { leagueId: string; driverId: string; points: number; wins: number; position: number; racesCompleted: number; }; export class EntityMappers { static toDriverDTO(driver: Driver | null): DriverDTO | null { if (!driver) return null; return { id: driver.id, iracingId: driver.iracingId, name: driver.name, country: driver.country, bio: driver.bio, joinedAt: driver.joinedAt.toISOString(), }; } static toLeagueDTO(league: League | null): LeagueDTO | null { if (!league) return null; return { id: league.id, name: league.name, description: league.description, ownerId: league.ownerId, settings: league.settings, createdAt: league.createdAt.toISOString(), }; } static toLeagueDTOs(leagues: League[]): LeagueDTO[] { return leagues.map(league => ({ id: league.id, name: league.name, description: league.description, ownerId: league.ownerId, settings: league.settings, createdAt: league.createdAt.toISOString(), })); } static toRaceDTO(race: Race | null): RaceDTO | null { if (!race) return null; return { id: race.id, leagueId: race.leagueId, scheduledAt: race.scheduledAt.toISOString(), track: race.track, car: race.car, sessionType: race.sessionType, status: race.status, }; } static toRaceDTOs(races: Race[]): RaceDTO[] { return races.map(race => ({ id: race.id, leagueId: race.leagueId, scheduledAt: race.scheduledAt.toISOString(), track: race.track, car: race.car, sessionType: race.sessionType, status: race.status, })); } static toResultDTO(result: Result | null): ResultDTO | null { if (!result) return null; return { id: result.id, raceId: result.raceId, driverId: result.driverId, position: result.position, fastestLap: result.fastestLap, incidents: result.incidents, startPosition: result.startPosition, }; } static toResultDTOs(results: Result[]): ResultDTO[] { return results.map(result => ({ id: result.id, raceId: result.raceId, driverId: result.driverId, position: result.position, fastestLap: result.fastestLap, incidents: result.incidents, startPosition: result.startPosition, })); } static toStandingDTO(standing: Standing | null): StandingDTO | null { if (!standing) return null; return { leagueId: standing.leagueId, driverId: standing.driverId, points: standing.points, wins: standing.wins, position: standing.position, racesCompleted: standing.racesCompleted, }; } static toStandingDTOs(standings: Standing[]): StandingDTO[] { return standings.map(standing => ({ leagueId: standing.leagueId, driverId: standing.driverId, points: standing.points, wins: standing.wins, position: standing.position, racesCompleted: standing.racesCompleted, })); } }