Files
flxn-app/src/features/bracket/components/match-slot.tsx
T
2026-07-12 21:26:39 -07:00

104 lines
3.0 KiB
TypeScript

import { Flex, Text } from "@mantine/core";
import React, { useEffect, useRef, useState } from "react";
import { CrownIcon } from "@phosphor-icons/react";
import { SeedBadge } from "./seed-badge";
import { TeamInfo } from "@/features/teams/types";
import AnimatedScore from "@/features/matches/components/animated-score";
import classes from "./match-slot.module.css";
interface MatchSlotProps {
from?: number;
from_loser?: boolean;
team?: TeamInfo;
seed?: number;
cups?: number;
isWinner?: boolean;
groupLabel?: string;
}
export const MatchSlot: React.FC<MatchSlotProps> = ({
from,
from_loser,
team,
seed,
cups,
isWinner,
groupLabel
}) => {
const teamId = team?.id;
const previousTeamIdRef = useRef<string | undefined>(teamId);
const [entranceKey, setEntranceKey] = useState(0);
useEffect(() => {
const previousTeamId = previousTeamIdRef.current;
previousTeamIdRef.current = teamId;
if (teamId && previousTeamId !== teamId) {
setEntranceKey((key) => key + 1);
}
}, [teamId]);
return (
<Flex
align="stretch"
style={{
backgroundColor: isWinner ? 'var(--mantine-color-green-light)' : 'transparent',
borderRadius: 'var(--mantine-radius-sm)',
transition: 'background-color 200ms ease',
}}
>
{(seed && seed > 0) ? <SeedBadge seed={seed} /> : undefined}
<Flex p="6px 10px" w='100%' align="center">
<Flex
key={entranceKey}
className={entranceKey > 0 ? classes.slotEnter : undefined}
align="center"
gap={4}
flex={1}
>
{team ? (
<>
<Text
size={team.name.length > 12 ? (team.name.length > 18 ? '10px' : '11px') : 'xs'}
truncate
style={{ minWidth: 0, flex: 1, lineHeight: "12px" }}
>
{team.name}
</Text>
{isWinner && (
<CrownIcon
size={14}
weight="fill"
style={{
color: 'gold',
marginLeft: '2px',
marginTop: '-1px',
filter: 'drop-shadow(0 1px 1px rgba(0,0,0,0.3))',
flexShrink: 0
}}
/>
)}
</>
) : groupLabel ? (
<Text c="dimmed" size="xs" truncate style={{ minWidth: 0, flex: 1 }}>
{groupLabel}
</Text>
) : from ? (
<Text c="dimmed" size="xs" truncate style={{ minWidth: 0, flex: 1 }}>
{from_loser ? "Loser" : "Winner"} of Match {from}
</Text>
) : (
<Text c="dimmed" size="xs" truncate style={{ minWidth: 0, flex: 1 }}>
TBD
</Text>
)}
</Flex>
{
cups !== undefined ? (
<AnimatedScore ta='center' w={15} fw={800} ml={4} size="xs" value={cups} />
) : undefined
}
</Flex>
</Flex>
);
};