109 lines
3.5 KiB
TypeScript
109 lines
3.5 KiB
TypeScript
import { useMemo } from "react";
|
|
import { Tournament } from "../../types";
|
|
import { useAuth } from "@/contexts/auth-context";
|
|
import { Box, Divider, Stack, Text, Card, Center } from "@mantine/core";
|
|
import { Carousel } from "@mantine/carousel";
|
|
import ListLink from "@/components/list-link";
|
|
import { TreeStructureIcon, UsersIcon, ClockIcon, ListDashes } from "@phosphor-icons/react";
|
|
import TeamListButton from "../upcoming-tournament/team-list-button";
|
|
import RulesListButton from "../upcoming-tournament/rules-list-button";
|
|
import MatchCard from "@/features/matches/components/match-card";
|
|
import Header from "./header";
|
|
import { Podium } from "../podium";
|
|
|
|
const StartedTournament: React.FC<{ tournament: Tournament }> = ({
|
|
tournament,
|
|
}) => {
|
|
const { roles } = useAuth();
|
|
|
|
const isAdmin = useMemo(() => roles.includes("Admin"), [roles]);
|
|
|
|
const startedMatches = useMemo(() =>
|
|
tournament.matches?.filter(match => match.status === "started") || [],
|
|
[tournament.matches]
|
|
);
|
|
|
|
const isTournamentOver = useMemo(() => {
|
|
const matches = tournament.matches || [];
|
|
if (matches.length === 0) return false;
|
|
|
|
const nonByeMatches = matches.filter((match) => !(match.status === 'tbd' && match.bye === true));
|
|
if (nonByeMatches.length === 0) return false;
|
|
|
|
const finalsMatch = nonByeMatches.reduce((highest, current) =>
|
|
(!highest || current.lid > highest.lid) ? current : highest
|
|
);
|
|
|
|
return finalsMatch?.status === 'ended';
|
|
}, [tournament.matches]);
|
|
|
|
const hasGroupStage = useMemo(() => {
|
|
return tournament.matches?.some((match) => match.round === -1) || false;
|
|
}, [tournament.matches]);
|
|
|
|
return (
|
|
<Stack gap="lg">
|
|
<Header tournament={tournament} />
|
|
|
|
{startedMatches.length > 0 ? (
|
|
<Box>
|
|
<Carousel
|
|
slideSize="95%"
|
|
slideGap="xs"
|
|
withControls={false}
|
|
>
|
|
{startedMatches.map((match, index) => (
|
|
<Carousel.Slide key={match.id}>
|
|
<Box pl={index === 0 ? "md" : undefined } pr={index === startedMatches.length - 1 ? "md" : undefined}>
|
|
<MatchCard match={match} />
|
|
</Box>
|
|
</Carousel.Slide>
|
|
))}
|
|
</Carousel>
|
|
</Box>
|
|
) : isTournamentOver ? (
|
|
<Box px="lg" w="100%">
|
|
<Podium tournament={tournament} />
|
|
</Box>
|
|
) : (
|
|
<Card withBorder radius="lg" p="xl" mx="md">
|
|
<Center>
|
|
<Stack align="center" gap="md">
|
|
<ClockIcon size={48} color="var(--mantine-color-dimmed)" />
|
|
<Text size="lg" fw={500} c="dimmed">
|
|
No active matches
|
|
</Text>
|
|
</Stack>
|
|
</Center>
|
|
</Card>
|
|
)}
|
|
|
|
<Box>
|
|
<Divider />
|
|
{isAdmin && (
|
|
<ListLink
|
|
label={`Manage ${tournament.name}`}
|
|
to={`/admin/tournaments/${tournament.id}`}
|
|
Icon={UsersIcon}
|
|
/>
|
|
)}
|
|
{hasGroupStage && (
|
|
<ListLink
|
|
label={`View Groups`}
|
|
to={`/tournaments/${tournament.id}/groups`}
|
|
Icon={ListDashes}
|
|
/>
|
|
)}
|
|
<ListLink
|
|
label={`View Bracket`}
|
|
to={`/tournaments/${tournament.id}/bracket`}
|
|
Icon={TreeStructureIcon}
|
|
/>
|
|
<TeamListButton teams={tournament.teams || []} isRegional={tournament.regional} />
|
|
<RulesListButton tournamentId={tournament.id} />
|
|
</Box>
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
export default StartedTournament; |