From ab6ba0c13ec5bb065c438f4fbfee791e94dd44e4 Mon Sep 17 00:00:00 2001 From: Daniel Allaire Date: Sun, 31 May 2026 23:30:57 -0400 Subject: [PATCH] Ajuster gestion des groupes multi-groupes --- backend/app/routers/admin.py | 31 +++-- backend/app/routers/auth.py | 3 +- backend/app/routers/presences.py | 1 - backend/app/routers/rapports.py | 10 +- backend/app/routers/reunions.py | 1 - backend/app/services/admin_database.py | 50 +++++-- deploy/seed.py | 175 ++----------------------- frontend/src/components/PageHeader.jsx | 6 +- frontend/src/pages/Accueil.jsx | 5 +- frontend/src/pages/GererMembres.jsx | 4 +- frontend/src/pages/GestionGroupes.jsx | 62 +++------ frontend/src/pages/Inscription.jsx | 2 +- frontend/src/pages/Login.jsx | 2 +- frontend/src/pages/Parametres.jsx | 1 - 14 files changed, 99 insertions(+), 254 deletions(-) diff --git a/backend/app/routers/admin.py b/backend/app/routers/admin.py index acaf408..067bacd 100644 --- a/backend/app/routers/admin.py +++ b/backend/app/routers/admin.py @@ -10,8 +10,8 @@ from app.services.admin_database import ( creer_groupe, initialiser_demo, modifier_groupe, + reinitialiser_groupe, reinitialiser_demo, - remettre_a_zero, supprimer_groupe, ) from app.models.groupe import Groupe @@ -30,7 +30,6 @@ class SysadminLoginRequest(BaseModel): class GroupeAdminRequest(BaseModel): nom: str district: str = "87-16" - region: str = "87" adresse_local: str | None = None jour_reunion: str | None = "mardi" heure_reunion: str | None = "19:30" @@ -55,14 +54,6 @@ async def sysadmin_login(req: SysadminLoginRequest, db: AsyncSession = Depends(g raise HTTPException(status_code=401, detail="PIN Sysadmin invalide") -@router.post("/reset") -async def reset_database( - _sysadmin=Depends(require_sysadmin), - db: AsyncSession = Depends(get_db), -): - return await remettre_a_zero(db) - - @router.post("/demo") async def demo_database( _sysadmin=Depends(require_sysadmin), @@ -79,13 +70,26 @@ async def reset_demo_database( return await reinitialiser_demo(db) +@router.post("/groupes/{groupe_id}/reset") +async def reset_groupe_admin( + groupe_id: str, + _sysadmin=Depends(require_sysadmin), + db: AsyncSession = Depends(get_db), +): + try: + return await reinitialiser_groupe(db, groupe_id) + except ValueError as exc: + raise HTTPException(status_code=400, detail=str(exc)) + + @router.get("/groupes") async def liste_groupes_admin( _sysadmin=Depends(require_sysadmin), db: AsyncSession = Depends(get_db), ): await initialiser_demo(db) - groupes = (await db.execute(select(Groupe).order_by(Groupe.nom))).scalars().all() + groupes = (await db.execute(select(Groupe))).scalars().all() + groupes.sort(key=lambda g: (g.nom == "Groupe Démonstration", g.nom.lower())) out = [] for groupe in groupes: nb_membres = (await db.execute( @@ -101,7 +105,6 @@ async def liste_groupes_admin( "id": str(groupe.id), "nom": groupe.nom, "district": groupe.district, - "region": groupe.region, "adresse_local": groupe.adresse_local, "jour_reunion": groupe.jour_reunion, "heure_reunion": groupe.heure_reunion.strftime("%H:%M") if groupe.heure_reunion else None, @@ -112,8 +115,8 @@ async def liste_groupes_admin( "membres": nb_membres, "reunions": nb_reunions, "traces": nb_traces, - "demo": groupe.nom == "Groupe Résilience", - "protege": groupe.nom == "Groupe Résilience", + "demo": groupe.nom == "Groupe Démonstration", + "protege": groupe.nom == "Groupe Démonstration", }) return out diff --git a/backend/app/routers/auth.py b/backend/app/routers/auth.py index 24c093f..c87e6c2 100644 --- a/backend/app/routers/auth.py +++ b/backend/app/routers/auth.py @@ -29,8 +29,9 @@ async def health(db: AsyncSession = Depends(get_db)): @router.get("/groupes") async def liste_groupes(db: AsyncSession = Depends(get_db)): await initialiser_demo(db) - result = await db.execute(select(Groupe).order_by(Groupe.nom)) + result = await db.execute(select(Groupe)) groupes = result.scalars().all() + groupes.sort(key=lambda g: (g.nom == "Groupe Démonstration", g.nom.lower())) return [{ "id": str(g.id), "nom": g.nom, diff --git a/backend/app/routers/presences.py b/backend/app/routers/presences.py index 4c5e839..733010f 100644 --- a/backend/app/routers/presences.py +++ b/backend/app/routers/presences.py @@ -352,7 +352,6 @@ async def rapport_assemblee_pdf( item for item in [ groupe.adresse_local if groupe else None, f"District {groupe.district}" if groupe and groupe.district else None, - f"Région {groupe.region}" if groupe and groupe.region else None, ] if item ]) html = f""" diff --git a/backend/app/routers/rapports.py b/backend/app/routers/rapports.py index 84d99c0..e7f9c89 100644 --- a/backend/app/routers/rapports.py +++ b/backend/app/routers/rapports.py @@ -119,7 +119,7 @@ async def rapport_finances( html_content = f"""
{groupe.nom if groupe else 'Groupe'}
-
District {groupe.district if groupe else '87-16'} · Région {groupe.region if groupe else '87'}
+
District {groupe.district if groupe else '87-16'}

Rapport financier — {MOIS_FR[mois]} {annee}

@@ -190,7 +190,7 @@ async def rapport_reunions( html_content = f"""
{groupe.nom if groupe else 'Groupe'}
-
District {groupe.district if groupe else '87-16'} · Région {groupe.region if groupe else '87'}
+
District {groupe.district if groupe else '87-16'}

Réunions — {MOIS_FR[mois]} {annee}

@@ -391,7 +391,7 @@ async def rapport_resolutions(
{groupe.nom if groupe else 'Groupe'}
-
District {groupe.district if groupe else '87-16'} · Région {groupe.region if groupe else '87'}
+
District {groupe.district if groupe else '87-16'}

Registre des résolutions — {annee}

Décisions prises en Groupe

@@ -760,12 +760,10 @@ async def _html_etat_resultats( groupe_nom = groupe.nom if groupe and groupe.nom else "Groupe" district = str(groupe.district if groupe and groupe.district else "87-16") - region = str(groupe.region if groupe and groupe.region else "87") - html_content = f"""
{escape(groupe_nom)}
-
District {escape(district)} · Région {escape(region)}
+
District {escape(district)}

État des résultats — {MOIS_FR[mois]} {annee}

diff --git a/backend/app/routers/reunions.py b/backend/app/routers/reunions.py index 0900b0e..b616e7b 100644 --- a/backend/app/routers/reunions.py +++ b/backend/app/routers/reunions.py @@ -394,7 +394,6 @@ async def rapport_reunion_pdf( item for item in [ groupe.adresse_local if groupe else None, f"District {groupe.district}" if groupe and groupe.district else None, - f"Région {groupe.region}" if groupe and groupe.region else None, ] if item ]) ventes_lit_html = ( diff --git a/backend/app/services/admin_database.py b/backend/app/services/admin_database.py index 39156fe..9b36ff2 100644 --- a/backend/app/services/admin_database.py +++ b/backend/app/services/admin_database.py @@ -40,6 +40,9 @@ from app.models.transaction_comptable import TransactionComptable from app.models.vente_litterature import VenteLitterature from app.models.vente_jeton import VenteJeton +DEMO_GROUP_NAME = "Groupe Démonstration" +OLD_DEMO_GROUP_NAMES = ("Groupe Résilience",) + POSTES = [ ("RSG", "executif", "Représente le groupe auprès du district et rapporte les informations de service.", "2 ans de stabilité", 1, ["M3", "C2", "C5"]), @@ -106,8 +109,21 @@ async def remettre_a_zero(db: AsyncSession) -> dict: } +async def _groupe_demo(db: AsyncSession) -> Groupe | None: + result = await db.execute(select(Groupe).where(Groupe.nom.in_([DEMO_GROUP_NAME, *OLD_DEMO_GROUP_NAMES]))) + groupe = result.scalars().first() + if groupe and groupe.nom != DEMO_GROUP_NAME: + groupe.nom = DEMO_GROUP_NAME + await db.flush() + return groupe + + +def _est_groupe_demo(groupe: Groupe | None) -> bool: + return bool(groupe and groupe.nom in {DEMO_GROUP_NAME, *OLD_DEMO_GROUP_NAMES}) + + async def initialiser_demo(db: AsyncSession) -> dict: - existant = (await db.execute(select(Groupe).where(Groupe.nom == "Groupe Résilience"))).scalar_one_or_none() + existant = await _groupe_demo(db) if existant: membres_existants = await _membres_par_courriel(db, existant.id) return { @@ -121,7 +137,7 @@ async def initialiser_demo(db: AsyncSession) -> dict: groupe, sysadmin, postes, litterature = await _creer_base( db, - nom_groupe="Groupe Résilience", + nom_groupe=DEMO_GROUP_NAME, adresse_local="Salle communautaire Saint-Louis, Montréal", ) membres = {sysadmin.courriel: sysadmin} @@ -141,7 +157,7 @@ async def initialiser_demo(db: AsyncSession) -> dict: async def reinitialiser_demo(db: AsyncSession) -> dict: - groupe = (await db.execute(select(Groupe).where(Groupe.nom == "Groupe Résilience"))).scalar_one_or_none() + groupe = await _groupe_demo(db) if not groupe: return await initialiser_demo(db) await _vider_groupe(db, groupe.id) @@ -161,16 +177,28 @@ async def reinitialiser_demo(db: AsyncSession) -> dict: } +async def reinitialiser_groupe(db: AsyncSession, groupe_id) -> dict: + groupe = await db.get(Groupe, groupe_id) + if not groupe: + raise ValueError("Groupe introuvable") + if _est_groupe_demo(groupe): + return await reinitialiser_demo(db) + await _vider_groupe(db, groupe.id) + await _peupler_groupe_base(db, groupe) + await db.flush() + return {"message": f"Groupe {groupe.nom} réinitialisé", "groupe_id": groupe.id} + + async def creer_groupe(db: AsyncSession, data: dict) -> Groupe: nom = (data.get("nom") or "").strip() if not nom: raise ValueError("Nom requis") - if nom == "Groupe Résilience": + if nom == DEMO_GROUP_NAME or nom in OLD_DEMO_GROUP_NAMES: raise ValueError("Ce nom est réservé au groupe de démonstration") groupe = Groupe( nom=nom, district=(data.get("district") or "87-16").strip(), - region=(data.get("region") or "87").strip(), + region="", adresse_local=(data.get("adresse_local") or "").strip() or None, jour_reunion=(data.get("jour_reunion") or "mardi").strip() or None, heure_reunion=_parse_heure(data.get("heure_reunion")), @@ -190,12 +218,12 @@ async def modifier_groupe(db: AsyncSession, groupe_id, data: dict) -> Groupe: if not groupe: raise ValueError("Groupe introuvable") nom = (data.get("nom") or groupe.nom).strip() - if groupe.nom == "Groupe Résilience" and nom != "Groupe Résilience": + if _est_groupe_demo(groupe) and nom != DEMO_GROUP_NAME: raise ValueError("Le groupe de démonstration ne peut pas être renommé") - if nom == "Groupe Résilience" and groupe.nom != "Groupe Résilience": + if (nom == DEMO_GROUP_NAME or nom in OLD_DEMO_GROUP_NAMES) and not _est_groupe_demo(groupe): raise ValueError("Ce nom est réservé au groupe de démonstration") groupe.nom = nom - for attr in ["district", "region", "adresse_local", "jour_reunion", "assemblee_affaires_ordre", "format_reunion", "lien_aa87"]: + for attr in ["district", "adresse_local", "jour_reunion", "assemblee_affaires_ordre", "format_reunion", "lien_aa87"]: if attr in data: valeur = data.get(attr) setattr(groupe, attr, valeur.strip() if isinstance(valeur, str) and valeur.strip() else None) @@ -209,7 +237,7 @@ async def supprimer_groupe(db: AsyncSession, groupe_id) -> dict: groupe = await db.get(Groupe, groupe_id) if not groupe: raise ValueError("Groupe introuvable") - if groupe.nom == "Groupe Résilience": + if _est_groupe_demo(groupe): raise ValueError("Le groupe de démonstration est protégé") nb_groupes = (await db.execute(select(Groupe))).scalars().all() if len(nb_groupes) <= 1: @@ -222,13 +250,13 @@ async def supprimer_groupe(db: AsyncSession, groupe_id) -> dict: async def _creer_base( db: AsyncSession, - nom_groupe: str = "Groupe Méditation", + nom_groupe: str = DEMO_GROUP_NAME, adresse_local: str = "Salle communautaire, Montréal", ): groupe = Groupe( nom=nom_groupe, district="87-16", - region="87", + region="", adresse_local=adresse_local, jour_reunion="mardi", heure_reunion=time(19, 30), diff --git a/deploy/seed.py b/deploy/seed.py index ca50417..a4644a5 100644 --- a/deploy/seed.py +++ b/deploy/seed.py @@ -1,22 +1,16 @@ """ -Script d'initialisation — Groupe Résilience -Crée les postes, le groupe initial et le premier membre. +Script d'initialisation. +Crée le schéma et le groupe de démonstration initial. Usage: cd /opt/groupe-meditation/backend && venv/bin/python ../deploy/seed.py """ import asyncio import sys import os -import uuid -import secrets -import csv -from datetime import date, datetime, timedelta, timezone -from pathlib import Path # Ajouter le backend au path sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "backend")) from app.core.database import engine, Base, async_session -from app.core.security import hash_pin from app.services.admin_database import initialiser_demo # Importer TOUS les modèles pour que create_all crée toutes les tables from app.models.groupe import Groupe @@ -48,173 +42,20 @@ from app.models.mouvement_reserve import MouvementReserve from app.models.destinataire_contribution import DestinataireContribution -POSTES = [ - ("RSG", "executif", "Représentant aux Services du Groupe", "730 days", "2 ans sobriété", 1), - ("RSG Substitut(e)", "executif", "Remplace le RSG, se prépare à assumer le rôle", "730 days", "1 an sobriété", 2), - ("Trésorier(ière)", "executif", "Gestion financière, 7e Tradition", "548 days", "1 an sobriété", 3), - ("Secrétaire", "executif", "PV, correspondance, mémoire du groupe", "548 days", "6 mois sobriété", 4), - ("Animateur(trice)", "service", "Anime les réunions régulières", None, "6 mois sobriété", 5), - ("Responsable accueil", "physique", "Accueil des membres et nouveaux", "365 days", "Sobriété stable", 6), - ("Responsable café", "physique", "Café, entretien de la salle", "365 days", "Aucun", 7), - ("Responsable littérature", "service", "Inventaire et vente de littérature AA", "365 days", "Connaissance littérature AA", 8), - ("Responsable jetons", "service", "Jetons et anniversaires de sobriété", "365 days", "Aucun", 9), - ("Responsable clés", "physique", "Ouverture et fermeture du local", None, "Fiabilité", 10), -] - - -def charger_catalogue_litterature(): - chemin = Path(__file__).resolve().parents[1] / "data" / "import" / "Liste-de-prix-rev.-Fevrier-2026.csv" - if not chemin.exists(): - return [ - {"titre": "Les Alcooliques anonymes (Gros Livre)", "categorie": "livre", "prix_coutant": 12.00, "code_bsg": "B-1"}, - {"titre": "Les Douze Étapes et les Douze Traditions", "categorie": "livre", "prix_coutant": 11.00, "code_bsg": "B-2"}, - {"titre": "Vivre sans alcool", "categorie": "livre", "prix_coutant": 9.00, "code_bsg": "B-7"}, - {"titre": "Les AA sont-ils pour vous?", "categorie": "brochure", "prix_coutant": 0.00, "code_bsg": "P-3"}, - {"titre": "Un nouveau arrive", "categorie": "depliant", "prix_coutant": 0.00, "code_bsg": "P-16"}, - ] - - with chemin.open(newline="", encoding="utf-8") as fichier: - return [ - { - "code_bsg": row["code_bsg"].strip() or None, - "titre": row["titre"].strip(), - "categorie": row["categorie"].strip(), - "prix_coutant": float(row["prix_coutant"]) if row["prix_coutant"].strip() else None, - } - for row in csv.DictReader(fichier) - if row.get("titre", "").strip() - ] - - async def seed(): - # Créer les tables async with engine.begin() as conn: await conn.run_sync(Base.metadata.create_all) async with async_session() as db: - # ── Créer le groupe ── - print("\n═══ Initialisation du Groupe Résilience ═══\n") - groupe = Groupe( - nom="Groupe Résilience", - district="87-16", - region="87", - adresse_local="Salle communautaire Saint-Louis, Montréal", - jour_reunion="mardi", - heure_reunion=datetime.strptime("19:30", "%H:%M").time(), - format_reunion="Discussion ouverte", - lien_aa87="https://aa87.org", - ) - db.add(groupe) - await db.flush() - print(f"✓ Groupe créé: {groupe.nom} (district {groupe.district})") - - # ── Créer les postes ── - postes_map = {} - for nom, cat, desc, duree, prereq, ordre in POSTES: - poste = Poste( - groupe_id=groupe.id, - nom=nom, - categorie=cat, - description=desc, - prerequis=prereq, - ordre_affichage=ordre, - ) - db.add(poste) - await db.flush() - postes_map[nom] = poste - print(f" ✓ Poste: {nom} ({cat})") - - # ── Premier membre ── - print("\n── Premier membre (vous) ──") - prenom = input(" Prénom: ").strip().title() - nom_membre = input(" Nom (optionnel, Entrée pour passer): ").strip() - nom_membre = nom_membre.title() if nom_membre else None - courriel = input(" Courriel: ").strip().lower() - while not courriel or ("@" not in courriel and courriel != "sysadmin"): - courriel = input(" Courriel invalide. Réessayer: ").strip().lower() - telephone = input(" Téléphone: ").strip() - while not telephone: - telephone = input(" Téléphone obligatoire: ").strip() - pin = input(" PIN (4 chiffres): ").strip() - while not pin.isdigit() or len(pin) != 4: - pin = input(" PIN invalide. 4 chiffres: ").strip() - - poste_choisi = None - if courriel != "sysadmin": - print("\n Postes disponibles:") - for i, (nom_poste, _, _, _, _, _) in enumerate(POSTES[:4], 1): - print(f" {i}. {nom_poste}") - choix = input(" Votre poste (1-4): ").strip() - poste_idx = int(choix) - 1 if choix.isdigit() and 1 <= int(choix) <= 4 else 0 - poste_choisi = POSTES[poste_idx][0] - - membre = Membre( - groupe_id=groupe.id, - prenom=prenom, - nom=nom_membre, - courriel=courriel, - telephone=telephone, - pin_hash=hash_pin(pin), - ) - db.add(membre) - await db.flush() - - if poste_choisi: - affectation = Affectation( - groupe_id=groupe.id, - membre_id=membre.id, - poste_id=postes_map[poste_choisi].id, - date_debut=date.today(), - statut="actif", - ) - db.add(affectation) - - # ── Première invitation ── - code = secrets.token_hex(6).upper() - invitation = Invitation( - groupe_id=groupe.id, - code=code, - cree_par=membre.id, - expire_le=datetime.now(timezone.utc) + timedelta(days=7), - ) - db.add(invitation) - - # ── Littérature de base ── - catalogue_litterature = charger_catalogue_litterature() - for item in catalogue_litterature: - db.add(Litterature( - groupe_id=groupe.id, - titre=item["titre"], - categorie=item["categorie"], - prix_coutant=item["prix_coutant"], - quantite_stock=0, - seuil_commande=2, - code_bsg=item["code_bsg"], - )) - print(f" ✓ Littérature de base : {len(catalogue_litterature)} titres") - - db.add(DestinataireContribution( - groupe_id=groupe.id, - nom="District 87-16", - protege=True, - actif=True, - )) - print(" ✓ Destinataire de contribution : District 87-16") - demo = await initialiser_demo(db) - print(f" ✓ Groupe de démonstration : {demo['message']}") - await db.commit() - print(f"\n═══ Initialisation terminée ═══") - print(f" Membre: {prenom} ({courriel})") - print(f" Groupe: Groupe Méditation") - print(f" Poste: {poste_choisi or 'Sysadmin'}") - print(f"\n Code d'invitation pour les prochains membres: {code}") - print(f" (Expire dans 7 jours)") - print(f"\n Connectez-vous sur l'app avec:") - print(f" Courriel: {courriel}") - print(f" PIN: {pin}") + print("\n═══ Initialisation terminée ═══") + print(" Groupe: Groupe Démonstration") + print(f" {demo['message']}") + print("\n Connectez-vous avec:") + print(" Identifiant: sysadmin") + print(" PIN: 0000") if __name__ == "__main__": diff --git a/frontend/src/components/PageHeader.jsx b/frontend/src/components/PageHeader.jsx index 8412039..578a296 100644 --- a/frontend/src/components/PageHeader.jsx +++ b/frontend/src/components/PageHeader.jsx @@ -2,7 +2,7 @@ import React from 'react'; import { useStore } from '../stores/store'; export default function PageHeader({ titre, sousTitre, retour = true, action = null }) { - const { membre, setPage, logout } = useStore(); + const { membre, groupe, setPage, logout } = useStore(); return (
@@ -17,7 +17,9 @@ export default function PageHeader({ titre, sousTitre, retour = true, action = n )}
-

Bonjour {membre?.prenom}

+

+ {groupe?.nom ? `${groupe.nom} · ` : ''}Bonjour {membre?.prenom} +

{titre}

{sousTitre &&

{sousTitre}

}
diff --git a/frontend/src/pages/Accueil.jsx b/frontend/src/pages/Accueil.jsx index f70dede..b2ef3ec 100644 --- a/frontend/src/pages/Accueil.jsx +++ b/frontend/src/pages/Accueil.jsx @@ -87,6 +87,7 @@ export default function Accueil() { modulesGestion, navContext, setPage, + groupe, } = useStore(); const [recherche, setRecherche] = useState(''); @@ -126,7 +127,9 @@ export default function Accueil() {
-

Bonjour {membre?.prenom}

+

+ {groupe?.nom ? `${groupe.nom} · ` : ''}Bonjour {membre?.prenom} +

{contexte.titre}

{contexte.description}

diff --git a/frontend/src/pages/GererMembres.jsx b/frontend/src/pages/GererMembres.jsx index b3b04c6..d9d9227 100644 --- a/frontend/src/pages/GererMembres.jsx +++ b/frontend/src/pages/GererMembres.jsx @@ -4,7 +4,7 @@ import { useStore } from '../stores/store'; import PageHeader from '../components/PageHeader'; export default function GererMembres() { - const { membre, estSysadmin, impersoner } = useStore(); + const { membre, groupe, estSysadmin, impersoner } = useStore(); const [membres, setMembres] = useState([]); const [loading, setLoading] = useState(true); const [detail, setDetail] = useState(null); @@ -54,7 +54,7 @@ export default function GererMembres() { }; const partagerSMS = () => { - const texte = `Rejoins le Groupe Méditation sur l'app. Ton code d'invitation : ${code}`; + const texte = `Rejoins ${groupe?.nom || 'le groupe'} sur l'app. Ton code d'invitation : ${code}`; window.open(`sms:?body=${encodeURIComponent(texte)}`); }; diff --git a/frontend/src/pages/GestionGroupes.jsx b/frontend/src/pages/GestionGroupes.jsx index 94e71ad..8e4d8e4 100644 --- a/frontend/src/pages/GestionGroupes.jsx +++ b/frontend/src/pages/GestionGroupes.jsx @@ -9,7 +9,7 @@ const jourLabel = (jour) => { }; export default function GestionGroupes() { - const { loadGroupes, logout } = useStore(); + const { loadGroupes } = useStore(); const [groupes, setGroupes] = useState([]); const [ouvertId, setOuvertId] = useState(''); const [editionId, setEditionId] = useState(''); @@ -35,30 +35,11 @@ export default function GestionGroupes() { useEffect(() => { charger(); }, []); - const resetDemo = async () => { - const confirmation = window.prompt('Cette action réinitialise seulement les données fictives du groupe de démonstration. Tapez CONFIRMER pour continuer.'); - if (confirmation !== 'CONFIRMER') return; - setBusy(true); - setError(''); - setMsg(''); - try { - const res = await api.post('/admin/demo/reset'); - setMsg(res.message || 'Groupe de démonstration réinitialisé'); - await charger(); - await loadGroupes(); - } catch (e) { - setError(e.message); - } finally { - setBusy(false); - } - }; - const nouveauGroupe = () => { setEditionId('nouveau'); setForm({ nom: '', district: '87-16', - region: '87', adresse_local: '', jour_reunion: 'mardi', heure_reunion: '19:30', @@ -73,7 +54,6 @@ export default function GestionGroupes() { setForm({ nom: groupe.nom || '', district: groupe.district || '87-16', - region: groupe.region || '87', adresse_local: groupe.adresse_local || '', jour_reunion: groupe.jour_reunion || 'mardi', heure_reunion: groupe.heure_reunion || '19:30', @@ -124,17 +104,20 @@ export default function GestionGroupes() { } }; - const remettreAZero = async () => { - const confirmation = window.prompt('Cette action efface toute la base et recrée seulement le compte Sysadmin. Tapez EFFACER pour continuer.'); - if (confirmation !== 'EFFACER') return; + const reinitialiser = async (groupe) => { + const confirmation = window.prompt(`Réinitialiser les données du groupe "${groupe.nom}"? Tapez REINIT pour continuer.`); + if (confirmation !== 'REINIT') return; setBusy(true); setError(''); + setMsg(''); try { - await api.post('/admin/reset'); - alert('Base remise à zéro. Reconnectez-vous avec Sysadmin / 0000.'); - logout(); + const res = await api.post(`/admin/groupes/${groupe.id}/reset`); + setMsg(res.message || 'Groupe réinitialisé'); + await charger(); + await loadGroupes(); } catch (e) { setError(e.message); + } finally { setBusy(false); } }; @@ -155,13 +138,6 @@ export default function GestionGroupes() { > Créer un groupe -
{form && ( @@ -173,9 +149,8 @@ export default function GestionGroupes() { setForm({ ...form, jour_reunion: e.target.value })} placeholder="Jour" className="w-full p-3 bg-gray-50 rounded-xl border-0" /> setForm({ ...form, heure_reunion: e.target.value })} className="w-full p-3 bg-gray-50 rounded-xl border-0" />
-
+
setForm({ ...form, district: e.target.value })} placeholder="District" className="w-full p-3 bg-gray-50 rounded-xl border-0" /> - setForm({ ...form, region: e.target.value })} placeholder="Région" className="w-full p-3 bg-gray-50 rounded-xl border-0" />
DateTypeAnimateurThèmeAnnonces