import { useState, useRef } from 'react' import { importContacts } from '../api/api' import './ImportContacts.css' /** * ImportContacts * * Opens a modal that lets the user upload a CSV or JSON file of contacts and * import them into the current event's guest list. * * Props: * eventId – UUID of the current event * onImportComplete – callback called when a real (non-dry-run) import succeeds */ function ImportContacts({ eventId, onImportComplete }) { const [open, setOpen] = useState(false) const [file, setFile] = useState(null) const [isDryRun, setIsDryRun] = useState(false) const [dragging, setDragging] = useState(false) const [loading, setLoading] = useState(false) const [result, setResult] = useState(null) // ImportContactsResponse const [error, setError] = useState('') const fileInputRef = useRef() // ── helpers ──────────────────────────────────────────────────────────────── const reset = () => { setFile(null) setResult(null) setError('') setLoading(false) setIsDryRun(false) } const handleClose = () => { setOpen(false) reset() } const handleFileChange = (e) => { const f = e.target.files?.[0] if (f) { setFile(f); setResult(null); setError('') } } const handleDrop = (e) => { e.preventDefault() setDragging(false) const f = e.dataTransfer.files?.[0] if (f) { setFile(f); setResult(null); setError('') } } // ── submit ───────────────────────────────────────────────────────────────── const handleUpload = async () => { if (!file) { setError('אנא בחר קובץ לפני ההעלאה.'); return } setLoading(true) setError('') setResult(null) try { const res = await importContacts(eventId, file, isDryRun) setResult(res) if (!isDryRun && (res.created > 0 || res.updated > 0) && onImportComplete) { onImportComplete() } } catch (err) { const msg = err?.response?.data?.detail || err.message || 'שגיאה בעת ייבוא הקובץ.' setError(typeof msg === 'string' ? msg : JSON.stringify(msg)) } finally { setLoading(false) } } // ── action label helpers ─────────────────────────────────────────────────── const actionLabel = { created: { text: 'נוצר', cls: 'badge-created' }, updated: { text: 'עודכן', cls: 'badge-updated' }, skipped: { text: 'דולג', cls: 'badge-skipped' }, error: { text: 'שגיאה', cls: 'badge-error' }, would_create: { text: 'ייווצר', cls: 'badge-dry' }, } // ── modal ────────────────────────────────────────────────────────────────── if (!open) { return ( ) } return (
e.target === e.currentTarget && handleClose()}>
{/* Header */}

📂 ייבוא אנשי קשר מקובץ

{/* Body */}
{/* File drop zone */}
{ e.preventDefault(); setDragging(true) }} onDragLeave={() => setDragging(false)} onDrop={handleDrop} onClick={() => fileInputRef.current?.click()} > {file ? ( <>

{file.name}

לחץ להחלפת הקובץ

) : ( <> 📄

גרור קובץ CSV או JSON לכאן

או לחץ לבחירת קובץ

)}
{/* Format hint */}
פורמטים נתמכים

CSV — כל שורה = אורח. עמודות נתמכות:

First Name, Last Name, Full Name, Phone, Email, RSVP, Meal, Notes, Side, Table

JSON — מערך של אובייקטים עם אותן שדות, או {`{"data":[…]}`}.

הייבוא ניתן לביצוע כפעולת מה-Excel שיצאת: אותן עמודות שמופיעות בייצוא לאקסל.

{/* Dry-run toggle */} {/* Error */} {error &&
{error}
} {/* Upload button */} {!result && ( )} {/* Results */} {result && (
{result.dry_run ? '🔍 תוצאות בדיקה (לא נשמר)' : '✅ הייבוא הושלם!'}
{result.total}סה"כ
{result.created}{result.dry_run ? 'ייווצרו' : 'נוצרו'}
{result.updated}עודכנו
{result.skipped}דולגו
{result.errors > 0 && (
{result.errors}שגיאות
)}
{/* Row-level table */} {result.rows.length > 0 && (
{result.rows.map((r) => { const lbl = actionLabel[r.action] || { text: r.action, cls: '' } return ( ) })}
# שם טלפון פעולה הערה
{r.row} {r.name || '—'} {r.phone || '—'} {lbl.text} {r.reason || ''}
)} {/* Post-result actions */}
{result.dry_run && ( )}
)}
) } export default ImportContacts