From e086d7398a54b56fc9d18d617918336065662400 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Fri, 3 Apr 2026 19:27:31 -0700 Subject: [PATCH] feat: add tournament type and team support to tournament APIs Update tournament APIs to support: - tournamentType field (individual/team) - Team creation for team tournaments - Even number validation for team tournaments - Automatic pairing of consecutive players into teams --- .../tournaments/[id]/participants/route.ts | 101 +++++++++++++++++- src/app/api/tournaments/[id]/route.ts | 2 + src/app/api/tournaments/route.ts | 7 +- 3 files changed, 107 insertions(+), 3 deletions(-) diff --git a/src/app/api/tournaments/[id]/participants/route.ts b/src/app/api/tournaments/[id]/participants/route.ts index daa261e..654c751 100644 --- a/src/app/api/tournaments/[id]/participants/route.ts +++ b/src/app/api/tournaments/[id]/participants/route.ts @@ -36,7 +36,106 @@ export async function POST( ); } - // Add participants to tournament + // Fetch tournament to check type + const tournament = await prisma.event.findUnique({ + where: { id: tournamentId }, + select: { tournamentType: true }, + }); + + if (!tournament) { + return NextResponse.json( + { error: "Tournament not found" }, + { status: 404 } + ); + } + + const isTeamTournament = tournament.tournamentType === "team"; + + // For team tournaments, pair players into teams + if (isTeamTournament) { + if (playerIds.length % 2 !== 0) { + return NextResponse.json( + { error: "Team tournaments require an even number of players" }, + { status: 400 } + ); + } + + // Create teams from consecutive pairs + const teams = []; + for (let i = 0; i < playerIds.length; i += 2) { + const player1Id = playerIds[i]; + const player2Id = playerIds[i + 1]; + + // Check if team already exists + const existingTeam = await prisma.team.findFirst({ + where: { + eventId: tournamentId, + OR: [ + { AND: [{ player1Id }, { player2Id }] }, + { AND: [{ player1Id: player2Id }, { player2Id: player1Id }] }, + ], + }, + }); + + let team; + if (existingTeam) { + team = existingTeam; + } else { + team = await prisma.team.create({ + data: { + eventId: tournamentId, + player1Id, + player2Id, + }, + }); + } + + // Create participants linked to this team + const participant1 = await prisma.eventParticipant.upsert({ + where: { + eventId_playerId: { + eventId: tournamentId, + playerId: player1Id, + }, + }, + update: { teamId: team.id }, + create: { + eventId: tournamentId, + playerId: player1Id, + teamId: team.id, + status: "registered", + registrationDate: new Date(), + }, + }); + + const participant2 = await prisma.eventParticipant.upsert({ + where: { + eventId_playerId: { + eventId: tournamentId, + playerId: player2Id, + }, + }, + update: { teamId: team.id }, + create: { + eventId: tournamentId, + playerId: player2Id, + teamId: team.id, + status: "registered", + registrationDate: new Date(), + }, + }); + + teams.push({ team, participants: [participant1, participant2] }); + } + + return NextResponse.json({ + success: true, + teamsCreated: teams.length, + teams, + }); + } + + // Individual tournament - just add participants const participants = await Promise.all( playerIds.map(async (playerId: number) => { try { diff --git a/src/app/api/tournaments/[id]/route.ts b/src/app/api/tournaments/[id]/route.ts index cc05214..287d86f 100644 --- a/src/app/api/tournaments/[id]/route.ts +++ b/src/app/api/tournaments/[id]/route.ts @@ -144,6 +144,7 @@ export async function PUT(request: Request, { params }: RouteParams) { description, eventDate, eventType, + tournamentType, format, status, maxParticipants, @@ -166,6 +167,7 @@ export async function PUT(request: Request, { params }: RouteParams) { description: description || null, eventDate: eventDate ? new Date(eventDate) : null, eventType: eventType || "tournament", + tournamentType: tournamentType || "individual", format: format || "round_robin", maxParticipants: maxParticipants ? parseInt(maxParticipants) : null, targetScore: targetScore ? parseInt(targetScore) : null, diff --git a/src/app/api/tournaments/route.ts b/src/app/api/tournaments/route.ts index 514da70..904adf0 100644 --- a/src/app/api/tournaments/route.ts +++ b/src/app/api/tournaments/route.ts @@ -69,7 +69,7 @@ export async function POST(request: Request) { } const body = await request.json(); - const { name, format, eventDate, targetScore, allowTies } = body; + const { name, format, eventDate, targetScore, allowTies, maxParticipants, tournamentType } = body; const tournament = await prisma.event.create({ data: { @@ -77,10 +77,13 @@ export async function POST(request: Request) { format: format || "round_robin", eventDate: eventDate ? new Date(eventDate) : null, eventType: "tournament", + tournamentType: tournamentType || "individual", status: "planned", - ownerId: session.user.id, // Assign ownership to the creator + ownerId: session.user.id, targetScore: targetScore ? parseInt(targetScore) : null, allowTies: allowTies ?? false, + maxParticipants: maxParticipants ? parseInt(maxParticipants) : null, + description: body.description, }, });