Fix Rosters page.
This commit is contained in:
parent
09b5193f18
commit
269ba05316
3 changed files with 108 additions and 31 deletions
|
|
@ -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<string, string>;
|
||||
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 (
|
||||
<div className="h-full overflow-y-auto">
|
||||
<div className="p-4 space-y-4">
|
||||
{/* Team selector */}
|
||||
<div className="space-y-1">
|
||||
<label
|
||||
htmlFor="roster-team-select"
|
||||
|
|
@ -89,31 +117,76 @@ export const TeamRosterView = memo(function TeamRosterView({
|
|||
</Select>
|
||||
</div>
|
||||
|
||||
{totalPicks === 0 ? (
|
||||
<p className="text-sm text-muted-foreground text-center py-6">
|
||||
No picks yet
|
||||
</p>
|
||||
{/* Mini dashboard */}
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="rounded-lg border bg-card px-3 py-2.5 space-y-0.5">
|
||||
<p className="text-xs text-muted-foreground font-medium">Flex Picks</p>
|
||||
{flexPicksAvailable === 0 ? (
|
||||
<p className="text-sm font-semibold text-muted-foreground">N/A</p>
|
||||
) : (
|
||||
<>
|
||||
<p className={`text-xl font-bold tabular-nums leading-none ${flexColor}`}>
|
||||
{flexPicksRemaining}
|
||||
<span className="text-sm font-normal text-muted-foreground ml-1">
|
||||
/ {flexPicksAvailable}
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">remaining</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className="rounded-lg border bg-card px-3 py-2.5 space-y-0.5">
|
||||
<p className="text-xs text-muted-foreground font-medium">Sports Remaining</p>
|
||||
<p className={`text-xl font-bold tabular-nums leading-none ${missingSports.length > 0 ? "text-foreground" : "text-emerald-500 dark:text-emerald-400"}`}>
|
||||
{missingSports.length}
|
||||
<span className="text-sm font-normal text-muted-foreground ml-1">
|
||||
/ {sports.length}
|
||||
</span>
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">to draft</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Missing sports list */}
|
||||
{missingSports.length > 0 && (
|
||||
<div>
|
||||
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-1.5">Still Needed</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{missingSports.map((s) => s.name).join(" · ")}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Per-sport pick cells */}
|
||||
{draftedSports.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground text-center py-6">No picks yet</p>
|
||||
) : (
|
||||
sportsWithPicks.map((sport) => {
|
||||
const sportPicks = teamPicks?.get(sport.id) ?? [];
|
||||
return (
|
||||
<div key={sport.id}>
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<h3 className="text-sm font-semibold">{sport.name}</h3>
|
||||
<Badge variant="secondary" className="text-xs px-1.5 py-0">
|
||||
{sportPicks.length}
|
||||
</Badge>
|
||||
<div className="space-y-3">
|
||||
{draftedSports.map((sport) => {
|
||||
const sportPicks = teamPicks?.get(sport.id) ?? [];
|
||||
return (
|
||||
<div key={sport.id}>
|
||||
<p className="text-xs font-semibold uppercase tracking-wider text-muted-foreground mb-1.5">
|
||||
{sport.name}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{sportPicks.map((pick) => (
|
||||
<DraftPickCell
|
||||
key={pick.id}
|
||||
pickNumber={pick.pickNumber}
|
||||
round={pick.round}
|
||||
pickInRound={pick.pickInRound}
|
||||
state="picked"
|
||||
pick={pick}
|
||||
corona="gradient"
|
||||
className="w-44 flex-none"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<ul className="space-y-1 pl-2">
|
||||
{sportPicks.map((pick) => (
|
||||
<li key={pick.id} className="text-sm text-foreground">
|
||||
{pick.participant.name}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -1577,6 +1577,7 @@ export default function DraftRoom() {
|
|||
picks,
|
||||
sports: seasonSportsData,
|
||||
ownerMap,
|
||||
totalRounds: season.draftRounds,
|
||||
};
|
||||
|
||||
const handleAutodraftUpdate = useCallback(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue