import React from 'react'; import { read, utils } from 'xlsx'; import { api } from '../../lib/api'; import { logError } from '../../lib/logger'; interface FileImporterProps { token: string; selectedOrgId: string; onImportSuccess: (data: { listId: string; listName: string; count: number }) => void; onImportError: (error: string) => void; setIsUploading: (loading: boolean) => void; } export const FileImporter: React.FC = ({ token, selectedOrgId, onImportSuccess, onImportError, setIsUploading }) => { const normalizeContacts = (rows: any[]): { phoneNumber: string; name?: string; attributes: Record }[] => { const PHONE_KEYS = ['phonenumber', 'phone', 'telephone', 'téléphone', 'mobile', 'numero', 'numéro', 'number', 'whatsapp', 'tel']; const NAME_KEYS = ['name', 'nom', 'prenom', 'prénom', 'firstname', 'lastname', 'fullname', 'contact']; return rows.reduce<{ phoneNumber: string; name?: string; attributes: Record }[]>((acc, row) => { const keys = Object.keys(row); const phoneKey = keys.find(k => PHONE_KEYS.includes(k.toLowerCase().replace(/[\s_-]/g, ''))); const nameKey = keys.find(k => NAME_KEYS.includes(k.toLowerCase().replace(/[\s_-]/g, ''))); const raw = phoneKey ? String(row[phoneKey]).replace(/\s+/g, '') : null; if (!raw) return acc; // skip rows with no phone // Keep remaining columns as attributes const attributes: Record = {}; keys.forEach(k => { if (k !== phoneKey && k !== nameKey) attributes[k] = row[k]; }); acc.push({ phoneNumber: raw, ...(nameKey ? { name: String(row[nameKey]) } : {}), attributes }); return acc; }, []); }; const handleFile = async (file: File) => { if (!token || !selectedOrgId) return; setIsUploading(true); const reader = new FileReader(); reader.onload = async (event) => { try { // 1. Parse Excel/CSV on the client side const data = new Uint8Array(event.target?.result as ArrayBuffer); const workbook = read(data, { type: 'array' }); const firstSheetName = workbook.SheetNames[0]; const worksheet = workbook.Sheets[firstSheetName]; const rawRows = utils.sheet_to_json(worksheet); // 2. Normalize column names → { phoneNumber, name?, attributes } const contacts = normalizeContacts(rawRows); if (contacts.length === 0) { onImportError("Aucun contact trouvé. Vérifiez que votre fichier contient une colonne \"Téléphone\" ou \"Mobile\"."); setIsUploading(false); return; } // 3. Send JSON to the bulk endpoint const responseData = await api.post(`/v1/organizations/${selectedOrgId}/contacts/bulk`, { contacts, listName: file.name.split('.')[0] }, token, selectedOrgId); onImportSuccess({ listId: responseData.listId, listName: responseData.listName, count: responseData.results.created }); } catch (err: any) { logError("Parsing/Upload failed:", err); const msg = typeof err?.message === 'string' && !err.message.includes('[object') ? err.message : "Une erreur technique est survenue."; onImportError(msg); } finally { setIsUploading(false); } }; reader.readAsArrayBuffer(file); }; return ( { const file = e.target.files?.[0]; if (file) handleFile(file); }} /> ); };