diff --git a/app/routes.ts b/app/routes.ts index 372c11f..d2e8900 100644 --- a/app/routes.ts +++ b/app/routes.ts @@ -14,6 +14,7 @@ export default [ index("routes/admin._index.tsx"), route("sports", "routes/admin.sports.tsx"), route("sports/new", "routes/admin.sports.new.tsx"), + route("sports/:id", "routes/admin.sports.$id.tsx"), route("sports-seasons", "routes/admin.sports-seasons.tsx"), route("sports-seasons/new", "routes/admin.sports-seasons.new.tsx"), route("sports-seasons/:id", "routes/admin.sports-seasons.$id.tsx"), diff --git a/app/routes/admin.sports.$id.tsx b/app/routes/admin.sports.$id.tsx new file mode 100644 index 0000000..90f28a5 --- /dev/null +++ b/app/routes/admin.sports.$id.tsx @@ -0,0 +1,170 @@ +import { Form, Link, redirect } from "react-router"; +import type { Route } from "./+types/admin.sports.$id"; +import { findSportById, updateSport } from "~/models/sport"; +import { Button } from "~/components/ui/button"; +import { Input } from "~/components/ui/input"; +import { Label } from "~/components/ui/label"; +import { Textarea } from "~/components/ui/textarea"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "~/components/ui/card"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "~/components/ui/select"; + +export async function loader({ params }: Route.LoaderArgs) { + const sport = await findSportById(params.id); + + if (!sport) { + throw new Response("Sport not found", { status: 404 }); + } + + return { sport }; +} + +export async function action({ request, params }: Route.ActionArgs) { + const formData = await request.formData(); + const name = formData.get("name"); + const type = formData.get("type"); + const slug = formData.get("slug"); + const description = formData.get("description"); + + // Validation + if (typeof name !== "string" || !name.trim()) { + return { error: "Sport name is required" }; + } + + if (type !== "team" && type !== "individual") { + return { error: "Sport type must be either 'team' or 'individual'" }; + } + + if (typeof slug !== "string" || !slug.trim()) { + return { error: "Slug is required" }; + } + + // Validate slug format (lowercase, hyphens only) + if (!/^[a-z0-9-]+$/.test(slug)) { + return { error: "Slug must contain only lowercase letters, numbers, and hyphens" }; + } + + try { + await updateSport(params.id, { + name: name.trim(), + type, + slug: slug.trim(), + description: typeof description === "string" ? description.trim() : null, + }); + + return redirect("/admin/sports"); + } catch (error) { + console.error("Error updating sport:", error); + return { error: "Failed to update sport. The slug might already exist." }; + } +} + +export default function EditSport({ loaderData, actionData }: Route.ComponentProps) { + const { sport } = loaderData; + + return ( +
+ Update the sport information +
+Current Season
-{league.currentSeason.year}
++ {league.currentSeason.year} +
Status