mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-27 13:47:56 -05:00
Tournament team-picked map lists and check-ins fixes
This commit is contained in:
@@ -815,15 +815,7 @@ async function updateTournamentTables(
|
||||
|
||||
// the teams' picks were made against the old settings, so they pick again
|
||||
if (changedMapPickingStyle || changedMapPool) {
|
||||
await trx
|
||||
.deleteFrom("MapPoolMap")
|
||||
.where("tournamentTeamId", "in", (eb) =>
|
||||
eb
|
||||
.selectFrom("TournamentTeam")
|
||||
.select("id")
|
||||
.where("tournamentId", "=", tournamentId),
|
||||
)
|
||||
.execute();
|
||||
await resetTeamMapPicks({ tournamentId, args }, trx);
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -841,6 +833,47 @@ async function updateTournamentTables(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes every team's map picks. Teams that had picked are also checked out when picks are still
|
||||
* a check-in requirement, as otherwise they would enter the bracket without a pool.
|
||||
*/
|
||||
async function resetTeamMapPicks(
|
||||
{
|
||||
tournamentId,
|
||||
args,
|
||||
}: { tournamentId: number; args: Pick<UpdateArgs, "mapPickingStyle"> },
|
||||
trx: Transaction<DB>,
|
||||
) {
|
||||
// before the picks go, as the teams to check out are the ones that have them
|
||||
if (args.mapPickingStyle !== "TO") {
|
||||
await trx
|
||||
.deleteFrom("TournamentTeamCheckIn")
|
||||
.where("bracketIdx", "is", null)
|
||||
.where("tournamentTeamId", "in", (eb) =>
|
||||
eb
|
||||
.selectFrom("MapPoolMap")
|
||||
.innerJoin(
|
||||
"TournamentTeam",
|
||||
"TournamentTeam.id",
|
||||
"MapPoolMap.tournamentTeamId",
|
||||
)
|
||||
.select("TournamentTeam.id")
|
||||
.where("TournamentTeam.tournamentId", "=", tournamentId),
|
||||
)
|
||||
.execute();
|
||||
}
|
||||
|
||||
await trx
|
||||
.deleteFrom("MapPoolMap")
|
||||
.where("tournamentTeamId", "in", (eb) =>
|
||||
eb
|
||||
.selectFrom("TournamentTeam")
|
||||
.select("id")
|
||||
.where("tournamentId", "=", tournamentId),
|
||||
)
|
||||
.execute();
|
||||
}
|
||||
|
||||
function teamPickSettings(
|
||||
args: Pick<CreateArgs, "mapPickingStyle" | "teamPick" | "isFullTournament">,
|
||||
) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import { beforeEach, describe, expect, test } from "vitest";
|
||||
import * as BadgeFactory from "~/db/seed/factories/BadgeFactory";
|
||||
import * as TournamentFactory from "~/db/seed/factories/TournamentFactory";
|
||||
import * as TournamentOrganizationFactory from "~/db/seed/factories/TournamentOrganizationFactory";
|
||||
import * as TournamentTeamFactory from "~/db/seed/factories/TournamentTeamFactory";
|
||||
import * as UserFactory from "~/db/seed/factories/UserFactory";
|
||||
import * as CalendarRepository from "~/features/calendar/CalendarRepository.server";
|
||||
import { MapPool } from "~/features/map-list-generator/core/map-pool";
|
||||
@@ -21,6 +22,8 @@ const editAction = wrappedAction<typeof calendarNewSchemaServer>({
|
||||
const users = UserFactory.pool();
|
||||
|
||||
const badgeManagingAuthorId = () => users.id(1);
|
||||
const teamPickAuthorId = () => users.id(5);
|
||||
const teamPickTeamMemberIds = () => users.ids(4);
|
||||
|
||||
describe("calendar new action: editing an event with badge prizes", () => {
|
||||
let orgAdminId: number;
|
||||
@@ -168,6 +171,7 @@ describe("calendar new action: bracket URL", () => {
|
||||
describe("calendar new action: team picked tournament", () => {
|
||||
beforeEach(async () => {
|
||||
await UserFactory.createRegular(null, { roles: ["TOURNAMENT_ORGANIZER"] });
|
||||
await users.create(5);
|
||||
});
|
||||
|
||||
test("saves the team pick settings and the custom pool", async () => {
|
||||
@@ -211,4 +215,37 @@ describe("calendar new action: team picked tournament", () => {
|
||||
customPool.serialized,
|
||||
);
|
||||
});
|
||||
|
||||
test("changing the pick settings resets the teams' picks and checks them out", async () => {
|
||||
const tournament = await TournamentFactory.create({
|
||||
authorId: teamPickAuthorId(),
|
||||
mapPickingStyle: "AUTO",
|
||||
teamPick: { modes: [{ mode: "SZ", count: 2 }], pool: "ALL" },
|
||||
});
|
||||
await TournamentTeamFactory.create(
|
||||
{
|
||||
tournamentId: tournament.id,
|
||||
memberUserIds: teamPickTeamMemberIds(),
|
||||
mapPool: new MapPool({ ...MapPool.EMPTY.parsed, SZ: [1, 2] }),
|
||||
},
|
||||
{ isCheckedIn: true },
|
||||
);
|
||||
|
||||
const res = await editAction(
|
||||
calendarNewFormValues({
|
||||
eventToEditId: tournament.eventId,
|
||||
bracketUrl: "https://sendou.ink",
|
||||
mapPickingStyle: "AUTO",
|
||||
teamPickModes: ["SZ"],
|
||||
teamPickCounts: [{ mode: "SZ", count: 3 }],
|
||||
teamPickPool: "ALL",
|
||||
}),
|
||||
{ user: teamPickAuthorId() },
|
||||
);
|
||||
expect(res.fieldErrors).toBeUndefined();
|
||||
|
||||
const edited = await tournamentFromDB(tournament.id);
|
||||
expect(edited.ctx.teams[0].hasMapPool).toBe(0);
|
||||
expect(edited.ctx.teams[0].checkIns).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -601,13 +601,18 @@ function TeamPickCountInputs({
|
||||
value={count}
|
||||
onChange={(e) =>
|
||||
onChange(
|
||||
pickedModes.map((m) => ({
|
||||
mode: m,
|
||||
count:
|
||||
// an emptied input drops the entry so the mode falls back to the default count
|
||||
pickedModes.flatMap((m) => {
|
||||
const newCount =
|
||||
m === mode
|
||||
? Number(e.target.value)
|
||||
: (value.find((c) => c.mode === m)?.count ?? 1),
|
||||
})),
|
||||
? Number.parseInt(e.target.value, 10)
|
||||
: value.find((c) => c.mode === m)?.count;
|
||||
|
||||
return typeof newCount === "number" &&
|
||||
!Number.isNaN(newCount)
|
||||
? [{ mode: m, count: newCount }]
|
||||
: [];
|
||||
}),
|
||||
mode,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -118,7 +118,12 @@ export default function TournamentRegisterPage() {
|
||||
|
||||
return (
|
||||
<div className={clsx("stack lg", containerClassName("normal"))}>
|
||||
{isRegularMemberOfATeam ? (
|
||||
{tournament.hasStarted && teamMemberOf ? (
|
||||
<div className="stack md">
|
||||
<Alert>{t("tournament:pre.startedNoEdit")}</Alert>
|
||||
<RegistrationForms readOnly />
|
||||
</div>
|
||||
) : isRegularMemberOfATeam ? (
|
||||
<div className="stack md">
|
||||
<Alert>{t("tournament:pre.captainOnlyEdit")}</Alert>
|
||||
<div className="stack md items-center">
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Log in for at tilmelde dig",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Logge dich zum Registrieren ein",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -362,7 +362,7 @@
|
||||
"options.teamPickPool.SENDOUQ": "SendouQ legal maps",
|
||||
"options.teamPickPool.ALL": "All maps",
|
||||
"options.teamPickPool.CUSTOM": "Custom",
|
||||
"bottomTexts.teamPickReset": "Changing the map settings resets the maps every team has already picked",
|
||||
"bottomTexts.teamPickReset": "Changing the map settings resets the maps every team has already picked and checks those teams out",
|
||||
"bottomTexts.regClosesAt": "All times relative to the reported tournament start time e.g. \"30 minutes\" means \"30 minutes before event start time\". After registration closes only TO's can make changes to team rosters.",
|
||||
"bottomTexts.maxTeamSize": "Maximum number of players that can be registered per team. Doesn't apply to tournament organizers. Default is 6.",
|
||||
"bottomTexts.avatarValidation": "Note that for non-patrons there is a validation process before avatar is shown.",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "To play tournaments on sendou.ink you'll need to register your friend code.",
|
||||
"pre.logIn": "Log in to register",
|
||||
"pre.captainOnlyEdit": "You are in a team for this event. Only the team captain can edit the registration.",
|
||||
"pre.startedNoEdit": "The tournament has started. Registration can no longer be edited.",
|
||||
"pre.leave.button": "Leave the team",
|
||||
"pre.leave.confirm": "Leave \"{{teamName}}\"?",
|
||||
"pre.leave.cant.organizerAdded": "You were added to the team by the organizer. Contact the TO to leave the team.",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Inicia sesión para inscribirte",
|
||||
"pre.captainOnlyEdit": "Estás en un equipo para este evento. Solo el capitán del equipo puede editar la inscripción.",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Inicia sesión para inscribirte",
|
||||
"pre.captainOnlyEdit": "Estás en un equipo para este evento. Solo el capitán del equipo puede editar la inscripción.",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Connectez-vous pour vous inscrire",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Connectez-vous pour vous inscrire",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "התחבר כדי להירשם",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Accedi per iscriverti",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "ログインして登録する",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Faça o login para registrar",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "Войдите, чтобы зарегистрироваться",
|
||||
"pre.captainOnlyEdit": "",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"pre.friendCode.needed": "",
|
||||
"pre.logIn": "登录以报名",
|
||||
"pre.captainOnlyEdit": "您已加入此赛事的某支队伍。只有队长可以修改报名信息。",
|
||||
"pre.startedNoEdit": "",
|
||||
"pre.leave.button": "",
|
||||
"pre.leave.confirm": "",
|
||||
"pre.leave.cant.organizerAdded": "",
|
||||
|
||||
Reference in New Issue
Block a user