169 lines
7.1 KiB
Svelte
169 lines
7.1 KiB
Svelte
<script>
|
|
import Button from '@/components/ui/button/button.svelte';
|
|
import Calendar from '@/components/ui/calendar/calendar.svelte';
|
|
import Input from '@/components/ui/input/input.svelte';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select';
|
|
import Textarea from '@/components/ui/textarea/textarea.svelte';
|
|
import AppLayout from '@/layouts/AppLayout.svelte';
|
|
import { router } from '@inertiajs/svelte';
|
|
import { format } from 'date-fns';
|
|
|
|
import { CalendarIcon } from 'lucide-svelte';
|
|
import { cn } from 'tailwind-variants';
|
|
|
|
// Form data
|
|
let form = $state({
|
|
name: '',
|
|
description: '',
|
|
location: '',
|
|
start_date: '',
|
|
end_date: '',
|
|
registration_deadline: '',
|
|
max_teams: 10,
|
|
status: 'draft',
|
|
field_ids: [],
|
|
team_ids: [],
|
|
});
|
|
|
|
// Form errors from backend
|
|
let errors = $state({});
|
|
|
|
// Date objects for calendar components
|
|
let startDate = $state(null);
|
|
|
|
// Status options
|
|
const statusOptions = [
|
|
{ value: 'draft', label: 'Draft' },
|
|
{ value: 'public', label: 'Public' },
|
|
{ value: 'private', label: 'Private' },
|
|
];
|
|
|
|
// Function to format dates for form submission
|
|
function formatDateForSubmission(date) {
|
|
return date ? format(date, 'yyyy-MM-dd') : '';
|
|
}
|
|
|
|
// Handle form submission
|
|
function handleSubmit(e) {
|
|
e.preventDefault();
|
|
// Update form with formatted dates
|
|
form.start_date = formatDateForSubmission(startDate);
|
|
|
|
// Submit the form
|
|
router.post('/tournaments', form, {
|
|
onError: (err) => {
|
|
errors = err;
|
|
},
|
|
onSuccess: () => {
|
|
// The redirect is handled by the controller
|
|
},
|
|
});
|
|
}
|
|
|
|
// Breadcrumbs
|
|
const breadcrumbs = [
|
|
{ title: 'Home', href: '/' },
|
|
{ title: 'Create Tournament', href: '/tournaments/create' },
|
|
];
|
|
</script>
|
|
|
|
<AppLayout {breadcrumbs}>
|
|
<div class="container mx-auto py-10">
|
|
<h1 class="text-2xl font-bold mb-6">Create New Tournament</h1>
|
|
<div class="bg-white dark:bg-gray-800 shadow-sm rounded-lg p-6">
|
|
<form onsubmit={handleSubmit} class="space-y-6">
|
|
<!-- Tournament Name -->
|
|
<div class="space-y-2">
|
|
<Label for="name">Tournament Name*</Label>
|
|
<Input id="name" type="text" bind:value={form.name} placeholder="Enter tournament name" />
|
|
{#if errors.name}
|
|
<p class="text-destructive text-sm">{errors.name}</p>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Description -->
|
|
<div class="space-y-2">
|
|
<Label for="description">Description</Label>
|
|
<Textarea id="description" bind:value={form.description} placeholder="Enter tournament description" />
|
|
<p class="text-muted-foreground text-sm">Provide a brief description of the tournament.</p>
|
|
{#if errors.description}
|
|
<p class="text-destructive text-sm">{errors.description}</p>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Location -->
|
|
<div class="space-y-2">
|
|
<Label for="location">Location</Label>
|
|
<Input id="location" type="text" bind:value={form.location} placeholder="Enter location" />
|
|
{#if errors.location}
|
|
<p class="text-destructive text-sm">{errors.location}</p>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Dates Section -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<!-- Start Date -->
|
|
<div class="space-y-2">
|
|
<Label>Start Date*</Label>
|
|
<Popover>
|
|
<PopoverTrigger>
|
|
<Button variant="outline" class={cn('w-full pl-3 text-left font-normal', !startDate && 'text-muted-foreground')}>
|
|
{#if startDate}
|
|
{format(startDate, 'PPP')}
|
|
{:else}
|
|
<span>Pick a date</span>
|
|
{/if}
|
|
<CalendarIcon class="ml-auto h-4 w-4 opacity-50" />
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent class="w-auto p-0" align="start">
|
|
<Calendar initialFocus type="single" bind:value={startDate} />
|
|
</PopoverContent>
|
|
</Popover>
|
|
{#if errors.start_date}
|
|
<p class="text-destructive text-sm">{errors.start_date}</p>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Configuration Section -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Max Teams -->
|
|
<div class="space-y-2">
|
|
<Label for="max_teams">Maximum Teams</Label>
|
|
<Input id="max_teams" type="number" min="2" bind:value={form.max_teams} />
|
|
<p class="text-muted-foreground text-sm">Maximum number of teams that can participate.</p>
|
|
{#if errors.max_teams}
|
|
<p class="text-destructive text-sm">{errors.max_teams}</p>
|
|
{/if}
|
|
</div>
|
|
|
|
<!-- Status -->
|
|
<div class="space-y-2">
|
|
<Label>Tournament Status*</Label>
|
|
<Select type="single" bind:value={form.status}>
|
|
<SelectTrigger class="w-full capitalize">{form.status ? form.status : 'Select a status'}</SelectTrigger>
|
|
<SelectContent>
|
|
{#each statusOptions as option (option.value)}
|
|
<SelectItem value={option.value}>{option.label}</SelectItem>
|
|
{/each}
|
|
</SelectContent>
|
|
</Select>
|
|
<p class="text-muted-foreground text-sm">Draft: Only you can see. Public: Anyone can see. Private: Only invited users.</p>
|
|
{#if errors.status}
|
|
<p class="text-destructive text-sm">{errors.status}</p>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Submit Buttons -->
|
|
<div class="flex justify-end gap-4 mt-8">
|
|
<Button type="button" variant="outline" href="/">Cancel</Button>
|
|
<Button type="submit">Create Tournament</Button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</AppLayout>
|