mrrrp
This commit is contained in:
+70
-33
@@ -5536,37 +5536,12 @@ function inferSwissRounds(sides) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function TeamTotals({ matches, navigate, highlight, onHover }) {
|
function TeamTotalsRoundTable({ teams, highlight, onHover, navigate }) {
|
||||||
const teams = useMemo(() => {
|
|
||||||
const map = {}
|
|
||||||
for (const match of matches) {
|
|
||||||
const teamA = displayTeamName(match.team_a_name)
|
|
||||||
const teamB = displayTeamName(match.team_b_name)
|
|
||||||
const winner = displayTeamName(match.winner_name)
|
|
||||||
for (const name of [teamA, teamB]) {
|
|
||||||
if (!name) continue
|
|
||||||
if (!map[name]) map[name] = { wins: 0, losses: 0 }
|
|
||||||
if (winner) {
|
|
||||||
if (winner === name) map[name].wins++
|
|
||||||
else map[name].losses++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Object.entries(map)
|
|
||||||
.map(([name, s]) => ({ name, wins: s.wins, losses: s.losses, total: s.wins + s.losses }))
|
|
||||||
.sort((a, b) => b.wins - a.wins || a.losses - b.losses || a.name.localeCompare(b.name))
|
|
||||||
}, [matches])
|
|
||||||
|
|
||||||
if (!teams.length) return null
|
|
||||||
|
|
||||||
const active = Boolean(highlight)
|
const active = Boolean(highlight)
|
||||||
|
if (!teams.length) return null
|
||||||
return (
|
return (
|
||||||
<div className={`overflow-hidden rounded-lg border border-border bg-fury-white shadow-sm${active ? ' has-trace' : ''}`}>
|
<div className={`overflow-hidden rounded-lg border border-border bg-fury-white shadow-sm${active ? ' has-trace' : ''}`}>
|
||||||
<p className="border-b border-border px-5 py-3 text-xs font-semibold uppercase tracking-wide text-fury-cyan">
|
<div className="grid grid-cols-[1fr_3rem_3rem_4rem] gap-2 border-b border-border px-3 py-2 text-xs font-semibold uppercase tracking-wide text-text-soft">
|
||||||
TEAM TOTALS
|
|
||||||
</p>
|
|
||||||
<div className="grid grid-cols-[1fr_3rem_3rem_4rem] gap-2 border-b border-border px-5 py-3 text-xs font-semibold uppercase tracking-wide text-text-soft">
|
|
||||||
<p>Team</p>
|
<p>Team</p>
|
||||||
<p className="text-center">W</p>
|
<p className="text-center">W</p>
|
||||||
<p className="text-center">L</p>
|
<p className="text-center">L</p>
|
||||||
@@ -5577,7 +5552,7 @@ function TeamTotals({ matches, navigate, highlight, onHover }) {
|
|||||||
const wr = team.total > 0 ? Math.round(team.wins / team.total * 100) : 0
|
const wr = team.total > 0 ? Math.round(team.wins / team.total * 100) : 0
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`grid grid-cols-[1fr_3rem_3rem_4rem] items-center gap-2 border-b border-surface px-5 py-2.5 text-sm team-total-row${traced}`}
|
className={`grid grid-cols-[1fr_3rem_3rem_4rem] items-center gap-2 border-b border-surface px-3 py-1.5 text-sm team-total-row${traced}`}
|
||||||
key={team.name}
|
key={team.name}
|
||||||
onMouseEnter={() => onHover?.({ [team.name.toLowerCase()]: 'win' })}
|
onMouseEnter={() => onHover?.({ [team.name.toLowerCase()]: 'win' })}
|
||||||
onMouseLeave={() => onHover?.(null)}
|
onMouseLeave={() => onHover?.(null)}
|
||||||
@@ -5599,6 +5574,68 @@ function TeamTotals({ matches, navigate, highlight, onHover }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TeamTotals({ sides, navigate, highlight, onHover }) {
|
||||||
|
const roundTotals = useMemo(() => {
|
||||||
|
return sides.flatMap((side) => {
|
||||||
|
const running = {}
|
||||||
|
return side.columns.map((column) => {
|
||||||
|
for (const match of column.matches) {
|
||||||
|
const teamA = displayTeamName(match.team_a_name)
|
||||||
|
const teamB = displayTeamName(match.team_b_name)
|
||||||
|
const winner = displayTeamName(match.winner_name)
|
||||||
|
for (const name of [teamA, teamB]) {
|
||||||
|
if (!name) continue
|
||||||
|
if (!running[name]) running[name] = { wins: 0, losses: 0 }
|
||||||
|
if (winner) {
|
||||||
|
if (winner === name) running[name].wins++
|
||||||
|
else running[name].losses++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const teams = Object.entries(running)
|
||||||
|
.map(([name, s]) => ({ name, wins: s.wins, losses: s.losses, total: s.wins + s.losses }))
|
||||||
|
.sort((a, b) => b.wins - a.wins || a.losses - b.losses || a.name.localeCompare(b.name))
|
||||||
|
return { label: column.label, teams }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, [sides])
|
||||||
|
|
||||||
|
if (!roundTotals.length) return null
|
||||||
|
|
||||||
|
const active = Boolean(highlight)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="bracket-side">
|
||||||
|
<p className="mb-3 text-sm font-semibold uppercase tracking-wide text-fury-violet">
|
||||||
|
TEAM TOTALS
|
||||||
|
</p>
|
||||||
|
<BracketViewport>
|
||||||
|
<div className={`tournament-bracket-grid${active ? ' has-trace' : ''}`}>
|
||||||
|
{roundTotals.map((round, index) => (
|
||||||
|
<div className="tournament-list-column" key={index}>
|
||||||
|
<button
|
||||||
|
aria-expanded
|
||||||
|
className="tournament-list-round-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
{round.label}
|
||||||
|
</button>
|
||||||
|
<div className="min-w-0 flex-1">
|
||||||
|
<TeamTotalsRoundTable
|
||||||
|
teams={round.teams}
|
||||||
|
highlight={highlight}
|
||||||
|
onHover={onHover}
|
||||||
|
navigate={navigate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</BracketViewport>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function TournamentDetailPage({ tournamentId, navigate }) {
|
function TournamentDetailPage({ tournamentId, navigate }) {
|
||||||
const [state, setState] = useState({ status: 'loading', data: null, error: null })
|
const [state, setState] = useState({ status: 'loading', data: null, error: null })
|
||||||
|
|
||||||
@@ -5627,8 +5664,8 @@ function TournamentDetailPage({ tournamentId, navigate }) {
|
|||||||
}, [matches])
|
}, [matches])
|
||||||
const bracketSides = sides.filter((side) => side.kind === 'bracket')
|
const bracketSides = sides.filter((side) => side.kind === 'bracket')
|
||||||
const listSides = sides.filter((side) => side.kind === 'list')
|
const listSides = sides.filter((side) => side.kind === 'list')
|
||||||
const swissMatches = useMemo(() => {
|
const swissSides = useMemo(() => {
|
||||||
return listSides.filter((s) => s.key === 'swiss').flatMap((s) => s.columns.flatMap((c) => c.matches))
|
return listSides.filter((s) => s.key === 'swiss')
|
||||||
}, [listSides])
|
}, [listSides])
|
||||||
const standings = data?.standings || []
|
const standings = data?.standings || []
|
||||||
const hasStandings = standings.length > 0
|
const hasStandings = standings.length > 0
|
||||||
@@ -5688,8 +5725,8 @@ function TournamentDetailPage({ tournamentId, navigate }) {
|
|||||||
{bracketSides.length ? <h2 className="text-lg font-semibold">Group stage</h2> : null}
|
{bracketSides.length ? <h2 className="text-lg font-semibold">Group stage</h2> : null}
|
||||||
{hasStandings ? <TournamentStandings standings={standings} /> : null}
|
{hasStandings ? <TournamentStandings standings={standings} /> : null}
|
||||||
{listSides.length ? <TournamentMatchList highlight={highlight} navigate={navigate} onHover={onHover} sides={listSides} /> : null}
|
{listSides.length ? <TournamentMatchList highlight={highlight} navigate={navigate} onHover={onHover} sides={listSides} /> : null}
|
||||||
{swissMatches.length ? (
|
{swissSides.length ? (
|
||||||
<TeamTotals matches={swissMatches} navigate={navigate} highlight={highlight} onHover={onHover} />
|
<TeamTotals sides={swissSides} navigate={navigate} highlight={highlight} onHover={onHover} />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|||||||
Reference in New Issue
Block a user