feat: add draft queue component and data fetching to draft room page

This commit is contained in:
Chris Parsons 2025-10-16 01:32:23 -07:00
parent 013edbc661
commit 8a61085f3b
2 changed files with 138 additions and 3 deletions

View file

@ -0,0 +1,125 @@
import { useState } from "react";
import { Button } from "~/components/ui/button";
import { Badge } from "~/components/ui/badge";
import { GripVertical, X } from "lucide-react";
interface Participant {
id: string;
name: string;
sport: string;
expectedValue: number;
}
interface QueueItem {
id: string;
participantId: string;
queuePosition: number;
}
interface DraftQueueProps {
queueItems: QueueItem[];
participants: Participant[];
onReorder?: (participantIds: string[]) => void;
onRemove?: (queueItemId: string) => void;
}
export function DraftQueue({
queueItems,
participants,
onReorder,
onRemove,
}: DraftQueueProps) {
const [draggedIndex, setDraggedIndex] = useState<number | null>(null);
// Create a map for quick participant lookup
const participantMap = new Map(participants.map((p) => [p.id, p]));
// Sort queue items by position
const sortedQueue = [...queueItems].sort((a, b) => a.queuePosition - b.queuePosition);
const handleDragStart = (index: number) => {
setDraggedIndex(index);
};
const handleDragOver = (e: React.DragEvent, index: number) => {
e.preventDefault();
if (draggedIndex === null || draggedIndex === index) return;
// Reorder the items
const newQueue = [...sortedQueue];
const draggedItem = newQueue[draggedIndex];
newQueue.splice(draggedIndex, 1);
newQueue.splice(index, 0, draggedItem);
// Update positions and notify parent
const participantIds = newQueue.map((item) => item.participantId);
onReorder?.(participantIds);
setDraggedIndex(index);
};
const handleDragEnd = () => {
setDraggedIndex(null);
};
if (sortedQueue.length === 0) {
return (
<div className="text-center py-8 text-muted-foreground">
<p>Your queue is empty</p>
<p className="text-sm mt-2">Add players from the Available Players list</p>
</div>
);
}
return (
<div className="space-y-2">
{sortedQueue.map((item, index) => {
const participant = participantMap.get(item.participantId);
if (!participant) return null;
return (
<div
key={item.id}
draggable
onDragStart={() => handleDragStart(index)}
onDragOver={(e) => handleDragOver(e, index)}
onDragEnd={handleDragEnd}
className={`flex items-center gap-2 p-3 rounded-lg border bg-card transition-all ${
draggedIndex === index ? "opacity-50" : "hover:bg-accent cursor-move"
}`}
>
{/* Drag Handle */}
<div className="flex items-center gap-2 text-muted-foreground">
<GripVertical className="h-4 w-4" />
<span className="text-sm font-semibold w-6">{index + 1}</span>
</div>
{/* Player Info */}
<div className="flex-1 min-w-0">
<div className="font-medium truncate">{participant.name}</div>
<div className="flex items-center gap-2 mt-1">
<Badge variant="secondary" className="text-xs">
{participant.sport}
</Badge>
<span className="text-xs text-muted-foreground">
EV: {participant.expectedValue.toFixed(1)}
</span>
</div>
</div>
{/* Remove Button */}
{onRemove && (
<Button
variant="ghost"
size="sm"
onClick={() => onRemove(item.id)}
className="h-8 w-8 p-0"
>
<X className="h-4 w-4" />
</Button>
)}
</div>
);
})}
</div>
);
}

View file

@ -10,9 +10,11 @@ import {
getDraftPicks,
getSeasonTimers,
findSeasonWithSportsSeasons,
getTeamQueue,
} from "~/models";
import { DraftGrid } from "~/components/draft/DraftGrid";
import { PlayerList } from "~/components/draft/PlayerList";
import { DraftQueue } from "~/components/draft/DraftQueue";
export async function loader(args: LoaderFunctionArgs) {
const { userId } = await getAuth(args);
@ -69,6 +71,9 @@ export async function loader(args: LoaderFunctionArgs) {
const draftPicks = await getDraftPicks(season.id);
const timers = await getSeasonTimers(season.id);
// Get user's queue if they have a team
const queueItems = userTeam ? await getTeamQueue(userTeam.id) : [];
// Calculate current pick info
const totalPicks = season.draftRounds * teams.length;
const currentPickNumber = season.currentPickNumber || 1;
@ -83,6 +88,7 @@ export async function loader(args: LoaderFunctionArgs) {
userTeam,
draftPicks,
participants,
queueItems,
timers,
currentPickNumber,
totalPicks,
@ -98,6 +104,7 @@ export default function DraftRoom({ loaderData }: { loaderData: Awaited<ReturnTy
teams,
draftPicks,
participants,
queueItems,
isCommissioner,
userTeam,
currentPickNumber,
@ -170,10 +177,13 @@ export default function DraftRoom({ loaderData }: { loaderData: Awaited<ReturnTy
</div>
{/* Your Queue */}
<div className="rounded-lg border bg-card p-6">
<div className="rounded-lg border bg-card p-6 flex flex-col" style={{ height: "600px" }}>
<h2 className="mb-4 text-xl font-bold">Your Queue</h2>
<div className="flex items-center justify-center py-12 text-muted-foreground">
Queue will be implemented in Phase 7
<div className="flex-1 overflow-y-auto">
<DraftQueue
queueItems={queueItems}
participants={participants}
/>
</div>
</div>