"use client"; import { useState, useRef, useEffect } from 'react'; import { Modal, Upload, message } from 'antd'; import NextImage from 'next/image'; import { CloseOutlined, UserOutlined, CameraOutlined, BulbOutlined, CloudUploadOutlined, CheckOutlined } from '@ant-design/icons'; import type { PhotoType } from '../PhotoPreview/types'; interface AddItemModalProps { /** Modal visibility state */ visible: boolean; /** Close handler */ onClose: () => void; /** Type of item to add */ itemType: PhotoType | null; /** Submit handler */ onSubmit: (data: { name: string; description: string; file: File; index?: number }) => void; /** Edit mode - initial data for editing */ editData?: { index: number; name?: string; description?: string; imageUrl?: string; }; } /** * Modern modal for adding/editing items (character, scene, prop) with name, description, and image. * Features a card-based, non-traditional form design matching the app theme. */ export function AddItemModal({ visible, onClose, itemType, onSubmit, editData, }: AddItemModalProps) { const [name, setName] = useState(''); const [description, setDescription] = useState(''); const [imageFile, setImageFile] = useState(null); const [imagePreview, setImagePreview] = useState(null); const [isDragging, setIsDragging] = useState(false); const fileInputRef = useRef(null); const isEditMode = !!editData; /** Initialize form with edit data */ useEffect(() => { if (visible && editData) { setName(editData.name || ''); setDescription(editData.description || ''); setImagePreview(editData.imageUrl || null); setImageFile(null); } else if (visible) { setName(''); setDescription(''); setImagePreview(null); setImageFile(null); } }, [visible, editData]); /** Get item configuration based on type */ const getItemConfig = () => { const prefix = isEditMode ? 'Edit' : 'Add'; switch (itemType) { case 'character': return { icon: , title: `${prefix} Character`, namePlaceholder: 'Character name', descriptionPlaceholder: 'Describe the character\'s appearance, personality, or key features...', }; case 'scene': return { icon: , title: `${prefix} Scene`, namePlaceholder: 'Scene name', descriptionPlaceholder: 'Describe the location, atmosphere, or visual elements...', }; case 'prop': return { icon: , title: `${prefix} Prop`, namePlaceholder: 'Prop name', descriptionPlaceholder: 'Describe the object\'s appearance, function, or significance...', }; default: return { icon: null, title: `${prefix} Item`, namePlaceholder: 'Item name', descriptionPlaceholder: 'Add a description...', }; } }; const config = getItemConfig(); /** Handle file selection */ const handleFileSelect = (file: File) => { if (!file.type.startsWith('image/')) { message.error('Please upload an image file'); return; } setImageFile(file); const reader = new FileReader(); reader.onload = (e) => { setImagePreview(e.target?.result as string); }; reader.readAsDataURL(file); }; /** Handle drag and drop */ const handleDrop = (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (file) { handleFileSelect(file); } }; /** Handle form submission */ const handleSubmit = () => { if (!name.trim()) { message.warning('Please enter a name'); return; } // In edit mode, if no new file is selected, we need to use existing image if (!imageFile && !imagePreview) { message.warning('Please upload an image'); return; } // If editing and no new file, create a dummy file for the existing image const submitFile = imageFile || new File([], 'existing-image'); onSubmit({ name: name.trim(), description: description.trim(), file: submitFile, ...(isEditMode && editData && { index: editData.index }), }); // Reset form setName(''); setDescription(''); setImageFile(null); setImagePreview(null); onClose(); }; /** Handle modal close */ const handleClose = () => { setName(''); setDescription(''); setImageFile(null); setImagePreview(null); onClose(); }; return ( } width="90%" style={{ maxWidth: '480px' }} styles={{ mask: { backdropFilter: 'blur(4px)', backgroundColor: 'rgba(0, 0, 0, 0.5)' }, content: { padding: 0, backdropFilter: 'blur(12px)', backgroundColor: 'rgba(0, 0, 0, 0.85)', border: '1px solid rgba(255, 255, 255, 0.1)', borderRadius: '24px', overflow: 'hidden', }, }} >
{/* Header with gradient */}
{config.icon}

{config.title}

{/* Content */}
{/* Image Upload Area */}
Image
{ e.preventDefault(); setIsDragging(true); }} onDragLeave={() => setIsDragging(false)} onDrop={handleDrop} onClick={() => fileInputRef.current?.click()} style={{ cursor: 'pointer', aspectRatio: '16/9' }} > {imagePreview ? (
Click to change
) : (

Click to upload or drag & drop

PNG, JPG, WEBP up to 10MB

)} { const file = e.target.files?.[0]; if (file) handleFileSelect(file); }} />
{/* Name Input */}
Name
setName(e.target.value)} placeholder={config.namePlaceholder} className="w-full px-3 py-2 bg-black/30 border border-white/10 rounded-lg text-gray-200 placeholder-gray-500 outline-none focus:border-cyan-400/60 focus:bg-black/40 transition-all duration-200 text-sm" maxLength={50} />
{/* Description Input */}
Description (Optional)