111 lines
3.6 KiB
TypeScript
111 lines
3.6 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { useParams, useRouter } from 'next/navigation';
|
|
import { LeagueDetailTemplate } from '@/templates/LeagueDetailTemplate';
|
|
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
|
import { useSponsorMode } from '@/components/sponsors/SponsorInsightsCard';
|
|
import EndRaceModal from '@/components/leagues/EndRaceModal';
|
|
|
|
// Shared state components
|
|
import { StateContainer } from '@/components/shared/state/StateContainer';
|
|
import { useLeagueDetailWithSponsors } from '@/hooks/league/useLeagueDetailWithSponsors';
|
|
import { useInject } from '@/lib/di/hooks/useInject';
|
|
import { LEAGUE_MEMBERSHIP_SERVICE_TOKEN, RACE_SERVICE_TOKEN } from '@/lib/di/tokens';
|
|
import { Trophy } from 'lucide-react';
|
|
|
|
export default function LeagueDetailInteractive() {
|
|
const router = useRouter();
|
|
const params = useParams();
|
|
const leagueId = params.id as string;
|
|
const isSponsor = useSponsorMode();
|
|
const leagueMembershipService = useInject(LEAGUE_MEMBERSHIP_SERVICE_TOKEN);
|
|
const raceService = useInject(RACE_SERVICE_TOKEN);
|
|
|
|
const [endRaceModalRaceId, setEndRaceModalRaceId] = useState<string | null>(null);
|
|
|
|
const currentDriverId = useEffectiveDriverId();
|
|
const membership = leagueMembershipService.getMembership(leagueId, currentDriverId);
|
|
|
|
const { data: viewModel, isLoading, error, retry } = useLeagueDetailWithSponsors(leagueId);
|
|
|
|
const handleMembershipChange = () => {
|
|
retry();
|
|
};
|
|
|
|
const handleEndRaceModalOpen = (raceId: string) => {
|
|
setEndRaceModalRaceId(raceId);
|
|
};
|
|
|
|
const handleLiveRaceClick = (raceId: string) => {
|
|
router.push(`/races/${raceId}`);
|
|
};
|
|
|
|
const handleBackToLeagues = () => {
|
|
router.push('/leagues');
|
|
};
|
|
|
|
const handleEndRaceConfirm = async () => {
|
|
if (!endRaceModalRaceId) return;
|
|
|
|
try {
|
|
await raceService.completeRace(endRaceModalRaceId);
|
|
await retry();
|
|
setEndRaceModalRaceId(null);
|
|
} catch (err) {
|
|
alert(err instanceof Error ? err.message : 'Failed to complete race');
|
|
}
|
|
};
|
|
|
|
const handleEndRaceCancel = () => {
|
|
setEndRaceModalRaceId(null);
|
|
};
|
|
|
|
return (
|
|
<StateContainer
|
|
data={viewModel}
|
|
isLoading={isLoading}
|
|
error={error}
|
|
retry={retry}
|
|
config={{
|
|
loading: { variant: 'skeleton', message: 'Loading league...' },
|
|
error: { variant: 'full-screen' },
|
|
empty: {
|
|
icon: Trophy,
|
|
title: 'League not found',
|
|
description: 'The league may have been deleted or you may not have access',
|
|
action: { label: 'Back to Leagues', onClick: handleBackToLeagues }
|
|
}
|
|
}}
|
|
>
|
|
{(leagueData) => (
|
|
<>
|
|
<LeagueDetailTemplate
|
|
viewModel={leagueData!}
|
|
leagueId={leagueId}
|
|
isSponsor={isSponsor}
|
|
membership={membership}
|
|
currentDriverId={currentDriverId}
|
|
onMembershipChange={handleMembershipChange}
|
|
onEndRaceModalOpen={handleEndRaceModalOpen}
|
|
onLiveRaceClick={handleLiveRaceClick}
|
|
onBackToLeagues={handleBackToLeagues}
|
|
>
|
|
{/* End Race Modal */}
|
|
{endRaceModalRaceId && leagueData && (() => {
|
|
const race = leagueData.runningRaces.find(r => r.id === endRaceModalRaceId);
|
|
return race ? (
|
|
<EndRaceModal
|
|
raceId={race.id}
|
|
raceName={race.name}
|
|
onConfirm={handleEndRaceConfirm}
|
|
onCancel={handleEndRaceCancel}
|
|
/>
|
|
) : null;
|
|
})()}
|
|
</LeagueDetailTemplate>
|
|
</>
|
|
)}
|
|
</StateContainer>
|
|
);
|
|
} |