Fix multi-détenteur
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user