'use client'; import { useState, useEffect, useCallback } from 'react'; import { useParams } from 'next/navigation'; import Card from '@/components/ui/Card'; import StandingsTable from '@/components/leagues/StandingsTable'; import { EntityMappers, type DriverDTO, type LeagueDriverSeasonStatsDTO, } from '@gridpilot/racing'; import { getGetLeagueDriverSeasonStatsUseCase, getDriverRepository, getLeagueMembershipRepository } from '@/lib/di-container'; import { useEffectiveDriverId } from '@/lib/currentDriver'; import { isLeagueAdminOrHigherRole } from '@/lib/leagueRoles'; import type { MembershipRole, LeagueMembership } from '@/lib/leagueMembership'; export default function LeagueStandingsPage() { const params = useParams(); const leagueId = params.id as string; const currentDriverId = useEffectiveDriverId(); const [standings, setStandings] = useState([]); const [drivers, setDrivers] = useState([]); const [memberships, setMemberships] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [isAdmin, setIsAdmin] = useState(false); const loadData = useCallback(async () => { try { const getLeagueDriverSeasonStatsUseCase = getGetLeagueDriverSeasonStatsUseCase(); const driverRepo = getDriverRepository(); const membershipRepo = getLeagueMembershipRepository(); await getLeagueDriverSeasonStatsUseCase.execute({ leagueId }); type GetLeagueDriverSeasonStatsUseCaseType = { presenter: { getViewModel(): { stats: LeagueDriverSeasonStatsDTO[] }; }; }; const typedUseCase = getLeagueDriverSeasonStatsUseCase as GetLeagueDriverSeasonStatsUseCaseType; const standingsViewModel = typedUseCase.presenter.getViewModel(); setStandings(standingsViewModel.stats); const allDrivers = await driverRepo.findAll(); const driverDtos: DriverDTO[] = allDrivers .map((driver) => EntityMappers.toDriverDTO(driver)) .filter((dto): dto is DriverDTO => dto !== null); setDrivers(driverDtos); // Load league memberships from repository (consistent with other data) const allMemberships = await membershipRepo.getLeagueMembers(leagueId); type RawMembership = { id: string | number; leagueId: string; driverId: string; role: MembershipRole; status: LeagueMembership['status']; joinedAt: string | Date; }; // Convert to the format expected by StandingsTable (website-level LeagueMembership) const membershipData: LeagueMembership[] = (allMemberships as RawMembership[]).map((m) => ({ id: String(m.id), leagueId: m.leagueId, driverId: m.driverId, role: m.role, status: m.status, joinedAt: m.joinedAt instanceof Date ? m.joinedAt.toISOString() : String(m.joinedAt), })); setMemberships(membershipData); // Check if current user is admin const membership = await membershipRepo.getMembership(leagueId, currentDriverId); setIsAdmin(membership ? isLeagueAdminOrHigherRole(membership.role) : false); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load standings'); } finally { setLoading(false); } }, [leagueId, currentDriverId]); useEffect(() => { loadData(); }, [loadData]); const handleRemoveMember = async (driverId: string) => { if (!confirm('Are you sure you want to remove this member?')) { return; } try { const membershipRepo = getLeagueMembershipRepository(); const performer = await membershipRepo.getMembership(leagueId, currentDriverId); if (!performer || (performer.role !== 'owner' && performer.role !== 'admin')) { throw new Error('Only owners or admins can remove members'); } const membership = await membershipRepo.getMembership(leagueId, driverId); if (!membership) { throw new Error('Member not found'); } if (membership.role === 'owner') { throw new Error('Cannot remove the league owner'); } await membershipRepo.removeMembership(leagueId, driverId); await loadData(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to remove member'); } }; const handleUpdateRole = async (driverId: string, newRole: MembershipRole) => { try { const membershipRepo = getLeagueMembershipRepository(); const performer = await membershipRepo.getMembership(leagueId, currentDriverId); if (!performer || performer.role !== 'owner') { throw new Error('Only the league owner can update roles'); } const membership = await membershipRepo.getMembership(leagueId, driverId); if (!membership) { throw new Error('Member not found'); } if (membership.role === 'owner') { throw new Error('Cannot change the owner role'); } await membershipRepo.saveMembership({ ...membership, role: newRole, }); await loadData(); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to update role'); } }; if (loading) { return (
Loading standings...
); } if (error) { return (
{error}
); } const leader = standings[0]; const totalRaces = Math.max(...standings.map(s => s.racesStarted), 0); return (
{/* Championship Stats */} {standings.length > 0 && (
🏆

Championship Leader

{drivers.find(d => d.id === leader?.driverId)?.name || 'N/A'}

{leader?.totalPoints || 0} points

🏁

Races Completed

{totalRaces}

Season in progress

👥

Active Drivers

{standings.length}

Competing for points

)}

Championship Standings

); }