import React, { useEffect, useState } from 'react'; import { api } from '../stores/api'; import { useStore } from '../stores/store'; import PageHeader from '../components/PageHeader'; import { dateHeureReunionIso, datesAssembleesAffaires, dateLocale, labelDateReunion } from '../utils/datesReunion'; const INPUT = 'w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue'; export default function AssembleeAffaires() { const { postes, groupe } = useStore(); const estExecutif = postes.some((p) => ['RSG', 'RSG Substitut(e)', 'Trésorier(ière)', 'Secrétaire'].includes(p)); const choixDates = datesAssembleesAffaires(groupe); const [membres, setMembres] = useState([]); const [reunions, setReunions] = useState([]); const [pvs, setPvs] = useState([]); const [propositions, setPropositions] = useState([]); const [resolutions, setResolutions] = useState([]); const [postesVacants, setPostesVacants] = useState([]); const [reunionId, setReunionId] = useState(''); const [dateSelection, setDateSelection] = useState(dateLocale()); const [dateReunion, setDateReunion] = useState(dateLocale()); const [note, setNote] = useState(''); const [presencesMap, setPresencesMap] = useState({}); const [contenu, setContenu] = useState(''); const [pvPrecedent, setPvPrecedent] = useState(null); const [showPvPrecedent, setShowPvPrecedent] = useState(false); const [adoption, setAdoption] = useState({ proposeur_id: '', secondeur_id: '' }); const [msg, setMsg] = useState(''); const [error, setError] = useState(''); const [loading, setLoading] = useState(false); const charger = async () => { try { const [m, r, pv, props, res, postesDispo] = await Promise.all([ api.get('/membres/actifs'), api.get('/presences/reunions'), api.get('/pv/'), api.get('/propositions/?statut=secondee&limite=100'), api.get('/propositions/resolutions'), api.get('/postes/disponibles'), ]); setMembres(m); setReunions(r); setPvs(pv); setPropositions(props); setResolutions(res); setPostesVacants(postesDispo); const map = {}; m.forEach((mb) => { map[mb.id] = true; }); setPresencesMap(map); const duJour = r.find((x) => x.date_reunion?.slice(0, 10) === dateSelection); if (duJour) setReunionId(duJour.id); } catch (e) { setError(e.message); } }; useEffect(() => { charger(); }, []); useEffect(() => { if (choixDates.length > 0) { if (!choixDates.includes(dateSelection)) setDateSelection(choixDates.find((d) => d >= dateLocale()) || choixDates[choixDates.length - 1]); if (!choixDates.includes(dateReunion)) setDateReunion(choixDates.find((d) => d >= dateLocale()) || choixDates[choixDates.length - 1]); } }, [groupe?.jour_reunion, groupe?.assemblee_affaires_ordre]); useEffect(() => { const duJour = reunions.find((x) => x.date_reunion?.slice(0, 10) === dateSelection); setReunionId(duJour?.id || ''); const precedents = pvs.filter((p) => p.date_reunion && p.date_reunion.slice(0, 10) < dateSelection); setPvPrecedent(precedents[0] || null); }, [dateSelection, reunions, pvs]); const reunion = reunions.find((r) => r.id === reunionId); const pvJour = pvs.find((p) => p.date_reunion?.slice(0, 10) === dateSelection); const resolutionsJour = resolutions.filter((r) => (r.date_vote || r.cree_le?.slice(0, 10)) === dateSelection); const nbPresents = Object.values(presencesMap).filter(Boolean).length; const toggle = (membreId) => setPresencesMap({ ...presencesMap, [membreId]: !presencesMap[membreId] }); const imprimer = () => window.print(); const creerRapport = async () => { const res = await api.post('/presences/reunion', { date_reunion: dateHeureReunionIso(dateReunion, groupe), note: note.trim() || null, }); setReunionId(res.id); setReunions([res, ...reunions]); setDateSelection(res.date_reunion.slice(0, 10)); return res.id; }; const enregistrer = async () => { setError(''); setMsg(''); setLoading(true); try { const id = reunionId || await creerRapport(); const presences = Object.entries(presencesMap).map(([membre_id, present]) => ({ membre_id, present })); await api.post('/presences/', { reunion_id: id, presences }); if (contenu.trim()) { await api.post('/pv/', { reunion_id: id, contenu: contenu.trim(), decisions: null, }); } setMsg(contenu.trim() ? 'Présences et PV enregistrés' : 'Présences enregistrées'); await charger(); } catch (e) { setError(e.message); } setLoading(false); }; const adopterPvPrecedent = async () => { if (!pvPrecedent) return; if (!adoption.proposeur_id || !adoption.secondeur_id) { setError('Proposeur et secondeur requis'); return; } setError(''); try { await api.patch(`/pv/${pvPrecedent.id}/adopter`, adoption); setMsg('PV précédent adopté'); await charger(); } catch (e) { setError(e.message); } }; const textePvAuto = [ 'Ouverture de l’assemblée.', '', pvPrecedent ? `Lecture du procès-verbal précédent (${new Date(pvPrecedent.date_reunion).toLocaleDateString('fr-CA')}).` : 'Lecture du procès-verbal précédent.', '', 'Réflexions en cours:', ...propositions.map((p) => `- ${p.sujet} (${p.proposeur_prenom} / ${p.secondeur_prenom || 'à confirmer'})`), '', 'Décisions prises pendant cette assemblée:', ...resolutionsJour.map((r) => `- ${r.numero_resolution || ''} ${r.sujet}`.trim()), '', 'Postes disponibles:', ...postesVacants.map((p) => `- ${p.nom}`), ].join('\n'); return (
{msg &&
{msg}
} {error &&
{error}
}
{pvPrecedent && ( )}
{showPvPrecedent && pvPrecedent && (

{new Date(pvPrecedent.date_reunion).toLocaleDateString('fr-CA')}

{pvPrecedent.contenu}

{estExecutif && !pvPrecedent.approuve && (
)}
)}

Rapport d’assemblée d’affaires

{dateSelection}

{reunion?.presences?.length ? reunion.presences.filter((p) => p.present).map((p) =>
  • {p.membre_prenom}
  • ) :
  • Présences à cocher sur papier
  • }
    {propositions.length ? propositions.map((p) =>
  • {p.sujet} ({p.proposeur_prenom} / {p.secondeur_prenom || 'à confirmer'})
  • ) :
  • Aucune proposition secondée non résolue
  • }
    {resolutionsJour.length ? resolutionsJour.map((r) =>
  • {r.numero_resolution} — {r.sujet}
  • ) :
  • Aucune décision enregistrée pour cette date
  • }
    {postesVacants.length ? postesVacants.map((p) =>
  • {p.nom}
  • ) :
  • Aucun poste vacant
  • }

    Procès-verbal

    {pvJour?.contenu || textePvAuto}

    {estExecutif && ( <> {reunions.length > 0 && ( )} {!reunionId && ( <> setNote(e.target.value)} placeholder="Note optionnelle" className={INPUT} /> )}
    {membres.map((m) => ( ))}