brackt/app/components/draft/DraftGrid.tsx

184 lines
6.2 KiB
TypeScript
Raw Normal View History

import { useMemo } from "react";
import { DraftTimer } from "./DraftTimer";
interface Team {
id: string;
name: string;
draftOrder: number;
ownerId: string | null;
}
interface DraftPick {
id: string;
teamId: string;
participantId: string;
pickNumber: number;
round: number;
pickInRound: number;
pickedByType: "owner" | "commissioner" | "auto";
}
interface Participant {
id: string;
name: string;
sport: string;
}
interface Timer {
teamId: string;
timeRemaining: number;
}
interface DraftGridProps {
teams: Team[];
draftPicks: DraftPick[];
participants: Participant[];
draftRounds: number;
currentPickNumber: number;
userTeamId?: string;
timers?: Timer[];
}
export function DraftGrid({
teams,
draftPicks,
participants,
draftRounds,
currentPickNumber,
userTeamId,
timers = [],
}: DraftGridProps) {
// Create a map of participant IDs to participant data for quick lookup
const participantMap = useMemo(() => {
return new Map(participants.map((p) => [p.id, p]));
}, [participants]);
// Create a map of pick numbers to draft picks
const pickMap = useMemo(() => {
return new Map(draftPicks.map((p) => [p.pickNumber, p]));
}, [draftPicks]);
// Create a map of team IDs to timers
const timerMap = useMemo(() => {
return new Map(timers.map((t) => [t.teamId, t]));
}, [timers]);
// Calculate pick number for a given round and team
const getPickNumber = (round: number, teamIndex: number): number => {
const isOddRound = round % 2 === 1;
const pickInRound = isOddRound ? teamIndex + 1 : teams.length - teamIndex;
return (round - 1) * teams.length + pickInRound;
};
return (
<div className="overflow-x-auto">
<div className="inline-block min-w-full">
{/* Header Row - Team Names */}
<div className="flex border-b-2 border-border bg-muted/50 sticky top-0 z-10">
<div className="w-16 flex-shrink-0 p-2 font-semibold text-sm border-r">
Round
</div>
{teams.map((team) => {
const timer = timerMap.get(team.id);
// Determine if this team is on the clock
const currentPick = Math.ceil(currentPickNumber / teams.length);
const pickInRound = ((currentPickNumber - 1) % teams.length) + 1;
const isOddRound = currentPick % 2 === 1;
const currentTeamIndex = isOddRound ? pickInRound - 1 : teams.length - pickInRound;
const isOnClock = teams[currentTeamIndex]?.id === team.id;
return (
<div
key={team.id}
className={`flex-1 min-w-[140px] p-2 text-center font-semibold text-sm border-r last:border-r-0 ${
team.id === userTeamId ? "bg-primary/10" : ""
}`}
>
<div className="truncate" title={team.name}>
{team.name}
</div>
{timer && (
<div className="mt-1">
<DraftTimer timeRemaining={timer.timeRemaining} isActive={isOnClock} />
</div>
)}
</div>
);
})}
</div>
{/* Draft Rounds */}
{Array.from({ length: draftRounds }, (_, roundIndex) => {
const round = roundIndex + 1;
const isOddRound = round % 2 === 1;
return (
<div key={round} className="flex border-b border-border hover:bg-muted/30">
{/* Round Number */}
<div className="w-16 flex-shrink-0 p-2 text-center font-medium text-sm border-r bg-muted/30">
{round}
</div>
{/* Picks for this round */}
{teams.map((team, teamIndex) => {
const pickNumber = getPickNumber(round, teamIndex);
const pick = pickMap.get(pickNumber);
const participant = pick ? participantMap.get(pick.participantId) : null;
const isCurrentPick = pickNumber === currentPickNumber;
const isPastPick = pickNumber < currentPickNumber;
const isUserTeam = team.id === userTeamId;
return (
<div
key={team.id}
className={`flex-1 min-w-[140px] p-2 border-r last:border-r-0 ${
isUserTeam ? "bg-primary/5" : ""
} ${isCurrentPick ? "ring-2 ring-primary ring-inset" : ""}`}
>
<div className="flex flex-col gap-1">
{/* Pick Number */}
<div className="text-xs text-muted-foreground">
{round}.{String(isOddRound ? teamIndex + 1 : teams.length - teamIndex).padStart(2, "0")}
</div>
{/* Participant or Status */}
{participant ? (
<div className="space-y-0.5">
<div className="font-medium text-sm truncate" title={participant.name}>
{participant.name}
</div>
<div className="text-xs text-muted-foreground truncate">
{participant.sport}
</div>
{pick && pick.pickedByType !== "owner" && (
<div className="text-xs text-muted-foreground italic">
({pick.pickedByType})
</div>
)}
</div>
) : isCurrentPick ? (
<div className="text-sm font-medium text-primary">
On the clock
</div>
) : isPastPick ? (
<div className="text-xs text-muted-foreground italic">
Skipped
</div>
) : (
<div className="text-xs text-muted-foreground">
-
</div>
)}
</div>
</div>
);
})}
</div>
);
})}
</div>
</div>
);
}