import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { AxiosError } from 'axios' import { createBackup } from '../api/backups' import { useImport } from '../hooks/useImport' import ImportBanner from '../components/ImportBanner' import ImportReviewTable from '../components/ImportReviewTable' import ImportSitesModal from '../components/ImportSitesModal' import ImportSuccessModal from '../components/dialogs/ImportSuccessModal' /** Response data structure for import API errors containing warnings */ interface ImportErrorResponse { error?: string; warning?: string; } export default function ImportCaddy() { const { t } = useTranslation() const navigate = useNavigate() const { session, preview, loading, error, upload, commit, cancel, commitResult, clearCommitResult } = useImport() const [content, setContent] = useState('') const [showReview, setShowReview] = useState(false) const [showMultiModal, setShowMultiModal] = useState(false) const [showSuccessModal, setShowSuccessModal] = useState(false) // Warning extracted from 400 error responses (e.g., file_server detection) const [warningFromError, setWarningFromError] = useState(null) const handleUpload = async () => { if (!content.trim()) { alert(t('importCaddy.enterCaddyfileContent')) return } // Clear any previous warning from error responses setWarningFromError(null) try { await upload(content) setShowReview(true) } catch (err) { // Check if error response contains a warning (e.g., file_server detected) const axiosErr = err as AxiosError if (axiosErr.response?.data?.warning) { setWarningFromError(axiosErr.response.data.warning) } // Other error handling is done by hook } } const handleFileUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0] if (!file) return const text = await file.text() setContent(text) } const handleCommit = async (resolutions: Record, names: Record) => { try { // Create a backup before committing import to allow rollback await createBackup() await commit(resolutions, names) setContent('') setShowReview(false) setShowSuccessModal(true) } catch { // Error is already set by hook } } const handleCloseSuccessModal = () => { setShowSuccessModal(false) clearCommitResult() } const handleCancel = async () => { if (confirm(t('importCaddy.cancelConfirm'))) { try { await cancel() setShowReview(false) } catch { // Error is already set by hook } } } return (

{t('importCaddy.title')}

{session && (
setShowReview(true)} onCancel={handleCancel} />
)} {error && (
{error}
)} {/* Backend-provided warning (e.g. file_server-only) */} {preview?.warning && (

{t('importCaddy.warningTitle')}

{preview.warning}

)} {/* Warning extracted from 400 error response (e.g., file_server detection) */} {warningFromError && (

{t('importCaddy.warningTitle')}

{warningFromError}

)} {/* Show warning if preview is empty but session exists (e.g. mounted file was empty or invalid) */} {session && preview && preview.preview && preview.preview.hosts.length === 0 && (

{t('importCaddy.noDomainsFound')}

{t('importCaddy.emptyFileWarning')}

)} {!session && (

{t('importCaddy.uploadOrPaste')}

{t('importCaddy.description')}

{/* File Upload */}
{/* Or Divider */}
{t('importCaddy.orPasteContent')}
{/* Text Area */}