124 lines
3.6 KiB
TypeScript
124 lines
3.6 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
|
import { useParams, useRouter } from 'next/navigation';
|
|
import { LeagueDetailTemplate } from '@/templates/LeagueDetailTemplate';
|
|
import { useServices } from '@/lib/services/ServiceProvider';
|
|
import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId';
|
|
import { useSponsorMode } from '@/components/sponsors/SponsorInsightsCard';
|
|
import { LeagueDetailPageViewModel } from '@/lib/view-models/LeagueDetailPageViewModel';
|
|
import EndRaceModal from '@/components/leagues/EndRaceModal';
|
|
|
|
export default function LeagueDetailInteractive() {
|
|
const router = useRouter();
|
|
const params = useParams();
|
|
const leagueId = params.id as string;
|
|
const isSponsor = useSponsorMode();
|
|
const { leagueService, leagueMembershipService, raceService } = useServices();
|
|
|
|
const [viewModel, setViewModel] = useState<LeagueDetailPageViewModel | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [endRaceModalRaceId, setEndRaceModalRaceId] = useState<string | null>(null);
|
|
|
|
const currentDriverId = useEffectiveDriverId();
|
|
const membership = leagueMembershipService.getMembership(leagueId, currentDriverId);
|
|
|
|
const loadLeagueData = async () => {
|
|
try {
|
|
const viewModelData = await leagueService.getLeagueDetailPageData(leagueId);
|
|
|
|
if (!viewModelData) {
|
|
setError('League not found');
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
setViewModel(viewModelData);
|
|
} catch (err) {
|
|
setError(err instanceof Error ? err.message : 'Failed to load league');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
loadLeagueData();
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [leagueId]);
|
|
|
|
const handleMembershipChange = () => {
|
|
loadLeagueData();
|
|
};
|
|
|
|
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 loadLeagueData();
|
|
setEndRaceModalRaceId(null);
|
|
} catch (err) {
|
|
alert(err instanceof Error ? err.message : 'Failed to complete race');
|
|
}
|
|
};
|
|
|
|
const handleEndRaceCancel = () => {
|
|
setEndRaceModalRaceId(null);
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<div className="text-center text-gray-400">Loading league...</div>
|
|
);
|
|
}
|
|
|
|
if (error || !viewModel) {
|
|
return (
|
|
<div className="text-center text-warning-amber">
|
|
{error || 'League not found'}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<LeagueDetailTemplate
|
|
viewModel={viewModel}
|
|
leagueId={leagueId}
|
|
isSponsor={isSponsor}
|
|
membership={membership}
|
|
currentDriverId={currentDriverId}
|
|
onMembershipChange={handleMembershipChange}
|
|
onEndRaceModalOpen={handleEndRaceModalOpen}
|
|
onLiveRaceClick={handleLiveRaceClick}
|
|
onBackToLeagues={handleBackToLeagues}
|
|
>
|
|
{/* End Race Modal */}
|
|
{endRaceModalRaceId && viewModel && (() => {
|
|
const race = viewModel.runningRaces.find(r => r.id === endRaceModalRaceId);
|
|
return race ? (
|
|
<EndRaceModal
|
|
raceId={race.id}
|
|
raceName={race.name}
|
|
onConfirm={handleEndRaceConfirm}
|
|
onCancel={handleEndRaceCancel}
|
|
/>
|
|
) : null;
|
|
})()}
|
|
</LeagueDetailTemplate>
|
|
</>
|
|
);
|
|
} |