- 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
116 lines
3.6 KiB
TypeScript
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>
|
|
);
|
|
}
|