diff --git a/app/db/types.ts b/app/db/types.ts
index f4213eaaf..61092d3be 100644
--- a/app/db/types.ts
+++ b/app/db/types.ts
@@ -253,6 +253,7 @@ export interface TournamentStage {
type: "round_robin" | "single_elimination" | "double_elimination";
settings: string; // json
number: number;
+ createdAt: number | null;
}
/** A group is a logical structure used to group multiple rounds together.
diff --git a/app/features/calendar/loaders/calendar.new.server.ts b/app/features/calendar/loaders/calendar.new.server.ts
index 84646cf9e..d893c4892 100644
--- a/app/features/calendar/loaders/calendar.new.server.ts
+++ b/app/features/calendar/loaders/calendar.new.server.ts
@@ -3,7 +3,7 @@ import { json, redirect } from "@remix-run/node";
import { requireUser } from "~/features/auth/core/user.server";
import * as BadgeRepository from "~/features/badges/BadgeRepository.server";
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
-import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server";
+import { tournamentData } from "~/features/tournament-bracket/core/Tournament.server";
import { i18next } from "~/modules/i18n/i18next.server";
import { canEditCalendarEvent } from "~/permissions";
import { validate } from "~/utils/remix";
@@ -35,17 +35,15 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
// special tags that are added automatically
const tags = event?.tags?.filter((tag) => tag !== "BADGE");
- if (!event?.tournamentId) return { ...event, tags, tournamentCtx: null };
+ if (!event?.tournamentId) return { ...event, tags, tournament: null };
return {
...event,
tags,
- tournamentCtx: (
- await tournamentFromDB({
- tournamentId: event.tournamentId,
- user,
- })
- ).ctx,
+ tournament: await tournamentData({
+ tournamentId: event.tournamentId,
+ user,
+ }),
};
};
@@ -56,11 +54,11 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
// no editing tournament after the start
if (
eventToEdit &&
- eventToEdit.tournamentCtx?.inProgressBrackets &&
- eventToEdit.tournamentCtx.inProgressBrackets.length > 0
+ eventToEdit.tournament?.data.stage &&
+ eventToEdit.tournament.data.stage.length > 0
) {
return redirect(
- tournamentBracketsPage({ tournamentId: eventToEdit.tournamentCtx.id }),
+ tournamentBracketsPage({ tournamentId: eventToEdit.tournament.ctx.id }),
);
}
diff --git a/app/features/calendar/routes/calendar.new.tsx b/app/features/calendar/routes/calendar.new.tsx
index 0aa3e5ebb..fe551bba0 100644
--- a/app/features/calendar/routes/calendar.new.tsx
+++ b/app/features/calendar/routes/calendar.new.tsx
@@ -279,7 +279,7 @@ function DescriptionTextarea({
function RulesTextarea({ supportsMarkdown }: { supportsMarkdown?: boolean }) {
const baseEvent = useBaseEvent();
const [value, setValue] = React.useState(
- baseEvent?.tournamentCtx?.rules ?? "",
+ baseEvent?.tournament?.ctx.rules ?? "",
);
return (
@@ -617,10 +617,10 @@ function AvatarImageInput({
if (
baseEvent?.avatarImgId &&
- baseEvent?.tournamentCtx?.logoUrl &&
+ baseEvent?.tournament?.ctx.logoUrl &&
showPrevious
) {
- const logoImgUrl = userSubmittedImage(baseEvent.tournamentCtx.logoUrl);
+ const logoImgUrl = userSubmittedImage(baseEvent.tournament.ctx.logoUrl);
return (
@@ -784,7 +784,7 @@ function TournamentLogoColorInputsWithShowcase({
function RankedToggle() {
const baseEvent = useBaseEvent();
const [isRanked, setIsRanked] = React.useState(
- baseEvent?.tournamentCtx?.settings.isRanked ?? true,
+ baseEvent?.tournament?.ctx.settings.isRanked ?? true,
);
const id = React.useId();
@@ -813,7 +813,7 @@ function RankedToggle() {
function EnableNoScreenToggle() {
const baseEvent = useBaseEvent();
const [enableNoScreen, setEnableNoScreen] = React.useState(
- baseEvent?.tournamentCtx?.settings.enableNoScreenToggle ?? true,
+ baseEvent?.tournament?.ctx.settings.enableNoScreenToggle ?? true,
);
const id = React.useId();
@@ -840,7 +840,7 @@ function EnableNoScreenToggle() {
function AutonomousSubsToggle() {
const baseEvent = useBaseEvent();
const [autonomousSubs, setAutonomousSubs] = React.useState(
- baseEvent?.tournamentCtx?.settings.autonomousSubs ?? true,
+ baseEvent?.tournament?.ctx.settings.autonomousSubs ?? true,
);
const id = React.useId();
@@ -867,7 +867,7 @@ function AutonomousSubsToggle() {
function RequireIGNToggle() {
const baseEvent = useBaseEvent();
const [requireIGNs, setRequireIGNs] = React.useState(
- baseEvent?.tournamentCtx?.settings.requireInGameNames ?? false,
+ baseEvent?.tournament?.ctx.settings.requireInGameNames ?? false,
);
const id = React.useId();
@@ -895,7 +895,7 @@ function RequireIGNToggle() {
function InvitationalToggle() {
const baseEvent = useBaseEvent();
const [isInvitational, setIsInvitational] = React.useState(
- baseEvent?.tournamentCtx?.settings.isInvitational ?? false,
+ baseEvent?.tournament?.ctx.settings.isInvitational ?? false,
);
const id = React.useId();
@@ -922,7 +922,7 @@ function InvitationalToggle() {
function StrictDeadlinesToggle() {
const baseEvent = useBaseEvent();
const [strictDeadlines, setStrictDeadlines] = React.useState(
- baseEvent?.tournamentCtx?.settings.deadlines === "STRICT" ? true : false,
+ baseEvent?.tournament?.ctx.settings.deadlines === "STRICT" ? true : false,
);
const id = React.useId();
@@ -949,11 +949,11 @@ function StrictDeadlinesToggle() {
function RegClosesAtSelect() {
const baseEvent = useBaseEvent();
const [regClosesAt, setRegClosesAt] = React.useState
(
- baseEvent?.tournamentCtx?.settings.regClosesAt
+ baseEvent?.tournament?.ctx.settings.regClosesAt
? datesToRegClosesAt({
- startTime: new Date(baseEvent.tournamentCtx.startTime),
+ startTime: new Date(baseEvent.tournament.ctx.startTime),
regClosesAt: databaseTimestampToDate(
- baseEvent.tournamentCtx.settings.regClosesAt,
+ baseEvent.tournament.ctx.settings.regClosesAt,
),
})
: "0",
@@ -1212,30 +1212,30 @@ function MapPoolValidationStatusMessage({
function TournamentFormatSelector() {
const baseEvent = useBaseEvent();
const [format, setFormat] = React.useState(
- baseEvent?.tournamentCtx?.settings.bracketProgression
+ baseEvent?.tournament?.ctx.settings.bracketProgression
? bracketProgressionToShortTournamentFormat(
- baseEvent.tournamentCtx.settings.bracketProgression,
+ baseEvent.tournament.ctx.settings.bracketProgression,
)
: "DE",
);
const [withUndergroundBracket, setWithUndergroundBracket] = React.useState(
- baseEvent?.tournamentCtx
- ? baseEvent.tournamentCtx.settings.bracketProgression.some(
+ baseEvent?.tournament
+ ? baseEvent.tournament.ctx.settings.bracketProgression.some(
(b) => b.name === BRACKET_NAMES.UNDERGROUND,
)
: false,
);
const [thirdPlaceMatch, setThirdPlaceMatch] = React.useState(
- baseEvent?.tournamentCtx?.settings.thirdPlaceMatch ?? true,
+ baseEvent?.tournament?.ctx.settings.thirdPlaceMatch ?? true,
);
const [teamsPerGroup, setTeamsPerGroup] = React.useState(
- baseEvent?.tournamentCtx?.settings.teamsPerGroup ?? 4,
+ baseEvent?.tournament?.ctx.settings.teamsPerGroup ?? 4,
);
const [swissGroupCount, setSwissGroupCount] = React.useState(
- baseEvent?.tournamentCtx?.settings.swiss?.groupCount ?? 1,
+ baseEvent?.tournament?.ctx.settings.swiss?.groupCount ?? 1,
);
const [swissRoundCount, setSwissRoundCount] = React.useState(
- baseEvent?.tournamentCtx?.settings.swiss?.roundCount ?? 5,
+ baseEvent?.tournament?.ctx.settings.swiss?.roundCount ?? 5,
);
return (
@@ -1377,17 +1377,17 @@ function FollowUpBrackets({
}) {
const baseEvent = useBaseEvent();
const [autoCheckInAll, setAutoCheckInAll] = React.useState(
- baseEvent?.tournamentCtx?.settings.autoCheckInAll ?? false,
+ baseEvent?.tournament?.ctx.settings.autoCheckInAll ?? false,
);
const [_brackets, setBrackets] = React.useState>(
() => {
if (
- baseEvent?.tournamentCtx &&
+ baseEvent?.tournament &&
["round_robin", "swiss"].includes(
- baseEvent.tournamentCtx.settings.bracketProgression[0].type,
+ baseEvent.tournament.ctx.settings.bracketProgression[0].type,
)
) {
- return baseEvent.tournamentCtx.settings.bracketProgression
+ return baseEvent.tournament.ctx.settings.bracketProgression
.slice(1)
.map((b) => ({
name: b.name,
diff --git a/app/features/tournament-bracket/core/Bracket.ts b/app/features/tournament-bracket/core/Bracket.ts
index c4d778e25..22fa5e19d 100644
--- a/app/features/tournament-bracket/core/Bracket.ts
+++ b/app/features/tournament-bracket/core/Bracket.ts
@@ -20,7 +20,7 @@ interface CreateBracketArgs {
name: string;
teamsPendingCheckIn?: number[];
tournament: Tournament;
- createdAt: number | null;
+ createdAt?: number | null;
sources?: {
bracketIdx: number;
placements: number[];
diff --git a/app/features/tournament-bracket/core/Tournament.server.ts b/app/features/tournament-bracket/core/Tournament.server.ts
index 41e0f4b15..8f29e2ef2 100644
--- a/app/features/tournament-bracket/core/Tournament.server.ts
+++ b/app/features/tournament-bracket/core/Tournament.server.ts
@@ -17,12 +17,13 @@ export async function tournamentData({
user?: { id: number };
tournamentId: number;
}) {
+ const data = manager.get.tournamentData(tournamentId);
const ctx = notFoundIfFalsy(
await TournamentRepository.findById(tournamentId),
);
const revealAllMapPools =
- ctx.inProgressBrackets.length > 0 ||
+ data.stage.length > 0 ||
ctx.author.id === user?.id ||
ctx.staff.some(
(staff) => staff.id === user?.id && staff.role === "ORGANIZER",
@@ -32,7 +33,7 @@ export async function tournamentData({
: HACKY_resolvePicture(ctx);
return {
- data: manager.get.tournamentData(tournamentId),
+ data,
ctx: {
...ctx,
logoSrc: logo,
diff --git a/app/features/tournament-bracket/core/Tournament.ts b/app/features/tournament-bracket/core/Tournament.ts
index e8c23234a..8e4fe33d5 100644
--- a/app/features/tournament-bracket/core/Tournament.ts
+++ b/app/features/tournament-bracket/core/Tournament.ts
@@ -32,7 +32,7 @@ export class Tournament {
ctx;
constructor({ data, ctx }: TournamentData) {
- const hasStarted = ctx.inProgressBrackets.length > 0;
+ const hasStarted = data.stage.length > 0;
const teamsInSeedOrder = ctx.teams.sort((a, b) => {
if (a.seed && b.seed) {
@@ -91,9 +91,7 @@ export class Tournament {
bracketIdx,
{ type, name, sources },
] of this.ctx.settings.bracketProgression.entries()) {
- const inProgressStage = this.ctx.inProgressBrackets.find(
- (stage) => stage.name === name,
- );
+ const inProgressStage = data.stage.find((stage) => stage.name === name);
if (inProgressStage) {
const match = data.match.filter(
diff --git a/app/features/tournament-bracket/core/brackets-manager/crud-db.server.ts b/app/features/tournament-bracket/core/brackets-manager/crud-db.server.ts
index 4dec32d0f..2cfe587a5 100644
--- a/app/features/tournament-bracket/core/brackets-manager/crud-db.server.ts
+++ b/app/features/tournament-bracket/core/brackets-manager/crud-db.server.ts
@@ -100,6 +100,7 @@ export class Stage {
settings: JSON.parse(rawStage.settings),
tournament_id: rawStage.tournamentId,
type: rawStage.type,
+ createdAt: rawStage.createdAt,
};
}
diff --git a/app/features/tournament-bracket/core/tests/test-utils.ts b/app/features/tournament-bracket/core/tests/test-utils.ts
index 42080b7dd..e67dece8d 100644
--- a/app/features/tournament-bracket/core/tests/test-utils.ts
+++ b/app/features/tournament-bracket/core/tests/test-utils.ts
@@ -68,12 +68,6 @@ export const testTournament = (
{ name: BRACKET_NAMES.MAIN, type: "double_elimination" },
],
},
- inProgressBrackets: data.stage.map((stage) => ({
- id: stage.id,
- name: stage.name,
- type: stage.type,
- createdAt: 0,
- })),
castedMatchesInfo: null,
teams: nTeams(participant.length, Math.min(...participant)),
author: {
diff --git a/app/features/tournament/TournamentRepository.server.ts b/app/features/tournament/TournamentRepository.server.ts
index a9790b223..d5d877e40 100644
--- a/app/features/tournament/TournamentRepository.server.ts
+++ b/app/features/tournament/TournamentRepository.server.ts
@@ -61,18 +61,6 @@ export async function findById(id: number) {
.where("TournamentResult.tournamentId", "=", id)
.select("TournamentResult.tournamentId"),
).as("isFinalized"),
- jsonArrayFrom(
- eb
- .selectFrom("TournamentStage")
- .select([
- "TournamentStage.id",
- "TournamentStage.name",
- "TournamentStage.type",
- "TournamentStage.createdAt",
- ])
- .where("TournamentStage.tournamentId", "=", id)
- .orderBy("TournamentStage.number asc"),
- ).as("inProgressBrackets"),
jsonArrayFrom(
eb
.selectFrom("TournamentTeam")
diff --git a/app/features/tournament/routes/to.$id.admin.tsx b/app/features/tournament/routes/to.$id.admin.tsx
index c7a1d445e..85a93a05f 100644
--- a/app/features/tournament/routes/to.$id.admin.tsx
+++ b/app/features/tournament/routes/to.$id.admin.tsx
@@ -106,10 +106,7 @@ export const action: ActionFunction = async ({ request, params }) => {
}
case "CHANGE_TEAM_NAME": {
validateIsTournamentOrganizer();
- validate(
- tournament.ctx.inProgressBrackets.length === 0,
- "Tournament started",
- );
+ validate(!tournament.hasStarted, "Tournament started");
const team = tournament.teamById(data.teamId);
validate(team, "Invalid team id");
diff --git a/app/features/tournament/routes/to.$id.register.tsx b/app/features/tournament/routes/to.$id.register.tsx
index bd1e23217..09d340045 100644
--- a/app/features/tournament/routes/to.$id.register.tsx
+++ b/app/features/tournament/routes/to.$id.register.tsx
@@ -91,7 +91,7 @@ export const action: ActionFunction = async ({ request, params }) => {
const event = notFoundIfFalsy(findByIdentifier(tournamentId));
validate(
- tournament.ctx.inProgressBrackets.length === 0,
+ !tournament.hasStarted,
"Tournament has started, cannot make edits to registration",
);
diff --git a/app/features/tournament/routes/to.$id.tsx b/app/features/tournament/routes/to.$id.tsx
index d41efe328..8ac6fc9ba 100644
--- a/app/features/tournament/routes/to.$id.tsx
+++ b/app/features/tournament/routes/to.$id.tsx
@@ -142,7 +142,7 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => {
const tournament = await tournamentData({ tournamentId, user });
const streams =
- tournament.ctx.inProgressBrackets.length > 0
+ tournament.data.stage.length > 0
? await streamsByTournamentId({
tournamentId,
castTwitchAccounts: tournament.ctx.castTwitchAccounts,
diff --git a/app/modules/brackets-model/storage.ts b/app/modules/brackets-model/storage.ts
index 0bd7b9ab8..cfc115f61 100644
--- a/app/modules/brackets-model/storage.ts
+++ b/app/modules/brackets-model/storage.ts
@@ -32,6 +32,8 @@ export interface Stage {
/** The number of the stage in its tournament. */
number: number;
+
+ createdAt?: number | null;
}
/**