import React, { useEffect, useState } from 'react'; import './MatchesSchedule.css'; import TeamLogo from './TeamLogo'; const poolColors = [ '#bae6fd', // darker blue '#fde68a', // darker yellow '#f9a8d4', // darker pink '#6ee7b7', // darker green '#fca5a5', // darker red '#a5b4fc', // darker purple ]; function groupMatchesByPoolAndRound(matches) { // Only round robin matches const rrMatches = matches.filter(m => m.stage?.type === 'ROUND_ROBIN'); let poolMap = {}; rrMatches.forEach(m => { const pool = m.pool || 1; if (!poolMap[pool]) poolMap[pool] = []; poolMap[pool].push(m); }); // For each pool, group matches by round (scheduledAt) const poolRounds = {}; Object.entries(poolMap).forEach(([pool, matches]) => { const rounds = {}; matches.forEach(match => { const key = match.scheduledAt; if (!rounds[key]) rounds[key] = []; rounds[key].push(match); }); poolRounds[pool] = Object.values(rounds).sort((a, b) => new Date(a[0].scheduledAt) - new Date(b[0].scheduledAt)); }); return poolRounds; } const MatchesSchedule = () => { const [matches, setMatches] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [editingMatchId, setEditingMatchId] = useState(null); const [score1, setScore1] = useState(''); const [score2, setScore2] = useState(''); const [submitMsg, setSubmitMsg] = useState(''); const [mobileTab, setMobileTab] = useState(null); // Calculate poolRounds and poolNumbers BEFORE any useEffect/useState that uses them const poolRounds = groupMatchesByPoolAndRound(matches); const poolNumbers = Object.keys(poolRounds).sort((a, b) => Number(a) - Number(b)); useEffect(() => { setLoading(true); fetch('/api/matches') .then(res => res.ok ? res.json() : Promise.reject(res)) .then(data => { setMatches(data); setLoading(false); }) .catch(() => { setError('Failed to load matches'); setLoading(false); }); }, []); // Set default mobile tab React.useEffect(() => { if (mobileTab === null && poolNumbers.length > 0) setMobileTab(poolNumbers[0]); }, [poolNumbers, mobileTab]); // Responsive: tabs for mobile, columns for desktop const isMobile = window.innerWidth < 700; const handleEdit = (match) => { setEditingMatchId(match.id); setScore1(''); setScore2(''); setSubmitMsg(''); }; const handleSubmit = async (match) => { setSubmitMsg(''); if (score1 === '' || score2 === '' || score1 === score2) { setSubmitMsg('Scores must be different and not empty.'); return; } try { const res = await fetch(`/api/admin/matches/${match.id}/result`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ team1Score: Number(score1), team2Score: Number(score2) }) }); const data = await res.json(); if (res.ok) { setSubmitMsg('Result saved!'); setEditingMatchId(null); setLoading(true); fetch('/api/matches') .then(res => res.ok ? res.json() : Promise.reject(res)) .then(data => { setMatches(data); setLoading(false); }); } else { setSubmitMsg(data.error || 'Failed to save result'); } } catch { setSubmitMsg('Failed to save result'); } }; if (loading) return
Loading matches...
; if (error) return
{error}
; return (

Matches Schedule (by Pool)

{isMobile ? ( <>
{poolNumbers.map((pool, idx) => ( ))}
{poolNumbers.map((pool, idx) => ( mobileTab === pool && (

{`Pool ${pool}`}

{poolRounds[pool].map((round, roundIdx) => (
{`Round ${roundIdx + 1}`}
{round.map(match => (
vs
{new Date(match.scheduledAt).toLocaleString()}
{match.result ? (
Result: {match.result.team1Score} - {match.result.team2Score}
) : ( editingMatchId === match.id ? (
setScore1(e.target.value)} placeholder="Team 1 Score" /> setScore2(e.target.value)} placeholder="Team 2 Score" />
{submitMsg}
) : ( ) )}
))}
))}
) ))} ) : (
{poolNumbers.map((pool, idx) => (
{`Pool ${pool}`}
{poolRounds[pool].map((round, roundIdx) => (
{`Round ${roundIdx + 1}`}
{round.map(match => (
vs
{new Date(match.scheduledAt).toLocaleString()}
{match.result ? (
Result: {match.result.team1Score} - {match.result.team2Score}
) : ( editingMatchId === match.id ? (
setScore1(e.target.value)} placeholder="Team 1 Score" /> setScore2(e.target.value)} placeholder="Team 2 Score" />
{submitMsg}
) : ( ) )}
))}
))}
))}
)}
); }; export default MatchesSchedule;