mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-29 06:43:17 -05:00
@@ -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
|
||||
|
||||
@@ -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<TournamentTeamMember, "userId" | "isOwner"> &
|
||||
Pick<User, "discordAvatar" | "discordId" | "discordName">
|
||||
Pick<
|
||||
UserWithPlusTier,
|
||||
"discordAvatar" | "discordId" | "discordName" | "plusTier"
|
||||
>
|
||||
>;
|
||||
mapPool: Array<Pick<MapPoolMap, "mode" | "stageId">>;
|
||||
}
|
||||
|
||||
@@ -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<typeof loader>;
|
||||
@@ -38,6 +39,7 @@ export const handle: SendouRouteHandle = {
|
||||
i18n: ["tournament"],
|
||||
};
|
||||
|
||||
export type TournamentToolsTeam = Unpacked<TournamentToolsLoaderData["teams"]>;
|
||||
export type TournamentToolsLoaderData = SerializeFrom<typeof loader>;
|
||||
|
||||
export const loader = async ({ params, request }: LoaderArgs) => {
|
||||
|
||||
@@ -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 (
|
||||
<Main className="stack lg">
|
||||
{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 (
|
||||
<div key={team.id} className="stack sm items-center">
|
||||
<div className="tournament__pick-status-container">
|
||||
<Image
|
||||
path={navIconUrl("maps")}
|
||||
alt={t("tournament:teams.mapsPickedStatus")}
|
||||
title={t("tournament:teams.mapsPickedStatus")}
|
||||
height={16}
|
||||
width={16}
|
||||
/>
|
||||
{hasMapPool() ? (
|
||||
<CheckmarkIcon className="fill-success" />
|
||||
) : (
|
||||
<AlertIcon className="fill-warning" />
|
||||
)}
|
||||
return (
|
||||
<div key={team.id} className="stack sm items-center">
|
||||
<div className="tournament__pick-status-container">
|
||||
<Image
|
||||
path={navIconUrl("maps")}
|
||||
alt={t("tournament:teams.mapsPickedStatus")}
|
||||
title={t("tournament:teams.mapsPickedStatus")}
|
||||
height={16}
|
||||
width={16}
|
||||
/>
|
||||
{hasMapPool() ? (
|
||||
<CheckmarkIcon className="fill-success" />
|
||||
) : (
|
||||
<AlertIcon className="fill-warning" />
|
||||
)}
|
||||
</div>
|
||||
<TeamWithRoster team={team} />
|
||||
</div>
|
||||
<TeamWithRoster team={team} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
);
|
||||
})}
|
||||
</Main>
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user