Files
valknar 2bd32daae1 fix: show 0-0 for live matches with no score data; exclude live from recent
MatchCard: display '0–0' instead of '?–?' when a match is live but
score_ft_home is still NULL (sync hasn't picked up the score yet, or
Wikipedia hasn't been updated — every match starts at 0-0).

recentMatches resolver: fetch limit*2 rows then filter out live matches
so a match with score_ft_home=0 that is still in progress doesn't appear
in both the live section and recent results simultaneously.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 20:00:07 +02:00

123 lines
5.5 KiB
TypeScript
Raw Permalink 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.
import Link from 'next/link'
import { TeamFlag } from './team-flag'
import { LiveBadge } from './live-badge'
interface Team { name: string; iso2?: string | null; slug?: string | null }
interface Match {
id: number
year: number
round: string
group?: string | null
date?: string | null
time?: string | null
team1: Team
team2: Team
scoreFt?: number[] | null
scoreEt?: number[] | null
scoreP?: number[] | null
isLive: boolean
}
function formatDate(d: string) {
return new Date(d).toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' })
}
export function MatchCard({ match, compact = false }: { match: Match; compact?: boolean }) {
const ft = match.scoreFt
const hasScore = ft != null
// Winner: penalties first, then ET, then FT
const decisive = match.scoreP ?? match.scoreEt ?? ft
const winner = decisive ? (decisive[0] > decisive[1] ? 'home' : decisive[0] < decisive[1] ? 'away' : 'draw') : null
if (compact) {
return (
<Link href={`/tournaments/${match.year}#match-${match.id}`} className="block">
<div className="glass-card rounded-xl p-3.5 hover:border-green/[22%] transition-colors">
<div className="text-[9px] text-green-muted tracking-[0.1em] uppercase mb-2.5">
{match.round}{match.group ? ` · ${match.group}` : ''} · {match.date ? formatDate(match.date) : ''}
</div>
<div className="flex items-center gap-2">
<div className="flex-1 flex items-center gap-2 overflow-hidden">
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="sm" />
<span className={`text-sm font-medium truncate ${winner === 'home' ? 'text-text' : 'text-green-mid'}`}>
{match.team1.name}
</span>
</div>
<div className="flex-shrink-0 min-w-[52px] text-center">
<div className="font-['Bebas_Neue'] text-xl text-green">
{hasScore
? match.scoreP
? `${match.scoreP[0]} ${match.scoreP[1]}`
: match.scoreEt
? `${match.scoreEt[0]} ${match.scoreEt[1]}`
: `${ft![0]} ${ft![1]}`
: match.isLive ? '0 0' : ''}
</div>
{match.scoreP && (
<div className="text-[8px] text-green-muted leading-none">
{ft![0]}{ft![1]} a.e.t.
</div>
)}
{match.scoreEt && !match.scoreP && (
<div className="text-[8px] text-green-muted leading-none">a.e.t.</div>
)}
</div>
<div className="flex-1 flex items-center justify-end gap-2 overflow-hidden">
<span className={`text-sm font-medium truncate ${winner === 'away' ? 'text-text' : 'text-green-mid'}`}>
{match.team2.name}
</span>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="sm" />
</div>
</div>
{match.scoreEt && !match.scoreP && (
<div className="text-[9px] text-green-muted mt-1 text-center">a.e.t.</div>
)}
</div>
</Link>
)
}
const matchHref = `/tournaments/${match.year}#match-${match.id}`
return (
<div className="glass-card-hero rounded-2xl px-5 py-6 sm:px-9 sm:py-9 hover:border-green/45 transition-colors">
{match.isLive && <div className="mb-4"><LiveBadge label="Live Now" /></div>}
<div className="grid grid-cols-[1fr_auto_1fr] items-center gap-3 sm:gap-8">
<Link href={match.team1.slug ? `/teams/${match.team1.slug}` : matchHref}
className={`text-center block transition-colors hover:text-green ${winner === 'home' ? 'text-text' : 'text-green-sec'}`}>
<TeamFlag name={match.team1.name} iso2={match.team1.iso2} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate">
{match.team1.name}
</div>
</Link>
<Link href={matchHref} className="text-center flex-shrink-0 block">
<div className="font-['Bebas_Neue'] text-[48px] sm:text-[76px] text-green leading-none hover:opacity-80 transition-opacity">
{hasScore
? match.scoreP
? `${match.scoreP[0]}${match.scoreP[1]}`
: match.scoreEt
? `${match.scoreEt[0]}${match.scoreEt[1]}`
: `${ft![0]}${ft![1]}`
: match.isLive ? '00' : '??'}
</div>
{match.scoreP && (
<div className="text-[10px] text-green-muted mt-0.5">{ft![0]}{ft![1]} a.e.t.</div>
)}
{match.scoreEt && !match.scoreP && (
<div className="text-[10px] text-green-muted mt-0.5">{ft![0]}{ft![1]} (a.e.t.)</div>
)}
<div className="text-[9px] text-green-muted tracking-[0.12em] uppercase mt-1.5">{match.round}</div>
<div className="text-[10px] text-green-dark mt-0.5">{match.date ? formatDate(match.date) : ''}</div>
</Link>
<Link href={match.team2.slug ? `/teams/${match.team2.slug}` : matchHref}
className={`text-center block transition-colors hover:text-green ${winner === 'away' ? 'text-text' : 'text-green-sec'}`}>
<TeamFlag name={match.team2.name} iso2={match.team2.iso2} size="xl" className="mb-2" />
<div className="font-['Bebas_Neue'] text-base sm:text-xl tracking-[0.07em] truncate">
{match.team2.name}
</div>
</Link>
</div>
</div>
)
}