player h2h

This commit is contained in:
yohlo
2025-10-11 14:47:03 -05:00
parent 43972b6a06
commit d3379e54a4
11 changed files with 671 additions and 36 deletions

View File

@@ -0,0 +1,270 @@
import { Stack, Text, Group, Box, Divider, Paper } from "@mantine/core";
import { usePlayerHeadToHead } from "@/features/matches/queries";
import { useMemo, useEffect, useState } from "react";
import { CrownIcon } from "@phosphor-icons/react";
import MatchList from "@/features/matches/components/match-list";
interface PlayerHeadToHeadSheetProps {
player1Id: string;
player1Name: string;
player2Id: string;
player2Name: string;
isOpen?: boolean;
}
const PlayerHeadToHeadSheet = ({
player1Id,
player1Name,
player2Id,
player2Name,
isOpen = true,
}: PlayerHeadToHeadSheetProps) => {
const [shouldFetch, setShouldFetch] = useState(false);
useEffect(() => {
if (isOpen && !shouldFetch) {
setShouldFetch(true);
}
}, [isOpen, shouldFetch]);
const { data: matches, isLoading } = usePlayerHeadToHead(player1Id, player2Id, shouldFetch);
const stats = useMemo(() => {
if (!matches || matches.length === 0) {
return {
player1Wins: 0,
player2Wins: 0,
player1CupsFor: 0,
player2CupsFor: 0,
player1CupsAgainst: 0,
player2CupsAgainst: 0,
player1AvgMargin: 0,
player2AvgMargin: 0,
};
}
let player1Wins = 0;
let player2Wins = 0;
let player1CupsFor = 0;
let player2CupsFor = 0;
let player1CupsAgainst = 0;
let player2CupsAgainst = 0;
let player1TotalWinMargin = 0;
let player2TotalWinMargin = 0;
matches.forEach((match) => {
const isPlayer1Home = match.home?.players?.some((p) => p.id === player1Id);
const player1Cups = isPlayer1Home ? match.home_cups : match.away_cups;
const player2Cups = isPlayer1Home ? match.away_cups : match.home_cups;
if (player1Cups > player2Cups) {
player1Wins++;
player1TotalWinMargin += (player1Cups - player2Cups);
} else if (player2Cups > player1Cups) {
player2Wins++;
player2TotalWinMargin += (player2Cups - player1Cups);
}
player1CupsFor += player1Cups;
player2CupsFor += player2Cups;
player1CupsAgainst += player2Cups;
player2CupsAgainst += player1Cups;
});
const player1AvgMargin =
player1Wins > 0 ? player1TotalWinMargin / player1Wins : 0;
const player2AvgMargin =
player2Wins > 0 ? player2TotalWinMargin / player2Wins : 0;
return {
player1Wins,
player2Wins,
player1CupsFor,
player2CupsFor,
player1CupsAgainst,
player2CupsAgainst,
player1AvgMargin,
player2AvgMargin,
};
}, [matches, player1Id]);
if (isLoading) {
return (
<Stack p="md" gap="md">
<Text size="sm" c="dimmed" ta="center">
Loading...
</Text>
</Stack>
);
}
if (!matches || matches.length === 0) {
return (
<Stack p="md" gap="md">
<Text size="sm" c="dimmed" ta="center">
These players have not faced each other yet.
</Text>
</Stack>
);
}
const totalGames = stats.player1Wins + stats.player2Wins;
const leader =
stats.player1Wins > stats.player2Wins
? player1Name
: stats.player2Wins > stats.player1Wins
? player2Name
: null;
return (
<Stack gap="md">
<Paper p="md" withBorder radius="md">
<Stack gap="sm">
<Group justify="center" gap="xs">
<Text size="lg" fw={700}>
{player1Name}
</Text>
<Text size="sm" c="dimmed">
vs
</Text>
<Text size="lg" fw={700}>
{player2Name}
</Text>
</Group>
<Group justify="center" gap="lg">
<Stack gap={0} align="center">
<Text size="xl" fw={700}>
{stats.player1Wins}
</Text>
<Text size="xs" c="dimmed">
{player1Name}
</Text>
</Stack>
<Text size="md" c="dimmed">
-
</Text>
<Stack gap={0} align="center">
<Text size="xl" fw={700}>
{stats.player2Wins}
</Text>
<Text size="xs" c="dimmed">
{player2Name}
</Text>
</Stack>
</Group>
{leader && (
<Group justify="center" gap="xs">
<CrownIcon size={16} weight="fill" color="gold" />
<Text size="xs" c="dimmed">
{leader} leads the series
</Text>
</Group>
)}
{!leader && totalGames > 0 && (
<Text size="xs" c="dimmed" ta="center">
Series is tied
</Text>
)}
</Stack>
</Paper>
<Stack gap={0}>
<Text size="sm" fw={600} px="md" mb="xs">
Stats Comparison
</Text>
<Paper withBorder>
<Stack gap={0}>
<Group justify="space-between" px="md" py="sm">
<Group gap="xs">
<Text size="sm" fw={600}>
{stats.player1CupsFor}
</Text>
<Text size="xs" c="dimmed">
cups
</Text>
</Group>
<Text size="xs" fw={500}>
Total Cups
</Text>
<Group gap="xs">
<Text size="xs" c="dimmed">
cups
</Text>
<Text size="sm" fw={600}>
{stats.player2CupsFor}
</Text>
</Group>
</Group>
<Divider />
<Group justify="space-between" px="md" py="sm">
<Group gap="xs">
<Text size="sm" fw={600}>
{totalGames > 0
? (stats.player1CupsFor / totalGames).toFixed(1)
: "0.0"}
</Text>
<Text size="xs" c="dimmed">
avg
</Text>
</Group>
<Text size="xs" fw={500}>
Avg Cups/Game
</Text>
<Group gap="xs">
<Text size="xs" c="dimmed">
avg
</Text>
<Text size="sm" fw={600}>
{totalGames > 0
? (stats.player2CupsFor / totalGames).toFixed(1)
: "0.0"}
</Text>
</Group>
</Group>
<Divider />
<Group justify="space-between" px="md" py="sm">
<Group gap="xs">
<Text size="sm" fw={600}>
{!isNaN(stats.player1AvgMargin)
? stats.player1AvgMargin.toFixed(1)
: "0.0"}
</Text>
<Text size="xs" c="dimmed">
margin
</Text>
</Group>
<Text size="xs" fw={500}>
Avg Win Margin
</Text>
<Group gap="xs">
<Text size="xs" c="dimmed">
margin
</Text>
<Text size="sm" fw={600}>
{!isNaN(stats.player2AvgMargin)
? stats.player2AvgMargin.toFixed(1)
: "0.0"}
</Text>
</Group>
</Group>
</Stack>
</Paper>
</Stack>
<Stack gap="xs">
<Text size="sm" fw={600} px="md">
Match History ({totalGames} games)
</Text>
<MatchList matches={matches} hideH2H />
</Stack>
</Stack>
);
};
export default PlayerHeadToHeadSheet;