groupe-meditation/frontend/src/pages/GererMembres.jsx

146 lines
6.4 KiB
React
Raw Normal View History

2026-03-04 14:01:00 -05:00
import React, { useState, useEffect } from 'react';
import { api } from '../stores/api';
import PageHeader from '../components/PageHeader';
export default function GererMembres() {
const [membres, setMembres] = useState([]);
const [loading, setLoading] = useState(true);
const [detail, setDetail] = useState(null);
const [confirmAction, setConfirmAction] = useState(null);
const [msg, setMsg] = useState('');
const charger = async () => {
setLoading(true);
try {
const data = await api.get('/membres/');
setMembres(data);
} catch {}
setLoading(false);
};
useEffect(() => { charger(); }, []);
const desactiver = async (id) => {
try {
const res = await api.patch(`/membres/${id}/desactiver`);
setMsg(res.message);
setConfirmAction(null);
setDetail(null);
charger();
setTimeout(() => setMsg(''), 3000);
} catch (e) { alert(e.message); }
};
const droitOubli = async (id) => {
try {
const res = await api.request('DELETE', `/membres/${id}/oubli`);
setMsg(res.message);
setConfirmAction(null);
setDetail(null);
charger();
setTimeout(() => setMsg(''), 3000);
} catch (e) { alert(e.message); }
};
// Vue détail d'un membre
if (detail) {
return (
<div className="min-h-screen bg-gray-100">
<div className="bg-aa-blue text-white p-4 flex items-center gap-3">
<button onClick={() => { setDetail(null); setConfirmAction(null); }} className="text-2xl">←</button>
<h1 className="text-lg font-bold">{detail.prenom} {detail.nom}</h1>
</div>
<div className="p-4 space-y-4">
{msg && <div className="bg-green-50 text-green-700 p-3 rounded-xl text-center text-sm font-medium">{msg}</div>}
<div className="bg-white rounded-2xl p-4 shadow-sm space-y-3">
<div><p className="text-xs text-gray-400">Prénom</p><p className="font-medium">{detail.prenom}</p></div>
<div><p className="text-xs text-gray-400">Nom</p><p className="font-medium">{detail.nom}</p></div>
<div><p className="text-xs text-gray-400">Téléphone</p><p className="font-medium">{detail.telephone || '—'}</p></div>
<div><p className="text-xs text-gray-400">Courriel</p><p className="font-medium">{detail.courriel || '—'}</p></div>
<div><p className="text-xs text-gray-400">Date d'abstinence</p><p className="font-medium">{detail.date_abstinence || '—'}</p></div>
<div><p className="text-xs text-gray-400">Statut</p>
<span className={`inline-block px-2 py-1 rounded-full text-xs font-bold ${detail.actif ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>
{detail.actif ? 'Actif' : 'Inactif'}
</span>
</div>
</div>
{/* Contact rapide */}
<div className="grid grid-cols-2 gap-2">
{detail.telephone && (
<a href={`tel:${detail.telephone}`}
className="p-3 bg-green-50 border border-green-200 rounded-xl text-center text-green-700 font-bold text-sm">
📞 Appeler
</a>
)}
{detail.courriel && (
<a href={`mailto:${detail.courriel}`}
className="p-3 bg-blue-50 border border-blue-200 rounded-xl text-center text-blue-700 font-bold text-sm">
✉️ Courriel
</a>
)}
</div>
{/* Actions */}
{detail.actif && !confirmAction && (
<button onClick={() => setConfirmAction('desactiver')}
className="w-full p-3 bg-orange-50 border border-orange-200 text-orange-700 rounded-xl font-bold text-sm">
Désactiver ce membre
</button>
)}
{!confirmAction && (
<button onClick={() => setConfirmAction('oubli')}
className="w-full p-3 bg-red-50 border border-red-200 text-red-700 rounded-xl font-bold text-sm">
Droit à l'oubli (irréversible)
</button>
)}
{/* Confirmations */}
{confirmAction === 'desactiver' && (
<div className="bg-orange-50 rounded-2xl p-4 border border-orange-200">
<p className="text-sm text-orange-800 mb-3">Désactiver {detail.prenom} ? Le membre ne pourra plus se connecter.</p>
<div className="flex gap-2">
<button onClick={() => desactiver(detail.id)} className="flex-1 p-3 bg-orange-500 text-white rounded-xl font-bold">Confirmer</button>
<button onClick={() => setConfirmAction(null)} className="flex-1 p-3 bg-gray-200 text-gray-700 rounded-xl font-bold">Annuler</button>
</div>
</div>
)}
{confirmAction === 'oubli' && (
<div className="bg-red-50 rounded-2xl p-4 border border-red-200">
<p className="text-sm text-red-800 mb-3">⚠️ Cette action est irréversible. Toutes les données personnelles de {detail.prenom} seront anonymisées.</p>
<div className="flex gap-2">
<button onClick={() => droitOubli(detail.id)} className="flex-1 p-3 bg-red-600 text-white rounded-xl font-bold">Supprimer</button>
<button onClick={() => setConfirmAction(null)} className="flex-1 p-3 bg-gray-200 text-gray-700 rounded-xl font-bold">Annuler</button>
</div>
</div>
)}
</div>
</div>
);
}
return (
<div className="min-h-screen bg-gray-100">
<PageHeader titre="Gérer les membres" sousTitre="G2 — Fiche complète, désactiver" />
<div className="p-4 space-y-2">
{msg && <div className="bg-green-50 text-green-700 p-3 rounded-xl text-center text-sm font-medium mb-2">{msg}</div>}
{loading ? (
<p className="text-center text-gray-400 py-8">Chargement...</p>
) : (
membres.map((m) => (
<button key={m.id} onClick={() => setDetail(m)}
className="w-full bg-white rounded-2xl p-4 shadow-sm flex items-center justify-between active:scale-[0.98] transition">
<div>
<p className="font-bold text-gray-800">{m.prenom} {m.nom}</p>
<p className="text-xs text-gray-400">{m.telephone || m.courriel || '—'}</p>
</div>
<span className="text-gray-300">→</span>
</button>
))
)}
</div>
</div>
);
}