Update draft room UI.
This commit is contained in:
parent
e3bc3c1ce2
commit
44ad954dfe
9 changed files with 125 additions and 59 deletions
|
|
@ -3,7 +3,6 @@ import { Check, Info, ChevronDown } from "lucide-react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { Label } from "~/components/ui/label";
|
import { Label } from "~/components/ui/label";
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "~/components/ui/popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "~/components/ui/popover";
|
||||||
import { Button } from "~/components/ui/button";
|
|
||||||
|
|
||||||
type AutodraftMode = "next_pick" | "while_on";
|
type AutodraftMode = "next_pick" | "while_on";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import {
|
||||||
} from "~/components/ui/context-menu";
|
} from "~/components/ui/context-menu";
|
||||||
import { DraftPickCell, type CoronaState } from "~/components/draft/DraftPickCell";
|
import { DraftPickCell, type CoronaState } from "~/components/draft/DraftPickCell";
|
||||||
import { TeamAvatar } from "~/components/TeamAvatar";
|
import { TeamAvatar } from "~/components/TeamAvatar";
|
||||||
|
import type { SeasonStatus } from "~/models/season";
|
||||||
|
|
||||||
interface DraftCell {
|
interface DraftCell {
|
||||||
pickNumber: number;
|
pickNumber: number;
|
||||||
|
|
@ -36,6 +37,8 @@ interface DraftGridProps {
|
||||||
connectedTeams?: Set<string>;
|
connectedTeams?: Set<string>;
|
||||||
ownerMap?: Record<string, string>;
|
ownerMap?: Record<string, string>;
|
||||||
coronaStates?: Record<string, CoronaState>;
|
coronaStates?: Record<string, CoronaState>;
|
||||||
|
seasonStatus?: SeasonStatus;
|
||||||
|
draftPaused?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DraftGrid({
|
export function DraftGrid({
|
||||||
|
|
@ -52,6 +55,8 @@ export function DraftGrid({
|
||||||
connectedTeams = new Set(),
|
connectedTeams = new Set(),
|
||||||
ownerMap = {},
|
ownerMap = {},
|
||||||
coronaStates = {},
|
coronaStates = {},
|
||||||
|
seasonStatus,
|
||||||
|
draftPaused,
|
||||||
}: DraftGridProps) {
|
}: DraftGridProps) {
|
||||||
const totalTeams = draftSlots.length;
|
const totalTeams = draftSlots.length;
|
||||||
|
|
||||||
|
|
@ -61,30 +66,33 @@ export function DraftGrid({
|
||||||
<div className="w-full overflow-x-auto">
|
<div className="w-full overflow-x-auto">
|
||||||
<div className="min-w-max">
|
<div className="min-w-max">
|
||||||
{/* Team Headers */}
|
{/* Team Headers */}
|
||||||
<div className="flex gap-2 mb-2">
|
<div className="flex gap-1.5 mb-1.5">
|
||||||
{draftSlots.map((slot) => {
|
{draftSlots.map((slot) => {
|
||||||
const teamTime = teamTimers?.[slot.team.id];
|
const teamTime = teamTimers?.[slot.team.id];
|
||||||
const isAutodraft = autodraftStatus[slot.team.id] || false;
|
const isAutodraft = autodraftStatus[slot.team.id] || false;
|
||||||
const isConnected = connectedTeams.has(slot.team.id);
|
const isConnected = connectedTeams.has(slot.team.id);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={slot.id} className="flex-1 min-w-32 text-center">
|
<div key={slot.id} className="flex-1 min-w-20 text-center">
|
||||||
<div className="flex justify-center mb-1">
|
<div className="flex justify-center mb-1">
|
||||||
<TeamAvatar
|
<TeamAvatar
|
||||||
teamId={slot.team.id}
|
teamId={slot.team.id}
|
||||||
teamName={ownerMap[slot.team.id] || slot.team.name}
|
teamName={ownerMap[slot.team.id] || slot.team.name}
|
||||||
logoUrl={slot.team.logoUrl}
|
logoUrl={slot.team.logoUrl}
|
||||||
size="md"
|
size="lg"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`font-semibold text-sm truncate px-2 ${!isConnected ? "italic text-muted-foreground" : ""}`}
|
className={`font-semibold text-xs truncate px-1 flex items-center justify-center ${!isConnected ? "italic text-muted-foreground" : ""}`}
|
||||||
>
|
>
|
||||||
{ownerMap[slot.team.id] || slot.team.name}
|
{isAutodraft && (
|
||||||
|
<span className="mr-1 inline-flex items-center justify-center h-4 w-4 text-[10px] font-bold text-white bg-black shrink-0">A</span>
|
||||||
|
)}
|
||||||
|
<span className="truncate">{ownerMap[slot.team.id] || slot.team.name}</span>
|
||||||
</div>
|
</div>
|
||||||
{teamTimers && formatTime && (
|
{teamTimers && formatTime && (
|
||||||
<div
|
<div
|
||||||
className={`text-xs font-mono ${
|
className={`text-sm font-mono ${
|
||||||
teamTime === undefined
|
teamTime === undefined
|
||||||
? "text-muted-foreground"
|
? "text-muted-foreground"
|
||||||
: teamTime > 60
|
: teamTime > 60
|
||||||
|
|
@ -95,9 +103,6 @@ export function DraftGrid({
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{formatTime(teamTime)}
|
{formatTime(teamTime)}
|
||||||
{isAutodraft && (
|
|
||||||
<span className="ml-1 text-muted-foreground">(auto)</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -106,7 +111,7 @@ export function DraftGrid({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Draft Grid Rows */}
|
{/* Draft Grid Rows */}
|
||||||
<div className="space-y-2.5">
|
<div className="space-y-1.5">
|
||||||
{draftGrid.map((roundPicks, roundIndex) => {
|
{draftGrid.map((roundPicks, roundIndex) => {
|
||||||
const round = roundIndex + 1;
|
const round = roundIndex + 1;
|
||||||
const isEvenRound = round % 2 === 0;
|
const isEvenRound = round % 2 === 0;
|
||||||
|
|
@ -115,7 +120,7 @@ export function DraftGrid({
|
||||||
: roundPicks;
|
: roundPicks;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={round} className="flex gap-2">
|
<div key={round} className="flex gap-1.5">
|
||||||
{displayPicks.map((cell, index) => {
|
{displayPicks.map((cell, index) => {
|
||||||
const actualIndex = isEvenRound
|
const actualIndex = isEvenRound
|
||||||
? roundPicks.length - 1 - index
|
? roundPicks.length - 1 - index
|
||||||
|
|
@ -144,6 +149,8 @@ export function DraftGrid({
|
||||||
coronaState={
|
coronaState={
|
||||||
cell ? coronaStates[cell.participant.id] : undefined
|
cell ? coronaStates[cell.participant.id] : undefined
|
||||||
}
|
}
|
||||||
|
seasonStatus={seasonStatus}
|
||||||
|
draftPaused={draftPaused}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -67,16 +67,45 @@ describe('DraftGrid Component', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Current Pick Highlighting', () => {
|
describe('Current Pick Highlighting', () => {
|
||||||
it('should highlight current pick with "On Clock" text', () => {
|
it('should show "Up Next" when draft is pre_draft', () => {
|
||||||
render(
|
render(
|
||||||
<DraftGrid
|
<DraftGrid
|
||||||
draftSlots={mockDraftSlots}
|
draftSlots={mockDraftSlots}
|
||||||
draftGrid={mockGrid}
|
draftGrid={mockGrid}
|
||||||
currentPick={2}
|
currentPick={2}
|
||||||
|
seasonStatus="pre_draft"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(screen.getByText('On Clock')).toBeInTheDocument();
|
expect(screen.getByText('Up Next')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show "Paused Draft" when draft is paused', () => {
|
||||||
|
render(
|
||||||
|
<DraftGrid
|
||||||
|
draftSlots={mockDraftSlots}
|
||||||
|
draftGrid={mockGrid}
|
||||||
|
currentPick={2}
|
||||||
|
seasonStatus="draft"
|
||||||
|
draftPaused={true}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('Paused Draft')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show "On The Clock" when draft is active', () => {
|
||||||
|
render(
|
||||||
|
<DraftGrid
|
||||||
|
draftSlots={mockDraftSlots}
|
||||||
|
draftGrid={mockGrid}
|
||||||
|
currentPick={2}
|
||||||
|
seasonStatus="draft"
|
||||||
|
draftPaused={false}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(screen.getByText('On The Clock')).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should apply correct styling to current pick', () => {
|
it('should apply correct styling to current pick', () => {
|
||||||
|
|
@ -85,12 +114,14 @@ describe('DraftGrid Component', () => {
|
||||||
draftSlots={mockDraftSlots}
|
draftSlots={mockDraftSlots}
|
||||||
draftGrid={mockGrid}
|
draftGrid={mockGrid}
|
||||||
currentPick={2}
|
currentPick={2}
|
||||||
|
seasonStatus="draft"
|
||||||
|
draftPaused={false}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentPickCell = screen.getByText('On Clock').closest('[class*="border-electric"]');
|
const currentPickCell = screen.getByText('On The Clock').closest('.border-transparent');
|
||||||
expect(currentPickCell).toHaveClass('border-electric');
|
expect(currentPickCell).toHaveClass('bg-muted/80');
|
||||||
expect(currentPickCell).toHaveClass('bg-electric/20');
|
expect(currentPickCell).toHaveClass('border-transparent');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import { Button } from "~/components/ui/button";
|
||||||
import { MoreVertical } from "lucide-react";
|
import { MoreVertical } from "lucide-react";
|
||||||
import { formatClockTime, getTimerColorClass } from "~/lib/draft-timer";
|
import { formatClockTime, getTimerColorClass } from "~/lib/draft-timer";
|
||||||
import { DraftPickCell } from "~/components/draft/DraftPickCell";
|
import { DraftPickCell } from "~/components/draft/DraftPickCell";
|
||||||
|
import type { SeasonStatus } from "~/models/season";
|
||||||
|
|
||||||
type MobileSheetData =
|
type MobileSheetData =
|
||||||
| { type: "team"; teamId: string }
|
| { type: "team"; teamId: string }
|
||||||
|
|
@ -53,6 +54,8 @@ interface DraftGridSectionProps {
|
||||||
autodraftStatus: Record<string, { isEnabled: boolean; mode: "next_pick" | "while_on"; queueOnly: boolean }>;
|
autodraftStatus: Record<string, { isEnabled: boolean; mode: "next_pick" | "while_on"; queueOnly: boolean }>;
|
||||||
connectedTeams: Set<string>;
|
connectedTeams: Set<string>;
|
||||||
isCommissioner: boolean;
|
isCommissioner: boolean;
|
||||||
|
seasonStatus?: SeasonStatus;
|
||||||
|
draftPaused?: boolean;
|
||||||
onAdjustTimeBankOpen?: (teamId: string) => void;
|
onAdjustTimeBankOpen?: (teamId: string) => void;
|
||||||
onSetAutodraftOpen?: (teamId: string) => void;
|
onSetAutodraftOpen?: (teamId: string) => void;
|
||||||
onForceAutopick: (pickNumber: number, teamId: string) => void;
|
onForceAutopick: (pickNumber: number, teamId: string) => void;
|
||||||
|
|
@ -70,6 +73,8 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
autodraftStatus,
|
autodraftStatus,
|
||||||
connectedTeams,
|
connectedTeams,
|
||||||
isCommissioner,
|
isCommissioner,
|
||||||
|
seasonStatus,
|
||||||
|
draftPaused,
|
||||||
onAdjustTimeBankOpen,
|
onAdjustTimeBankOpen,
|
||||||
onSetAutodraftOpen,
|
onSetAutodraftOpen,
|
||||||
onForceAutopick,
|
onForceAutopick,
|
||||||
|
|
@ -91,9 +96,7 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
<div className="flex-1 overflow-auto">
|
<div className="flex-1 overflow-auto">
|
||||||
<div className="inline-block min-w-full min-h-full">
|
<div className="inline-block min-w-full min-h-full">
|
||||||
{/* Team Headers */}
|
{/* Team Headers */}
|
||||||
<div className="flex gap-2 mb-2 sticky top-0 z-10 bg-background/95 backdrop-blur-sm py-1">
|
<div className="flex gap-1.5 mb-1.5 sticky top-0 z-10 bg-background/95 backdrop-blur-sm py-1">
|
||||||
{/* Spacer for round column — sticky so it covers the corner when scrolling both axes */}
|
|
||||||
<div className="w-8 flex-shrink-0 sticky left-0 z-[6] bg-background/95" />
|
|
||||||
{draftSlots.map((slot) => {
|
{draftSlots.map((slot) => {
|
||||||
const teamTime = teamTimers[slot.team.id];
|
const teamTime = teamTimers[slot.team.id];
|
||||||
const isAutodraft = autodraftStatus[slot.team.id]?.isEnabled || false;
|
const isAutodraft = autodraftStatus[slot.team.id]?.isEnabled || false;
|
||||||
|
|
@ -106,11 +109,11 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
teamId={slot.team.id}
|
teamId={slot.team.id}
|
||||||
teamName={ownerMap[slot.team.id] || slot.team.name}
|
teamName={ownerMap[slot.team.id] || slot.team.name}
|
||||||
logoUrl={slot.team.logoUrl}
|
logoUrl={slot.team.logoUrl}
|
||||||
size="sm"
|
size="md"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`font-semibold text-sm truncate px-2 ${
|
className={`font-semibold text-xs px-1 flex items-center justify-center ${
|
||||||
slot.team.id === currentTeamId
|
slot.team.id === currentTeamId
|
||||||
? "text-electric font-bold"
|
? "text-electric font-bold"
|
||||||
: !isConnected
|
: !isConnected
|
||||||
|
|
@ -118,17 +121,15 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
: ""
|
: ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{ownerMap[slot.team.id] || slot.team.name}
|
{isAutodraft && (
|
||||||
|
<span className="mr-1 inline-flex items-center justify-center h-4 w-4 text-[10px] font-bold text-white bg-black shrink-0">A</span>
|
||||||
|
)}
|
||||||
|
<span className="truncate">{ownerMap[slot.team.id] || slot.team.name}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`text-xs font-mono px-2 ${getTimerColorClass(teamTime)}`}
|
className={`text-xs font-mono px-1 ${getTimerColorClass(teamTime)}`}
|
||||||
>
|
>
|
||||||
{formatClockTime(teamTime)}
|
{formatClockTime(teamTime)}
|
||||||
{isAutodraft && (
|
|
||||||
<span className="ml-1 text-muted-foreground">
|
|
||||||
(auto)
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{isCommissioner && (onAdjustTimeBankOpen || onSetAutodraftOpen) && (
|
{isCommissioner && (onAdjustTimeBankOpen || onSetAutodraftOpen) && (
|
||||||
<button
|
<button
|
||||||
|
|
@ -145,7 +146,7 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
return (
|
return (
|
||||||
<ContextMenu key={slot.id}>
|
<ContextMenu key={slot.id}>
|
||||||
<ContextMenuTrigger asChild>
|
<ContextMenuTrigger asChild>
|
||||||
<div className="flex-1 min-w-32 text-center cursor-context-menu">
|
<div className="flex-1 min-w-20 text-center cursor-context-menu">
|
||||||
{headerInner}
|
{headerInner}
|
||||||
</div>
|
</div>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
|
|
@ -166,7 +167,7 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={slot.id} className="flex-1 min-w-32 text-center">
|
<div key={slot.id} className="flex-1 min-w-20 text-center">
|
||||||
{headerInner}
|
{headerInner}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -174,7 +175,7 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Draft Grid Rows */}
|
{/* Draft Grid Rows */}
|
||||||
<div className="space-y-2.5">
|
<div className="space-y-1.5">
|
||||||
{draftGrid.map((roundPicks, roundIndex) => {
|
{draftGrid.map((roundPicks, roundIndex) => {
|
||||||
const round = roundIndex + 1;
|
const round = roundIndex + 1;
|
||||||
const isEvenRound = round % 2 === 0;
|
const isEvenRound = round % 2 === 0;
|
||||||
|
|
@ -183,11 +184,7 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
: roundPicks;
|
: roundPicks;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={round} className="flex gap-2 items-stretch">
|
<div key={round} className="flex gap-1.5 items-stretch">
|
||||||
{/* Round label */}
|
|
||||||
<div className="w-8 flex-shrink-0 sticky left-0 z-[5] bg-background/95 flex items-center justify-center">
|
|
||||||
<span className="text-xs font-mono text-muted-foreground">R{round}</span>
|
|
||||||
</div>
|
|
||||||
{displayPicks.map((cell) => {
|
{displayPicks.map((cell) => {
|
||||||
const isCurrent = cell.pickNumber === currentPick;
|
const isCurrent = cell.pickNumber === currentPick;
|
||||||
const isPicked = !!cell.pick;
|
const isPicked = !!cell.pick;
|
||||||
|
|
@ -229,6 +226,8 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
state={cellState}
|
state={cellState}
|
||||||
pick={pickData}
|
pick={pickData}
|
||||||
coronaState={pendingCorona}
|
coronaState={pendingCorona}
|
||||||
|
seasonStatus={seasonStatus}
|
||||||
|
draftPaused={draftPaused}
|
||||||
className="cursor-context-menu"
|
className="cursor-context-menu"
|
||||||
>
|
>
|
||||||
{mobileButtons}
|
{mobileButtons}
|
||||||
|
|
@ -268,6 +267,8 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
state={cellState}
|
state={cellState}
|
||||||
pick={pickData}
|
pick={pickData}
|
||||||
coronaState={pendingCorona}
|
coronaState={pendingCorona}
|
||||||
|
seasonStatus={seasonStatus}
|
||||||
|
draftPaused={draftPaused}
|
||||||
className="cursor-context-menu"
|
className="cursor-context-menu"
|
||||||
>
|
>
|
||||||
{mobileButtons}
|
{mobileButtons}
|
||||||
|
|
@ -305,6 +306,8 @@ export const DraftGridSection = memo(function DraftGridSection({
|
||||||
state={cellState}
|
state={cellState}
|
||||||
pick={pickData}
|
pick={pickData}
|
||||||
coronaState={pendingCorona}
|
coronaState={pendingCorona}
|
||||||
|
seasonStatus={seasonStatus}
|
||||||
|
draftPaused={draftPaused}
|
||||||
>
|
>
|
||||||
{mobileButtons}
|
{mobileButtons}
|
||||||
</DraftPickCell>
|
</DraftPickCell>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { forwardRef, type CSSProperties, type ComponentPropsWithoutRef } from "react";
|
import { forwardRef, type CSSProperties, type ComponentPropsWithoutRef } from "react";
|
||||||
import { cn } from "~/lib/utils";
|
import { cn } from "~/lib/utils";
|
||||||
|
import type { SeasonStatus } from "~/models/season";
|
||||||
|
|
||||||
export type CoronaState =
|
export type CoronaState =
|
||||||
| { type: "eliminated"; points: 0 }
|
| { type: "eliminated"; points: 0 }
|
||||||
|
|
@ -24,6 +25,8 @@ type DraftPickCellProps = ComponentPropsWithoutRef<"div"> & {
|
||||||
};
|
};
|
||||||
corona?: CoronaVariant;
|
corona?: CoronaVariant;
|
||||||
coronaState?: CoronaState;
|
coronaState?: CoronaState;
|
||||||
|
seasonStatus?: SeasonStatus;
|
||||||
|
draftPaused?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const coronaClasses: Record<CoronaVariant, string> = {
|
const coronaClasses: Record<CoronaVariant, string> = {
|
||||||
|
|
@ -57,6 +60,8 @@ function DraftPickCell({
|
||||||
pick,
|
pick,
|
||||||
corona = "gradient",
|
corona = "gradient",
|
||||||
coronaState,
|
coronaState,
|
||||||
|
seasonStatus,
|
||||||
|
draftPaused,
|
||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
...rest
|
...rest
|
||||||
|
|
@ -64,11 +69,18 @@ function DraftPickCell({
|
||||||
const showCorona = state === "picked" || (state === "upcoming" && !!coronaState);
|
const showCorona = state === "picked" || (state === "upcoming" && !!coronaState);
|
||||||
const isCurrent = state === "current";
|
const isCurrent = state === "current";
|
||||||
|
|
||||||
|
let currentLabel = "On The Clock";
|
||||||
|
if (seasonStatus === "pre_draft") {
|
||||||
|
currentLabel = "Up Next";
|
||||||
|
} else if (seasonStatus === "draft" && draftPaused) {
|
||||||
|
currentLabel = "Paused Draft";
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex-1 min-w-32 overflow-hidden",
|
"relative flex-1 min-w-20 overflow-hidden",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...rest}
|
{...rest}
|
||||||
|
|
@ -90,7 +102,7 @@ function DraftPickCell({
|
||||||
) : null}
|
) : null}
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative z-10 h-14 border-2 rounded-lg p-2 transition-all",
|
"relative z-10 h-14 border-2 rounded-lg p-1.5 transition-all",
|
||||||
(showCorona || isCurrent) && "mr-1",
|
(showCorona || isCurrent) && "mr-1",
|
||||||
isCurrent
|
isCurrent
|
||||||
? "bg-muted/80 border-transparent"
|
? "bg-muted/80 border-transparent"
|
||||||
|
|
@ -100,29 +112,29 @@ function DraftPickCell({
|
||||||
)}
|
)}
|
||||||
title={`Overall Pick #${pickNumber}`}
|
title={`Overall Pick #${pickNumber}`}
|
||||||
>
|
>
|
||||||
<div className={cn("flex", isCurrent ? "items-center justify-center h-full" : "gap-1 items-start")}>
|
<div className={cn("flex flex-col", isCurrent ? "items-center justify-center h-full" : "gap-0.5")}>
|
||||||
{state === "picked" && pick ? (
|
|
||||||
<div className="text-sm min-w-0 flex-1">
|
|
||||||
<div className="font-semibold truncate text-sm">{pick.participant.name}</div>
|
|
||||||
<div className="text-muted-foreground truncate text-xs">
|
|
||||||
{pick.sport.name}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : isCurrent ? (
|
|
||||||
<div className="text-sm font-bold text-white">On The Clock</div>
|
|
||||||
) : null}
|
|
||||||
{!isCurrent && (
|
{!isCurrent && (
|
||||||
<div className="flex flex-col items-end shrink-0">
|
<div className="flex items-center justify-between">
|
||||||
<div className="text-xs font-mono text-muted-foreground leading-5">
|
<div className="text-[10px] font-mono text-muted-foreground leading-3">
|
||||||
{round}.{String(pickInRound).padStart(2, "0")}
|
{round}.{String(pickInRound).padStart(2, "0")}
|
||||||
</div>
|
</div>
|
||||||
{coronaState && coronaState.type !== "pending" && (
|
{coronaState && coronaState.type !== "pending" && (
|
||||||
<span className={`text-xs font-mono font-bold mt-0.5 ${coronaState.type === "eliminated" ? "text-coral-accent" : "text-emerald-400"}`}>
|
<span className={`text-[10px] font-mono font-bold ${coronaState.type === "eliminated" ? "text-coral-accent" : "text-emerald-400"}`}>
|
||||||
{coronaState.type === "scored" && "▲"}{coronaState.points}
|
{coronaState.type === "scored" && "▲"}{coronaState.points}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{state === "picked" && pick ? (
|
||||||
|
<>
|
||||||
|
<div className="font-semibold truncate text-xs leading-4">{pick.participant.name}</div>
|
||||||
|
<div className="text-muted-foreground truncate text-[10px] leading-3">
|
||||||
|
{pick.sport.name}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : isCurrent ? (
|
||||||
|
<div className="text-sm font-bold text-white">{currentLabel}</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
{children && <div className="absolute inset-0 pointer-events-none [&_*]:pointer-events-auto">{children}</div>}
|
{children && <div className="absolute inset-0 pointer-events-none [&_*]:pointer-events-auto">{children}</div>}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { memo, useMemo } from "react";
|
import { memo, useMemo } from "react";
|
||||||
import { DraftPickCell } from "~/components/draft/DraftPickCell";
|
import { DraftPickCell } from "~/components/draft/DraftPickCell";
|
||||||
|
import type { SeasonStatus } from "~/models/season";
|
||||||
import {
|
import {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
ContextMenuContent,
|
ContextMenuContent,
|
||||||
|
|
@ -36,6 +37,8 @@ interface MiniDraftGridProps {
|
||||||
currentPick: number;
|
currentPick: number;
|
||||||
currentRound: number;
|
currentRound: number;
|
||||||
ownerMap?: Record<string, string>;
|
ownerMap?: Record<string, string>;
|
||||||
|
seasonStatus?: SeasonStatus;
|
||||||
|
draftPaused?: boolean;
|
||||||
onForceAutopick?: (pickNumber: number, teamId: string) => void;
|
onForceAutopick?: (pickNumber: number, teamId: string) => void;
|
||||||
onForceManualPickOpen?: (pickNumber: number, teamId: string) => void;
|
onForceManualPickOpen?: (pickNumber: number, teamId: string) => void;
|
||||||
onReplacePick?: (pickNumber: number, teamId: string) => void;
|
onReplacePick?: (pickNumber: number, teamId: string) => void;
|
||||||
|
|
@ -48,6 +51,8 @@ export const MiniDraftGrid = memo(function MiniDraftGrid({
|
||||||
currentPick,
|
currentPick,
|
||||||
currentRound,
|
currentRound,
|
||||||
ownerMap = {},
|
ownerMap = {},
|
||||||
|
seasonStatus,
|
||||||
|
draftPaused,
|
||||||
onForceAutopick,
|
onForceAutopick,
|
||||||
onForceManualPickOpen,
|
onForceManualPickOpen,
|
||||||
onReplacePick,
|
onReplacePick,
|
||||||
|
|
@ -113,6 +118,8 @@ export const MiniDraftGrid = memo(function MiniDraftGrid({
|
||||||
pickInRound={cell.pickInRound}
|
pickInRound={cell.pickInRound}
|
||||||
state={cellState}
|
state={cellState}
|
||||||
pick={pickData}
|
pick={pickData}
|
||||||
|
seasonStatus={seasonStatus}
|
||||||
|
draftPaused={draftPaused}
|
||||||
className="[&>div]:h-10 cursor-context-menu"
|
className="[&>div]:h-10 cursor-context-menu"
|
||||||
/>
|
/>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
|
|
@ -142,6 +149,8 @@ export const MiniDraftGrid = memo(function MiniDraftGrid({
|
||||||
pickInRound={cell.pickInRound}
|
pickInRound={cell.pickInRound}
|
||||||
state={cellState}
|
state={cellState}
|
||||||
pick={pickData}
|
pick={pickData}
|
||||||
|
seasonStatus={seasonStatus}
|
||||||
|
draftPaused={draftPaused}
|
||||||
className="[&>div]:h-10 cursor-context-menu"
|
className="[&>div]:h-10 cursor-context-menu"
|
||||||
/>
|
/>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
|
|
@ -172,6 +181,8 @@ export const MiniDraftGrid = memo(function MiniDraftGrid({
|
||||||
pickInRound={cell.pickInRound}
|
pickInRound={cell.pickInRound}
|
||||||
state={cellState}
|
state={cellState}
|
||||||
pick={pickData}
|
pick={pickData}
|
||||||
|
seasonStatus={seasonStatus}
|
||||||
|
draftPaused={draftPaused}
|
||||||
className="[&>div]:h-10"
|
className="[&>div]:h-10"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ interface QueueSectionProps {
|
||||||
name: string;
|
name: string;
|
||||||
sport: { name: string };
|
sport: { name: string };
|
||||||
}>;
|
}>;
|
||||||
isMyTurn: boolean;
|
|
||||||
canPick: boolean;
|
canPick: boolean;
|
||||||
onRemoveFromQueue: (queueId: string) => void;
|
onRemoveFromQueue: (queueId: string) => void;
|
||||||
onReorder: (participantIds: string[]) => void;
|
onReorder: (participantIds: string[]) => void;
|
||||||
|
|
@ -122,7 +121,6 @@ const SortableQueueItem = memo(function SortableQueueItem({
|
||||||
export const QueueSection = memo(function QueueSection({
|
export const QueueSection = memo(function QueueSection({
|
||||||
queue,
|
queue,
|
||||||
availableParticipants,
|
availableParticipants,
|
||||||
isMyTurn,
|
|
||||||
canPick,
|
canPick,
|
||||||
onRemoveFromQueue,
|
onRemoveFromQueue,
|
||||||
onReorder,
|
onReorder,
|
||||||
|
|
|
||||||
|
|
@ -311,6 +311,8 @@ export default function DraftBoard() {
|
||||||
currentPick={currentPick}
|
currentPick={currentPick}
|
||||||
ownerMap={ownerMap}
|
ownerMap={ownerMap}
|
||||||
coronaStates={coronaStates}
|
coronaStates={coronaStates}
|
||||||
|
seasonStatus={season.status}
|
||||||
|
draftPaused={season.draftPaused}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import { useDraftSocket } from "~/hooks/useDraftSocket";
|
||||||
import { logger } from "~/lib/logger";
|
import { logger } from "~/lib/logger";
|
||||||
import { useCallback, useEffect, useState, useMemo, useRef } from "react";
|
import { useCallback, useEffect, useState, useMemo, useRef } from "react";
|
||||||
import { Button } from "~/components/ui/button";
|
import { Button } from "~/components/ui/button";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";
|
import { Tabs, TabsList, TabsTrigger } from "~/components/ui/tabs";
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "~/components/ui/dialog";
|
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from "~/components/ui/dialog";
|
||||||
import { getAuth } from "@clerk/react-router/server";
|
import { getAuth } from "@clerk/react-router/server";
|
||||||
import { getTeamQueue } from "~/models/draft-queue";
|
import { getTeamQueue } from "~/models/draft-queue";
|
||||||
|
|
@ -1509,11 +1509,13 @@ export default function DraftRoom() {
|
||||||
currentPick,
|
currentPick,
|
||||||
currentRound,
|
currentRound,
|
||||||
ownerMap,
|
ownerMap,
|
||||||
|
seasonStatus: season.status,
|
||||||
|
draftPaused: isPaused,
|
||||||
onForceAutopick: isCommissioner ? handleForceAutopick : undefined,
|
onForceAutopick: isCommissioner ? handleForceAutopick : undefined,
|
||||||
onForceManualPickOpen: isCommissioner ? handleForceManualPickOpen : undefined,
|
onForceManualPickOpen: isCommissioner ? handleForceManualPickOpen : undefined,
|
||||||
onReplacePick: isCommissioner ? handleReplacePickOpen : undefined,
|
onReplacePick: isCommissioner ? handleReplacePickOpen : undefined,
|
||||||
onRollbackToPick: isCommissioner && !isDraftComplete ? handleRollbackToPick : undefined,
|
onRollbackToPick: isCommissioner && !isDraftComplete ? handleRollbackToPick : undefined,
|
||||||
}), [draftSlots, draftGrid, currentPick, currentRound, ownerMap, isCommissioner, handleForceAutopick, handleForceManualPickOpen, handleReplacePickOpen, handleRollbackToPick, isDraftComplete]);
|
}), [draftSlots, draftGrid, currentPick, currentRound, ownerMap, season.status, isPaused, isCommissioner, handleForceAutopick, handleForceManualPickOpen, handleReplacePickOpen, handleRollbackToPick, isDraftComplete]);
|
||||||
|
|
||||||
const availableParticipantsSectionProps = useMemo(() => ({
|
const availableParticipantsSectionProps = useMemo(() => ({
|
||||||
participants: filteredParticipants,
|
participants: filteredParticipants,
|
||||||
|
|
@ -1550,6 +1552,8 @@ export default function DraftRoom() {
|
||||||
connectedTeams,
|
connectedTeams,
|
||||||
isCommissioner,
|
isCommissioner,
|
||||||
ownerMap,
|
ownerMap,
|
||||||
|
seasonStatus: season.status,
|
||||||
|
draftPaused: isPaused,
|
||||||
onAdjustTimeBankOpen: isCommissioner ? handleAdjustTimeBankOpen : undefined,
|
onAdjustTimeBankOpen: isCommissioner ? handleAdjustTimeBankOpen : undefined,
|
||||||
onSetAutodraftOpen: isCommissioner ? handleSetAutodraftOpen : undefined,
|
onSetAutodraftOpen: isCommissioner ? handleSetAutodraftOpen : undefined,
|
||||||
onForceAutopick: handleForceAutopick,
|
onForceAutopick: handleForceAutopick,
|
||||||
|
|
@ -1584,7 +1588,6 @@ export default function DraftRoom() {
|
||||||
? {
|
? {
|
||||||
queue,
|
queue,
|
||||||
availableParticipants,
|
availableParticipants,
|
||||||
isMyTurn,
|
|
||||||
canPick,
|
canPick,
|
||||||
onRemoveFromQueue: handleRemoveFromQueue,
|
onRemoveFromQueue: handleRemoveFromQueue,
|
||||||
onReorder: handleReorderQueue,
|
onReorder: handleReorderQueue,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue