2026-05-25 17:39:38 -04:00
import React , { useEffect , useState } from 'react' ;
import { api } from '../stores/api' ;
import { useStore } from '../stores/store' ;
import PageHeader from '../components/PageHeader' ;
import { dateHeureReunionIso , datesReunion , dateLocale , labelDateReunion } from '../utils/datesReunion' ;
const TYPES _JETONS = [ [ 'desir' , 'Désir' ] , [ '24h' , '24 heures' ] , [ '1mois' , '1 mois' ] , [ '2mois' , '2 mois' ] , [ '3mois' , '3 mois' ] , [ '6mois' , '6 mois' ] , [ '9mois' , '9 mois' ] , [ '1an' , '1 an' ] , [ 'multiple' , 'Multiple' ] ] ;
const INPUT = 'w-full p-3 bg-gray-50 rounded-xl border-0 focus:ring-2 focus:ring-aa-blue' ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
export default function ReunionHebdomadaire ( { contexte = false } ) {
2026-05-31 09:15:12 -04:00
const { estExecutif , groupe } = useStore ( ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const choixDatesChrono = datesReunion ( groupe , { joursAvant : 365 , joursApres : 180 } ) ;
const choixDates = [ ... choixDatesChrono ] . reverse ( ) ;
const prochaineDate = choixDatesChrono . find ( ( d ) => d >= dateLocale ( ) ) || choixDatesChrono [ choixDatesChrono . length - 1 ] || dateLocale ( ) ;
2026-05-25 17:39:38 -04:00
const [ membres , setMembres ] = useState ( [ ] ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const [ animateurDefautId , setAnimateurDefautId ] = useState ( '' ) ;
2026-05-25 17:39:38 -04:00
const [ catalogue , setCatalogue ] = useState ( [ ] ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const [ rencontres , setRencontres ] = useState ( [ ] ) ;
const [ ouverteId , setOuverteId ] = useState ( null ) ;
const [ action , setAction ] = useState ( '' ) ;
2026-05-25 17:39:38 -04:00
const [ msg , setMsg ] = useState ( '' ) ;
const [ error , setError ] = useState ( '' ) ;
const [ loading , setLoading ] = useState ( false ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const [ planifier , setPlanifier ] = useState ( false ) ;
const [ plan , setPlan ] = useState ( { date : prochaineDate , animateur _id : '' , theme : '' , annonces : '' , note : '' } ) ;
const [ collecte , setCollecte ] = useState ( { montant : '' , detenteur _id : '' } ) ;
const [ vente , setVente ] = useState ( { type : 'litterature' , litterature _id : '' , type _jeton : 'desir' , quantite : '1' , montant : '' , vendu _par _id : '' } ) ;
const [ jeton , setJeton ] = useState ( { type _jeton : '' , membre _id : '' , annees : '' } ) ;
const [ rapport , setRapport ] = useState ( { animateur _id : '' , theme : '' , annonces : '' , note : '' } ) ;
2026-05-25 17:39:38 -04:00
const charger = async ( ) => {
try {
const [ m , l , r ] = await Promise . all ( [
api . get ( '/membres/actifs' ) ,
api . get ( '/litterature/' ) ,
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
api . get ( '/reunions/rencontres/details?limite=80' ) ,
2026-05-25 17:39:38 -04:00
] ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
let animateurId = '' ;
if ( estExecutif ) {
try {
const affectations = await api . get ( '/postes/affectations/groupe' ) ;
const affectationAnimateur = affectations . find ( ( a ) => ( a . poste _nom || '' ) . toLowerCase ( ) . includes ( 'animateur' ) ) ;
animateurId = affectationAnimateur ? . membre _id || '' ;
} catch {
animateurId = '' ;
}
}
2026-05-25 17:39:38 -04:00
setMembres ( m ) ;
setCatalogue ( l ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
setRencontres ( r ) ;
setAnimateurDefautId ( animateurId ) ;
if ( m . length > 0 ) {
const fallbackAnimateur = animateurId || m [ 0 ] . id ;
setPlan ( ( f ) => ( { ... f , animateur _id : f . animateur _id || fallbackAnimateur } ) ) ;
setRapport ( ( f ) => ( { ... f , animateur _id : f . animateur _id || fallbackAnimateur } ) ) ;
setCollecte ( ( f ) => ( { ... f , detenteur _id : f . detenteur _id || m [ 0 ] . id } ) ) ;
setVente ( ( f ) => ( { ... f , vendu _par _id : f . vendu _par _id || m [ 0 ] . id } ) ) ;
}
2026-05-25 17:39:38 -04:00
} catch ( e ) { setError ( e . message ) ; }
} ;
useEffect ( ( ) => { charger ( ) ; } , [ ] ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const flash = ( texte ) => { setMsg ( texte ) ; setTimeout ( ( ) => setMsg ( '' ) , 2500 ) ; } ;
const dateRencontre = ( r ) => r . date _reunion ? . slice ( 0 , 10 ) ;
const rencontreOuverte = rencontres . find ( ( r ) => r . id === ouverteId ) ;
const ouvrir = ( id ) => {
const prochaine = ouverteId === id ? null : id ;
setOuverteId ( prochaine ) ;
setAction ( '' ) ;
const r = rencontres . find ( ( x ) => x . id === id ) ;
const animateur = membres . find ( ( m ) => m . prenom === r ? . animateur _prenom ) ;
setRapport ( {
animateur _id : animateur ? . id || animateurDefautId || membres [ 0 ] ? . id || '' ,
theme : r ? . theme || '' ,
annonces : ( r ? . annonces || [ ] ) . join ( '\n' ) ,
note : r ? . note || '' ,
} ) ;
} ;
2026-05-25 17:39:38 -04:00
const choisirLitterature = ( id ) => {
const item = catalogue . find ( ( c ) => c . id === id ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const quantite = parseInt ( vente . quantite || '1' ) ;
setVente ( {
... vente ,
litterature _id : id ,
montant : item ? . prix _coutant ? ( item . prix _coutant * quantite ) . toFixed ( 2 ) : vente . montant ,
} ) ;
2026-05-25 17:39:38 -04:00
} ;
const changerQuantite = ( valeur ) => {
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const item = catalogue . find ( ( c ) => c . id === vente . litterature _id ) ;
const qte = parseInt ( valeur || '0' ) ;
setVente ( {
... vente ,
quantite : valeur ,
montant : vente . type === 'litterature' && item ? . prix _coutant && qte > 0 ? ( item . prix _coutant * qte ) . toFixed ( 2 ) : vente . montant ,
} ) ;
2026-05-25 17:39:38 -04:00
} ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const creerRencontre = async ( ) => {
setLoading ( true ) ;
setError ( '' ) ;
try {
await api . post ( '/reunions/' , {
type : 'reguliere' ,
date _reunion : dateHeureReunionIso ( plan . date , groupe ) ,
animateur _id : plan . animateur _id || animateurDefautId || null ,
theme : plan . theme . trim ( ) || 'Rencontre hebdomadaire' ,
annonces : plan . annonces . split ( '\n' ) . map ( ( a ) => a . trim ( ) ) . filter ( Boolean ) || null ,
note : plan . note . trim ( ) || null ,
} ) ;
setPlanifier ( false ) ;
setPlan ( { date : prochaineDate , animateur _id : animateurDefautId , theme : '' , annonces : '' , note : '' } ) ;
flash ( 'Rencontre planifiée' ) ;
await charger ( ) ;
} catch ( e ) { setError ( e . message ) ; }
setLoading ( false ) ;
} ;
2026-05-25 17:39:38 -04:00
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const enregistrerCollecte = async ( ) => {
if ( ! rencontreOuverte || ! collecte . montant || ! collecte . detenteur _id ) { setError ( 'Montant et détenteur requis' ) ; return ; }
setLoading ( true ) ;
2026-05-25 17:39:38 -04:00
setError ( '' ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
try {
await api . post ( '/collectes/' , {
reunion _id : rencontreOuverte . id ,
date _collecte : dateRencontre ( rencontreOuverte ) ,
montant : parseFloat ( collecte . montant ) ,
detenteur _id : collecte . detenteur _id ,
} ) ;
setCollecte ( { ... collecte , montant : '' } ) ;
flash ( 'Collecte saisie' ) ;
await charger ( ) ;
} catch ( e ) { setError ( e . message ) ; }
setLoading ( false ) ;
} ;
const enregistrerVente = async ( ) => {
if ( ! rencontreOuverte || ! vente . montant || ! vente . vendu _par _id ) { setError ( 'Montant et vendeur requis' ) ; return ; }
const quantite = parseInt ( vente . quantite || '0' ) ;
if ( quantite <= 0 ) { setError ( 'Quantité invalide' ) ; return ; }
2026-05-25 17:39:38 -04:00
setLoading ( true ) ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
setError ( '' ) ;
2026-05-25 17:39:38 -04:00
try {
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
if ( vente . type === 'litterature' ) {
if ( ! vente . litterature _id ) { setError ( 'Sélectionnez un titre' ) ; setLoading ( false ) ; return ; }
await api . post ( '/ventes-litterature/' , {
reunion _id : rencontreOuverte . id ,
litterature _id : vente . litterature _id ,
quantite ,
montant : parseFloat ( vente . montant ) ,
date _vente : dateRencontre ( rencontreOuverte ) ,
vendu _par _id : vente . vendu _par _id ,
} ) ;
} else {
await api . post ( '/jetons/ventes' , {
reunion _id : rencontreOuverte . id ,
type _jeton : vente . type _jeton ,
quantite ,
montant : parseFloat ( vente . montant ) ,
date _vente : dateRencontre ( rencontreOuverte ) ,
vendu _par _id : vente . vendu _par _id ,
2026-05-25 17:39:38 -04:00
} ) ;
}
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
setVente ( { ... vente , litterature _id : '' , quantite : '1' , montant : '' } ) ;
flash ( 'Vente saisie' ) ;
await charger ( ) ;
2026-05-25 17:39:38 -04:00
} catch ( e ) { setError ( e . message ) ; }
setLoading ( false ) ;
} ;
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
const enregistrerJeton = async ( ) => {
if ( ! rencontreOuverte || ! jeton . type _jeton ) { setError ( 'Sélectionnez un type de jeton' ) ; return ; }
if ( jeton . type _jeton !== 'desir' && ! jeton . membre _id ) { setError ( 'Sélectionnez un membre' ) ; return ; }
if ( jeton . type _jeton === 'multiple' && ( ! jeton . annees || parseInt ( jeton . annees ) < 2 ) ) { setError ( "Nombre d'années requis" ) ; return ; }
setLoading ( true ) ;
setError ( '' ) ;
try {
const body = {
reunion _id : rencontreOuverte . id ,
type _jeton : jeton . type _jeton ,
date _remise : dateRencontre ( rencontreOuverte ) ,
} ;
if ( jeton . membre _id ) body . membre _id = jeton . membre _id ;
if ( jeton . type _jeton === 'multiple' ) body . annees = parseInt ( jeton . annees ) ;
await api . post ( '/jetons/' , body ) ;
setJeton ( { type _jeton : '' , membre _id : '' , annees : '' } ) ;
flash ( 'Jeton/gâteau comptabilisé' ) ;
await charger ( ) ;
} catch ( e ) { setError ( e . message ) ; }
setLoading ( false ) ;
} ;
const enregistrerRapport = async ( ) => {
if ( ! rencontreOuverte ) return ;
setLoading ( true ) ;
setError ( '' ) ;
try {
await api . patch ( ` /reunions/ ${ rencontreOuverte . id } ` , {
type : 'reguliere' ,
date _reunion : rencontreOuverte . date _reunion ,
animateur _id : rapport . animateur _id || null ,
theme : rapport . theme . trim ( ) || 'Rencontre hebdomadaire' ,
annonces : rapport . annonces . split ( '\n' ) . map ( ( a ) => a . trim ( ) ) . filter ( Boolean ) || null ,
note : rapport . note . trim ( ) || null ,
} ) ;
flash ( 'Rapport enregistré' ) ;
await charger ( ) ;
} catch ( e ) { setError ( e . message ) ; }
setLoading ( false ) ;
} ;
const telechargerRapport = async ( rencontre ) => {
setLoading ( true ) ;
setError ( '' ) ;
try {
const token = api . getToken ( ) ;
const res = await fetch ( ` /api/reunions/ ${ rencontre . id } /rapport.pdf ` , {
headers : { Authorization : ` Bearer ${ token } ` } ,
} ) ;
if ( ! res . ok ) throw new Error ( 'Erreur de génération du rapport PDF' ) ;
const blob = await res . blob ( ) ;
const a = document . createElement ( 'a' ) ;
a . href = URL . createObjectURL ( blob ) ;
a . download = ` rapport_rencontre_ ${ dateRencontre ( rencontre ) } .pdf ` ;
a . click ( ) ;
URL . revokeObjectURL ( a . href ) ;
} catch ( e ) {
setError ( e . message ) ;
} finally {
setLoading ( false ) ;
}
} ;
const heure = ( dateIso ) => ( dateIso ? new Date ( dateIso ) . toLocaleTimeString ( 'fr-CA' , { hour : '2-digit' , minute : '2-digit' } ) : '—' ) ;
2026-05-25 17:39:38 -04:00
return (
< div className = "min-h-screen bg-gray-100" >
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
< PageHeader titre = "Rencontres" sousTitre = "Saisies et rapports des rencontres hebdomadaires" retour = { ! contexte } / >
2026-05-25 17:39:38 -04:00
< 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 > }
{ error && < div className = "bg-red-50 text-red-600 p-3 rounded-xl text-center text-sm" > { error } < / div > }
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
{ estExecutif && (
< button onClick = { ( ) => setPlanifier ( ! planifier ) } className = "w-full p-3 bg-aa-blue text-white rounded-xl text-sm font-bold" >
Planifier une rencontre
2026-05-26 08:15:28 -04:00
< / button >
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
) }
2026-05-25 17:39:38 -04:00
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
{ planifier && (
< Card titre = "Nouvelle rencontre" >
< Champ label = "Date" > < SelectDate value = { plan . date } onChange = { ( v ) => setPlan ( { ... plan , date : v } ) } dates = { choixDates } / > < / Champ >
< Champ label = "Animé par" > < MembreSelect value = { plan . animateur _id } onChange = { ( v ) => setPlan ( { ... plan , animateur _id : v } ) } membres = { membres } / > < / Champ >
< Champ label = "Sujet" > < input value = { plan . theme } onChange = { ( e ) => setPlan ( { ... plan , theme : e . target . value } ) } className = { INPUT } / > < / Champ >
< Champ label = "Annonces" > < textarea value = { plan . annonces } onChange = { ( e ) => setPlan ( { ... plan , annonces : e . target . value } ) } rows = { 3 } className = { ` ${ INPUT } resize-none ` } / > < / Champ >
< Champ label = "Note" > < textarea value = { plan . note } onChange = { ( e ) => setPlan ( { ... plan , note : e . target . value } ) } rows = { 2 } className = { ` ${ INPUT } resize-none ` } / > < / Champ >
< button onClick = { creerRencontre } disabled = { loading } className = "w-full p-3 bg-green-600 text-white rounded-xl text-sm font-bold disabled:opacity-40" > Créer < / button >
< / Card >
2026-05-25 17:39:38 -04:00
) }
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
< div className = "space-y-3" >
{ rencontres . map ( ( r ) => (
< div key = { r . id } className = "bg-white rounded-2xl shadow-sm overflow-hidden" >
< div className = "flex items-start gap-2 p-4" >
< button onClick = { ( ) => ouvrir ( r . id ) } className = "min-w-0 flex-1 text-left active:bg-gray-50" >
< div className = "flex items-start justify-between gap-3" >
< div className = "min-w-0" >
< p className = "font-extrabold text-gray-900" > { labelDateReunion ( dateRencontre ( r ) ) } · { heure ( r . date _reunion ) } < / p >
< p className = "text-sm text-gray-500 truncate" > Sujet : { r . theme || 'Rencontre hebdomadaire' } · Animé par : { r . animateur _prenom || '—' } < / p >
< / div >
< span className = "text-xl text-gray-300" > { ouverteId === r . id ? '⌃' : '⌄' } < / span >
< / div >
< / button >
< button onClick = { ( ) => telechargerRapport ( r ) } disabled = { loading }
className = "shrink-0 rounded-xl bg-gray-900 px-3 py-2 text-xs font-bold text-white disabled:opacity-40" >
Rapport PDF
< / button >
< / div >
{ ouverteId === r . id && (
< div className = "p-4 pt-0 space-y-3 border-t border-gray-100" >
< Resume rencontre = { r } / >
< div className = "grid grid-cols-2 gap-2" >
{ [ 'Collecte' , 'Ventes' , 'Jetons/Gâteaux' ] . map ( ( nom ) => (
< button key = { nom } onClick = { ( ) => setAction ( action === nom ? '' : nom ) }
className = { ` p-3 rounded-xl text-sm font-bold ${ action === nom ? 'bg-aa-blue text-white' : 'bg-gray-50 text-gray-700' } ` } >
{ nom }
< / button >
) ) }
{ estExecutif && (
< button onClick = { ( ) => setAction ( action === 'Modifier' ? '' : 'Modifier' ) }
className = { ` p-3 rounded-xl text-sm font-bold ${ action === 'Modifier' ? 'bg-aa-blue text-white' : 'bg-gray-50 text-gray-700' } ` } >
Modifier
< / button >
) }
< / div >
{ action === 'Collecte' && (
< Card titre = "Collecte" >
{ r . collecte ? < p className = "text-sm text-gray-500" > Collecte déjà saisie pour cette rencontre . < / p > : (
< >
< Champ label = "Montant" > < input type = "number" inputMode = "decimal" step = "0.01" value = { collecte . montant } onChange = { ( e ) => setCollecte ( { ... collecte , montant : e . target . value } ) } className = { INPUT } / > < / Champ >
< Champ label = "Détenteur de l'argent" > < MembreSelect value = { collecte . detenteur _id } onChange = { ( v ) => setCollecte ( { ... collecte , detenteur _id : v } ) } membres = { membres } / > < / Champ >
< button onClick = { enregistrerCollecte } disabled = { loading } className = "w-full p-3 bg-green-600 text-white rounded-xl text-sm font-bold disabled:opacity-40" > Saisir la collecte < / button >
< / >
) }
< / Card >
) }
{ action === 'Ventes' && (
< Card titre = "Ventes" >
< div className = "grid grid-cols-2 gap-2" >
{ [ 'litterature' , 'jeton' ] . map ( ( type ) => < button key = { type } onClick = { ( ) => setVente ( { ... vente , type } ) } className = { ` p-3 rounded-xl text-sm font-bold ${ vente . type === type ? 'bg-aa-blue text-white' : 'bg-gray-50 text-gray-600' } ` } > { type === 'litterature' ? 'Littérature' : 'Jeton' } < / button > ) }
< / div >
{ vente . type === 'litterature' ? (
< Champ label = "Titre" > < select value = { vente . litterature _id } onChange = { ( e ) => choisirLitterature ( e . target . value ) } className = { INPUT } > < option value = "" > Sélectionner < / option > { catalogue . map ( ( c ) => < option key = { c . id } value = { c . id } > { c . titre } ( { c . quantite _stock } ) < / option > ) } < / select > < / Champ >
) : (
< Champ label = "Type de jeton" > < select value = { vente . type _jeton } onChange = { ( e ) => setVente ( { ... vente , type _jeton : e . target . value } ) } className = { INPUT } > { TYPES _JETONS . map ( ( [ value , label ] ) => < option key = { value } value = { value } > { label } < / option > ) } < / select > < / Champ >
) }
< div className = "grid grid-cols-2 gap-2" >
< Champ label = "Quantité" > < input type = "number" min = "1" value = { vente . quantite } onChange = { ( e ) => changerQuantite ( e . target . value ) } className = { INPUT } / > < / Champ >
< Champ label = "Montant" > < input type = "number" inputMode = "decimal" step = "0.01" value = { vente . montant } onChange = { ( e ) => setVente ( { ... vente , montant : e . target . value } ) } className = { INPUT } / > < / Champ >
< / div >
< Champ label = "Vendu par" > < MembreSelect value = { vente . vendu _par _id } onChange = { ( v ) => setVente ( { ... vente , vendu _par _id : v } ) } membres = { membres } / > < / Champ >
< button onClick = { enregistrerVente } disabled = { loading } className = "w-full p-3 bg-green-600 text-white rounded-xl text-sm font-bold disabled:opacity-40" > Saisir la vente < / button >
< / Card >
) }
{ action === 'Jetons/Gâteaux' && (
< Card titre = "Jetons/Gâteaux" >
< Champ label = "Type" > < select value = { jeton . type _jeton } onChange = { ( e ) => setJeton ( { ... jeton , type _jeton : e . target . value } ) } className = { INPUT } > < option value = "" > Sélectionner < / option > { TYPES _JETONS . map ( ( [ value , label ] ) => < option key = { value } value = { value } > { label } < / option > ) } < / select > < / Champ >
< Champ label = "Membre" > < MembreSelect value = { jeton . membre _id } onChange = { ( v ) => setJeton ( { ... jeton , membre _id : v } ) } membres = { membres } empty = "Anonyme / non applicable" / > < / Champ >
{ jeton . type _jeton === 'multiple' && < Champ label = "Années" > < input type = "number" min = "2" value = { jeton . annees } onChange = { ( e ) => setJeton ( { ... jeton , annees : e . target . value } ) } className = { INPUT } / > < / Champ > }
< button onClick = { enregistrerJeton } disabled = { loading } className = "w-full p-3 bg-aa-gold text-white rounded-xl text-sm font-bold disabled:opacity-40" > Comptabiliser < / button >
< / Card >
) }
{ action === 'Modifier' && (
< Card titre = "Modifier la rencontre" >
< Champ label = "Animé par" > < MembreSelect value = { rapport . animateur _id } onChange = { ( v ) => setRapport ( { ... rapport , animateur _id : v } ) } membres = { membres } / > < / Champ >
< Champ label = "Sujet" > < input value = { rapport . theme } onChange = { ( e ) => setRapport ( { ... rapport , theme : e . target . value } ) } className = { INPUT } / > < / Champ >
< Champ label = "Annonces" > < textarea value = { rapport . annonces } onChange = { ( e ) => setRapport ( { ... rapport , annonces : e . target . value } ) } rows = { 3 } className = { ` ${ INPUT } resize-none ` } / > < / Champ >
< Champ label = "Note" > < textarea value = { rapport . note } onChange = { ( e ) => setRapport ( { ... rapport , note : e . target . value } ) } rows = { 2 } className = { ` ${ INPUT } resize-none ` } / > < / Champ >
< button onClick = { enregistrerRapport } disabled = { loading } className = "w-full p-3 bg-green-600 text-white rounded-xl text-sm font-bold disabled:opacity-40" > Enregistrer < / button >
< / Card >
) }
< / div >
) }
< / div >
) ) }
< / div >
2026-05-25 17:39:38 -04:00
< / div >
< / div >
) ;
}
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
function Resume ( { rencontre } ) {
return (
< div className = "text-sm text-gray-600 space-y-1" >
< p > Animateur : { rencontre . animateur _prenom || '—' } < / p >
{ rencontre . collecte && < p > Collecte : { rencontre . collecte . montant . toFixed ( 2 ) } $ ( { rencontre . collecte . statut } ) détenue par { rencontre . collecte . detenteur _prenom || '—' } < / p > }
{ rencontre . ventes _litterature . map ( ( v ) => < p key = { v . id } > Vente littérature : { v . titre } x { v . quantite } , { v . montant . toFixed ( 2 ) } $ par { v . vendu _par _prenom || '—' } < / p > ) }
{ rencontre . ventes _jetons . map ( ( v ) => < p key = { v . id } > Vente jeton : { v . type _jeton } x { v . quantite } , { v . montant . toFixed ( 2 ) } $ par { v . vendu _par _prenom || '—' } < / p > ) }
{ rencontre . jetons . map ( ( j ) => < p key = { j . id } > Jeton / gâteau : { j . membre _prenom || 'Anonyme' } — { j . type _jeton } { j . annees ? ` ( ${ j . annees } ans) ` : '' } < / p > ) }
< / div >
) ;
}
2026-05-25 17:39:38 -04:00
function Card ( { titre , children } ) {
return < div className = "bg-white rounded-2xl p-4 shadow-sm space-y-3" > < h2 className = "font-bold text-gray-800" > { titre } < / h2 > { children } < / div > ;
}
function Champ ( { label , children } ) {
return < label className = "block" > < span className = "text-xs text-gray-400 block mb-1" > { label } < / span > { children } < / label > ;
}
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
function MembreSelect ( { value , onChange , membres , empty = 'Sélectionner' } ) {
return < select value = { value } onChange = { ( e ) => onChange ( e . target . value ) } className = { INPUT } > < option value = "" > { empty } < / option > { membres . map ( ( m ) => < option key = { m . id } value = { m . id } > { m . prenom } < / option > ) } < / select > ;
}
2026-05-25 17:39:38 -04:00
function SelectDate ( { value , onChange , dates } ) {
Intégrer rencontres et assemblées pilotées par tuiles
Refond les pages Rencontres et Assemblées autour de tuiles ouvrables avec actions locales, PDF serveur, ventes, collectes, présences, décisions, postes et contributions.
Ajoute les invitations publiques d'assemblée en lecture seule avec lien expirant, l'adoption formelle du rapport du trésorier avec proposeur/secondeur, et bloque les contributions tant que ce rapport n'est pas adopté.
Uniformise la navigation et les entêtes, retire les modules redondants des contextes, ajoute la création de comptes membres par exécutif et les données démo reliées aux nouveaux processus.
Ce commit capture un lot fonctionnel important; une refactorisation ciblée du module Assemblées, puis Trésorerie/Gouvernance, est maintenant pertinente pour isoler les règles métier et faciliter les tests.
2026-05-31 09:02:02 -04:00
if ( ! dates . length ) return < div className = "rounded-xl bg-gray-50 p-3 text-sm text-gray-500" > Configurez le jour de réunion . < / div > ;
return < select value = { value } onChange = { ( e ) => onChange ( e . target . value ) } className = { INPUT } > { dates . map ( ( d ) => < option key = { d } value = { d } > { labelDateReunion ( d ) } < / option > ) } < / select > ;
2026-05-25 17:39:38 -04:00
}