diff --git a/frontend/src/features/assemblees/assembleeUi.jsx b/frontend/src/features/assemblees/assembleeUi.jsx
new file mode 100644
index 0000000..0431ac3
--- /dev/null
+++ b/frontend/src/features/assemblees/assembleeUi.jsx
@@ -0,0 +1,87 @@
+import React from 'react';
+import { labelDateReunion } from '../../utils/datesReunion';
+
+export const INPUT = 'w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue';
+
+const STATUTS = {
+ proposee: ['À seconder', 'bg-yellow-100 text-yellow-700'],
+ secondee: ['Secondée', 'bg-blue-100 text-blue-700'],
+ rejetee: ['Rejetée', 'bg-red-100 text-red-700'],
+};
+
+export function boutonAction(actif) {
+ return `p-3 rounded-xl text-sm font-bold ${actif ? 'bg-aa-blue text-white' : 'bg-gray-50 text-gray-700'}`;
+}
+
+export function Card({ titre, children }) {
+ return
{titre}
{children};
+}
+
+export function Champ({ label, children }) {
+ return ;
+}
+
+export function SelectDate({ value, onChange, dates }) {
+ if (!dates.length) {
+ return Configurez le jour de réunion dans les paramètres du groupe.
;
+ }
+ return (
+
+ );
+}
+
+export function MembreSelect({ label, value, onChange, membres }) {
+ return (
+
+ );
+}
+
+export function DecisionItem({ p, membres, estExecutif, form, setForm, seconderPour, setSeconderPour, seconder, voter }) {
+ const [label, cls] = STATUTS[p.statut] || STATUTS.proposee;
+ const motif = (form.etant_donne_que || '').trim();
+ const decision = (form.groupe_a_decide_de || '').trim();
+ return (
+
+
+
+
{p.sujet}
+ {p.description &&
{p.description}
}
+
Proposée par {p.proposeur_prenom}{p.secondeur_prenom ? ` · Secondée par ${p.secondeur_prenom}` : ''}
+
+
{label}
+
+
+ {p.statut === 'proposee' && (
+
+ )}
+
+ {p.statut === 'secondee' && estExecutif && (
+
+ )}
+
+ );
+}
diff --git a/frontend/src/features/assemblees/assembleeUtils.js b/frontend/src/features/assemblees/assembleeUtils.js
new file mode 100644
index 0000000..e8c01b6
--- /dev/null
+++ b/frontend/src/features/assemblees/assembleeUtils.js
@@ -0,0 +1,29 @@
+export function textePvAuto(pvPrecedent, propositions, resolutionsJour, postesVacants) {
+ return [
+ "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');
+}
+
+export function moisPrecedent(dateStr) {
+ const d = new Date(`${dateStr}T12:00:00`);
+ d.setMonth(d.getMonth() - 1);
+ const annee = d.getFullYear();
+ const mois = d.getMonth() + 1;
+ const noms = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
+ return { annee, mois, libelle: `${noms[mois]} ${annee}` };
+}
+
+export function heure(dateIso) {
+ return dateIso ? new Date(dateIso).toLocaleTimeString('fr-CA', { hour: '2-digit', minute: '2-digit' }) : '--:--';
+}
diff --git a/frontend/src/pages/AssembleeAffaires.jsx b/frontend/src/pages/AssembleeAffaires.jsx
index 6d59e5c..38bbfae 100644
--- a/frontend/src/pages/AssembleeAffaires.jsx
+++ b/frontend/src/pages/AssembleeAffaires.jsx
@@ -3,18 +3,13 @@ import { api } from '../stores/api';
import { useStore } from '../stores/store';
import PageHeader from '../components/PageHeader';
import { dateHeureReunionIso, datesAssembleesAffaires, dateLocale, labelDateReunion } from '../utils/datesReunion';
+import { heure, moisPrecedent, textePvAuto } from '../features/assemblees/assembleeUtils';
+import { boutonAction, Card, Champ, DecisionItem, INPUT, MembreSelect, SelectDate } from '../features/assemblees/assembleeUi';
-const INPUT = 'w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue';
const METHODES = [['VIREMENT', 'Virement'], ['CHEQUE', 'Chèque']];
-const STATUTS = {
- proposee: ['À seconder', 'bg-yellow-100 text-yellow-700'],
- secondee: ['Secondée', 'bg-blue-100 text-blue-700'],
- rejetee: ['Rejetée', 'bg-red-100 text-red-700'],
-};
export default function AssembleeAffaires({ contexte = false }) {
- const { postes, groupe } = useStore();
- const estExecutif = postes.some((p) => ['Sysadmin', 'RSG', 'RSG Substitut(e)', 'Trésorier(ière)', 'Secrétaire'].includes(p));
+ const { estExecutif, groupe } = useStore();
const choixDatesChrono = datesAssembleesAffaires(groupe);
const choixDates = [...choixDatesChrono].reverse();
const prochaineDate = choixDatesChrono.find((d) => d >= dateLocale()) || choixDatesChrono[choixDatesChrono.length - 1] || dateLocale();
@@ -513,140 +508,3 @@ export default function AssembleeAffaires({ contexte = false }) {
);
}
-
-function RapportAssemblee({ date, reunion, pvJour, pvPrecedent, propositions, resolutionsJour, postesVacants }) {
- const contenuAuto = textePvAuto(pvPrecedent, propositions, resolutionsJour, postesVacants);
- return (
-
-
Rapport d'assemblée d'affaires
-
{labelDateReunion(date)}
-
- {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 || contenuAuto}
-
-
- );
-}
-
-function textePvAuto(pvPrecedent, propositions, resolutionsJour, postesVacants) {
- return [
- "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');
-}
-
-function moisPrecedent(dateStr) {
- const d = new Date(`${dateStr}T12:00:00`);
- d.setMonth(d.getMonth() - 1);
- const annee = d.getFullYear();
- const mois = d.getMonth() + 1;
- const noms = ['', 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre'];
- return { annee, mois, libelle: `${noms[mois]} ${annee}` };
-}
-
-function DecisionItem({ p, membres, estExecutif, form, setForm, seconderPour, setSeconderPour, seconder, voter }) {
- const [label, cls] = STATUTS[p.statut] || STATUTS.proposee;
- const motif = (form.etant_donne_que || '').trim();
- const decision = (form.groupe_a_decide_de || '').trim();
- return (
-
-
-
-
{p.sujet}
- {p.description &&
{p.description}
}
-
Proposée par {p.proposeur_prenom}{p.secondeur_prenom ? ` · Secondée par ${p.secondeur_prenom}` : ''}
-
-
{label}
-
-
- {p.statut === 'proposee' && (
-
- {estExecutif &&
- )}
-
- {p.statut === 'secondee' && estExecutif && (
-
-
- )}
-
- );
-}
-
-function boutonAction(actif) {
- return `p-3 rounded-xl text-sm font-bold ${actif ? 'bg-aa-blue text-white' : 'bg-gray-50 text-gray-700'}`;
-}
-
-function heure(dateIso) {
- return dateIso ? new Date(dateIso).toLocaleTimeString('fr-CA', { hour: '2-digit', minute: '2-digit' }) : '--:--';
-}
-
-function Card({ titre, children }) {
- return {titre}
{children};
-}
-
-function Champ({ label, children }) {
- return ;
-}
-
-function Section({ titre, children }) {
- return ;
-}
-
-function SelectDate({ value, onChange, dates }) {
- if (!dates.length) {
- return Configurez le jour de réunion dans les paramètres du groupe.
;
- }
- return (
-
- );
-}
-
-function MembreSelect({ label, value, onChange, membres }) {
- return (
-
- );
-}
diff --git a/frontend/src/pages/Decisions.jsx b/frontend/src/pages/Decisions.jsx
index 4418f87..86118fc 100644
--- a/frontend/src/pages/Decisions.jsx
+++ b/frontend/src/pages/Decisions.jsx
@@ -19,7 +19,7 @@ const TYPES = {
};
export default function Decisions() {
- const { postes, estExecutif } = useStore();
+ const { estExecutif } = useStore();
const [propositions, setPropositions] = useState([]);
const [resolutions, setResolutions] = useState([]);
const [membres, setMembres] = useState([]);
@@ -34,9 +34,7 @@ export default function Decisions() {
const [seconderPour, setSeconderPour] = useState({});
const [decisionOuverte, setDecisionOuverte] = useState(null);
- const peutExecutif = estExecutif || postes.some((p) =>
- ['RSG', 'RSG Substitut(e)', 'Trésorier(ière)', 'Secrétaire'].includes(p)
- );
+ const peutExecutif = estExecutif;
const charger = async () => {
setLoading(true);
diff --git a/frontend/src/pages/Evenements.jsx b/frontend/src/pages/Evenements.jsx
index 9be64ad..2eb8180 100644
--- a/frontend/src/pages/Evenements.jsx
+++ b/frontend/src/pages/Evenements.jsx
@@ -9,7 +9,7 @@ const TYPE_STYLE = {
};
export default function Evenements() {
- const { postes } = useStore();
+ const { estExecutif } = useStore();
const [evenements, setEvenements] = useState([]);
const [filtres, setFiltres] = useState(['anniversaire', 'adhoc']);
const [loading, setLoading] = useState(true);
@@ -23,10 +23,6 @@ export default function Evenements() {
const [description, setDescription] = useState('');
const [lieu, setLieu] = useState('');
- const estExecutif = postes.some((p) =>
- ['RSG', 'RSG Substitut(e)', 'Trésorier(ière)', 'Secrétaire'].includes(p)
- );
-
const charger = async () => {
try {
const data = await api.get('/evenements/?jours=365&jours_avant=365');
diff --git a/frontend/src/pages/ReunionHebdomadaire.jsx b/frontend/src/pages/ReunionHebdomadaire.jsx
index 5f420f6..e9d449b 100644
--- a/frontend/src/pages/ReunionHebdomadaire.jsx
+++ b/frontend/src/pages/ReunionHebdomadaire.jsx
@@ -8,8 +8,7 @@ const TYPES_JETONS = [['desir', 'Désir'], ['24h', '24 heures'], ['1mois', '1 mo
const INPUT = 'w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue';
export default function ReunionHebdomadaire({ contexte = false }) {
- const { postes, groupe } = useStore();
- const estExecutif = postes.some((p) => ['Sysadmin', 'RSG', 'RSG Substitut(e)', 'Trésorier(ière)', 'Secrétaire'].includes(p));
+ const { estExecutif, groupe } = useStore();
const choixDatesChrono = datesReunion(groupe, { joursAvant: 365, joursApres: 180 });
const choixDates = [...choixDatesChrono].reverse();
const prochaineDate = choixDatesChrono.find((d) => d >= dateLocale()) || choixDatesChrono[choixDatesChrono.length - 1] || dateLocale();