'use client' import { Suspense, useState } from 'react' import Link from 'next/link' import { useRouter, useSearchParams } from 'next/navigation' import { useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import { trpc } from '@/lib/trpc/client' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Skeleton } from '@/components/ui/skeleton' import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form' import { RoundTypeSettings } from '@/components/forms/round-type-settings' import { ArrowLeft, Loader2, AlertCircle } from 'lucide-react' import { DateTimePicker } from '@/components/ui/datetime-picker' const createRoundSchema = z.object({ programId: z.string().min(1, 'Please select a program'), name: z.string().min(1, 'Name is required').max(255), requiredReviews: z.number().int().min(1).max(10), votingStartAt: z.date().nullable().optional(), votingEndAt: z.date().nullable().optional(), }).refine((data) => { if (data.votingStartAt && data.votingEndAt) { return data.votingEndAt > data.votingStartAt } return true }, { message: 'End date must be after start date', path: ['votingEndAt'], }) type CreateRoundForm = z.infer function CreateRoundContent() { const router = useRouter() const searchParams = useSearchParams() const programIdParam = searchParams.get('program') const [roundType, setRoundType] = useState<'FILTERING' | 'EVALUATION' | 'LIVE_EVENT'>('EVALUATION') const [roundSettings, setRoundSettings] = useState>({}) const utils = trpc.useUtils() const { data: programs, isLoading: loadingPrograms } = trpc.program.list.useQuery() const createRound = trpc.round.create.useMutation({ onSuccess: (data) => { utils.program.list.invalidate({ includeRounds: true }) router.push(`/admin/rounds/${data.id}`) }, }) const form = useForm({ resolver: zodResolver(createRoundSchema), defaultValues: { programId: programIdParam || '', name: '', requiredReviews: 3, votingStartAt: null, votingEndAt: null, }, }) const onSubmit = async (data: CreateRoundForm) => { await createRound.mutateAsync({ programId: data.programId, name: data.name, roundType, requiredReviews: data.requiredReviews, settingsJson: roundSettings, votingStartAt: data.votingStartAt ?? undefined, votingEndAt: data.votingEndAt ?? undefined, }) } if (loadingPrograms) { return } if (!programs || programs.length === 0) { return (

No Programs Found

Create a program first before creating rounds

) } return (
{/* Header */}

Create Round

Set up a new selection round for project evaluation

{/* Form */}
Basic Information ( Edition )} /> ( Round Name A descriptive name for this selection round )} /> ( Required Reviews per Project field.onChange(parseInt(e.target.value) || 1)} /> Minimum number of evaluations each project should receive )} /> {/* Round Type & Settings */} Voting Window Optional: Set when jury members can submit their evaluations
( Start Date & Time )} /> ( End Date & Time )} />

Leave empty to set the voting window later. Past dates are allowed.

{/* Error */} {createRound.error && (

{createRound.error.message}

)} {/* Actions */}
) } function CreateRoundSkeleton() { return (
) } export default function CreateRoundPage() { return ( }> ) }