'use client' import { Suspense, use, useState, useEffect, useCallback } from 'react' import Link from 'next/link' import { useRouter } 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 { Textarea } from '@/components/ui/textarea' import { Badge } from '@/components/ui/badge' import { Skeleton } from '@/components/ui/skeleton' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from '@/components/ui/form' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { FileUpload } from '@/components/shared/file-upload' import { ProjectLogo } from '@/components/shared/project-logo' import { LogoUpload } from '@/components/shared/logo-upload' import { ArrowLeft, Loader2, AlertCircle, Trash2, X, Plus, FileText, Film, Presentation, FileIcon, } from 'lucide-react' import { formatFileSize } from '@/lib/utils' interface PageProps { params: Promise<{ id: string }> } const updateProjectSchema = z.object({ title: z.string().min(1, 'Title is required').max(500), teamName: z.string().optional(), description: z.string().optional(), status: z.enum([ 'SUBMITTED', 'ELIGIBLE', 'ASSIGNED', 'SEMIFINALIST', 'FINALIST', 'REJECTED', ]), tags: z.array(z.string()), }) type UpdateProjectForm = z.infer // File type icons const fileTypeIcons: Record = { EXEC_SUMMARY: , PRESENTATION: , VIDEO: , OTHER: , } function EditProjectContent({ projectId }: { projectId: string }) { const router = useRouter() const [tagInput, setTagInput] = useState('') // Fetch project data const { data: project, isLoading } = trpc.project.get.useQuery({ id: projectId, }) // Fetch files const { data: files, refetch: refetchFiles } = trpc.file.listByProject.useQuery({ projectId, }) // Fetch logo URL const { data: logoUrl, refetch: refetchLogo } = trpc.logo.getUrl.useQuery({ projectId, }) // Fetch existing tags for suggestions const { data: existingTags } = trpc.project.getTags.useQuery({ roundId: project?.roundId, }) // Mutations const updateProject = trpc.project.update.useMutation({ onSuccess: () => { router.push(`/admin/projects/${projectId}`) }, }) const deleteProject = trpc.project.delete.useMutation({ onSuccess: () => { router.push('/admin/projects') }, }) const deleteFile = trpc.file.delete.useMutation({ onSuccess: () => { refetchFiles() }, }) // Initialize form const form = useForm({ resolver: zodResolver(updateProjectSchema), defaultValues: { title: '', teamName: '', description: '', status: 'SUBMITTED', tags: [], }, }) // Update form when project loads useEffect(() => { if (project) { form.reset({ title: project.title, teamName: project.teamName || '', description: project.description || '', status: project.status as UpdateProjectForm['status'], tags: project.tags || [], }) } }, [project, form]) const tags = form.watch('tags') // Add tag const addTag = useCallback(() => { const tag = tagInput.trim() if (tag && !tags.includes(tag)) { form.setValue('tags', [...tags, tag]) setTagInput('') } }, [tagInput, tags, form]) // Remove tag const removeTag = useCallback( (tag: string) => { form.setValue( 'tags', tags.filter((t) => t !== tag) ) }, [tags, form] ) const onSubmit = async (data: UpdateProjectForm) => { await updateProject.mutateAsync({ id: projectId, title: data.title, teamName: data.teamName || null, description: data.description || null, status: data.status, tags: data.tags, }) } const handleDelete = async () => { await deleteProject.mutateAsync({ id: projectId }) } const handleDeleteFile = async (fileId: string) => { await deleteFile.mutateAsync({ id: fileId }) } if (isLoading) { return } if (!project) { return (

Project Not Found

) } const isPending = updateProject.isPending || deleteProject.isPending // Filter tag suggestions (exclude already selected) const tagSuggestions = existingTags?.filter((t) => !tags.includes(t)).slice(0, 5) || [] return (
{/* Header */}

Edit Project

Update project information and manage files

{/* Form */}
{/* Basic Information */} Basic Information {/* Project Logo */}
Project Logo Upload a logo for this project. It will be displayed in project lists and cards.
refetchLogo()} />
( Title )} /> ( Team Name )} /> ( Description