Files
gridpilot.gg/apps/website/lib/presenters/DashboardPresenter.ts
2026-01-12 01:01:49 +01:00

92 lines
3.6 KiB
TypeScript

import type { DashboardPageDto } from '@/lib/page-queries/DashboardPageDto';
import type { DashboardViewData } from '@/templates/DashboardViewData';
import {
formatDashboardDate,
formatRating,
formatRank,
formatConsistency,
formatRaceCount,
formatFriendCount,
formatLeaguePosition,
formatPoints,
formatTotalDrivers,
} from '@/lib/display-objects/DashboardDisplay';
/**
* DashboardPresenter - Client-side presenter for dashboard page
* Transforms Page DTO into ViewData for the template
* Deterministic; no hooks; no side effects
*/
export class DashboardPresenter {
static createViewData(pageDto: DashboardPageDto): DashboardViewData {
return {
currentDriver: {
name: pageDto.currentDriver?.name || '',
avatarUrl: pageDto.currentDriver?.avatarUrl || '',
country: pageDto.currentDriver?.country || '',
rating: pageDto.currentDriver ? formatRating(pageDto.currentDriver.rating) : '0.0',
rank: pageDto.currentDriver ? formatRank(pageDto.currentDriver.globalRank) : '0',
totalRaces: pageDto.currentDriver ? formatRaceCount(pageDto.currentDriver.totalRaces) : '0',
wins: pageDto.currentDriver ? formatRaceCount(pageDto.currentDriver.wins) : '0',
podiums: pageDto.currentDriver ? formatRaceCount(pageDto.currentDriver.podiums) : '0',
consistency: pageDto.currentDriver ? formatConsistency(pageDto.currentDriver.consistency) : '0%',
},
nextRace: pageDto.nextRace ? (() => {
const dateInfo = formatDashboardDate(new Date(pageDto.nextRace.scheduledAt));
return {
id: pageDto.nextRace.id,
track: pageDto.nextRace.track,
car: pageDto.nextRace.car,
scheduledAt: pageDto.nextRace.scheduledAt,
formattedDate: dateInfo.date,
formattedTime: dateInfo.time,
timeUntil: dateInfo.relative,
isMyLeague: pageDto.nextRace.isMyLeague,
};
})() : null,
upcomingRaces: pageDto.upcomingRaces.map((race) => {
const dateInfo = formatDashboardDate(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,
};
}),
leagueStandings: pageDto.leagueStandingsSummaries.map((standing) => ({
leagueId: standing.leagueId,
leagueName: standing.leagueName,
position: formatLeaguePosition(standing.position),
points: formatPoints(standing.points),
totalDrivers: formatTotalDrivers(standing.totalDrivers),
})),
feedItems: pageDto.feedSummary.items.map((item) => ({
id: item.id,
type: item.type,
headline: item.headline,
body: item.body,
timestamp: item.timestamp,
formattedTime: formatDashboardDate(new Date(item.timestamp)).relative,
ctaHref: item.ctaHref,
ctaLabel: item.ctaLabel,
})),
friends: pageDto.friends.map((friend) => ({
id: friend.id,
name: friend.name,
avatarUrl: friend.avatarUrl,
country: friend.country,
})),
activeLeaguesCount: formatRaceCount(pageDto.activeLeaguesCount),
friendCount: formatFriendCount(pageDto.friends.length),
hasUpcomingRaces: pageDto.upcomingRaces.length > 0,
hasLeagueStandings: pageDto.leagueStandingsSummaries.length > 0,
hasFeedItems: pageDto.feedSummary.items.length > 0,
hasFriends: pageDto.friends.length > 0,
};
}
}