117 lines
3.7 KiB
TypeScript
117 lines
3.7 KiB
TypeScript
import { notFound } from 'next/navigation';
|
|
import { PageWrapper } from '@/components/shared/state/PageWrapper';
|
|
import { RaceDetailTemplate } from '@/templates/RaceDetailTemplate';
|
|
import { PageDataFetcher } from '@/lib/page/PageDataFetcher';
|
|
import { RACE_SERVICE_TOKEN } from '@/lib/di/tokens';
|
|
import type { RaceService } from '@/lib/services/races/RaceService';
|
|
import type { RaceDetailViewModel } from '@/lib/view-models/RaceDetailViewModel';
|
|
|
|
interface RaceDetailPageProps {
|
|
params: {
|
|
id: string;
|
|
};
|
|
}
|
|
|
|
export default async function RaceDetailPage({ params }: RaceDetailPageProps) {
|
|
const raceId = params.id;
|
|
|
|
if (!raceId) {
|
|
notFound();
|
|
}
|
|
|
|
// Fetch initial race data
|
|
const data = await PageDataFetcher.fetch<RaceService, 'getRaceDetail'>(
|
|
RACE_SERVICE_TOKEN,
|
|
'getRaceDetail',
|
|
raceId,
|
|
'' // currentDriverId - will be handled client-side for auth
|
|
);
|
|
|
|
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: data.canReopenRace,
|
|
} : 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: () => {} }
|
|
}}
|
|
/>
|
|
);
|
|
} |