'use client'; import { useState, useCallback, useRef } from 'react'; import { FileSpreadsheet, X, Download, Upload, AlertCircle, CheckCircle2 } from 'lucide-react'; import Image from 'next/image'; import Papa from 'papaparse'; import QRCode from 'qrcode'; interface CSVBulkGeneratorProps { isOpen: boolean; onClose: () => void; } interface CSVRow { content: string; type?: string; filename?: string; } interface GeneratedQR { content: string; dataUrl: string; filename: string; } export default function CSVBulkGenerator({ isOpen, onClose }: CSVBulkGeneratorProps) { const [isDragging, setIsDragging] = useState(false); const [rows, setRows] = useState([]); const [generated, setGenerated] = useState([]); const [isProcessing, setIsProcessing] = useState(false); const [error, setError] = useState(null); const fileInputRef = useRef(null); const handleFile = useCallback((file: File) => { setError(null); setGenerated([]); Papa.parse>(file, { header: true, skipEmptyLines: true, complete: (results) => { if (results.errors.length > 0) { setError('Erreur de lecture du fichier CSV'); return; } const parsed: CSVRow[] = results.data .map((row) => ({ content: row.content || row.text || row.url || row.data || Object.values(row)[0] || '', type: row.type, filename: row.filename || row.name, })) .filter((r) => r.content.trim() !== ''); if (parsed.length === 0) { setError('Aucune donnée trouvée. Assurez-vous que le CSV contient une colonne "content".'); return; } setRows(parsed); }, }); }, []); const generateAll = useCallback(async () => { setIsProcessing(true); const results: GeneratedQR[] = []; for (let i = 0; i < rows.length; i++) { const row = rows[i]; try { const dataUrl = await QRCode.toDataURL(row.content, { width: 400, margin: 2, errorCorrectionLevel: 'M', }); results.push({ content: row.content, dataUrl, filename: row.filename || `qrcode-${i + 1}`, }); } catch { results.push({ content: row.content, dataUrl: '', filename: row.filename || `qrcode-${i + 1}`, }); } } setGenerated(results); setIsProcessing(false); }, [rows]); const downloadAll = useCallback(() => { generated.forEach((qr) => { if (qr.dataUrl) { const link = document.createElement('a'); link.download = `${qr.filename}.png`; link.href = qr.dataUrl; link.click(); } }); }, [generated]); const handleDrop = useCallback( (e: React.DragEvent) => { e.preventDefault(); setIsDragging(false); const file = e.dataTransfer.files[0]; if (file && (file.type === 'text/csv' || file.name.endsWith('.csv'))) { handleFile(file); } else { setError('Veuillez importer un fichier CSV'); } }, [handleFile] ); if (!isOpen) return null; return (
{/* Header */}

Génération en masse

{/* Content */}
{/* Upload area */} {rows.length === 0 && (
{ e.preventDefault(); setIsDragging(true); }} onDragLeave={() => setIsDragging(false)} onClick={() => fileInputRef.current?.click()} className={`border-2 border-dashed rounded-xl p-12 text-center cursor-pointer transition-all ${ isDragging ? 'border-violet-500 bg-violet-50 dark:bg-violet-900/20' : 'border-gray-200 dark:border-gray-700 hover:border-violet-400' }`} >

Glissez votre fichier CSV ici

ou parcourir

Le CSV doit contenir une colonne "content" avec les données à encoder

{ const file = e.target.files?.[0]; if (file) handleFile(file); }} className="hidden" />
{/* CSV format help */}

Format CSV attendu :

{`content,filename https://example.com,site-web Bonjour le monde,message +33612345678,contact`}
)} {/* Error */} {error && (
{error}
)} {/* Rows preview */} {rows.length > 0 && generated.length === 0 && (

{rows.length} QR Codes à générer

{rows.slice(0, 20).map((row, i) => (
{i + 1} {row.content}
))} {rows.length > 20 && (

... et {rows.length - 20} de plus

)}
)} {/* Generated results */} {generated.length > 0 && (
{generated.filter((g) => g.dataUrl).length} QR Codes générés
{generated.map((qr, i) => (
{qr.dataUrl ? ( {qr.content} ) : (
)}

{qr.filename}

))}
)}
); }