"use client"; import { useState, useRef, useEffect, useMemo } from "react"; import { Upload, X, Loader2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { useToast } from "@/hooks/use-toast"; import { validateFileForUpload, generateFilePreview } from "@/lib/file-utils"; import { COMIC_STYLES } from "@/lib/constants"; interface GeneratePageModalProps { isOpen: boolean; onClose: () => void; onGenerate: (data: { prompt: string; characterFiles?: File[]; characterUrls?: string[]; }) => void; pageNumber: number; } export function GeneratePageModal({ isOpen, onClose, onGenerate, pageNumber, }: GeneratePageModalProps) { const [prompt, setPrompt] = useState(""); const [uploadedFiles, setUploadedFiles] = useState([]); const [previews, setPreviews] = useState([]); const [showPreview, setShowPreview] = useState(null); const [isGenerating, setIsGenerating] = useState(false); const fileInputRef = useRef(null); const { toast } = useToast(); // Reset form when modal opens useEffect(() => { if (isOpen) { setPrompt(""); setUploadedFiles([]); setPreviews([]); setShowPreview(null); setIsGenerating(false); } }, [isOpen]); const handleFiles = async (newFiles: FileList | null) => { if (!newFiles) return; const filesArray = Array.from(newFiles); const validationResults = filesArray.map((file) => ({ file, validation: validateFileForUpload(file, true), })); validationResults.forEach(({ validation }) => { if (!validation.valid && validation.error) { toast({ title: "Invalid file", description: validation.error, variant: "destructive", duration: 4000, }); } }); const validFiles = validationResults .filter(({ validation }) => validation.valid) .map(({ file }) => file); if (validFiles.length === 0) return; const totalFiles = [...uploadedFiles, ...validFiles].slice(0, 2); setUploadedFiles(totalFiles); const newPreviews = await Promise.all( totalFiles.map((file) => generateFilePreview(file)) ); setPreviews(newPreviews); }; const removeFile = (index: number) => { const newFiles = uploadedFiles.filter((_, i) => i !== index); const newPreviews = previews.filter((_, i) => i !== index); setUploadedFiles(newFiles); setPreviews(newPreviews); setShowPreview(null); if (fileInputRef.current) { fileInputRef.current.value = ""; } }; const handleGenerate = async () => { if (!prompt.trim()) return; setIsGenerating(true); const fileDataUrls = await Promise.all( uploadedFiles.map((file) => { return new Promise((resolve) => { const reader = new FileReader(); reader.onload = (e) => { const base64 = e.target?.result as string; const [header, base64Data] = base64.split(","); // Send just the base64 data without the data URL prefix resolve(base64Data); }; reader.readAsDataURL(file); }); }) ); onGenerate({ prompt, characterFiles: uploadedFiles.length > 0 ? uploadedFiles : undefined, characterUrls: fileDataUrls, }); }; return ( <> Generate Page {pageNumber}
{/* Prompt Input */}