From 097ff77c8acc4ff538172b8409eafbbebf15a480 Mon Sep 17 00:00:00 2001 From: voidarc Date: Tue, 7 Jul 2026 20:55:18 +0100 Subject: [PATCH] added inserting players --- src/routes/api/registeredPlayers/+server.ts | 56 ++++++++- src/routes/registrations/+page.server.ts | 12 +- src/routes/registrations/+page.svelte | 129 ++++++++++++++++++++ 3 files changed, 190 insertions(+), 7 deletions(-) diff --git a/src/routes/api/registeredPlayers/+server.ts b/src/routes/api/registeredPlayers/+server.ts index 7c1ab6e..843c2f8 100644 --- a/src/routes/api/registeredPlayers/+server.ts +++ b/src/routes/api/registeredPlayers/+server.ts @@ -1,7 +1,55 @@ -import { getAllRegisteredEventPlayers } from '$lib/server/databaseManager'; +import { error, json } from '@sveltejs/kit'; +import { eq, and } from 'drizzle-orm'; +import { db } from '$lib/server/db'; +import { registeredPlayers, registeredEvents, scorers } from '$lib/server/db/schema'; import { globalEmitter } from '$lib/server/globalEmitter'; -import { generateEndpoint } from '$lib/server/endpoint'; -export async function POST({ request }: any) { - return new Response('ok'); +export async function POST({ request, locals }: any) { + if (!locals.user) throw error(401, 'Unauthorized'); + const [row] = await db.select({ role: scorers.role }).from(scorers).where(eq(scorers.id, locals.user.id)); + if (row?.role !== 'admin') throw error(403, 'Forbidden'); + + const body = await request.json(); + const { eventId, playerId, bracketId } = body; + + if (typeof eventId !== 'number' || typeof playerId !== 'number' || typeof bracketId !== 'number') { + throw error(400, 'eventId, playerId, and bracketId are required'); + } + + const event = await db + .select({ state: registeredEvents.state }) + .from(registeredEvents) + .where(eq(registeredEvents.id, eventId)) + .get(); + + if (!event) throw error(404, 'Event not found'); + if (event.state !== 0) throw error(403, 'Cannot register players for events that are ongoing or finished'); + + const existing = await db + .select({ id: registeredPlayers.id }) + .from(registeredPlayers) + .where( + and( + eq(registeredPlayers.playerID, playerId), + eq(registeredPlayers.registeredEventID, eventId) + ) + ) + .get(); + + if (existing) { + throw error(409, 'Player is already registered for this event'); + } + + const [inserted] = await db + .insert(registeredPlayers) + .values({ + playerID: playerId, + registeredEventID: eventId, + bracket: bracketId + }) + .returning({ id: registeredPlayers.id }); + + globalEmitter.emit('eventUpdate'); + + return json({ id: inserted.id }); } diff --git a/src/routes/registrations/+page.server.ts b/src/routes/registrations/+page.server.ts index 7df2c33..1538588 100644 --- a/src/routes/registrations/+page.server.ts +++ b/src/routes/registrations/+page.server.ts @@ -67,18 +67,23 @@ export const load: PageServerLoad = async ({ locals }) => { .innerJoin(players, eq(registeredPlayers.playerID, players.id)) .innerJoin(teams, eq(players.team, teams.id)) .innerJoin(divisions, eq(registeredEvents.division, divisions.id)) - .orderBy(registeredPlayers.id); + .orderBy(teams.name, registeredEvents.id, brackets.name); const allPlayers = await db .select({ id: players.id, firstName: players.firstName, lastName: players.lastName, - teamId: players.team + teamId: players.team, + teamName: teams.name, + teamColor: teams.color }) .from(players) + .innerJoin(teams, eq(players.team, teams.id)) .orderBy(players.firstName); + const bracketsList = await db.select().from(brackets).orderBy(brackets.id); + return { events: events.map((e) => ({ id: e.id, name: e.name, division: e.division, state: e.state })), registrations: registrations.map((r) => ({ @@ -99,6 +104,7 @@ export const load: PageServerLoad = async ({ locals }) => { points: r.points, stateLabel: r.state === 0 ? 'Not started' : r.state === 1 ? 'Ongoing' : 'Finished' })), - allPlayers + allPlayers, + brackets: bracketsList }; }; diff --git a/src/routes/registrations/+page.svelte b/src/routes/registrations/+page.svelte index 1fa4a73..ff14183 100644 --- a/src/routes/registrations/+page.svelte +++ b/src/routes/registrations/+page.svelte @@ -6,12 +6,20 @@ type Registration = (typeof data.registrations)[number]; type PlayerInfo = (typeof data.allPlayers)[number]; + type Bracket = (typeof data.brackets)[number]; let selectedEventId = $state(''); let searchQuery = $state(''); let editingId = $state(null); let editPlayerId = $state(0); + let showNewForm = $state(false); + let newEventId = $state(0); + let newBracketId = $state(0); + let newPlayerId = $state(0); + + let pendingEvents = $derived(data.events.filter((e) => e.state === 0)); + let filteredRegistrations = $derived( data.registrations.filter((r) => { if (selectedEventId !== '' && r.eventId !== selectedEventId) return false; @@ -63,6 +71,52 @@ if (idx !== -1) data.registrations.splice(idx, 1); } + function resetNewForm() { + showNewForm = false; + newEventId = 0; + newBracketId = 0; + newPlayerId = 0; + } + + async function submitNew() { + if (!newEventId || !newBracketId || !newPlayerId) return; + const res = await fetch('/api/registeredPlayers', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ eventId: newEventId, playerId: newPlayerId, bracketId: newBracketId }) + }); + if (!res.ok) { + const err = await res.json(); + alert(err.message || 'Failed to create registration'); + return; + } + const result = await res.json(); + const selectedPlayer = data.allPlayers.find((p) => p.id === newPlayerId); + const selectedEvent = data.events.find((e) => e.id === newEventId); + const selectedBracket = data.brackets.find((b) => b.id === newBracketId); + if (!selectedPlayer || !selectedEvent || !selectedBracket) return; + const newReg: Registration = { + id: result.id, + registeredPlayerId: result.id, + playerId: newPlayerId, + firstName: selectedPlayer.firstName, + lastName: selectedPlayer.lastName, + placement: 0, + bracket: selectedBracket.name, + eventId: newEventId, + eventName: selectedEvent.name, + teamId: selectedPlayer.teamId, + teamName: selectedPlayer.teamName, + teamColor: selectedPlayer.teamColor, + state: 0, + division: selectedEvent.division, + points: 0, + stateLabel: 'Not started' + }; + data.registrations.unshift(newReg); + resetNewForm(); + } + function stateColor(state: number): string { if (state === 0) return 'var(--ctp-mocha-yellow)'; if (state === 1) return 'var(--ctp-mocha-green)'; @@ -103,8 +157,51 @@ > Registrations {filteredRegistrations.length} entries + + {#if showNewForm} +
+
New Registration
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ {/if} + {#snippet header()} @@ -174,6 +271,37 @@ color: var(--ctp-mocha-red, #f38ba8); } + .action-btn.new-btn { + border-color: var(--ctp-mocha-green, #a6e3a1); + color: var(--ctp-mocha-green, #a6e3a1); + font-size: 0.85rem; + padding: 0.25rem 0.75rem; + } + + .action-btn.submit-btn { + border-color: var(--ctp-mocha-blue, #89b4fa); + color: var(--ctp-mocha-blue, #89b4fa); + padding: 0.3rem 0.75rem; + font-size: 0.85rem; + } + + .action-btn.submit-btn:disabled { + opacity: 0.4; + cursor: not-allowed; + } + + .new-form-card { + margin-bottom: 1rem; + padding: 0.75rem 1rem; + } + + .new-form-title { + font-size: 0.85rem; + font-weight: 600; + margin-bottom: 0.5rem; + opacity: 0.8; + } + td select { padding: 0.15rem 0.25rem; font-size: 0.75rem; @@ -184,3 +312,4 @@ max-width: 140px; } +
RP ID