reset match logic

This commit is contained in:
yohlo
2025-09-11 16:13:45 -05:00
parent 97c8c9e72b
commit 51e3d5141c
2 changed files with 72 additions and 42 deletions

View File

@@ -17,15 +17,18 @@ export const generateTournamentBracket = createServerFn()
.middleware([superTokensAdminFunctionMiddleware]) .middleware([superTokensAdminFunctionMiddleware])
.handler(async ({ data: { tournamentId, orderedTeamIds } }) => .handler(async ({ data: { tournamentId, orderedTeamIds } }) =>
toServerResult(async () => { toServerResult(async () => {
logger.info('Generating tournament bracket', { tournamentId, teamCount: orderedTeamIds.length }); logger.info("Generating tournament bracket", {
tournamentId,
teamCount: orderedTeamIds.length,
});
const tournament = await pbAdmin.getTournament(tournamentId); const tournament = await pbAdmin.getTournament(tournamentId);
if (!tournament) { if (!tournament) {
throw new Error('Tournament not found'); throw new Error("Tournament not found");
} }
if (tournament.matches && tournament.matches.length > 0) { if (tournament.matches && tournament.matches.length > 0) {
throw new Error('Tournament already has matches generated'); throw new Error("Tournament already has matches generated");
} }
const teamCount = orderedTeamIds.length; const teamCount = orderedTeamIds.length;
@@ -33,13 +36,15 @@ export const generateTournamentBracket = createServerFn()
throw new Error(`Bracket not available for ${teamCount} teams`); throw new Error(`Bracket not available for ${teamCount} teams`);
} }
const bracketTemplate = brackets[teamCount as keyof typeof brackets] as any; const bracketTemplate = brackets[
teamCount as keyof typeof brackets
] as any;
const seedToTeamId = new Map<number, string>(); const seedToTeamId = new Map<number, string>();
orderedTeamIds.forEach((teamId, index) => { orderedTeamIds.forEach((teamId, index) => {
seedToTeamId.set(index + 1, teamId); seedToTeamId.set(index + 1, teamId);
}); });
const matchInputs: MatchInput[] = []; const matchInputs: MatchInput[] = [];
bracketTemplate.winners.forEach((round: any[]) => { bracketTemplate.winners.forEach((round: any[]) => {
@@ -79,7 +84,7 @@ export const generateTournamentBracket = createServerFn()
} }
if (matchInput.home && matchInput.away) { if (matchInput.home && matchInput.away) {
matchInput.status = "ready" matchInput.status = "ready";
} }
matchInputs.push(matchInput); matchInputs.push(matchInput);
@@ -111,13 +116,13 @@ export const generateTournamentBracket = createServerFn()
}); });
const createdMatches = await pbAdmin.createMatches(matchInputs); const createdMatches = await pbAdmin.createMatches(matchInputs);
const matchIds = createdMatches.map(match => match.id); const matchIds = createdMatches.map((match) => match.id);
await pbAdmin.updateTournamentMatches(tournamentId, matchIds); await pbAdmin.updateTournamentMatches(tournamentId, matchIds);
logger.info('Tournament bracket generated', { logger.info("Tournament bracket generated", {
tournamentId, tournamentId,
matchCount: createdMatches.length matchCount: createdMatches.length,
}); });
return { return {
@@ -133,38 +138,38 @@ export const startMatch = createServerFn()
.middleware([superTokensAdminFunctionMiddleware]) .middleware([superTokensAdminFunctionMiddleware])
.handler(async ({ data }) => .handler(async ({ data }) =>
toServerResult(async () => { toServerResult(async () => {
logger.info('Starting match', data); logger.info("Starting match", data);
let match = await pbAdmin.getMatch(data); let match = await pbAdmin.getMatch(data);
if (!match) { if (!match) {
throw new Error('Match not found'); throw new Error("Match not found");
} }
match = await pbAdmin.updateMatch(data, { match = await pbAdmin.updateMatch(data, {
start_time: new Date().toISOString(), start_time: new Date().toISOString(),
status: "started" status: "started",
}); });
return match; return match;
} })
)); );
const endMatchSchema = z.object({ const endMatchSchema = z.object({
matchId: z.string(), matchId: z.string(),
home_cups: z.number(), home_cups: z.number(),
away_cups: z.number(), away_cups: z.number(),
ot_count: z.number() ot_count: z.number(),
}); });
export const endMatch = createServerFn() export const endMatch = createServerFn()
.validator(endMatchSchema) .validator(endMatchSchema)
.middleware([superTokensAdminFunctionMiddleware]) .middleware([superTokensAdminFunctionMiddleware])
.handler(async ({ data: { matchId, home_cups, away_cups, ot_count } }) => .handler(async ({ data: { matchId, home_cups, away_cups, ot_count } }) =>
toServerResult(async () => { toServerResult(async () => {
logger.info('Ending match', matchId); logger.info("Ending match", matchId);
let match = await pbAdmin.getMatch(matchId); let match = await pbAdmin.getMatch(matchId);
if (!match) { if (!match) {
throw new Error('Match not found'); throw new Error("Match not found");
} }
match = await pbAdmin.updateMatch(matchId, { match = await pbAdmin.updateMatch(matchId, {
@@ -172,38 +177,58 @@ export const endMatch = createServerFn()
status: "ended", status: "ended",
home_cups, home_cups,
away_cups, away_cups,
ot_count ot_count,
}) });
const matchWinner = home_cups > away_cups ? match.home : match.away; const matchWinner = home_cups > away_cups ? match.home : match.away;
const matchLoser = home_cups < away_cups ? match.home : match.away; const matchLoser = home_cups < away_cups ? match.home : match.away;
if (!matchWinner || !matchLoser) throw new Error("Something went wrong") if (!matchWinner || !matchLoser) throw new Error("Something went wrong");
// winner -> where to send match winner to, loser same // winner -> where to send match winner to, loser same
const { winner, loser } = await pbAdmin.getChildMatches(matchId) const { winner, loser } = await pbAdmin.getChildMatches(matchId);
// reset match check
if (winner && winner.reset) {
const awayTeamWon = match.away === matchWinner;
if (!awayTeamWon) {
// Reset match is not necessary
logger.info("Deleting reset match", {
resetMatchId: winner.id,
currentMatchId: match.id,
reason: "not necessary",
});
await pbAdmin.deleteMatch(winner.id);
return match;
}
}
// advance bracket
if (winner) { if (winner) {
await pbAdmin.updateMatch(winner.id, { await pbAdmin.updateMatch(winner.id, {
[winner.home_from_lid === match.lid ? "home" : "away"]: matchWinner, [winner.home_from_lid === match.lid ? "home" : "away"]: matchWinner,
status: status:
((winner.home_from_lid === match.lid) && winner.away) (winner.home_from_lid === match.lid && winner.away) ||
|| ((winner.away_from_lid === match.lid) && winner.home) (winner.away_from_lid === match.lid && winner.home)
? 'ready' : 'tbd' ? "ready"
}) : "tbd",
});
} }
if (loser) { if (loser) {
await pbAdmin.updateMatch(loser.id, { await pbAdmin.updateMatch(loser.id, {
[loser.home_from_lid === match.lid ? "home" : "away"]: matchLoser, [loser.home_from_lid === match.lid ? "home" : "away"]: matchLoser,
status: status:
((loser.home_from_lid === match.lid) && loser.away) (loser.home_from_lid === match.lid && loser.away) ||
|| ((loser.away_from_lid === match.lid) && loser.home) (loser.away_from_lid === match.lid && loser.home)
? 'ready' : 'tbd' ? "ready"
}) : "tbd",
});
} }
// TODO: send SSE // TODO: send SSE
return match; return match;
} })
)); );

View File

@@ -55,6 +55,11 @@ export function createMatchesService(pb: PocketBase) {
return result; return result;
}, },
async deleteMatch(id: string): Promise<void> {
logger.info("PocketBase | Deleting match", id);
await pb.collection("matches").delete(id);
},
async deleteMatchesByTournament(tournamentId: string): Promise<void> { async deleteMatchesByTournament(tournamentId: string): Promise<void> {
logger.info("PocketBase | Deleting matches for tournament", tournamentId); logger.info("PocketBase | Deleting matches for tournament", tournamentId);
const matches = await pb.collection("matches").getFullList({ const matches = await pb.collection("matches").getFullList({