From 269ba05316e5a82bbd5f78bc264316a5ab2fbe52 Mon Sep 17 00:00:00 2001 From: Chris Parsons Date: Sat, 18 Apr 2026 21:20:38 -0700 Subject: [PATCH] Fix Rosters page. --- app/components/draft/TeamRosterView.tsx | 135 ++++++++++++++---- app/components/draft/picks-utils.ts | 3 + .../leagues/$leagueId.draft.$seasonId.tsx | 1 + 3 files changed, 108 insertions(+), 31 deletions(-) diff --git a/app/components/draft/TeamRosterView.tsx b/app/components/draft/TeamRosterView.tsx index 08ab865..d0edb93 100644 --- a/app/components/draft/TeamRosterView.tsx +++ b/app/components/draft/TeamRosterView.tsx @@ -1,5 +1,4 @@ import { memo, useEffect, useMemo, useState } from "react"; -import { Badge } from "~/components/ui/badge"; import { Select, SelectContent, @@ -7,6 +6,7 @@ import { SelectTrigger, SelectValue, } from "~/components/ui/select"; +import { DraftPickCell } from "./DraftPickCell"; import { type DraftPick, groupPicksByTeamAndSport } from "./picks-utils"; interface TeamRosterViewProps { @@ -14,6 +14,7 @@ interface TeamRosterViewProps { ownerMap?: Record; picks: DraftPick[]; sports: Array<{ id: string; name: string }>; + totalRounds: number; } export const TeamRosterView = memo(function TeamRosterView({ @@ -21,12 +22,12 @@ export const TeamRosterView = memo(function TeamRosterView({ ownerMap = {}, picks, sports, + totalRounds, }: TeamRosterViewProps) { const [selectedTeamId, setSelectedTeamId] = useState( draftSlots[0]?.team.id ?? "" ); - // Reset selection if the selected team is no longer present in the slot list useEffect(() => { if ( draftSlots.length > 0 && @@ -46,16 +47,42 @@ export const TeamRosterView = memo(function TeamRosterView({ [picksByTeamAndSport, selectedTeamId] ); - const sportsWithPicks = useMemo( + const flexPicksAvailable = useMemo( + () => Math.max(0, totalRounds - sports.length), + [totalRounds, sports.length] + ); + + const flexPicksUsed = useMemo(() => { + let used = 0; + teamPicks?.forEach((sportPicks) => { + if (sportPicks.length > 1) used += sportPicks.length - 1; + }); + return used; + }, [teamPicks]); + + const flexPicksRemaining = useMemo( + () => flexPicksAvailable - flexPicksUsed, + [flexPicksAvailable, flexPicksUsed] + ); + + const missingSports = useMemo( + () => sports.filter((s) => (teamPicks?.get(s.id)?.length ?? 0) === 0), + [sports, teamPicks] + ); + + const draftedSports = useMemo( () => sports.filter((s) => (teamPicks?.get(s.id)?.length ?? 0) > 0), [sports, teamPicks] ); - const totalPicks = useMemo(() => { - let count = 0; - teamPicks?.forEach((sp) => (count += sp.length)); - return count; - }, [teamPicks]); + const flexColor = + flexPicksAvailable === 0 + ? "text-muted-foreground" + : flexPicksRemaining <= 0 + ? "text-destructive" + : flexPicksRemaining <= Math.ceil(flexPicksAvailable * 0.25) + ? "text-amber-500 dark:text-amber-400" + : "text-emerald-500 dark:text-emerald-400"; if (draftSlots.length === 0) { return ( @@ -68,6 +95,7 @@ export const TeamRosterView = memo(function TeamRosterView({ return (
+ {/* Team selector */}
- {totalPicks === 0 ? ( -

- No picks yet -

+ {/* Mini dashboard */} +
+
+

Flex Picks

+ {flexPicksAvailable === 0 ? ( +

N/A

+ ) : ( + <> +

+ {flexPicksRemaining} + + / {flexPicksAvailable} + +

+

remaining

+ + )} +
+
+

Sports Remaining

+

0 ? "text-foreground" : "text-emerald-500 dark:text-emerald-400"}`}> + {missingSports.length} + + / {sports.length} + +

+

to draft

+
+
+ + {/* Missing sports list */} + {missingSports.length > 0 && ( +
+

Still Needed

+

+ {missingSports.map((s) => s.name).join(" ยท ")} +

+
+ )} + + {/* Per-sport pick cells */} + {draftedSports.length === 0 ? ( +

No picks yet

) : ( - sportsWithPicks.map((sport) => { - const sportPicks = teamPicks?.get(sport.id) ?? []; - return ( -
-
-

{sport.name}

- - {sportPicks.length} - +
+ {draftedSports.map((sport) => { + const sportPicks = teamPicks?.get(sport.id) ?? []; + return ( +
+

+ {sport.name} +

+
+ {sportPicks.map((pick) => ( + + ))} +
-
    - {sportPicks.map((pick) => ( -
  • - {pick.participant.name} -
  • - ))} -
-
- ); - }) + ); + })} +
)}
diff --git a/app/components/draft/picks-utils.ts b/app/components/draft/picks-utils.ts index a521c67..0153d7f 100644 --- a/app/components/draft/picks-utils.ts +++ b/app/components/draft/picks-utils.ts @@ -1,5 +1,8 @@ export type DraftPick = { id: string; + pickNumber: number; + round: number; + pickInRound: number; team: { id: string; name: string }; participant: { id: string; name: string }; sport: { id: string; name: string }; diff --git a/app/routes/leagues/$leagueId.draft.$seasonId.tsx b/app/routes/leagues/$leagueId.draft.$seasonId.tsx index 86bf273..d439bc5 100644 --- a/app/routes/leagues/$leagueId.draft.$seasonId.tsx +++ b/app/routes/leagues/$leagueId.draft.$seasonId.tsx @@ -1577,6 +1577,7 @@ export default function DraftRoom() { picks, sports: seasonSportsData, ownerMap, + totalRounds: season.draftRounds, }; const handleAutodraftUpdate = useCallback(