Prevent unreg and kicking members in invitational tournaments

This commit is contained in:
Kalle
2026-08-29 19:46:06 +03:00
parent 5050b8d4fa
commit dfd84cf8f4
5 changed files with 33 additions and 22 deletions

View File

@@ -144,6 +144,10 @@ export const action: ActionFunction = async ({ request, params }) => {
}
case "DELETE_TEAM_MEMBER": {
errorToastIfFalsy(ownTeam, "You are not registered to this tournament");
errorToastIfFalsy(
!tournament.isInvitational,
"The organizer manages the roster of an invitational team",
);
errorToastIfFalsy(
ownTeam.memberUserIds.includes(data.userId),
"User is not in your team",
@@ -344,6 +348,10 @@ export const action: ActionFunction = async ({ request, params }) => {
}
case "UNREGISTER": {
errorToastIfFalsy(ownTeam, "You are not registered to this tournament");
errorToastIfFalsy(
!tournament.isInvitational,
"The organizer manages the roster of an invitational team",
);
errorToastIfFalsy(
!ownTeamCheckedIn,
"You cannot unregister after checking in",

View File

@@ -180,19 +180,12 @@ function RegistrationForms({ readOnly = false }: { readOnly?: boolean }) {
const ownTeamCheckedIn = Boolean(ownTeam && ownTeam.checkIns.length > 0);
const hasFriendCodeSet = Boolean(user?.friendCode);
if (!user && !tournament.isInvitational) {
if (!user) {
return <PleaseLogIn />;
}
const showRegistrationProgress = () => {
if (ownTeam) return true;
return !tournament.isInvitational;
};
const showRegisterNewTeam = () => {
if (ownTeam) return true;
if (tournament.isInvitational) return false;
if (!tournament.registrationOpen) return false;
return !tournament.regularCheckInHasEnded;
@@ -202,24 +195,19 @@ function RegistrationForms({ readOnly = false }: { readOnly?: boolean }) {
<div className="stack lg">
{showRegisterNewTeam() ? <FriendCode /> : null}
{hasFriendCodeSet ? (
showRegistrationProgress() ? (
<RegistrationProgress
checkedIn={ownTeamCheckedIn}
name={ownTeam?.name}
mapPool={data?.mapPool ?? undefined}
members={ownTeam?.members}
/>
) : (
<Alert>
This tournament is invitational. Tournament organizer adds all
teams.
</Alert>
)
<RegistrationProgress
checkedIn={ownTeamCheckedIn}
name={ownTeam?.name}
mapPool={data?.mapPool ?? undefined}
members={ownTeam?.members}
/>
) : null}
{showRegisterNewTeam() && hasFriendCodeSet ? (
<TeamInfo
ownTeam={ownTeam}
canUnregister={Boolean(ownTeam && !ownTeamCheckedIn)}
canUnregister={Boolean(
ownTeam && !ownTeamCheckedIn && !tournament.isInvitational,
)}
/>
) : null}
{tournament.isLeague &&
@@ -682,6 +670,7 @@ function FillRoster({
const showDeleteMemberSection =
!readOnly &&
!tournament.isInvitational &&
((!ownTeamCheckedIn && ownTeamMembers.length > 1) ||
(ownTeamCheckedIn &&
ownTeamMembers.length > tournament.minMembersPerTeam));

View File

@@ -0,0 +1,5 @@
---
navItem: calendar
type: bug
---
Captains of an invitational tournament team can no longer kick members or unregister the team on their own

View File

@@ -28,6 +28,8 @@ export class TournamentRegisterPage {
"Registration for this tournament has closed",
),
leaveTeamButton: page.getByRole("button", { name: "Leave the team" }),
deleteMemberButton: page.getByRole("button", { name: "Delete member" }),
unregisterButton: page.getByRole("button", { name: "Unregister" }),
organizerAddedLeaveExplanation: page.getByText(
"You were added to the team by the organizer. Contact the TO to leave the team.",
),

View File

@@ -85,6 +85,13 @@ test.describe("Invitational tournament", () => {
await expect(
register.locators.organizerAddedLeaveExplanation,
).toBeVisible();
// nor can the captain kick them, the organizer owns the roster
await impersonate(page, captain.id);
await register.goto(tournament.id);
await expect(register.member(2)).toBeVisible();
await expect(register.locators.deleteMemberButton).toHaveCount(0);
await expect(register.locators.unregisterButton).toHaveCount(0);
});
});