"use client"; import { useState } from 'react'; import { UseFormReturn } from 'react-hook-form'; import { z } from 'zod'; import { toast } from 'sonner'; import Image from 'next/image'; import { Sparkles, Upload } from 'lucide-react'; import { heroFormSchema } from '@/lib/validators'; import { regenerateImageAction } from '@/app/actions/db.actions'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'; // This helper can live in a utils file. It handles file uploads to a standard API endpoint. async function uploadFile(file: File): Promise { const formData = new FormData(); formData.append('file', file); // This remains a standard fetch call as it's handling multipart/form-data const response = await fetch('/api/upload', { method: 'POST', body: formData }); if (!response.ok) throw new Error('Upload failed'); const { url } = await response.json(); return url; } type FormSchemaType = z.infer; interface VisualsSectionProps { form: UseFormReturn; } export const VisualsSection = ({ form }: VisualsSectionProps) => { const [isGeneratingAvatar, setIsGeneratingAvatar] = useState(false); const [isGeneratingIcon, setIsGeneratingIcon] = useState(false); const handleFileChange = async (e: React.ChangeEvent, fieldName: 'avatarUrl' | 'iconUrl') => { const file = e.target.files?.[0]; if (!file) return; const toastId = toast.loading(`Uploading image...`); try { const url = await uploadFile(file); form.setValue(fieldName, url, { shouldValidate: true, shouldDirty: true }); toast.success("Upload complete!", { id: toastId }); } catch { toast.error("Upload failed.", { id: toastId }); } }; const handleGenerateImage = async (imageType: 'avatar' | 'icon') => { const setLoading = imageType === 'avatar' ? setIsGeneratingAvatar : setIsGeneratingIcon; const promptField = imageType === 'avatar' ? 'avatarPrompt' : 'iconPrompt'; const urlField = imageType === 'avatar' ? 'avatarUrl' : 'iconUrl'; setLoading(true); const toastId = toast.loading(`Generating new ${imageType}...`); const prompt = form.getValues(promptField); const heroName = form.getValues('heroName'); const result = await regenerateImageAction(prompt, heroName, imageType); if (result.success && result.data) { form.setValue(urlField, result.data, { shouldValidate: true, shouldDirty: true }); toast.success(`New ${imageType} generated!`, { id: toastId }); } else { toast.error(result.message || `Could not generate ${imageType}.`, { id: toastId }); } setLoading(false); }; return (

Visuals

{/* Avatar Section */}
( Avatar Prompt )} />
{form.watch('avatarUrl') && ( Hero Avatar )}
{/* Icon Section */}
( Icon Prompt )} />
{form.watch('iconUrl') && ( Superpower Icon )}
); };