"use client"; import { useState, useRef, useCallback } from "react"; import { useTranslations } from "next-intl"; import { Upload, FileText, AlertTriangle, X, Check } from "lucide-react"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { parseVCard, detectDuplicates } from "@/lib/vcard"; import type { ContactCard } from "@/lib/jmap/types"; import { getContactDisplayName, getContactPrimaryEmail } from "@/stores/contact-store"; interface ContactImportDialogProps { existingContacts: ContactCard[]; onImport: (contacts: ContactCard[]) => Promise; onClose: () => void; } export function ContactImportDialog({ existingContacts, onImport, onClose, }: ContactImportDialogProps) { const t = useTranslations("contacts"); const fileRef = useRef(null); const [parsed, setParsed] = useState([]); const [selected, setSelected] = useState>(new Set()); const [duplicates, setDuplicates] = useState>(new Map()); const [isImporting, setIsImporting] = useState(false); const [result, setResult] = useState(null); const [error, setError] = useState(null); const handleFileChange = useCallback(async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setError(null); setResult(null); if (file.size > 5 * 1024 * 1024) { setError(t("import.file_too_large")); return; } try { const text = await file.text(); const contacts = parseVCard(text); if (contacts.length === 0) { setError(t("import.no_contacts")); return; } const dupes = detectDuplicates(existingContacts, contacts); setParsed(contacts); setDuplicates(dupes); const initialSelected = new Set(); contacts.forEach((_, idx) => { if (!dupes.has(idx)) initialSelected.add(idx); }); setSelected(initialSelected); } catch (error) { console.error('Failed to parse vCard:', error); setError(t("import.parse_error")); } }, [existingContacts, t]); const toggleSelect = (idx: number) => { const next = new Set(selected); if (next.has(idx)) { next.delete(idx); } else { next.add(idx); } setSelected(next); }; const selectAll = () => { setSelected(new Set(parsed.map((_, i) => i))); }; const deselectAll = () => { setSelected(new Set()); }; const handleImport = async () => { const toImport = parsed.filter((_, i) => selected.has(i)); if (toImport.length === 0) return; setIsImporting(true); try { const count = await onImport(toImport); setResult(count); } catch (error) { console.error('Failed to import contacts:', error); setError(t("import.failed")); } finally { setIsImporting(false); } }; return (

{t("import.title")}

{result !== null ? (

{t("import.success", { count: result })}

) : parsed.length === 0 ? ( <> {error && (
{error}
)} ) : ( <> {error && (
{error}
)}

{t("import.found", { count: parsed.length })}

{parsed.map((contact, idx) => { const cName = getContactDisplayName(contact); const cEmail = getContactPrimaryEmail(contact); const isDupe = duplicates.has(idx); const isSelected = selected.has(idx); return ( ); })}
)}
{parsed.length > 0 && result === null && (

{t("import.selected", { count: selected.size })}

)}
); }