From 37de6787bf0e8cb50144e9c7f5c5b059a3f206fa Mon Sep 17 00:00:00 2001 From: Chris Parsons Date: Sun, 12 Oct 2025 21:54:49 -0700 Subject: [PATCH] feat: add admin routes and checkbox component for sports management --- app/components/ui/badge.tsx | 46 +++ app/components/ui/checkbox.tsx | 30 ++ app/components/ui/table.tsx | 114 ++++++ app/components/ui/textarea.tsx | 18 + app/routes.ts | 17 + app/routes/admin._index.tsx | 170 ++++++++ app/routes/admin.data-sync.tsx | 376 +++++++++++++++++ app/routes/admin.participants.tsx | 37 ++ .../admin.sports-seasons.$id.participants.tsx | 207 ++++++++++ app/routes/admin.sports-seasons.$id.tsx | 309 ++++++++++++++ app/routes/admin.sports-seasons.new.tsx | 221 ++++++++++ app/routes/admin.sports-seasons.tsx | 126 ++++++ app/routes/admin.sports.new.tsx | 155 +++++++ app/routes/admin.sports.tsx | 106 +++++ app/routes/admin.templates.$id.tsx | 381 ++++++++++++++++++ app/routes/admin.templates.new.tsx | 144 +++++++ app/routes/admin.templates.tsx | 108 +++++ app/routes/admin.tsx | 78 ++++ app/routes/api.admin.export-sports-data.ts | 21 + app/utils/sports-data-sync.server.ts | 334 +++++++++++++++ package-lock.json | 31 ++ package.json | 1 + 22 files changed, 3030 insertions(+) create mode 100644 app/components/ui/badge.tsx create mode 100644 app/components/ui/checkbox.tsx create mode 100644 app/components/ui/table.tsx create mode 100644 app/components/ui/textarea.tsx create mode 100644 app/routes/admin._index.tsx create mode 100644 app/routes/admin.data-sync.tsx create mode 100644 app/routes/admin.participants.tsx create mode 100644 app/routes/admin.sports-seasons.$id.participants.tsx create mode 100644 app/routes/admin.sports-seasons.$id.tsx create mode 100644 app/routes/admin.sports-seasons.new.tsx create mode 100644 app/routes/admin.sports-seasons.tsx create mode 100644 app/routes/admin.sports.new.tsx create mode 100644 app/routes/admin.sports.tsx create mode 100644 app/routes/admin.templates.$id.tsx create mode 100644 app/routes/admin.templates.new.tsx create mode 100644 app/routes/admin.templates.tsx create mode 100644 app/routes/admin.tsx create mode 100644 app/routes/api.admin.export-sports-data.ts create mode 100644 app/utils/sports-data-sync.server.ts diff --git a/app/components/ui/badge.tsx b/app/components/ui/badge.tsx new file mode 100644 index 0000000..465ecc8 --- /dev/null +++ b/app/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "app/lib/utils" + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +) + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span" + + return ( + + ) +} + +export { Badge, badgeVariants } diff --git a/app/components/ui/checkbox.tsx b/app/components/ui/checkbox.tsx new file mode 100644 index 0000000..8c9e905 --- /dev/null +++ b/app/components/ui/checkbox.tsx @@ -0,0 +1,30 @@ +import * as React from "react" +import * as CheckboxPrimitive from "@radix-ui/react-checkbox" +import { CheckIcon } from "lucide-react" + +import { cn } from "app/lib/utils" + +function Checkbox({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + + + ) +} + +export { Checkbox } diff --git a/app/components/ui/table.tsx b/app/components/ui/table.tsx new file mode 100644 index 0000000..1770fc1 --- /dev/null +++ b/app/components/ui/table.tsx @@ -0,0 +1,114 @@ +import * as React from "react" + +import { cn } from "app/lib/utils" + +function Table({ className, ...props }: React.ComponentProps<"table">) { + return ( +
+ + + ) +} + +function TableHeader({ className, ...props }: React.ComponentProps<"thead">) { + return ( + + ) +} + +function TableBody({ className, ...props }: React.ComponentProps<"tbody">) { + return ( + + ) +} + +function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) { + return ( + tr]:last:border-b-0", + className + )} + {...props} + /> + ) +} + +function TableRow({ className, ...props }: React.ComponentProps<"tr">) { + return ( + + ) +} + +function TableHead({ className, ...props }: React.ComponentProps<"th">) { + return ( +
[role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> + ) +} + +function TableCell({ className, ...props }: React.ComponentProps<"td">) { + return ( + [role=checkbox]]:translate-y-[2px]", + className + )} + {...props} + /> + ) +} + +function TableCaption({ + className, + ...props +}: React.ComponentProps<"caption">) { + return ( +
+ ) +} + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/app/components/ui/textarea.tsx b/app/components/ui/textarea.tsx new file mode 100644 index 0000000..9236690 --- /dev/null +++ b/app/components/ui/textarea.tsx @@ -0,0 +1,18 @@ +import * as React from "react" + +import { cn } from "app/lib/utils" + +function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { + return ( +