ready for regionals
CI/CD Pipeline / Build and Push App Docker Image (push) Successful in 2m46s
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Successful in 8s
CI/CD Pipeline / Deploy to Kubernetes (push) Successful in 44s

This commit is contained in:
yohlo
2026-03-07 01:22:21 -06:00
parent 569ea8833b
commit e67f6b073c
9 changed files with 353 additions and 95 deletions
+58 -5
View File
@@ -6,7 +6,6 @@ import { logger } from ".";
import { z } from "zod";
import { toServerResult } from "@/lib/tanstack-query/utils/to-server-result";
import { serverFnLoggingMiddleware } from "@/utils/activities";
import { fa } from "zod/v4/locales";
import brackets from "@/features/bracket/utils";
import { MatchInput } from "@/features/matches/types";
import { generateSingleEliminationBracket } from "./utils/bracket-generator";
@@ -540,10 +539,18 @@ export const generateKnockoutBracket = createServerFn()
}
const qualifiedTeams: { teamId: string; groupOrder: number; rank: number }[] = [];
const allStandings: { standing: GroupStanding; groupOrder: number }[] = [];
for (const group of groups) {
const standings = await calculateGroupStandings(group.id);
for (let i = 0; i < standings.length; i++) {
allStandings.push({
standing: standings[i],
groupOrder: group.order,
});
}
const topTeams = standings.slice(0, tournament.group_config.advance_per_group);
for (const standing of topTeams) {
qualifiedTeams.push({
@@ -582,7 +589,42 @@ export const generateKnockoutBracket = createServerFn()
if (team2) orderedTeamIds.push(team2);
}
const teamCount = orderedTeamIds.length;
let teamCount = orderedTeamIds.length;
const nextPowerOf2 = Math.pow(2, Math.ceil(Math.log2(teamCount)));
const wildcardsNeeded = nextPowerOf2 - teamCount;
if (wildcardsNeeded > 0) {
const qualifiedTeamIds = new Set(qualifiedTeams.map(t => t.teamId));
const wildcardCandidates = allStandings
.filter(s => !qualifiedTeamIds.has(s.standing.team.id))
.map(s => s.standing);
wildcardCandidates.sort((a, b) => {
if (b.wins !== a.wins) return b.wins - a.wins;
if (b.cup_differential !== a.cup_differential) return b.cup_differential - a.cup_differential;
if (b.cups_for !== a.cups_for) return b.cups_for - a.cups_for;
return a.team.id.localeCompare(b.team.id);
});
const wildcardTeams = wildcardCandidates.slice(0, wildcardsNeeded);
const wildcardTeamIds = wildcardTeams.map(t => t.team.id);
orderedTeamIds.push(...wildcardTeamIds);
teamCount = orderedTeamIds.length;
logger.info('Added wildcard teams to knockout bracket', {
tournamentId: data.tournamentId,
wildcardsNeeded,
wildcardTeams: wildcardTeams.map(t => ({
id: t.team.id,
name: t.team.name,
wins: t.wins,
cupDiff: t.cup_differential,
cupsFor: t.cups_for
}))
});
}
let bracketTemplate: any;
if (Object.keys(brackets).includes(teamCount.toString())) {
@@ -774,14 +816,25 @@ export const generateGroupStage = createServerFn()
}
const knockoutTeamCount = data.groupConfig.num_groups * data.groupConfig.advance_per_group;
const nextPowerOf2 = Math.pow(2, Math.ceil(Math.log2(knockoutTeamCount)));
const bracketSize = nextPowerOf2;
let bracketTemplate: any;
if (Object.keys(brackets).includes(knockoutTeamCount.toString())) {
bracketTemplate = brackets[knockoutTeamCount as keyof typeof brackets];
if (Object.keys(brackets).includes(bracketSize.toString())) {
bracketTemplate = brackets[bracketSize as keyof typeof brackets];
} else {
bracketTemplate = generateSingleEliminationBracket(knockoutTeamCount);
bracketTemplate = generateSingleEliminationBracket(bracketSize);
}
logger.info('Creating knockout bracket template', {
tournamentId: data.tournamentId,
knockoutTeamCount,
bracketSize,
wildcardsNeeded: bracketSize - knockoutTeamCount
});
const knockoutMatches: any[] = [];
bracketTemplate.winners.forEach((round: any[]) => {