Removed some ghost bracket, hidden rest match and better rendering and score submitting

This commit is contained in:
2026-02-23 01:04:27 +01:00 Verified
parent b152f6fd85
commit 0b3f857f50
5 changed files with 91 additions and 61 deletions
@@ -70,28 +70,10 @@ export default function BracketView({ matches, onMatchClick }) {
const renderRound = (list) => {
const rounds = {};
list.forEach(m => (rounds[m.round] = rounds[m.round] || []).push(m));
const roundKeys = Object.keys(rounds).sort((a, b) => Number(a) - Number(b));
let prevRoundMap = new Map();
return roundKeys.map((r, rIdx) => {
return roundKeys.map((r) => {
let matchesInRound = rounds[r];
if (rIdx === 0) {
matchesInRound.sort((a, b) => a.number - b.number);
} else {
matchesInRound.sort((a, b) => {
const getSourceAvg = (match) => {
const sources = list.filter(x => x.winner_next_match_id === match.id);
if (sources.length === 0) return 9999;
const indices = sources.map(s => prevRoundMap.get(s.id)).filter(i => i !== undefined);
if (indices.length === 0) return 9999;
return indices.reduce((sum, val) => sum + val, 0) / indices.length;
};
return getSourceAvg(a) - getSourceAvg(b);
});
}
matchesInRound.forEach((m, idx) => prevRoundMap.set(m.id, idx));
matchesInRound.sort((a, b) => a.number - b.number);
return (
<div key={r} className="flex flex-col gap-10 z-10 w-64 shrink-0 justify-around">
{matchesInRound.map(m => <MatchCard key={m.id} match={m} onClick={onMatchClick} />)}
@@ -1,8 +1,7 @@
// frontend/src/components/Tournament/ScoreModal.jsx
import React, { useState } from 'react';
import { Eraser, Clock, MapPin, Trophy } from 'lucide-react';
import { stringToColor } from '../../utils/helpers';
import { Clock, Eraser, MapPin, Trophy } from 'lucide-react';
import { useState } from 'react';
import Modal from '../UI/Modal';
const ScoreForm = ({ match, isAdmin, onSubmit, onClear }) => {
+54 -31
View File
@@ -29,6 +29,17 @@ export default function Tournament() {
const processMatches = (rawMatches, courts, teams) => {
if (!rawMatches) return [];
const gf1 = rawMatches.find(m =>
m.bracket_type === 'Finals' &&
m.winner_next_match_id &&
m.winner_next_match_id === m.loser_next_match_id
);
let skippedResetMatchId = null;
if (gf1 && gf1.status === 'Finished' && gf1.winner_team_id === gf1.p1_team_id) {
skippedResetMatchId = gf1.winner_next_match_id;
}
const courtMap = Object.fromEntries(courts.map(c => [c.id, c.name]));
const teamMap = Object.fromEntries(teams.map(t => [t.id, t.name]));
@@ -43,37 +54,39 @@ export default function Tournament() {
}
});
return rawMatches.map(m => {
const sources = incoming[m.id] || [];
return rawMatches
.filter(m => m.id !== skippedResetMatchId)
.map(m => {
const sources = incoming[m.id] || [];
let sourceIndex = 0;
const p1 = m.p1_team_id ? teamMap[m.p1_team_id] : (sources[sourceIndex++]?.label || 'TBD');
const p2 = m.p2_team_id ? teamMap[m.p2_team_id] : (sources[sourceIndex++]?.label || 'TBD');
let sourceIndex = 0;
const p1 = m.p1_team_id ? teamMap[m.p1_team_id] : (sources[sourceIndex++]?.label || 'TBD');
const p2 = m.p2_team_id ? teamMap[m.p2_team_id] : (sources[sourceIndex++]?.label || 'TBD');
const hasTeams = !!(m.p1_team_id && m.p2_team_id);
const isFinished = m.status === "Finished";
const isReady = hasTeams && !isFinished;
const winnerName = m.winner_team_id ? teamMap[m.winner_team_id] : null;
const hasTeams = !!(m.p1_team_id && m.p2_team_id);
const isFinished = m.status === "Finished";
const isReady = hasTeams && !isFinished;
const winnerName = m.winner_team_id ? teamMap[m.winner_team_id] : null;
return {
...m,
bracket: m.bracket_type,
round: m.round_number,
number: m.match_number,
p1,
p2,
winnerName,
p1_is_real: !!m.p1_team_id,
p2_is_real: !!m.p2_team_id,
isReady,
court: courtMap[m.court_id] || 'TBD',
time: m.start_time ? new Date(m.start_time).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '',
p1_sets: m.sets?.filter(s => s.p1 > s.p2).length || 0,
p2_sets: m.sets?.filter(s => s.p2 > s.p1).length || 0,
hasTeams,
isFinished
};
});
return {
...m,
bracket: m.bracket_type,
round: m.round_number,
number: m.match_number,
p1,
p2,
winnerName,
p1_is_real: !!m.p1_team_id,
p2_is_real: !!m.p2_team_id,
isReady,
court: courtMap[m.court_id] || 'TBD',
time: m.start_time ? new Date(m.start_time).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '',
p1_sets: m.sets?.filter(s => s.p1 > s.p2).length || 0,
p2_sets: m.sets?.filter(s => s.p2 > s.p1).length || 0,
hasTeams,
isFinished
};
});
};
const fetchData = async () => {
@@ -133,9 +146,19 @@ export default function Tournament() {
{scoreMatch && (
<ScoreModal
isOpen={!!scoreMatch} onClose={() => setScoreMatch(null)} match={scoreMatch} isAdmin={isAdmin}
onClear={async (mid, c) => { await api.delete(`/tournaments/${id}/matches/${mid}/score?code=${encodeURIComponent(c || '')}`); setScoreMatch(null); }}
onSubmit={async (mid, s, c) => { await api.post(`/tournaments/${id}/matches/${mid}/score`, { sets: s, code: c }); setScoreMatch(null); }}
isOpen={!!scoreMatch}
onClose={() => setScoreMatch(null)}
match={scoreMatch}
isAdmin={isAdmin}
onClear={async (mid, c) => {
await api.delete(`/tournaments/${id}/matches/${mid}/score?code=${encodeURIComponent(c || '')}`);
setScoreMatch(null);
}}
onSubmit={async (mid, s, c) => {
const method = scoreMatch.isFinished ? 'patch' : 'post';
await api[method](`/tournaments/${id}/matches/${mid}/score`, { sets: s, code: c });
setScoreMatch(null);
}}
/>
)}
<Modal isOpen={showSettings} onClose={() => setShowSettings(false)} title="Edit Tournament">