110 lines
3.5 KiB
TypeScript
110 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import { GROUP_IDS, GroupId, Match, Team } from "@/lib/types";
|
|
import Flag from "./Flag";
|
|
|
|
function teamById(teams: Team[], id: string | null) {
|
|
return id ? teams.find((t) => t.id === id) : undefined;
|
|
}
|
|
|
|
function fmtDate(iso: string): string {
|
|
const d = new Date(iso);
|
|
return d.toLocaleString("de-DE", {
|
|
weekday: "short", day: "2-digit", month: "2-digit",
|
|
hour: "2-digit", minute: "2-digit",
|
|
});
|
|
}
|
|
|
|
function statusText(m: Match): { text: string; live: boolean } {
|
|
switch (m.status) {
|
|
case "LIVE":
|
|
case "IN_PLAY":
|
|
return { text: m.minute != null ? `${m.minute}'` : "läuft", live: true };
|
|
case "PAUSED":
|
|
return { text: "Halbzeit", live: true };
|
|
case "FINISHED":
|
|
return { text: "Beendet", live: false };
|
|
default:
|
|
return { text: fmtDate(m.utcDate), live: false };
|
|
}
|
|
}
|
|
|
|
function ScoreOrTime({ m }: { m: Match }) {
|
|
const hasScore = m.homeScore != null && m.awayScore != null;
|
|
const st = statusText(m);
|
|
if (hasScore) {
|
|
return (
|
|
<span className={`fx-score ${st.live ? "score-live" : ""}`}>
|
|
{m.homeScore} : {m.awayScore}
|
|
</span>
|
|
);
|
|
}
|
|
return <span className="fx-time">{fmtDate(m.utcDate)}</span>;
|
|
}
|
|
|
|
export default function Fixtures({
|
|
group, teams, matches, onSelectGroup,
|
|
}: {
|
|
group: GroupId; teams: Team[]; matches: Match[];
|
|
onSelectGroup: (g: GroupId) => void;
|
|
}) {
|
|
const list = matches
|
|
.filter((m) => m.group === group)
|
|
.sort((a, b) => +new Date(a.utcDate) - +new Date(b.utcDate));
|
|
|
|
return (
|
|
<div>
|
|
<div className="grp-switch">
|
|
{GROUP_IDS.map((g) => (
|
|
<button
|
|
key={g}
|
|
className={`grp-chip ${g === group ? "active" : ""}`}
|
|
onClick={() => onSelectGroup(g)}
|
|
>
|
|
{g}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{list.length === 0 ? (
|
|
<div className="notice">Für Gruppe {group} liegen noch keine Spiele im Feed vor.</div>
|
|
) : (
|
|
<div className="fixtures">
|
|
{list.map((m) => {
|
|
const home = teamById(teams, m.homeTeamId);
|
|
const away = teamById(teams, m.awayTeamId);
|
|
const st = statusText(m);
|
|
const homeWin = m.homeScore != null && m.awayScore != null && m.homeScore > m.awayScore;
|
|
const awayWin = m.homeScore != null && m.awayScore != null && m.awayScore > m.homeScore;
|
|
return (
|
|
<div className={`fx ${st.live ? "fx-live" : ""}`} key={m.id}>
|
|
<div className="fx-status">
|
|
{st.live && <span className="dot live" />}
|
|
<span>{st.text}</span>
|
|
</div>
|
|
<div className="fx-teams">
|
|
<div className={`fx-team ${homeWin ? "win" : ""}`}>
|
|
<Flag team={home} size={22} />
|
|
<span className="fx-name">{home?.name ?? "—"}</span>
|
|
</div>
|
|
<ScoreOrTime m={m} />
|
|
<div className={`fx-team away ${awayWin ? "win" : ""}`}>
|
|
<span className="fx-name">{away?.name ?? "—"}</span>
|
|
<Flag team={away} size={22} />
|
|
</div>
|
|
</div>
|
|
<div className="fx-meta">
|
|
{m.venue && <span className="fx-venue">📍 {m.venue}</span>}
|
|
{m.attendance != null && (
|
|
<span className="fx-att">👥 {m.attendance.toLocaleString("de-DE")}</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|