diff --git a/frontend/src/pages/admin/UsersSection.jsx b/frontend/src/pages/admin/UsersSection.jsx index 8b1faaa..8478595 100644 --- a/frontend/src/pages/admin/UsersSection.jsx +++ b/frontend/src/pages/admin/UsersSection.jsx @@ -265,60 +265,42 @@ function InviteUserModal({ open, onClose, onSent }) { } // ── Modale renvoi invitation ─────────────────────────────────────────────── -function ResendInviteModal({ user, onClose, onSent }) { +function ResendInviteModal({ user, onClose, onSuccess, onError }) { const [loading, setLoading] = useState(false); const [err, setErr] = useState(null); - const [sent, setSent] = useState(false); - const handleClose = () => { setSent(false); setErr(null); onClose(); }; + const handleClose = () => { setErr(null); onClose(); }; const handleSend = async () => { setLoading(true); setErr(null); try { await api.post('/admin/invitations', { email: user.email, role: user.role }); - setSent(true); - onSent?.(); - } catch (e) { setErr(e.message); } - finally { setLoading(false); } + // Ferme d'abord, puis notifie le parent — évite le re-render concurrent + handleClose(); + onSuccess?.(user.email); + } catch (e) { + setErr(e.message); + } finally { setLoading(false); } }; const identity = user?.display_name ? `${user.display_name} (${user.email})` : user?.email; return ( Fermer - ) : ( + footer={ <> - )} + } > - {sent ? ( -
-
- - - -
-

Invitation renvoyée !

-

- Un nouveau lien a été envoyé à {user?.email}.
- L'ancien lien a été révoqué. Le nouveau est valable 7 jours. -

-
- ) : ( - <> - {err &&
{err}
} -

- Renvoyer un nouveau lien d'invitation à {identity} ? -
L'ancien lien sera révoqué et remplacé par un nouveau valable 7 jours. -

- - )} + {err &&
{err}
} +

+ Renvoyer un nouveau lien d'invitation à {identity} ? +
L'ancien lien sera révoqué et remplacé par un nouveau valable 7 jours. +

); } @@ -396,6 +378,7 @@ export default function UsersSection({ currentUserId }) { const [showCreate, setShowCreate] = useState(false); const [showInvite, setShowInvite] = useState(false); const [resendTarget, setResendTarget] = useState(null); + const [banner, setBanner] = useState(null); // { ok, msg } const [search, setSearch] = useState(''); const [filterStatus, setFilterStatus] = useState('all'); const [filterRole, setFilterRole] = useState('all'); @@ -445,6 +428,12 @@ export default function UsersSection({ currentUserId }) { `Marquer l'email de ${u.display_name || u.email} comme vérifié ?`, async () => { await api.patch(`/admin/users/${u.id}/verify-email`, {}); load(); }, 'Confirmer'); const resendInvitation = u => setResendTarget(u); + const resendVerifEmail = async u => { + try { + await api.post('/auth/resend-verification', { email: u.email }); + setBanner({ ok: true, msg: `Email de vérification renvoyé à ${u.email}.` }); + } catch (e) { setBanner({ ok: false, msg: e.message }); } + }; const setStatus = (u, status) => { const labels = { deactivated: 'Désactiver', active: 'Réactiver', locked: 'Verrouiller' }; confirm(`${labels[status]} le compte`, `${labels[status]} le compte de ${u.display_name || u.email} ?`, @@ -532,6 +521,15 @@ export default function UsersSection({ currentUserId }) { <>
+ {/* Bannière succès/erreur */} + {banner && ( + setBanner(null)} + style={{ margin: '12px 20px 0', borderRadius: 8 }} + /> + )} + {/* En-tête */}
@@ -668,10 +666,11 @@ export default function UsersSection({ currentUserId }) { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 8, boxShadow: '0 4px 20px rgba(0,0,0,0.15)', padding: '4px 0', minWidth: 200, }}> - } label={openMenu.user.role === 'admin' ? '→ Utilisateur' : '→ Admin'} onClick={() => { setOpenMenu(null); toggleRole(openMenu.user); }} /> + } label={openMenu.user.role === 'admin' ? 'Rétrograder en utilisateur' : 'Promouvoir en admin'} onClick={() => { setOpenMenu(null); toggleRole(openMenu.user); }} /> {!openMenu.user.email_verified && <> } label="Renvoyer l'invitation" onClick={() => { setOpenMenu(null); resendInvitation(openMenu.user); }} /> } label="Vérifier l'email" onClick={() => { setOpenMenu(null); verifyEmail(openMenu.user); }} /> + } label="Nouvelle demande de vérification" onClick={() => { setOpenMenu(null); resendVerifEmail(openMenu.user); }} /> } {openMenu.user.id !== currentUserId && <> {(!openMenu.user.status || openMenu.user.status === 'active') && } label="Désactiver" onClick={() => { setOpenMenu(null); setStatus(openMenu.user, 'deactivated'); }} />} @@ -693,7 +692,10 @@ export default function UsersSection({ currentUserId }) { setResendTarget(null)} - onSent={() => load()} + onSuccess={email => { + load(); + setBanner({ ok: true, msg: `Invitation renvoyée à ${email}. Le lien est valable 7 jours.` }); + }} />