From 88dc19f450592399dee4f1bd04e1f897044d82d9 Mon Sep 17 00:00:00 2001
From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com>
Date: Wed, 22 Dec 2021 18:19:41 +0200
Subject: [PATCH] =?UTF-8?q?Create=20tournaments=20rounds=20almost=E2=84=A2?=
=?UTF-8?q?=EF=B8=8F=20edition?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/core/tournament/bracket.ts | 5 +-
app/models/Tournament.ts | 1 +
app/routes/to/$organization.$tournament.tsx | 3 +-
.../to/$organization.$tournament/start.tsx | 36 +++++++---
app/services/tournament.ts | 67 ++++++++++++++++++-
app/styles/global.css | 3 +-
app/styles/tournament.css | 2 +-
7 files changed, 100 insertions(+), 17 deletions(-)
diff --git a/app/core/tournament/bracket.ts b/app/core/tournament/bracket.ts
index 065e38a43..5a46f1387 100644
--- a/app/core/tournament/bracket.ts
+++ b/app/core/tournament/bracket.ts
@@ -1,4 +1,5 @@
import type { BracketType, Stage, TeamOrder } from ".prisma/client";
+import { v4 as uuidv4 } from "uuid";
import invariant from "tiny-invariant";
import { TOURNAMENT_TEAM_ROSTER_MIN_SIZE } from "../../constants";
import { FindTournamentByNameForUrlI } from "../../services/tournament";
@@ -182,7 +183,8 @@ export function countParticipants(teams: FindTournamentByNameForUrlI["teams"]) {
}, 0);
}
-interface TournamentRoundForDB {
+export interface TournamentRoundForDB {
+ id: string;
position: number;
stages: {
position: number;
@@ -256,6 +258,7 @@ export function tournamentRoundsForDB({
});
result.push({
+ id: uuidv4(),
position,
stages,
matches,
diff --git a/app/models/Tournament.ts b/app/models/Tournament.ts
index 81d37cd7d..aa1586a91 100644
--- a/app/models/Tournament.ts
+++ b/app/models/Tournament.ts
@@ -50,6 +50,7 @@ export async function findByNameForUrl({
},
brackets: {
select: {
+ id: true,
type: true,
},
},
diff --git a/app/routes/to/$organization.$tournament.tsx b/app/routes/to/$organization.$tournament.tsx
index 6d80dd14d..fcaf932a4 100644
--- a/app/routes/to/$organization.$tournament.tsx
+++ b/app/routes/to/$organization.$tournament.tsx
@@ -117,7 +117,8 @@ export default function TournamentPage() {
-
+
+ {/* TODO: pass context instead of useMatches */}
);
diff --git a/app/routes/to/$organization.$tournament/start.tsx b/app/routes/to/$organization.$tournament/start.tsx
index 96919eb87..d7042d4a4 100644
--- a/app/routes/to/$organization.$tournament/start.tsx
+++ b/app/routes/to/$organization.$tournament/start.tsx
@@ -1,6 +1,11 @@
import type { Mode, Stage } from ".prisma/client";
import classNames from "classnames";
-import type { ActionFunction, LinksFunction, LoaderFunction } from "remix";
+import {
+ ActionFunction,
+ LinksFunction,
+ LoaderFunction,
+ useMatches,
+} from "remix";
import { Form, json, redirect, useLoaderData } from "remix";
import invariant from "tiny-invariant";
import { Alert } from "~/components/Alert";
@@ -9,6 +14,7 @@ import { Catcher } from "~/components/Catcher";
import { modesShort, modesShortToLong } from "~/constants";
import { eliminationBracket } from "~/core/tournament/algorithms";
import {
+ EliminationBracket,
EliminationBracketSide,
participantCountToRoundsInfo,
} from "~/core/tournament/bracket";
@@ -21,6 +27,7 @@ import type {
import {
createTournamentRounds,
findTournamentByNameForUrl,
+ FindTournamentByNameForUrlI,
} from "~/services/tournament";
import startBracketTabStylesUrl from "~/styles/tournament-start.css";
import { requireUser } from "~/utils";
@@ -32,11 +39,13 @@ export const links: LinksFunction = () => {
};
export const action: ActionFunction = async ({ request, params, context }) => {
- const mapListString = (await request.formData()).get("map-list");
+ const formData = await request.formData();
+ const mapListString = formData.get("map-list");
+ const bracketId = formData.get("bracket-id");
invariant(typeof mapListString === "string", "Type of map list not string");
- const mapList = JSON.parse(
- mapListString
- ) as UseTournamentRoundsState["bracket"];
+ invariant(typeof bracketId === "string", "Type of bracket id not string");
+ // TODO: could use Zod here
+ const mapList = JSON.parse(mapListString) as EliminationBracket;
const organizationNameForUrl = params.organization;
const tournamentNameForUrl = params.tournament;
@@ -50,10 +59,9 @@ export const action: ActionFunction = async ({ request, params, context }) => {
organizationNameForUrl,
tournamentNameForUrl,
userId: user.id,
+ bracketId,
});
- return null;
-
return redirect(
`/to/${organizationNameForUrl}/${tournamentNameForUrl}/bracket`
);
@@ -94,18 +102,26 @@ export const loader: LoaderFunction = async ({ params }) => {
// TODO: component that shows a table of map, counts in the map pool, which rounds
// TODO: handle warning if check-in has not concluded
export default function StartBracketTab() {
+ const [, parentRoute] = useMatches();
+ const { brackets } = parentRoute.data as FindTournamentByNameForUrlI;
const args = useLoaderData();
const [{ bracket, showAlert, actionButtonsDisabled }, dispatch] =
useTournamentRounds(args);
+ // TODO: dropdown to select this
+ const bracketId = brackets[0].id;
+
return (