154 lines
4.5 KiB
TypeScript
154 lines
4.5 KiB
TypeScript
"use client"
|
|
|
|
import { useRef, useState } from "react"
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/components/ui/dialog"
|
|
import { Button } from "@/components/ui/button"
|
|
import { Info } from "lucide-react"
|
|
import { useContactsStore } from "@/lib/contacts/contacts-store"
|
|
import { parseContactFile } from "@/lib/contacts/import-parsers"
|
|
|
|
interface ImportDialogProps {
|
|
open: boolean
|
|
onOpenChange: (open: boolean) => void
|
|
}
|
|
|
|
export function ImportDialog({ open, onOpenChange }: ImportDialogProps) {
|
|
const fileRef = useRef<HTMLInputElement>(null)
|
|
const addContacts = useContactsStore((s) => s.addContacts)
|
|
const [pendingFile, setPendingFile] = useState<File | null>(null)
|
|
const [previewCount, setPreviewCount] = useState(0)
|
|
const [error, setError] = useState<string | null>(null)
|
|
const [importing, setImporting] = useState(false)
|
|
|
|
function resetState() {
|
|
setPendingFile(null)
|
|
setPreviewCount(0)
|
|
setError(null)
|
|
setImporting(false)
|
|
if (fileRef.current) fileRef.current.value = ""
|
|
}
|
|
|
|
function handleOpenChange(next: boolean) {
|
|
if (!next) resetState()
|
|
onOpenChange(next)
|
|
}
|
|
|
|
function handleFileSelect() {
|
|
fileRef.current?.click()
|
|
}
|
|
|
|
async function handleFileChange(e: React.ChangeEvent<HTMLInputElement>) {
|
|
const file = e.target.files?.[0]
|
|
if (!file) return
|
|
|
|
setError(null)
|
|
setPendingFile(file)
|
|
|
|
try {
|
|
const parsed = await parseContactFile(file)
|
|
setPreviewCount(parsed.length)
|
|
if (parsed.length === 0) {
|
|
setError("Aucun contact trouvé dans ce fichier.")
|
|
}
|
|
} catch {
|
|
setError("Impossible de lire ce fichier.")
|
|
setPreviewCount(0)
|
|
}
|
|
}
|
|
|
|
async function handleImport() {
|
|
if (!pendingFile || previewCount === 0) return
|
|
|
|
setImporting(true)
|
|
setError(null)
|
|
try {
|
|
const parsed = await parseContactFile(pendingFile)
|
|
const count = addContacts(parsed)
|
|
if (count === 0) {
|
|
setError("Aucun contact importé.")
|
|
return
|
|
}
|
|
handleOpenChange(false)
|
|
} catch {
|
|
setError("L'import a échoué. Vérifiez le format du fichier.")
|
|
} finally {
|
|
setImporting(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={handleOpenChange}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<div className="flex items-center justify-between">
|
|
<DialogTitle>Importer des contacts</DialogTitle>
|
|
<Info className="h-5 w-5 text-[#5f6368]" />
|
|
</div>
|
|
</DialogHeader>
|
|
<div className="space-y-4 py-2">
|
|
<p className="text-sm text-[#3c4043]">
|
|
Pour commencer, sélectionnez un fichier.
|
|
<br />
|
|
Utilisez le format CSV ou vCard (.vcf).
|
|
</p>
|
|
|
|
<Button
|
|
type="button"
|
|
onClick={handleFileSelect}
|
|
className="rounded-full bg-[#1a73e8] px-5 text-sm font-medium text-white hover:bg-[#1557b0]"
|
|
>
|
|
Sélectionner un fichier
|
|
</Button>
|
|
|
|
<input
|
|
ref={fileRef}
|
|
type="file"
|
|
accept=".csv,.vcf,.vcard,text/vcard,text/csv"
|
|
className="hidden"
|
|
onChange={handleFileChange}
|
|
/>
|
|
|
|
{pendingFile && previewCount > 0 && (
|
|
<p className="text-sm text-[#1f1f1f]">
|
|
{previewCount} contact{previewCount > 1 ? "s" : ""} prêt
|
|
{previewCount > 1 ? "s" : ""} à importer depuis{" "}
|
|
<span className="font-medium">{pendingFile.name}</span>
|
|
</p>
|
|
)}
|
|
|
|
{error && <p className="text-sm text-red-600">{error}</p>}
|
|
|
|
<p className="text-xs text-[#5f6368]">
|
|
Vous essayez de sauvegarder les contacts de votre mobile ?
|
|
<br />
|
|
<span className="cursor-pointer text-[#1a73e8]">Voici comment les synchroniser.</span>
|
|
</p>
|
|
</div>
|
|
<div className="flex justify-end gap-3">
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
onClick={() => handleOpenChange(false)}
|
|
className="text-sm font-medium text-[#1a73e8]"
|
|
>
|
|
Non, ne rien faire
|
|
</Button>
|
|
<Button
|
|
type="button"
|
|
onClick={handleImport}
|
|
disabled={!pendingFile || previewCount === 0 || importing}
|
|
className="text-sm font-medium"
|
|
>
|
|
{importing ? "Importation…" : "Importer"}
|
|
</Button>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
)
|
|
}
|