Loser team source info shown

This commit is contained in:
Kalle (Sendou)
2022-01-06 23:01:30 +02:00
parent 58a0356615
commit 16f5691424
4 changed files with 133 additions and 65 deletions

View File

@@ -3,6 +3,7 @@ import invariant from "tiny-invariant";
import { matchIsOver } from "~/core/tournament/utils";
import type { BracketModified } from "~/services/tournament";
import { MyCSSProperties, Unpacked } from "~/utils";
import { EliminationBracketMatch } from "./EliminationBracketMatch";
export function EliminationBracket({
bracketSide,
@@ -84,7 +85,7 @@ export function EliminationBracket({
{round.matches.map((match) => {
// TODO: handle losers
return (
<Match
<EliminationBracketMatch
hidden={
round.name.includes("Winner") &&
roundI === 0 &&
@@ -137,65 +138,3 @@ function RoundInfo({
</div>
);
}
export function Match({
match,
hidden,
ownTeamName,
isOver,
}: {
match: Unpacked<Unpacked<BracketModified["winners"]>["matches"]>;
hidden?: boolean;
ownTeamName?: string;
isOver: boolean;
}) {
return (
<div className={clsx("tournament-bracket__elim__match", { hidden })}>
<div className="tournament-bracket__elim__roundNumber">
{match.number}
</div>
<div
className={clsx(
"tournament-bracket__elim__team",
"tournament-bracket__elim__teamOne",
{
own:
!isOver && ownTeamName && ownTeamName === match.participants?.[0],
defeated:
isOver && (match.score?.[0] ?? 0) < (match.score?.[1] ?? 0),
}
)}
>
{match.participants?.[0]}{" "}
<span
className={clsx("tournament-bracket__elim__score", {
invisible: typeof match.score?.[0] !== "number",
})}
>
{match.score?.[0] ?? 0}
</span>
</div>
<div
className={clsx(
"tournament-bracket__elim__team",
"tournament-bracket__elim__teamTwo",
{
own:
!isOver && ownTeamName && ownTeamName === match.participants?.[1],
defeated:
isOver && (match.score?.[1] ?? 0) < (match.score?.[0] ?? 0),
}
)}
>
{match.participants?.[1]}{" "}
<span
className={clsx("tournament-bracket__elim__score", {
invisible: typeof match.score?.[0] !== "number",
})}
>
{match.score?.[1] ?? 0}
</span>
</div>
</div>
);
}

View File

@@ -0,0 +1,76 @@
import clsx from "clsx";
import type { BracketModified } from "~/services/tournament";
import { Unpacked } from "~/utils";
export function EliminationBracketMatch({
match,
hidden,
ownTeamName,
isOver,
}: {
match: Unpacked<Unpacked<BracketModified["winners"]>["matches"]>;
hidden?: boolean;
ownTeamName?: string;
isOver: boolean;
}) {
const cellText = (index: number) => {
if (match.participants?.[index]) return match.participants?.[index];
if (match.participantSourceMatches?.[index]) {
return (
<i className="tournament-bracket__elim__loser-info">{`Loser of match ${match.participantSourceMatches?.[index]}`}</i>
);
}
return null;
};
return (
<div className={clsx("tournament-bracket__elim__match", { hidden })}>
<div className="tournament-bracket__elim__roundNumber">
{match.number}
</div>
<div
className={clsx(
"tournament-bracket__elim__team",
"tournament-bracket__elim__teamOne",
{
own:
!isOver && ownTeamName && ownTeamName === match.participants?.[0],
defeated:
isOver && (match.score?.[0] ?? 0) < (match.score?.[1] ?? 0),
}
)}
>
{cellText(0)}
<span
className={clsx("tournament-bracket__elim__score", {
invisible: typeof match.score?.[0] !== "number",
})}
>
{match.score?.[0] ?? 0}
</span>
</div>
<div
className={clsx(
"tournament-bracket__elim__team",
"tournament-bracket__elim__teamTwo",
{
own:
!isOver && ownTeamName && ownTeamName === match.participants?.[1],
defeated:
isOver && (match.score?.[1] ?? 0) < (match.score?.[0] ?? 0),
}
)}
>
{cellText(1)}{" "}
<span
className={clsx("tournament-bracket__elim__score", {
invisible: typeof match.score?.[0] !== "number",
})}
>
{match.score?.[1] ?? 0}
</span>
</div>
</div>
);
}

View File

@@ -147,6 +147,10 @@ type BracketModifiedSide = {
number: number;
score?: [upperTeamScore: number, lowerTeamScore: number];
participants?: [upperTeamName: string | null, lowerTeamName: string | null];
participantSourceMatches?: [
upperTeamSourceMatchNumber: number | null,
lowerTeamSourceMatchNumber: number | null
];
winnerDestinationMatchId: string | null;
loserDestinationMatchId: string | null;
}[];
@@ -165,12 +169,20 @@ export async function bracketById(bracketId: string): Promise<BracketModified> {
.filter((round) => round.position < 0)
.sort((a, b) => b.position - a.position);
const winners = modifyRounds(
winnersRounds,
"winners",
losersRounds.length === 0
);
const losers = modifyRounds(losersRounds, "losers", false);
return {
winners: modifyRounds(winnersRounds, "winners", losersRounds.length === 0),
losers: modifyRounds(losersRounds, "losers", false),
winners,
losers: addLoserTeamSourceInfo({ winners, losers }),
};
}
// TODO: rename
function modifyRounds(
rounds: NonNullable<TournamentBracket.FindById>["rounds"],
side: EliminationBracketSide,
@@ -220,6 +232,40 @@ function modifyRounds(
});
}
function addLoserTeamSourceInfo({
winners,
losers,
}: {
winners: BracketModifiedSide;
losers: BracketModifiedSide;
}): BracketModifiedSide {
const matchIdToSourceMatchNumber = winners
.flatMap((round) => round.matches)
.reduce((acc: Map<string, number[]>, match) => {
if (!match.loserDestinationMatchId) return acc;
return acc.set(
match.loserDestinationMatchId,
(acc.get(match.loserDestinationMatchId) ?? [])
.concat(match.number)
.sort((a, b) => a - b)
);
}, new Map());
return losers.map((round) => ({
...round,
matches: round.matches.map((match) => {
const sourceMatches = matchIdToSourceMatchNumber.get(match.id);
return {
...match,
participantSourceMatches: sourceMatches
? [sourceMatches[0] ?? null, sourceMatches[1] ?? null]
: undefined,
};
}),
}));
}
export const createTournamentTeam = TournamentTeam.create;
export async function createTournamentRounds({

View File

@@ -230,6 +230,13 @@
grid-area: team-two;
}
.tournament-bracket__elim__loser-info {
display: flex;
align-items: center;
color: var(--text-lighter);
font-size: var(--fonts-xs);
}
.tournament-bracket__elim__score {
font-weight: bold;
}