- Share your invite link to add members: {inviteLink}
+ {t("tournament:actions.shareLink", { inviteLink })}
);
diff --git a/app/features/tournament/routes/to.$id.tsx b/app/features/tournament/routes/to.$id.tsx
index 5f1452717..ddaff9084 100644
--- a/app/features/tournament/routes/to.$id.tsx
+++ b/app/features/tournament/routes/to.$id.tsx
@@ -26,6 +26,7 @@ import { findTeamsByTournamentId } from "../queries/findTeamsByTournamentId.serv
import hasTournamentStarted from "../queries/hasTournamentStarted.server";
import { teamHasCheckedIn, tournamentIdFromParams } from "../tournament-utils";
import styles from "../tournament.css";
+import { findOwnTeam } from "../queries/findOwnTeam.server";
export const shouldRevalidate: ShouldRevalidateFunction = (args) => {
const wasMutation = args.formMethod === "post";
@@ -74,9 +75,6 @@ export const loader = async ({ params, request }: LoaderArgs) => {
teams = teams.filter(teamHasCheckedIn);
}
- const ownedTeamId = teams.find((team) =>
- team.members.some((member) => member.userId === user?.id && member.isOwner)
- )?.id;
const teamMemberOfName = teams.find((team) =>
team.members.some((member) => member.userId === user?.id)
)?.name;
@@ -86,7 +84,12 @@ export const loader = async ({ params, request }: LoaderArgs) => {
tieBreakerMapPool: db.calendarEvents.findTieBreakerMapPoolByEventId(
event.eventId
),
- ownedTeamId,
+ ownTeam: user
+ ? findOwnTeam({
+ tournamentId,
+ userId: user.id,
+ })
+ : null,
teamMemberOfName,
teams,
hasStarted,
diff --git a/app/features/tournament/tournament-constants.ts b/app/features/tournament/tournament-constants.ts
index a1d2717ce..d9fe07742 100644
--- a/app/features/tournament/tournament-constants.ts
+++ b/app/features/tournament/tournament-constants.ts
@@ -4,7 +4,7 @@ export const TOURNAMENT = {
COUNTERPICK_MAX_STAGE_REPEAT: 2,
COUNTERPICK_ONE_MODE_TOURNAMENT_MAPS_PER_MODE: 6,
TEAM_MIN_MEMBERS_FOR_FULL: 4,
- TEAM_MAX_MEMBERS: 6,
+ TEAM_MAX_MEMBERS_BEFORE_START: 6,
AVAILABLE_BEST_OF: [3, 5, 7] as const,
ENOUGH_TEAMS_TO_START: 2,
} as const;
diff --git a/app/features/tournament/tournament-utils.ts b/app/features/tournament/tournament-utils.ts
index 734019260..ae7840176 100644
--- a/app/features/tournament/tournament-utils.ts
+++ b/app/features/tournament/tournament-utils.ts
@@ -138,3 +138,10 @@ export function tournamentRoundI18nKey(round: PlayedSet["round"]) {
return `bracket.${round.type}` as const;
}
+
+export function tournamentTeamMaxSize(tournamentHasStarted: boolean) {
+ // ensuring every team can add at least one sub while the tournament is ongoing
+ return (
+ TOURNAMENT.TEAM_MAX_MEMBERS_BEFORE_START + Number(tournamentHasStarted)
+ );
+}
diff --git a/app/styles/utils.css b/app/styles/utils.css
index 8821e87ff..a35d019e4 100644
--- a/app/styles/utils.css
+++ b/app/styles/utils.css
@@ -170,6 +170,10 @@
margin-block-end: var(--s-1);
}
+.mb-4 {
+ margin-block-end: var(--s-4);
+}
+
.ml-auto {
margin-inline-start: auto;
}
@@ -190,6 +194,10 @@
margin-inline: var(--s-2);
}
+.my-2 {
+ margin-block: var(--s-2);
+}
+
.my-4 {
margin-block: var(--s-4);
}
diff --git a/e2e/tournament-bracket.spec.ts b/e2e/tournament-bracket.spec.ts
index dee07c180..2a739d58c 100644
--- a/e2e/tournament-bracket.spec.ts
+++ b/e2e/tournament-bracket.spec.ts
@@ -1,17 +1,15 @@
import { type Page, test, expect } from "@playwright/test";
import { NZAP_TEST_ID } from "~/db/seed/constants";
-import { impersonate, navigate, seed } from "~/utils/playwright";
+import { impersonate, navigate, seed, submit } from "~/utils/playwright";
import { tournamentBracketsPage } from "~/utils/urls";
-const TOURNAMENT_ID = 2;
-
-const startBracket = async (page: Page) => {
+const startBracket = async (page: Page, tournamentId = 2) => {
await seed(page);
await impersonate(page);
await navigate({
page,
- url: tournamentBracketsPage(TOURNAMENT_ID),
+ url: tournamentBracketsPage(tournamentId),
});
await page.getByTestId("finalize-bracket-button").click();
@@ -63,24 +61,25 @@ const expectScore = (page: Page, score: [number, number]) =>
// 7) As N-ZAP, undo all scores and switch to different team sweeping
test.describe("Tournament bracket", () => {
test("reports score and sees bracket update", async ({ page }) => {
+ const tournamentId = 2;
await startBracket(page);
await impersonate(page, NZAP_TEST_ID);
await navigate({
page,
- url: tournamentBracketsPage(TOURNAMENT_ID),
+ url: tournamentBracketsPage(tournamentId),
});
// 1)
await page.locator('[data-match-id="5"]').click();
- await reportResult(page, 2);
+ await reportResult(page, tournamentId);
await backToBracket(page);
// 2)
await impersonate(page);
await navigate({
page,
- url: tournamentBracketsPage(TOURNAMENT_ID),
+ url: tournamentBracketsPage(tournamentId),
});
await page.locator('[data-match-id="6"]').click();
await reportResult(page, 2);
@@ -112,7 +111,7 @@ test.describe("Tournament bracket", () => {
await impersonate(page, 2);
await navigate({
page,
- url: tournamentBracketsPage(TOURNAMENT_ID),
+ url: tournamentBracketsPage(tournamentId),
});
await page.locator('[data-match-id="5"]').click();
await page.getByTestId("undo-score-button").click();
@@ -123,4 +122,38 @@ test.describe("Tournament bracket", () => {
page.locator("[data-round-id='5'] [data-participant-id='102']")
).toBeVisible();
});
+
+ test("adds a sub mid tournament (from non checked in team)", async ({
+ page,
+ }) => {
+ const tournamentId = 1;
+ await startBracket(page, tournamentId);
+
+ // captain of the first team
+ await impersonate(page, 5);
+ await navigate({
+ page,
+ url: tournamentBracketsPage(tournamentId),
+ });
+
+ await page.getByTestId("add-sub-button").click();
+ await page.getByTestId("copy-invite-link-button").click();
+
+ const inviteLinkProd: string = await page.evaluate(
+ "navigator.clipboard.readText()"
+ );
+ const inviteLink = inviteLinkProd.replace(
+ "https://sendou.ink",
+ "http://localhost:5800"
+ );
+
+ await impersonate(page, NZAP_TEST_ID);
+ await navigate({
+ page,
+ url: inviteLink,
+ });
+
+ await submit(page);
+ await expect(page).toHaveURL(/brackets/);
+ });
});
diff --git a/playwright.config.ts b/playwright.config.ts
index 9e75dc14f..ea2df4cd0 100644
--- a/playwright.config.ts
+++ b/playwright.config.ts
@@ -40,6 +40,8 @@ const config: PlaywrightTestConfig = {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "retain-on-failure",
+
+ permissions: ["clipboard-read"],
},
/* Configure projects for major browsers */
diff --git a/public/locales/en/tournament.json b/public/locales/en/tournament.json
index 8d3701a4d..c952a9b17 100644
--- a/public/locales/en/tournament.json
+++ b/public/locales/en/tournament.json
@@ -59,5 +59,11 @@
"bracket.grand_finals": "Grand Finals",
"bracket.grand_finals.bracket_reset": "Bracket Reset",
"bracket.main": "Main Bracket",
- "bracket.underground": "Underground Bracket"
+ "bracket.underground": "Underground Bracket",
+
+ "actions.addSub": "Add sub",
+ "actions.shareLink": "Share your invite link to add members: {{inviteLink}}",
+ "actions.sub.prompt_other": "You can still add {{count}} subs to your roster",
+ "actions.sub.prompt_one": "You can still add {{count}} sub to your roster",
+ "actions.sub.prompt_zero": "Your roster is full and more subs can't be added"
}