more for the overhaul
This commit is contained in:
@@ -108,7 +108,8 @@ const StartedTournament: React.FC<{ tournament: Tournament }> = ({
|
||||
<ScoreReportCta matches={myLiveMatches} />
|
||||
|
||||
{isTournamentOver && (
|
||||
<Box px="lg" w="100%">
|
||||
<Box>
|
||||
<SectionHeading label="Final Results" />
|
||||
<Podium tournament={tournament} />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
@@ -27,6 +27,11 @@
|
||||
background-color: var(--mantine-color-default-hover);
|
||||
}
|
||||
|
||||
.tile:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.tile {
|
||||
transition: background-color 120ms ease-out, transform 120ms cubic-bezier(0.32, 0.72, 0, 1);
|
||||
|
||||
@@ -31,12 +31,13 @@ const RulesContent = lazy(
|
||||
interface NavTileProps {
|
||||
label: string;
|
||||
Icon: Icon;
|
||||
onClick: () => void;
|
||||
onClick?: () => void;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
/** A single square-ish nav tile with icon-over-label and press feedback. */
|
||||
const NavTile = ({ label, Icon, onClick }: NavTileProps) => (
|
||||
<UnstyledButton className={classes.tile} onClick={onClick}>
|
||||
export const NavTile = ({ label, Icon, onClick, disabled }: NavTileProps) => (
|
||||
<UnstyledButton className={classes.tile} onClick={onClick} disabled={disabled}>
|
||||
<span className={classes.icon}>
|
||||
<Icon size={22} weight="bold" />
|
||||
</span>
|
||||
|
||||
@@ -175,25 +175,27 @@ export const TournamentStats = memo(({ tournament }: TournamentStatsProps) => {
|
||||
</Alert>
|
||||
)}
|
||||
{!tournament.regional && <Podium tournament={tournament} />}
|
||||
{hasGroupStage && (
|
||||
<Stack gap={0}>
|
||||
{hasGroupStage && (
|
||||
<ListLink
|
||||
label={`View Groups`}
|
||||
to={`/tournaments/${tournament.id}/groups`}
|
||||
Icon={ListDashes}
|
||||
/>
|
||||
)}
|
||||
<ListLink
|
||||
label={`View Groups`}
|
||||
to={`/tournaments/${tournament.id}/groups`}
|
||||
Icon={ListDashes}
|
||||
label={`View Bracket`}
|
||||
to={`/tournaments/${tournament.id}/bracket`}
|
||||
Icon={TreeStructureIcon}
|
||||
/>
|
||||
)}
|
||||
<ListLink
|
||||
label={`View Bracket`}
|
||||
to={`/tournaments/${tournament.id}/bracket`}
|
||||
Icon={TreeStructureIcon}
|
||||
/>
|
||||
{isTournamentPredictable(tournament) && (
|
||||
<ListLink
|
||||
label={`View Predictions`}
|
||||
to={`/tournaments/${tournament.id}/predictions`}
|
||||
Icon={WizardOrbIcon}
|
||||
/>
|
||||
)}
|
||||
{isTournamentPredictable(tournament) && (
|
||||
<ListLink
|
||||
label={`View Predictions`}
|
||||
to={`/tournaments/${tournament.id}/predictions`}
|
||||
Icon={WizardOrbIcon}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
{renderTeamStatsTable()}
|
||||
</Stack>
|
||||
</Container>
|
||||
|
||||
+2
-6
@@ -1,4 +1,3 @@
|
||||
import ListButton from "@/components/list-button";
|
||||
import Sheet from "@/components/sheet/sheet";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import { UserListIcon } from "@phosphor-icons/react";
|
||||
@@ -7,6 +6,7 @@ import { useFreeAgents } from "../../queries";
|
||||
import { Text } from "@mantine/core";
|
||||
import PlayerList from "@/features/players/components/player-list";
|
||||
import { Player } from "@/features/players/types";
|
||||
import { NavTile } from "../started-tournament/sections/nav-grid";
|
||||
|
||||
interface EnrolledPlayersListButtonProps {
|
||||
tournamentId: string;
|
||||
@@ -24,11 +24,7 @@ const EnrolledPlayersListButton: React.FC<EnrolledPlayersListButtonProps> = ({ t
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListButton
|
||||
label={`View Enrolled Players (${count})`}
|
||||
Icon={UserListIcon}
|
||||
onClick={open}
|
||||
/>
|
||||
<NavTile label={`Players (${count})`} Icon={UserListIcon} onClick={open} />
|
||||
|
||||
<Sheet title="Enrolled Players" opened={isOpen} onChange={toggle}>
|
||||
{count === 0 ? (
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
import { Group, Stack, ThemeIcon, Text, Flex } from "@mantine/core";
|
||||
import { Tournament } from "../../types";
|
||||
import GlitchAvatar from "@/components/glitch-avatar";
|
||||
import {
|
||||
CalendarIcon,
|
||||
MapPinIcon,
|
||||
TrophyIcon,
|
||||
UsersIcon,
|
||||
} from "@phosphor-icons/react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const Header = ({ tournament }: { tournament: Tournament }) => {
|
||||
const tournamentStart = useMemo(
|
||||
() => new Date(tournament.start_time),
|
||||
[tournament.start_time]
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack align="center" gap={16}>
|
||||
<GlitchAvatar
|
||||
name={tournament.name}
|
||||
src={
|
||||
tournament.logo
|
||||
? `/api/files/tournaments/${tournament.id}/${tournament.logo}`
|
||||
: undefined
|
||||
}
|
||||
glitchSrc={
|
||||
tournament.glitch_logo
|
||||
? `/api/files/tournaments/${tournament.id}/${tournament.glitch_logo}`
|
||||
: undefined
|
||||
}
|
||||
radius="md"
|
||||
size={300}
|
||||
>
|
||||
<TrophyIcon size={32} />
|
||||
</GlitchAvatar>
|
||||
<Flex gap="xs" direction="column" justify="space-around" align="center">
|
||||
{tournament.location && (
|
||||
<Group gap="xs">
|
||||
<ThemeIcon size="sm" variant="light" radius="sm">
|
||||
<MapPinIcon size={14} />
|
||||
</ThemeIcon>
|
||||
<Text size="sm" c="dimmed">
|
||||
{tournament.location}
|
||||
</Text>
|
||||
</Group>
|
||||
)}
|
||||
|
||||
<Group gap="xs">
|
||||
<ThemeIcon size="sm" variant="light" radius="sm">
|
||||
<CalendarIcon size={14} />
|
||||
</ThemeIcon>
|
||||
<Text size="sm" c="dimmed">
|
||||
{tournamentStart.toLocaleDateString(undefined, {
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
})}{" "}
|
||||
at{" "}
|
||||
{tournamentStart.toLocaleTimeString([], {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
})}
|
||||
</Text>
|
||||
</Group>
|
||||
</Flex>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
@@ -1,15 +1,17 @@
|
||||
import { Suspense, useMemo } from "react";
|
||||
import { Tournament } from "../../types";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { Box, Card, Divider, Group, Stack, Text, Title } from "@mantine/core";
|
||||
import { Box, Divider, Paper, SimpleGrid, Stack, Text } from "@mantine/core";
|
||||
import Countdown from "@/components/countdown";
|
||||
import ListLink from "@/components/list-link";
|
||||
import { TreeStructureIcon, UsersIcon } from "@phosphor-icons/react";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import EnrollTeam from "./enroll-team";
|
||||
import EnrollFreeAgent from "./enroll-free-agent";
|
||||
import TeamListButton from "./team-list-button";
|
||||
import EnrolledPlayersListButton from "./enrolled-players-list-button";
|
||||
import Header from "./header";
|
||||
import Header from "../started-tournament/header";
|
||||
import SectionHeading from "../started-tournament/sections/section-heading";
|
||||
import { NavTile } from "../started-tournament/sections/nav-grid";
|
||||
import TeamCardSkeleton from "@/features/teams/components/team-card-skeleton";
|
||||
import TeamCard from "@/features/teams/components/team-card";
|
||||
import RegionalTeamCard from "@/features/teams/components/regional-team-card";
|
||||
@@ -24,6 +26,7 @@ const UpcomingTournament: React.FC<{ tournament: Tournament }> = ({
|
||||
tournament,
|
||||
}) => {
|
||||
const { user, roles } = useAuth();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const isAdmin = useMemo(() => roles.includes("Admin"), [roles]);
|
||||
const userTeam = useMemo(
|
||||
@@ -52,121 +55,109 @@ const UpcomingTournament: React.FC<{ tournament: Tournament }> = ({
|
||||
<Stack gap="lg">
|
||||
<Header tournament={tournament} />
|
||||
|
||||
<Stack px="xs">
|
||||
{tournament.desc && <Text px="md" ta="center" size="sm" style={{ whiteSpace: 'pre-wrap' }}>{tournament.desc}</Text>}
|
||||
{tournament.desc && (
|
||||
<Text px="md" size="sm" c="dimmed" style={{ whiteSpace: "pre-wrap" }}>
|
||||
{tournament.desc}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
<Card
|
||||
withBorder
|
||||
p="lg"
|
||||
style={{
|
||||
borderRadius:
|
||||
"2px 2px var(--mantine-radius-lg) var(--mantine-radius-lg)",
|
||||
borderTop: "3px solid var(--mantine-primary-color-filled)",
|
||||
}}
|
||||
>
|
||||
<Stack gap="xs">
|
||||
<Group gap="xs" align="center">
|
||||
<UsersIcon size={16} />
|
||||
<Title mt={4} order={5}>
|
||||
Enrollment
|
||||
</Title>
|
||||
{isEnrollmentOpen && (
|
||||
<Box ml="auto">
|
||||
<Countdown
|
||||
date={enrollmentDeadline}
|
||||
label="Time left"
|
||||
color="yellow"
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<SectionHeading
|
||||
label="Enrollment"
|
||||
action={
|
||||
isEnrollmentOpen ? (
|
||||
<Countdown date={enrollmentDeadline} />
|
||||
) : undefined
|
||||
}
|
||||
/>
|
||||
<Box px="md">
|
||||
<Paper withBorder p="md">
|
||||
<Stack gap="sm">
|
||||
{!isUserEnrolled && !isEnrollmentOpen && (
|
||||
<Text fw={600} c="dimmed" size="sm">
|
||||
Enrollment has been closed for this tournament.
|
||||
</Text>
|
||||
)}
|
||||
</Group>
|
||||
|
||||
{!isUserEnrolled && !isEnrollmentOpen && (
|
||||
<Text fw={600} c="dimmed" size="sm">
|
||||
Enrollment has been closed for this tournament.
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{!isUserEnrolled && isEnrollmentOpen && !isFreeAgent && (
|
||||
<>
|
||||
{!tournament.regional && (
|
||||
<>
|
||||
<EnrollTeam
|
||||
tournamentId={tournament.id}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
<Divider my={0} label="or" />
|
||||
</>
|
||||
)}
|
||||
<EnrollFreeAgent
|
||||
tournamentId={tournament.id}
|
||||
isRegional={tournament.regional}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isUserEnrolled && (
|
||||
<>
|
||||
<Suspense fallback={<TeamCardSkeleton />}>
|
||||
{tournament.regional === true ? (
|
||||
<RegionalTeamCard teamId={userTeam.id} />
|
||||
) : (
|
||||
<TeamCard teamId={userTeam.id} />
|
||||
)}
|
||||
</Suspense>
|
||||
{tournament.regional !== true && (
|
||||
<>
|
||||
<UpdateTeam tournamentId={tournament.id} teamId={userTeam.id} />
|
||||
{isEnrollmentOpen && (
|
||||
<UnenrollTeam
|
||||
{!isUserEnrolled && isEnrollmentOpen && !isFreeAgent && (
|
||||
<>
|
||||
{!tournament.regional && (
|
||||
<>
|
||||
<EnrollTeam
|
||||
tournamentId={tournament.id}
|
||||
teamId={userTeam.id}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Divider my={0} label="or" />
|
||||
</>
|
||||
)}
|
||||
<EnrollFreeAgent
|
||||
tournamentId={tournament.id}
|
||||
isRegional={tournament.regional}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{
|
||||
isFreeAgent && isEnrollmentOpen && (
|
||||
{isUserEnrolled && (
|
||||
<>
|
||||
<Suspense fallback={<TeamCardSkeleton />}>
|
||||
{tournament.regional === true ? (
|
||||
<RegionalTeamCard teamId={userTeam.id} />
|
||||
) : (
|
||||
<TeamCard teamId={userTeam.id} />
|
||||
)}
|
||||
</Suspense>
|
||||
{tournament.regional !== true && (
|
||||
<>
|
||||
<UpdateTeam tournamentId={tournament.id} teamId={userTeam.id} />
|
||||
{isEnrollmentOpen && (
|
||||
<UnenrollTeam
|
||||
tournamentId={tournament.id}
|
||||
teamId={userTeam.id}
|
||||
onSubmit={handleSubmit}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{isFreeAgent && isEnrollmentOpen && (
|
||||
<EnrolledFreeAgent
|
||||
tournamentId={tournament.id}
|
||||
isRegional={tournament.regional}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
)}
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box>
|
||||
<Divider />
|
||||
{isAdmin && (
|
||||
<ListLink
|
||||
label={`Manage ${tournament.name}`}
|
||||
to={`/admin/tournaments/${tournament.id}`}
|
||||
Icon={UsersIcon}
|
||||
/>
|
||||
)}
|
||||
<ListLink
|
||||
label={`View Bracket`}
|
||||
to={`/tournaments/${tournament.id}/bracket`}
|
||||
Icon={TreeStructureIcon}
|
||||
disabled
|
||||
/>
|
||||
{tournament.regional === true ? (
|
||||
(tournament.teams && tournament.teams.length > 0) ? (
|
||||
<TeamListButton teams={tournament.teams} isRegional={true} />
|
||||
) : (
|
||||
<EnrolledPlayersListButton tournamentId={tournament.id} />
|
||||
)
|
||||
) : (
|
||||
<TeamListButton teams={tournament.teams || []} isRegional={false} />
|
||||
)}
|
||||
<RulesListButton tournamentId={tournament.id} />
|
||||
<Divider mb="sm" />
|
||||
<Box px="md">
|
||||
<SimpleGrid cols={3} spacing="sm" verticalSpacing="sm">
|
||||
{isAdmin && (
|
||||
<NavTile
|
||||
label="Manage"
|
||||
Icon={UsersIcon}
|
||||
onClick={() =>
|
||||
navigate({ to: `/admin/tournaments/${tournament.id}` })
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<NavTile label="Bracket" Icon={TreeStructureIcon} disabled />
|
||||
{tournament.regional === true ? (
|
||||
(tournament.teams && tournament.teams.length > 0) ? (
|
||||
<TeamListButton teams={tournament.teams} isRegional={true} />
|
||||
) : (
|
||||
<EnrolledPlayersListButton tournamentId={tournament.id} />
|
||||
)
|
||||
) : (
|
||||
<TeamListButton teams={tournament.teams || []} isRegional={false} />
|
||||
)}
|
||||
<RulesListButton tournamentId={tournament.id} />
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import ListButton from "@/components/list-button"
|
||||
import Sheet from "@/components/sheet/sheet"
|
||||
import { useSheet } from "@/hooks/use-sheet"
|
||||
import { ListIcon } from "@phosphor-icons/react"
|
||||
import { useTournament } from "../../queries"
|
||||
import { Button, Flex, Loader, Stack } from "@mantine/core"
|
||||
import { lazy, Suspense } from "react"
|
||||
import { NavTile } from "../started-tournament/sections/nav-grid"
|
||||
|
||||
const RulesContent = lazy(() => import("./rules-content"));
|
||||
|
||||
@@ -18,11 +18,7 @@ const RulesListButton: React.FC<RulesListButtonProps> = ({ tournamentId }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ListButton
|
||||
label={`View Rules`}
|
||||
Icon={ListIcon}
|
||||
onClick={open}
|
||||
/>
|
||||
<NavTile label="Rules" Icon={ListIcon} onClick={open} />
|
||||
|
||||
<Sheet title="Tournament Rules" opened={isOpen} onChange={toggle}>
|
||||
<Stack gap="xs">
|
||||
|
||||
@@ -1,44 +1,38 @@
|
||||
import { Box, Card, Divider, Flex, Group, Skeleton, Stack } from "@mantine/core";
|
||||
import { Box, Divider, Group, Paper, SimpleGrid, Skeleton, Stack } from "@mantine/core";
|
||||
|
||||
const UpcomingTournamentSkeleton = () => {
|
||||
return (
|
||||
<Stack gap="lg">
|
||||
<Flex px="md" justify="center" w="100%">
|
||||
<Skeleton height={318} width={318} radius="lg" />
|
||||
</Flex>
|
||||
<Stack align="center" gap={2}>
|
||||
<Skeleton height={16} w="30%" mb="md" />
|
||||
<Skeleton height={16} w="30%" />
|
||||
<Group px="md" gap="md" wrap="nowrap" align="center">
|
||||
<Skeleton height={64} width={64} radius="md" />
|
||||
<Stack gap={8} style={{ flex: 1 }}>
|
||||
<Skeleton height={14} width="55%" />
|
||||
<Skeleton height={14} width="40%" />
|
||||
</Stack>
|
||||
</Group>
|
||||
|
||||
<Stack px="md">
|
||||
<Card
|
||||
withBorder
|
||||
p="lg"
|
||||
style={{
|
||||
borderRadius:
|
||||
"2px 2px var(--mantine-radius-lg) var(--mantine-radius-lg)",
|
||||
}}
|
||||
>
|
||||
<Skeleton height={14} width="80%" mb={16} />
|
||||
<Group mb="sm" gap="xs" align="center">
|
||||
<Skeleton height={32} width={16} />
|
||||
<Skeleton height={32} width="20%" />
|
||||
<Box ml="auto">
|
||||
<Skeleton height={32} width={80} radius="sm" />
|
||||
</Box>
|
||||
</Group>
|
||||
<Group mb="sm" gap="xs" align="center">
|
||||
<Skeleton height={32} width={16} />
|
||||
<Skeleton height={32} width="20%" />
|
||||
<Box ml="auto">
|
||||
<Skeleton height={32} width={80} radius="sm" />
|
||||
</Box>
|
||||
</Group>
|
||||
</Card>
|
||||
</Stack>
|
||||
<Box>
|
||||
<Skeleton height={12} width={90} ml="md" mb={10} />
|
||||
<Box px="md">
|
||||
<Paper withBorder p="md">
|
||||
<Stack gap="sm">
|
||||
<Skeleton height={36} radius="sm" />
|
||||
<Skeleton height={36} radius="sm" />
|
||||
</Stack>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box px="md">
|
||||
<Divider mb="sm" />
|
||||
<SimpleGrid cols={3} spacing="sm" verticalSpacing="sm">
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<Skeleton key={index} height={72} radius="md" />
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpcomingTournamentSkeleton;
|
||||
export default UpcomingTournamentSkeleton;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import ListButton from "@/components/list-button"
|
||||
import Sheet from "@/components/sheet/sheet"
|
||||
import TeamList from "@/features/teams/components/team-list"
|
||||
import { TeamInfo } from "@/features/teams/types"
|
||||
import { useSheet } from "@/hooks/use-sheet"
|
||||
import { UsersIcon } from "@phosphor-icons/react"
|
||||
import { useMemo } from "react"
|
||||
import { NavTile } from "../started-tournament/sections/nav-grid"
|
||||
|
||||
interface TeamListButtonProps {
|
||||
teams: TeamInfo[]
|
||||
@@ -16,11 +16,7 @@ const TeamListButton: React.FC<TeamListButtonProps> = ({ teams, isRegional }) =>
|
||||
const { open, isOpen, toggle } = useSheet();
|
||||
return (
|
||||
<>
|
||||
<ListButton
|
||||
label={`View Teams (${count})`}
|
||||
Icon={UsersIcon}
|
||||
onClick={open}
|
||||
/>
|
||||
<NavTile label={`Teams (${count})`} Icon={UsersIcon} onClick={open} />
|
||||
|
||||
<Sheet title="Enrolled Teams" opened={isOpen} onChange={toggle}>
|
||||
<TeamList teams={teams} isRegional={isRegional} />
|
||||
@@ -29,4 +25,4 @@ const TeamListButton: React.FC<TeamListButtonProps> = ({ teams, isRegional }) =>
|
||||
)
|
||||
}
|
||||
|
||||
export default TeamListButton;
|
||||
export default TeamListButton;
|
||||
|
||||
Reference in New Issue
Block a user