import { Form, Link, redirect } from "react-router"; import type { Route } from "./+types/admin.sports.new"; import { logger } from "~/lib/logger"; import { createSport, findAllSports } from "~/models/sport"; import { deleteSportIconIfUnused } from "~/lib/sport-icon-cleanup.server"; import { parseSportIconUrlInput } from "~/lib/sport-icon-url"; 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 { SportIconUploader } from "~/components/ui/SportIconUploader"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "~/components/ui/card"; const SELECT_CLASS = "h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm"; export function meta(): Route.MetaDescriptors { return [{ title: "New Sport - Brackt Admin" }]; } export async function loader() { const sports = await findAllSports(); return { existingIconOptions: sports .filter((sport) => Boolean(sport.iconUrl)) .map((sport) => ({ id: sport.id, name: sport.name, iconUrl: sport.iconUrl as string })), }; } export async function action({ request }: 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"); const iconUrlValue = formData.get("iconUrl"); const excludeFromHomepage = formData.get("excludeFromHomepage") === "on"; // 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" }; } const iconUrl = parseSportIconUrlInput(iconUrlValue); if (iconUrl === undefined) { return { error: "Sport icon must be an uploaded SVG icon." }; } try { await createSport({ name: name.trim(), type, slug: slug.trim(), description: typeof description === "string" ? description.trim() : null, iconUrl, excludeFromHomepage, }); return redirect("/admin/sports"); } catch (error) { logger.error("Error creating sport:", error); if (iconUrl) { await deleteSportIconIfUnused({ iconUrl, reason: "unused" }); } return { error: "Failed to create sport. The slug might already exist." }; } } export default function NewSport({ loaderData, actionData }: Route.ComponentProps) { return (

Create New Sport

Add a new sport to the system

Sport Details Enter the information for the new sport

Team sports have teams, individual sports have players

URL-friendly identifier (lowercase, hyphens only)