Files
flxn-app/src/app/routes/_authed/admin/tournaments/run.$id.tsx
T
kyle e2863c1f6c feat(telemetry): collections, universal server-fn coverage, beacon, client tracker
- activities indexes + client_events/client_errors/rollups/alerts collections
- global function middleware via createStart; reads skipped on success
- actor stash, denial dedup, control-flow error guards
- api route logging, auth event overrides, beacon endpoint, web vitals
- centralized admin role checks, shared skeletons, award-badges fix
- extracted deriveRunState with tests
2026-08-25 21:33:25 -07:00

142 lines
4.9 KiB
TypeScript

import { createFileRoute, redirect } from "@tanstack/react-router";
import {
tournamentQueries,
useTournament,
} from "@/features/tournaments/queries";
import { ensureServerQueryData } from "@/lib/tanstack-query/utils/ensure";
import SeedTournament from "@/features/tournaments/components/seed-tournament";
import SetupGroupStage from "@/features/tournaments/components/setup-group-stage";
import GroupStageView from "@/features/tournaments/components/group-stage-view";
import { Container, Stack, Divider, Title, Box, Card, Group, Skeleton, SimpleGrid } from "@mantine/core";
import BracketView from "@/features/bracket/components/bracket-view";
import { SpotifyControlsBar } from "@/features/spotify/components";
import { useIsAdmin } from "@/features/core/hooks/use-is-admin";
import { useTournamentRunState } from "@/features/tournaments/hooks/use-tournament-run-state";
import { Trans } from "@lingui/react/macro";
import { msg } from "@lingui/core/macro";
export const Route = createFileRoute("/_authed/admin/tournaments/run/$id")({
beforeLoad: async ({ context, params }) => {
const { queryClient } = context;
const tournament = await ensureServerQueryData(
queryClient,
tournamentQueries.details(params.id)
);
if (!tournament) throw redirect({ to: "/admin/tournaments" });
return {
tournament,
};
},
loader: ({ context }) => ({
fullWidth: true,
withPadding: false,
showSpotifyPanel: true,
header: {
withBackButton: true,
title: msg`Run {name}`,
titleValues: { name: context.tournament.name },
},
}),
component: RouteComponent,
pendingComponent: RunTournamentPending,
});
function RunTournamentPending() {
return (
<Container size="md" px={0}>
<Box p="md">
<Stack gap="md">
<Group gap={0} grow mb="md">
{Array.from({ length: 4 }).map((_, index) => (
<Skeleton
key={`run-pending-tab-${index}`}
height={44}
radius="sm"
style={{ opacity: 0.85 - index * 0.1 }}
/>
))}
</Group>
<Card withBorder radius="md" p={0}>
<Group justify="space-between" p="sm">
<Skeleton height={16} width={120} radius="sm" />
<Skeleton height={22} width={22} radius="xl" />
</Group>
</Card>
<SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
{Array.from({ length: 6 }).map((_, index) => (
<Skeleton
key={`run-pending-match-${index}`}
height={100}
radius="md"
style={{ opacity: Math.max(1 - index * 0.12, 0.4) }}
/>
))}
</SimpleGrid>
</Stack>
</Box>
</Container>
);
}
function RouteComponent() {
const { id } = Route.useParams();
const { data: tournament } = useTournament(id);
const isAdmin = useIsAdmin();
const { hasGroupStage, hasKnockout, knockoutBracketPopulated, nextUpMatchId, bracket } =
useTournamentRunState(tournament.matches);
return (
<Container size="md" px={0}>
{ isAdmin && !tournament.regional && <SpotifyControlsBar />}
{tournament.matches?.length ? (
hasGroupStage && hasKnockout ? (
<Stack gap="xl">
<GroupStageView
groups={tournament.groups || []}
matches={tournament.matches}
showControls
tournamentId={tournament.id}
hasKnockoutBracket={knockoutBracketPopulated}
isRegional={tournament.regional}
groupConfig={tournament.group_config}
nextUpMatchId={nextUpMatchId}
/>
<Divider />
<div>
<Title order={3} ta="center" mb="md"><Trans>Knockout Bracket</Trans></Title>
<BracketView bracket={bracket} showControls groupConfig={tournament.group_config} nextUpMatchId={nextUpMatchId} />
</div>
</Stack>
) : hasGroupStage ? (
<GroupStageView
groups={tournament.groups || []}
matches={tournament.matches}
showControls
tournamentId={tournament.id}
hasKnockoutBracket={knockoutBracketPopulated}
isRegional={tournament.regional}
groupConfig={tournament.group_config}
nextUpMatchId={nextUpMatchId}
/>
) : (
<BracketView bracket={bracket} showControls groupConfig={tournament.group_config} nextUpMatchId={nextUpMatchId} />
)
) : (
tournament.regional === true ? (
<SetupGroupStage
tournamentId={tournament.id}
teams={tournament.teams || []}
/>
) : (
<SeedTournament
tournamentId={tournament.id}
teams={tournament.teams || []}
isRegional={tournament.regional}
/>
)
)}
</Container>
);
}