import React, { useState, useEffect, useMemo } from 'react'; import { api } from '../stores/api'; import PageHeader from '../components/PageHeader'; const CATEGORIES = [ { value: 'executif', label: 'Exécutif' }, { value: 'service', label: 'Service' }, { value: 'physique', label: 'Physique' }, ]; const MODULES = [ ['S0', 'Rencontres'], ['M0', "Assemblée d'affaires"], ['C5', 'Gouvernance'], ['S1T', 'Trésorerie'], ['M4', 'Donner au suivant'], ['M1', 'Rédiger PV'], ['M2', 'Présences'], ['M3', 'Rapport RSG'], ['S2', 'Remise jeton'], ['M6', 'Commander jetons'], ['S3', 'Vente littérature'], ['M5', 'Ajuster inventaire'], ['G2', 'Gestion membres'], ['G9', 'Paramètres'], ['G11', 'Gestion mandats'], ['G12', 'Gestion postes'], ]; const GROUPES_MODULES = [ { titre: 'Réunion', codes: ['S0'] }, { titre: 'Affaires', codes: ['M0', 'M1', 'M2', 'M3', 'C5'] }, { titre: 'Finances', codes: ['S1T', 'S5', 'M4'] }, { titre: 'Inventaire', codes: ['M5', 'M6'] }, { titre: 'Administration', codes: ['G2', 'G9', 'G11', 'G12', 'G13'] }, ]; export default function GererPostes() { const [postes, setPostes] = useState([]); const [modulesPostes, setModulesPostes] = useState({}); const [candidatures, setCandidatures] = useState([]); const [tab, setTab] = useState('postes'); const [posteOuvert, setPosteOuvert] = useState(null); const [posteDetail, setPosteDetail] = useState(null); const [posteAttentes, setPosteAttentes] = useState(null); const [posteEdition, setPosteEdition] = useState(null); const [showForm, setShowForm] = useState(false); const [msg, setMsg] = useState(''); const [error, setError] = useState(''); const [nom, setNom] = useState(''); const [categorie, setCategorie] = useState('service'); const [description, setDescription] = useState(''); const [prerequis, setPrerequis] = useState(''); const [informations, setInformations] = useState(''); const charger = async () => { try { const [p, mp, c] = await Promise.all([ api.get('/postes/?inclure_abolis=true'), api.get('/postes/modules'), api.get('/postes/candidatures'), ]); setPostes(p); setModulesPostes(mp); setCandidatures(c); } catch (e) { setError(e.message); } }; useEffect(() => { charger(); }, []); const flash = (m) => { setMsg(m); setTimeout(() => setMsg(''), 2500); }; const creerPoste = async () => { if (!nom.trim()) { setError('Nom requis'); return; } setError(''); try { await api.post('/postes/', { nom: nom.trim(), categorie, description: description.trim() || null, prerequis: prerequis.trim() || null, informations: informations.trim() || null, }); setNom(''); setDescription(''); setPrerequis(''); setInformations(''); setShowForm(false); flash('Poste créé ✓'); await charger(); } catch (e) { setError(e.message); } }; const abolir = async (id, nomPoste) => { if (!confirm(`Abolir le poste «${nomPoste}» ?\nTous les mandats actifs seront terminés.`)) return; try { const res = await api.request('DELETE', `/postes/${id}`); flash(`Poste aboli — ${res.mandats_termines} mandat(s) terminé(s)`); await charger(); } catch (e) { setError(e.message); } }; const reactiver = async (id) => { try { await api.post(`/postes/${id}/reactiver`); flash('Poste réactivé ✓'); await charger(); } catch (e) { setError(e.message); } }; const supprimerPermanent = async (id, nomPoste) => { if (!confirm(`Supprimer définitivement le poste «${nomPoste}» ?`)) return; try { await api.request('DELETE', `/postes/${id}/permanent`); flash('Poste supprimé'); await charger(); } catch (e) { setError(e.message); } }; const ouvrirEdition = (p) => { setPosteEdition(p.id); setNom(p.nom || ''); setCategorie(p.categorie || 'service'); setDescription(p.description || ''); setPrerequis(p.prerequis || ''); setInformations(p.informations || ''); }; const modifierPoste = async (id) => { if (!nom.trim()) { setError('Nom requis'); return; } setError(''); try { await api.patch(`/postes/${id}`, { nom: nom.trim(), categorie, description: description.trim() || null, prerequis: prerequis.trim() || null, informations: informations.trim() || null, }); setPosteEdition(null); setNom(''); setDescription(''); setPrerequis(''); setInformations(''); flash('Poste modifié ✓'); await charger(); } catch (e) { setError(e.message); } }; const toggleModule = async (posteId, code) => { const actuel = new Set(modulesPostes[posteId] || []); if (actuel.has(code)) actuel.delete(code); else actuel.add(code); const codes = [...actuel]; setModulesPostes({ ...modulesPostes, [posteId]: codes }); try { await api.request('PUT', `/postes/${posteId}/modules`, codes); flash('Accès mis à jour ✓'); } catch (e) { setError(e.message); await charger(); } }; const traiterCandidature = async (id, statut) => { try { await api.patch(`/postes/candidatures/${id}?statut=${statut}`); flash(statut === 'acceptee' ? 'Candidature acceptée ✓' : 'Candidature refusée'); await charger(); } catch (e) { setError(e.message); } }; const CAT_ICON = { executif: '🔵', service: '🟣', physique: '🟢' }; const moduleParCode = useMemo(() => new Map(MODULES.map(([code, label]) => [code, label])), []); const groupesPourPoste = (posteId) => GROUPES_MODULES.map((groupe) => ({ ...groupe, modules: groupe.codes .filter((code) => moduleParCode.has(code)) .map((code) => [code, moduleParCode.get(code), (modulesPostes[posteId] || []).includes(code)]), })).filter((groupe) => groupe.modules.length > 0); return (
{msg &&
{msg}
} {error &&
{error}
}
{[ ['postes', `Postes (${postes.length})`], ['candidatures', `Candidatures (${candidatures.length})`], ].map(([t, label]) => ( ))}
{tab === 'postes' && (
{showForm && (
setNom(e.target.value)} placeholder="Nom du poste" className="w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue" /> setDescription(e.target.value)} placeholder="Description" className="w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue" /> setPrerequis(e.target.value)} placeholder="Prérequis" className="w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue" />