From aaf11b877e7c582742cad88e2fbbe42a2ad788fc Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Fri, 27 Mar 2026 14:54:26 -0700 Subject: [PATCH] feat: add player profiles, schedule, tournaments admin, and CSV upload API --- package-lock.json | 7 + package.json | 1 + src/app/admin/tournaments/new/page.tsx | 178 ++++++++++++++++++ src/app/admin/tournaments/page.tsx | 134 ++++++++++++++ src/app/api/matches/route.ts | 234 ++++++++++++++++++++++++ src/app/api/matches/upload/route.ts | 244 +++++++++++++++++++++++++ src/app/api/tournaments/[id]/route.ts | 129 +++++++++++++ src/app/api/tournaments/route.ts | 68 +++++++ src/app/players/[id]/profile/page.tsx | 174 ++++++++++++++++++ src/app/players/[id]/schedule/page.tsx | 210 +++++++++++++++++++++ src/types/papaparse.d.ts | 29 +++ tsconfig.json | 1 + 12 files changed, 1409 insertions(+) create mode 100644 src/app/admin/tournaments/new/page.tsx create mode 100644 src/app/admin/tournaments/page.tsx create mode 100644 src/app/api/matches/route.ts create mode 100644 src/app/api/matches/upload/route.ts create mode 100644 src/app/api/tournaments/[id]/route.ts create mode 100644 src/app/api/tournaments/route.ts create mode 100644 src/app/players/[id]/profile/page.tsx create mode 100644 src/app/players/[id]/schedule/page.tsx create mode 100644 src/types/papaparse.d.ts diff --git a/package-lock.json b/package-lock.json index bdcabc2..5fe0532 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "bcryptjs": "^3.0.3", "next": "16.2.1", "next-auth": "^4.24.13", + "papaparse": "^5.5.3", "prisma": "^6.19.2", "react": "19.2.4", "react-dom": "19.2.4", @@ -5731,6 +5732,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/papaparse": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.5.3.tgz", + "integrity": "sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==", + "license": "MIT" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", diff --git a/package.json b/package.json index 9e1331f..090e8b3 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "bcryptjs": "^3.0.3", "next": "16.2.1", "next-auth": "^4.24.13", + "papaparse": "^5.5.3", "prisma": "^6.19.2", "react": "19.2.4", "react-dom": "19.2.4", diff --git a/src/app/admin/tournaments/new/page.tsx b/src/app/admin/tournaments/new/page.tsx new file mode 100644 index 0000000..012f46c --- /dev/null +++ b/src/app/admin/tournaments/new/page.tsx @@ -0,0 +1,178 @@ +"use client" + +import { useState } from "react" +import { useRouter } from "next/navigation" +import Navigation from "@/components/Navigation" +import { auth } from "@/lib/auth" + +export default function NewTournamentPage() { + const router = useRouter() + const [formData, setFormData] = useState({ + name: "", + description: "", + eventDate: "", + format: "round_robin", + maxParticipants: "", + }) + const [error, setError] = useState("") + const [isLoading, setIsLoading] = useState(false) + + const handleChange = (e: React.ChangeEvent) => { + setFormData({ + ...formData, + [e.target.name]: e.target.value, + }) + } + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + setError("") + setIsLoading(true) + + try { + const response = await fetch("/api/tournaments", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: formData.name, + description: formData.description, + eventDate: formData.eventDate || null, + format: formData.format, + maxParticipants: formData.maxParticipants ? parseInt(formData.maxParticipants) : null, + }), + }) + + const data = await response.json() + + if (!response.ok) { + throw new Error(data.error || "Failed to create tournament") + } + + router.push(`/admin/tournaments/${data.tournament.id}`) + } catch (err: any) { + setError(err.message) + } finally { + setIsLoading(false) + } + } + + return ( +
+ + +
+
+

+ Create New Tournament +

+ +
+ {error && ( +
+
{error}
+
+ )} + +
+ + +
+ +
+ +