Remove unnecessary fields from tournament team

This commit is contained in:
Kalle
2022-03-27 17:43:28 +03:00
parent b6fc09d935
commit cd7e8531aa
9 changed files with 28 additions and 231 deletions

View File

@@ -1,6 +1,5 @@
import { Form, useMatches } from "remix";
import invariant from "tiny-invariant";
import { resolveHostInfo } from "~/core/tournament/utils";
import type { BracketModified } from "~/services/bracket";
import type { FindTournamentByNameForUrlI } from "~/services/tournament";
import { Unpacked } from "~/utils";
@@ -19,7 +18,7 @@ export function DuringMatchActions({
currentRound: Unpacked<BracketModified["rounds"]>;
}) {
const [, parentRoute] = useMatches();
const { teams, seeds } = parentRoute.data as FindTournamentByNameForUrlI;
const { teams } = parentRoute.data as FindTournamentByNameForUrlI;
const opponentTeam = teams.find(
(team) =>
@@ -29,11 +28,12 @@ export function DuringMatchActions({
);
invariant(opponentTeam, "opponentTeam is undefined");
const { weHost, friendCodeToAdd, roomPass } = resolveHostInfo({
ourTeam: ownTeam,
theirTeam: opponentTeam,
seeds,
});
// TODO:
const { weHost, friendCodeToAdd, roomPass } = {
weHost: true,
friendCodeToAdd: "1234-1234-1234",
roomPass: "1324",
};
const currentPosition =
currentMatch.score?.reduce((acc, cur) => acc + cur, 1) ?? 1;

View File

@@ -1,7 +1,5 @@
import invariant from "tiny-invariant";
import { ROOM_PASS_LENGTH } from "~/constants";
import type { FindTournamentByNameForUrlI } from "~/services/tournament";
import { Unpacked } from "~/utils";
export function checkInHasStarted(checkInStartTime: string) {
return new Date(checkInStartTime) < new Date();
@@ -60,43 +58,6 @@ export function matchIsOver(
return upperTeamScore > half || lowerTeamScore > half;
}
export function resolveHostInfo({
ourTeam,
theirTeam,
seeds,
}: {
ourTeam: Unpacked<FindTournamentByNameForUrlI["teams"]>;
theirTeam: Unpacked<FindTournamentByNameForUrlI["teams"]>;
seeds: string[];
}): { friendCodeToAdd: string; roomPass: string; weHost: boolean } {
const seededOrder = [ourTeam, theirTeam].sort(sortTeamsBySeed(seeds));
const weAreHigherSeed = seededOrder[0].id === ourTeam.id;
let weHost = false;
if (ourTeam.canHost && !theirTeam.canHost) weHost = true;
if (!ourTeam.canHost && !theirTeam.canHost && weAreHigherSeed) weHost = true;
const teamToHost = weHost ? ourTeam : theirTeam;
return {
weHost,
roomPass: teamToHost.roomPass ?? idToRoomPass(teamToHost.id),
friendCodeToAdd: teamToHost.friendCode,
};
}
function idToRoomPass(id: string) {
let pass = "";
for (const letter of id) {
if (pass.length === ROOM_PASS_LENGTH) break;
const maybeNumber = Number(letter);
if (Number.isNaN(maybeNumber)) continue;
pass += letter;
}
return pass;
}
export const tournamentURL = ({
organizerNameForUrl,
tournamentNameForUrl,

View File

@@ -71,9 +71,6 @@ export async function findByNameForUrl({
id: true,
name: true,
createdAt: true,
friendCode: true,
roomPass: true,
canHost: true,
inviteCode: withInviteCodes,
members: {
select: {

View File

@@ -6,18 +6,15 @@ export function create({
userId,
teamName,
tournamentId,
friendCode,
}: {
userId: string;
teamName: string;
tournamentId: string;
friendCode: string;
}) {
return db.tournamentTeam.create({
data: {
name: teamName.trim(),
tournamentId,
friendCode,
members: {
create: {
memberId: userId,
@@ -60,27 +57,3 @@ export function checkOut(id: string) {
},
});
}
export type EditTeam = Prisma.PromiseReturnType<typeof editTeam>;
export function editTeam({
id,
friendCode,
roomPass,
canHost,
}: {
id: string;
friendCode: string;
roomPass: string | null;
canHost: boolean;
}) {
return db.tournamentTeam.update({
where: {
id,
},
data: {
friendCode,
roomPass,
canHost,
},
});
}

View File

@@ -1,7 +1,6 @@
import { Prisma } from ".prisma/client";
import {
ActionFunction,
Form,
json,
LinksFunction,
LoaderFunction,
@@ -14,18 +13,9 @@ import { z } from "zod";
import { AddPlayers } from "~/components/AddPlayers";
import { Alert } from "~/components/Alert";
import { Catcher } from "~/components/Catcher";
import { FormInfoText } from "~/components/FormInfoText";
import { Label } from "~/components/Label";
import { SubmitButton } from "~/components/SubmitButton";
import { TeamRoster } from "~/components/tournament/TeamRoster";
import { TOURNAMENT_TEAM_ROSTER_MAX_SIZE } from "~/constants";
import {
friendCodeRegExp,
friendCodeRegExpString,
roompassRegExp,
roompassRegExpString,
tournamentURL,
} from "~/core/tournament/utils";
import { tournamentURL } from "~/core/tournament/utils";
import {
isCaptainOfTheTeam,
teamHasNotCheckedIn,
@@ -54,18 +44,6 @@ const actionSchema = z.union([
userId: z.string().uuid(),
teamId: z.string().uuid(),
}),
z.object({
_action: z.literal("EDIT_TEAM"),
teamId: z.string().uuid(),
friendCode: z.string().regex(friendCodeRegExp),
canHost: z
.enum(["yes", "no"])
.transform((val) => (val === "yes" ? true : false)),
roomPass: z.preprocess(
(val) => val || null,
z.string().regex(roompassRegExp).nullable()
),
}),
]);
type ActionData = {
@@ -135,24 +113,6 @@ export const action: ActionFunction = async ({
return { ok: "DELETE_PLAYER" };
}
case "EDIT_TEAM": {
const tournamentTeam = await TournamentTeam.findById(data.teamId);
validate(tournamentTeam, "Invalid team id");
validate(
isCaptainOfTheTeam(user, tournamentTeam),
"Not captain of the team"
);
await TournamentTeam.editTeam({
id: data.teamId,
canHost: data.canHost,
friendCode: data.friendCode,
roomPass: data.roomPass,
});
return { ok: "EDIT_TEAM" };
}
default: {
const exhaustive: never = data;
throw new Response(`Unknown action: ${JSON.stringify(exhaustive)}`, {
@@ -217,83 +177,6 @@ export default function ManageTeamPage() {
<div className="tournament__manage-team__roster-container">
<TeamRoster team={ownTeam} deleteMode={!ownTeam.checkedInTime} />
</div>
<Form method="post">
<input type="hidden" name="_action" value="EDIT_TEAM" />
<input type="hidden" name="teamId" value={ownTeam.id} />
<fieldset>
<legend>Edit team info</legend>
<Label htmlFor="friendCode">
Friend code for your opponents to add
</Label>
<input
name="friendCode"
id="friendCode"
defaultValue={ownTeam.friendCode}
required
pattern={friendCodeRegExpString}
/>
<Label className="mt-3" htmlFor="roomPass">
Room password
</Label>
<input
name="roomPass"
id="roomPass"
defaultValue={ownTeam.roomPass ?? undefined}
placeholder="1234"
pattern={roompassRegExpString}
/>
<FormInfoText>
If blank the password will be randomly generated whenever you host
</FormInfoText>
<Label className="mt-3" htmlFor="canHost">
Does your team want to host?
</Label>
<div className="tournament__manage-team__radio-with-label">
<input
type="radio"
id="yes"
name="canHost"
value="yes"
defaultChecked={ownTeam.canHost}
/>
<Label
className="tournament__manage-team__radio-label"
htmlFor="yes"
>
Yes
</Label>
</div>
<div className="tournament__manage-team__radio-with-label">
<input
type="radio"
id="no"
name="canHost"
value="no"
defaultChecked={!ownTeam.canHost}
/>
<Label
className="tournament__manage-team__radio-label"
htmlFor="no"
>
No
</Label>
</div>
<FormInfoText>
You might still have to host if both teams prefer not to
</FormInfoText>
<SubmitButton
className="mt-4"
loadingText="Saving..."
successText="Saved!"
actionType="EDIT_TEAM"
>
Save
</SubmitButton>
</fieldset>
</Form>
{ownTeam.members.length < TOURNAMENT_TEAM_ROSTER_MAX_SIZE && (
<AddPlayers
pathname={location.pathname.replace("manage-team", "join-team")}

View File

@@ -12,21 +12,16 @@ import {
} from "remix";
import invariant from "tiny-invariant";
import { Button } from "~/components/Button";
import { Catcher } from "~/components/Catcher";
import { FormErrorMessage } from "~/components/FormErrorMessage";
import { Label } from "~/components/Label";
import { useUser } from "~/hooks/common";
import {
createTournamentTeam,
FindTournamentByNameForUrlI,
} from "~/services/tournament";
import styles from "~/styles/tournament-register.css";
import { useUser } from "~/hooks/common";
import { requireUser } from "~/utils";
import { Catcher } from "~/components/Catcher";
import {
friendCodeRegExp,
friendCodeRegExpString,
} from "~/core/tournament/utils";
import { FormInfoText } from "~/components/FormInfoText";
import { Label } from "~/components/Label";
export const links: LinksFunction = () => {
return [{ rel: "stylesheet", href: styles }];
@@ -39,7 +34,6 @@ type ActionData = {
fieldErrors?: { teamName?: string };
fields?: {
teamName: string;
friendCode: string;
};
};
@@ -54,10 +48,6 @@ export const action: ActionFunction = async ({
typeof data.tournamentId === "string",
"Invalid type for tournament id"
);
invariant(
typeof data.friendCode === "string",
"Invalid type for friend code"
);
if (
data.teamName.length < TEAM_NAME_MIN_LENGTH ||
@@ -69,10 +59,6 @@ export const action: ActionFunction = async ({
);
}
if (!friendCodeRegExp.test(data.friendCode)) {
return new Response("Invalid friend code", { status: 400 });
}
const user = requireUser(context);
// TODO: validate can register for tournament i.e. reg is open
@@ -81,7 +67,6 @@ export const action: ActionFunction = async ({
await createTournamentTeam({
teamName: data.teamName,
tournamentId: data.tournamentId,
friendCode: data.friendCode,
userId: user.id,
});
} catch (e) {
@@ -89,7 +74,7 @@ export const action: ActionFunction = async ({
if (e.code === "P2002" && e.message.includes("`name`")) {
return {
fieldErrors: { teamName: "Team name already taken." },
fields: { teamName: data.teamName, friendCode: data.friendCode },
fields: { teamName: data.teamName },
};
}
}
@@ -149,19 +134,6 @@ export default function RegisterPage() {
data-cy="team-name-input"
/>
<FormErrorMessage errorMsg={actionData?.fieldErrors?.teamName} />
<Label className="mt-3" htmlFor="friendCode">
Friend code for your opponents to add
</Label>
<input
name="friendCode"
id="friendCode"
defaultValue={actionData?.fields?.friendCode}
required
data-cy="friend-code-input"
placeholder="1234-1234-1234"
pattern={friendCodeRegExpString}
/>
<FormInfoText>Friend code can be changed later</FormInfoText>
<div className="tournament__register__buttons-container">
<Button
type="submit"

View File

@@ -0,0 +1,15 @@
/*
Warnings:
- You are about to drop the column `canHost` on the `TournamentTeam` table. All the data in the column will be lost.
- You are about to drop the column `friendCode` on the `TournamentTeam` table. All the data in the column will be lost.
- You are about to drop the column `roomPass` on the `TournamentTeam` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "TournamentTeam" DROP COLUMN "canHost",
DROP COLUMN "friendCode",
DROP COLUMN "roomPass";
-- AlterTable
ALTER TABLE "User" ADD COLUMN "canVc" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -20,6 +20,7 @@ model User {
youtubeName String?
miniBio String?
friendCode String?
canVc Boolean @default(false)
weapons String[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@ -94,9 +95,6 @@ model TournamentTeam {
id String @id @default(uuid())
name String
tournamentId String
canHost Boolean @default(true)
friendCode String
roomPass String?
inviteCode String @default(uuid())
checkedInTime DateTime?
createdAt DateTime @default(now())

View File

@@ -184,7 +184,6 @@ export async function seed(variation?: SeedVariations) {
data: {
name: "Kraken Paradise",
tournamentId,
friendCode: "1234-1234-1234",
inviteCode: "033e3695-0421-4aa1-a5ef-6ee82297a398",
checkedInTime:
variation === "match" || variation === "tournament-start"
@@ -220,7 +219,6 @@ export async function seed(variation?: SeedVariations) {
data: {
name: mockTeam,
tournamentId,
friendCode: "0123-4567-8910",
checkedInTime: memberCount >= 4 ? new Date() : undefined,
},
});