277 lines
9.6 KiB
TypeScript
277 lines
9.6 KiB
TypeScript
import { Stack, Text, TextInput, Box, Paper, Group, Divider, Center, ActionIcon, Badge } from "@mantine/core";
|
|
import { useState, useMemo } from "react";
|
|
import { MagnifyingGlassIcon, XIcon, ArrowRightIcon } from "@phosphor-icons/react";
|
|
import { useAllPlayerStats } from "../queries";
|
|
import { useSheet } from "@/hooks/use-sheet";
|
|
import Sheet from "@/components/sheet/sheet";
|
|
import PlayerHeadToHeadSheet from "./player-head-to-head-sheet";
|
|
import PlayerAvatar from "@/components/player-avatar";
|
|
|
|
const LeagueHeadToHead = () => {
|
|
const [player1Id, setPlayer1Id] = useState<string | null>(null);
|
|
const [player2Id, setPlayer2Id] = useState<string | null>(null);
|
|
const [search, setSearch] = useState("");
|
|
const { data: allPlayerStats } = useAllPlayerStats();
|
|
const h2hSheet = useSheet();
|
|
|
|
const player1Name = useMemo(() => {
|
|
if (!player1Id || !allPlayerStats) return "";
|
|
return allPlayerStats.find((p) => p.player_id === player1Id)?.player_name || "";
|
|
}, [player1Id, allPlayerStats]);
|
|
|
|
const player2Name = useMemo(() => {
|
|
if (!player2Id || !allPlayerStats) return "";
|
|
return allPlayerStats.find((p) => p.player_id === player2Id)?.player_name || "";
|
|
}, [player2Id, allPlayerStats]);
|
|
|
|
const filteredPlayers = useMemo(() => {
|
|
if (!allPlayerStats) return [];
|
|
|
|
return allPlayerStats
|
|
.filter((stat) => {
|
|
if (player1Id && stat.player_id === player1Id) return false;
|
|
if (player2Id && stat.player_id === player2Id) return false;
|
|
return true;
|
|
})
|
|
.filter((stat) =>
|
|
stat.player_name.toLowerCase().includes(search.toLowerCase())
|
|
)
|
|
.sort((a, b) => b.matches - a.matches);
|
|
}, [allPlayerStats, player1Id, player2Id, search]);
|
|
|
|
const handlePlayerClick = (playerId: string) => {
|
|
if (!player1Id) {
|
|
setPlayer1Id(playerId);
|
|
} else if (!player2Id) {
|
|
setPlayer2Id(playerId);
|
|
h2hSheet.open();
|
|
}
|
|
};
|
|
|
|
const handleClearPlayer1 = () => {
|
|
setPlayer1Id(null);
|
|
if (player2Id) {
|
|
setPlayer1Id(player2Id);
|
|
setPlayer2Id(null);
|
|
}
|
|
};
|
|
|
|
const handleClearPlayer2 = () => {
|
|
setPlayer2Id(null);
|
|
};
|
|
|
|
const activeStep = !player1Id ? 1 : !player2Id ? 2 : 0;
|
|
|
|
return (
|
|
<>
|
|
<Stack gap="md">
|
|
<Paper px="md" pt="md" pb="sm" withBorder shadow="sm">
|
|
<Stack gap="xs">
|
|
<Group gap="xs" wrap="nowrap">
|
|
<Paper
|
|
p="sm"
|
|
withBorder
|
|
style={{
|
|
flex: 1,
|
|
minHeight: 70,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
position: "relative",
|
|
borderWidth: 2,
|
|
borderColor: activeStep === 1 ? "var(--mantine-primary-color-filled)" : undefined,
|
|
backgroundColor: player1Id && activeStep !== 1 ? "var(--mantine-color-default-hover)" : undefined,
|
|
cursor: player1Id && activeStep === 0 ? "pointer" : undefined,
|
|
transition: "all 150ms ease",
|
|
}}
|
|
onClick={player1Id && activeStep === 0 ? handleClearPlayer1 : undefined}
|
|
>
|
|
{player1Id ? (
|
|
<>
|
|
<Stack gap={4} align="center" style={{ flex: 1 }}>
|
|
<PlayerAvatar name={player1Name} size={36} disableFullscreen />
|
|
<Text size="xs" fw={600} ta="center" lineClamp={1}>
|
|
{player1Name}
|
|
</Text>
|
|
</Stack>
|
|
<ActionIcon
|
|
variant="light"
|
|
color="gray"
|
|
size="xs"
|
|
radius="xl"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
handleClearPlayer1();
|
|
}}
|
|
style={{ position: "absolute", top: 4, right: 4 }}
|
|
>
|
|
<XIcon size={10} />
|
|
</ActionIcon>
|
|
</>
|
|
) : (
|
|
<Stack gap={4} align="center">
|
|
<PlayerAvatar size={36} disableFullscreen />
|
|
<Text size="xs" c="dimmed" fw={500}>
|
|
Player 1
|
|
</Text>
|
|
</Stack>
|
|
)}
|
|
</Paper>
|
|
|
|
<Center>
|
|
<Text size="xl" fw={700} c="dimmed">
|
|
VS
|
|
</Text>
|
|
</Center>
|
|
|
|
<Paper
|
|
p="sm"
|
|
withBorder
|
|
style={{
|
|
flex: 1,
|
|
minHeight: 70,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
position: "relative",
|
|
borderWidth: 2,
|
|
borderColor: activeStep === 2 ? "var(--mantine-primary-color-filled)" : undefined,
|
|
backgroundColor: player2Id && activeStep !== 2 ? "var(--mantine-color-default-hover)" : undefined,
|
|
cursor: player2Id && activeStep === 0 ? "pointer" : undefined,
|
|
transition: "all 150ms ease",
|
|
}}
|
|
onClick={player2Id && activeStep === 0 ? handleClearPlayer2 : undefined}
|
|
>
|
|
{player2Id ? (
|
|
<>
|
|
<Stack gap={4} align="center" style={{ flex: 1 }}>
|
|
<PlayerAvatar name={player2Name} size={36} disableFullscreen />
|
|
<Text size="xs" fw={600} ta="center" lineClamp={1}>
|
|
{player2Name}
|
|
</Text>
|
|
</Stack>
|
|
<ActionIcon
|
|
variant="light"
|
|
color="gray"
|
|
size="xs"
|
|
radius="xl"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
handleClearPlayer2();
|
|
}}
|
|
style={{ position: "absolute", top: 4, right: 4 }}
|
|
>
|
|
<XIcon size={10} />
|
|
</ActionIcon>
|
|
</>
|
|
) : (
|
|
<Stack gap={4} align="center">
|
|
<PlayerAvatar size={36} disableFullscreen />
|
|
<Text size="xs" c="dimmed" fw={500}>
|
|
Player 2
|
|
</Text>
|
|
</Stack>
|
|
)}
|
|
</Paper>
|
|
</Group>
|
|
|
|
{activeStep > 0 ? (
|
|
<Badge
|
|
variant="light"
|
|
size="sm"
|
|
radius="sm"
|
|
fullWidth
|
|
styles={{ label: { textTransform: "none" } }}
|
|
>
|
|
{activeStep === 1 && "Select first player"}
|
|
{activeStep === 2 && "Select second player"}
|
|
</Badge>
|
|
) : (
|
|
<Group justify="center">
|
|
<Text
|
|
size="xs"
|
|
c="dimmed"
|
|
style={{ cursor: "pointer" }}
|
|
onClick={() => {
|
|
setPlayer1Id(null);
|
|
setPlayer2Id(null);
|
|
}}
|
|
td="underline"
|
|
>
|
|
Clear both players
|
|
</Text>
|
|
</Group>
|
|
)}
|
|
</Stack>
|
|
</Paper>
|
|
|
|
<TextInput
|
|
placeholder="Search players"
|
|
value={search}
|
|
onChange={(e) => setSearch(e.currentTarget.value)}
|
|
leftSection={<MagnifyingGlassIcon size={16} />}
|
|
size="md"
|
|
px="md"
|
|
/>
|
|
|
|
<Box px="md" pb="md">
|
|
<Paper withBorder>
|
|
{filteredPlayers.length === 0 && (
|
|
<Text size="sm" c="dimmed" ta="center" py="xl">
|
|
{search ? `No players found matching "${search}"` : "No players available"}
|
|
</Text>
|
|
)}
|
|
|
|
{filteredPlayers.map((player, index) => (
|
|
<Box key={player.player_id}>
|
|
<Group
|
|
p="md"
|
|
gap="sm"
|
|
wrap="nowrap"
|
|
style={{
|
|
cursor: "pointer",
|
|
transition: "background-color 150ms ease",
|
|
}}
|
|
onClick={() => handlePlayerClick(player.player_id)}
|
|
styles={{
|
|
root: {
|
|
"&:hover": {
|
|
backgroundColor: "var(--mantine-color-default-hover)",
|
|
},
|
|
},
|
|
}}
|
|
>
|
|
<PlayerAvatar name={player.player_name} size={44} disableFullscreen />
|
|
<Box style={{ flex: 1, minWidth: 0 }}>
|
|
<Text size="sm" fw={600} truncate>
|
|
{player.player_name}
|
|
</Text>
|
|
</Box>
|
|
<ActionIcon variant="subtle" color="gray" size="lg" radius="xl">
|
|
<ArrowRightIcon size={18} />
|
|
</ActionIcon>
|
|
</Group>
|
|
{index < filteredPlayers.length - 1 && <Divider />}
|
|
</Box>
|
|
))}
|
|
</Paper>
|
|
</Box>
|
|
</Stack>
|
|
|
|
{player1Id && player2Id && (
|
|
<Sheet title="Head to Head" {...h2hSheet.props}>
|
|
<PlayerHeadToHeadSheet
|
|
player1Id={player1Id}
|
|
player1Name={player1Name}
|
|
player2Id={player2Id}
|
|
player2Name={player2Name}
|
|
isOpen={h2hSheet.props.opened}
|
|
/>
|
|
</Sheet>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default LeagueHeadToHead;
|