diff --git a/app/db/models/tournaments/findTeamsByEventId.sql b/app/db/models/tournaments/findTeamsByEventId.sql index d51dbabb9..5c6eb7683 100644 --- a/app/db/models/tournaments/findTeamsByEventId.sql +++ b/app/db/models/tournaments/findTeamsByEventId.sql @@ -13,13 +13,16 @@ with "TeamWithMembers" as ( 'discordId', "User"."discordId", 'discordAvatar', - "User"."discordAvatar" + "User"."discordAvatar", + 'plusTier', + "PlusTier"."tier" ) ) as "members" from "TournamentTeam" left join "TournamentTeamMember" on "TournamentTeamMember"."tournamentTeamId" = "TournamentTeam"."id" left join "User" on "User"."id" = "TournamentTeamMember"."userId" + left join "PlusTier" on "User"."id" = "PlusTier"."userId" where "TournamentTeam"."calendarEventId" = @calendarEventId group by diff --git a/app/db/models/tournaments/queries.server.ts b/app/db/models/tournaments/queries.server.ts index 845ea5c0a..c5defa9ae 100644 --- a/app/db/models/tournaments/queries.server.ts +++ b/app/db/models/tournaments/queries.server.ts @@ -5,6 +5,7 @@ import type { TournamentTeam, TournamentTeamMember, User, + UserWithPlusTier, } from "~/db/types"; import { databaseCreatedAt } from "~/utils/dates"; import type { MapPool } from "~/modules/map-pool-serializer"; @@ -101,7 +102,10 @@ export interface FindTeamsByEventIdItem { name: TournamentTeam["name"]; members: Array< Pick & - Pick + Pick< + UserWithPlusTier, + "discordAvatar" | "discordId" | "discordName" | "plusTier" + > >; mapPool: Array>; } diff --git a/app/routes/to.$identifier.tsx b/app/routes/to.$identifier.tsx index c0e81a4b9..9579481a5 100644 --- a/app/routes/to.$identifier.tsx +++ b/app/routes/to.$identifier.tsx @@ -19,6 +19,7 @@ import { findOwnedTeam } from "~/utils/tournaments"; import styles from "~/styles/tournament.css"; import { makeTitle } from "~/utils/strings"; import { useTranslation } from "~/hooks/useTranslation"; +import type { Unpacked } from "~/utils/types"; export const meta: MetaFunction = (args) => { const data = args.data as SerializeFrom; @@ -38,6 +39,7 @@ export const handle: SendouRouteHandle = { i18n: ["tournament"], }; +export type TournamentToolsTeam = Unpacked; export type TournamentToolsLoaderData = SerializeFrom; export const loader = async ({ params, request }: LoaderArgs) => { diff --git a/app/routes/to.$identifier/teams.tsx b/app/routes/to.$identifier/teams.tsx index ad29d5ba4..64d1628c9 100644 --- a/app/routes/to.$identifier/teams.tsx +++ b/app/routes/to.$identifier/teams.tsx @@ -3,9 +3,13 @@ import { AlertIcon } from "~/components/icons/Alert"; import { CheckmarkIcon } from "~/components/icons/Checkmark"; import { Image } from "~/components/Image"; import { Main } from "~/components/Main"; +import { TOURNAMENT } from "~/constants"; import { useTranslation } from "~/hooks/useTranslation"; import { navIconUrl } from "~/utils/urls"; -import type { TournamentToolsLoaderData } from "../to.$identifier"; +import type { + TournamentToolsLoaderData, + TournamentToolsTeam, +} from "../to.$identifier"; import { TeamWithRoster } from "./components/TeamWithRoster"; export default function TournamentToolsTeamsPage() { @@ -14,37 +18,76 @@ export default function TournamentToolsTeamsPage() { return (
- {data.teams.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.event.isBeforeStart) { - return Boolean(team.mapPool); - } + {data.teams + .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.event.isBeforeStart) { + return Boolean(team.mapPool); + } - return team.mapPool && team.mapPool.length > 0; - }; + return team.mapPool && team.mapPool.length > 0; + }; - return ( -
-
- {t("tournament:teams.mapsPickedStatus")} - {hasMapPool() ? ( - - ) : ( - - )} + return ( +
+
+ {t("tournament:teams.mapsPickedStatus")} + {hasMapPool() ? ( + + ) : ( + + )} +
+
- -
- ); - })} + ); + })}
); } + +function fullTeamAndHigherPlusStatusOnTop( + teamA: TournamentToolsTeam, + teamB: TournamentToolsTeam +) { + if ( + teamA.members.length >= TOURNAMENT.TEAM_MIN_MEMBERS_FOR_FULL && + teamB.members.length < TOURNAMENT.TEAM_MIN_MEMBERS_FOR_FULL + ) { + return -1; + } + + if ( + teamA.members.length < TOURNAMENT.TEAM_MIN_MEMBERS_FOR_FULL && + teamB.members.length >= TOURNAMENT.TEAM_MIN_MEMBERS_FOR_FULL + ) { + return 1; + } + + const lowestATeamPlusTier = Math.min( + ...teamA.members.map((m) => m.plusTier ?? Infinity) + ); + const lowestBTeamPlusTier = Math.min( + ...teamB.members.map((m) => m.plusTier ?? Infinity) + ); + + if (lowestATeamPlusTier > lowestBTeamPlusTier) { + return 1; + } + + if (lowestATeamPlusTier < lowestBTeamPlusTier) { + return -1; + } + + return 0; +}