Fix multi-détenteur

This commit is contained in:
2026-07-14 15:35:35 +02:00
parent 069e316362
commit 3a9de15526
@@ -44,6 +44,7 @@ export default function DataCleanupSection() {
const [purgeScope, setPurgeScope] = useState('all'); const [purgeScope, setPurgeScope] = useState('all');
const [showPurgeModal, setShowPurgeModal] = useState(false); const [showPurgeModal, setShowPurgeModal] = useState(false);
const [purgeConfirmText, setPurgeConfirmText] = useState(''); const [purgeConfirmText, setPurgeConfirmText] = useState('');
const [purgePin, setPurgePin] = useState('');
const [loadingPurge, setLoadingPurge] = useState(false); const [loadingPurge, setLoadingPurge] = useState(false);
useEffect(() => { useEffect(() => {
@@ -51,22 +52,29 @@ export default function DataCleanupSection() {
}, []); }, []);
const purgePlat = plats.find(p => String(p.id) === String(purgePlatId)) || null; const purgePlat = plats.find(p => String(p.id) === String(purgePlatId)) || null;
// Plusieurs membres de la famille/entreprise peuvent avoir une plateforme du même nom
// (ex. deux comptes "Enky" distincts) — on ajoute le détenteur au libellé pour lever
// l'ambiguïté, uniquement quand plus d'un détenteur est présent dans la liste.
const multiDetenteurPlats = new Set(plats.map(p => p.investisseur_id)).size > 1;
const openPurgeModal = () => { const openPurgeModal = () => {
if (!purgePlat) return; if (!purgePlat) return;
setPurgeConfirmText(''); setPurgeConfirmText('');
setPurgePin(String(Math.floor(100000 + Math.random() * 900000)));
setShowPurgeModal(true); setShowPurgeModal(true);
}; };
const handlePurge = async () => { const handlePurge = async () => {
if (!purgePlat || purgeConfirmText.trim() !== purgePlat.nom) return; if (!purgePlat || purgeConfirmText.trim() !== purgePin) return;
setLoadingPurge(true); setLoadingPurge(true);
setErrorMsg(null); setErrorMsg(null);
setSuccessMsg(null); setSuccessMsg(null);
try { try {
const r = await api.post(`/plateformes/${purgePlat.id}/purge-donnees`, { const r = await api.post(`/plateformes/${purgePlat.id}/purge-donnees`, {
scope: purgeScope, scope: purgeScope,
confirmNom: purgeConfirmText.trim(), // Le PIN est une confirmation côté interface uniquement ; l'API continue d'exiger
// le nom exact de la plateforme, déjà connu ici puisque sélectionné dans le formulaire.
confirmNom: purgePlat.nom,
}); });
setSuccessMsg(`"${r.plateforme}" — ${purgeSummary(r.counts, purgeScope)}`); setSuccessMsg(`"${r.plateforme}" — ${purgeSummary(r.counts, purgeScope)}`);
setShowPurgeModal(false); setShowPurgeModal(false);
@@ -300,7 +308,11 @@ export default function DataCleanupSection() {
<label style={{ fontSize: 12 }}>Plateforme</label> <label style={{ fontSize: 12 }}>Plateforme</label>
<select value={purgePlatId} onChange={e => setPurgePlatId(e.target.value)}> <select value={purgePlatId} onChange={e => setPurgePlatId(e.target.value)}>
<option value="">Sélectionnez une plateforme…</option> <option value="">Sélectionnez une plateforme…</option>
{plats.map(p => <option key={p.id} value={p.id}>{p.nom}</option>)} {plats.map(p => (
<option key={p.id} value={p.id}>
{p.nom}{multiDetenteurPlats && p.investisseur_nom ? ` — ${p.investisseur_nom}` : ''}
</option>
))}
</select> </select>
</div> </div>
<div style={{ flex: '1 1 280px', minWidth: 240 }}> <div style={{ flex: '1 1 280px', minWidth: 240 }}>
@@ -474,7 +486,8 @@ export default function DataCleanupSection() {
<h3 style={{ margin: 0, color: 'var(--danger, #ef4444)' }}> Suppression de données action irréversible</h3> <h3 style={{ margin: 0, color: 'var(--danger, #ef4444)' }}> Suppression de données action irréversible</h3>
</div> </div>
<p style={{ margin: '0 0 12px', lineHeight: 1.6 }}> <p style={{ margin: '0 0 12px', lineHeight: 1.6 }}>
Vous vous apprêtez à supprimer, pour la plateforme <strong>{purgePlat.nom}</strong> : Vous vous apprêtez à supprimer, pour la plateforme <strong>{purgePlat.nom}</strong>
{multiDetenteurPlats && purgePlat.investisseur_nom ? <> (<strong>{purgePlat.investisseur_nom}</strong>)</> : null} :
</p> </p>
<p style={{ margin: '0 0 12px', lineHeight: 1.6, fontFamily: 'monospace', fontSize: 13, <p style={{ margin: '0 0 12px', lineHeight: 1.6, fontFamily: 'monospace', fontSize: 13,
background: 'var(--surface-2, var(--bg))', padding: '8px 12px', borderRadius: 6, background: 'var(--surface-2, var(--bg))', padding: '8px 12px', borderRadius: 6,
@@ -485,16 +498,30 @@ export default function DataCleanupSection() {
La fiche plateforme "{purgePlat.nom}" est conservée. Cette opération ne peut pas être annulée. La fiche plateforme "{purgePlat.nom}" est conservée. Cette opération ne peut pas être annulée.
</p> </p>
<div style={{ margin: '0 0 20px' }}> <div style={{ margin: '0 0 20px' }}>
<label style={{ display: 'block', fontSize: 'var(--fs-sm)', fontWeight: 500, marginBottom: 6 }}> <label style={{ display: 'block', fontSize: 'var(--fs-sm)', fontWeight: 500, marginBottom: 8 }}>
Pour confirmer, retapez le nom exact de la plateforme : <strong>{purgePlat.nom}</strong> Pour confirmer, retapez le code affiché ci-dessous :
</label> </label>
<div style={{
textAlign: 'center', margin: '0 0 14px', padding: '14px 10px',
background: 'var(--surface-2, var(--bg))', border: '1px dashed var(--danger, #ef4444)',
borderRadius: 8,
}}>
<span style={{
fontFamily: 'monospace', fontSize: 30, fontWeight: 700,
letterSpacing: 8, color: 'var(--danger, #ef4444)',
}}>
{purgePin}
</span>
</div>
<input <input
type="text" type="text"
inputMode="numeric"
maxLength={6}
value={purgeConfirmText} value={purgeConfirmText}
onChange={e => setPurgeConfirmText(e.target.value)} onChange={e => setPurgeConfirmText(e.target.value.replace(/\D/g, '').slice(0, 6))}
placeholder={purgePlat.nom} placeholder="000000"
disabled={loadingPurge} disabled={loadingPurge}
style={{ width: '100%' }} style={{ width: '100%', textAlign: 'center', fontFamily: 'monospace', fontSize: 18, letterSpacing: 4 }}
/> />
</div> </div>
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}> <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8 }}>
@@ -502,7 +529,7 @@ export default function DataCleanupSection() {
<button <button
className="danger" className="danger"
onClick={handlePurge} onClick={handlePurge}
disabled={loadingPurge || purgeConfirmText.trim() !== purgePlat.nom} disabled={loadingPurge || purgeConfirmText.trim() !== purgePin}
> >
{loadingPurge ? 'Suppression en cours…' : 'Confirmer la suppression'} {loadingPurge ? 'Suppression en cours…' : 'Confirmer la suppression'}
</button> </button>