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 ──────────────────────────────────────── */}
>
}
>
{/* ── Modal entreprise ───────────────────────────────────── */}
>
}
>
setDeleteConfirm(null)}
/>
);
}