+ );
+}
diff --git a/app/features/tournament-bracket/components/TeamRosterInputs.tsx b/app/features/tournament-bracket/components/TeamRosterInputs.tsx
new file mode 100644
index 000000000..1f13c5af8
--- /dev/null
+++ b/app/features/tournament-bracket/components/TeamRosterInputs.tsx
@@ -0,0 +1,200 @@
+import clsx from "clsx";
+import clone from "just-clone";
+import * as React from "react";
+import { TOURNAMENT } from "../../tournament/tournament-constants";
+import { Label } from "~/components/Label";
+import type {
+ TournamentLoaderData,
+ TournamentLoaderTeam,
+} from "../../tournament/routes/to.$id";
+import type { Unpacked } from "~/utils/types";
+import { inGameNameWithoutDiscriminator } from "~/utils/strings";
+import { useLoaderData } from "@remix-run/react";
+import type { TournamentMatchLoaderData } from "../routes/to.$id.matches.$mid";
+import type { Result } from "./ScoreReporter";
+
+export type TeamRosterInputsType = "DEFAULT" | "DISABLED" | "PRESENTATIONAL";
+
+/** Inputs to select who played for teams in a match as well as the winner. Can also be used in a presentational way. */
+export function TeamRosterInputs({
+ teams,
+ winnerId,
+ setWinnerId,
+ checkedPlayers,
+ setCheckedPlayers,
+ result,
+}: {
+ teams: [TournamentLoaderTeam, TournamentLoaderTeam];
+ winnerId?: number | null;
+ setWinnerId: (newId?: number) => void;
+ checkedPlayers: [number[], number[]];
+ setCheckedPlayers?: (newPlayerIds: [number[], number[]]) => void;
+ result?: Result;
+}) {
+ const presentational = Boolean(result);
+
+ const data = useLoaderData();
+ const inputMode = (
+ team: Unpacked
+ ): TeamRosterInputsType => {
+ if (presentational) return "PRESENTATIONAL";
+
+ // Disabled in this case because we expect a result to have exactly
+ // TOURNAMENT_TEAM_ROSTER_MIN_SIZE members per team when reporting it
+ // so there is no point to let user to change them around
+ if (team.members.length <= TOURNAMENT.TEAM_MIN_MEMBERS_FOR_FULL) {
+ return "DISABLED";
+ }
+
+ return "DEFAULT";
+ };
+
+ React.useEffect(() => {
+ setWinnerId(undefined);
+ }, [data, setWinnerId]);
+
+ return (
+
- You can still play without submitting roster, but you might be seeded
- lower in the bracket.
+ At least {TOURNAMENT.TEAM_MIN_MEMBERS_FOR_FULL} members are required to
+ participate. Max roster size is {TOURNAMENT.TEAM_MAX_MEMBERS}.
+ >
+ );
+}
+
+export const CatchBoundary = Catcher;
diff --git a/app/features/tournament/routes/to.$id.teams.tsx b/app/features/tournament/routes/to.$id.teams.tsx
index 74f0523f6..e3597b6c2 100644
--- a/app/features/tournament/routes/to.$id.teams.tsx
+++ b/app/features/tournament/routes/to.$id.teams.tsx
@@ -1,17 +1,12 @@
import { Link, useOutletContext } from "@remix-run/react";
import { Avatar } from "~/components/Avatar";
-import { AlertIcon } from "~/components/icons/Alert";
-import { CheckmarkIcon } from "~/components/icons/Checkmark";
-import { Image } from "~/components/Image";
-import { useTranslation } from "~/hooks/useTranslation";
-import { navIconUrl, userPage } from "~/utils/urls";
-import type { FindTeamsByEventIdItem } from "../queries/findTeamsByEventId.server";
+import { userPage } from "~/utils/urls";
+import type { FindTeamsByTournamentIdItem } from "../queries/findTeamsByTournamentId.server";
import { TOURNAMENT } from "../tournament-constants";
-import type { TournamentToolsLoaderData, TournamentToolsTeam } from "./to.$id";
+import type { TournamentLoaderData, TournamentLoaderTeam } from "./to.$id";
-export default function TournamentToolsTeamsPage() {
- const { t } = useTranslation(["tournament"]);
- const data = useOutletContext();
+export default function TournamentTeamsPage() {
+ const data = useOutletContext();
return (
@@ -19,35 +14,7 @@ export default function TournamentToolsTeamsPage() {
.slice()
.sort(fullTeamAndHigherPlusStatusOnTop)
.map((team) => {
- const hasMapPool = () => {
- // before start empty array is returned if team has map list
- // after start empty array means team has no map list
- if (!data.mapListGeneratorAvailable) {
- return Boolean(team.mapPool);
- }
-
- return team.mapPool && team.mapPool.length > 0;
- };
-
- return (
-