Files
flxn-app/src/features/tournaments/components/started-tournament/sections/nav-grid.tsx
T
2026-07-22 15:47:34 -07:00

165 lines
4.3 KiB
TypeScript

import { lazy, Suspense } from "react";
import {
Box,
Button,
Flex,
Loader,
SimpleGrid,
Stack,
Text,
UnstyledButton,
} from "@mantine/core";
import { Icon } from "@phosphor-icons/react";
import {
ListDashes,
ListIcon,
TreeStructureIcon,
UsersIcon,
} from "@phosphor-icons/react";
import { useNavigate } from "@tanstack/react-router";
import Sheet from "@/components/sheet/sheet";
import { useSheet } from "@/hooks/use-sheet";
import TeamList from "@/features/teams/components/team-list";
import WizardOrbIcon from "@/components/wizard-orb-icon";
import { Tournament } from "../../../types";
import classes from "./nav-grid.module.css";
const RulesContent = lazy(
() => import("../../upcoming-tournament/rules-content")
);
interface NavTileProps {
label: string;
Icon: Icon;
onClick: () => void;
}
/** 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}>
<span className={classes.icon}>
<Icon size={22} weight="bold" />
</span>
<Text size="xs" fw={600} lineClamp={2} lh={1.2}>
{label}
</Text>
</UnstyledButton>
);
interface NavGridProps {
tournament: Tournament;
isAdmin: boolean;
hasGroupStage: boolean;
isPredictable: boolean;
predictionsLocked: boolean;
hasSubmitted: boolean;
}
/**
* Consolidates the old stack of full-width ListLinks into a compact icon grid
* so it no longer dominates the page. Every original destination stays
* reachable with identical conditional visibility. Teams and Rules open sheets;
* everything else navigates.
*/
const NavGrid = ({
tournament,
isAdmin,
hasGroupStage,
isPredictable,
predictionsLocked,
hasSubmitted,
}: NavGridProps) => {
const navigate = useNavigate();
const teamsSheet = useSheet();
const rulesSheet = useSheet();
return (
<Box px="md">
<SimpleGrid cols={3} spacing="sm" verticalSpacing="sm">
{isAdmin && (
<NavTile
label="Manage"
Icon={UsersIcon}
onClick={() =>
navigate({ to: `/admin/tournaments/${tournament.id}` })
}
/>
)}
{hasGroupStage && (
<NavTile
label="Groups"
Icon={ListDashes}
onClick={() =>
navigate({ to: `/tournaments/${tournament.id}/groups` })
}
/>
)}
<NavTile
label="Bracket"
Icon={TreeStructureIcon}
onClick={() =>
navigate({ to: `/tournaments/${tournament.id}/bracket` })
}
/>
{isPredictable && !predictionsLocked && (
<NavTile
label={hasSubmitted ? "Edit Prediction" : "Make Prediction"}
Icon={WizardOrbIcon}
onClick={() =>
navigate({ to: `/tournaments/${tournament.id}/predictions/make` })
}
/>
)}
{isPredictable && (predictionsLocked || hasSubmitted) && (
<NavTile
label="Predictions"
Icon={WizardOrbIcon}
onClick={() =>
navigate({ to: `/tournaments/${tournament.id}/predictions` })
}
/>
)}
<NavTile
label={`Teams${
tournament.teams ? ` (${tournament.teams.length})` : ""
}`}
Icon={UsersIcon}
onClick={teamsSheet.open}
/>
<NavTile label="Rules" Icon={ListIcon} onClick={rulesSheet.open} />
</SimpleGrid>
<Sheet title="Enrolled Teams" {...teamsSheet.props}>
<TeamList
teams={tournament.teams || []}
isRegional={tournament.regional}
/>
</Sheet>
<Sheet title="Tournament Rules" {...rulesSheet.props}>
<Stack gap="xs">
<Suspense
fallback={
<Flex
justify="center"
align="center"
w="100%"
style={{ minHeight: "25vh" }}
>
<Loader size="lg" />
</Flex>
}
>
<RulesContent content={tournament.rules || ""} />
</Suspense>
<Button variant="subtle" c="red" onClick={rulesSheet.close}>
Close
</Button>
</Stack>
</Sheet>
</Box>
);
};
export default NavGrid;