'use client' import { useCallback, useEffect } from 'react' import { Controller, useForm } from 'react-hook-form' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import { EpisodeProfile, SpeakerProfile } from '@/lib/types/podcasts' import { useCreateEpisodeProfile, useUpdateEpisodeProfile, useLanguages, } from '@/lib/hooks/use-podcasts' import { useTranslation } from '@/lib/hooks/use-translation' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog' import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Textarea } from '@/components/ui/textarea' import { Separator } from '@/components/ui/separator' import { ModelSelector } from '@/components/common/ModelSelector' import type { TFunction } from 'i18next' const episodeProfileSchema = (t: TFunction) => z.object({ name: z.string().min(1, t('podcasts.nameRequired') || 'Name is required'), description: z.string().optional(), speaker_config: z.string().min(1, t('podcasts.profileRequired') || 'Speaker profile is required'), outline_llm: z.string().min(1, t('podcasts.outlineModelRequired') || 'Outline model is required'), transcript_llm: z.string().min(1, t('podcasts.transcriptModelRequired') || 'Transcript model is required'), language: z.string().nullable().optional(), default_briefing: z.string().min(1, t('podcasts.defaultBriefingRequired') || 'Default briefing is required'), num_segments: z.number() .int(t('podcasts.segmentsInteger') || 'Must be an integer') .min(3, t('podcasts.segmentsMin') || 'At least 3 segments') .max(20, t('podcasts.segmentsMax') || 'Maximum 20 segments'), }) export type EpisodeProfileFormValues = z.infer> interface EpisodeProfileFormDialogProps { mode: 'create' | 'edit' open: boolean onOpenChange: (open: boolean) => void speakerProfiles: SpeakerProfile[] initialData?: EpisodeProfile } export function EpisodeProfileFormDialog({ mode, open, onOpenChange, speakerProfiles, initialData, }: EpisodeProfileFormDialogProps) { const { t } = useTranslation() const createProfile = useCreateEpisodeProfile() const updateProfile = useUpdateEpisodeProfile() const { data: languages = [] } = useLanguages() const getDefaults = useCallback((): EpisodeProfileFormValues => { const firstSpeaker = speakerProfiles[0]?.name ?? '' if (initialData) { return { name: initialData.name, description: initialData.description ?? '', speaker_config: initialData.speaker_config, outline_llm: initialData.outline_llm ?? '', transcript_llm: initialData.transcript_llm ?? '', language: initialData.language ?? null, default_briefing: initialData.default_briefing, num_segments: initialData.num_segments, } } return { name: '', description: '', speaker_config: firstSpeaker, outline_llm: '', transcript_llm: '', language: null, default_briefing: '', num_segments: 5, } }, [initialData, speakerProfiles]) const { control, register, handleSubmit, reset, formState: { errors }, } = useForm({ resolver: zodResolver(episodeProfileSchema(t)), defaultValues: getDefaults(), }) useEffect(() => { if (!open) { return } reset(getDefaults()) }, [open, reset, getDefaults]) const onSubmit = async (values: EpisodeProfileFormValues) => { const payload = { ...values, description: values.description ?? '', language: values.language || null, } if (mode === 'create') { await createProfile.mutateAsync(payload) } else if (initialData) { await updateProfile.mutateAsync({ profileId: initialData.id, payload, }) } onOpenChange(false) } const isSubmitting = createProfile.isPending || updateProfile.isPending const disableSubmit = isSubmitting || speakerProfiles.length === 0 const isEdit = mode === 'edit' return ( {isEdit ? t('podcasts.editEpisodeProfile') : t('podcasts.createEpisodeProfile')} {t('podcasts.episodeProfileFormDesc')} {speakerProfiles.length === 0 ? ( {t('podcasts.noSpeakerProfilesAvailable')} {t('podcasts.noSpeakerProfilesDesc')} ) : null}
{errors.name ? (

{errors.name.message}

) : null}
{errors.num_segments ? (

{errors.num_segments.message}

) : null}