mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-10 21:26:08 -05:00
Delete tournament feature
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Form } from "@remix-run/react";
|
||||
import { Form, useFetcher } from "@remix-run/react";
|
||||
import React from "react";
|
||||
import invariant from "tiny-invariant";
|
||||
import { useTranslation } from "~/hooks/useTranslation";
|
||||
@@ -11,12 +11,15 @@ export function FormWithConfirm({
|
||||
children,
|
||||
dialogHeading,
|
||||
deleteButtonText,
|
||||
action,
|
||||
}: {
|
||||
fields?: [name: string, value: string | number][];
|
||||
children: React.ReactNode;
|
||||
dialogHeading: string;
|
||||
deleteButtonText?: string;
|
||||
action?: string;
|
||||
}) {
|
||||
const fetcher = useFetcher();
|
||||
const { t } = useTranslation(["common"]);
|
||||
const [dialogOpen, setDialogOpen] = React.useState(false);
|
||||
const formRef = React.useRef<HTMLFormElement>(null);
|
||||
@@ -29,11 +32,17 @@ export function FormWithConfirm({
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form id={id} className="hidden" ref={formRef} method="post">
|
||||
<fetcher.Form
|
||||
id={id}
|
||||
className="hidden"
|
||||
ref={formRef}
|
||||
method="post"
|
||||
action={action}
|
||||
>
|
||||
{fields?.map(([name, value]) => (
|
||||
<input type="hidden" key={name} name={name} value={value} />
|
||||
))}
|
||||
</Form>
|
||||
</fetcher.Form>
|
||||
<Dialog isOpen={dialogOpen} close={closeDialog} className="text-center">
|
||||
<div className="stack md">
|
||||
<h2 className="text-sm">{dialogHeading}</h2>
|
||||
|
||||
4
app/db/models/calendar/deleteTournamentById.sql
Normal file
4
app/db/models/calendar/deleteTournamentById.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
delete from
|
||||
"Tournament"
|
||||
where
|
||||
id = @id
|
||||
@@ -41,6 +41,7 @@ import findAllEventsWithMapPoolsSql from "./findAllEventsWithMapPools.sql";
|
||||
import findTieBreakerMapPoolByEventIdSql from "./findTieBreakerMapPoolByEventId.sql";
|
||||
import deleteByIdSql from "./deleteById.sql";
|
||||
import createTournamentSql from "./createTournament.sql";
|
||||
import deleteTournamentByIdSql from "./deleteTournamentById.sql";
|
||||
|
||||
const createStm = sql.prepare(createSql);
|
||||
const updateStm = sql.prepare(updateSql);
|
||||
@@ -58,6 +59,7 @@ const findTieBreakerMapPoolByEventIdtm = sql.prepare(
|
||||
findTieBreakerMapPoolByEventIdSql
|
||||
);
|
||||
const deleteByIdStm = sql.prepare(deleteByIdSql);
|
||||
const deleteTournamentByIdStm = sql.prepare(deleteTournamentByIdSql);
|
||||
const createTournamentStm = sql.prepare(createTournamentSql);
|
||||
|
||||
const createTournament = (
|
||||
@@ -512,6 +514,15 @@ export function findTieBreakerMapPoolByEventId(
|
||||
>;
|
||||
}
|
||||
|
||||
export function deleteById(id: CalendarEvent["id"]) {
|
||||
return deleteByIdStm.run({ id });
|
||||
}
|
||||
export const deleteById = sql.transaction(
|
||||
({
|
||||
eventId,
|
||||
tournamentId,
|
||||
}: {
|
||||
eventId: number;
|
||||
tournamentId: number | null;
|
||||
}) => {
|
||||
deleteByIdStm.run({ id: eventId });
|
||||
if (tournamentId) deleteTournamentByIdStm.run({ id: tournamentId });
|
||||
}
|
||||
);
|
||||
|
||||
@@ -30,8 +30,13 @@ import { joinTeam, leaveTeam } from "../queries/joinLeaveTeam.server";
|
||||
import { TOURNAMENT } from "../tournament-constants";
|
||||
import { deleteTeam } from "../queries/deleteTeam.server";
|
||||
import { useUser } from "~/modules/auth";
|
||||
import { calendarEditPage, tournamentPage } from "~/utils/urls";
|
||||
import {
|
||||
calendarEditPage,
|
||||
calendarEventPage,
|
||||
tournamentPage,
|
||||
} from "~/utils/urls";
|
||||
import { Redirect } from "~/components/Redirect";
|
||||
import { FormWithConfirm } from "~/components/FormWithConfirm";
|
||||
|
||||
export const action: ActionFunction = async ({ request, params }) => {
|
||||
const user = await requireUserId(request);
|
||||
@@ -138,7 +143,9 @@ export const action: ActionFunction = async ({ request, params }) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
// xxx: seed order for challonge download
|
||||
export default function TournamentAdminPage() {
|
||||
const { t } = useTranslation(["calendar"]);
|
||||
const data = useOutletContext<TournamentLoaderData>();
|
||||
const user = useUser();
|
||||
|
||||
@@ -151,7 +158,7 @@ export default function TournamentAdminPage() {
|
||||
<AdminActions />
|
||||
{isAdmin(user) ? <EnableMapList /> : null}
|
||||
<DownloadParticipants />
|
||||
<div className="stack items-start mt-4">
|
||||
<div className="stack horizontal items-end mt-4">
|
||||
<LinkButton
|
||||
to={calendarEditPage(data.event.eventId)}
|
||||
size="tiny"
|
||||
@@ -159,6 +166,23 @@ export default function TournamentAdminPage() {
|
||||
>
|
||||
Edit event info
|
||||
</LinkButton>
|
||||
{!data.hasStarted ? (
|
||||
<FormWithConfirm
|
||||
dialogHeading={t("calendar:actions.delete.confirm", {
|
||||
name: data.event.name,
|
||||
})}
|
||||
action={calendarEventPage(data.event.eventId)}
|
||||
>
|
||||
<Button
|
||||
className="ml-auto"
|
||||
size="tiny"
|
||||
variant="minimal-destructive"
|
||||
type="submit"
|
||||
>
|
||||
{t("calendar:actions.delete")}
|
||||
</Button>
|
||||
</FormWithConfirm>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -58,7 +58,7 @@ export const links: LinksFunction = () => {
|
||||
};
|
||||
|
||||
export const handle: SendouRouteHandle = {
|
||||
i18n: ["tournament"],
|
||||
i18n: ["tournament", "calendar"],
|
||||
};
|
||||
|
||||
export type TournamentLoaderTeam = Unpacked<TournamentLoaderData["teams"]>;
|
||||
|
||||
@@ -69,7 +69,10 @@ export const action: ActionFunction = async ({ params, request }) => {
|
||||
})
|
||||
);
|
||||
|
||||
db.calendarEvents.deleteById(event.eventId);
|
||||
db.calendarEvents.deleteById({
|
||||
eventId: event.eventId,
|
||||
tournamentId: event.tournamentId,
|
||||
});
|
||||
|
||||
return redirect(CALENDAR_PAGE);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user