diff --git a/app/features/tournament-bracket/core/Tournament.ts b/app/features/tournament-bracket/core/Tournament.ts
index bc7330a69..b819dd12e 100644
--- a/app/features/tournament-bracket/core/Tournament.ts
+++ b/app/features/tournament-bracket/core/Tournament.ts
@@ -15,7 +15,7 @@ import {
} from "~/features/tournament/tournament-utils";
import type * as Progression from "~/features/tournament-bracket/core/Progression";
import type { TournamentManagerDataSet } from "~/modules/brackets-manager/types";
-import type { Match, Stage } from "~/modules/brackets-model";
+import { type Match, type Stage, Status } from "~/modules/brackets-model";
import type { ModeShort } from "~/modules/in-game-lists/types";
import { isAdmin } from "~/modules/permissions/utils";
import {
@@ -798,6 +798,11 @@ export class Tournament {
// match didn't start yet
if (!match.opponent1 || !match.opponent2) return false;
+ // waiting for teams to finish their previous matches
+ if (match.status === Status.Locked || match.status === Status.Waiting) {
+ return false;
+ }
+
const matchIsOver =
match.opponent1.result === "win" || match.opponent2.result === "win";
diff --git a/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts b/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts
index fbc9ad550..3981cc8dc 100644
--- a/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts
+++ b/app/features/tournament-match/actions/to.$id.matches.$mid.server.ts
@@ -77,6 +77,12 @@ export const action: ActionFunction = async ({ params, request }) => {
(p) => p.id === user?.id,
);
+ errorToastIfFalsy(
+ match.status !== TournamentMatchStatus.Locked &&
+ match.status !== TournamentMatchStatus.Waiting,
+ "Match is locked, waiting for teams to finish their previous matches",
+ );
+
errorToastIfFalsy(
canReportTournamentScore({
match,
diff --git a/app/features/tournament-match/components/TournamentMatchBanner.tsx b/app/features/tournament-match/components/TournamentMatchBanner.tsx
index a25400dbd..91c757ce4 100644
--- a/app/features/tournament-match/components/TournamentMatchBanner.tsx
+++ b/app/features/tournament-match/components/TournamentMatchBanner.tsx
@@ -55,6 +55,7 @@ export function TournamentMatchBanner({
currentMap,
teamsMissingActiveRoster,
matchIsLocked,
+ waitingForPreviousMatch,
joinPool,
joinPass,
teams,
@@ -156,6 +157,16 @@ export function TournamentMatchBanner({
header={t("tournament:match.waitingForTeams.header")}
subtitle={t("tournament:match.waitingForTeams.subtitle")}
/>
+ ) : waitingForPreviousMatch ? (
+ }
+ header={t("tournament:match.waitingForPrevious.header")}
+ subtitle={t("tournament:match.waitingForPrevious.subtitle")}
+ screenLegal={screenLegal}
+ joinPool={joinPool}
+ joinPass={joinPass}
+ host={host}
+ />
) : teamsMissingActiveRoster.length > 0 ? (
}
diff --git a/app/features/tournament-match/match-page-context.tsx b/app/features/tournament-match/match-page-context.tsx
index 72e5c586e..427557fd4 100644
--- a/app/features/tournament-match/match-page-context.tsx
+++ b/app/features/tournament-match/match-page-context.tsx
@@ -1,6 +1,7 @@
import * as React from "react";
import { TAB_KEYS } from "~/components/match-page/MatchTabs";
import { resolveRoomPass } from "~/components/match-page/utils";
+import { TournamentMatchStatus } from "~/db/tables";
import { useUser } from "~/features/auth/core/user";
import { useTournament } from "~/features/tournament/routes/to.$id";
import { isLeagueRoundLocked } from "~/features/tournament/tournament-utils";
@@ -32,6 +33,7 @@ type MatchPageContextValue = {
turnOfResult: ReturnType;
isPickBanStep: boolean;
matchIsLocked: boolean;
+ waitingForPreviousMatch: boolean;
joinPool: string | null;
joinPass: string | null;
};
@@ -99,6 +101,10 @@ export function MatchPageProvider({
scores,
});
+ const waitingForPreviousMatch =
+ data.match.status === TournamentMatchStatus.Locked ||
+ data.match.status === TournamentMatchStatus.Waiting;
+
const joinInfo = resolveJoinInfo({ tournament, data, teams });
const tabs = resolveVisibleTabs({
@@ -117,6 +123,7 @@ export function MatchPageProvider({
tournament.isOrganizerOrStreamer(user) && !tournament.ctx.isFinalized,
leagueRoundLocked: isLeagueRoundLocked(tournament, data.match.roundId),
lockedForCast,
+ waitingForPreviousMatch,
});
return (
@@ -132,6 +139,7 @@ export function MatchPageProvider({
turnOfResult,
isPickBanStep,
matchIsLocked: lockedForCast,
+ waitingForPreviousMatch,
joinPool: joinInfo?.pool ?? null,
joinPass: joinInfo?.pass ?? null,
}}
@@ -160,6 +168,7 @@ function resolveVisibleTabs({
isAdminEligible,
leagueRoundLocked,
lockedForCast,
+ waitingForPreviousMatch,
}: {
canReportScore: boolean;
canReportWeapons: boolean;
@@ -171,11 +180,13 @@ function resolveVisibleTabs({
isAdminEligible: boolean;
leagueRoundLocked: boolean;
lockedForCast: boolean;
+ waitingForPreviousMatch: boolean;
}): MatchTabKey[] {
const tabs: MatchTabKey[] = [TAB_KEYS.ROSTERS];
if (
!leagueRoundLocked &&
+ !waitingForPreviousMatch &&
(isPickBanStep ||
(canReportScore &&
hasCurrentMap &&
diff --git a/app/features/tournament-match/routes/to.$id.matches.$mid.test.ts b/app/features/tournament-match/routes/to.$id.matches.$mid.test.ts
index 399275df3..503f3dfd7 100644
--- a/app/features/tournament-match/routes/to.$id.matches.$mid.test.ts
+++ b/app/features/tournament-match/routes/to.$id.matches.$mid.test.ts
@@ -246,6 +246,21 @@ describe("Tournament match page", () => {
});
});
+ describe("locked match", () => {
+ it("should return error when reporting score for a match waiting on previous matches", async () => {
+ await setActiveRosterAction();
+ await db
+ .updateTable("TournamentMatch")
+ .set({ status: 0 })
+ .where("id", "=", 1)
+ .execute();
+
+ const res = await reportScoreAction({ position: 0 });
+
+ assertResponseErrored(res, "Match is locked");
+ });
+ });
+
describe("BYE matches", () => {
it("should 404 when accessing a BYE match", async () => {
await db
diff --git a/locales/da/tournament.json b/locales/da/tournament.json
index fe88e8fe8..b338abba1 100644
--- a/locales/da/tournament.json
+++ b/locales/da/tournament.json
@@ -171,6 +171,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Annuller sidste score",
"match.action.reopenMatch": "Genåbn kamp",
diff --git a/locales/de/tournament.json b/locales/de/tournament.json
index e45efa7a4..960756aa7 100644
--- a/locales/de/tournament.json
+++ b/locales/de/tournament.json
@@ -171,6 +171,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Letztes Ergebnis widerrufen",
"match.action.reopenMatch": "Match erneut öffnen",
diff --git a/locales/en/tournament.json b/locales/en/tournament.json
index e61902699..46d2622b5 100644
--- a/locales/en/tournament.json
+++ b/locales/en/tournament.json
@@ -171,6 +171,8 @@
"match.locked.subtitle": "Please wait for staff to unlock",
"match.waitingForTeams.header": "Waiting for teams",
"match.waitingForTeams.subtitle": "Teams will be resolved from earlier matches",
+ "match.waitingForPrevious.header": "Previous match ongoing",
+ "match.waitingForPrevious.subtitle": "Match will be reportable when both teams are ready to play",
"match.tbd": "TBD",
"match.action.undoLastScore": "Undo last score",
"match.action.reopenMatch": "Reopen match",
diff --git a/locales/es-ES/tournament.json b/locales/es-ES/tournament.json
index f4c6e30bb..de3f5da55 100644
--- a/locales/es-ES/tournament.json
+++ b/locales/es-ES/tournament.json
@@ -173,6 +173,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Anular resultado previo",
"match.action.reopenMatch": "Reabrir partido",
diff --git a/locales/es-US/tournament.json b/locales/es-US/tournament.json
index 1954fa13a..e3089b74f 100644
--- a/locales/es-US/tournament.json
+++ b/locales/es-US/tournament.json
@@ -173,6 +173,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Anular resultado previo",
"match.action.reopenMatch": "Reabrir partido",
diff --git a/locales/fr-CA/tournament.json b/locales/fr-CA/tournament.json
index 16e9b27a9..59739fe0d 100644
--- a/locales/fr-CA/tournament.json
+++ b/locales/fr-CA/tournament.json
@@ -173,6 +173,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Annuler le dernier score",
"match.action.reopenMatch": "Rouvrir le match",
diff --git a/locales/fr-EU/tournament.json b/locales/fr-EU/tournament.json
index a95bc342b..257b63120 100644
--- a/locales/fr-EU/tournament.json
+++ b/locales/fr-EU/tournament.json
@@ -173,6 +173,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Annuler le dernier score",
"match.action.reopenMatch": "Rouvrir le match",
diff --git a/locales/he/tournament.json b/locales/he/tournament.json
index 0763a5957..a0df9ba61 100644
--- a/locales/he/tournament.json
+++ b/locales/he/tournament.json
@@ -173,6 +173,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "בטלו את התוצאה האחרונה",
"match.action.reopenMatch": "פתיחה מחדש של הקרב",
diff --git a/locales/it/tournament.json b/locales/it/tournament.json
index 697ad843d..125294514 100644
--- a/locales/it/tournament.json
+++ b/locales/it/tournament.json
@@ -173,6 +173,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Annulla ultimo punteggio",
"match.action.reopenMatch": "Riapri match",
diff --git a/locales/ja/tournament.json b/locales/ja/tournament.json
index 0c3694d80..89f7c9eea 100644
--- a/locales/ja/tournament.json
+++ b/locales/ja/tournament.json
@@ -167,6 +167,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "最後のスコアをやりなおす",
"match.action.reopenMatch": "対戦を再度開く",
diff --git a/locales/ko/tournament.json b/locales/ko/tournament.json
index 022754298..4ee278b26 100644
--- a/locales/ko/tournament.json
+++ b/locales/ko/tournament.json
@@ -167,6 +167,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "",
"match.action.reopenMatch": "",
diff --git a/locales/nl/tournament.json b/locales/nl/tournament.json
index 141826d9f..cdfffbd05 100644
--- a/locales/nl/tournament.json
+++ b/locales/nl/tournament.json
@@ -171,6 +171,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "",
"match.action.reopenMatch": "",
diff --git a/locales/pl/tournament.json b/locales/pl/tournament.json
index 1e6b39be9..c5bd99d1e 100644
--- a/locales/pl/tournament.json
+++ b/locales/pl/tournament.json
@@ -175,6 +175,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "",
"match.action.reopenMatch": "",
diff --git a/locales/pt-BR/tournament.json b/locales/pt-BR/tournament.json
index 66e0e53f2..825462b2f 100644
--- a/locales/pt-BR/tournament.json
+++ b/locales/pt-BR/tournament.json
@@ -173,6 +173,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Desfazer última pontuação",
"match.action.reopenMatch": "Reabrir partida",
diff --git a/locales/ru/tournament.json b/locales/ru/tournament.json
index 7d00ebebd..207457e1a 100644
--- a/locales/ru/tournament.json
+++ b/locales/ru/tournament.json
@@ -175,6 +175,8 @@
"match.locked.subtitle": "",
"match.waitingForTeams.header": "",
"match.waitingForTeams.subtitle": "",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "",
"match.action.undoLastScore": "Отменить последний результат",
"match.action.reopenMatch": "Открыть матч заново",
diff --git a/locales/zh/tournament.json b/locales/zh/tournament.json
index b98d1ed2b..43d220467 100644
--- a/locales/zh/tournament.json
+++ b/locales/zh/tournament.json
@@ -169,6 +169,8 @@
"match.locked.subtitle": "请等待工作人员解锁",
"match.waitingForTeams.header": "正在等待队伍",
"match.waitingForTeams.subtitle": "队伍将由先前的对局结果决定",
+ "match.waitingForPrevious.header": "",
+ "match.waitingForPrevious.subtitle": "",
"match.tbd": "待定",
"match.action.undoLastScore": "撤销上一局比分",
"match.action.reopenMatch": "重新开启对局",