mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-01 23:58:36 -05:00
Remove unnecessary fields from tournament team
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -71,9 +71,6 @@ export async function findByNameForUrl({
|
||||
id: true,
|
||||
name: true,
|
||||
createdAt: true,
|
||||
friendCode: true,
|
||||
roomPass: true,
|
||||
canHost: true,
|
||||
inviteCode: withInviteCodes,
|
||||
members: {
|
||||
select: {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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")}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
@@ -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())
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user