work on team enrollment
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
import Button from "@/components/button";
|
||||
import Sheet from "@/components/sheet/sheet";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import { useSheet } from "@/hooks/use-sheet";
|
||||
import { Text } from "@mantine/core";
|
||||
|
||||
const EnrollFreeAgent = () => {
|
||||
const { open, isOpen, toggle } = useSheet();
|
||||
const { user } = useAuth();
|
||||
return (
|
||||
<>
|
||||
<Button variant="subtle" size="sm" onClick={open}>
|
||||
Enroll As Free Agent
|
||||
</Button>
|
||||
|
||||
<Sheet title="Free Agent Enrollment" opened={isOpen} onChange={toggle}>
|
||||
<Text size="md" mb="md">
|
||||
Enrolling as a free agent will enter you in a pool of players wanting to play but don't have a teammate yet.
|
||||
</Text>
|
||||
<Text size="sm" mb="md" c='dimmed'>
|
||||
You will be automatically paired with a partner before the tournament starts, and you will be able to see your new team and set a walkout song in the app.
|
||||
</Text>
|
||||
<Button onClick={console.log}>Confirm</Button>
|
||||
</Sheet>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EnrollFreeAgent;
|
||||
@@ -0,0 +1,61 @@
|
||||
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 } from "react";
|
||||
import TeamSelectionView from "./team-selection-view";
|
||||
import TeamForm from "@/features/teams/components/team-form";
|
||||
|
||||
interface EnrollTeamProps {
|
||||
tournamentId: string;
|
||||
}
|
||||
|
||||
const EnrollTeam = ({ tournamentId }: EnrollTeamProps) => {
|
||||
const { open, isOpen, toggle } = useSheet();
|
||||
const { user } = useAuth();
|
||||
|
||||
const hasTeams = useMemo(() => !!user?.teams?.length, [user?.teams]);
|
||||
const [selectedTeamId, setSelectedTeamId] = useState<string>();
|
||||
const [showTeamForm, setShowTeamForm] = useState<boolean>(!!hasTeams);
|
||||
|
||||
const teamOptions = useMemo(() =>
|
||||
user?.teams?.map(team => ({
|
||||
value: team.id,
|
||||
label: team.name
|
||||
})) || [],
|
||||
[user?.teams]
|
||||
);
|
||||
|
||||
const handleSelect = useCallback((teamId: string | undefined) => {
|
||||
setSelectedTeamId(teamId);
|
||||
setShowTeamForm(true);
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button size="sm" onClick={open}>
|
||||
Enroll Your Team
|
||||
</Button>
|
||||
|
||||
<Sheet title={showTeamForm ? "Team Details" : "Enroll Team"} opened={!isOpen} onChange={toggle}>
|
||||
{showTeamForm ? (
|
||||
<TeamForm close={console.log} tournamentId={tournamentId} />
|
||||
) : (
|
||||
<>
|
||||
<TeamSelectionView
|
||||
options={teamOptions}
|
||||
onSelect={handleSelect}
|
||||
/>
|
||||
<Button mt='sm' variant="subtle" color='red' size="sm" onClick={toggle}>
|
||||
Cancel
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
|
||||
</Sheet>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default EnrollTeam;
|
||||
@@ -0,0 +1,57 @@
|
||||
import { Stack, Button, Divider, Autocomplete, Group, ComboboxItem } from '@mantine/core';
|
||||
import { PlusIcon } from '@phosphor-icons/react';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
|
||||
interface TeamSelectionViewProps {
|
||||
options: ComboboxItem[];
|
||||
onSelect: (teamId: string | undefined) => void;
|
||||
}
|
||||
|
||||
const TeamSelectionView: React.FC<TeamSelectionViewProps> = React.memo(({
|
||||
options,
|
||||
onSelect
|
||||
}) => {
|
||||
const [value, setValue] = useState<string>();
|
||||
const selectedOption = useMemo(() => options.find(option => option.label === value), [value])
|
||||
|
||||
|
||||
const handleCreateNewTeamClicked = () => onSelect(undefined);
|
||||
const handleSelectExistingTeam = () => onSelect(selectedOption?.value)
|
||||
|
||||
return (
|
||||
<Stack gap="md">
|
||||
<Button
|
||||
leftSection={<PlusIcon weight="bold" />}
|
||||
onClick={handleCreateNewTeamClicked}
|
||||
variant="light"
|
||||
fullWidth
|
||||
>
|
||||
Create New Team
|
||||
</Button>
|
||||
|
||||
<Divider my="sm" label="or" />
|
||||
|
||||
<Stack gap="sm">
|
||||
<Autocomplete
|
||||
placeholder="Select one of your existing teams"
|
||||
value={selectedOption?.label || ''}
|
||||
onChange={setValue}
|
||||
data={options.map(option => option.label)}
|
||||
comboboxProps={{ withinPortal: false }}
|
||||
/>
|
||||
|
||||
<Button
|
||||
onClick={handleSelectExistingTeam}
|
||||
disabled={!selectedOption}
|
||||
fullWidth
|
||||
>
|
||||
Enroll Selected Team
|
||||
</Button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
});
|
||||
|
||||
TeamSelectionView.displayName = 'TeamSelectionView';
|
||||
|
||||
export default TeamSelectionView;
|
||||
@@ -1,72 +1,81 @@
|
||||
import { Group, Stack, ThemeIcon, Text } from "@mantine/core";
|
||||
import { Tournament } from "../../types";
|
||||
import Avatar from "@/components/avatar";
|
||||
import { CalendarIcon, MapPinIcon, TrophyIcon, UsersIcon } from "@phosphor-icons/react";
|
||||
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]);
|
||||
const teamCount = useMemo(() => tournament.teams?.length || 0, [tournament.teams]);
|
||||
const Header = ({ tournament }: { tournament: Tournament }) => {
|
||||
const tournamentStart = useMemo(
|
||||
() => new Date(tournament.start_time),
|
||||
[tournament.start_time]
|
||||
);
|
||||
const teamCount = useMemo(
|
||||
() => tournament.teams?.length || 0,
|
||||
[tournament.teams]
|
||||
);
|
||||
|
||||
return (
|
||||
<Group justify="space-around" align="flex-start" w='100%'>
|
||||
<Group align="center" gap="lg">
|
||||
<Avatar
|
||||
name={tournament.name}
|
||||
src={
|
||||
tournament.logo
|
||||
? `/api/files/tournaments/${tournament.id}/${tournament.logo}`
|
||||
: undefined
|
||||
}
|
||||
radius="md"
|
||||
size={200}
|
||||
px='md'
|
||||
withBorder={false}
|
||||
>
|
||||
<TrophyIcon size={32} />
|
||||
</Avatar>
|
||||
<Stack gap="xs">
|
||||
{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>
|
||||
)}
|
||||
return (
|
||||
<Stack align="center" gap="lg">
|
||||
<Avatar
|
||||
name={tournament.name}
|
||||
src={
|
||||
tournament.logo
|
||||
? `/api/files/tournaments/${tournament.id}/${tournament.logo}`
|
||||
: undefined
|
||||
}
|
||||
radius="md"
|
||||
size={200}
|
||||
px="xs"
|
||||
withBorder={false}
|
||||
>
|
||||
<TrophyIcon size={32} />
|
||||
</Avatar>
|
||||
<Stack gap="xs">
|
||||
{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>
|
||||
|
||||
<Group gap="xs">
|
||||
<ThemeIcon size="sm" variant="light" radius="sm">
|
||||
<UsersIcon size={14} />
|
||||
</ThemeIcon>
|
||||
<Text size="sm" c="dimmed">
|
||||
{teamCount} teams enrolled
|
||||
</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
<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>
|
||||
</Group>
|
||||
)
|
||||
}
|
||||
|
||||
export default Header;
|
||||
<Group gap="xs">
|
||||
<ThemeIcon size="sm" variant="light" radius="sm">
|
||||
<UsersIcon size={14} />
|
||||
</ThemeIcon>
|
||||
<Text size="sm" c="dimmed">
|
||||
{teamCount} teams enrolled
|
||||
</Text>
|
||||
</Group>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
||||
@@ -1,30 +1,23 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useMemo } from "react";
|
||||
import { Tournament } from "../../types";
|
||||
import { useAuth } from "@/contexts/auth-context";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Card,
|
||||
Divider,
|
||||
Group,
|
||||
Stack,
|
||||
Title,
|
||||
Text,
|
||||
ThemeIcon,
|
||||
} from "@mantine/core";
|
||||
import Avatar from "@/components/avatar";
|
||||
import Countdown from "@/components/countdown";
|
||||
import ListLink from "@/components/list-link";
|
||||
import ListButton from "@/components/list-button";
|
||||
import {
|
||||
TrophyIcon,
|
||||
CalendarIcon,
|
||||
MapPinIcon,
|
||||
UsersIcon,
|
||||
ListIcon,
|
||||
} from "@phosphor-icons/react";
|
||||
import EnrollTeam from "../enroll-team";
|
||||
import EnrollFreeAgent from "../enroll-free-agent";
|
||||
import EnrollTeam from "./enroll-team";
|
||||
import EnrollFreeAgent from "./enroll-free-agent";
|
||||
import TeamListButton from "./team-list-button";
|
||||
import Header from "./header";
|
||||
|
||||
@@ -56,8 +49,8 @@ const UpcomingTournament: React.FC<{ tournament: Tournament }> = ({
|
||||
{tournament.desc && <Text size="sm">{tournament.desc}</Text>}
|
||||
|
||||
<Card withBorder radius="md" p="lg">
|
||||
<Stack gap="md">
|
||||
<Group gap="xs" align="center">
|
||||
<Stack gap="xs">
|
||||
<Group mb='sm' gap="xs" align="center">
|
||||
<UsersIcon size={16} />
|
||||
<Text size="sm" fw={500}>
|
||||
Enrollment
|
||||
@@ -73,10 +66,14 @@ 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 && (
|
||||
<>
|
||||
<EnrollTeam />
|
||||
<Divider label="or" />
|
||||
<EnrollTeam tournamentId={tournament.id} />
|
||||
<Divider my={0} label="or" />
|
||||
<EnrollFreeAgent />
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user