From 085d717217cccc55d0cef172a042d489518b246f Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sun, 24 Mar 2024 10:48:28 +0200 Subject: [PATCH] Subs registration closing when regular registration closes feature --- .../tournament-bracket/core/Tournament.ts | 16 ++++- .../routes/to.$id.subs.new.tsx | 19 +++++- .../tournament-subs/routes/to.$id.subs.tsx | 61 ++++++++++++++++--- .../tournament-subs-schemas.server.ts | 5 ++ .../tournament/routes/to.$id.register.tsx | 2 +- 5 files changed, 90 insertions(+), 13 deletions(-) diff --git a/app/features/tournament-bracket/core/Tournament.ts b/app/features/tournament-bracket/core/Tournament.ts index 4defb8981..8255b48f2 100644 --- a/app/features/tournament-bracket/core/Tournament.ts +++ b/app/features/tournament-bracket/core/Tournament.ts @@ -12,7 +12,10 @@ import { } from "~/features/tournament/tournament-utils"; import { rankedModesShort } from "~/modules/in-game-lists/modes"; import type { ModeShort } from "~/modules/in-game-lists"; -import { databaseTimestampToDate } from "~/utils/dates"; +import { + databaseTimestampToDate, + dateToDatabaseTimestamp, +} from "~/utils/dates"; import { fillWithNullTillPowerOfTwo } from "../tournament-bracket-utils"; import type { Stage } from "~/modules/brackets-model"; import { Bracket } from "./Bracket"; @@ -636,6 +639,17 @@ export class Tournament { return !this.isInvitational(); } + get canAddNewSubPost() { + if (!this.subsFeatureEnabled) return false; + + return ( + !this.ctx.settings.regClosesAt || + this.ctx.settings.regClosesAt === + dateToDatabaseTimestamp(this.ctx.startTime) || + this.registrationOpen + ); + } + get maxTeamMemberCount() { const maxMembersBeforeStart = this.isInvitational() ? 5 diff --git a/app/features/tournament-subs/routes/to.$id.subs.new.tsx b/app/features/tournament-subs/routes/to.$id.subs.new.tsx index e8baffd25..3aae2db14 100644 --- a/app/features/tournament-subs/routes/to.$id.subs.new.tsx +++ b/app/features/tournament-subs/routes/to.$id.subs.new.tsx @@ -17,12 +17,17 @@ import { Button } from "~/components/Button"; import { TrashIcon } from "~/components/icons/Trash"; import { findSubsByTournamentId } from "../queries/findSubsByTournamentId.server"; import { tournamentIdFromParams } from "~/features/tournament"; -import { parseRequestFormData, type SendouRouteHandle } from "~/utils/remix"; +import { + parseRequestFormData, + validate, + type SendouRouteHandle, +} from "~/utils/remix"; import { FormMessage } from "~/components/FormMessage"; import { subSchema } from "../tournament-subs-schemas.server"; import { upsertSub } from "../queries/upsertSub.server"; import { tournamentSubsPage } from "~/utils/urls"; import { useUser } from "~/features/auth/core/user"; +import { tournamentFromDB } from "~/features/tournament-bracket/core/Tournament.server"; import "../tournament-subs.css"; @@ -37,8 +42,13 @@ export const action: ActionFunction = async ({ params, request }) => { schema: subSchema, }); const tournamentId = tournamentIdFromParams(params); + const tournament = await tournamentFromDB({ tournamentId, user }); - // TODO: validate tournament is not finalized + validate(!tournament.everyBracketOver, "Tournament is over"); + validate( + tournament.canAddNewSubPost, + "Registration is closed or subs feature disabled", + ); upsertSub({ bestWeapons: data.bestWeapons.join(","), @@ -56,6 +66,11 @@ export const action: ActionFunction = async ({ params, request }) => { export const loader = async ({ request, params }: LoaderFunctionArgs) => { const user = await requireUser(request); const tournamentId = tournamentIdFromParams(params); + const tournament = await tournamentFromDB({ tournamentId, user }); + + if (!tournament.canAddNewSubPost) { + throw redirect(tournamentSubsPage(tournamentId)); + } const sub = findSubsByTournamentId({ tournamentId }).find( (sub) => sub.userId === user.id, diff --git a/app/features/tournament-subs/routes/to.$id.subs.tsx b/app/features/tournament-subs/routes/to.$id.subs.tsx index 89c0089cb..c1ab91157 100644 --- a/app/features/tournament-subs/routes/to.$id.subs.tsx +++ b/app/features/tournament-subs/routes/to.$id.subs.tsx @@ -27,16 +27,30 @@ import { findSubsByTournamentId, type SubByTournamentId, } from "../queries/findSubsByTournamentId.server"; +import { parseRequestFormData, validate } from "~/utils/remix"; +import { deleteSubSchema } from "../tournament-subs-schemas.server"; +import { Popover } from "~/components/Popover"; import "../tournament-subs.css"; export const action: ActionFunction = async ({ request, params }) => { const user = await requireUser(request); const tournamentId = tournamentIdFromParams(params); + const tournament = await tournamentFromDB({ tournamentId, user }); + const data = await parseRequestFormData({ + request, + schema: deleteSubSchema, + }); + + validate( + user.id === data.userId || tournament.isOrganizer(user), + "You can only delete your own sub post", + 401, + ); deleteSub({ tournamentId, - userId: user.id, + userId: data.userId, }); return null; @@ -84,7 +98,6 @@ export const loader = async ({ params, request }: LoaderFunctionArgs) => { export default function TournamentSubsPage() { const user = useUser(); - const { t } = useTranslation(["tournament"]); const data = useLoaderData(); const tournament = useTournament(); @@ -96,11 +109,7 @@ export default function TournamentSubsPage() {
{!tournament.teamMemberOfByUser(user) && user ? (
- - {data.hasOwnSubPost - ? t("tournament:subs.editPost") - : t("tournament:subs.addPost")} - +
) : null} {data.subs.map((sub) => { @@ -110,9 +119,36 @@ export default function TournamentSubsPage() { ); } +function AddOrEditSubButton() { + const { t } = useTranslation(["tournament"]); + const data = useLoaderData(); + const tournament = useTournament(); + + const buttonText = data.hasOwnSubPost + ? t("tournament:subs.editPost") + : t("tournament:subs.addPost"); + + if (!tournament.canAddNewSubPost) { + return ( + {buttonText}} triggerClassName="tiny"> + {data.hasOwnSubPost + ? "Sub post can't be edited anymore since registration has closed" + : "Sub post can't be added anymore since registration has closed"} + + ); + } + + return ( + + {buttonText} + + ); +} + function SubInfoSection({ sub }: { sub: SubByTournamentId }) { const { t } = useTranslation(["common", "tournament"]); const user = useUser(); + const tournament = useTournament(); const infos = [
@@ -172,9 +208,16 @@ function SubInfoSection({ sub }: { sub: SubByTournamentId }) {
{sub.message}
) : null} - {user?.id === sub.userId ? ( + {user?.id === sub.userId || tournament.isOrganizer(user) ? (
- +