import type { GetDriverProfileOutputDTO } from '@/lib/types/generated/GetDriverProfileOutputDTO'; import type { DriverProfileViewData } from '@/lib/types/view-data/DriverProfileViewData'; import { DateDisplay } from '@/lib/display-objects/DateDisplay'; import { RatingDisplay } from '@/lib/display-objects/RatingDisplay'; import { NumberDisplay } from '@/lib/display-objects/NumberDisplay'; import { FinishDisplay } from '@/lib/display-objects/FinishDisplay'; import { PercentDisplay } from '@/lib/display-objects/PercentDisplay'; /** * DriverProfileViewDataBuilder * * Transforms GetDriverProfileOutputDTO into ViewData for the driver profile page. * Deterministic, side-effect free, no HTTP calls. */ export class DriverProfileViewDataBuilder { static build(apiDto: GetDriverProfileOutputDTO): DriverProfileViewData { return { currentDriver: apiDto.currentDriver ? { id: apiDto.currentDriver.id, name: apiDto.currentDriver.name, country: apiDto.currentDriver.country, avatarUrl: apiDto.currentDriver.avatarUrl || '', iracingId: typeof apiDto.currentDriver.iracingId === 'string' ? parseInt(apiDto.currentDriver.iracingId, 10) : (apiDto.currentDriver.iracingId ?? null), joinedAt: apiDto.currentDriver.joinedAt, joinedAtLabel: DateDisplay.formatMonthYear(apiDto.currentDriver.joinedAt), rating: apiDto.currentDriver.rating ?? null, ratingLabel: RatingDisplay.format(apiDto.currentDriver.rating), globalRank: apiDto.currentDriver.globalRank ?? null, globalRankLabel: apiDto.currentDriver.globalRank != null ? `#${apiDto.currentDriver.globalRank}` : '—', consistency: apiDto.currentDriver.consistency ?? null, bio: apiDto.currentDriver.bio ?? null, totalDrivers: apiDto.currentDriver.totalDrivers ?? null, } : null, stats: apiDto.stats ? { totalRaces: apiDto.stats.totalRaces, totalRacesLabel: NumberDisplay.format(apiDto.stats.totalRaces), wins: apiDto.stats.wins, winsLabel: NumberDisplay.format(apiDto.stats.wins), podiums: apiDto.stats.podiums, podiumsLabel: NumberDisplay.format(apiDto.stats.podiums), dnfs: apiDto.stats.dnfs, dnfsLabel: NumberDisplay.format(apiDto.stats.dnfs), avgFinish: apiDto.stats.avgFinish ?? null, avgFinishLabel: FinishDisplay.formatAverage(apiDto.stats.avgFinish), bestFinish: apiDto.stats.bestFinish ?? null, bestFinishLabel: FinishDisplay.format(apiDto.stats.bestFinish), worstFinish: apiDto.stats.worstFinish ?? null, worstFinishLabel: FinishDisplay.format(apiDto.stats.worstFinish), finishRate: apiDto.stats.finishRate ?? null, winRate: apiDto.stats.winRate ?? null, podiumRate: apiDto.stats.podiumRate ?? null, percentile: apiDto.stats.percentile ?? null, rating: apiDto.stats.rating ?? null, ratingLabel: RatingDisplay.format(apiDto.stats.rating), consistency: apiDto.stats.consistency ?? null, consistencyLabel: PercentDisplay.formatWhole(apiDto.stats.consistency), overallRank: apiDto.stats.overallRank ?? null, } : null, finishDistribution: apiDto.finishDistribution ? { totalRaces: apiDto.finishDistribution.totalRaces, wins: apiDto.finishDistribution.wins, podiums: apiDto.finishDistribution.podiums, topTen: apiDto.finishDistribution.topTen, dnfs: apiDto.finishDistribution.dnfs, other: apiDto.finishDistribution.other, } : null, teamMemberships: apiDto.teamMemberships.map(m => ({ teamId: m.teamId, teamName: m.teamName, teamTag: m.teamTag ?? null, role: m.role, joinedAt: m.joinedAt, joinedAtLabel: DateDisplay.formatMonthYear(m.joinedAt), isCurrent: m.isCurrent, })), socialSummary: { friendsCount: apiDto.socialSummary.friendsCount, friends: apiDto.socialSummary.friends.map(f => ({ id: f.id, name: f.name, country: f.country, avatarUrl: f.avatarUrl || '', })), }, extendedProfile: apiDto.extendedProfile ? { socialHandles: apiDto.extendedProfile.socialHandles.map(h => ({ platform: h.platform, handle: h.handle, url: h.url, })), achievements: apiDto.extendedProfile.achievements.map(a => ({ id: a.id, title: a.title, description: a.description, icon: a.icon, rarity: a.rarity, rarityLabel: a.rarity, earnedAt: a.earnedAt, earnedAtLabel: DateDisplay.formatShort(a.earnedAt), })), racingStyle: apiDto.extendedProfile.racingStyle, favoriteTrack: apiDto.extendedProfile.favoriteTrack, favoriteCar: apiDto.extendedProfile.favoriteCar, timezone: apiDto.extendedProfile.timezone, availableHours: apiDto.extendedProfile.availableHours, lookingForTeam: apiDto.extendedProfile.lookingForTeam, openToRequests: apiDto.extendedProfile.openToRequests, } : null, }; } }