154 lines
4.8 KiB
TypeScript
154 lines
4.8 KiB
TypeScript
import { FileInput, Stack, TextInput, Textarea } from "@mantine/core";
|
|
import { useForm, UseFormInput } from "@mantine/form";
|
|
import { LinkIcon } from "@phosphor-icons/react";
|
|
import SlidePanel, { SlidePanelField } from "@/components/sheet/slide-panel";
|
|
import { TournamentFormInput } from "@/features/tournaments/types";
|
|
import { DateTimePicker } from "./date-time-picker";
|
|
import { isNotEmpty } from "@mantine/form";
|
|
import useCreateTournament from "../hooks/use-create-tournament";
|
|
import toast from '@/lib/sonner';
|
|
import { logger } from "..";
|
|
import { useQueryClient } from "@tanstack/react-query";
|
|
import { tournamentQueries } from "@/features/tournaments/queries";
|
|
|
|
const CreateTournament = ({ close }: { close: () => void }) => {
|
|
|
|
const config: UseFormInput<TournamentFormInput> = {
|
|
initialValues: { // TODO : Remove fake initial values
|
|
name: 'Test Tournament',
|
|
location: 'Test Location',
|
|
desc: 'Test Description',
|
|
start_time: '2025-01-01T00:00:00Z',
|
|
enroll_time: '2025-01-01T00:00:00Z',
|
|
},
|
|
onSubmitPreventDefault: 'always',
|
|
validate: {
|
|
name: isNotEmpty('Name is required'),
|
|
location: isNotEmpty('Location is required'),
|
|
start_time: isNotEmpty('Start time is required'),
|
|
enroll_time: isNotEmpty('Enrollment time is required'),
|
|
}
|
|
}
|
|
|
|
const form = useForm(config);
|
|
const queryClient = useQueryClient();
|
|
|
|
const { mutate: createTournament, isPending } = useCreateTournament();
|
|
|
|
const handleSubmit = async (values: TournamentFormInput) => {
|
|
const { logo, ...tournamentData } = values;
|
|
|
|
createTournament(tournamentData, {
|
|
onSuccess: async (tournament) => {
|
|
if (logo && tournament) {
|
|
try {
|
|
const formData = new FormData();
|
|
formData.append('tournamentId', tournament.id);
|
|
formData.append('logo', logo);
|
|
|
|
const response = await fetch('/api/tournaments/upload-logo', {
|
|
method: 'POST',
|
|
body: formData,
|
|
});
|
|
|
|
if (!response.ok) {
|
|
const error = await response.json();
|
|
throw new Error(error.error || 'Failed to upload logo');
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
queryClient.invalidateQueries({ queryKey: tournamentQueries.list().queryKey });
|
|
queryClient.setQueryData(
|
|
tournamentQueries.details(result.tournament!.id).queryKey,
|
|
result.tournament
|
|
);
|
|
|
|
toast.success('Tournament created successfully!');
|
|
} catch (error: any) {
|
|
toast.error(`Tournament created but logo upload failed: ${error.message}`);
|
|
logger.error('Tournament logo upload error', error);
|
|
}
|
|
}
|
|
close();
|
|
}
|
|
});
|
|
}
|
|
|
|
return (
|
|
<SlidePanel
|
|
onSubmit={form.onSubmit(handleSubmit)}
|
|
onCancel={close}
|
|
submitText="Create Tournament"
|
|
cancelText="Cancel"
|
|
loading={isPending}
|
|
>
|
|
<Stack>
|
|
<TextInput
|
|
label="Name"
|
|
withAsterisk
|
|
key={form.key('name')}
|
|
{...form.getInputProps('name')}
|
|
/>
|
|
<TextInput
|
|
label="Location"
|
|
withAsterisk
|
|
key={form.key('location')}
|
|
{...form.getInputProps('location')}
|
|
/>
|
|
|
|
<TextInput
|
|
label="Short Description"
|
|
key={form.key('desc')}
|
|
{...form.getInputProps('desc')}
|
|
/>
|
|
|
|
<FileInput
|
|
key={form.key('logo')}
|
|
accept="image/png,image/jpeg,image/gif,image/jpg"
|
|
label="Logo"
|
|
leftSection={<LinkIcon size={16} />}
|
|
{...form.getInputProps('logo')}
|
|
/>
|
|
|
|
<SlidePanelField
|
|
key={form.key('start_time')}
|
|
{...form.getInputProps('start_time')}
|
|
Component={DateTimePicker}
|
|
title="Select Start Date"
|
|
label="Start Date"
|
|
withAsterisk
|
|
formatValue={(date) => new Date(date).toLocaleDateString('en-US', {
|
|
weekday: 'short',
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
hour12: true
|
|
})}
|
|
/>
|
|
|
|
<SlidePanelField
|
|
key={form.key('enroll_time')}
|
|
{...form.getInputProps('enroll_time')}
|
|
Component={DateTimePicker}
|
|
title="Select Enrollment Due Date"
|
|
label="Enrollment Due"
|
|
withAsterisk
|
|
formatValue={(date) => new Date(date).toLocaleDateString('en-US', {
|
|
weekday: 'short',
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: 'numeric',
|
|
hour12: true
|
|
})}
|
|
/>
|
|
</Stack>
|
|
</SlidePanel>
|
|
);
|
|
};
|
|
|
|
export default CreateTournament; |