enroll team polish?

This commit is contained in:
yohlo
2025-09-17 20:20:52 -05:00
parent cac42c9b29
commit 285a33c488
22 changed files with 411 additions and 124 deletions

View File

@@ -34,7 +34,15 @@ const TeamItem = memo(({ team, onUnenroll, disabled }: TeamItemProps) => {
return (
<Group py="xs" px="sm" w="100%" gap="sm" align="center">
<Avatar size={32} name={team.name} />
<Avatar
size={32}
name={team.name}
src={
team.logo
? `/api/files/teams/${team.id}/${team.logo}`
: undefined
}
/>
<Stack gap={0} style={{ flex: 1, minWidth: 0 }}>
<Text fw={500} truncate>
{team.name}

View File

@@ -27,11 +27,11 @@ interface SeedTournamentProps {
const SeedTournament: React.FC<SeedTournamentProps> = ({
tournamentId,
teams
teams,
}) => {
const [orderedTeams, setOrderedTeams] = useState<TeamInfo[]>(teams);
const { data: bracketPreview } = useBracketPreview(teams.length);
const queryClient = useQueryClient()
const queryClient = useQueryClient();
const bracket: BracketData = useMemo(
() => ({
@@ -48,7 +48,7 @@ const SeedTournament: React.FC<SeedTournamentProps> = ({
: undefined,
}))
),
losers: bracketPreview.losers
losers: bracketPreview.losers,
}),
[bracketPreview, orderedTeams]
);
@@ -58,8 +58,8 @@ const SeedTournament: React.FC<SeedTournamentProps> = ({
successMessage: "Tournament bracket generated successfully!",
onSuccess: () => {
queryClient.invalidateQueries({
queryKey: tournamentKeys.details(tournamentId)
})
queryKey: tournamentKeys.details(tournamentId),
});
},
});
@@ -99,7 +99,7 @@ const SeedTournament: React.FC<SeedTournamentProps> = ({
};
return (
<div style={{ display: 'flex', gap: '2rem', alignItems: 'flex-start' }}>
<div style={{ display: "flex", gap: "2rem", alignItems: "flex-start" }}>
<Stack gap="lg" style={{ flexShrink: 0 }}>
<Stack gap={0} pos="relative" w={400}>
<LoadingOverlay visible={generateBracket.isPending} />
@@ -171,7 +171,16 @@ const SeedTournament: React.FC<SeedTournamentProps> = ({
}}
/>
<Avatar size={24} radius="sm" name={team.name} />
<Avatar
size={24}
radius="sm"
name={team.name}
src={
team.logo
? `/api/files/teams/${team.id}/${team.logo}`
: undefined
}
/>
<Text fw={500} size="sm" style={{ flex: 1 }}>
{team.name}
@@ -197,8 +206,8 @@ const SeedTournament: React.FC<SeedTournamentProps> = ({
Confirm Seeding
</Button>
</Stack>
<div style={{ flex: 1, overflow: 'auto' }}>
<div style={{ flex: 1, overflow: "auto" }}>
<BracketView bracket={bracket} />
</div>
</div>

View File

@@ -8,12 +8,16 @@ import TeamForm from "@/features/teams/components/team-form";
import { teamQueries } from "@/features/teams/queries";
import { Team } from "@/features/teams/types";
import { useQuery } from "@tanstack/react-query";
import { Loader } from "@mantine/core";
import useEnrollTeam from "@/features/tournaments/hooks/use-enroll-team";
import { useServerQuery } from "@/lib/tanstack-query/hooks";
interface EnrollTeamProps {
tournamentId: string;
onSubmit: () => void;
}
const EnrollTeam = ({ tournamentId }: EnrollTeamProps) => {
const EnrollTeam = ({ tournamentId, onSubmit }: EnrollTeamProps) => {
const { open, isOpen, toggle } = useSheet();
const { user } = useAuth();
@@ -22,14 +26,14 @@ const EnrollTeam = ({ tournamentId }: EnrollTeamProps) => {
const [showTeamForm, setShowTeamForm] = useState<boolean>(!hasTeams);
const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);
const { data: teamData } = useQuery({
const { data: teamData } = useServerQuery({
...teamQueries.details(selectedTeamId!),
enabled: !!selectedTeamId,
options: { enabled: !!selectedTeamId }
});
useEffect(() => {
if (teamData?.success) {
setSelectedTeam(teamData.data);
if (teamData) {
setSelectedTeam(teamData);
setShowTeamForm(true);
}
}, [teamData]);
@@ -71,6 +75,16 @@ const EnrollTeam = ({ tournamentId }: EnrollTeamProps) => {
};
}, [selectedTeam]);
const { mutate: enrollTeam, isPending: isEnrolling } = useEnrollTeam();
const handleEnrollTeam = (teamId: string) => {
enrollTeam({ tournamentId, teamId }, {
onSuccess: () => {
toggle();
onSubmit();
}
});
}
return (
<>
<Button size="sm" onClick={open}>
@@ -78,12 +92,14 @@ const EnrollTeam = ({ tournamentId }: EnrollTeamProps) => {
</Button>
<Sheet title={showTeamForm ? "Team Details" : "Enroll Team"} opened={isOpen} onChange={toggle}>
{showTeamForm ? (
{ isEnrolling && <Loader size="lg" /> }
{showTeamForm && !isEnrolling ? (
<TeamForm
close={handleBack}
tournamentId={tournamentId}
initialValues={initialValues}
teamId={selectedTeamId}
onSubmit={handleEnrollTeam}
/>
) : (
<>

View File

@@ -1,27 +1,21 @@
import { useMemo } from "react";
import { Suspense, useCallback, useMemo } from "react";
import { Tournament } from "../../types";
import { useAuth } from "@/contexts/auth-context";
import {
Box,
Card,
Divider,
Group,
Stack,
Text,
} from "@mantine/core";
import { Box, Button, Card, Divider, Group, Stack, Text } from "@mantine/core";
import Countdown from "@/components/countdown";
import ListLink from "@/components/list-link";
import ListButton from "@/components/list-button";
import {
UsersIcon,
ListIcon,
} from "@phosphor-icons/react";
import { UsersIcon, ListIcon } from "@phosphor-icons/react";
import EnrollTeam from "./enroll-team";
import EnrollFreeAgent from "./enroll-free-agent";
import TeamListButton from "./team-list-button";
import Header from "./header";
import EmojiPicker from "@/features/reactions/components/emoji-picker";
import EmojiBar from "@/features/reactions/components/emoji-bar";
import TeamCardSkeleton from "@/features/teams/components/team-card-skeleton";
import TeamCard from "@/features/teams/components/team-card";
import UpdateTeam from "./update-team";
import UnenrollTeam from "./unenroll-team";
import { useQueryClient } from "@tanstack/react-query";
import { tournamentKeys } from "../../queries";
const UpcomingTournament: React.FC<{ tournament: Tournament }> = ({
tournament,
@@ -43,18 +37,21 @@ const UpcomingTournament: React.FC<{ tournament: Tournament }> = ({
: new Date(tournament.start_time);
const isEnrollmentOpen = enrollmentDeadline > new Date();
const queryClient = useQueryClient();
const handleSubmit = () => {
queryClient.invalidateQueries({ queryKey: tournamentKeys.current })
}
console.log(userTeam)
return (
<Stack gap="lg">
<Header tournament={tournament} />
<EmojiBar />
{tournament.desc && <Text size="sm">{tournament.desc}</Text>}
<Card withBorder radius="md" p="lg">
<Card withBorder radius="lg" p="lg">
<Stack gap="xs">
<Group mb='sm' gap="xs" align="center">
<Group mb="sm" gap="xs" align="center">
<UsersIcon size={16} />
<Text size="sm" fw={500}>
Enrollment
@@ -70,17 +67,29 @@ const UpcomingTournament: React.FC<{ tournament: Tournament }> = ({
)}
</Group>
{!isEnrollmentOpen && !isUserEnrolled && (
<Text fw={600} c="dimmed" size="sm">Enrollment has been closed for this tournament.</Text>
{!isUserEnrolled &&!isEnrollmentOpen && (
<Text fw={600} c="dimmed" size="sm">
Enrollment has been closed for this tournament.
</Text>
)}
{!isUserEnrolled && isEnrollmentOpen && (
{!isUserEnrolled &&isEnrollmentOpen && (
<>
<EnrollTeam tournamentId={tournament.id} />
<EnrollTeam tournamentId={tournament.id} onSubmit={handleSubmit} />
<Divider my={0} label="or" />
<EnrollFreeAgent />
</>
)}
{
isUserEnrolled && <>
<Suspense fallback={<TeamCardSkeleton />}>
<TeamCard teamId={userTeam.id} />
</Suspense>
<UpdateTeam tournamentId={tournament.id} teamId={userTeam.id} />
{ isEnrollmentOpen && <UnenrollTeam tournamentId={tournament.id} teamId={userTeam.id} onSubmit={handleSubmit} />}
</>
}
</Stack>
</Card>

View File

@@ -0,0 +1,46 @@
import Button from "@/components/button";
import Sheet from "@/components/sheet/sheet";
import { useSheet } from "@/hooks/use-sheet";
import { useCallback } from "react";
import useUnenrollTeam from "../../hooks/use-unenroll-team";
import { Stack, Text } from "@mantine/core";
interface UnenrollTeamProps {
tournamentId: string;
teamId: string
onSubmit: () => void;
}
const UnenrollTeam = ({ tournamentId, teamId, onSubmit }: UnenrollTeamProps) => {
const { open, isOpen, toggle } = useSheet();
const { mutate: unenrollTeam } = useUnenrollTeam();
const handleUnenrollTeam = useCallback(
async () => {
await unenrollTeam({ tournamentId, teamId }, {
onSuccess: () => {
toggle();
onSubmit();
}
});
},
[unenrollTeam, tournamentId]
);
return (
<>
<Button size="sm" onClick={open} variant="subtle">
Unenroll
</Button>
<Sheet title={"Unenroll Team"} opened={isOpen} onChange={toggle}>
<Stack gap='xs'>
<Text size="sm" fw={500}>Are you sure you want to unenroll from this tournament? You can enroll again at any point before the deadline.</Text>
<Button onClick={handleUnenrollTeam}>Confirm</Button>
<Button variant="subtle" color="red" onClick={toggle}>Cancel</Button>
</Stack>
</Sheet>
</>
);
};
export default UnenrollTeam;

View File

@@ -0,0 +1,59 @@
import Button from "@/components/button";
import Sheet from "@/components/sheet/sheet";
import { useAuth } from "@/contexts/auth-context";
import { useSheet } from "@/hooks/use-sheet";
import { useMemo, useState, useCallback, useEffect } from "react";
import TeamSelectionView from "./enroll-team/team-selection-view";
import TeamForm from "@/features/teams/components/team-form";
import { teamQueries, useTeam } from "@/features/teams/queries";
import { Team } from "@/features/teams/types";
import { useQuery } from "@tanstack/react-query";
import { Loader } from "@mantine/core";
import useEnrollTeam from "@/features/tournaments/hooks/use-enroll-team";
interface UpdateTeamProps {
tournamentId: string;
teamId: string
}
const UpdateTeam = ({ tournamentId, teamId }: UpdateTeamProps) => {
const { open, isOpen, toggle } = useSheet();
const { data: team } = useTeam(teamId);
const initialValues = useMemo(() => {
if (!team) return undefined;
return {
name: team.name,
song_id: team.song_id,
song_name: team.song_name,
song_artist: team.song_artist,
song_album: team.song_album,
song_start: team.song_start,
song_end: team.song_end,
song_image_url: team.song_image_url,
players: team.players?.map(player => player.id),
};
}, [team]);
return (
<>
<Button size="sm" onClick={open}>
Update Team
</Button>
<Sheet title={"Update Team"} opened={isOpen} onChange={toggle}>
<TeamForm
close={toggle}
tournamentId={tournamentId}
initialValues={initialValues}
teamId={teamId}
onSubmit={(_) => close()}
/>
</Sheet>
</>
);
};
export default UpdateTeam;