feat: add draft room authentication and UI improvements with exit button
This commit is contained in:
parent
137c4eb0fd
commit
269499d584
1 changed files with 70 additions and 26 deletions
|
|
@ -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<typeof loader>();
|
||||
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 (
|
||||
<div className="container mx-auto p-4">
|
||||
{/* Header */}
|
||||
<div className="mb-6">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<h1 className="text-3xl font-bold">
|
||||
{season.league.name} - {season.year} Draft
|
||||
</h1>
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`w-3 h-3 rounded-full ${
|
||||
isConnected ? "bg-green-500" : "bg-red-500"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-sm font-medium">
|
||||
{isConnected ? "Live" : "Disconnected"}
|
||||
</span>
|
||||
<div className="min-h-screen bg-background">
|
||||
{/* Standalone Header - No Main Nav */}
|
||||
<div className="border-b bg-card">
|
||||
<div className="container mx-auto p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">
|
||||
{season.league.name} - {season.year} Draft
|
||||
</h1>
|
||||
<div className="flex gap-4 text-sm text-muted-foreground mt-1">
|
||||
<span>Round: {currentRound}</span>
|
||||
<span>Pick: {currentPick}</span>
|
||||
<span className="capitalize">{season.status.replace("_", " ")}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`w-3 h-3 rounded-full ${
|
||||
isConnected ? "bg-green-500" : "bg-red-500"
|
||||
}`}
|
||||
/>
|
||||
<span className="text-sm font-medium">
|
||||
{isConnected ? "Live" : "Disconnected"}
|
||||
</span>
|
||||
</div>
|
||||
<Button variant="outline" asChild>
|
||||
<Link to={`/leagues/${season.leagueId}`}>
|
||||
Exit Draft Room
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-4 text-sm text-gray-600">
|
||||
<span>Round: {currentRound}</span>
|
||||
<span>Pick: {currentPick}</span>
|
||||
<span>Status: {season.status}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
{/* Main Content */}
|
||||
<div className="container mx-auto p-4">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
{/* Left Column: Draft Board */}
|
||||
<div className="lg:col-span-2">
|
||||
<Card className="p-4">
|
||||
|
|
@ -226,6 +269,7 @@ export default function DraftRoom() {
|
|||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue