brackt/app/routes/admin.leagues.tsx
Claude ddb646402c
All checks were successful
🚀 Deploy / 🧪 Test (pull_request) Successful in 2m45s
🚀 Deploy / ʦ🔍 Typecheck & Lint (pull_request) Successful in 1m21s
🚀 Deploy / 🐳 Build (pull_request) Has been skipped
🚀 Deploy / 🚀 Deploy (pull_request) Has been skipped
Add admin leagues page and mobile-friendly admin layout
- Make admin sidebar responsive: hidden on mobile with a Sheet drawer
  triggered by a hamburger menu button; fixed top bar on mobile
- Reduce dashboard padding to p-4 on mobile (p-8 on md+)
- Add listLeaguesWithStatus() to league model (left-joins seasons for status/year)
- New /admin/leagues page: table of all leagues with link, season year, status badge
- Register admin/leagues route and add Leagues nav link to admin sidebar

https://claude.ai/code/session_01GWWdJ5m8cBK1Es355YNt18
2026-06-11 00:14:31 +00:00

116 lines
3.6 KiB
TypeScript

import { Link } from "react-router";
import type { Route } from "./+types/admin.leagues";
import { listLeaguesWithStatus } from "~/models/league";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "~/components/ui/card";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "~/components/ui/table";
import { Badge } from "~/components/ui/badge";
import type { SeasonStatus } from "~/models/season";
export function meta(): Route.MetaDescriptors {
return [{ title: "Leagues — Brackt Admin" }];
}
export async function loader() {
const leagues = await listLeaguesWithStatus();
return { leagues };
}
function StatusBadge({ status }: { status: SeasonStatus | null }) {
if (!status) {
return <Badge variant="outline" className="text-muted-foreground">No Season</Badge>;
}
switch (status) {
case "pre_draft":
return <Badge variant="secondary">Pre-Draft</Badge>;
case "draft":
return (
<Badge className="border-amber-300 text-amber-700 dark:border-amber-700 dark:text-amber-400 bg-amber-50 dark:bg-amber-950/30" variant="outline">
Drafting
</Badge>
);
case "active":
return (
<Badge className="border-green-300 text-green-700 dark:border-green-700 dark:text-green-400 bg-green-50 dark:bg-green-950/30" variant="outline">
Active
</Badge>
);
case "completed":
return <Badge variant="outline">Completed</Badge>;
}
}
export default function AdminLeagues({ loaderData }: Route.ComponentProps) {
const { leagues } = loaderData;
return (
<div className="p-4 md:p-8">
<div className="mb-6">
<h1 className="text-2xl font-bold">Leagues</h1>
<p className="text-muted-foreground text-sm mt-1">{leagues.length} total leagues</p>
</div>
<Card>
<CardHeader>
<CardTitle>All Leagues</CardTitle>
<CardDescription>Every league in the system with their current season status.</CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>League Name</TableHead>
<TableHead>Season Year</TableHead>
<TableHead>Status</TableHead>
<TableHead>Created</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{leagues.length === 0 && (
<TableRow>
<TableCell colSpan={4} className="text-center text-muted-foreground py-8">
No leagues found.
</TableCell>
</TableRow>
)}
{leagues.map((league) => (
<TableRow key={league.id}>
<TableCell className="font-medium">
<Link
to={`/leagues/${league.id}`}
className="hover:underline text-foreground"
>
{league.name}
</Link>
</TableCell>
<TableCell className="text-sm text-muted-foreground">
{league.currentSeasonYear ?? "—"}
</TableCell>
<TableCell>
<StatusBadge status={league.currentSeasonStatus} />
</TableCell>
<TableCell className="text-sm text-muted-foreground">
{new Date(league.createdAt).toLocaleDateString()}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</CardContent>
</Card>
</div>
);
}