import { useEffect, useRef, useState } from "react"; import { Link, useSearchParams } from "react-router"; import { toast } from "sonner"; import { format } from "date-fns"; import type { Route } from "./+types/$leagueId"; import { Button } from "~/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; import { SportSeasonCard } from "~/components/sports/SportSeasonCard"; import { UpcomingCalendarPanel } from "~/components/sport-season/UpcomingCalendarPanel"; import { TeamNameDisplay } from "~/components/ui/team-name-display"; import { getDisplayRank } from "~/lib/standings-display"; export function meta({ data }: Route.MetaArgs): Route.MetaDescriptors { return [{ title: `${data?.league?.name ?? "League"} - Brackt` }]; } export { loader } from "./$leagueId.server"; export default function LeagueHome({ loaderData }: Route.ComponentProps) { const { league, season, teams, commissioners, currentUserId, isUserCommissioner, ownerMap, commissionerMap, availableTeamCount, sportsCount, teamsWithOwners, isDraftOrderSet, draftSlots, sportsSeasons, standings, origin, upcomingCalendarEvents, } = loaderData; const myTeam = teams.find((t) => t.ownerId === currentUserId); const [searchParams, setSearchParams] = useSearchParams(); const [copied, setCopied] = useState(false); // Guard against double-firing toasts (e.g. React Strict Mode double-invoke) const processedParamsRef = useRef(null); useEffect(() => { const paramString = searchParams.toString(); if (!paramString || paramString === processedParamsRef.current) return; if (searchParams.get("updated") === "true") { processedParamsRef.current = paramString; toast.success("Team updated successfully"); setSearchParams({}); } else if (searchParams.get("joined") === "true") { processedParamsRef.current = paramString; toast.success("Welcome to the league! You've been assigned a team."); setSearchParams({}); } else if (searchParams.get("left") === "true") { processedParamsRef.current = paramString; toast.success("You have left the league. Your team is now available."); setSearchParams({}); } }, [searchParams, setSearchParams]); const handleCopyInviteLink = async () => { if (!season?.inviteCode) return; const inviteUrl = `${origin}/i/${season.inviteCode}`; try { await navigator.clipboard.writeText(inviteUrl); setCopied(true); toast.success("Invite link copied to clipboard!"); setTimeout(() => setCopied(false), 2000); } catch { toast.error("Failed to copy invite link"); } }; // Pre-compute standings map to avoid O(n²) lookups in render const standingsMap = new Map(standings.map((s) => [s.teamId, s])); // Pre-compute sorted standings list const sortedTeams = [...teams].toSorted((a, b) => { const rankA = standingsMap.get(a.id)?.currentRank ?? Infinity; const rankB = standingsMap.get(b.id)?.currentRank ?? Infinity; return rankA - rankB; }); // Pre-compute sorted sports seasons: active → upcoming → completed, // season_standings last within active, then alphabetical by sport name const sortedSportsSeasons = [...sportsSeasons].toSorted((a, b) => { const statusOrder = { active: 0, upcoming: 1, completed: 2 } as const; const statusDiff = statusOrder[a.status] - statusOrder[b.status]; if (statusDiff !== 0) return statusDiff; if (a.status === "active") { const aSeasonLong = a.scoringPattern === "season_standings" ? 1 : 0; const bSeasonLong = b.scoringPattern === "season_standings" ? 1 : 0; if (aSeasonLong !== bSeasonLong) return aSeasonLong - bSeasonLong; } return a.sport.name.localeCompare(b.sport.name); }); const isDraftOrPreDraft = season?.status === "pre_draft" || season?.status === "draft"; const isActiveOrCompleted = season?.status === "active" || season?.status === "completed"; return (

{league.name}

{myTeam && ( )} {isUserCommissioner && ( )}
{season && (

{season.year} Season •{" "} {season.status.replace("_", " ")}

)}
{season?.status === "draft" && (
Draft is live! Your league draft is currently in progress.
)}
{/* Left Column - 2/3 width on desktop */}
{/* Standings Panel - active/completed seasons */} {season && isActiveOrCompleted && (
Standings {season.status === "completed" ? "Final standings" : "Current season standings"}
{sortedTeams.map((team) => { const standing = standingsMap.get(team.id); const ownerName = team.ownerId ? ownerMap[team.ownerId] : null; return (
{getDisplayRank(standing, standings.length)}
{standing ? standing.totalPoints : 0} pts
); })}
)} {/* Sports Seasons Section */} {season && sortedSportsSeasons.length > 0 && ( Sports Seasons {sortedSportsSeasons.length} sport{sortedSportsSeasons.length !== 1 ? "s" : ""} in this season
{sortedSportsSeasons.map((sportSeason) => ( ))}
)} {isUserCommissioner && season && season.status === "pre_draft" && availableTeamCount > 0 && ( Invite Link Share this link to invite people to join your league ( {availableTeamCount} spot{availableTeamCount !== 1 ? "s" : ""}{" "} available)
e.currentTarget.select()} />

Anyone with this link can join your league

)} {/* Draft Order card - shown when order is set, pre_draft/draft */} {season && isDraftOrPreDraft && draftSlots.length > 0 && (
Draft Order {season.status === "pre_draft" ? "Upcoming draft order" : "Current draft order"}
{draftSlots.map((slot, index) => { const ownerName = slot.team.ownerId ? ownerMap[slot.team.ownerId] : null; return (
{index + 1}

{slot.team.name}

{ownerName && (

{ownerName}

)}
); })}
)} {/* Teams card - pre_draft/draft only; replaced by standings panel post-draft */} {season && isDraftOrPreDraft && ( Teams {teams.length} team{teams.length !== 1 ? "s" : ""} in this league
{teams.map((team) => { const isOwned = team.ownerId === currentUserId; const ownerName = team.ownerId ? ownerMap[team.ownerId] : null; return ( {team.name} {team.ownerId ? ( isOwned ? ( Your Team ) : ( {ownerName || "Unknown Owner"} ) ) : ( Available )} ); })}
)}
{/* Right Column - 1/3 width on desktop */}
{upcomingCalendarEvents.length > 0 && ( )} League Info

Created

{new Date(league.createdAt).toLocaleDateString()}

{season && ( <> {isDraftOrPreDraft && (

Teams Filled

{teamsWithOwners} of {teams.length}

)} {isDraftOrPreDraft && (

Draft Order Set

{isDraftOrderSet ? "Yes" : "No"}

{!isDraftOrderSet && isUserCommissioner && ( )}
)}

Draft Rounds

{season.draftRounds}

Sports Selected

{sportsCount}

Draft Board

View Draft Board
{isActiveOrCompleted && (

Standings

View Standings
)}

Flex Spots

{Math.max(0, season.draftRounds - sportsCount)}

Picks not tied to a specific sport

{season.draftDateTime && (

Draft Date

{format(new Date(season.draftDateTime), "PPP 'at' p")}

)} )}
Commissioners {commissioners.length} commissioner {commissioners.length !== 1 ? "s" : ""}
{commissioners.map((commissioner) => { const commissionerName = commissionerMap[commissioner.userId]; const hasTeam = teams.some( (t) => t.ownerId === commissioner.userId ); return (

{commissionerName || "Unknown User"} {commissioner.userId === currentUserId && ( (You) )}

{!hasTeam && (

No team

)}
); })}
); }