'use client'; import DriverIdentity from '@/components/drivers/DriverIdentity'; import EndRaceModal from '@/components/leagues/EndRaceModal'; import JoinLeagueButton from '@/components/leagues/JoinLeagueButton'; import LeagueActivityFeed from '@/components/leagues/LeagueActivityFeed'; import SponsorInsightsCard, { MetricBuilders, SlotTemplates, useSponsorMode, type SponsorMetric, } from '@/components/sponsors/SponsorInsightsCard'; import Button from '@/components/ui/Button'; import Card from '@/components/ui/Card'; import { useEffectiveDriverId } from '@/hooks/useEffectiveDriverId'; import { LeagueRoleDisplay } from '@/lib/display-objects/LeagueRoleDisplay'; import { useServices } from '@/lib/services/ServiceProvider'; import { LeagueDetailPageViewModel } from '@/lib/view-models/LeagueDetailPageViewModel'; import { Calendar, ExternalLink, Star, Trophy, Users } from 'lucide-react'; import { useParams, useRouter } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; export default function LeagueDetailPage() { const router = useRouter(); const params = useParams(); const leagueId = params.id as string; const isSponsor = useSponsorMode(); const { leagueService, leagueMembershipService, raceService } = useServices(); const [viewModel, setViewModel] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [endRaceModalRaceId, setEndRaceModalRaceId] = useState(null); const currentDriverId = useEffectiveDriverId(); const membership = leagueMembershipService.getMembership(leagueId, currentDriverId); // Build metrics for SponsorInsightsCard const leagueMetrics: SponsorMetric[] = useMemo(() => { if (!viewModel) return []; return [ MetricBuilders.views(viewModel.sponsorInsights.avgViewsPerRace, 'Avg Views/Race'), MetricBuilders.engagement(viewModel.sponsorInsights.engagementRate), MetricBuilders.reach(viewModel.sponsorInsights.estimatedReach), MetricBuilders.sof(viewModel.averageSOF ?? '—'), ]; }, [viewModel]); 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(); }; // Note: driver summaries are now handled by the ViewModel return loading ? (
Loading league...
) : error || !viewModel ? (
{error || 'League not found'}
) : ( <> {/* Sponsor Insights Card - Only shown to sponsors, at top of page */} {isSponsor && viewModel && ( )} {/* Live Race Card - Prominently show running races */} {viewModel && viewModel.runningRaces.length > 0 && (

🏁 Live Race in Progress

{viewModel.runningRaces.map((race) => (
LIVE

{race.name}

{membership?.role === 'admin' && ( )}
Started {new Date(race.date).toLocaleDateString()}
{race.registeredCount && (
{race.registeredCount} drivers registered
)} {race.strengthOfField && (
SOF: {race.strengthOfField}
)}
))}
)} {/* Action Card */} {!membership && !isSponsor && (

Join This League

Become a member to participate in races and track your progress

)} {/* League Overview - Activity Center with Info Sidebar */}
{/* Center - Activity Feed */}

Recent Activity

{/* Right Sidebar - League Info */}
{/* League Info - Combined */}

About

{/* Stats Grid */}
{viewModel.memberships.length}
Members
{viewModel.completedRacesCount}
Races
{viewModel.averageSOF ?? '—'}
Avg SOF
{/* Details */}
Structure Solo • {viewModel.settings.maxDrivers ?? 32} max
Scoring {viewModel.scoringConfig?.scoringPresetName ?? 'Standard'}
Created {new Date(viewModel.createdAt).toLocaleDateString('en-US', { month: 'short', year: 'numeric' })}
{viewModel.socialLinks && (
{viewModel.socialLinks.discordUrl && ( Discord )} {viewModel.socialLinks.youtubeUrl && ( YouTube )} {viewModel.socialLinks.websiteUrl && ( Website )}
)}
{/* Sponsors Section - Show sponsor logos */} {viewModel.sponsors.length > 0 && (

{viewModel.sponsors.find(s => s.tier === 'main') ? 'Presented by' : 'Sponsors'}

{/* Main Sponsor - Featured prominently */} {viewModel.sponsors.filter(s => s.tier === 'main').map(sponsor => (
{sponsor.logoUrl ? (
{sponsor.name}
) : (
)}
{sponsor.name} Main
{sponsor.tagline && (

{sponsor.tagline}

)}
{sponsor.websiteUrl && ( )}
))} {/* Secondary Sponsors - Smaller display */} {viewModel.sponsors.filter(s => s.tier === 'secondary').length > 0 && (
{viewModel.sponsors.filter(s => s.tier === 'secondary').map(sponsor => (
{sponsor.logoUrl ? (
{sponsor.name}
) : (
)}
{sponsor.name}
{sponsor.websiteUrl && ( )}
))}
)}
)} {/* Management */} {viewModel && (viewModel.ownerSummary || viewModel.adminSummaries.length > 0 || viewModel.stewardSummaries.length > 0) && (

Management

{viewModel.ownerSummary && (() => { const summary = viewModel.ownerSummary; const roleDisplay = LeagueRoleDisplay.getLeagueRoleDisplay('owner'); const meta = summary.rating !== null ? `Rating ${summary.rating}${summary.rank ? ` • Rank ${summary.rank}` : ''}` : null; return (
{roleDisplay.text}
); })()} {viewModel.adminSummaries.map((summary) => { const roleDisplay = LeagueRoleDisplay.getLeagueRoleDisplay('admin'); const meta = summary.rating !== null ? `Rating ${summary.rating}${summary.rank ? ` • Rank ${summary.rank}` : ''}` : null; return (
{roleDisplay.text}
); })} {viewModel.stewardSummaries.map((summary) => { const roleDisplay = LeagueRoleDisplay.getLeagueRoleDisplay('steward'); const meta = summary.rating !== null ? `Rating ${summary.rating}${summary.rank ? ` • Rank ${summary.rank}` : ''}` : null; return (
{roleDisplay.text}
); })}
)}
{/* End Race Modal */} {endRaceModalRaceId && viewModel && (() => { const race = viewModel.runningRaces.find(r => r.id === endRaceModalRaceId); return race ? ( { try { await raceService.completeRace(race.id); await loadLeagueData(); setEndRaceModalRaceId(null); } catch (err) { alert(err instanceof Error ? err.message : 'Failed to complete race'); } }} onCancel={() => setEndRaceModalRaceId(null)} /> ) : null; })()} ); }