'use client' import { useState } from 'react' import { trpc } from '@/lib/trpc/client' import { toast } from 'sonner' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Badge } from '@/components/ui/badge' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog' import { Plus, Lock, Unlock, LockKeyhole, Loader2 } from 'lucide-react' import { cn } from '@/lib/utils' import { formatDistanceToNow } from 'date-fns' type SubmissionWindowManagerProps = { competitionId: string roundId: string } export function SubmissionWindowManager({ competitionId, roundId }: SubmissionWindowManagerProps) { const [isCreateOpen, setIsCreateOpen] = useState(false) const [name, setName] = useState('') const [slug, setSlug] = useState('') const [roundNumber, setRoundNumber] = useState(1) const utils = trpc.useUtils() // For now, we'll query all windows for the competition // In a real implementation, we'd filter by round or have a dedicated endpoint const { data: competition, isLoading } = trpc.competition.getById.useQuery({ id: competitionId, }) const createWindowMutation = trpc.round.createSubmissionWindow.useMutation({ onSuccess: () => { utils.competition.getById.invalidate({ id: competitionId }) toast.success('Submission window created') setIsCreateOpen(false) setName('') setSlug('') setRoundNumber(1) }, onError: (err) => toast.error(err.message), }) const openWindowMutation = trpc.round.openSubmissionWindow.useMutation({ onSuccess: () => { utils.competition.getById.invalidate({ id: competitionId }) toast.success('Window opened') }, onError: (err) => toast.error(err.message), }) const closeWindowMutation = trpc.round.closeSubmissionWindow.useMutation({ onSuccess: () => { utils.competition.getById.invalidate({ id: competitionId }) toast.success('Window closed') }, onError: (err) => toast.error(err.message), }) const lockWindowMutation = trpc.round.lockSubmissionWindow.useMutation({ onSuccess: () => { utils.competition.getById.invalidate({ id: competitionId }) toast.success('Window locked') }, onError: (err) => toast.error(err.message), }) const handleCreate = () => { if (!name || !slug) { toast.error('Name and slug are required') return } createWindowMutation.mutate({ competitionId, name, slug, roundNumber, }) } const handleNameChange = (value: string) => { setName(value) const autoSlug = value.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '') setSlug(autoSlug) } const windows = competition?.submissionWindows ?? [] return (
Submission Windows

File upload windows for this round

Create Submission Window
handleNameChange(e.target.value)} />
setSlug(e.target.value)} />
setRoundNumber(parseInt(e.target.value, 10))} />
{isLoading ? (
Loading windows...
) : windows.length === 0 ? (
No submission windows yet. Create one to enable file uploads.
) : (
{windows.map((window) => { const isPending = !window.windowOpenAt const isOpen = window.windowOpenAt && !window.windowCloseAt const isClosed = window.windowCloseAt && !window.isLocked const isLocked = window.isLocked return (

{window.name}

{isPending && ( Pending )} {isOpen && ( Open )} {isClosed && ( Closed )} {isLocked && ( Locked )}

{window.slug}

Round {window.roundNumber} {window._count.fileRequirements} requirements {window._count.projectFiles} files
{isPending && ( )} {isOpen && ( )} {isClosed && ( )}
) })}
)}
) }