This commit is contained in:
2026-06-22 22:11:04 -05:00
parent 73d07e7f18
commit 93ae2cbf0a
9 changed files with 519 additions and 53 deletions

View File

@@ -1,4 +1,5 @@
import { GroupId, Match, MatchStatus, Team } from "./types";
import { venueFor } from "./venues";
// ----------------------------------------------------------------------------
// Caching: einfacher In-Memory-Cache mit TTL. Verhindert, dass jede Browser-
@@ -80,6 +81,32 @@ function stageFor(stage: string, group: GroupId | null): Match["stage"] {
}
}
// Phasen-Reihenfolge für die K.o.-Nummerierung.
const STAGE_ORDER: Record<Match["stage"], number> = {
GROUP: 0, R32: 1, R16: 2, QF: 3, SF: 4, "3RD": 5, FINAL: 6,
};
// Setzt Spielnummern und Stadien.
// - K.o.-Spiele: chronologisch ab 73 (Anstöße dort eindeutig) -> für Bracket nötig.
// - Venue: Gruppenspiele über die Teampaarung, K.o.-Spiele über die Spielnummer.
function assignNumbersAndVenues(matches: Match[], teams: Team[]): void {
// K.o.-Spiele eindeutig durchnummerieren (73..104).
const ko = matches
.filter((m) => m.group == null)
.sort((a, b) => {
const sa = STAGE_ORDER[a.stage], sb = STAGE_ORDER[b.stage];
if (sa !== sb) return sa - sb;
const t = +new Date(a.utcDate) - +new Date(b.utcDate);
return t !== 0 ? t : Number(a.id) - Number(b.id);
});
ko.forEach((m, i) => { m.matchNumber = 73 + i; });
// Stadien setzen (Gruppenphase per Paarung, K.o. per Nummer).
for (const m of matches) {
m.venue = venueFor(m, teams);
}
}
// Holt alle Spiele + leitet die Teamliste daraus ab (spart einen Extra-Call).
export async function fetchMatchesAndTeams(): Promise<{ matches: Match[]; teams: Team[] }> {
return cached("fd:matches", 60_000, async () => {
@@ -110,7 +137,8 @@ export async function fetchMatchesAndTeams(): Promise<{ matches: Match[]; teams:
id: String(m.id),
group,
stage: stageFor(m.stage, group),
matchNumber: m.matchday ?? 0,
// Vorläufig 0 — die echte FIFA-Spielnummer wird unten gesetzt.
matchNumber: 0,
utcDate: m.utcDate,
status: mapStatus(m.status),
minute: m.minute ?? null,
@@ -118,12 +146,15 @@ export async function fetchMatchesAndTeams(): Promise<{ matches: Match[]; teams:
awayTeamId: m.awayTeam.id != null ? String(m.awayTeam.id) : null,
homeScore: m.score.fullTime.home,
awayScore: m.score.fullTime.away,
venue: m.venue ?? null,
venue: null, // wird unten aus der Map gesetzt
attendance: m.attendance ?? null,
};
});
return { matches, teams: [...teamMap.values()] };
const teams = [...teamMap.values()];
assignNumbersAndVenues(matches, teams);
return { matches, teams };
});
}
@@ -203,4 +234,4 @@ export function attachOdds(matches: Match[], teams: Team[], odds: OddsEntry[]):
},
};
});
}
}