import { useEffect, useRef, useState } from 'react'; import { api } from '../api.js'; import { memberInitials, memberDisplayName } from '../utils/format.js'; import { useInvestisseur } from '../context/InvestisseurContext.jsx'; import Modal from '../components/Modal.jsx'; import ConfirmModal from '../components/ConfirmModal.jsx'; /* ── Avatar ─────────────────────────────────────────────────── */ function MemberAvatar({ membre, size = 40 }) { const initials = memberInitials(membre); const bg = membre.type === 'entreprise' ? 'linear-gradient(135deg, #4f46e5 0%, #3730a3 100%)' : 'linear-gradient(135deg, #1e40af 0%, #1e3a8a 100%)'; return (
{initials}
); } /* ── Menu "···" par membre ──────────────────────────────────── */ function MemberMenu({ onEdit, onDelete, isPrincipal, isOnly }) { const [open, setOpen] = useState(false); const ref = useRef(null); useEffect(() => { if (!open) return; const h = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); }; document.addEventListener('mousedown', h); return () => document.removeEventListener('mousedown', h); }, [open]); return (
{open && (
{!isPrincipal && ( )}
)}
); } /* ── Ligne "Ajouter" ─────────────────────────────────────────── */ function AddRow({ label, onClick }) { return (
e.key === 'Enter' && onClick()}>
{label}
); } /* ── Composant principal ─────────────────────────────────────── */ export default function FamilleEntreprises() { const { reload: reloadCtx } = useInvestisseur(); const [membres, setMembres] = useState([]); const [tab, setTab] = useState('famille'); const [err, setErr] = useState(null); /* Modals */ const [modalFamille, setModalFamille] = useState(false); const [modalEntreprise, setModalEntreprise] = useState(false); const [editTarget, setEditTarget] = useState(null); // membre à éditer /* Formulaires */ const emptyFam = { prenom: '', nom_famille: '' }; const emptyEnt = { nom: '', type_fiscal: 'PM' }; const [famForm, setFamForm] = useState(emptyFam); const [entForm, setEntForm] = useState(emptyEnt); const [saving, setSaving] = useState(false); const [deleteConfirm, setDeleteConfirm] = useState(null); const load = async () => { const list = await api.get('/investisseurs'); setMembres(list); }; useEffect(() => { load(); }, []); const famille = membres.filter(m => m.type === 'famille'); const entreprises = membres.filter(m => m.type === 'entreprise'); const totalCount = membres.length; /* ── Ouvrir modal édition ─────────────────────────────────── */ const openEdit = (m) => { setEditTarget(m); if (m.type === 'famille') { const restNom = m.prenom ? m.nom.replace(m.prenom, '').trim() : m.nom; setFamForm({ prenom: m.prenom || '', nom_famille: restNom }); setModalFamille(true); } else { setEntForm({ nom: m.nom, type_fiscal: m.type_fiscal || 'PM' }); setModalEntreprise(true); } }; const closeModals = () => { setModalFamille(false); setModalEntreprise(false); setEditTarget(null); setFamForm(emptyFam); setEntForm(emptyEnt); setErr(null); }; /* ── Sauvegarde famille ────────────────────────────────────── */ const saveFamille = async (e) => { e.preventDefault(); setErr(null); setSaving(true); try { const fullName = [famForm.prenom.trim(), famForm.nom_famille.trim()].filter(Boolean).join(' '); if (!fullName) throw new Error('Veuillez renseigner au moins un prénom ou un nom.'); const payload = { nom: fullName, prenom: famForm.prenom.trim() || null, type: 'famille', type_fiscal: 'PP', }; if (editTarget) { await api.put(`/investisseurs/${editTarget.id}`, payload); } else { await api.post('/investisseurs', payload); } await load(); await reloadCtx(); closeModals(); } catch (e) { setErr(e.message); } finally { setSaving(false); } }; /* ── Sauvegarde entreprise ─────────────────────────────────── */ const saveEntreprise = async (e) => { e.preventDefault(); setErr(null); setSaving(true); try { const payload = { nom: entForm.nom.trim(), prenom: null, type: 'entreprise', type_fiscal: entForm.type_fiscal, }; if (editTarget) { await api.put(`/investisseurs/${editTarget.id}`, payload); } else { await api.post('/investisseurs', payload); } await load(); await reloadCtx(); closeModals(); } catch (e) { setErr(e.message); } finally { setSaving(false); } }; /* ── Suppression ──────────────────────────────────────────── */ const deleteMembre = (m) => { setDeleteConfirm({ message: `Supprimer "${memberDisplayName(m)}" ? Tous les investissements associés seront effacés.`, onConfirm: async () => { try { await api.del(`/investisseurs/${m.id}`); await load(); await reloadCtx(); } catch (e) { setErr(e.message); } finally { setDeleteConfirm(null); } }, }); }; /* ── Render ───────────────────────────────────────────────── */ const currentList = tab === 'famille' ? famille : entreprises; return (
{/* Tabs */}
{err &&
{err}
} {/* Liste */}
{currentList.map(m => (
{memberDisplayName(m)} {m.type === 'famille' && ( {m.is_principal ? '(compte principal)' : '(Membre de la famille)'} )}
{m.type_fiscal && m.type === 'entreprise' && ( {m.type_fiscal} )} openEdit(m)} onDelete={() => deleteMembre(m)} isPrincipal={!!m.is_principal} isOnly={totalCount <= 1} />
))} {/* Ligne d'ajout */} {tab === 'famille' && ( { setEditTarget(null); setFamForm(emptyFam); setModalFamille(true); }} /> )} {tab === 'entreprise' && ( { setEditTarget(null); setEntForm(emptyEnt); setModalEntreprise(true); }} /> )}
{/* ── Modal famille ──────────────────────────────────────── */} } >
{err &&
{err}
}
setFamForm({ ...famForm, prenom: e.target.value })} placeholder="Olivier" />
setFamForm({ ...famForm, nom_famille: e.target.value })} placeholder="CROGUENNEC" />
{/* ── Modal entreprise ───────────────────────────────────── */} } >
{err &&
{err}
}
setEntForm({ ...entForm, nom: e.target.value })} placeholder="SCI Famille Croguennec" />
setDeleteConfirm(null)} />
); }