"use client"; import { useState } from 'react'; import { UseFormReturn } from 'react-hook-form'; import { z } from 'zod'; import { toast } from 'sonner'; import { Sparkles, Upload, Volume2 } from 'lucide-react'; import { heroFormSchema } from '@/lib/validators'; import { regenerateAudioAction } 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'; // Re-using the same upload helper async function uploadFile(file: File): Promise { const formData = new FormData(); formData.append('file', file); 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 AudioSectionProps { form: UseFormReturn; } export const AudioSection = ({ form }: AudioSectionProps) => { const [isGeneratingIntro, setIsGeneratingIntro] = useState(false); const [isGeneratingSuper, setIsGeneratingSuper] = useState(false); const playAudio = (url?: string | null) => { if (url) new Audio(url).play(); }; const handleFileChange = async (e: React.ChangeEvent, fieldName: 'introLineAudioUrl' | 'superpowerActivationLineAudioUrl') => { const file = e.target.files?.[0]; if (!file) return; const toastId = toast.loading(`Uploading audio...`); try { const url = await uploadFile(file); form.setValue(fieldName, url, { shouldDirty: true, shouldValidate: true }); toast.success("Upload complete!", { id: toastId }); } catch { toast.error("Upload failed.", { id: toastId }); } }; const handleGenerateAudio = async (lineType: 'intro' | 'superpower') => { const setLoading = lineType === 'intro' ? setIsGeneratingIntro : setIsGeneratingSuper; const textField = lineType === 'intro' ? 'introLine' : 'superpowerActivationLine'; const urlField = lineType === 'intro' ? 'introLineAudioUrl' : 'superpowerActivationLineAudioUrl'; const textToSpeak = form.getValues(textField); if (!textToSpeak) { toast.error("Please enter some dialogue first."); return; } try{ setLoading(true); const toastId = toast.loading(`Generating new ${lineType} audio...`); const heroName = form.getValues('heroName'); const heroGender = form.getValues('heroGender'); const result = await regenerateAudioAction(textToSpeak, heroName, heroGender, lineType); if (result.success && result.data) { form.setValue(urlField, result.data, { shouldValidate: true, shouldDirty: true }); toast.success(`New ${lineType} audio generated!`, { id: toastId }); } setLoading(false); } catch (error: unknown) { const toastId = toast.loading(`Generating new ${lineType} audio...`); if (error instanceof Error) { toast.error(error.message || `Could not generate ${lineType} audio.`, { id: toastId }); } else { toast.error(`Could not generate ${lineType} audio.`, { id: toastId }); } setLoading(false); } } return (

Voice Lines

{/* Intro Line */}
( Intro Dialogue )} />
{/* Superpower Line */}
( Superpower Activation Dialogue )} />
) }