Files
wm-projekt/app/components/Bracket.tsx
2026-06-22 15:44:54 -05:00

123 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { GroupTable, Match, Team, ThirdPlaceRow } from "@/lib/types";
import { ThirdAssignment } from "@/lib/bracket";
import { resolveBracket, ResolvedSide, ResolvedTie } from "@/lib/resolve-bracket";
import Flag from "./Flag";
function Side({
s, prob, teams,
}: { s: ResolvedSide; prob?: number | null; teams: Team[] }) {
const team = s.teamId ? teams.find((t) => t.id === s.teamId) : undefined;
return (
<div className={`side ${s.isWinner ? "win" : ""} ${s.provisional ? "prov" : ""}`}>
<span className="nm">
{s.teamId ? (
<>
<Flag team={team} size={18} />
<span>{s.label}</span>
{s.provisional && <span className="prov-mark" title="vorläufig Gruppe/Zuordnung noch nicht fix"></span>}
</>
) : (
<span className="lbl">{s.label}</span>
)}
{prob != null && prob > 0 && (
<span className="prob">{Math.round(prob * 100)}%</span>
)}
</span>
<span className="sc">{s.score != null ? s.score : ""}</span>
</div>
);
}
function Tie({ tie, teams, isFinal }: { tie: ResolvedTie; teams: Team[]; isFinal?: boolean }) {
return (
<div className={`tie ${isFinal ? "final-tie" : ""}`}>
<span className="tie-num">Spiel {tie.matchNumber}</span>
<Side s={tie.home} prob={tie.prob?.home} teams={teams} />
<Side s={tie.away} prob={tie.prob?.away} teams={teams} />
</div>
);
}
export default function Bracket({
matches, teams, tables, thirds, assignment, annexResolved,
}: {
matches: Match[]; teams: Team[]; tables: GroupTable[];
thirds: ThirdPlaceRow[]; assignment: ThirdAssignment | null; annexResolved: boolean;
}) {
const { r32, later } = resolveBracket(
matches, teams, tables, thirds, assignment, annexResolved,
);
const pick = (nums: number[]) => nums.map((n) => later[n]).filter(Boolean);
const r16 = pick([89, 90, 91, 92, 93, 94, 95, 96]);
const qf = pick([97, 98, 99, 100]);
const sf = pick([101, 102]);
const fin = later[104];
const third = later[103];
return (
<div>
<div className="bracket-banner">
<span className="k">Annex-C-Zuordnung der Drittplatzierten:</span>
<span className="v">
{annexResolved
? "aufgelöst — die acht Dritten sind den Gruppensiegern fest zugeteilt"
: "noch offen — sobald die 8 besten Dritten feststehen, verbindet sich der Baum automatisch"}
</span>
</div>
<div className="bracket-scroll">
<div className="bracket">
<div className="round">
<div className="round-label">Letzte 32</div>
<div className="round-matches">
{r32.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} />)}
</div>
</div>
<div className="round">
<div className="round-label">Achtelfinale</div>
<div className="round-matches">
{r16.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} />)}
</div>
</div>
<div className="round">
<div className="round-label">Viertelfinale</div>
<div className="round-matches">
{qf.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} />)}
</div>
</div>
<div className="round">
<div className="round-label">Halbfinale</div>
<div className="round-matches">
{sf.map((t) => <Tie key={t.matchNumber} tie={t} teams={teams} />)}
</div>
</div>
<div className="round">
<div className="round-label">Finale</div>
<div className="round-matches">
{fin && <Tie tie={fin} teams={teams} isFinal />}
{third && (
<div style={{ marginTop: 20 }}>
<div className="round-label" style={{ marginBottom: 8 }}>Spiel um Platz 3</div>
<Tie tie={third} teams={teams} />
</div>
)}
</div>
</div>
</div>
</div>
<div className="legend">
<span><i style={{ background: "var(--turf)" }} />Sieger / weiter</span>
<span><i style={{ background: "var(--gold)" }} />Finale</span>
<span><i className="leg-fix" />fix qualifiziert</span>
<span><i className="leg-prov" />vorläufig (, nach aktueller Tabelle)</span>
<span><i style={{ background: "var(--ink-faint)" }} />Platzhalter offen</span>
<span>%-Werte: Polymarket-Wahrscheinlichkeit (falls verfügbar)</span>
</div>
</div>
);
}