import type { DashboardOverviewDTO } from '@/lib/types/generated/DashboardOverviewDTO'; import type { DashboardViewData } from '@/lib/view-data/DashboardViewData'; import { DashboardDateDisplay } from '@/lib/display-objects/DashboardDateDisplay'; import { RatingDisplay } from '@/lib/display-objects/RatingDisplay'; import { DashboardRankDisplay } from '@/lib/display-objects/DashboardRankDisplay'; import { DashboardConsistencyDisplay } from '@/lib/display-objects/DashboardConsistencyDisplay'; import { DashboardCountDisplay } from '@/lib/display-objects/DashboardCountDisplay'; import { DashboardLeaguePositionDisplay } from '@/lib/display-objects/DashboardLeaguePositionDisplay'; /** * DashboardViewDataBuilder * * Transforms DashboardOverviewDTO (API DTO) into DashboardViewData for server-side rendering. * Deterministic; side-effect free; no HTTP calls. */ export class DashboardViewDataBuilder { static build(apiDto: DashboardOverviewDTO): DashboardViewData { return { currentDriver: { name: apiDto.currentDriver?.name || '', avatarUrl: apiDto.currentDriver?.avatarUrl || '', country: apiDto.currentDriver?.country || '', rating: apiDto.currentDriver ? RatingDisplay.format(apiDto.currentDriver.rating ?? 0) : '0.0', rank: apiDto.currentDriver ? DashboardRankDisplay.format(apiDto.currentDriver.globalRank ?? 0) : '0', totalRaces: apiDto.currentDriver ? DashboardCountDisplay.format(apiDto.currentDriver.totalRaces ?? 0) : '0', wins: apiDto.currentDriver ? DashboardCountDisplay.format(apiDto.currentDriver.wins ?? 0) : '0', podiums: apiDto.currentDriver ? DashboardCountDisplay.format(apiDto.currentDriver.podiums ?? 0) : '0', consistency: apiDto.currentDriver ? DashboardConsistencyDisplay.format(apiDto.currentDriver.consistency ?? 0) : '0%', }, nextRace: apiDto.nextRace ? DashboardViewDataBuilder.buildNextRace(apiDto.nextRace) : null, upcomingRaces: apiDto.upcomingRaces.map((race) => DashboardViewDataBuilder.buildRace(race)), leagueStandings: apiDto.leagueStandingsSummaries.map((standing) => ({ leagueId: standing.leagueId, leagueName: standing.leagueName, position: DashboardLeaguePositionDisplay.format(standing.position), points: DashboardCountDisplay.format(standing.points), totalDrivers: DashboardCountDisplay.format(standing.totalDrivers), })), feedItems: apiDto.feedSummary.items.map((item) => ({ id: item.id, type: item.type, headline: item.headline, body: item.body, timestamp: item.timestamp, formattedTime: DashboardDateDisplay.format(new Date(item.timestamp)).relative, ctaHref: item.ctaHref, ctaLabel: item.ctaLabel, })), friends: apiDto.friends.map((friend) => ({ id: friend.id, name: friend.name, avatarUrl: friend.avatarUrl || '', country: friend.country, })), activeLeaguesCount: DashboardCountDisplay.format(apiDto.activeLeaguesCount), friendCount: DashboardCountDisplay.format(apiDto.friends.length), hasUpcomingRaces: apiDto.upcomingRaces.length > 0, hasLeagueStandings: apiDto.leagueStandingsSummaries.length > 0, hasFeedItems: apiDto.feedSummary.items.length > 0, hasFriends: apiDto.friends.length > 0, }; } private static buildNextRace(race: NonNullable) { const dateInfo = DashboardDateDisplay.format(new Date(race.scheduledAt)); return { id: race.id, track: race.track, car: race.car, scheduledAt: race.scheduledAt, formattedDate: dateInfo.date, formattedTime: dateInfo.time, timeUntil: dateInfo.relative, isMyLeague: race.isMyLeague, }; } private static buildRace(race: DashboardOverviewDTO['upcomingRaces'][number]) { const dateInfo = DashboardDateDisplay.format(new Date(race.scheduledAt)); return { id: race.id, track: race.track, car: race.car, scheduledAt: race.scheduledAt, formattedDate: dateInfo.date, formattedTime: dateInfo.time, timeUntil: dateInfo.relative, isMyLeague: race.isMyLeague, }; } }