137 lines
4.8 KiB
TypeScript
137 lines
4.8 KiB
TypeScript
import { Link } from "react-router";
|
|
import type { Route } from "./+types/admin.sports-seasons";
|
|
import { findAllSportsSeasons } from "~/models/sports-season";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "~/components/ui/card";
|
|
import { Button } from "~/components/ui/button";
|
|
import { Plus, Calendar } from "lucide-react";
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from "~/components/ui/table";
|
|
import { Badge } from "~/components/ui/badge";
|
|
|
|
export async function loader() {
|
|
const sportsSeasons = await findAllSportsSeasons();
|
|
// Type assertion since we know the sport and participants relations are included from the model
|
|
return {
|
|
sportsSeasons: sportsSeasons as Array<
|
|
typeof sportsSeasons[0] & {
|
|
sport: { id: string; name: string; type: string; slug: string };
|
|
participants: Array<{ id: string }>;
|
|
}
|
|
>
|
|
};
|
|
}
|
|
|
|
export default function AdminSportsSeasons({ loaderData }: Route.ComponentProps) {
|
|
const { sportsSeasons } = loaderData;
|
|
|
|
return (
|
|
<div className="p-8">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h1 className="text-3xl font-bold">Sports Seasons</h1>
|
|
<p className="text-muted-foreground mt-1">
|
|
Manage sports seasons across all sports
|
|
</p>
|
|
</div>
|
|
<Button asChild>
|
|
<Link to="/admin/sports-seasons/new">
|
|
<Plus className="mr-2 h-4 w-4" />
|
|
Add Sports Season
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle>All Sports Seasons</CardTitle>
|
|
<CardDescription>
|
|
{sportsSeasons.length} {sportsSeasons.length === 1 ? "season" : "seasons"} total
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{sportsSeasons.length === 0 ? (
|
|
<div className="text-center py-12">
|
|
<Calendar className="mx-auto h-12 w-12 text-muted-foreground" />
|
|
<h3 className="mt-4 text-lg font-semibold">No sports seasons yet</h3>
|
|
<p className="text-muted-foreground mt-2">
|
|
Get started by creating your first sports season
|
|
</p>
|
|
<Button className="mt-4" asChild>
|
|
<Link to="/admin/sports-seasons/new">
|
|
<Plus className="mr-2 h-4 w-4" />
|
|
Add Sports Season
|
|
</Link>
|
|
</Button>
|
|
</div>
|
|
) : (
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Name</TableHead>
|
|
<TableHead>Sport</TableHead>
|
|
<TableHead>Year</TableHead>
|
|
<TableHead>Status</TableHead>
|
|
<TableHead>Scoring Type</TableHead>
|
|
<TableHead>Participants</TableHead>
|
|
<TableHead className="text-right">Actions</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{sportsSeasons.map((season) => (
|
|
<TableRow key={season.id}>
|
|
<TableCell className="font-medium">{season.name}</TableCell>
|
|
<TableCell>{season.sport.name}</TableCell>
|
|
<TableCell>{season.year}</TableCell>
|
|
<TableCell>
|
|
<Badge
|
|
variant={
|
|
season.status === "active"
|
|
? "default"
|
|
: season.status === "completed"
|
|
? "secondary"
|
|
: "outline"
|
|
}
|
|
>
|
|
{season.status}
|
|
</Badge>
|
|
</TableCell>
|
|
<TableCell className="text-muted-foreground capitalize">
|
|
{season.scoringType.replace("_", " ")}
|
|
</TableCell>
|
|
<TableCell className="text-muted-foreground">
|
|
{season.participants.length}
|
|
</TableCell>
|
|
<TableCell className="text-right">
|
|
<div className="flex items-center justify-end gap-2">
|
|
<Button variant="ghost" size="sm" asChild>
|
|
<Link to={`/admin/sports-seasons/${season.id}/participants`}>
|
|
Participants
|
|
</Link>
|
|
</Button>
|
|
<Button variant="ghost" size="sm" asChild>
|
|
<Link to={`/admin/sports-seasons/${season.id}`}>Edit</Link>
|
|
</Button>
|
|
</div>
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
</TableBody>
|
|
</Table>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|