| 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<FileImporterProps> = ({ |
| token, |
| selectedOrgId, |
| onImportSuccess, |
| onImportError, |
| setIsUploading |
| }) => { |
| |
| const normalizeContacts = (rows: any[]): { phoneNumber: string; name?: string; attributes: Record<string, unknown> }[] => { |
| 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<string, unknown> }[]>((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; |
|
|
| |
| const attributes: Record<string, unknown> = {}; |
| 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 { |
| |
| 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); |
|
|
| |
| 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; |
| } |
|
|
| |
| 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 ( |
| <input |
| type="file" |
| id="crm-file-upload" |
| className="hidden" |
| accept=".xlsx,.csv" |
| onChange={(e) => { |
| const file = e.target.files?.[0]; |
| if (file) handleFile(file); |
| }} |
| /> |
| ); |
| }; |
|
|