202 lines
6.0 KiB
TypeScript
202 lines
6.0 KiB
TypeScript
import React, { useCallback } from "react";
|
|
import { Card, Group, Stack, Text, ActionIcon, Indicator, Flex, Box } from "@mantine/core";
|
|
import { PlayIcon, PencilIcon } from "@phosphor-icons/react";
|
|
import { Match } from "@/features/matches/types";
|
|
import { useSheet } from "@/hooks/use-sheet";
|
|
import Sheet from "@/components/sheet/sheet";
|
|
import { useServerMutation } from "@/lib/tanstack-query/hooks";
|
|
import { endMatch, startMatch } from "@/features/matches/server";
|
|
import { tournamentKeys } from "@/features/tournaments/queries";
|
|
import { useQueryClient } from "@tanstack/react-query";
|
|
import { MatchForm } from "@/features/bracket/components/match-form";
|
|
import TeamAvatar from "@/components/team-avatar";
|
|
|
|
interface GroupMatchCardProps {
|
|
match: Match;
|
|
showControls?: boolean;
|
|
}
|
|
|
|
const GroupMatchCard: React.FC<GroupMatchCardProps> = ({ match, showControls }) => {
|
|
const queryClient = useQueryClient();
|
|
const editSheet = useSheet();
|
|
|
|
const isReady = match.status === "ready";
|
|
const isStarted = match.status === "started";
|
|
const isEnded = match.status === "ended";
|
|
|
|
const homeWon = isEnded && match.home_cups !== undefined && match.away_cups !== undefined && match.home_cups > match.away_cups;
|
|
const awayWon = isEnded && match.away_cups !== undefined && match.home_cups !== undefined && match.away_cups > match.home_cups;
|
|
|
|
const start = useServerMutation({
|
|
mutationFn: startMatch,
|
|
successMessage: "Match started!",
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: tournamentKeys.details(match.tournament.id),
|
|
});
|
|
},
|
|
});
|
|
|
|
const end = useServerMutation({
|
|
mutationFn: endMatch,
|
|
onSuccess: () => {
|
|
queryClient.invalidateQueries({
|
|
queryKey: tournamentKeys.details(match.tournament.id),
|
|
});
|
|
editSheet.close();
|
|
},
|
|
});
|
|
|
|
const handleFormSubmit = useCallback(
|
|
async (data: {
|
|
home_cups: number;
|
|
away_cups: number;
|
|
ot_count: number;
|
|
}) => {
|
|
end.mutate({
|
|
data: {
|
|
...data,
|
|
matchId: match.id,
|
|
},
|
|
});
|
|
},
|
|
[end, match.id]
|
|
);
|
|
|
|
const handleStartMatch = () => {
|
|
start.mutate({ data: match.id });
|
|
};
|
|
|
|
const showStartButton = isReady && showControls;
|
|
const showEditButton = isStarted && showControls;
|
|
|
|
return (
|
|
<>
|
|
<Flex direction="row" align="stretch">
|
|
<Indicator
|
|
inline
|
|
processing={isStarted}
|
|
color="red"
|
|
size={16}
|
|
disabled={!isStarted || showEditButton}
|
|
style={{ flex: 1 }}
|
|
>
|
|
<Card
|
|
withBorder
|
|
radius="md"
|
|
p="md"
|
|
style={{
|
|
position: 'relative',
|
|
width: '100%',
|
|
}}
|
|
>
|
|
<Stack gap="sm">
|
|
<Group justify="space-between" align="center" wrap="nowrap">
|
|
<Group gap="sm" style={{ flex: 1, minWidth: 0 }}>
|
|
{match.home && <TeamAvatar team={match.home} size={32} radius="sm" isRegional={match.tournament.regional} />}
|
|
<Text
|
|
size="sm"
|
|
fw={homeWon ? 700 : 500}
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
lineClamp={1}
|
|
>
|
|
{match.home?.name || "TBD"}
|
|
</Text>
|
|
</Group>
|
|
{isEnded && match.home_cups !== undefined && (
|
|
<Text
|
|
size="xl"
|
|
fw={700}
|
|
c={homeWon ? "green" : "dimmed"}
|
|
style={{ minWidth: 32, textAlign: 'center' }}
|
|
>
|
|
{match.home_cups}
|
|
</Text>
|
|
)}
|
|
</Group>
|
|
|
|
<Box
|
|
style={{
|
|
height: 1,
|
|
backgroundColor: 'var(--mantine-color-default-border)',
|
|
}}
|
|
/>
|
|
|
|
<Group justify="space-between" align="center" wrap="nowrap">
|
|
<Group gap="sm" style={{ flex: 1, minWidth: 0 }}>
|
|
{match.away && <TeamAvatar team={match.away} size={32} radius="sm" isRegional={match.tournament.regional} />}
|
|
<Text
|
|
size="sm"
|
|
fw={awayWon ? 700 : 500}
|
|
style={{ flex: 1, minWidth: 0 }}
|
|
lineClamp={1}
|
|
>
|
|
{match.away?.name || "TBD"}
|
|
</Text>
|
|
</Group>
|
|
{isEnded && match.away_cups !== undefined && (
|
|
<Text
|
|
size="xl"
|
|
fw={700}
|
|
c={awayWon ? "green" : "dimmed"}
|
|
style={{ minWidth: 32, textAlign: 'center' }}
|
|
>
|
|
{match.away_cups}
|
|
</Text>
|
|
)}
|
|
</Group>
|
|
</Stack>
|
|
</Card>
|
|
</Indicator>
|
|
|
|
{showStartButton && (
|
|
<ActionIcon
|
|
color="green"
|
|
onClick={handleStartMatch}
|
|
loading={start.isPending}
|
|
size="md"
|
|
h="100%"
|
|
radius="sm"
|
|
ml={-4}
|
|
style={{
|
|
borderTopLeftRadius: 0,
|
|
borderBottomLeftRadius: 0,
|
|
}}
|
|
>
|
|
<PlayIcon size={16} weight="fill" />
|
|
</ActionIcon>
|
|
)}
|
|
|
|
{showEditButton && (
|
|
<ActionIcon
|
|
color="blue"
|
|
onClick={editSheet.open}
|
|
size="md"
|
|
h="100%"
|
|
radius="sm"
|
|
ml={-4}
|
|
style={{
|
|
borderTopLeftRadius: 0,
|
|
borderBottomLeftRadius: 0,
|
|
}}
|
|
>
|
|
<PencilIcon size={16} />
|
|
</ActionIcon>
|
|
)}
|
|
</Flex>
|
|
|
|
{showControls && (
|
|
<Sheet title="End Match" opened={editSheet.isOpen} onChange={editSheet.toggle}>
|
|
<MatchForm
|
|
match={match}
|
|
onSubmit={handleFormSubmit}
|
|
onCancel={editSheet.close}
|
|
/>
|
|
</Sheet>
|
|
)}
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default GroupMatchCard;
|