changes
This commit is contained in:
@@ -9,13 +9,15 @@ function Side({
|
||||
s, prob, teams,
|
||||
}: { s: ResolvedSide; prob?: number | null; teams: Team[] }) {
|
||||
const team = s.teamId ? teams.find((t) => t.id === s.teamId) : undefined;
|
||||
// fix = ein echtes Team steht fest (nicht vorläufig). Eigene Klasse für klares Styling.
|
||||
const fix = s.teamId != null && !s.provisional;
|
||||
return (
|
||||
<div className={`side ${s.isWinner ? "win" : ""} ${s.provisional ? "prov" : ""}`}>
|
||||
<div className={`side ${s.isWinner ? "win" : ""} ${s.provisional ? "prov" : ""} ${fix ? "fix" : ""}`}>
|
||||
<span className="nm">
|
||||
{s.teamId ? (
|
||||
<>
|
||||
<Flag team={team} size={18} />
|
||||
<span>{s.label}</span>
|
||||
<span className="tn">{s.label}</span>
|
||||
{s.provisional && <span className="prov-mark" title="vorläufig – Gruppe/Zuordnung noch nicht fix">≈</span>}
|
||||
</>
|
||||
) : (
|
||||
@@ -33,7 +35,7 @@ function Side({
|
||||
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>
|
||||
<div className="tie-head">Spiel {tie.matchNumber}</div>
|
||||
<Side s={tie.home} prob={tie.prob?.home} teams={teams} />
|
||||
<Side s={tie.away} prob={tie.prob?.away} teams={teams} />
|
||||
</div>
|
||||
@@ -119,4 +121,4 @@ export default function Bracket({
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,31 @@
|
||||
"use client";
|
||||
|
||||
import { GROUP_IDS, GroupId, Match, Team } from "@/lib/types";
|
||||
import { computeGroupTables } from "@/lib/standings";
|
||||
import Flag from "./Flag";
|
||||
|
||||
function teamById(teams: Team[], id: string | null) {
|
||||
return id ? teams.find((t) => t.id === id) : undefined;
|
||||
}
|
||||
|
||||
// Kürzel der lokalen Browser-Zeitzone, z.B. "MEZ"/"GMT+1" – einmal ermittelt.
|
||||
const TZ_LABEL = (() => {
|
||||
try {
|
||||
const parts = new Intl.DateTimeFormat("de-DE", { timeZoneName: "short" })
|
||||
.formatToParts(new Date());
|
||||
return parts.find((p) => p.type === "timeZoneName")?.value ?? "";
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
})();
|
||||
|
||||
function fmtDate(iso: string): string {
|
||||
const d = new Date(iso);
|
||||
return d.toLocaleString("de-DE", {
|
||||
const s = d.toLocaleString("de-DE", {
|
||||
weekday: "short", day: "2-digit", month: "2-digit",
|
||||
hour: "2-digit", minute: "2-digit",
|
||||
});
|
||||
return TZ_LABEL ? `${s} ${TZ_LABEL}` : s;
|
||||
}
|
||||
|
||||
function statusText(m: Match): { text: string; live: boolean } {
|
||||
@@ -29,7 +42,10 @@ function statusText(m: Match): { text: string; live: boolean } {
|
||||
}
|
||||
}
|
||||
|
||||
function ScoreOrTime({ m }: { m: Match }) {
|
||||
// Mitte: Ergebnis (wenn vorhanden) oder ein schlichtes "–" bei ungespielten
|
||||
// Spielen. Datum/Uhrzeit steht bereits links im Status und wird hier NICHT
|
||||
// wiederholt.
|
||||
function ScoreCell({ m }: { m: Match }) {
|
||||
const hasScore = m.homeScore != null && m.awayScore != null;
|
||||
const st = statusText(m);
|
||||
if (hasScore) {
|
||||
@@ -39,7 +55,69 @@ function ScoreOrTime({ m }: { m: Match }) {
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return <span className="fx-time">{fmtDate(m.utcDate)}</span>;
|
||||
return <span className="fx-vs">–</span>;
|
||||
}
|
||||
|
||||
function GroupStandings({
|
||||
group, teams, matches,
|
||||
}: { group: GroupId; teams: Team[]; matches: Match[] }) {
|
||||
// Live-Tabelle: laufende Spiele werden mit Zwischenstand eingerechnet.
|
||||
const table = computeGroupTables(teams, matches, true).find((t) => t.group === group);
|
||||
if (!table) return null;
|
||||
|
||||
// Teams, die gerade ein laufendes Spiel haben -> Zeile markieren.
|
||||
const liveTeamIds = new Set<string>();
|
||||
let hasLive = false;
|
||||
for (const m of matches) {
|
||||
if (m.group !== group) continue;
|
||||
if (m.status === "LIVE" || m.status === "IN_PLAY" || m.status === "PAUSED") {
|
||||
hasLive = true;
|
||||
if (m.homeTeamId) liveTeamIds.add(m.homeTeamId);
|
||||
if (m.awayTeamId) liveTeamIds.add(m.awayTeamId);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fx-standings">
|
||||
<div className="fx-standings-title">
|
||||
Tabelle – Gruppe {group}
|
||||
{hasLive && <span className="fx-standings-live">● LIVE</span>}
|
||||
</div>
|
||||
<table className="standings">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="team">Mannschaft</th>
|
||||
<th>Sp</th><th>S</th><th>U</th><th>N</th>
|
||||
<th>Tore</th><th>±</th><th>Pkt</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{table.rows.map((r) => {
|
||||
const team = teamById(teams, r.teamId);
|
||||
const cls = r.rank <= 2 ? `q${r.rank}` : r.rank === 3 ? "q3" : "";
|
||||
const isLive = liveTeamIds.has(r.teamId);
|
||||
return (
|
||||
<tr key={r.teamId} className={isLive ? "row-live" : ""}>
|
||||
<td className="team">
|
||||
<span className={`rankdot ${cls}`}>{r.rank}</span>
|
||||
<Flag team={team} size={20} />
|
||||
<span className="team-name">{team?.name ?? r.teamId}</span>
|
||||
{isLive && <span className="row-live-dot" title="läuft gerade" />}
|
||||
</td>
|
||||
<td>{r.played}</td>
|
||||
<td>{r.won}</td>
|
||||
<td>{r.drawn}</td>
|
||||
<td>{r.lost}</td>
|
||||
<td>{r.goalsFor}:{r.goalsAgainst}</td>
|
||||
<td>{r.goalDiff > 0 ? `+${r.goalDiff}` : r.goalDiff}</td>
|
||||
<td className="pts">{r.points}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default function Fixtures({
|
||||
@@ -83,14 +161,14 @@ export default function Fixtures({
|
||||
<span>{st.text}</span>
|
||||
</div>
|
||||
<div className="fx-teams">
|
||||
<div className={`fx-team ${homeWin ? "win" : ""}`}>
|
||||
<div className={`fx-team home ${homeWin ? "win" : ""}`}>
|
||||
<Flag team={home} size={22} />
|
||||
<span className="fx-name">{home?.name ?? "—"}</span>
|
||||
</div>
|
||||
<ScoreOrTime m={m} />
|
||||
<ScoreCell m={m} />
|
||||
<div className={`fx-team away ${awayWin ? "win" : ""}`}>
|
||||
<span className="fx-name">{away?.name ?? "—"}</span>
|
||||
<Flag team={away} size={22} />
|
||||
<span className="fx-name">{away?.name ?? "—"}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="fx-meta">
|
||||
@@ -104,6 +182,10 @@ export default function Fixtures({
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{list.length > 0 && (
|
||||
<GroupStandings group={group} teams={teams} matches={matches} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user