"use client" import { DownloadIcon, FileUpIcon, InfoIcon } from "lucide-react" import { useMemo, useRef, useState } from "react" import { toast } from "sonner" import { OptionCombobox } from "@/components/option-combobox" import { ProjectDialog } from "@/components/project-dialog" import { Button } from "@/components/ui/button" import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, } from "@/components/ui/field" import { Input } from "@/components/ui/input" import { ScrollArea } from "@/components/ui/scroll-area" import { downloadKnowledgeFAQImportTemplate, importKnowledgeFAQs, type KnowledgeFAQImportMode, type KnowledgeFAQImportResult, } from "@/lib/api/admin" import { useI18n } from "@/i18n/provider" type FAQImportDialogProps = { open: boolean knowledgeBaseId: number | null importing: boolean onOpenChange: (open: boolean) => void onImportingChange: (importing: boolean) => void onImported: () => Promise } export function FAQImportDialog({ open, knowledgeBaseId, importing, onOpenChange, onImportingChange, onImported, }: FAQImportDialogProps) { const t = useI18n() const fileInputRef = useRef(null) const [file, setFile] = useState(null) const [mode, setMode] = useState("append") const [result, setResult] = useState(null) const modeOptions = useMemo( () => [ { value: "append", label: t("knowledge.importModeAppend") }, { value: "overwrite", label: t("knowledge.importModeOverwrite") }, ], [t], ) function resetState() { setFile(null) setMode("append") setResult(null) if (fileInputRef.current) { fileInputRef.current.value = "" } } function handleFileChange(event: React.ChangeEvent) { const nextFile = event.target.files?.[0] ?? null setResult(null) if (!nextFile) { setFile(null) return } if (!nextFile.name.toLowerCase().endsWith(".xlsx")) { setFile(null) if (fileInputRef.current) { fileInputRef.current.value = "" } toast.error(t("knowledge.importXlsxOnly")) return } setFile(nextFile) } async function handleDownloadTemplate() { try { await downloadKnowledgeFAQImportTemplate() } catch (error) { toast.error(error instanceof Error ? error.message : t("knowledge.downloadTemplateFailed")) } } async function handleImport() { if (!knowledgeBaseId || !file || importing) { return } onImportingChange(true) setResult(null) try { const data = await importKnowledgeFAQs({ knowledgeBaseId, mode, file, }) setResult(data) await onImported() toast.success( t("knowledge.importFAQResultToast", { created: data.created, updated: data.updated, skipped: data.skipped, failed: data.failed, }), ) if (data.failed === 0) { resetState() onOpenChange(false) } } catch (error) { toast.error(error instanceof Error ? error.message : t("knowledge.importFailed")) } finally { onImportingChange(false) } } return ( { if (!nextOpen && !importing) { resetState() } onOpenChange(nextOpen) }} title={t("knowledge.importFAQTitle")} description={t("knowledge.importFAQDescription")} size="lg" footer={ <> } > {t("knowledge.importMode")} setMode(value as KnowledgeFAQImportMode)} /> {mode === "overwrite" ? t("knowledge.importModeOverwriteDescription") : t("knowledge.importModeAppendDescription")} {t("knowledge.importFile")}
{t("knowledge.importFileDescription")}
{file ? (
{t("knowledge.currentFile", { name: file.name })}
) : null}
{t("knowledge.importHint")}
{t("knowledge.importXlsxHint")}
{result ? (
{t("knowledge.importResult")}
{result.errors.length > 0 ? (
    {result.errors.map((item, index) => (
  • {t("knowledge.importRowFailed", { row: item.row, message: item.message, })}
  • ))}
) : null}
) : null}
) } function ImportMetric({ label, value }: { label: string; value: number }) { return (
{label}
{value}
) }