Files
gridpilot.gg/apps/website/app/races/[id]/page.tsx
2026-01-14 02:02:24 +01:00

124 lines
4.0 KiB
TypeScript

import { notFound } from 'next/navigation';
import { PageWrapper } from '@/components/shared/state/PageWrapper';
import { RaceDetailTemplate } from '@/templates/RaceDetailTemplate';
import { RacesApiClient } from '@/lib/api/races/RacesApiClient';
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
import { getWebsiteApiBaseUrl } from '@/lib/config/apiBaseUrl';
interface RaceDetailPageProps {
params: {
id: string;
};
}
export default async function RaceDetailPage({ params }: RaceDetailPageProps) {
const raceId = params.id;
if (!raceId) {
notFound();
}
// Manual wiring: create dependencies
const baseUrl = getWebsiteApiBaseUrl();
const logger = new ConsoleLogger();
const errorReporter = new EnhancedErrorReporter(logger, {
showUserNotifications: true,
logToConsole: true,
reportToExternal: process.env.NODE_ENV === 'production',
});
// Create API client
const apiClient = new RacesApiClient(baseUrl, errorReporter, logger);
// Fetch initial race data (empty driverId for now, handled client-side)
const data = await apiClient.getDetail(raceId, '');
if (!data) notFound();
// Transform data for template
const templateViewModel = data && data.race ? {
race: {
id: data.race.id,
track: data.race.track,
car: data.race.car,
scheduledAt: data.race.scheduledAt,
status: data.race.status as 'scheduled' | 'running' | 'completed' | 'cancelled',
sessionType: data.race.sessionType,
},
league: data.league ? {
id: data.league.id,
name: data.league.name,
description: data.league.description || undefined,
settings: data.league.settings as { maxDrivers: number; qualifyingFormat: string },
} : undefined,
entryList: data.entryList.map((entry: any) => ({
id: entry.id,
name: entry.name,
avatarUrl: entry.avatarUrl,
country: entry.country,
rating: entry.rating,
isCurrentUser: entry.isCurrentUser,
})),
registration: {
isUserRegistered: data.registration.isUserRegistered,
canRegister: data.registration.canRegister,
},
userResult: data.userResult ? {
position: data.userResult.position,
startPosition: data.userResult.startPosition,
positionChange: data.userResult.positionChange,
incidents: data.userResult.incidents,
isClean: data.userResult.isClean,
isPodium: data.userResult.isPodium,
ratingChange: data.userResult.ratingChange,
} : undefined,
canReopenRace: false, // Not provided by API, default to false
} : undefined;
return (
<PageWrapper
data={data}
Template={({ data }) => (
<RaceDetailTemplate
viewModel={templateViewModel}
isLoading={false}
error={null}
// These will be handled client-side in the template or a wrapper
onBack={() => {}}
onRegister={() => {}}
onWithdraw={() => {}}
onCancel={() => {}}
onReopen={() => {}}
onEndRace={() => {}}
onFileProtest={() => {}}
onResultsClick={() => {}}
onStewardingClick={() => {}}
onLeagueClick={() => {}}
onDriverClick={() => {}}
currentDriverId={''}
isOwnerOrAdmin={false}
showProtestModal={false}
setShowProtestModal={() => {}}
showEndRaceModal={false}
setShowEndRaceModal={() => {}}
mutationLoading={{
register: false,
withdraw: false,
cancel: false,
reopen: false,
complete: false,
}}
/>
)}
loading={{ variant: 'skeleton', message: 'Loading race details...' }}
errorConfig={{ variant: 'full-screen' }}
empty={{
icon: require('lucide-react').Flag,
title: 'Race not found',
description: 'The race may have been cancelled or deleted',
action: { label: 'Back to Races', onClick: () => {} }
}}
/>
);
}