'use client'; import { zodResolver } from '@hookform/resolvers/zod'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { type FormEvent, useEffect, useState } from 'react'; import { useForm } from 'react-hook-form'; import { Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Textarea } from '@/components/ui/textarea'; import type { TlsCertificateItem } from '@/lib/services/openflare'; import { TlsCertificateService } from '@/lib/services/openflare'; import { useTranslations } from 'next-intl'; import { createManualImportSchema, defaultFileImportValues, defaultManualImportValues, type FileImportFormValues, type ManualImportFormValues, } from './schemas'; import { getErrorMessage, toFilePayload, toManualPayload, } from './website-utils'; const certificatesQueryKey = ['openflare', 'tls-certificates']; interface CertificateImportDialogProps { open: boolean; onOpenChange: (open: boolean) => void; onImported?: (certificate: TlsCertificateItem) => void; } export function CertificateImportDialog({ open, onOpenChange, onImported, }: CertificateImportDialogProps) { const t = useTranslations('certificates'); const queryClient = useQueryClient(); const [importMode, setImportMode] = useState<'manual' | 'file'>('manual'); const [error, setError] = useState(''); const [fileForm, setFileForm] = useState( defaultFileImportValues, ); const [certFile, setCertFile] = useState(null); const [keyFile, setKeyFile] = useState(null); const [fileInputNonce, setFileInputNonce] = useState(0); const manualForm = useForm({ resolver: zodResolver(createManualImportSchema(t)), defaultValues: defaultManualImportValues, }); useEffect(() => { if (!open) return; setError(''); }, [open]); const invalidateQueries = async () => { await Promise.all([ queryClient.invalidateQueries({ queryKey: certificatesQueryKey }), ]); }; const resetFileForm = () => { setFileForm(defaultFileImportValues); setCertFile(null); setKeyFile(null); setFileInputNonce((value) => value + 1); }; const resetAll = () => { setImportMode('manual'); setError(''); manualForm.reset(defaultManualImportValues); resetFileForm(); }; const handleClose = () => { resetAll(); onOpenChange(false); }; const manualImportMutation = useMutation({ mutationFn: (values: ManualImportFormValues) => TlsCertificateService.create(toManualPayload(values)), onSuccess: async (certificate) => { await invalidateQueries(); onImported?.(certificate); handleClose(); }, onError: (err) => setError(getErrorMessage(err, t('requestFailed'))), }); const fileImportMutation = useMutation({ mutationFn: (values: FileImportFormValues) => TlsCertificateService.importFile( toFilePayload(values, certFile, keyFile, t('selectFiles')), ), onSuccess: async (certificate) => { await invalidateQueries(); onImported?.(certificate); handleClose(); }, onError: (err) => setError(getErrorMessage(err, t('requestFailed'))), }); const handleManualSubmit = manualForm.handleSubmit((values) => { setError(''); manualImportMutation.mutate(values); }); const handleFileSubmit = (event: FormEvent) => { event.preventDefault(); setError(''); fileImportMutation.mutate(fileForm); }; const pending = manualImportMutation.isPending || fileImportMutation.isPending; return ( !next && handleClose()}> {t('importTitle')} {t('importDesc')} {error ?

{error}

: null} setImportMode(value as 'manual' | 'file')} > {t('manualImport')} {t('fileImport')}
{manualForm.formState.errors.name ? (

{manualForm.formState.errors.name.message}

) : null}