'use client' import { useState } from 'react' import { useRouter } from 'next/navigation' import Link from 'next/link' import dynamic from 'next/dynamic' import { trpc } from '@/lib/trpc/client' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Textarea } from '@/components/ui/textarea' import { Switch } from '@/components/ui/switch' import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { toast } from 'sonner' import { ArrowLeft, Save, Loader2, FileText, Video, Link as LinkIcon, File } from 'lucide-react' // Dynamically import BlockEditor to avoid SSR issues const BlockEditor = dynamic( () => import('@/components/shared/block-editor').then((mod) => mod.BlockEditor), { ssr: false, loading: () => (
), } ) const resourceTypeOptions = [ { value: 'DOCUMENT', label: 'Document', icon: FileText }, { value: 'PDF', label: 'PDF', icon: FileText }, { value: 'VIDEO', label: 'Video', icon: Video }, { value: 'LINK', label: 'External Link', icon: LinkIcon }, { value: 'OTHER', label: 'Other', icon: File }, ] const cohortOptions = [ { value: 'ALL', label: 'All Members', description: 'Visible to everyone' }, { value: 'SEMIFINALIST', label: 'Semi-finalists', description: 'Visible to semi-finalist evaluators' }, { value: 'FINALIST', label: 'Finalists', description: 'Visible to finalist evaluators only' }, ] export default function NewLearningResourcePage() { const router = useRouter() // Form state const [title, setTitle] = useState('') const [description, setDescription] = useState('') const [contentJson, setContentJson] = useState('') const [resourceType, setResourceType] = useState('DOCUMENT') const [cohortLevel, setCohortLevel] = useState('ALL') const [externalUrl, setExternalUrl] = useState('') const [isPublished, setIsPublished] = useState(false) // API const { data: programs } = trpc.program.list.useQuery({ status: 'ACTIVE' }) const [programId, setProgramId] = useState(null) const createResource = trpc.learningResource.create.useMutation() const getUploadUrl = trpc.learningResource.getUploadUrl.useMutation() // Handle file upload for BlockNote const handleUploadFile = async (file: File): Promise => { try { const { url, bucket, objectKey } = await getUploadUrl.mutateAsync({ fileName: file.name, mimeType: file.type, }) // Upload to MinIO await fetch(url, { method: 'PUT', body: file, headers: { 'Content-Type': file.type, }, }) // Return the MinIO URL const minioEndpoint = process.env.NEXT_PUBLIC_MINIO_ENDPOINT || 'http://localhost:9000' return `${minioEndpoint}/${bucket}/${objectKey}` } catch (error) { toast.error('Failed to upload file') throw error } } const handleSubmit = async () => { if (!title.trim()) { toast.error('Please enter a title') return } if (resourceType === 'LINK' && !externalUrl) { toast.error('Please enter an external URL') return } try { await createResource.mutateAsync({ programId, title, description: description || undefined, contentJson: contentJson ? JSON.parse(contentJson) : undefined, resourceType: resourceType as 'PDF' | 'VIDEO' | 'DOCUMENT' | 'LINK' | 'OTHER', cohortLevel: cohortLevel as 'ALL' | 'SEMIFINALIST' | 'FINALIST', externalUrl: externalUrl || undefined, isPublished, }) toast.success('Resource created successfully') router.push('/admin/learning') } catch (error) { toast.error(error instanceof Error ? error.message : 'Failed to create resource') } } return (
{/* Header */}

Add Resource

Create a new learning resource for jury members

{/* Main content */}
{/* Basic Info */} Resource Details Basic information about this resource
setTitle(e.target.value)} placeholder="e.g., Ocean Conservation Best Practices" />