import { getAuth } from "@clerk/react-router/server"; import { findLeagueById, findTeamsBySeasonId, findCommissionersByLeagueId, isUserLeagueMember, isCommissioner, findUserByClerkId, findDraftSlotsBySeasonId, } from "~/models"; import { findCurrentSeasonWithSports } from "~/models/season"; import { getSeasonStandings } from "~/models/standings"; import { getNextScoringEvent } from "~/models/scoring-event"; import type { Route } from "./+types/$leagueId"; export async function loader(args: Route.LoaderArgs) { const { userId } = await getAuth(args); const { params } = args; const { leagueId } = params; // Fetch league const league = await findLeagueById(leagueId); if (!league) { throw new Response("League not found", { status: 404 }); } // Fetch current season with sports const seasonWithSports = await findCurrentSeasonWithSports(leagueId); const season = seasonWithSports || null; // Fetch commissioners const commissioners = await findCommissionersByLeagueId(leagueId); // Check if current user is a commissioner const isUserCommissioner = userId ? await isCommissioner(leagueId, userId) : false; // Check if user is a member (has a team in current season) const isUserMember = userId ? await isUserLeagueMember(leagueId, userId) : false; // Check access: user must be a commissioner, a member, or an admin // If not logged in or not authorized, throw 403 if (!userId) { throw new Response("You must be logged in to view this league", { status: 401, }); } if (!isUserCommissioner && !isUserMember) { throw new Response("You do not have access to this league", { status: 403, }); } // Fetch teams for current season const teams = season ? await findTeamsBySeasonId(season.id) : []; // Fetch draft slots if season is in pre_draft or draft status const draftSlots = season && (season.status === "pre_draft" || season.status === "draft") ? await findDraftSlotsBySeasonId(season.id) : []; // Fetch standings for active/completed seasons const standings = season && (season.status === "active" || season.status === "completed") ? await getSeasonStandings(season.id) : []; // Fetch user data for team owners const ownerIds = teams .map((t) => t.ownerId) .filter((id): id is string => id !== null); const uniqueOwnerIds = [...new Set(ownerIds)]; const owners = await Promise.all( uniqueOwnerIds.map(async (ownerId) => { const user = await findUserByClerkId(ownerId); return user ? { clerkId: ownerId, name: user.username || user.displayName } : null; }) ); const ownerMap = new Map( owners .filter((o): o is NonNullable => o !== null) .map((o) => [o.clerkId, o.name]) ); // Fetch user data for commissioners const commissionerIds = commissioners.map((c) => c.userId); const commissionerUsers = await Promise.all( commissionerIds.map(async (commissionerId) => { const user = await findUserByClerkId(commissionerId); return user ? { clerkId: commissionerId, name: user.username || user.displayName } : null; }) ); const commissionerMap = new Map( commissionerUsers .filter((c): c is NonNullable => c !== null) .map((c) => [c.clerkId, c.name]) ); // Count available teams const availableTeamCount = teams.filter((t) => !t.ownerId).length; // Count teams with owners const teamsWithOwners = teams.filter((t) => t.ownerId !== null).length; // Get sports seasons data including next upcoming event for each const rawSportsSeasons = seasonWithSports?.seasonSports?.map((ss) => ss.sportsSeason) || []; const sportsSeasons = await Promise.all( rawSportsSeasons.map(async (ss) => { const nextEvent = ss.status === "active" ? await getNextScoringEvent(ss.id) : null; return { id: ss.id, name: ss.name, status: ss.status as "upcoming" | "active" | "completed", scoringPattern: ss.scoringPattern, sport: ss.sport, nextEvent: nextEvent ? { name: nextEvent.name, eventDate: nextEvent.eventDate } : null, }; }) ); const sportsCount = sportsSeasons.length; // Check if draft order is set const isDraftOrderSet = draftSlots.length > 0; // Extract origin for client use (avoids SSR/client mismatch on invite URLs) const origin = new URL(args.request.url).origin; return { league, season, teams, commissioners, currentUserId: userId, isUserCommissioner, ownerMap: Object.fromEntries(ownerMap), commissionerMap: Object.fromEntries(commissionerMap), availableTeamCount, sportsCount, teamsWithOwners, isDraftOrderSet, sportsSeasons, standings, origin, }; }