Files
flxn-app/src/features/tournaments/components/group-match-card.tsx
yohlo c138442530
All checks were successful
CI/CD Pipeline / Build and Push App Docker Image (push) Successful in 3m0s
CI/CD Pipeline / Build and Push PocketBase Docker Image (push) Successful in 8s
CI/CD Pipeline / Deploy to Kubernetes (push) Successful in 45s
fix
2026-03-01 21:46:59 -06:00

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;