Files
gridpilot.gg/apps/website/lib/page-queries/page-queries/DashboardPageQuery.ts
2026-01-12 01:01:49 +01:00

149 lines
5.1 KiB
TypeScript

import { DashboardApiClient } from '@/lib/api/dashboard/DashboardApiClient';
import { ConsoleErrorReporter } from '@/lib/infrastructure/logging/ConsoleErrorReporter';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
import type { DashboardOverviewDTO } from '@/lib/types/generated/DashboardOverviewDTO';
import type { PageQueryResult } from '@/lib/page-queries/page-query-result/PageQueryResult';
import type { DashboardPageDto } from '@/lib/page-queries/page-dtos/DashboardPageDto';
interface ErrorWithStatusCode extends Error {
statusCode?: number;
}
/**
* Transform DashboardOverviewDTO to DashboardPageDto
* Converts Date objects to ISO strings for JSON serialization
*/
function transformDtoToPageDto(dto: DashboardOverviewDTO): DashboardPageDto {
return {
currentDriver: dto.currentDriver ? {
id: dto.currentDriver.id,
name: dto.currentDriver.name,
avatarUrl: dto.currentDriver.avatarUrl || '',
country: dto.currentDriver.country,
totalRaces: dto.currentDriver.totalRaces,
wins: dto.currentDriver.wins,
podiums: dto.currentDriver.podiums,
rating: dto.currentDriver.rating ?? 0,
globalRank: dto.currentDriver.globalRank ?? 0,
consistency: dto.currentDriver.consistency ?? 0,
} : undefined,
myUpcomingRaces: dto.myUpcomingRaces.map(race => ({
id: race.id,
track: race.track,
car: race.car,
scheduledAt: new Date(race.scheduledAt).toISOString(),
status: race.status,
isMyLeague: race.isMyLeague,
})),
otherUpcomingRaces: dto.otherUpcomingRaces.map(race => ({
id: race.id,
track: race.track,
car: race.car,
scheduledAt: new Date(race.scheduledAt).toISOString(),
status: race.status,
isMyLeague: race.isMyLeague,
})),
upcomingRaces: dto.upcomingRaces.map(race => ({
id: race.id,
track: race.track,
car: race.car,
scheduledAt: new Date(race.scheduledAt).toISOString(),
status: race.status,
isMyLeague: race.isMyLeague,
})),
activeLeaguesCount: dto.activeLeaguesCount,
nextRace: dto.nextRace ? {
id: dto.nextRace.id,
track: dto.nextRace.track,
car: dto.nextRace.car,
scheduledAt: new Date(dto.nextRace.scheduledAt).toISOString(),
status: dto.nextRace.status,
isMyLeague: dto.nextRace.isMyLeague,
} : undefined,
recentResults: dto.recentResults.map(result => ({
id: result.raceId,
track: result.raceName,
car: '', // Not in DTO, will need to handle
position: result.position,
date: new Date(result.finishedAt).toISOString(),
})),
leagueStandingsSummaries: dto.leagueStandingsSummaries.map(standing => ({
leagueId: standing.leagueId,
leagueName: standing.leagueName,
position: standing.position,
points: standing.points,
totalDrivers: standing.totalDrivers,
})),
feedSummary: {
notificationCount: dto.feedSummary.notificationCount,
items: dto.feedSummary.items.map(item => ({
id: item.id,
type: item.type,
headline: item.headline,
body: item.body,
timestamp: new Date(item.timestamp).toISOString(),
ctaHref: item.ctaHref,
ctaLabel: item.ctaLabel,
})),
},
friends: dto.friends.map(friend => ({
id: friend.id,
name: friend.name,
avatarUrl: friend.avatarUrl || '',
country: friend.country,
})),
};
}
/**
* Dashboard page query with manual wiring
* Returns PageQueryResult<DashboardPageDto>
* No DI container usage - constructs dependencies explicitly
*/
export class DashboardPageQuery {
/**
* Execute the dashboard page query
* Constructs API client manually with required dependencies
*/
static async execute(): Promise<PageQueryResult<DashboardPageDto>> {
try {
// Manual wiring: construct dependencies explicitly
const errorReporter = new ConsoleErrorReporter();
const logger = new ConsoleLogger();
// Construct API client with required dependencies
// Using environment variable for base URL, fallback to empty string
const baseUrl = process.env.NEXT_PUBLIC_API_URL || '';
const apiClient = new DashboardApiClient(baseUrl, errorReporter, logger);
// Fetch data
const dto = await apiClient.getDashboardOverview();
if (!dto) {
return { status: 'notFound' };
}
// Transform to Page DTO
const pageDto = transformDtoToPageDto(dto);
return { status: 'ok', dto: pageDto };
} catch (error) {
// Handle specific error types
if (error instanceof Error) {
const errorWithStatus = error as ErrorWithStatusCode;
if (errorWithStatus.message?.includes('not found') || errorWithStatus.statusCode === 404) {
return { status: 'notFound' };
}
// Check if it's a redirect error
if (errorWithStatus.message?.includes('redirect') || errorWithStatus.statusCode === 302) {
return { status: 'redirect', to: '/' };
}
return { status: 'error', errorId: 'DASHBOARD_FETCH_FAILED' };
}
return { status: 'error', errorId: 'UNKNOWN_ERROR' };
}
}
}