From 269499d5847dd4dfe8093902d8f9dd482b820d3c Mon Sep 17 00:00:00 2001 From: Chris Parsons Date: Fri, 17 Oct 2025 12:45:30 -0700 Subject: [PATCH] feat: add draft room authentication and UI improvements with exit button --- .../leagues/$leagueId.draft.$seasonId.tsx | 96 ++++++++++++++----- 1 file changed, 70 insertions(+), 26 deletions(-) diff --git a/app/routes/leagues/$leagueId.draft.$seasonId.tsx b/app/routes/leagues/$leagueId.draft.$seasonId.tsx index 9fc3e2f..50211fe 100644 --- a/app/routes/leagues/$leagueId.draft.$seasonId.tsx +++ b/app/routes/leagues/$leagueId.draft.$seasonId.tsx @@ -1,4 +1,4 @@ -import { useLoaderData } from "react-router"; +import { useLoaderData, Link } from "react-router"; import { eq, and, asc, notInArray } from "drizzle-orm"; import { database } from "~/database/context"; import * as schema from "~/database/schema"; @@ -6,14 +6,24 @@ import { useDraftSocket } from "~/hooks/useDraftSocket"; import { useEffect, useState } from "react"; import { Card } from "~/components/ui/card"; import { Badge } from "~/components/ui/badge"; +import { Button } from "~/components/ui/button"; +import { getAuth } from "@clerk/react-router/server"; +import { getTeamQueue } from "~/models/draft-queue"; -export async function loader({ params }: { params: { seasonId: string } }) { - const { seasonId } = params; +export async function loader(args: any) { + const { params } = args; + const { seasonId, leagueId } = params; + const auth = await getAuth(args); + const userId = (auth as any).userId as string | null; if (!seasonId) { throw new Response("Season ID is required", { status: 400 }); } + if (!userId) { + throw new Response("You must be logged in to view the draft room", { status: 401 }); + } + const db = database(); // Get season details @@ -29,6 +39,19 @@ export async function loader({ params }: { params: { seasonId: string } }) { throw new Response("Season not found", { status: 404 }); } + // Verify user access: must be team owner or commissioner + const userTeam = season.teams.find((team: any) => team.ownerId === userId); + const isCommissioner = await db.query.commissioners.findFirst({ + where: and( + eq(schema.commissioners.leagueId, leagueId), + eq(schema.commissioners.userId, userId) + ), + }); + + if (!userTeam && !isCommissioner) { + throw new Response("You do not have access to this draft room", { status: 403 }); + } + // Get draft slots (draft order) - using select instead of query builder const draftSlots = await db .select({ @@ -82,16 +105,23 @@ export async function loader({ params }: { params: { seasonId: string } }) { ) .orderBy(asc(schema.participants.name)); + // Load user's team queue if they have a team + const userQueue = userTeam ? await getTeamQueue(userTeam.id) : []; + return { season, draftSlots, draftPicks, availableParticipants, + userTeam, + userQueue, + isCommissioner: !!isCommissioner, + currentUserId: userId, }; } export default function DraftRoom() { - const { season, draftSlots, draftPicks, availableParticipants } = + const { season, draftSlots, draftPicks, availableParticipants, userTeam: _userTeam, isCommissioner: _isCommissioner } = useLoaderData(); const { isConnected, on, off } = useDraftSocket(season.id); const [picks, setPicks] = useState(draftPicks); @@ -117,32 +147,45 @@ export default function DraftRoom() { const currentRound = Math.ceil(currentPick / draftSlots.length); return ( -
- {/* Header */} -
-
-

- {season.league.name} - {season.year} Draft -

-
-
- - {isConnected ? "Live" : "Disconnected"} - +
+ {/* Standalone Header - No Main Nav */} +
+
+
+
+

+ {season.league.name} - {season.year} Draft +

+
+ Round: {currentRound} + Pick: {currentPick} + {season.status.replace("_", " ")} +
+
+
+
+
+ + {isConnected ? "Live" : "Disconnected"} + +
+ +
-
- Round: {currentRound} - Pick: {currentPick} - Status: {season.status} -
-
+ {/* Main Content */} +
+
{/* Left Column: Draft Board */}
@@ -226,6 +269,7 @@ export default function DraftRoom() {
+
); }