Configure Maven repository for unionflow-server-api dependency

This commit is contained in:
dahoud
2025-12-10 01:12:54 +00:00
commit 2910809949
1173 changed files with 435718 additions and 0 deletions

View File

@@ -0,0 +1,595 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Aides - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-heart text-pink-500 mr-2"></i>
Gestion des Aides
</h3>
<p class="text-600 m-0">#{aideBean.totalAides} aides • #{aideBean.montantDistribue} distribués • #{aideBean.budgetDisponible} disponible</p>
</div>
<h:form id="formActionsAides">
<div class="flex gap-2">
<p:commandButton value="Nouvelle aide"
icon="pi pi-plus"
styleClass="ui-button-success"
onclick="PF('dlgNouvelleAide').show();" />
<p:commandButton value="Campagne d'aide"
icon="pi pi-megaphone"
styleClass="ui-button-outlined ui-button-info"
action="#{aideBean.nouvelleCampagne}" />
<p:commandButton value="Budget & Critères"
icon="pi pi-cog"
styleClass="ui-button-outlined ui-button-secondary"
action="#{aideBean.gestionBudget}" />
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Statistiques -->
<div class="grid">
<div class="col-12 md:col-3">
<div class="card bg-pink-100 border-left-3 border-pink-500">
<div class="flex justify-content-between">
<div>
<div class="text-pink-900 font-bold text-2xl">#{aideBean.aidesActives}</div>
<div class="text-pink-700">Aides Actives</div>
</div>
<div class="bg-pink-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-heart text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-green-100 border-left-3 border-green-500">
<div class="flex justify-content-between">
<div>
<div class="text-green-900 font-bold text-2xl">#{aideBean.montantDistribue}</div>
<div class="text-green-700">Montant Distribué</div>
</div>
<div class="bg-green-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-dollar text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-blue-100 border-left-3 border-blue-500">
<div class="flex justify-content-between">
<div>
<div class="text-blue-900 font-bold text-2xl">#{aideBean.beneficiaires}</div>
<div class="text-blue-700">Bénéficiaires</div>
</div>
<div class="bg-blue-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-users text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-orange-100 border-left-3 border-orange-500">
<div class="flex justify-content-between">
<div>
<div class="text-orange-900 font-bold text-2xl">#{aideBean.enAttente}</div>
<div class="text-orange-700">En Attente</div>
</div>
<div class="bg-orange-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-clock text-xl"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Budget et critères -->
<div class="grid">
<div class="col-12 md:col-8">
<div class="card">
<h5>Budget des Aides</h5>
<div class="grid">
<div class="col-12 md:col-4">
<div class="text-center p-3 surface-50 border-round">
<div class="text-2xl font-bold text-primary mb-2">#{aideBean.budgetTotal}</div>
<div class="text-600">Budget Total</div>
</div>
</div>
<div class="col-12 md:col-4">
<div class="text-center p-3 surface-50 border-round">
<div class="text-2xl font-bold text-green-500 mb-2">#{aideBean.budgetUtilise}</div>
<div class="text-600">Utilisé</div>
</div>
</div>
<div class="col-12 md:col-4">
<div class="text-center p-3 surface-50 border-round">
<div class="text-2xl font-bold text-blue-500 mb-2">#{aideBean.budgetDisponible}</div>
<div class="text-600">Disponible</div>
</div>
</div>
</div>
<p:progressBar value="#{aideBean.tauxUtilisationBudget}"
labelTemplate="#{aideBean.tauxUtilisationBudget}% du budget utilisé"
styleClass="mt-3" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Prochaines Échéances</h5>
<ui:repeat value="#{aideBean.prochainesEcheances}" var="aide" varStatus="status">
<div class="flex align-items-center justify-content-between p-2 mb-2 border-round"
style="background: var(--surface-50);">
<div>
<div class="font-medium text-sm">#{aide.beneficiaire}</div>
<small class="text-600">#{aide.typeAide}</small>
</div>
<div class="text-right">
<div class="font-bold text-sm">#{aide.prochainVersement}</div>
<small class="text-orange-500">#{aide.dateEcheance}</small>
</div>
</div>
</ui:repeat>
</div>
</div>
</div>
<!-- Graphiques -->
<div class="grid">
<div class="col-12 md:col-8">
<div class="card">
<h5>Évolution des Aides (12 derniers mois)</h5>
<div class="grid">
<div class="col-2">
<div class="text-center p-2">
<div class="text-sm font-medium text-blue-500">15</div>
<div class="text-xs text-600">Jan</div>
</div>
</div>
<div class="col-2">
<div class="text-center p-2">
<div class="text-sm font-medium text-green-500">22</div>
<div class="text-xs text-600">Fév</div>
</div>
</div>
<div class="col-2">
<div class="text-center p-2">
<div class="text-sm font-medium text-purple-500">18</div>
<div class="text-xs text-600">Mar</div>
</div>
</div>
<div class="col-2">
<div class="text-center p-2">
<div class="text-sm font-medium text-orange-500">25</div>
<div class="text-xs text-600">Avr</div>
</div>
</div>
<div class="col-2">
<div class="text-center p-2">
<div class="text-sm font-medium text-red-500">12</div>
<div class="text-xs text-600">Mai</div>
</div>
</div>
<div class="col-2">
<div class="text-center p-2">
<div class="text-sm font-medium text-cyan-500">28</div>
<div class="text-xs text-600">Juin</div>
</div>
</div>
</div>
<div class="surface-50 p-3 border-round mt-3 text-center">
<div class="text-2xl font-bold text-primary">235</div>
<div class="text-600">Total aides accordées cette année</div>
</div>
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Répartition par Type</h5>
<div class="grid">
<div class="col-12">
<div class="flex align-items-center justify-content-between p-2 surface-50 border-round mb-2">
<span class="text-600">🏥 Médicale</span>
<span class="font-bold text-blue-500">45%</span>
</div>
</div>
<div class="col-12">
<div class="flex align-items-center justify-content-between p-2 surface-50 border-round mb-2">
<span class="text-600">👥 Sociale</span>
<span class="font-bold text-green-500">30%</span>
</div>
</div>
<div class="col-12">
<div class="flex align-items-center justify-content-between p-2 surface-50 border-round mb-2">
<span class="text-600">🎓 Scolaire</span>
<span class="font-bold text-purple-500">15%</span>
</div>
</div>
<div class="col-12">
<div class="flex align-items-center justify-content-between p-2 surface-50 border-round mb-2">
<span class="text-600">🚨 Urgence</span>
<span class="font-bold text-red-500">10%</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Liste des aides -->
<div class="card">
<h:form id="formAides">
<h5>Gestion des Aides</h5>
<!-- Filtres -->
<p:toolbar>
<p:toolbarGroup>
<div class="flex align-items-center gap-2">
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<p:inputText placeholder="Rechercher..."
value="#{aideBean.searchFilter}">
<p:ajax event="keyup" update="dtAides" />
</p:inputText>
</span>
<p:selectOneMenu value="#{aideBean.statutFilter}">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="Active" itemValue="ACTIVE" />
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
<f:selectItem itemLabel="Suspendue" itemValue="SUSPENDUE" />
<f:selectItem itemLabel="Terminée" itemValue="TERMINEE" />
<f:selectItem itemLabel="Annulée" itemValue="ANNULEE" />
<p:ajax update="dtAides" />
</p:selectOneMenu>
<p:selectOneMenu value="#{aideBean.typeFilter}">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Aide médicale" itemValue="MEDICALE" />
<f:selectItem itemLabel="Aide funéraire" itemValue="FUNERAIRE" />
<f:selectItem itemLabel="Aide sociale" itemValue="SOCIALE" />
<f:selectItem itemLabel="Aide scolaire" itemValue="SCOLAIRE" />
<f:selectItem itemLabel="Aide d'urgence" itemValue="URGENCE" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
<p:ajax update="dtAides" />
</p:selectOneMenu>
<p:selectOneMenu value="#{aideBean.frequenceFilter}">
<f:selectItem itemLabel="Toutes fréquences" itemValue="" />
<f:selectItem itemLabel="Ponctuelle" itemValue="PONCTUELLE" />
<f:selectItem itemLabel="Mensuelle" itemValue="MENSUELLE" />
<f:selectItem itemLabel="Trimestrielle" itemValue="TRIMESTRIELLE" />
<f:selectItem itemLabel="Annuelle" itemValue="ANNUELLE" />
<p:ajax update="dtAides" />
</p:selectOneMenu>
</div>
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:commandButton value="Versements groupés"
icon="pi pi-send"
styleClass="ui-button-outlined ui-button-success mr-2"
action="#{aideBean.versementsGroupes}" />
<p:commandButton icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary"
action="#{aideBean.actualiser}"
update="@form"
title="Actualiser" />
</p:toolbarGroup>
</p:toolbar>
<!-- DataTable -->
<p:dataTable id="dtAides"
var="aide"
value="#{aideBean.aides}"
paginator="true"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,25,50"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
selection="#{aideBean.selectedAides}"
rowKey="#{aide.id}"
selectionMode="multiple"
styleClass="mt-3">
<p:column selectionMode="multiple" style="width:50px" />
<p:column headerText="Référence" sortBy="#{aide.reference}" style="width:120px">
<h:outputText value="#{aide.reference}" styleClass="font-mono font-bold" />
</p:column>
<p:column headerText="Bénéficiaire" sortBy="#{aide.nomBeneficiaire}">
<div class="flex align-items-center">
<div class="border-circle overflow-hidden mr-3"
style="width: 40px; height: 40px;">
<h:graphicImage value="#{aide.photoBeneficiaire}"
style="width: 100%; height: 100%; object-fit: cover;"
rendered="#{aide.photoBeneficiaire != null}" />
<div class="bg-primary text-white flex align-items-center justify-content-center w-full h-full"
rendered="#{aide.photoBeneficiaire == null}">
<span style="font-size: 0.9rem;">#{aide.initialesBeneficiaire}</span>
</div>
</div>
<div>
<div class="font-medium text-900">#{aide.nomCompletBeneficiaire}</div>
<div class="text-600 text-sm">
<span>#{aide.numeroMembre}</span>
<span class="mx-2"></span>
<span>#{aide.telephoneBeneficiaire}</span>
</div>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{aide.type}" style="width:140px">
<div class="flex align-items-center">
<div class="border-round p-2 mr-2 #{aide.typeColorClass}">
<i class="pi #{aide.typeIcon} text-white text-sm"></i>
</div>
<span>#{aide.type}</span>
</div>
</p:column>
<p:column headerText="Motif" sortBy="#{aide.motif}">
<h:outputText value="#{aide.motif}" />
</p:column>
<p:column headerText="Montant" sortBy="#{aide.montant}" style="width:120px">
<div class="text-center">
<div class="font-bold text-green-500">#{aide.montantTotal}</div>
<small class="text-600">#{aide.frequence}</small>
</div>
</p:column>
<p:column headerText="Versé" sortBy="#{aide.montantVerse}" style="width:120px">
<div class="text-center">
<div class="font-bold text-blue-500">#{aide.montantVerse}</div>
<p:progressBar value="#{aide.pourcentageVerse}"
labelTemplate=""
styleClass="h-1rem mt-1" />
</div>
</p:column>
<p:column headerText="Statut" sortBy="#{aide.statut}" style="width:120px">
<p:tag value="#{aide.statut}"
severity="#{aide.statutSeverity}"
icon="pi #{aide.statutIcon}" />
</p:column>
<p:column headerText="Début" sortBy="#{aide.dateDebut}" style="width:100px">
<h:outputText value="#{aide.dateDebut}">
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
</h:outputText>
</p:column>
<p:column headerText="Fin prévue" sortBy="#{aide.dateFinPrevue}" style="width:100px">
<h:outputText value="#{aide.dateFinPrevue}"
styleClass="#{aide.finPrevueClass}">
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
</h:outputText>
</p:column>
<p:column headerText="Prochain versement" style="width:130px">
<div class="text-center" rendered="#{aide.prochainVersement != null}">
<div class="font-medium">#{aide.prochainVersementMontant}</div>
<small class="text-600">#{aide.prochainVersementDate}</small>
</div>
<span class="text-400" rendered="#{aide.prochainVersement == null}">-</span>
</p:column>
<p:column headerText="Actions" style="width:220px">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
action="#{aideBean.voirAide(aide)}"
title="Voir détails" />
<p:commandButton icon="pi pi-dollar"
styleClass="ui-button-rounded ui-button-text ui-button-success"
action="#{aideBean.effectuerVersement(aide)}"
title="Verser"
rendered="#{aide.statut == 'ACTIVE' and aide.prochainVersement != null}" />
<p:commandButton icon="pi pi-history"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
action="#{aideBean.voirHistorique(aide)}"
title="Historique" />
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-warning"
action="#{aideBean.modifierAide(aide)}"
title="Modifier" />
<p:commandButton icon="pi pi-pause"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
action="#{aideBean.suspendreAide(aide)}"
title="Suspendre"
rendered="#{aide.statut == 'ACTIVE'}" />
<p:commandButton icon="pi pi-play"
styleClass="ui-button-rounded ui-button-text ui-button-success"
action="#{aideBean.reactiverAide(aide)}"
title="Réactiver"
rendered="#{aide.statut == 'SUSPENDUE'}" />
<p:commandButton icon="pi pi-times"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
action="#{aideBean.annulerAide(aide)}"
onclick="return confirm('Êtes-vous sûr de vouloir annuler cette aide ?');"
title="Annuler"
rendered="#{aide.statut != 'TERMINEE' and aide.statut != 'ANNULEE'}" />
</div>
</p:column>
</p:dataTable>
<!-- Actions groupées -->
<div class="mt-3 flex justify-content-between align-items-center">
<div>
<span class="text-600">#{aideBean.selectedAides.size()} aide(s) sélectionnée(s)</span>
</div>
<div class="flex gap-2">
<p:commandButton value="Verser sélection"
icon="pi pi-send"
styleClass="ui-button-outlined ui-button-success"
action="#{aideBean.verserSelection}"
disabled="#{empty aideBean.selectedAides}" />
<p:commandButton value="Suspendre sélection"
icon="pi pi-pause"
styleClass="ui-button-outlined ui-button-warning"
action="#{aideBean.suspendreSelection}"
disabled="#{empty aideBean.selectedAides}" />
<p:commandButton value="Exporter sélection"
icon="pi pi-file-excel"
styleClass="ui-button-outlined ui-button-secondary"
action="#{aideBean.exporterSelection}"
disabled="#{empty aideBean.selectedAides}" />
</div>
</div>
</h:form>
</div>
<!-- Dialog Nouvelle Aide -->
<p:dialog header="Nouvelle Aide" widgetVar="dlgNouvelleAide" modal="true" width="800">
<h:form id="formNouvelleAide">
<div class="ui-fluid">
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="beneficiaireSelect" value="Bénéficiaire" />
<p:autoComplete id="beneficiaireSelect"
value="#{aideBean.membreBeneficiaire}"
completeMethod="#{aideBean.rechercherMembres}"
var="membre" itemLabel="#{membre.nomComplet}" itemValue="#{membre}"
converter="membreConverter"
placeholder="Rechercher un membre..."
required="true">
<p:column>
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-2"
style="width: 30px; height: 30px;">
<span style="font-size: 0.8rem;">#{membre.initiales}</span>
</div>
<div>
<div class="font-medium">#{membre.nomComplet}</div>
<small class="text-600">#{membre.numeroMembre}</small>
</div>
</div>
</p:column>
</p:autoComplete>
</div>
<div class="field">
<p:outputLabel for="typeAide" value="Type d'aide" />
<p:selectOneMenu id="typeAide" value="#{aideBean.nouvelleAide.type}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="🏥 Aide médicale" itemValue="MEDICALE" />
<f:selectItem itemLabel="⚰️ Aide funéraire" itemValue="FUNERAIRE" />
<f:selectItem itemLabel="👥 Aide sociale" itemValue="SOCIALE" />
<f:selectItem itemLabel="🎓 Aide scolaire" itemValue="SCOLAIRE" />
<f:selectItem itemLabel="🚨 Aide d'urgence" itemValue="URGENCE" />
<f:selectItem itemLabel="🔧 Autre" itemValue="AUTRE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="montantAide" value="Montant" />
<p:inputNumber id="montantAide" value="#{aideBean.nouvelleAide.montant}"
symbol=" FCFA" symbolPosition="s" required="true" />
</div>
<div class="field">
<p:outputLabel for="frequenceAide" value="Fréquence" />
<p:selectOneMenu id="frequenceAide" value="#{aideBean.nouvelleAide.frequence}">
<f:selectItem itemLabel="Ponctuelle" itemValue="PONCTUELLE" />
<f:selectItem itemLabel="Mensuelle" itemValue="MENSUELLE" />
<f:selectItem itemLabel="Trimestrielle" itemValue="TRIMESTRIELLE" />
<f:selectItem itemLabel="Annuelle" itemValue="ANNUELLE" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="motifAide" value="Motif" />
<p:inputText id="motifAide" value="#{aideBean.nouvelleAide.motif}"
required="true" placeholder="Raison de l'aide" />
</div>
<div class="field">
<p:outputLabel for="dateDebutAide" value="Date de début" />
<p:calendar id="dateDebutAide" value="#{aideBean.nouvelleAide.dateDebut}"
pattern="dd/MM/yyyy" showIcon="true" required="true" />
</div>
<div class="field">
<p:outputLabel for="dateFinAide" value="Date de fin (optionnelle)" />
<p:calendar id="dateFinAide" value="#{aideBean.nouvelleAide.dateFin}"
pattern="dd/MM/yyyy" showIcon="true" />
</div>
<div class="field">
<p:outputLabel for="modePaiementAide" value="Mode de paiement" />
<p:selectOneMenu id="modePaiementAide" value="#{aideBean.nouvelleAide.modePaiement}">
<f:selectItem itemLabel="💰 Espèces" itemValue="ESPECES" />
<f:selectItem itemLabel="📱 Wave Money" itemValue="WAVE" />
<f:selectItem itemLabel="🏦 Virement bancaire" itemValue="VIREMENT" />
<f:selectItem itemLabel="💳 Chèque" itemValue="CHEQUE" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12">
<div class="field">
<p:outputLabel for="descriptionAide" value="Description détaillée" />
<p:inputTextarea id="descriptionAide" value="#{aideBean.nouvelleAide.description}"
rows="3" placeholder="Détails sur la situation et l'aide accordée..." />
</div>
<div class="field">
<p:selectBooleanCheckbox id="versementImmediat" value="#{aideBean.versementImmediat}" />
<p:outputLabel for="versementImmediat" value=" Effectuer le premier versement immédiatement" />
</div>
<div class="field">
<p:outputLabel for="justificatifs" value="Justificatifs" />
<p:fileUpload id="justificatifs" mode="advanced"
multiple="true" dragDropSupport="true"
uploadLabel="Télécharger" cancelLabel="Annuler" chooseLabel="Sélectionner"
sizeLimit="5000000" fileLimit="10" />
</div>
</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Créer l'aide" icon="pi pi-check"
styleClass="ui-button-success"
action="#{aideBean.creerAide}"
update="@form :formAides"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleAide').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgNouvelleAide').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">UnionFlow - Administration Audit</ui:define>
<ui:define name="content">
<div class="grid">
<div class="col-12">
<div class="card">
<h2>Administration - Audit</h2>
<p>Page d'administration en cours de développement...</p>
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
</div>
</div>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,460 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Journal d'Audit - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<ui:include src="/templates/components/layout/page-header.xhtml">
<ui:param name="icon" value="pi pi-history text-indigo-500" />
<ui:param name="title" value="Journal d'Audit" />
<ui:param name="description" value="Traçabilité complète des actions et modifications système" />
<ui:define name="actions">
<h:form id="formActions">
<div class="flex gap-2">
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Exporter" />
<ui:param name="icon" value="pi pi-download" />
<ui:param name="onclick" value="PF('exportDialog').show(); return false;" />
<ui:param name="outlined" value="true" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-refresh" />
<ui:param name="action" value="#{auditBean.actualiser}" />
<ui:param name="update" value=":formFiltres :formTableau:tableauAudit" />
<ui:param name="title" value="Actualiser" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</div>
</h:form>
</ui:define>
</ui:include>
<!-- Statistiques -->
<div class="grid">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Événements Totaux" />
<ui:param name="value" value="#{auditBean.totalEvenements}" />
<ui:param name="icon" value="pi-history" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Connexions Réussies" />
<ui:param name="value" value="#{auditBean.connexionsReussies}" />
<ui:param name="icon" value="pi-check-circle" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Tentatives Échouées" />
<ui:param name="value" value="#{auditBean.tentativesEchouees}" />
<ui:param name="icon" value="pi-times-circle" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Alertes Sécurité" />
<ui:param name="value" value="#{auditBean.alertesSecurite}" />
<ui:param name="icon" value="pi-exclamation-triangle" />
<ui:param name="iconColor" value="red-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
</div>
<!-- Filtres -->
<div class="card">
<h:form id="formFiltres">
<h5>Filtres de Recherche</h5>
<div class="grid">
<div class="col-12 md:col-3">
<ui:include src="/templates/components/forms/form-field-calendar.xhtml">
<ui:param name="id" value="dateDebut" />
<ui:param name="label" value="Date Début" />
<ui:param name="value" value="#{auditBean.dateDebut}" />
<ui:param name="update" value=":formTableau:tableauAudit" />
</ui:include>
</div>
<div class="col-12 md:col-3">
<ui:include src="/templates/components/forms/form-field-calendar.xhtml">
<ui:param name="id" value="dateFin" />
<ui:param name="label" value="Date Fin" />
<ui:param name="value" value="#{auditBean.dateFin}" />
<ui:param name="update" value=":formTableau:tableauAudit" />
</ui:include>
</div>
<div class="col-12 md:col-3">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="typeAction" />
<ui:param name="label" value="Type d'Action" />
<ui:param name="value" value="#{auditBean.typeAction}" />
<ui:param name="update" value=":formTableau:tableauAudit" />
<ui:define name="items">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Connexion" itemValue="CONNEXION" />
<f:selectItem itemLabel="Déconnexion" itemValue="DECONNEXION" />
<f:selectItem itemLabel="Création" itemValue="CREATION" />
<f:selectItem itemLabel="Modification" itemValue="MODIFICATION" />
<f:selectItem itemLabel="Suppression" itemValue="SUPPRESSION" />
<f:selectItem itemLabel="Consultation" itemValue="CONSULTATION" />
<f:selectItem itemLabel="Export" itemValue="EXPORT" />
<f:selectItem itemLabel="Configuration" itemValue="CONFIGURATION" />
</ui:define>
</ui:include>
</div>
<div class="col-12 md:col-3">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="severite" />
<ui:param name="label" value="Sévérité" />
<ui:param name="value" value="#{auditBean.severite}" />
<ui:param name="update" value=":formTableau:tableauAudit" />
<ui:define name="items">
<f:selectItem itemLabel="Toutes" itemValue="" />
<f:selectItem itemLabel="Info" itemValue="INFO" />
<f:selectItem itemLabel="Succès" itemValue="SUCCESS" />
<f:selectItem itemLabel="Avertissement" itemValue="WARNING" />
<f:selectItem itemLabel="Erreur" itemValue="ERROR" />
<f:selectItem itemLabel="Critique" itemValue="CRITICAL" />
</ui:define>
</ui:include>
</div>
<div class="col-12 md:col-3">
<ui:include src="/templates/components/forms/form-field-search-text.xhtml">
<ui:param name="id" value="utilisateur" />
<ui:param name="label" value="Utilisateur" />
<ui:param name="value" value="#{auditBean.utilisateur}" />
<ui:param name="placeholder" value="Nom ou email..." />
<ui:param name="update" value=":formTableau:tableauAudit" />
</ui:include>
</div>
<div class="col-12 md:col-3">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="module" />
<ui:param name="label" value="Module" />
<ui:param name="value" value="#{auditBean.module}" />
<ui:param name="update" value=":formTableau:tableauAudit" />
<ui:define name="items">
<f:selectItem itemLabel="Tous les modules" itemValue="" />
<f:selectItem itemLabel="Authentification" itemValue="AUTH" />
<f:selectItem itemLabel="Membres" itemValue="MEMBRES" />
<f:selectItem itemLabel="Cotisations" itemValue="COTISATIONS" />
<f:selectItem itemLabel="Événements" itemValue="EVENTS" />
<f:selectItem itemLabel="Documents" itemValue="DOCUMENTS" />
<f:selectItem itemLabel="Configuration" itemValue="CONFIG" />
<f:selectItem itemLabel="Rapports" itemValue="RAPPORTS" />
</ui:define>
</ui:include>
</div>
<div class="col-12 md:col-3">
<ui:include src="/templates/components/forms/form-field-search-text.xhtml">
<ui:param name="id" value="ipAddress" />
<ui:param name="label" value="Adresse IP" />
<ui:param name="value" value="#{auditBean.ipAddress}" />
<ui:param name="placeholder" value="Ex: 192.168.1.1" />
<ui:param name="update" value=":formTableau:tableauAudit" />
</ui:include>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel />
<div class="flex gap-2">
<ui:include src="/templates/components/buttons/button-primary.xhtml">
<ui:param name="value" value="Rechercher" />
<ui:param name="icon" value="pi pi-search" />
<ui:param name="action" value="#{auditBean.rechercher}" />
<ui:param name="update" value=":formTableau:tableauAudit" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Réinitialiser" />
<ui:param name="icon" value="pi pi-refresh" />
<ui:param name="action" value="#{auditBean.reinitialiserFiltres}" />
<ui:param name="update" value=":formFiltres :formTableau:tableauAudit" />
<ui:param name="outlined" value="true" />
</ui:include>
</div>
</div>
</div>
</div>
</h:form>
</div>
<!-- Tableau du journal d'audit -->
<div class="card">
<h:form id="formTableau">
<h5>Journal d'Audit</h5>
<p:dataTable id="tableauAudit"
value="#{auditBean.evenementsFiltres}"
var="log"
paginator="true"
rows="20"
rowsPerPageTemplate="10,20,50,100"
emptyMessage="Aucun événement trouvé"
styleClass="p-datatable-sm p-datatable-striped"
sortMode="multiple"
rowKey="#{log.id}">
<p:column headerText="Date/Heure" sortBy="#{log.dateHeure}" style="width: 12%">
<div>
<div class="font-semibold">#{log.dateFormatee}</div>
<div class="text-sm text-600">#{log.heureFormatee}</div>
</div>
</p:column>
<p:column headerText="Sévérité" sortBy="#{log.severite}" style="width: 8%" styleClass="text-center">
<p:tag value="#{log.severiteLibelle}"
severity="#{log.severiteSeverity}"
icon="#{log.severiteIcon}" />
</p:column>
<p:column headerText="Utilisateur" sortBy="#{log.utilisateur}" style="width: 15%">
<div class="flex align-items-center gap-2">
<i class="pi pi-user text-blue-500"></i>
<div>
<div class="font-semibold">#{log.utilisateur}</div>
<div class="text-sm text-600">#{log.role}</div>
</div>
</div>
</p:column>
<p:column headerText="Action" sortBy="#{log.typeAction}" style="width: 12%">
<div class="flex align-items-center gap-2">
<i class="#{log.actionIcon} text-lg"></i>
<span class="font-semibold">#{log.actionLibelle}</span>
</div>
</p:column>
<p:column headerText="Module" sortBy="#{log.module}" style="width: 10%">
<p:tag value="#{log.moduleLibelle}"
severity="info" />
</p:column>
<p:column headerText="Description" style="width: 25%">
<div>#{log.description}</div>
<div class="text-sm text-600 mt-1" rendered="#{not empty log.details}">
<i class="pi pi-info-circle"></i> #{log.details}
</div>
</p:column>
<p:column headerText="IP/Appareil" style="width: 12%">
<div class="text-sm">
<i class="pi pi-globe"></i> #{log.ipAddress}
</div>
<div class="text-xs text-600">#{log.userAgentCourt}</div>
</p:column>
<p:column headerText="Actions" style="width: 6%" styleClass="text-center">
<div class="flex justify-content-center gap-1">
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-eye" />
<ui:param name="action" value="#{auditBean.selectionnerLog(log)}" />
<ui:param name="update" value=":formDetails:dlgDetails" />
<ui:param name="oncomplete" value="PF('dlgDetails').show();" />
<ui:param name="title" value="Voir les détails" />
<ui:param name="styleClass" value="p-button-sm p-button-rounded" />
</ui:include>
</div>
</p:column>
</p:dataTable>
</h:form>
</div>
<!-- Dialog Détails -->
<h:form id="formDetails">
<p:dialog id="dlgDetails"
widgetVar="dlgDetails"
header="Détails de l'Événement"
modal="true"
resizable="false"
style="width: 90vw; max-width: 800px;">
<div class="grid" rendered="#{auditBean.evenementSelectionne != null}">
<div class="col-12">
<ui:include src="/templates/components/forms/form-section.xhtml">
<ui:define name="title">Informations Générales</ui:define>
<ui:define name="content">
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<label class="font-semibold">Date/Heure</label>
<div>#{auditBean.evenementSelectionne.dateHeureComplete}</div>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label class="font-semibold">Sévérité</label>
<div>
<p:tag value="#{auditBean.evenementSelectionne.severiteLibelle}"
severity="#{auditBean.evenementSelectionne.severiteSeverity}" />
</div>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label class="font-semibold">Utilisateur</label>
<div>#{auditBean.evenementSelectionne.utilisateur}</div>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label class="font-semibold">Rôle</label>
<div>#{auditBean.evenementSelectionne.role}</div>
</div>
</div>
</div>
</ui:define>
</ui:include>
</div>
<div class="col-12">
<ui:include src="/templates/components/forms/form-section.xhtml">
<ui:define name="title">Détails de l'Action</ui:define>
<ui:define name="content">
<div class="grid">
<div class="col-12">
<div class="field">
<label class="font-semibold">Description</label>
<div>#{auditBean.evenementSelectionne.description}</div>
</div>
</div>
<div class="col-12" rendered="#{not empty auditBean.evenementSelectionne.details}">
<div class="field">
<label class="font-semibold">Détails</label>
<div class="surface-50 p-3 border-round">#{auditBean.evenementSelectionne.details}</div>
</div>
</div>
<div class="col-12" rendered="#{not empty auditBean.evenementSelectionne.donneesAvant}">
<div class="field">
<label class="font-semibold">Données Avant</label>
<pre class="surface-200 border-round p-2 text-sm">#{auditBean.evenementSelectionne.donneesAvant}</pre>
</div>
</div>
<div class="col-12" rendered="#{not empty auditBean.evenementSelectionne.donneesApres}">
<div class="field">
<label class="font-semibold">Données Après</label>
<pre class="surface-200 border-round p-2 text-sm">#{auditBean.evenementSelectionne.donneesApres}</pre>
</div>
</div>
</div>
</ui:define>
</ui:include>
</div>
<div class="col-12">
<ui:include src="/templates/components/forms/form-section.xhtml">
<ui:define name="title">Informations Techniques</ui:define>
<ui:define name="content">
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<label class="font-semibold">Adresse IP</label>
<div>#{auditBean.evenementSelectionne.ipAddress}</div>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label class="font-semibold">Session ID</label>
<div class="text-sm">#{auditBean.evenementSelectionne.sessionId}</div>
</div>
</div>
<div class="col-12">
<div class="field">
<label class="font-semibold">User Agent</label>
<div class="text-sm">#{auditBean.evenementSelectionne.userAgent}</div>
</div>
</div>
</div>
</ui:define>
</ui:include>
</div>
</div>
<f:facet name="footer">
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Fermer" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="onclick" value="PF('dlgDetails').hide();" />
<ui:param name="outlined" value="true" />
</ui:include>
</f:facet>
</p:dialog>
</h:form>
<!-- Dialog Export -->
<h:form id="formExport">
<p:dialog id="exportDialog"
widgetVar="exportDialog"
header="Exporter le Journal d'Audit"
modal="true"
resizable="false"
style="width: 90vw; max-width: 500px;">
<div class="grid">
<div class="col-12">
<div class="field">
<p:outputLabel for="formatExport" value="Format d'Export" />
<p:selectOneRadio id="formatExport"
value="#{auditBean.formatExport}"
layout="grid"
columns="1">
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
<f:selectItem itemLabel="PDF" itemValue="PDF" />
<f:selectItem itemLabel="CSV" itemValue="CSV" />
<f:selectItem itemLabel="JSON" itemValue="JSON" />
</p:selectOneRadio>
</div>
</div>
<div class="col-12">
<div class="field">
<p:selectBooleanCheckbox id="inclureFiltres"
value="#{auditBean.inclureFiltresExport}"
itemLabel="Inclure uniquement les données filtrées" />
</div>
</div>
</div>
<f:facet name="footer">
<div class="flex justify-content-end gap-2">
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Annuler" />
<ui:param name="onclick" value="PF('exportDialog').hide();" />
<ui:param name="outlined" value="true" />
</ui:include>
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="Exporter" />
<ui:param name="icon" value="pi pi-download" />
<ui:param name="action" value="#{auditBean.exporter}" />
<ui:param name="update" value="none" />
</ui:include>
</div>
</f:facet>
</p:dialog>
</h:form>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">UnionFlow - Administration Backup</ui:define>
<ui:define name="content">
<div class="grid">
<div class="col-12">
<div class="card">
<h2>Administration - Backup</h2>
<p>Page d'administration en cours de développement...</p>
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
</div>
</div>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,725 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Cotisations - UnionFlow</ui:define>
<ui:define name="content">
<div class="ui-fluid">
<!-- En-tête principal avec disposition Freya stricte -->
<div class="card">
<div class="formgrid grid">
<div class="field col-12 lg:col-8">
<h2 class="text-primary font-bold mb-2">
<i class="pi pi-dollar mr-2"></i>
Gestion des Cotisations
</h2>
<p class="text-600 mt-0">
<span class="font-semibold">127 organisations</span>
<span class="font-semibold">#{cotisationsGestionBean.periodeActuelle}</span>
Recouvrement: <span class="font-semibold text-green-600">#{cotisationsGestionBean.tauxRecouvrement}%</span>
<span class="font-semibold">#{cotisationsGestionBean.totalMembresActifs}</span> membres actifs
</p>
</div>
<div class="field col-12 lg:col-4 text-right">
<h:form id="formActionsGlobales">
<p:commandButton icon="pi pi-megaphone"
title="Nouvelle Campagne"
styleClass="ui-button-success ui-button-sm mr-3"
onclick="PF('dlgNouvelleCampagne').show();" />
<p:commandButton icon="pi pi-send"
title="Relances groupées"
styleClass="ui-button-warning ui-button-outlined ui-button-sm mr-3"
action="#{cotisationsGestionBean.relancesGroupees}" />
<p:commandButton icon="pi pi-file-excel"
title="Export global"
styleClass="ui-button-info ui-button-outlined ui-button-sm"
action="#{cotisationsGestionBean.exporterTout}" />
</h:form>
</div>
</div>
</div>
<!-- KPIs Financiers avec grille Freya stricte -->
<div class="formgrid grid">
<!-- KPI 1: Montant Collecté -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Collecté ce mois" />
<ui:param name="value" value="#{cotisationsGestionBean.montantCollecte}" />
<ui:param name="icon" value="pi-check" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="growthValue" value="#{cotisationsGestionBean.progressionMensuelle}" />
<ui:param name="growthLabel" value="de l'objectif" />
<ui:param name="progressValue" value="#{cotisationsGestionBean.progressionMensuelle}" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3 xl:col-2" />
</ui:include>
<!-- KPI 2: Membres à jour -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Membres à jour" />
<ui:param name="value" value="#{cotisationsGestionBean.membresAJour}" />
<ui:param name="icon" value="pi-users" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="statusIcon" value="pi-circle-fill" />
<ui:param name="statusLabel" value="Conformes" />
<ui:param name="statusValue" value="#{cotisationsGestionBean.pourcentageMembresAJour}%" />
<ui:param name="progressValue" value="#{cotisationsGestionBean.pourcentageMembresAJour}" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3 xl:col-2" />
</ui:include>
<!-- KPI 3: En Attente -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="En attente" />
<ui:param name="value" value="#{cotisationsGestionBean.montantEnAttente}" />
<ui:param name="icon" value="pi-clock" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="statusIcon" value="pi-exclamation-triangle" />
<ui:param name="statusLabel" value="Cotisations" />
<ui:param name="statusValue" value="#{cotisationsGestionBean.nombreCotisationsEnAttente}" />
<ui:param name="noDataLabel" value="À traiter rapidement" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3 xl:col-2" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 4: Impayés -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Impayés" />
<ui:param name="value" value="#{cotisationsGestionBean.montantImpayes}" />
<ui:param name="icon" value="pi-exclamation-circle" />
<ui:param name="iconColor" value="red-600" />
<ui:param name="statusIcon" value="pi-arrow-down" />
<ui:param name="statusLabel" value="Retard moyen" />
<ui:param name="statusValue" value="#{cotisationsGestionBean.joursRetardMoyen}j" />
<ui:param name="noDataLabel" value="Action requise" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3 xl:col-2" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 5: Revenus 2024 -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Revenus 2024" />
<ui:param name="value" value="#{cotisationsGestionBean.revenus2024}" />
<ui:param name="icon" value="pi-chart-line" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="growthValue" value="#{cotisationsGestionBean.croissanceAnnuelle}" />
<ui:param name="growthLabel" value="Croissance annuelle" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3 xl:col-2" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 6: Wave Money -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Prélèvements Auto" />
<ui:param name="value" value="#{cotisationsGestionBean.prelevementsActifs}" />
<ui:param name="icon" value="pi-mobile" />
<ui:param name="iconColor" value="teal-600" />
<ui:param name="statusIcon" value="pi-sync" />
<ui:param name="statusLabel" value="Montant/mois" />
<ui:param name="statusValue" value="#{cotisationsGestionBean.montantPrelevementsPrevu} FCFA" />
<ui:param name="noDataLabel" value="Automatique" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3 xl:col-2" />
<ui:param name="showProgress" value="false" />
</ui:include>
</div>
<!-- Section Analytics avec disposition Freya -->
<div class="formgrid grid">
<!-- Top Organisations -->
<div class="field col-12 lg:col-8">
<div class="card">
<div class="flex align-items-center justify-content-between mb-3">
<h5 class="m-0">
<i class="pi pi-trophy text-yellow-500 mr-2"></i>
Top 5 Organisations Performantes
</h5>
<p:selectOneMenu value="#{cotisationsGestionBean.periodeGraphique}" styleClass="w-8rem">
<f:selectItem itemLabel="12 mois" itemValue="12M" />
<f:selectItem itemLabel="6 mois" itemValue="6M" />
<f:selectItem itemLabel="3 mois" itemValue="3M" />
<f:selectItem itemLabel="Ce mois" itemValue="1M" />
</p:selectOneMenu>
</div>
<p:dataTable value="#{cotisationsGestionBean.topOrganisations}" var="org"
styleClass="p-datatable-sm p-datatable-gridlines">
<p:column headerText="Organisation" style="width:40%">
<div class="flex align-items-center">
<div class="flex align-items-center justify-content-center bg-primary-100 border-round mr-2"
style="width: 2rem; height: 2rem;">
<i class="pi pi-building text-primary-600"></i>
</div>
<span class="font-semibold">#{org.nom}</span>
</div>
</p:column>
<p:column headerText="Taux" style="width:15%; text-align: center;">
<p:progressBar value="#{org.tauxRecouvrement}"
labelTemplate="#{org.tauxRecouvrement}%"
styleClass="h-1rem" />
</p:column>
<p:column headerText="Montant" style="width:20%; text-align: right;">
<span class="font-bold text-green-600">#{org.montantCollecte} FCFA</span>
</p:column>
<p:column headerText="Membres" style="width:25%; text-align: center;">
<p:tag value="#{org.nombreMembresAJour}/#{org.totalMembres}"
severity="info" styleClass="text-xs" />
</p:column>
</p:dataTable>
</div>
</div>
<!-- Répartition Paiements -->
<div class="field col-12 lg:col-4">
<div class="card">
<h5 class="mb-3">
<i class="pi pi-chart-pie text-blue-500 mr-2"></i>
Méthodes de Paiement
</h5>
<div class="surface-50 border-round-lg p-3 mb-2">
<div class="flex align-items-center justify-content-between mb-2">
<div class="flex align-items-center">
<i class="pi pi-mobile text-blue-500 mr-2"></i>
<span class="font-medium">Wave Money</span>
</div>
<span class="font-bold">#{cotisationsGestionBean.paiementsWave}%</span>
</div>
<p:progressBar value="#{cotisationsGestionBean.paiementsWave}"
showValue="false"
styleClass="h-05rem" />
</div>
<div class="surface-50 border-round-lg p-3 mb-2">
<div class="flex align-items-center justify-content-between mb-2">
<div class="flex align-items-center">
<i class="pi pi-building text-purple-500 mr-2"></i>
<span class="font-medium">Virement</span>
</div>
<span class="font-bold">#{cotisationsGestionBean.paiementsVirement}%</span>
</div>
<p:progressBar value="#{cotisationsGestionBean.paiementsVirement}"
showValue="false"
styleClass="h-05rem" />
</div>
<div class="surface-50 border-round-lg p-3">
<div class="flex align-items-center justify-content-between mb-2">
<div class="flex align-items-center">
<i class="pi pi-money-bill text-green-500 mr-2"></i>
<span class="font-medium">Espèces</span>
</div>
<span class="font-bold">#{cotisationsGestionBean.paiementsEspeces}%</span>
</div>
<p:progressBar value="#{cotisationsGestionBean.paiementsEspeces}"
showValue="false"
styleClass="h-05rem" />
</div>
</div>
</div>
</div>
<!-- Section Filtrage avec structure Freya -->
<div class="card">
<h:form id="formFiltres">
<div class="formgrid grid">
<!-- Filtres principaux -->
<div class="field col-12 md:col-6 lg:col-3">
<label for="filtreOrganisation" class="block text-900 font-medium mb-2">Organisation</label>
<p:selectOneMenu id="filtreOrganisation"
value="#{cotisationsGestionBean.filtres.organisation}"
filter="true" filterMatchMode="contains"
styleClass="w-full">
<f:selectItem itemLabel="Toutes les organisations" itemValue="" />
<f:selectItems value="#{cotisationsGestionBean.listeOrganisations}"
var="org"
itemLabel="#{org.nom}"
itemValue="#{org.id}" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6 lg:col-2">
<label for="filtrePeriode" class="block text-900 font-medium mb-2">Période</label>
<p:selectOneMenu id="filtrePeriode"
value="#{cotisationsGestionBean.filtres.periode}"
styleClass="w-full">
<f:selectItem itemLabel="Ce mois" itemValue="MOIS" />
<f:selectItem itemLabel="3 derniers mois" itemValue="TRIMESTRE" />
<f:selectItem itemLabel="6 derniers mois" itemValue="SEMESTRE" />
<f:selectItem itemLabel="Cette année" itemValue="ANNEE" />
<f:selectItem itemLabel="Toutes" itemValue="TOUTES" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6 lg:col-2">
<label for="filtreStatut" class="block text-900 font-medium mb-2">Statut</label>
<p:selectOneMenu id="filtreStatut"
value="#{cotisationsGestionBean.filtres.statut}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="Payées" itemValue="PAYE" />
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
<f:selectItem itemLabel="En retard" itemValue="EN_RETARD" />
<f:selectItem itemLabel="Annulées" itemValue="ANNULE" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6 lg:col-2">
<label for="filtreType" class="block text-900 font-medium mb-2">Type</label>
<p:selectOneMenu id="filtreType"
value="#{cotisationsGestionBean.filtres.type}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Mensuelle" itemValue="MENSUELLE" />
<f:selectItem itemLabel="Spéciale" itemValue="SPECIALE" />
<f:selectItem itemLabel="Adhésion" itemValue="ADHESION" />
<f:selectItem itemLabel="Événement" itemValue="EVENEMENT" />
</p:selectOneMenu>
</div>
<div class="field col-12 lg:col-3">
<label for="recherche" class="block text-900 font-medium mb-2">Recherche</label>
<span class="p-input-icon-left w-full">
<i class="pi pi-search"></i>
<p:inputText id="recherche"
value="#{cotisationsGestionBean.filtres.recherche}"
placeholder="Membre, numéro, référence..."
styleClass="w-full">
<p:ajax event="keyup" delay="300"
update=":formTableCotisations:dtCotisations"
listener="#{cotisationsGestionBean.appliquerFiltres}" />
</p:inputText>
</span>
</div>
</div>
<!-- Filtres avancés -->
<p:panel header="Filtres Avancés (Business Intelligence)"
toggleable="true"
collapsed="true"
styleClass="mt-3">
<div class="formgrid grid mt-3">
<div class="field col-12 md:col-6 lg:col-3">
<label for="filtreMontantMin" class="block text-900 font-medium mb-2">Montant minimum</label>
<p:inputNumber id="filtreMontantMin"
value="#{cotisationsGestionBean.filtres.montantMin}"
suffix=" FCFA"
styleClass="w-full" />
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="filtreMontantMax" class="block text-900 font-medium mb-2">Montant maximum</label>
<p:inputNumber id="filtreMontantMax"
value="#{cotisationsGestionBean.filtres.montantMax}"
suffix=" FCFA"
styleClass="w-full" />
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="filtreRetardJours" class="block text-900 font-medium mb-2">Retard (jours)</label>
<p:selectOneMenu id="filtreRetardJours"
value="#{cotisationsGestionBean.filtres.retardJours}"
styleClass="w-full">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="0-7 jours" itemValue="7" />
<f:selectItem itemLabel="8-30 jours" itemValue="30" />
<f:selectItem itemLabel="31-60 jours" itemValue="60" />
<f:selectItem itemLabel="Plus de 60 jours" itemValue="60+" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="filtreModePaiement" class="block text-900 font-medium mb-2">Mode de paiement</label>
<p:selectOneMenu id="filtreModePaiement"
value="#{cotisationsGestionBean.filtres.modePaiement}"
styleClass="w-full">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="Wave Money" itemValue="WAVE" />
<f:selectItem itemLabel="Orange Money" itemValue="ORANGE" />
<f:selectItem itemLabel="Virement" itemValue="VIREMENT" />
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
</p:selectOneMenu>
</div>
</div>
<div class="flex justify-content-end mt-3">
<p:commandButton value="Appliquer"
icon="pi pi-check"
styleClass="ui-button-primary ui-button-sm mr-2"
action="#{cotisationsGestionBean.appliquerFiltres}"
update="@form :formTableCotisations:dtCotisations" />
<p:commandButton value="Réinitialiser"
icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary ui-button-sm"
action="#{cotisationsGestionBean.reinitialiserFiltres}"
update="@form :formTableCotisations:dtCotisations" />
</div>
</p:panel>
</h:form>
</div>
<!-- Table des Cotisations avec structure Freya -->
<div class="card">
<h:form id="formTableCotisations">
<div class="flex align-items-center justify-content-between mb-3">
<h5 class="m-0">
<i class="pi pi-list text-primary mr-2"></i>
Liste des Cotisations
</h5>
<div class="flex gap-3 align-items-center">
<p:commandButton value="Actions groupées"
icon="pi pi-bars"
styleClass="ui-button-warning ui-button-sm"
onclick="PF('dlgActionsGroupees').show();"
disabled="#{empty cotisationsGestionBean.cotisationsSelectionnees}" />
<p:commandButton value="Export Excel"
icon="pi pi-file-excel"
styleClass="ui-button-success ui-button-outlined ui-button-sm"
action="#{cotisationsGestionBean.exporterExcel}" />
</div>
</div>
<p:dataTable id="dtCotisations"
var="cotisation"
value="#{cotisationsGestionBean.cotisationsFiltrees}"
selection="#{cotisationsGestionBean.cotisationsSelectionnees}"
rowKey="#{cotisation.id}"
paginator="true"
rows="25"
paginatorPosition="bottom"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,25,50,100"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords} cotisations"
styleClass="p-datatable-sm p-datatable-gridlines p-datatable-striped"
emptyMessage="Aucune cotisation trouvée">
<p:column selectionMode="multiple" style="width:3rem" exportable="false"/>
<p:column headerText="Organisation" sortBy="#{cotisation.nomOrganisation}" filterBy="#{cotisation.nomOrganisation}">
<div class="flex align-items-center">
<i class="pi #{cotisation.iconeOrganisation} text-primary mr-2"></i>
<div>
<div class="font-semibold">#{cotisation.nomOrganisation}</div>
<div class="text-500 text-xs">#{cotisation.regionOrganisation}</div>
</div>
</div>
</p:column>
<p:column headerText="Membre" sortBy="#{cotisation.nomCompletMembre}" filterBy="#{cotisation.nomCompletMembre}">
<div class="flex align-items-center">
<div class="flex align-items-center justify-content-center bg-primary-100 border-circle mr-2"
style="width: 2rem; height: 2rem;">
<span class="text-primary-700 font-semibold text-sm">#{cotisation.initialesMembre}</span>
</div>
<div>
<div class="font-medium">#{cotisation.nomCompletMembre}</div>
<div class="text-500 text-xs">#{cotisation.numeroMembre} • #{cotisation.typeMembre}</div>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{cotisation.type}" filterBy="#{cotisation.type}" style="width:10rem">
<p:tag value="#{cotisation.typeLibelle}"
severity="#{cotisation.typeSeverity}"
icon="pi #{cotisation.typeIcon}"
styleClass="text-xs" />
</p:column>
<p:column headerText="Période" sortBy="#{cotisation.periode}" style="width:10rem">
<div>
<div class="font-medium">#{cotisation.periode}</div>
<div class="text-500 text-xs">#{cotisation.annee}</div>
</div>
</p:column>
<p:column headerText="Montant" sortBy="#{cotisation.montant}" style="width:8rem; text-align:right">
<span class="font-bold text-green-600">#{cotisation.montantFormatte} FCFA</span>
</p:column>
<p:column headerText="Statut" sortBy="#{cotisation.statut}" filterBy="#{cotisation.statut}" style="width:8rem">
<p:tag value="#{cotisation.statutLibelle}"
severity="#{cotisation.statutSeverity}"
icon="pi #{cotisation.statutIcon}"
styleClass="text-xs w-full" />
</p:column>
<p:column headerText="Échéance" sortBy="#{cotisation.dateEcheance}" style="width:8rem">
<div>
<div class="text-xs">#{cotisation.dateEcheanceFormattee}</div>
<div class="text-xs #{cotisation.retardCouleur} font-semibold">#{cotisation.retardTexte}</div>
</div>
</p:column>
<p:column headerText="Paiement" style="width:10rem">
<div rendered="#{cotisation.datePaiement != null}">
<div class="text-xs">#{cotisation.datePaiementFormattee}</div>
<div class="flex align-items-center text-xs text-500">
<i class="pi #{cotisation.modePaiementIcon} mr-1"></i>
#{cotisation.modePaiementLibelle}
</div>
</div>
<span class="text-400 text-xs" rendered="#{cotisation.datePaiement == null}">Non payé</span>
</p:column>
<p:column headerText="Actions" style="width:8rem" exportable="false">
<div class="flex gap-1">
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success ui-button-sm"
title="Enregistrer paiement"
action="#{cotisationsGestionBean.enregistrerPaiement(cotisation)}"
rendered="#{cotisation.statut != 'PAYE'}" />
<p:commandButton icon="pi pi-file-pdf"
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
title="Générer reçu"
action="#{cotisationsGestionBean.genererRecu(cotisation)}"
rendered="#{cotisation.statut == 'PAYE'}" />
<p:commandButton icon="pi pi-send"
styleClass="ui-button-rounded ui-button-text ui-button-warning ui-button-sm"
title="Envoyer rappel"
action="#{cotisationsGestionBean.envoyerRappel(cotisation)}"
rendered="#{cotisation.statut == 'EN_RETARD'}" />
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
title="Voir détails"
action="#{cotisationsGestionBean.voirDetails(cotisation)}" />
</div>
</p:column>
</p:dataTable>
<!-- Résumé sélection -->
<div class="surface-100 border-round-lg p-3 mt-3" rendered="#{not empty cotisationsGestionBean.cotisationsSelectionnees}">
<div class="flex align-items-center justify-content-between">
<span class="font-medium">
<i class="pi pi-info-circle text-blue-500 mr-2"></i>
#{cotisationsGestionBean.cotisationsSelectionnees.size()} cotisation(s) sélectionnée(s)
</span>
<span class="font-bold text-green-600">
Montant total: #{cotisationsGestionBean.montantTotalSelectionne}
</span>
</div>
</div>
</h:form>
</div>
<!-- Section Wave Money avec structure Freya -->
<div class="formgrid grid">
<div class="field col-12 lg:col-6">
<div class="card">
<h5 class="mb-3">
<i class="pi pi-mobile text-teal-500 mr-2"></i>
Intégration Wave Money
</h5>
<div class="surface-50 border-round-lg p-3 mb-3">
<div class="formgrid grid">
<div class="field col-6">
<div class="text-500 text-sm mb-1">Membres actifs</div>
<div class="text-900 font-bold text-xl">#{cotisationsGestionBean.membresPrelevementActif}</div>
</div>
<div class="field col-6">
<div class="text-500 text-sm mb-1">Montant mensuel</div>
<div class="text-900 font-bold text-xl">#{cotisationsGestionBean.montantPrelevementMensuel}</div>
</div>
<div class="field col-12">
<div class="text-500 text-sm mb-1">Prochain prélèvement</div>
<div class="text-900 font-bold">#{cotisationsGestionBean.prochainPrelevement}</div>
</div>
</div>
</div>
<h:form id="formWaveMoney">
<div class="flex flex-wrap gap-2">
<p:commandButton value="Lancer prélèvements"
icon="pi pi-play"
styleClass="ui-button-success ui-button-sm"
action="#{cotisationsGestionBean.lancerPrelevements}" />
<p:commandButton value="Tester API"
icon="pi pi-check-circle"
styleClass="ui-button-info ui-button-outlined ui-button-sm"
action="#{cotisationsGestionBean.testerAPIWave}" />
<p:commandButton value="Historique"
icon="pi pi-history"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
action="#{cotisationsGestionBean.voirHistoriquePrelevements}" />
</div>
</h:form>
</div>
</div>
<div class="field col-12 lg:col-6">
<div class="card">
<h5 class="mb-3">
<i class="pi pi-bolt text-orange-500 mr-2"></i>
Actions Rapides
</h5>
<h:form id="formActionsRapides">
<div class="formgrid grid">
<div class="field col-12 md:col-6">
<p:commandButton value="Rapport mensuel"
icon="pi pi-chart-bar"
styleClass="ui-button-primary ui-button-outlined ui-button-sm w-full mb-2"
action="#{cotisationsGestionBean.genererRapportMensuel}" />
</div>
<div class="field col-12 md:col-6">
<p:commandButton value="Relances auto"
icon="pi pi-sync"
styleClass="ui-button-warning ui-button-outlined ui-button-sm w-full mb-2"
action="#{cotisationsGestionBean.configurerRelancesAuto}" />
</div>
<div class="field col-12 md:col-6">
<p:commandButton value="Types cotisations"
icon="pi pi-tags"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full mb-2"
action="#{cotisationsGestionBean.gererTypesCotisations}" />
</div>
<div class="field col-12 md:col-6">
<p:commandButton value="Tableau de bord"
icon="pi pi-desktop"
styleClass="ui-button-success ui-button-outlined ui-button-sm w-full mb-2"
action="#{cotisationsGestionBean.tableauDeBord}" />
</div>
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Dialogs avec structure Freya -->
<!-- Dialog Nouvelle Campagne -->
<p:dialog header="Créer une Nouvelle Campagne de Cotisation"
widgetVar="dlgNouvelleCampagne"
modal="true"
width="600"
height="auto"
resizable="false">
<h:form id="formNouvelleCampagne">
<div class="ui-fluid formgrid grid">
<div class="field col-12">
<label for="nomCampagne" class="block text-900 font-medium mb-2">Nom de la campagne *</label>
<p:inputText id="nomCampagne"
value="#{cotisationsGestionBean.nouvelleCampagne.nom}"
required="true"
placeholder="Ex: Cotisation Janvier 2025" />
</div>
<div class="field col-12 md:col-6">
<label for="typeCampagne" class="block text-900 font-medium mb-2">Type *</label>
<p:selectOneMenu id="typeCampagne"
value="#{cotisationsGestionBean.nouvelleCampagne.type}"
required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Mensuelle" itemValue="MENSUELLE" />
<f:selectItem itemLabel="Spéciale" itemValue="SPECIALE" />
<f:selectItem itemLabel="Événement" itemValue="EVENEMENT" />
<f:selectItem itemLabel="Adhésion" itemValue="ADHESION" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<label for="montantCampagne" class="block text-900 font-medium mb-2">Montant (FCFA) *</label>
<p:inputNumber id="montantCampagne"
value="#{cotisationsGestionBean.nouvelleCampagne.montant}"
required="true"
symbol=" FCFA"
symbolPosition="s"
minValue="0" />
</div>
<div class="field col-12 md:col-6">
<label for="dateEcheanceCampagne" class="block text-900 font-medium mb-2">Date d'échéance *</label>
<p:datePicker id="dateEcheanceCampagne"
value="#{cotisationsGestionBean.nouvelleCampagne.dateEcheance}"
required="true"
showIcon="true"
pattern="dd/MM/yyyy" />
</div>
<div class="field col-12 md:col-6">
<label for="scopeCampagne" class="block text-900 font-medium mb-2">Portée</label>
<p:selectOneMenu id="scopeCampagne"
value="#{cotisationsGestionBean.nouvelleCampagne.scope}">
<f:selectItem itemLabel="Toutes les organisations" itemValue="TOUTES" />
<f:selectItem itemLabel="Organisations sélectionnées" itemValue="SELECTION" />
<f:selectItem itemLabel="Par région" itemValue="REGION" />
</p:selectOneMenu>
</div>
<div class="field col-12">
<label for="descriptionCampagne" class="block text-900 font-medium mb-2">Description</label>
<p:inputTextarea id="descriptionCampagne"
value="#{cotisationsGestionBean.nouvelleCampagne.description}"
rows="3"
placeholder="Description optionnelle de la campagne..." />
</div>
<div class="field col-12">
<p:selectBooleanCheckbox id="relanceAuto"
value="#{cotisationsGestionBean.nouvelleCampagne.relanceAutomatique}" />
<label for="relanceAuto" class="ml-2">Activer les relances automatiques</label>
</div>
</div>
<div class="flex justify-content-end gap-2 mt-3">
<p:commandButton value="Annuler"
icon="pi pi-times"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
onclick="PF('dlgNouvelleCampagne').hide();"
type="button" />
<p:commandButton value="Créer la campagne"
icon="pi pi-check"
styleClass="ui-button-success ui-button-sm"
action="#{cotisationsGestionBean.creerCampagne}"
update="@form"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleCampagne').hide();" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Actions Groupées -->
<p:dialog header="Actions Groupées"
widgetVar="dlgActionsGroupees"
modal="true"
width="400"
height="auto"
resizable="false">
<h:form id="formActionsGroupees">
<div class="surface-50 border-round-lg p-3 mb-3">
<div class="text-500 text-sm mb-1">Cotisations sélectionnées</div>
<div class="text-900 font-bold text-xl">#{cotisationsGestionBean.cotisationsSelectionnees.size()}</div>
<div class="text-500 text-sm">Montant total: #{cotisationsGestionBean.montantTotalSelectionne}</div>
</div>
<div class="flex flex-column gap-2">
<p:commandButton value="Marquer comme payées"
icon="pi pi-check"
styleClass="ui-button-success ui-button-sm w-full"
action="#{cotisationsGestionBean.marquerPayeesGroupees}"
onclick="PF('dlgActionsGroupees').hide();" />
<p:commandButton value="Envoyer relances"
icon="pi pi-send"
styleClass="ui-button-warning ui-button-sm w-full"
action="#{cotisationsGestionBean.envoyerRelancesGroupees}"
onclick="PF('dlgActionsGroupees').hide();" />
<p:commandButton value="Générer reçus"
icon="pi pi-file-pdf"
styleClass="ui-button-info ui-button-sm w-full"
action="#{cotisationsGestionBean.genererRecusGroupes}"
onclick="PF('dlgActionsGroupees').hide();" />
<p:commandButton value="Annuler cotisations"
icon="pi pi-times"
styleClass="ui-button-danger ui-button-outlined ui-button-sm w-full"
action="#{cotisationsGestionBean.annulerCotisationsGroupees}"
onclick="return confirm('Êtes-vous sûr de vouloir annuler ces cotisations ?');" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,558 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Demandes d'Aide - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-heart text-red-500 mr-2"></i>
Gestion des Demandes d'Aide
</h3>
<p class="text-600 m-0">Traitement et suivi des demandes d'assistance</p>
</div>
<h:form id="formActionsEntete">
<div class="flex gap-2">
<p:commandButton value="Nouvelle demande"
icon="pi pi-plus"
styleClass="ui-button-success"
onclick="PF('dlgNouvelleDemande').show();" />
<p:commandButton value="Import demandes"
icon="pi pi-upload"
styleClass="ui-button-outlined ui-button-info"
onclick="PF('dlgImportDemandes').show();" />
<p:commandButton value="Exporter"
icon="pi pi-download"
styleClass="ui-button-outlined ui-button-secondary"
action="#{demandesAideBean.exporterDemandes}" />
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Statistiques -->
<div class="grid">
<div class="col-12 md:col-3">
<div class="card bg-blue-100 border-left-3 border-blue-500">
<div class="flex justify-content-between">
<div>
<div class="text-blue-900 font-bold text-xl">#{demandesAideBean.statistiques.totalDemandes}</div>
<div class="text-blue-700">Total Demandes</div>
</div>
<div class="bg-blue-500 text-white border-round text-center"
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
<i class="pi pi-list text-lg"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-orange-100 border-left-3 border-orange-500">
<div class="flex justify-content-between">
<div>
<div class="text-orange-900 font-bold text-xl">#{demandesAideBean.statistiques.demandesEnAttente}</div>
<div class="text-orange-700">En Attente</div>
</div>
<div class="bg-orange-500 text-white border-round text-center"
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
<i class="pi pi-clock text-lg"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-green-100 border-left-3 border-green-500">
<div class="flex justify-content-between">
<div>
<div class="text-green-900 font-bold text-xl">#{demandesAideBean.statistiques.demandesApprouvees}</div>
<div class="text-green-700">Approuvées</div>
</div>
<div class="bg-green-500 text-white border-round text-center"
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
<i class="pi pi-check text-lg"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-purple-100 border-left-3 border-purple-500">
<div class="flex justify-content-between">
<div>
<div class="text-purple-900 font-bold text-xl">#{demandesAideBean.statistiques.montantTotalAide}</div>
<div class="text-purple-700">Aide Accordée</div>
</div>
<div class="bg-purple-500 text-white border-round text-center"
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
<i class="pi pi-dollar text-lg"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Demandes prioritaires -->
<div class="card">
<h5>🚨 Demandes Prioritaires</h5>
<div class="grid">
<ui:repeat value="#{demandesAideBean.demandesPrioritaires}" var="demande" varStatus="status">
<div class="col-12 md:col-6 lg:col-4">
<div class="card border-left-3 border-#{demande.urgenceSeverity} hover:surface-50 transition-colors transition-duration-150">
<div class="flex align-items-start justify-content-between mb-3">
<div class="flex align-items-center">
<div class="bg-#{demande.urgenceSeverity} text-white border-round flex align-items-center justify-content-center mr-3"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi #{demande.typeIcon}"></i>
</div>
<div>
<h6 class="text-900 m-0 mb-1">#{demande.demandeur}</h6>
<p:tag value="#{demande.typeLibelle}" severity="#{demande.typeSeverity}" />
</div>
</div>
<p:tag value="#{demande.urgence}" severity="#{demande.urgenceSeverity}" />
</div>
<div class="text-600 mb-3">
<div class="flex align-items-center mb-2">
<i class="pi pi-calendar mr-2"></i>
<span>#{demande.dateDemandeFormatee}</span>
</div>
<div class="flex align-items-center mb-2">
<i class="pi pi-map-marker mr-2"></i>
<span>#{demande.localisation}</span>
</div>
<div class="flex align-items-center">
<i class="pi pi-dollar mr-2"></i>
<span>#{demande.montantDemandeFormatte}</span>
</div>
</div>
<div class="text-sm text-600 mb-3">
#{demande.motif}
</div>
<div class="flex justify-content-between align-items-center">
<span class="text-600 text-sm">#{demande.joursDepuisDemande} jours</span>
<h:form>
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
title="Voir détails">
<f:setPropertyActionListener target="#{demandesAideBean.demandeSelectionnee}" value="#{demande}" />
</p:commandButton>
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success"
title="Approuver"
action="#{demandesAideBean.approuverDemande}">
<f:setPropertyActionListener target="#{demandesAideBean.demandeSelectionnee}" value="#{demande}" />
</p:commandButton>
</div>
</h:form>
</div>
</div>
</div>
</ui:repeat>
</div>
</div>
<!-- Workflow des demandes -->
<div class="card">
<h5>📋 Workflow de Traitement</h5>
<div class="grid">
<ui:repeat value="#{demandesAideBean.etapesWorkflow}" var="etape" varStatus="status">
<div class="col-12 md:col-2">
<div class="text-center p-3">
<div class="bg-#{etape.couleur} text-white border-round flex align-items-center justify-content-center mx-auto mb-3"
style="width: 3rem; height: 3rem;">
<i class="pi #{etape.icon} text-xl"></i>
</div>
<h6 class="text-900 mb-2">#{etape.libelle}</h6>
<div class="text-2xl font-bold text-#{etape.couleur} mb-1">#{etape.nombre}</div>
<div class="text-600 text-sm">demandes</div>
</div>
<div class="text-center" rendered="#{status.index lt demandesAideBean.etapesWorkflow.size() - 1}">
<i class="pi pi-arrow-right text-300"></i>
</div>
</div>
</ui:repeat>
</div>
</div>
<!-- Filtres et recherche -->
<div class="card">
<h5>Filtres et Recherche</h5>
<h:form id="formFiltres">
<div class="ui-fluid">
<div class="grid">
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="searchDemandeur" value="Demandeur" />
<p:inputText id="searchDemandeur" value="#{demandesAideBean.filtres.demandeur}"
placeholder="Rechercher par nom...">
<p:ajax event="keyup" update="dtDemandes @(.stats-summary)" />
</p:inputText>
</div>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="filterType" value="Type d'aide" />
<p:selectOneMenu id="filterType" value="#{demandesAideBean.filtres.type}">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Aide Médicale" itemValue="AIDE_MEDICALE" />
<f:selectItem itemLabel="Aide Alimentaire" itemValue="AIDE_ALIMENTAIRE" />
<f:selectItem itemLabel="Aide Éducative" itemValue="AIDE_EDUCATIVE" />
<f:selectItem itemLabel="Aide Logement" itemValue="AIDE_LOGEMENT" />
<f:selectItem itemLabel="Aide d'Urgence" itemValue="AIDE_URGENCE" />
<p:ajax update="dtDemandes @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="filterStatut" value="Statut" />
<p:selectOneMenu id="filterStatut" value="#{demandesAideBean.filtres.statut}">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
<f:selectItem itemLabel="En évaluation" itemValue="EN_EVALUATION" />
<f:selectItem itemLabel="Approuvée" itemValue="APPROUVEE" />
<f:selectItem itemLabel="Rejetée" itemValue="REJETEE" />
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
<f:selectItem itemLabel="Terminée" itemValue="TERMINEE" />
<p:ajax update="dtDemandes @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="filterUrgence" value="Urgence" />
<p:selectOneMenu id="filterUrgence" value="#{demandesAideBean.filtres.urgence}">
<f:selectItem itemLabel="Toutes les urgences" itemValue="" />
<f:selectItem itemLabel="Faible" itemValue="FAIBLE" />
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="Élevée" itemValue="ELEVEE" />
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
<p:ajax update="dtDemandes @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
</div>
<div class="grid">
<div class="col-12 md:col-4">
<div class="field">
<p:outputLabel for="filterDateDebut" value="Date début" />
<p:datePicker id="filterDateDebut" value="#{demandesAideBean.filtres.dateDebut}"
placeholder="Sélectionner une date">
<p:ajax update="dtDemandes @(.stats-summary)" />
</p:datePicker>
</div>
</div>
<div class="col-12 md:col-4">
<div class="field">
<p:outputLabel for="filterDateFin" value="Date fin" />
<p:datePicker id="filterDateFin" value="#{demandesAideBean.filtres.dateFin}"
placeholder="Sélectionner une date">
<p:ajax update="dtDemandes @(.stats-summary)" />
</p:datePicker>
</div>
</div>
<div class="col-12 md:col-4">
<div class="field">
<p:outputLabel for="filterLocalisation" value="Localisation" />
<p:inputText id="filterLocalisation" value="#{demandesAideBean.filtres.localisation}"
placeholder="Filtrer par zone...">
<p:ajax event="keyup" update="dtDemandes @(.stats-summary)" />
</p:inputText>
</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Rechercher"
icon="pi pi-search"
styleClass="ui-button-primary"
action="#{demandesAideBean.rechercher}"
update="dtDemandes @(.stats-summary)" />
<p:commandButton value="Réinitialiser"
icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary"
action="#{demandesAideBean.reinitialiserFiltres}"
update="@form dtDemandes @(.stats-summary)" />
</div>
</div>
</h:form>
</div>
<!-- Liste des demandes -->
<div class="card">
<div class="flex align-items-center justify-content-between mb-3">
<h5 class="m-0">Demandes d'Aide (#{demandesAideBean.demandesFiltrees.size()})</h5>
<div class="flex align-items-center gap-2">
<h:form id="formActionsGroupees">
<p:commandButton value="Actions groupées"
icon="pi pi-cog"
styleClass="ui-button-outlined ui-button-warning"
onclick="PF('dlgActionsGroupees').show();"
disabled="#{empty demandesAideBean.demandesSelectionnees}" />
</h:form>
<span class="text-600 text-sm stats-summary">
#{demandesAideBean.demandesFiltrees.size()} sur #{demandesAideBean.toutesLesDemandes.size()} demandes
</span>
</div>
</div>
<p:dataTable id="dtDemandes"
value="#{demandesAideBean.demandesFiltrees}"
var="demande"
selection="#{demandesAideBean.demandesSelectionnees}"
rowKey="#{demande.id}"
paginator="true"
rows="15"
paginatorPosition="both"
sortMode="single"
styleClass="p-datatable-sm"
emptyMessage="Aucune demande trouvée">
<p:column selectionMode="multiple" width="40" />
<p:column headerText="Demandeur" sortBy="#{demande.demandeur}" width="200">
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-3"
style="width: 32px; height: 32px;">
<i class="pi pi-user"></i>
</div>
<div>
<div class="text-900 font-medium">#{demande.demandeur}</div>
<div class="text-600 text-sm">#{demande.telephone}</div>
</div>
</div>
</p:column>
<p:column headerText="Type d'aide" sortBy="#{demande.type}" width="130">
<p:tag value="#{demande.typeLibelle}"
severity="#{demande.typeSeverity}"
icon="pi #{demande.typeIcon}" />
</p:column>
<p:column headerText="Motif" width="250">
<div class="text-900 text-sm">#{demande.motif}</div>
<div class="text-600 text-xs" rendered="#{demande.description != null and demande.description.length() > 0}">
#{demande.description.length() > 50 ? demande.description.substring(0, 50) + '...' : demande.description}
</div>
</p:column>
<p:column headerText="Montant" sortBy="#{demande.montantDemande}" width="100">
<div class="text-900 text-sm text-right font-bold">#{demande.montantDemandeFormatte}</div>
<div class="text-600 text-xs text-right" rendered="#{demande.montantAccorde != null}">
Accordé: #{demande.montantAccordeFormatte}
</div>
</p:column>
<p:column headerText="Date demande" sortBy="#{demande.dateDemande}" width="100">
<div class="text-900 text-sm">#{demande.dateDemandeFormatee}</div>
<div class="text-600 text-xs">#{demande.joursDepuisDemande} jours</div>
</p:column>
<p:column headerText="Localisation" width="120">
<div class="text-900 text-sm">#{demande.localisation}</div>
</p:column>
<p:column headerText="Urgence" sortBy="#{demande.urgence}" width="80">
<p:tag value="#{demande.urgence}"
severity="#{demande.urgenceSeverity}" />
</p:column>
<p:column headerText="Statut" sortBy="#{demande.statut}" width="100">
<p:tag value="#{demande.statutLibelle}"
severity="#{demande.statutSeverity}"
icon="pi #{demande.statutIcon}" />
</p:column>
<p:column headerText="Actions" width="150">
<h:form id="formActions#{demande.id}">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
onclick="PF('dlgDetailsDemande').show();"
title="Voir détails">
<f:setPropertyActionListener target="#{demandesAideBean.demandeSelectionnee}" value="#{demande}" />
</p:commandButton>
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success"
title="Approuver"
action="#{demandesAideBean.approuverDemande}"
rendered="#{demande.statut == 'EN_ATTENTE' or demande.statut == 'EN_EVALUATION'}">
<f:setPropertyActionListener target="#{demandesAideBean.demandeSelectionnee}" value="#{demande}" />
</p:commandButton>
<p:commandButton icon="pi pi-times"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
title="Rejeter"
onclick="return confirm('Êtes-vous sûr de vouloir rejeter cette demande ?');"
action="#{demandesAideBean.rejeterDemande}"
rendered="#{demande.statut == 'EN_ATTENTE' or demande.statut == 'EN_EVALUATION'}">
<f:setPropertyActionListener target="#{demandesAideBean.demandeSelectionnee}" value="#{demande}" />
</p:commandButton>
<p:commandButton icon="pi pi-cog"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
onclick="PF('dlgActionsDemande').show();"
title="Actions">
<f:setPropertyActionListener target="#{demandesAideBean.demandeSelectionnee}" value="#{demande}" />
</p:commandButton>
</div>
</h:form>
</p:column>
</p:dataTable>
</div>
<!-- Dialog Nouvelle Demande -->
<p:dialog header="Créer une Nouvelle Demande" widgetVar="dlgNouvelleDemande" modal="true" width="900">
<h:form id="formNouvelleDemande">
<div class="ui-fluid">
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="newDemandeur" value="Nom du demandeur" />
<p:inputText id="newDemandeur" value="#{demandesAideBean.nouvelleDemande.demandeur}" required="true" />
</div>
<div class="field">
<p:outputLabel for="newTelephone" value="Téléphone" />
<p:inputText id="newTelephone" value="#{demandesAideBean.nouvelleDemande.telephone}" required="true" />
</div>
<div class="field">
<p:outputLabel for="newEmail" value="Email" />
<p:inputText id="newEmail" value="#{demandesAideBean.nouvelleDemande.email}" />
</div>
<div class="field">
<p:outputLabel for="newType" value="Type d'aide" />
<p:selectOneMenu id="newType" value="#{demandesAideBean.nouvelleDemande.type}" required="true">
<f:selectItem itemLabel="Sélectionner un type" itemValue="" />
<f:selectItem itemLabel="Aide Médicale" itemValue="AIDE_MEDICALE" />
<f:selectItem itemLabel="Aide Alimentaire" itemValue="AIDE_ALIMENTAIRE" />
<f:selectItem itemLabel="Aide Éducative" itemValue="AIDE_EDUCATIVE" />
<f:selectItem itemLabel="Aide Logement" itemValue="AIDE_LOGEMENT" />
<f:selectItem itemLabel="Aide d'Urgence" itemValue="AIDE_URGENCE" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="newLocalisation" value="Localisation" />
<p:inputText id="newLocalisation" value="#{demandesAideBean.nouvelleDemande.localisation}" required="true" />
</div>
<div class="field">
<p:outputLabel for="newMontant" value="Montant demandé" />
<p:inputNumber id="newMontant" value="#{demandesAideBean.nouvelleDemande.montantDemande}"
mode="currency" currency="XOF" locale="fr-CI" required="true" />
</div>
<div class="field">
<p:outputLabel for="newUrgence" value="Niveau d'urgence" />
<p:selectOneMenu id="newUrgence" value="#{demandesAideBean.nouvelleDemande.urgence}">
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="Faible" itemValue="FAIBLE" />
<f:selectItem itemLabel="Élevée" itemValue="ELEVEE" />
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="newDateLimite" value="Date limite souhaitée" />
<p:datePicker id="newDateLimite" value="#{demandesAideBean.nouvelleDemande.dateLimite}" />
</div>
</div>
<div class="col-12">
<div class="field">
<p:outputLabel for="newMotif" value="Motif de la demande" />
<p:inputText id="newMotif" value="#{demandesAideBean.nouvelleDemande.motif}" required="true" />
</div>
</div>
<div class="col-12">
<div class="field">
<p:outputLabel for="newDescription" value="Description détaillée" />
<p:inputTextarea id="newDescription" value="#{demandesAideBean.nouvelleDemande.description}" rows="4" />
</div>
</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Créer" icon="pi pi-check"
styleClass="ui-button-success"
action="#{demandesAideBean.creerDemande}"
update="@form dtDemandes @(.stats-summary)"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleDemande').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgNouvelleDemande').hide();" type="button" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Actions Demande -->
<p:dialog header="Actions sur la Demande" widgetVar="dlgActionsDemande" modal="true" width="400">
<h:form id="formActionsDemande">
<div class="grid">
<div class="col-12">
<p:commandButton value="Assigner à un responsable"
icon="pi pi-user-plus"
styleClass="ui-button-outlined ui-button-info w-full mb-2"
onclick="PF('dlgAssignerResponsable').show();" />
<p:commandButton value="Programmer une visite"
icon="pi pi-calendar-plus"
styleClass="ui-button-outlined ui-button-success w-full mb-2"
onclick="PF('dlgProgrammerVisite').show();" />
<p:commandButton value="Ajouter des documents"
icon="pi pi-file-plus"
styleClass="ui-button-outlined ui-button-warning w-full mb-2"
onclick="PF('dlgAjouterDocuments').show();" />
<p:commandButton value="Historique du traitement"
icon="pi pi-history"
styleClass="ui-button-outlined ui-button-secondary w-full mb-2"
action="#{demandesAideBean.voirHistorique}" />
<p:commandButton value="Envoyer notification"
icon="pi pi-send"
styleClass="ui-button-outlined ui-button-primary w-full mb-2"
action="#{demandesAideBean.envoyerNotification}" />
<p:commandButton value="Dupliquer la demande"
icon="pi pi-copy"
styleClass="ui-button-outlined ui-button-help w-full"
action="#{demandesAideBean.dupliquerDemande}" />
</div>
</div>
<div class="flex justify-content-end mt-3">
<p:commandButton value="Fermer" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgActionsDemande').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,561 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Demandes d'Aide - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-heart text-red-500 mr-2"></i>
Gestion des Demandes d'Aide
</h3>
<p class="text-600 m-0">Traitement et suivi des demandes d'assistance</p>
</div>
<h:form id="formActionsEntete">
<div class="flex gap-2">
<p:commandButton value="Nouvelle demande"
icon="pi pi-plus"
styleClass="ui-button-success"
onclick="PF('dlgNouvelleDemande').show();" />
<p:commandButton value="Import demandes"
icon="pi pi-upload"
styleClass="ui-button-outlined ui-button-info"
onclick="PF('dlgImportDemandes').show();" />
<p:commandButton value="Exporter"
icon="pi pi-download"
styleClass="ui-button-outlined ui-button-secondary"
action="#{demandesBean.exporterDemandes}" />
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Statistiques -->
<div class="grid">
<div class="col-12 md:col-3">
<div class="card bg-orange-100 border-left-3 border-orange-500">
<div class="flex justify-content-between">
<div>
<div class="text-orange-900 font-bold text-2xl">#{demandeBean.enAttente}</div>
<div class="text-orange-700">En Attente</div>
</div>
<div class="bg-orange-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-clock text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-red-100 border-left-3 border-red-500">
<div class="flex justify-content-between">
<div>
<div class="text-red-900 font-bold text-2xl">#{demandeBean.urgentes}</div>
<div class="text-red-700">Urgentes</div>
</div>
<div class="bg-red-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-exclamation-triangle text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-green-100 border-left-3 border-green-500">
<div class="flex justify-content-between">
<div>
<div class="text-green-900 font-bold text-2xl">#{demandeBean.traitees}</div>
<div class="text-green-700">Traitées</div>
</div>
<div class="bg-green-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-check text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-blue-100 border-left-3 border-blue-500">
<div class="flex justify-content-between">
<div>
<div class="text-blue-900 font-bold text-2xl">#{demandeBean.delaiMoyenTraitement}</div>
<div class="text-blue-700">Délai Moyen (jours)</div>
</div>
<div class="bg-blue-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-calendar text-xl"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Demandes urgentes et récentes -->
<div class="grid">
<div class="col-12 md:col-6">
<div class="card">
<h5>
<i class="pi pi-exclamation-triangle text-red-500 mr-2"></i>
Demandes Urgentes
</h5>
<ui:repeat value="#{demandeBean.demandesUrgentes}" var="demande" varStatus="status">
<div class="flex align-items-start p-3 mb-2 border-round border-left-3 border-red-500"
style="background: var(--red-50);">
<div class="flex-1">
<div class="flex align-items-center justify-content-between mb-2">
<span class="font-medium text-900">#{demande.objet}</span>
<p:tag value="#{demande.type}" severity="danger" />
</div>
<div class="text-600 mb-2">
<i class="pi pi-user mr-1"></i>
#{demande.demandeur} • #{demande.numeroMembre}
</div>
<div class="text-sm text-600">
Déposée #{demande.dateDepotRelative} • Échéance: #{demande.dateEcheance}
</div>
</div>
<h:form id="formActionsUrgentes">
<div class="flex gap-1 ml-3">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
action="#{demandeBean.voirDemande(demande)}" />
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success"
action="#{demandeBean.traiterDemande(demande)}" />
</div>
</h:form>
</div>
</ui:repeat>
<h:form id="formVoirUrgentes">
<p:commandButton value="Voir toutes les urgentes"
icon="pi pi-arrow-right"
styleClass="ui-button-outlined ui-button-danger w-full mt-2"
action="#{demandeBean.filtrerUrgentes}" />
</h:form>
</div>
</div>
<div class="col-12 md:col-6">
<div class="card">
<h5>
<i class="pi pi-clock text-blue-500 mr-2"></i>
Dernières Demandes
</h5>
<ui:repeat value="#{demandeBean.dernieresDemandes}" var="demande" varStatus="status">
<div class="flex align-items-start p-3 mb-2 border-round"
style="background: var(--surface-50);">
<div class="border-round p-2 mr-3 #{demande.typeColorClass}">
<i class="pi #{demande.typeIcon} text-white"></i>
</div>
<div class="flex-1">
<div class="flex align-items-center justify-content-between mb-1">
<span class="font-medium text-900">#{demande.objet}</span>
<small class="text-600">#{demande.dateDepotRelative}</small>
</div>
<div class="text-600 text-sm mb-1">
#{demande.demandeur} • #{demande.numeroMembre}
</div>
<p:tag value="#{demande.statut}" severity="#{demande.statutSeverity}" />
</div>
<h:form id="formActionsRecentes">
<div class="flex gap-1 ml-2">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-sm"
action="#{demandeBean.voirDemande(demande)}" />
</div>
</h:form>
</div>
</ui:repeat>
</div>
</div>
</div>
<!-- Graphiques -->
<div class="grid">
<div class="col-12 md:col-8">
<div class="card">
<h5>Évolution des Demandes</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique temporaire</div></div><!--chart
-->
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Répartition par Type</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique temporaire</div></div><!--chart
-->
</div>
</div>
</div>
<!-- Liste complète des demandes -->
<div class="card">
<h:form id="formDemandes">
<h5>Toutes les Demandes</h5>
<!-- Filtres -->
<p:toolbar>
<p:toolbarGroup>
<div class="flex align-items-center gap-2">
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<p:inputText placeholder="Rechercher..."
value="#{demandeBean.searchFilter}">
<p:ajax event="keyup" update="dtDemandes" />
</p:inputText>
</span>
<p:selectOneMenu value="#{demandeBean.statutFilter}">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
<f:selectItem itemLabel="Approuvée" itemValue="APPROUVEE" />
<f:selectItem itemLabel="Rejetée" itemValue="REJETEE" />
<f:selectItem itemLabel="Annulée" itemValue="ANNULEE" />
<p:ajax update="dtDemandes" />
</p:selectOneMenu>
<p:selectOneMenu value="#{demandeBean.typeFilter}">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Adhésion" itemValue="ADHESION" />
<f:selectItem itemLabel="Aide financière" itemValue="AIDE_FINANCIERE" />
<f:selectItem itemLabel="Certificat" itemValue="CERTIFICAT" />
<f:selectItem itemLabel="Mutation" itemValue="MUTATION" />
<f:selectItem itemLabel="Réclamation" itemValue="RECLAMATION" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
<p:ajax update="dtDemandes" />
</p:selectOneMenu>
<p:selectOneMenu value="#{demandeBean.prioriteFilter}">
<f:selectItem itemLabel="Toutes priorités" itemValue="" />
<f:selectItem itemLabel="Urgente" itemValue="URGENTE" />
<f:selectItem itemLabel="Haute" itemValue="HAUTE" />
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="Basse" itemValue="BASSE" />
<p:ajax update="dtDemandes" />
</p:selectOneMenu>
<p:calendar value="#{demandeBean.dateFilter}"
pattern="dd/MM/yyyy" showIcon="true"
placeholder="Filtrer par date">
<p:ajax event="dateSelect" update="dtDemandes" />
</p:calendar>
</div>
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:commandButton icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary"
action="#{demandeBean.actualiser}"
update="@form"
title="Actualiser" />
</p:toolbarGroup>
</p:toolbar>
<!-- DataTable -->
<p:dataTable id="dtDemandes"
var="demande"
value="#{demandeBean.demandes}"
paginator="true"
rows="15"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,15,25,50"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
selection="#{demandeBean.selectedDemandes}"
rowKey="#{demande.id}"
selectionMode="multiple"
styleClass="mt-3">
<p:column selectionMode="multiple" style="width:50px" />
<p:column headerText="Référence" sortBy="#{demande.reference}" style="width:120px">
<h:outputText value="#{demande.reference}" styleClass="font-mono font-bold" />
</p:column>
<p:column headerText="Demandeur" sortBy="#{demande.nomDemandeur}">
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-2"
style="width: 30px; height: 30px;">
<span style="font-size: 0.8rem;">#{demande.initialesDemandeur}</span>
</div>
<div>
<div class="font-medium text-900">#{demande.nomCompletDemandeur}</div>
<small class="text-600">#{demande.numeroMembre} • #{demande.telephoneDemandeur}</small>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{demande.type}" style="width:140px">
<div class="flex align-items-center">
<div class="border-round p-2 mr-2 #{demande.typeColorClass}">
<i class="pi #{demande.typeIcon} text-white text-sm"></i>
</div>
<span>#{demande.type}</span>
</div>
</p:column>
<p:column headerText="Objet" sortBy="#{demande.objet}">
<h:outputText value="#{demande.objet}" />
</p:column>
<p:column headerText="Priorité" sortBy="#{demande.priorite}" style="width:100px">
<p:tag value="#{demande.priorite}"
severity="#{demande.prioriteSeverity}"
icon="pi #{demande.prioriteIcon}" />
</p:column>
<p:column headerText="Statut" sortBy="#{demande.statut}" style="width:120px">
<p:tag value="#{demande.statut}"
severity="#{demande.statutSeverity}"
icon="pi #{demande.statutIcon}" />
</p:column>
<p:column headerText="Date dépôt" sortBy="#{demande.dateDepot}" style="width:120px">
<div>
<div class="font-medium">#{demande.dateDepot}</div>
<small class="text-600">#{demande.heureDepot}</small>
</div>
</p:column>
<p:column headerText="Échéance" sortBy="#{demande.dateEcheance}" style="width:120px">
<h:outputText value="#{demande.dateEcheance}"
styleClass="#{demande.echeanceClass}">
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
</h:outputText>
</p:column>
<p:column headerText="Assignée à" sortBy="#{demande.assigneA}" style="width:120px">
<h:outputText value="#{demande.assigneA}" rendered="#{demande.assigneA != null}" />
<span class="text-400" rendered="#{demande.assigneA == null}">Non assignée</span>
</p:column>
<p:column headerText="Actions" style="width:200px">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
action="#{demandeBean.voirDemande(demande)}"
title="Voir détails" />
<p:commandButton icon="pi pi-user"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
action="#{demandeBean.assignerDemande(demande)}"
title="Assigner"
rendered="#{demande.assigneA == null}" />
<p:commandButton icon="pi pi-cog"
styleClass="ui-button-rounded ui-button-text ui-button-warning"
action="#{demandeBean.traiterDemande(demande)}"
title="Traiter"
rendered="#{demande.statut == 'EN_ATTENTE' or demande.statut == 'EN_COURS'}" />
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success"
action="#{demandeBean.approuverDemande(demande)}"
title="Approuver"
rendered="#{demande.statut == 'EN_COURS'}" />
<p:commandButton icon="pi pi-times"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
action="#{demandeBean.rejeterDemande(demande)}"
onclick="return confirm('Êtes-vous sûr de vouloir rejeter cette demande ?');"
title="Rejeter"
rendered="#{demande.statut == 'EN_COURS'}" />
<p:commandButton icon="pi pi-file"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
action="#{demandeBean.voirPiecesJointes(demande)}"
title="Pièces jointes"
rendered="#{demande.hasPiecesJointes}" />
</div>
</p:column>
</p:dataTable>
<!-- Actions groupées -->
<div class="mt-3 flex justify-content-between align-items-center">
<div>
<span class="text-600">#{demandeBean.selectedDemandes.size()} demande(s) sélectionnée(s)</span>
</div>
<div class="flex gap-2">
<p:commandButton value="Assigner en lot"
icon="pi pi-users"
styleClass="ui-button-outlined ui-button-secondary"
onclick="PF('dlgAssignationLot').show();"
disabled="#{empty demandeBean.selectedDemandes}" />
<p:commandButton value="Marquer traitées"
icon="pi pi-check-circle"
styleClass="ui-button-outlined ui-button-success"
action="#{demandeBean.marquerTraitees}"
disabled="#{empty demandeBean.selectedDemandes}" />
<p:commandButton value="Exporter sélection"
icon="pi pi-file-excel"
styleClass="ui-button-outlined ui-button-info"
action="#{demandeBean.exporterSelection}"
disabled="#{empty demandeBean.selectedDemandes}" />
</div>
</div>
</h:form>
</div>
<!-- Dialog Nouvelle Demande -->
<p:dialog header="Nouvelle Demande" widgetVar="dlgNouvelleDemande" modal="true" width="700">
<h:form id="formNouvelleDemande">
<div class="ui-fluid">
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="demandeurSelect" value="Demandeur" />
<p:autoComplete id="demandeurSelect"
value="#{demandeBean.membreDemandeur}"
completeMethod="#{demandeBean.rechercherMembres}"
var="membre" itemLabel="#{membre.nomComplet}" itemValue="#{membre}"
converter="membreConverter"
placeholder="Rechercher un membre...">
<p:column>
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-2"
style="width: 30px; height: 30px;">
<span style="font-size: 0.8rem;">#{membre.initiales}</span>
</div>
<div>
<div class="font-medium">#{membre.nomComplet}</div>
<small class="text-600">#{membre.numeroMembre}</small>
</div>
</div>
</p:column>
</p:autoComplete>
</div>
<div class="field">
<p:outputLabel for="typeDemande" value="Type de demande" />
<p:selectOneMenu id="typeDemande" value="#{demandeBean.nouvelleDemande.type}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="📋 Adhésion" itemValue="ADHESION" />
<f:selectItem itemLabel="💰 Aide financière" itemValue="AIDE_FINANCIERE" />
<f:selectItem itemLabel="📄 Certificat" itemValue="CERTIFICAT" />
<f:selectItem itemLabel="🔄 Mutation" itemValue="MUTATION" />
<f:selectItem itemLabel="⚠️ Réclamation" itemValue="RECLAMATION" />
<f:selectItem itemLabel="🔧 Autre" itemValue="AUTRE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="prioriteDemande" value="Priorité" />
<p:selectOneMenu id="prioriteDemande" value="#{demandeBean.nouvelleDemande.priorite}">
<f:selectItem itemLabel="🔴 Urgente" itemValue="URGENTE" />
<f:selectItem itemLabel="🟡 Haute" itemValue="HAUTE" />
<f:selectItem itemLabel="🟢 Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="⚪ Basse" itemValue="BASSE" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="objetDemande" value="Objet" />
<p:inputText id="objetDemande" value="#{demandeBean.nouvelleDemande.objet}"
required="true" placeholder="Résumé de la demande" />
</div>
<div class="field">
<p:outputLabel for="dateEcheanceDemande" value="Date d'échéance" />
<p:calendar id="dateEcheanceDemande" value="#{demandeBean.nouvelleDemande.dateEcheance}"
pattern="dd/MM/yyyy" showIcon="true" />
</div>
<div class="field">
<p:outputLabel for="assignerA" value="Assigner à" />
<p:selectOneMenu id="assignerA" value="#{demandeBean.nouvelleDemande.assigneA}">
<f:selectItem itemLabel="Non assigné" itemValue="" />
<f:selectItems value="#{demandeBean.gestionnairesDisponibles}"
var="gestionnaire"
itemLabel="#{gestionnaire.nom}"
itemValue="#{gestionnaire.id}" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12">
<div class="field">
<p:outputLabel for="descriptionDemande" value="Description détaillée" />
<p:inputTextarea id="descriptionDemande" value="#{demandeBean.nouvelleDemande.description}"
rows="4" placeholder="Décrivez la demande en détail..." />
</div>
<div class="field">
<p:outputLabel for="piecesJointes" value="Pièces jointes" />
<p:fileUpload id="piecesJointes" mode="advanced"
multiple="true" dragDropSupport="true"
uploadLabel="Télécharger" cancelLabel="Annuler" chooseLabel="Sélectionner"
sizeLimit="5000000" fileLimit="5" />
</div>
</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Créer la demande" icon="pi pi-check"
styleClass="ui-button-success"
action="#{demandeBean.creerDemande}"
update="@form :formDemandes"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleDemande').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgNouvelleDemande').hide();" type="button" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Assignation en Lot -->
<p:dialog header="Assignation en Lot" widgetVar="dlgAssignationLot" modal="true" width="400">
<h:form id="formAssignationLot">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="gestionnaireAssignation" value="Assigner à" />
<p:selectOneMenu id="gestionnaireAssignation" value="#{demandeBean.gestionnaireAssignation}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItems value="#{demandeBean.gestionnairesDisponibles}"
var="gestionnaire"
itemLabel="#{gestionnaire.nom}"
itemValue="#{gestionnaire.id}" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="commentaireAssignation" value="Commentaire" />
<p:inputTextarea id="commentaireAssignation" value="#{demandeBean.commentaireAssignation}"
rows="3" placeholder="Commentaire optionnel..." />
</div>
<div class="surface-50 p-3 border-round">
<div class="font-medium mb-2">Demandes sélectionnées :</div>
<div class="text-600">#{demandeBean.selectedDemandes.size()} demande(s) seront assignées</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Assigner" icon="pi pi-check"
styleClass="ui-button-warning"
action="#{demandeBean.effectuerAssignationLot}"
update="@form :formDemandes"
oncomplete="if(!args.validationFailed) PF('dlgAssignationLot').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgAssignationLot').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,714 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Demandes d'Aide - UnionFlow</ui:define>
<ui:define name="content">
<div class="ui-fluid">
<!-- En-tête principal avec composant réutilisable -->
<ui:include src="/templates/components/layout/page-header.xhtml">
<ui:param name="icon" value="pi pi-heart text-red-500" />
<ui:param name="title" value="Gestion des Demandes d'Aide" />
<ui:param name="description" value="Traitement et suivi des demandes d'assistance • #{demandeBean.demandes.size()} demandes • #{demandeBean.enAttente} en attente" />
<ui:define name="actions">
<h:form id="formActionsEntete">
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-plus" />
<ui:param name="title" value="Nouvelle demande" />
<ui:param name="onclick" value="PF('dlgNouvelleDemande').show();" />
<ui:param name="styleClass" value="ui-button-sm mr-3" />
</ui:include>
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-upload" />
<ui:param name="title" value="Import demandes" />
<ui:param name="onclick" value="PF('dlgImportDemandes').show();" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm mr-3" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-download" />
<ui:param name="title" value="Exporter" />
<ui:param name="action" value="#{demandeBean.exporterDemandes}" />
<ui:param name="update" value="none" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</h:form>
</ui:define>
</ui:include>
<!-- KPIs avec composant réutilisable -->
<div class="formgrid grid">
<!-- KPI 1: En Attente -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="En Attente" />
<ui:param name="value" value="#{demandeBean.enAttente}" />
<ui:param name="icon" value="pi-clock" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
<!-- KPI 2: Demandes Urgentes -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Urgentes" />
<ui:param name="value" value="#{demandeBean.urgentes}" />
<ui:param name="icon" value="pi-exclamation-triangle" />
<ui:param name="iconColor" value="red-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
<!-- KPI 3: Traitées -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Traitées" />
<ui:param name="value" value="#{demandeBean.traitees}" />
<ui:param name="icon" value="pi-check" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
<!-- KPI 4: Délai Moyen -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Délai Moyen" />
<ui:param name="value" value="#{demandeBean.delaiMoyenTraitement} jours" />
<ui:param name="icon" value="pi-calendar" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-6 lg:col-3" />
</ui:include>
</div>
<!-- Demandes urgentes et récentes -->
<div class="formgrid grid">
<div class="field col-12 md:col-8">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-3">
<h5 class="text-900 font-bold mb-3">
<i class="pi pi-exclamation-triangle text-red-500 mr-2"></i>
Demandes Urgentes
</h5>
<ui:repeat value="#{demandeBean.demandesUrgentes}" var="demande" varStatus="status">
<div class="surface-100 border-round-lg p-3 mb-3 border-left-3 border-red-500 hover:surface-200 transition-colors transition-duration-150">
<div class="flex align-items-start justify-content-between">
<div class="flex align-items-start">
<div class="flex align-items-center justify-content-center surface-100 border-round-lg mr-3"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi #{demande.typeIcon} text-red-600"></i>
</div>
<div class="flex-1">
<div class="flex align-items-center justify-content-between mb-2">
<h6 class="text-900 font-medium m-0">#{demande.objet}</h6>
<p:tag value="#{demande.priorite}"
severity="#{demande.prioriteSeverity}"
styleClass="text-xs" />
</div>
<div class="text-600 mb-2 text-sm">
<i class="pi pi-user mr-2"></i>
<span class="font-medium">#{demande.demandeur}</span> • #{demande.numeroMembre}
</div>
<div class="flex align-items-center text-xs text-500">
<i class="pi pi-clock mr-1"></i>
<span>Déposée #{demande.dateDepotRelative}</span>
<span class="mx-2"></span>
<i class="pi pi-calendar mr-1"></i>
<span>Échéance: #{demande.dateEcheance}</span>
</div>
</div>
</div>
<h:form>
<div class="flex gap-2">
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-eye" />
<ui:param name="title" value="Voir détails" />
<ui:param name="action" value="#{demandeBean.voirDemande(demande)}" />
<ui:param name="update" value="none" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="title" value="Traiter" />
<ui:param name="action" value="#{demandeBean.traiterDemande(demande)}" />
<ui:param name="update" value=":formDemandes:dtDemandes" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
</div>
</h:form>
</div>
</div>
</ui:repeat>
<div class="mt-3">
<h:form>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Voir toutes les urgentes" />
<ui:param name="icon" value="pi pi-arrow-right" />
<ui:param name="action" value="#{demandeBean.filtrerUrgentes}" />
<ui:param name="update" value="none" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-danger ui-button-sm w-full" />
</ui:include>
</h:form>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-4">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-3">
<h5 class="text-900 font-bold mb-3">
<i class="pi pi-clock text-blue-500 mr-2"></i>
Dernières Demandes
</h5>
<ui:repeat value="#{demandeBean.dernieresDemandes}" var="demande" varStatus="status">
<div class="surface-100 border-round-lg p-3 mb-3 hover:surface-200 transition-colors transition-duration-150">
<div class="flex align-items-start justify-content-between">
<div class="flex align-items-start">
<div class="flex align-items-center justify-content-center border-round-lg mr-3 #{demande.typeColorClass}"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi #{demande.typeIcon} text-white"></i>
</div>
<div class="flex-1">
<div class="flex align-items-center justify-content-between mb-2">
<h6 class="text-900 font-medium m-0">#{demande.objet}</h6>
<small class="text-500 text-xs">#{demande.dateDepotRelative}</small>
</div>
<div class="text-600 mb-2 text-sm">
<i class="pi pi-user mr-2"></i>
<span class="font-medium">#{demande.demandeur}</span> • #{demande.numeroMembre}
</div>
<p:tag value="#{demande.statut}"
severity="#{demande.statutSeverity}"
icon="pi #{demande.statutIcon}"
styleClass="text-xs" />
</div>
</div>
<h:form>
<div class="flex gap-2">
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-eye" />
<ui:param name="title" value="Voir détails" />
<ui:param name="action" value="#{demandeBean.voirDemande(demande)}" />
<ui:param name="update" value="none" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
</div>
</h:form>
</div>
</div>
</ui:repeat>
</div>
</div>
</div>
</div>
<!-- Section Filtres avec composant réutilisable -->
<ui:decorate template="/templates/components/cards/filter-bar.xhtml">
<ui:param name="title" value="Filtres et Recherche" />
<ui:define name="filters">
<h:form id="formFiltres">
<div class="formgrid grid">
<div class="field col-12 md:col-6 lg:col-3">
<ui:include src="/templates/components/forms/form-field-search-text.xhtml">
<ui:param name="id" value="searchFilter" />
<ui:param name="label" value="Rechercher" />
<ui:param name="value" value="#{demandeBean.searchFilter}" />
<ui:param name="placeholder" value="Rechercher..." />
<ui:param name="update" value=":formDemandes:dtDemandes" />
<ui:param name="event" value="keyup" />
</ui:include>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="statutFilter" />
<ui:param name="label" value="Statut" />
<ui:param name="value" value="#{demandeBean.statutFilter}" />
<ui:define name="items">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
<f:selectItem itemLabel="Approuvée" itemValue="APPROUVEE" />
<f:selectItem itemLabel="Rejetée" itemValue="REJETEE" />
<f:selectItem itemLabel="Annulée" itemValue="ANNULEE" />
</ui:define>
<ui:define name="ajax">
<p:ajax update=":formDemandes:dtDemandes" />
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="typeFilter" />
<ui:param name="label" value="Type" />
<ui:param name="value" value="#{demandeBean.typeFilter}" />
<ui:define name="items">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Adhésion" itemValue="ADHESION" />
<f:selectItem itemLabel="Aide financière" itemValue="AIDE_FINANCIERE" />
<f:selectItem itemLabel="Certificat" itemValue="CERTIFICAT" />
<f:selectItem itemLabel="Mutation" itemValue="MUTATION" />
<f:selectItem itemLabel="Réclamation" itemValue="RECLAMATION" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
</ui:define>
<ui:define name="ajax">
<p:ajax update=":formDemandes:dtDemandes" />
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="prioriteFilter" />
<ui:param name="label" value="Priorité" />
<ui:param name="value" value="#{demandeBean.prioriteFilter}" />
<ui:define name="items">
<f:selectItem itemLabel="Toutes priorités" itemValue="" />
<f:selectItem itemLabel="Urgente" itemValue="URGENTE" />
<f:selectItem itemLabel="Haute" itemValue="HAUTE" />
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="Basse" itemValue="BASSE" />
</ui:define>
<ui:define name="ajax">
<p:ajax update=":formDemandes:dtDemandes" />
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6 lg:col-4">
<ui:include src="/templates/components/forms/form-field-calendar.xhtml">
<ui:param name="id" value="dateFilter" />
<ui:param name="label" value="Date" />
<ui:param name="value" value="#{demandeBean.dateFilter}" />
<ui:param name="update" value=":formDemandes:dtDemandes" />
</ui:include>
</div>
</div>
</h:form>
</ui:define>
<ui:define name="actions">
<div class="field col-12 md:col-6 lg:col-8">
<h:form id="formActionsFiltres">
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Réinitialiser" />
<ui:param name="icon" value="pi pi-refresh" />
<ui:param name="action" value="#{demandeBean.actualiser}" />
<ui:param name="update" value=":formFiltres :formDemandes:dtDemandes" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</h:form>
</div>
</ui:define>
</ui:decorate>
<!-- Liste complète des demandes -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h:form id="formDemandes">
<div class="flex align-items-center justify-content-between mb-4">
<h5 class="m-0">
<i class="pi pi-list text-primary mr-2"></i>
Toutes les Demandes
</h5>
<div class="flex gap-3 align-items-center">
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Assigner en lot" />
<ui:param name="icon" value="pi pi-users" />
<ui:param name="onclick" value="PF('dlgAssignationLot').show();" />
<ui:param name="disabled" value="#{empty demandeBean.selectedDemandes}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="Marquer traitées" />
<ui:param name="icon" value="pi pi-check-circle" />
<ui:param name="action" value="#{demandeBean.marquerTraitees}" />
<ui:param name="update" value=":formDemandes:dtDemandes" />
<ui:param name="disabled" value="#{empty demandeBean.selectedDemandes}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="Exporter sélection" />
<ui:param name="icon" value="pi pi-file-excel" />
<ui:param name="action" value="#{demandeBean.exporterSelection}" />
<ui:param name="update" value="none" />
<ui:param name="disabled" value="#{empty demandeBean.selectedDemandes}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</div>
</div>
<!-- DataTable -->
<p:dataTable id="dtDemandes"
var="demande"
value="#{demandeBean.demandes}"
paginator="true"
rows="15"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,15,25,50"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
selection="#{demandeBean.selectedDemandes}"
rowKey="#{demande.id}"
styleClass="p-datatable-sm p-datatable-gridlines p-datatable-striped"
emptyMessage="Aucune demande trouvée">
<p:column selectionMode="multiple" style="width:3rem" exportable="false"/>
<p:column headerText="Référence" sortBy="#{demande.reference}" style="width:120px">
<h:outputText value="#{demande.reference}" styleClass="font-mono font-bold" />
</p:column>
<p:column headerText="Demandeur" sortBy="#{demande.nomDemandeur}">
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-2 flex-shrink-0"
style="width: 2.5rem; height: 2.5rem; min-width: 2.5rem;">
<span class="text-sm font-semibold">#{demande.initialesDemandeur}</span>
</div>
<div>
<div class="font-medium text-900">#{demande.nomCompletDemandeur}</div>
<small class="text-600">#{demande.numeroMembre} • #{demande.telephoneDemandeur}</small>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{demande.type}" style="width:140px">
<div class="flex align-items-center">
<div class="border-round-lg flex align-items-center justify-content-center mr-2 flex-shrink-0 #{demande.typeColorClass}"
style="width: 2.5rem; height: 2.5rem; min-width: 2.5rem;">
<i class="pi #{demande.typeIcon} text-white"></i>
</div>
<span class="text-sm font-medium">#{demande.type}</span>
</div>
</p:column>
<p:column headerText="Objet" sortBy="#{demande.objet}">
<h:outputText value="#{demande.objet}" />
</p:column>
<p:column headerText="Priorité" sortBy="#{demande.priorite}" style="width:100px">
<p:tag value="#{demande.priorite}"
severity="#{demande.prioriteSeverity}"
icon="pi #{demande.prioriteIcon}" />
</p:column>
<p:column headerText="Statut" sortBy="#{demande.statut}" style="width:120px">
<p:tag value="#{demande.statut}"
severity="#{demande.statutSeverity}"
icon="pi #{demande.statutIcon}" />
</p:column>
<p:column headerText="Date dépôt" sortBy="#{demande.dateDepot}" style="width:120px">
<div class="text-center">
<div class="font-medium text-900 text-sm">
<h:outputText value="#{demande.dateDepot}">
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
</h:outputText>
</div>
<small class="text-600">#{demande.heureDepot}</small>
</div>
</p:column>
<p:column headerText="Échéance" sortBy="#{demande.dateEcheance}" style="width:120px">
<div class="text-center">
<div class="font-medium text-sm #{demande.echeanceClass}">
<h:outputText value="#{demande.dateEcheance}">
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
</h:outputText>
</div>
<small class="text-500 text-xs">#{demande.dateDepotRelative}</small>
</div>
</p:column>
<p:column headerText="Assignée à" sortBy="#{demande.assigneA}" style="width:120px">
<h:outputText value="#{demande.assigneA}" rendered="#{demande.assigneA != null}" />
<span class="text-400" rendered="#{demande.assigneA == null}">Non assignée</span>
</p:column>
<!-- Colonne Actions -->
<p:column headerText="Actions" style="width:200px" exportable="false">
<div class="flex gap-1 justify-content-center">
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-eye" />
<ui:param name="title" value="Voir détails" />
<ui:param name="action" value="#{demandeBean.voirDemande(demande)}" />
<ui:param name="update" value="none" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-user" />
<ui:param name="title" value="Assigner" />
<ui:param name="action" value="#{demandeBean.assignerDemande(demande)}" />
<ui:param name="update" value=":formDemandes:dtDemandes" />
<ui:param name="rendered" value="#{demande.assigneA == null}" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-warning.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-cog" />
<ui:param name="title" value="Traiter" />
<ui:param name="action" value="#{demandeBean.traiterDemande(demande)}" />
<ui:param name="update" value=":formDemandes:dtDemandes" />
<ui:param name="rendered" value="#{demande.statut == 'EN_ATTENTE' or demande.statut == 'EN_COURS'}" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="title" value="Approuver" />
<ui:param name="action" value="#{demandeBean.approuverDemande(demande)}" />
<ui:param name="update" value=":formDemandes:dtDemandes" />
<ui:param name="rendered" value="#{demande.statut == 'EN_COURS'}" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="title" value="Rejeter" />
<ui:param name="action" value="#{demandeBean.rejeterDemande(demande)}" />
<ui:param name="onclick" value="return confirm('Êtes-vous sûr de vouloir rejeter cette demande ?');" />
<ui:param name="update" value=":formDemandes:dtDemandes" />
<ui:param name="rendered" value="#{demande.statut == 'EN_COURS'}" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-danger ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="" />
<ui:param name="icon" value="pi pi-file" />
<ui:param name="title" value="Pièces jointes" />
<ui:param name="action" value="#{demandeBean.voirPiecesJointes(demande)}" />
<ui:param name="update" value="none" />
<ui:param name="rendered" value="#{demande.hasPiecesJointes}" />
<ui:param name="styleClass" value="ui-button-rounded ui-button-text ui-button-sm" />
</ui:include>
</div>
</p:column>
</p:dataTable>
</h:form>
</div>
</div>
</div>
<!-- Dialog Nouvelle Demande avec composant réutilisable -->
<ui:decorate template="/templates/components/dialogs/form-dialog.xhtml">
<ui:param name="dialogId" value="dlgNouvelleDemande" />
<ui:param name="header" value="Nouvelle Demande" />
<ui:param name="widgetVar" value="dlgNouvelleDemande" />
<ui:param name="formId" value="formNouvelleDemande" />
<ui:param name="width" value="800" />
<ui:define name="content">
<div class="formgrid grid">
<div class="field col-12 md:col-6">
<label for="demandeurSelect" class="block text-900 font-medium mb-2">Demandeur *</label>
<p:autoComplete id="demandeurSelect"
value="#{demandeBean.membreDemandeur}"
completeMethod="#{demandeBean.rechercherMembres}"
var="membre" itemLabel="#{membre.nomComplet}" itemValue="#{membre}"
converter="membreConverter"
placeholder="Rechercher un membre..."
styleClass="w-full">
<p:column>
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-2"
style="width: 30px; height: 30px;">
<span style="font-size: 0.8rem;">#{membre.initiales}</span>
</div>
<div>
<div class="font-medium">#{membre.nomComplet}</div>
<small class="text-600">#{membre.numeroMembre}</small>
</div>
</div>
</p:column>
</p:autoComplete>
</div>
<div class="field col-12 md:col-6">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="typeDemande" />
<ui:param name="label" value="Type de demande *" />
<ui:param name="value" value="#{demandeBean.nouvelleDemande.type}" />
<ui:param name="required" value="true" />
<ui:define name="items">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Adhésion" itemValue="ADHESION" />
<f:selectItem itemLabel="Aide financière" itemValue="AIDE_FINANCIERE" />
<f:selectItem itemLabel="Certificat" itemValue="CERTIFICAT" />
<f:selectItem itemLabel="Mutation" itemValue="MUTATION" />
<f:selectItem itemLabel="Réclamation" itemValue="RECLAMATION" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6">
<ui:include src="/templates/components/forms/form-field-text.xhtml">
<ui:param name="id" value="objetDemande" />
<ui:param name="label" value="Objet *" />
<ui:param name="value" value="#{demandeBean.nouvelleDemande.objet}" />
<ui:param name="required" value="true" />
<ui:param name="placeholder" value="Résumé de la demande" />
</ui:include>
</div>
<div class="field col-12 md:col-6">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="prioriteDemande" />
<ui:param name="label" value="Priorité" />
<ui:param name="value" value="#{demandeBean.nouvelleDemande.priorite}" />
<ui:define name="items">
<f:selectItem itemLabel="Urgente" itemValue="URGENTE" />
<f:selectItem itemLabel="Haute" itemValue="HAUTE" />
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="Basse" itemValue="BASSE" />
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6">
<ui:include src="/templates/components/forms/form-field-calendar.xhtml">
<ui:param name="id" value="dateEcheanceDemande" />
<ui:param name="label" value="Date d'échéance" />
<ui:param name="value" value="#{demandeBean.nouvelleDemande.dateEcheance}" />
</ui:include>
</div>
<div class="field col-12 md:col-6">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="assignerA" />
<ui:param name="label" value="Assigner à" />
<ui:param name="value" value="#{demandeBean.nouvelleDemande.assigneA}" />
<ui:define name="items">
<f:selectItem itemLabel="Non assigné" itemValue="" />
<f:selectItems value="#{demandeBean.gestionnairesDisponibles}"
var="gestionnaire"
itemLabel="#{gestionnaire.nom}"
itemValue="#{gestionnaire.id}" />
</ui:define>
</ui:include>
</div>
<div class="field col-12">
<ui:include src="/templates/components/forms/form-field-textarea.xhtml">
<ui:param name="id" value="descriptionDemande" />
<ui:param name="label" value="Description détaillée" />
<ui:param name="value" value="#{demandeBean.nouvelleDemande.description}" />
<ui:param name="rows" value="4" />
<ui:param name="placeholder" value="Décrivez la demande en détail..." />
</ui:include>
</div>
<div class="field col-12">
<label for="piecesJointes" class="block text-900 font-medium mb-2">Pièces jointes</label>
<p:fileUpload id="piecesJointes" mode="advanced"
multiple="true" dragDropSupport="true"
uploadLabel="Télécharger" cancelLabel="Annuler" chooseLabel="Sélectionner"
sizeLimit="5000000" fileLimit="5" />
</div>
</div>
</ui:define>
<ui:define name="footer">
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Annuler" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="onclick" value="PF('dlgNouvelleDemande').hide();" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="Créer la demande" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="action" value="#{demandeBean.creerDemande}" />
<ui:param name="update" value=":formNouvelleDemande :formDemandes" />
<ui:param name="oncomplete" value="if(!args.validationFailed) PF('dlgNouvelleDemande').hide();" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</ui:define>
</ui:decorate>
<!-- Dialog Assignation en Lot avec composant réutilisable -->
<ui:decorate template="/templates/components/dialogs/form-dialog.xhtml">
<ui:param name="dialogId" value="dlgAssignationLot" />
<ui:param name="header" value="Assignation en Lot" />
<ui:param name="widgetVar" value="dlgAssignationLot" />
<ui:param name="formId" value="formAssignationLot" />
<ui:param name="width" value="500" />
<ui:define name="content">
<div class="formgrid grid">
<div class="field col-12">
<ui:include src="/templates/components/forms/form-field-select.xhtml">
<ui:param name="id" value="gestionnaireAssignation" />
<ui:param name="label" value="Assigner à *" />
<ui:param name="value" value="#{demandeBean.gestionnaireAssignation}" />
<ui:param name="required" value="true" />
<ui:define name="items">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItems value="#{demandeBean.gestionnairesDisponibles}"
var="gestionnaire"
itemLabel="#{gestionnaire.nom}"
itemValue="#{gestionnaire.id}" />
</ui:define>
</ui:include>
</div>
<div class="field col-12">
<ui:include src="/templates/components/forms/form-field-textarea.xhtml">
<ui:param name="id" value="commentaireAssignation" />
<ui:param name="label" value="Commentaire" />
<ui:param name="value" value="#{demandeBean.commentaireAssignation}" />
<ui:param name="rows" value="3" />
<ui:param name="placeholder" value="Commentaire optionnel..." />
</ui:include>
</div>
<div class="field col-12">
<div class="surface-50 border-round-lg p-3">
<div class="font-medium mb-2">Demandes sélectionnées :</div>
<div class="text-600">#{demandeBean.selectedDemandes.size()} demande(s) seront assignées</div>
</div>
</div>
</div>
</ui:define>
<ui:define name="footer">
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Annuler" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="onclick" value="PF('dlgAssignationLot').hide();" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-warning.xhtml">
<ui:param name="value" value="Assigner" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="action" value="#{demandeBean.effectuerAssignationLot}" />
<ui:param name="update" value=":formAssignationLot :formDemandes" />
<ui:param name="oncomplete" value="if(!args.validationFailed) PF('dlgAssignationLot').hide();" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</ui:define>
</ui:decorate>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,613 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Documents - UnionFlow</ui:define>
<ui:define name="content">
<div class="ui-fluid">
<!-- En-tête avec disposition Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<div class="formgrid grid">
<div class="field col-12 lg:col-8">
<h2 class="text-primary font-bold mb-2">
<i class="pi pi-folder text-blue-500 mr-2"></i>
Gestion des Documents
</h2>
<p class="text-600 mt-0">Centralisation et organisation documentaire</p>
</div>
<div class="field col-12 lg:col-4 text-right">
<h:form id="formActionsEntete">
<div class="formgrid grid">
<div class="field col-12 md:col-4">
<p:commandButton value="Télécharger"
icon="pi pi-upload"
styleClass="ui-button-success ui-button-sm w-full"
onclick="PF('dlgTelechargerDocument').show();" />
</div>
<div class="field col-12 md:col-4">
<p:commandButton value="Dossier"
icon="pi pi-folder-plus"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
onclick="PF('dlgCreerDossier').show();" />
</div>
<div class="field col-12 md:col-4">
<p:commandButton value="Modèle"
icon="pi pi-file-plus"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full"
onclick="PF('dlgGenererModele').show();" />
</div>
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Statistiques stockage avec Freya stricte -->
<div class="formgrid grid">
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Total Documents</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-file text-blue-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{documentsBean.statistiques.totalDocuments}</div>
<div class="flex align-items-center mb-2">
<div class="bg-blue-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">Actifs</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Dossiers</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-folder text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{documentsBean.statistiques.totalDossiers}</div>
<div class="flex align-items-center mb-2">
<div class="bg-green-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">Organisés</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Espace Utilisé</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-database text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{documentsBean.statistiques.espaceUtilise}</div>
<div class="flex align-items-center mb-2">
<div class="bg-orange-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">Stockage</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Partages</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-share-alt text-purple-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{documentsBean.statistiques.partagesMois}</div>
<div class="flex align-items-center mb-2">
<div class="bg-purple-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">ce mois</span>
</div>
</div>
</div>
</div>
</div>
<!-- Navigation des dossiers avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<div class="flex align-items-center justify-content-between mb-4">
<h5 class="text-900 font-bold m-0">
<i class="pi pi-folder-open text-blue-500 mr-2"></i>
Navigation
</h5>
<div class="flex align-items-center gap-2">
<p:breadCrumb value="#{documentsBean.cheminNavigation}" var="niveau">
<p:menuitem value="#{niveau.nom}" />
</p:breadCrumb>
</div>
</div>
<!-- Vue dossiers -->
<div class="formgrid grid">
<ui:repeat value="#{documentsBean.dossiersAffichage}" var="dossier" varStatus="status">
<div class="field col-12 md:col-6 lg:col-3">
<div class="surface-100 border-round-lg p-3 hover:surface-200 transition-colors transition-duration-150 cursor-pointer"
onclick="#{documentsBean.naviguerVersDossier(dossier)}">
<div class="flex align-items-center">
<div class="surface-200 border-round-lg flex align-items-center justify-content-center mr-3"
style="width: 3rem; height: 3rem;">
<i class="pi pi-folder text-#{dossier.couleur} text-xl"></i>
</div>
<div class="flex-1">
<h6 class="text-900 m-0 mb-1">#{dossier.nom}</h6>
<div class="text-600 text-sm mb-1">#{dossier.nombreDocuments} documents</div>
<div class="text-500 text-xs">Modifié #{dossier.derniereModificationRelative}</div>
</div>
<h:form>
<p:commandButton icon="pi pi-ellipsis-v"
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
onclick="PF('dlgActionsDossier').show();"
title="Actions">
<f:setPropertyActionListener target="#{documentsBean.dossierSelectionne}" value="#{dossier}" />
</p:commandButton>
</h:form>
</div>
</div>
</div>
</ui:repeat>
</div>
</div>
</div>
<!-- Filtres et recherche avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-search text-blue-500 mr-2"></i>
Filtres et Recherche
</h5>
<h:form id="formFiltres">
<div class="ui-fluid">
<div class="formgrid grid">
<div class="field col-12 md:col-4">
<p:outputLabel for="searchNom" value="Nom du document" />
<p:inputText id="searchNom" value="#{documentsBean.filtres.nom}"
placeholder="Rechercher par nom...">
<p:ajax event="keyup" update="dtDocuments @(.stats-summary)" />
</p:inputText>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterType" value="Type" />
<p:selectOneMenu id="filterType" value="#{documentsBean.filtres.type}">
<f:selectItem itemLabel="Tous types" itemValue="" />
<f:selectItem itemLabel="PDF" itemValue="PDF" />
<f:selectItem itemLabel="Word" itemValue="WORD" />
<f:selectItem itemLabel="Excel" itemValue="EXCEL" />
<f:selectItem itemLabel="Image" itemValue="IMAGE" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
<p:ajax update="dtDocuments @(.stats-summary)" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterCategorie" value="Catégorie" />
<p:selectOneMenu id="filterCategorie" value="#{documentsBean.filtres.categorie}">
<f:selectItem itemLabel="Toutes" itemValue="" />
<f:selectItem itemLabel="Administratif" itemValue="ADMINISTRATIF" />
<f:selectItem itemLabel="Financier" itemValue="FINANCIER" />
<f:selectItem itemLabel="Juridique" itemValue="JURIDIQUE" />
<f:selectItem itemLabel="Communication" itemValue="COMMUNICATION" />
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
<p:ajax update="dtDocuments @(.stats-summary)" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterStatut" value="Statut" />
<p:selectOneMenu id="filterStatut" value="#{documentsBean.filtres.statut}">
<f:selectItem itemLabel="Tous statuts" itemValue="" />
<f:selectItem itemLabel="Brouillon" itemValue="BROUILLON" />
<f:selectItem itemLabel="Validé" itemValue="VALIDE" />
<f:selectItem itemLabel="Archivé" itemValue="ARCHIVE" />
<f:selectItem itemLabel="Expiré" itemValue="EXPIRE" />
<p:ajax update="dtDocuments @(.stats-summary)" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterAuteur" value="Auteur" />
<p:inputText id="filterAuteur" value="#{documentsBean.filtres.auteur}"
placeholder="Filtrer par auteur...">
<p:ajax event="keyup" update="dtDocuments @(.stats-summary)" />
</p:inputText>
</div>
</div>
<div class="formgrid grid">
<div class="field col-12 md:col-3">
<p:outputLabel for="filterDateDebut" value="Date début" />
<p:datePicker id="filterDateDebut" value="#{documentsBean.filtres.dateDebut}"
placeholder="Date de début">
<p:ajax update="dtDocuments @(.stats-summary)" />
</p:datePicker>
</div>
<div class="field col-12 md:col-3">
<p:outputLabel for="filterDateFin" value="Date fin" />
<p:datePicker id="filterDateFin" value="#{documentsBean.filtres.dateFin}"
placeholder="Date de fin">
<p:ajax update="dtDocuments @(.stats-summary)" />
</p:datePicker>
</div>
<div class="field col-12 md:col-3">
<p:outputLabel for="filterTaille" value="Taille max (MB)" />
<p:inputNumber id="filterTaille" value="#{documentsBean.filtres.tailleMax}"
placeholder="Taille maximum">
<p:ajax update="dtDocuments @(.stats-summary)" />
</p:inputNumber>
</div>
<div class="field col-12 md:col-3">
<p:outputLabel for="filterMots" value="Mots-clés" />
<p:inputText id="filterMots" value="#{documentsBean.filtres.motsCles}"
placeholder="Tags, mots-clés...">
<p:ajax event="keyup" update="dtDocuments @(.stats-summary)" />
</p:inputText>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Rechercher"
icon="pi pi-search"
styleClass="ui-button-primary ui-button-sm"
action="#{documentsBean.rechercher}"
update="dtDocuments @(.stats-summary)" />
<p:commandButton value="Réinitialiser"
icon="pi pi-refresh"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
action="#{documentsBean.reinitialiserFiltres}"
update="@form dtDocuments @(.stats-summary)" />
</div>
</div>
</h:form>
</div>
</div>
<!-- Liste des documents avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<div class="flex align-items-center justify-content-between mb-4">
<h5 class="text-900 font-bold m-0">
<i class="pi pi-file-o text-blue-500 mr-2"></i>
Documents (#{documentsBean.documentsFiltres.size()})
</h5>
<div class="flex align-items-center gap-2">
<h:form id="formActionsGroupees">
<p:commandButton value="Actions groupées"
icon="pi pi-cog"
styleClass="ui-button-outlined ui-button-warning"
onclick="PF('dlgActionsGroupees').show();"
disabled="#{empty documentsBean.documentsSelectionnes}" />
</h:form>
<div class="flex align-items-center gap-2">
<h:form>
<p:commandButton icon="pi pi-th-large"
styleClass="ui-button-rounded ui-button-outlined #{documentsBean.modeAffichage == 'GRID' ? 'ui-button-primary' : 'ui-button-secondary'}"
action="#{documentsBean.changerModeAffichage('GRID')}"
update="@form"
title="Vue grille" />
<p:commandButton icon="pi pi-list"
styleClass="ui-button-rounded ui-button-outlined #{documentsBean.modeAffichage == 'LIST' ? 'ui-button-primary' : 'ui-button-secondary'}"
action="#{documentsBean.changerModeAffichage('LIST')}"
update="@form"
title="Vue liste" />
</h:form>
</div>
<span class="text-600 text-sm stats-summary">
#{documentsBean.documentsFiltres.size()} sur #{documentsBean.tousLesDocuments.size()} documents
</span>
</div>
</div>
<!-- Vue grille -->
<div class="formgrid grid" rendered="#{documentsBean.modeAffichage == 'GRID'}">
<ui:repeat value="#{documentsBean.documentsFiltres}" var="document" varStatus="status">
<div class="field col-12 md:col-6 lg:col-4 xl:col-3">
<div class="surface-100 border-round-lg p-3 hover:surface-200 transition-colors transition-duration-150">
<div class="flex align-items-start justify-content-between mb-3">
<div class="surface-200 border-round-lg flex align-items-center justify-content-center"
style="width: 3rem; height: 3rem;">
<i class="pi #{document.typeIcon} text-#{document.typeCouleur} text-lg"></i>
</div>
<h:form>
<p:selectBooleanCheckbox value="#{documentsBean.estSelectionne(document)}"
onchange="#{documentsBean.toggleSelection(document)}" />
</h:form>
</div>
<h6 class="text-900 mb-2 line-height-3">#{document.nom}</h6>
<div class="flex align-items-center justify-content-between mb-2">
<p:tag value="#{document.categorieLibelle}" severity="#{document.categorieSeverity}" />
<span class="text-600 text-sm">#{document.taille}</span>
</div>
<div class="text-600 text-sm mb-3">
<div class="flex align-items-center mb-1">
<i class="pi pi-user mr-2"></i>
<span>#{document.auteur}</span>
</div>
<div class="flex align-items-center mb-1">
<i class="pi pi-calendar mr-2"></i>
<span>#{document.dateCreationFormatee}</span>
</div>
<div class="flex align-items-center">
<i class="pi pi-eye mr-2"></i>
<span>#{document.nombreVues} vues</span>
</div>
</div>
<div class="flex justify-content-between align-items-center">
<p:tag value="#{document.statutLibelle}" severity="#{document.statutSeverity}" />
<h:form>
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
title="Prévisualiser"
onclick="PF('dlgPrevisualiser').show();">
<f:setPropertyActionListener target="#{documentsBean.documentSelectionne}" value="#{document}" />
</p:commandButton>
<p:commandButton icon="pi pi-download"
styleClass="ui-button-rounded ui-button-text ui-button-success ui-button-sm"
title="Télécharger"
action="#{documentsBean.telechargerDocument(document)}" />
<p:commandButton icon="pi pi-ellipsis-v"
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
title="Actions"
onclick="PF('dlgActionsDocument').show();">
<f:setPropertyActionListener target="#{documentsBean.documentSelectionne}" value="#{document}" />
</p:commandButton>
</div>
</h:form>
</div>
</div>
</div>
</ui:repeat>
</div>
<!-- Vue liste -->
<p:dataTable id="dtDocuments"
value="#{documentsBean.documentsFiltres}"
var="document"
selection="#{documentsBean.documentsSelectionnes}"
rowKey="#{document.id}"
paginator="true"
rows="15"
paginatorPosition="both"
sortMode="single"
styleClass="p-datatable-sm"
emptyMessage="Aucun document trouvé"
rendered="#{documentsBean.modeAffichage == 'LIST'}">
<p:column selectionMode="multiple" width="40" />
<p:column headerText="Document" sortBy="#{document.nom}" width="300">
<div class="flex align-items-center">
<div class="bg-#{document.typeCouleur} text-white border-round flex align-items-center justify-content-center mr-3"
style="width: 32px; height: 32px;">
<i class="pi #{document.typeIcon}"></i>
</div>
<div>
<div class="text-900 font-medium">#{document.nom}</div>
<div class="text-600 text-sm">#{document.description}</div>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{document.type}" width="80">
<span class="text-900 font-bold">#{document.type}</span>
</p:column>
<p:column headerText="Catégorie" sortBy="#{document.categorie}" width="120">
<p:tag value="#{document.categorieLibelle}" severity="#{document.categorieSeverity}" />
</p:column>
<p:column headerText="Taille" sortBy="#{document.tailleBytes}" width="80">
<span class="text-900">#{document.taille}</span>
</p:column>
<p:column headerText="Auteur" sortBy="#{document.auteur}" width="120">
<div class="flex align-items-center">
<div class="border-circle bg-300 mr-2" style="width: 24px; height: 24px;"></div>
<span class="text-900">#{document.auteur}</span>
</div>
</p:column>
<p:column headerText="Date création" sortBy="#{document.dateCreation}" width="100">
<div class="text-900 text-sm">#{document.dateCreationFormatee}</div>
<div class="text-600 text-xs">#{document.dateCreationRelative}</div>
</p:column>
<p:column headerText="Vues" sortBy="#{document.nombreVues}" width="60">
<div class="text-center">
<span class="text-900 font-bold">#{document.nombreVues}</span>
</div>
</p:column>
<p:column headerText="Statut" sortBy="#{document.statut}" width="100">
<p:tag value="#{document.statutLibelle}" severity="#{document.statutSeverity}" />
</p:column>
<p:column headerText="Actions" width="150">
<h:form id="formActions#{document.id}">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
title="Prévisualiser"
onclick="PF('dlgPrevisualiser').show();">
<f:setPropertyActionListener target="#{documentsBean.documentSelectionne}" value="#{document}" />
</p:commandButton>
<p:commandButton icon="pi pi-download"
styleClass="ui-button-rounded ui-button-text ui-button-success"
title="Télécharger"
action="#{documentsBean.telechargerDocument(document)}" />
<p:commandButton icon="pi pi-share-alt"
styleClass="ui-button-rounded ui-button-text ui-button-primary"
title="Partager"
onclick="PF('dlgPartagerDocument').show();">
<f:setPropertyActionListener target="#{documentsBean.documentSelectionne}" value="#{document}" />
</p:commandButton>
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-warning"
title="Modifier"
onclick="PF('dlgModifierDocument').show();">
<f:setPropertyActionListener target="#{documentsBean.documentSelectionne}" value="#{document}" />
</p:commandButton>
<p:commandButton icon="pi pi-trash"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
title="Supprimer"
onclick="return confirm('Êtes-vous sûr de vouloir supprimer ce document ?');"
action="#{documentsBean.supprimerDocument(document)}" />
</div>
</h:form>
</p:column>
</p:dataTable>
</div>
</div>
<!-- Dialog Télécharger Document avec Freya stricte -->
<p:dialog header="Télécharger un Document" widgetVar="dlgTelechargerDocument" modal="true" width="600">
<h:form id="formTelechargerDocument" enctype="multipart/form-data">
<div class="ui-fluid">
<div class="formgrid grid">
<div class="field col-12">
<p:outputLabel for="uploadFile" value="Fichier" />
<p:fileUpload id="uploadFile"
mode="advanced"
dragDropSupport="true"
multiple="true"
uploadLabel="Télécharger"
cancelLabel="Annuler"
chooseLabel="Sélectionner"
sizeLimit="10000000"
fileLimit="10"
allowTypes="/\.(pdf|doc|docx|xls|xlsx|ppt|pptx|txt|jpg|jpeg|png|gif)$/" />
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newCategorie" value="Catégorie" />
<p:selectOneMenu id="newCategorie" value="#{documentsBean.nouveauDocument.categorie}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Administratif" itemValue="ADMINISTRATIF" />
<f:selectItem itemLabel="Financier" itemValue="FINANCIER" />
<f:selectItem itemLabel="Juridique" itemValue="JURIDIQUE" />
<f:selectItem itemLabel="Communication" itemValue="COMMUNICATION" />
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newDossier" value="Dossier de destination" />
<p:selectOneMenu id="newDossier" value="#{documentsBean.nouveauDocument.dossierId}">
<f:selectItem itemLabel="Racine" itemValue="" />
<f:selectItems value="#{documentsBean.dossiersDisponibles}"
var="dossier"
itemLabel="#{dossier.cheminComplet}"
itemValue="#{dossier.id}" />
</p:selectOneMenu>
</div>
<div class="field col-12">
<p:outputLabel for="newDescription" value="Description" />
<p:inputTextarea id="newDescription" value="#{documentsBean.nouveauDocument.description}"
rows="3" placeholder="Description du document..." />
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newMotsCles" value="Mots-clés" />
<p:inputText id="newMotsCles" value="#{documentsBean.nouveauDocument.motsCles}"
placeholder="Séparer par des virgules..." />
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newAccesRestreint" value="Accès restreint" />
<p:selectBooleanCheckbox id="newAccesRestreint" value="#{documentsBean.nouveauDocument.accesRestreint}" />
</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Télécharger" icon="pi pi-upload"
styleClass="ui-button-success ui-button-sm"
action="#{documentsBean.telechargerNouveauDocument}"
update="@form"
oncomplete="if(!args.validationFailed) PF('dlgTelechargerDocument').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary ui-button-sm"
onclick="PF('dlgTelechargerDocument').hide();" type="button" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Actions Document avec Freya stricte -->
<p:dialog header="Actions sur le Document" widgetVar="dlgActionsDocument" modal="true" width="400">
<h:form id="formActionsDocument">
<div class="formgrid grid">
<div class="field col-12">
<p:commandButton value="Créer une copie"
icon="pi pi-copy"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full mb-2"
action="#{documentsBean.dupliquerDocument}" />
<p:commandButton value="Déplacer vers..."
icon="pi pi-arrow-right"
styleClass="ui-button-warning ui-button-outlined ui-button-sm w-full mb-2"
onclick="PF('dlgDeplacerDocument').show();" />
<p:commandButton value="Gérer les permissions"
icon="pi pi-lock"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full mb-2"
onclick="PF('dlgPermissionsDocument').show();" />
<p:commandButton value="Historique des versions"
icon="pi pi-history"
styleClass="ui-button-primary ui-button-outlined ui-button-sm w-full mb-2"
action="#{documentsBean.voirHistoriqueVersions}" />
<p:commandButton value="Archiver le document"
icon="pi pi-archive"
styleClass="ui-button-help ui-button-outlined ui-button-sm w-full mb-2"
action="#{documentsBean.archiverDocument}"
rendered="#{documentsBean.documentSelectionne.statut != 'ARCHIVE'}" />
<p:commandButton value="Supprimer définitivement"
icon="pi pi-trash"
styleClass="ui-button-danger ui-button-outlined ui-button-sm w-full"
onclick="return confirm('ATTENTION: Cette action est irréversible. Confirmer la suppression ?');"
action="#{documentsBean.supprimerDefinitivement}" />
</div>
</div>
<div class="flex justify-content-end mt-3">
<p:commandButton value="Fermer" icon="pi pi-times"
styleClass="ui-button-secondary ui-button-sm"
onclick="PF('dlgActionsDocument').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,541 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Créer un Événement - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-calendar-plus text-green-500 mr-2"></i>
Créer un Nouvel Événement
</h3>
<p class="text-600 m-0">Planifiez et organisez vos événements avec tous les détails nécessaires</p>
</div>
<div>
<p:commandButton value="Retour à la liste"
icon="pi pi-arrow-left"
styleClass="ui-button-outlined ui-button-secondary"
action="/pages/admin/evenements/liste?faces-redirect=true" />
</div>
</div>
</div>
</div>
</div>
<!-- Progression -->
<div class="card">
<h5>Progression de création</h5>
<div class="grid">
<div class="col-12 md:col-2">
<div class="text-center p-3">
<i class="pi pi-info-circle text-2xl text-primary mb-2"></i>
<div class="text-sm font-medium">Informations de base</div>
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{creationEvenementBean.etapeInformationsComplete ? 'inline' : 'none'};"></i>
</div>
</div>
<div class="col-12 md:col-2">
<div class="text-center p-3">
<i class="pi pi-calendar text-2xl text-primary mb-2"></i>
<div class="text-sm font-medium">Date et lieu</div>
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{creationEvenementBean.etapeDateLieuComplete ? 'inline' : 'none'};"></i>
</div>
</div>
<div class="col-12 md:col-2">
<div class="text-center p-3">
<i class="pi pi-users text-2xl text-primary mb-2"></i>
<div class="text-sm font-medium">Participants</div>
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{creationEvenementBean.etapeParticipantsComplete ? 'inline' : 'none'};"></i>
</div>
</div>
<div class="col-12 md:col-2">
<div class="text-center p-3">
<i class="pi pi-dollar text-2xl text-primary mb-2"></i>
<div class="text-sm font-medium">Tarification</div>
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{creationEvenementBean.etapeTarificationComplete ? 'inline' : 'none'};"></i>
</div>
</div>
<div class="col-12 md:col-2">
<div class="text-center p-3">
<i class="pi pi-bell text-2xl text-primary mb-2"></i>
<div class="text-sm font-medium">Notifications</div>
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{creationEvenementBean.etapeNotificationsComplete ? 'inline' : 'none'};"></i>
</div>
</div>
<div class="col-12 md:col-2">
<div class="text-center p-3">
<i class="pi pi-check text-2xl text-primary mb-2"></i>
<div class="text-sm font-medium">Validation</div>
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{creationEvenementBean.etapeValidationComplete ? 'inline' : 'none'};"></i>
</div>
</div>
</div>
<p:progressBar value="#{creationEvenementBean.progressionPourcentage}"
labelTemplate="{value}% complété"
styleClass="mb-3" />
</div>
<h:form id="formCreation" styleClass="ui-fluid">
<p:messages id="messages" showDetail="true" closable="true" />
<div class="grid">
<!-- Informations de base -->
<div class="col-12 md:col-6">
<div class="card">
<h5>
<i class="pi pi-info-circle mr-2"></i>
Informations de Base
</h5>
<div class="field">
<p:outputLabel for="titre" value="Titre de l'événement" />
<p:inputText id="titre" value="#{creationEvenementBean.evenement.titre}"
required="true" placeholder="Ex: Assemblée Générale 2024" />
</div>
<div class="field">
<p:outputLabel for="type" value="Type d'événement" />
<p:selectOneMenu id="type" value="#{creationEvenementBean.evenement.typeEvenement}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="🏛️ Assemblée Générale" itemValue="ASSEMBLEE_GENERALE" />
<f:selectItem itemLabel="📋 Réunion" itemValue="REUNION" />
<f:selectItem itemLabel="🎓 Formation" itemValue="FORMATION" />
<f:selectItem itemLabel="🎉 Événement social" itemValue="SOCIAL" />
<f:selectItem itemLabel="🏆 Cérémonie" itemValue="CEREMONIE" />
<f:selectItem itemLabel="🚌 Sortie/Voyage" itemValue="SORTIE" />
<f:selectItem itemLabel="🍽️ Repas" itemValue="REPAS" />
<f:selectItem itemLabel="🔧 Autre" itemValue="AUTRE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="description" value="Description" />
<p:inputTextarea id="description" value="#{creationEvenementBean.evenement.description}"
rows="4" placeholder="Décrivez l'événement, son objectif et son déroulement..." />
</div>
<div class="field">
<p:outputLabel for="organisateur" value="Organisateur" />
<p:inputText id="organisateur" value="#{creationEvenementBean.evenement.organisateur}"
placeholder="Nom de l'organisateur principal" />
</div>
<div class="field">
<p:outputLabel for="priorite" value="Priorité" />
<p:selectOneMenu id="priorite" value="#{creationEvenementBean.evenement.priorite}">
<f:selectItem itemLabel="🔴 Haute" itemValue="HAUTE" />
<f:selectItem itemLabel="🟡 Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="🟢 Basse" itemValue="BASSE" />
</p:selectOneMenu>
</div>
</div>
</div>
<!-- Date, heure et lieu -->
<div class="col-12 md:col-6">
<div class="card">
<h5>
<i class="pi pi-calendar mr-2"></i>
Date, Heure et Lieu
</h5>
<div class="field">
<p:outputLabel for="dateDebut" value="Date de début" />
<p:calendar id="dateDebut" value="#{creationEvenementBean.evenement.dateDebut}"
pattern="dd/MM/yyyy" showIcon="true" required="true"
locale="fr" />
</div>
<div class="formgrid grid">
<div class="field col">
<p:outputLabel for="heureDebut" value="Heure début" />
<p:calendar id="heureDebut" value="#{creationEvenementBean.evenement.heureDebut}"
pattern="HH:mm" timeOnly="true" showIcon="true" />
</div>
<div class="field col">
<p:outputLabel for="heureFin" value="Heure fin" />
<p:calendar id="heureFin" value="#{creationEvenementBean.evenement.heureFin}"
pattern="HH:mm" timeOnly="true" showIcon="true" />
</div>
</div>
<div class="field">
<p:selectBooleanCheckbox id="evenementRecurrent" value="#{creationEvenementBean.evenement.recurrent}" />
<p:outputLabel for="evenementRecurrent" value=" Événement récurrent" />
</div>
<div class="field" style="display: #{creationEvenementBean.evenement.recurrent ? 'block' : 'none'};">
<p:outputLabel for="frequenceRecurrence" value="Fréquence" />
<p:selectOneMenu id="frequenceRecurrence" value="#{creationEvenementBean.evenement.frequenceRecurrence}">
<f:selectItem itemLabel="Hebdomadaire" itemValue="HEBDOMADAIRE" />
<f:selectItem itemLabel="Mensuel" itemValue="MENSUEL" />
<f:selectItem itemLabel="Trimestriel" itemValue="TRIMESTRIEL" />
<f:selectItem itemLabel="Annuel" itemValue="ANNUEL" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="lieu" value="Lieu" />
<p:inputText id="lieu" value="#{creationEvenementBean.evenement.lieu}"
required="true" placeholder="Ex: Salle de réunion, Hôtel..." />
</div>
<div class="field">
<p:outputLabel for="adresse" value="Adresse complète" />
<p:inputTextarea id="adresse" value="#{creationEvenementBean.evenement.adresse}"
rows="3" placeholder="Adresse précise avec ville et points de repère" />
</div>
</div>
</div>
<!-- Configuration des participants -->
<div class="col-12 md:col-6">
<div class="card">
<h5>
<i class="pi pi-users mr-2"></i>
Participants et Inscription
</h5>
<div class="field">
<p:outputLabel for="placesMax" value="Nombre maximum de places" />
<p:inputNumber id="placesMax" value="#{creationEvenementBean.evenement.placesMax}"
symbol="" min="1" max="10000" />
</div>
<div class="field">
<p:selectBooleanCheckbox id="inscriptionRequise" value="#{creationEvenementBean.evenement.inscriptionRequise}" />
<p:outputLabel for="inscriptionRequise" value=" Inscription obligatoire" />
</div>
<div class="field" style="display: #{creationEvenementBean.evenement.inscriptionRequise ? 'block' : 'none'};">
<p:outputLabel for="dateLimiteInscription" value="Date limite d'inscription" />
<p:calendar id="dateLimiteInscription" value="#{creationEvenementBean.evenement.dateLimiteInscription}"
pattern="dd/MM/yyyy HH:mm" showIcon="true" locale="fr" />
</div>
<div class="field">
<p:outputLabel for="publicCible" value="Public cible" />
<p:selectCheckboxMenu id="publicCible" value="#{creationEvenementBean.evenement.publicCible}"
multiple="true" filter="true" filterMatchMode="contains">
<f:selectItem itemLabel="Tous les membres" itemValue="TOUS" />
<f:selectItem itemLabel="Membres actifs" itemValue="ACTIFS" />
<f:selectItem itemLabel="Membres bienfaiteurs" itemValue="BIENFAITEURS" />
<f:selectItem itemLabel="Membres honoraires" itemValue="HONORAIRES" />
<f:selectItem itemLabel="Bureau exécutif" itemValue="BUREAU" />
<f:selectItem itemLabel="Invités externes" itemValue="INVITES" />
</p:selectCheckboxMenu>
</div>
<div class="field">
<p:selectBooleanCheckbox id="listeAttente" value="#{creationEvenementBean.evenement.listeAttente}" />
<p:outputLabel for="listeAttente" value=" Activer liste d'attente si complet" />
</div>
<div class="field">
<p:outputLabel for="accompagnateurs" value="Nombre d'accompagnateurs autorisés" />
<p:inputNumber id="accompagnateurs" value="#{creationEvenementBean.evenement.accompagnateursMax}"
symbol="" min="0" max="10" />
</div>
</div>
</div>
<!-- Tarification -->
<div class="col-12 md:col-6">
<div class="card">
<h5>
<i class="pi pi-dollar mr-2"></i>
Tarification et Paiement
</h5>
<div class="field">
<p:selectBooleanCheckbox id="evenementPayant" value="#{creationEvenementBean.evenement.payant}" />
<p:outputLabel for="evenementPayant" value=" Événement payant" />
</div>
<div class="field" style="display: #{creationEvenementBean.evenement.payant ? 'block' : 'none'};">
<p:outputLabel for="prix" value="Prix par personne" />
<p:inputNumber id="prix" value="#{creationEvenementBean.evenement.prix}"
symbol=" FCFA" symbolPosition="s" min="0" />
</div>
<div class="field" style="display: #{creationEvenementBean.evenement.payant ? 'block' : 'none'};">
<p:outputLabel for="tarificationDifferenciee" value="Tarification différenciée" />
<p:selectBooleanCheckbox id="tarificationDifferenciee" value="#{creationEvenementBean.evenement.tarificationDifferenciee}" />
<p:outputLabel for="tarificationDifferenciee" value=" Activer tarifs différents selon le type de membre" />
</div>
<div class="field" style="display: #{creationEvenementBean.evenement.tarificationDifferenciee ? 'block' : 'none'};">
<h6>Tarifs par catégorie</h6>
<div class="formgrid grid">
<div class="field col-6">
<p:outputLabel value="Membres actifs" />
<p:inputNumber value="#{creationEvenementBean.evenement.prixMembresActifs}"
symbol=" FCFA" symbolPosition="s" />
</div>
<div class="field col-6">
<p:outputLabel value="Membres associés" />
<p:inputNumber value="#{creationEvenementBean.evenement.prixMembresAssocies}"
symbol=" FCFA" symbolPosition="s" />
</div>
<div class="field col-6">
<p:outputLabel value="Invités externes" />
<p:inputNumber value="#{creationEvenementBean.evenement.prixInvites}"
symbol=" FCFA" symbolPosition="s" />
</div>
<div class="field col-6">
<p:outputLabel value="Accompagnateurs" />
<p:inputNumber value="#{creationEvenementBean.evenement.prixAccompagnateurs}"
symbol=" FCFA" symbolPosition="s" />
</div>
</div>
</div>
<div class="field" style="display: #{creationEvenementBean.evenement.payant ? 'block' : 'none'};">
<p:outputLabel for="modesPaiement" value="Modes de paiement acceptés" />
<p:selectCheckboxMenu id="modesPaiement" value="#{creationEvenementBean.evenement.modesPaiement}"
multiple="true">
<f:selectItem itemLabel="💰 Espèces" itemValue="ESPECES" />
<f:selectItem itemLabel="📱 Wave Money" itemValue="WAVE" />
<f:selectItem itemLabel="🏦 Virement bancaire" itemValue="VIREMENT" />
<f:selectItem itemLabel="💳 Chèque" itemValue="CHEQUE" />
<f:selectItem itemLabel="💸 Prélèvement automatique" itemValue="PRELEVEMENT" />
</p:selectCheckboxMenu>
</div>
</div>
</div>
<!-- Notifications et communication -->
<div class="col-12">
<div class="card">
<h5>
<i class="pi pi-bell mr-2"></i>
Notifications et Communication
</h5>
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<p:selectBooleanCheckbox id="notifierCreation" value="#{creationEvenementBean.evenement.notifierCreation}" />
<p:outputLabel for="notifierCreation" value=" Notifier immédiatement la création" />
</div>
<div class="field">
<p:outputLabel for="canauxNotification" value="Canaux de notification" />
<p:selectCheckboxMenu id="canauxNotification" value="#{creationEvenementBean.evenement.canauxNotification}"
multiple="true">
<f:selectItem itemLabel="📧 Email" itemValue="EMAIL" />
<f:selectItem itemLabel="📱 SMS" itemValue="SMS" />
<f:selectItem itemLabel="💬 WhatsApp" itemValue="WHATSAPP" />
<f:selectItem itemLabel="🔔 Notification push" itemValue="PUSH" />
</p:selectCheckboxMenu>
</div>
<div class="field">
<p:outputLabel for="messagePersonnalise" value="Message personnalisé" />
<p:inputTextarea id="messagePersonnalise" value="#{creationEvenementBean.evenement.messagePersonnalise}"
rows="4" placeholder="Message d'invitation personnalisé..." />
</div>
</div>
<div class="col-12 md:col-6">
<h6>Rappels automatiques</h6>
<div class="field">
<p:selectBooleanCheckbox id="rappelJ7" value="#{creationEvenementBean.evenement.rappelJ7}" />
<p:outputLabel for="rappelJ7" value=" Rappel 7 jours avant" />
</div>
<div class="field">
<p:selectBooleanCheckbox id="rappelJ3" value="#{creationEvenementBean.evenement.rappelJ3}" />
<p:outputLabel for="rappelJ3" value=" Rappel 3 jours avant" />
</div>
<div class="field">
<p:selectBooleanCheckbox id="rappelJ1" value="#{creationEvenementBean.evenement.rappelJ1}" />
<p:outputLabel for="rappelJ1" value=" Rappel 1 jour avant" />
</div>
<div class="field">
<p:selectBooleanCheckbox id="rappelH2" value="#{creationEvenementBean.evenement.rappelH2}" />
<p:outputLabel for="rappelH2" value=" Rappel 2 heures avant" />
</div>
<div class="field">
<p:selectBooleanCheckbox id="notificationSuivi" value="#{creationEvenementBean.evenement.notificationSuivi}" />
<p:outputLabel for="notificationSuivi" value=" Envoyer bilan après l'événement" />
</div>
</div>
</div>
</div>
</div>
<!-- Documents et pièces jointes -->
<div class="col-12">
<div class="card">
<h5>
<i class="pi pi-file mr-2"></i>
Documents et Pièces Jointes
</h5>
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="programme" value="Programme détaillé" />
<p:fileUpload id="programme" mode="simple" skinSimple="true"
accept="application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
</div>
<div class="field">
<p:outputLabel for="invitation" value="Carte d'invitation" />
<p:fileUpload id="invitation" mode="simple" skinSimple="true"
accept="image/*,application/pdf" />
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<p:outputLabel for="documentsComplementaires" value="Documents complémentaires" />
<p:fileUpload id="documentsComplementaires" mode="advanced"
multiple="true" dragDropSupport="true"
uploadLabel="Télécharger" cancelLabel="Annuler" chooseLabel="Sélectionner"
sizeLimit="10000000" fileLimit="5" />
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Actions -->
<div class="card">
<h5>Finalisation</h5>
<div class="surface-50 p-4 border-round mb-4">
<div class="flex align-items-center">
<i class="pi pi-info-circle text-blue-500 mr-3"></i>
<div>
<div class="font-medium text-900">Vérifiez toutes les informations</div>
<div class="text-600">L'événement sera créé avec le statut "Planifié" et pourra être modifié ultérieurement</div>
</div>
</div>
</div>
<div class="flex flex-wrap gap-2">
<p:commandButton value="🎯 Créer l'événement" icon="pi pi-check"
styleClass="ui-button ui-button-success"
action="#{creationEvenementBean.creerEvenement}"
update="messages"
disabled="#{!creationEvenementBean.formulaireValide}" />
<p:commandButton value="💾 Enregistrer brouillon" icon="pi pi-save"
styleClass="ui-button ui-button-outlined ui-button-info"
action="#{creationEvenementBean.enregistrerBrouillon}"
update="messages" />
<p:commandButton value="👁️ Prévisualiser" icon="pi pi-eye"
styleClass="ui-button ui-button-outlined ui-button-warning"
onclick="PF('dlgPreview').show();"
type="button" />
<p:commandButton value="🔄 Réinitialiser" icon="pi pi-refresh"
styleClass="ui-button ui-button-outlined ui-button-secondary"
type="reset"
onclick="return confirm('Êtes-vous sûr de vouloir réinitialiser le formulaire ?');" />
<p:commandButton value="❌ Annuler" icon="pi pi-times"
styleClass="ui-button ui-button-outlined ui-button-danger"
action="/pages/admin/evenements/liste?faces-redirect=true"
immediate="true"
onclick="return confirm('Êtes-vous sûr de vouloir annuler la création ?');" />
</div>
<div class="mt-4 text-600">
<small>
<i class="pi pi-shield mr-1"></i>
Les données de l'événement sont sécurisées et conformes RGPD
</small>
</div>
</div>
</h:form>
<!-- Dialog Prévisualisation -->
<p:dialog header="Prévisualisation de l'événement" widgetVar="dlgPreview" modal="true" width="800" height="600">
<h:form id="formPreview">
<div class="card border-none p-0">
<div class="flex align-items-start mb-4">
<div class="border-round p-3 mr-3" style="background: var(--primary-color);">
<i class="pi pi-calendar text-white text-2xl"></i>
</div>
<div class="flex-1">
<h4 class="mt-0 mb-2">#{creationEvenementBean.evenement.titre}</h4>
<div class="text-600 mb-2">#{creationEvenementBean.evenement.typeEvenementLibelle}</div>
<p:tag value="#{creationEvenementBean.evenement.priorite}"
severity="#{creationEvenementBean.evenement.prioriteSeverity}" />
</div>
</div>
<div class="grid">
<div class="col-12 md:col-6">
<h6>📅 Date et Heure</h6>
<p>#{creationEvenementBean.evenement.dateCompleteFormatee}</p>
<h6>📍 Lieu</h6>
<p>#{creationEvenementBean.evenement.lieu}</p>
<small class="text-600">#{creationEvenementBean.evenement.adresse}</small>
<h6>👥 Participants</h6>
<p>Maximum #{creationEvenementBean.evenement.placesMax} places</p>
<p>Public: #{creationEvenementBean.evenement.publicCibleFormate}</p>
</div>
<div class="col-12 md:col-6">
<h6>💰 Tarification</h6>
<p>
<span class="text-green-500 font-bold" rendered="#{!creationEvenementBean.evenement.payant}">Gratuit</span>
<span rendered="#{creationEvenementBean.evenement.payant}">
Prix: #{creationEvenementBean.evenement.prix} FCFA
</span>
</p>
<h6>🔔 Notifications</h6>
<p>Canaux: #{creationEvenementBean.evenement.canauxNotificationFormates}</p>
<h6>👨‍💼 Organisateur</h6>
<p>#{creationEvenementBean.evenement.organisateur}</p>
</div>
<div class="col-12">
<h6>📝 Description</h6>
<p class="line-height-3">#{creationEvenementBean.evenement.description}</p>
</div>
</div>
</div>
<div class="flex gap-2 mt-4">
<p:commandButton value="Modifier" icon="pi pi-pencil"
styleClass="ui-button-warning"
onclick="PF('dlgPreview').hide();"
type="button" />
<p:commandButton value="Créer maintenant" icon="pi pi-check"
styleClass="ui-button-success"
action="#{creationEvenementBean.creerEvenement}"
update=":formCreation:messages"
oncomplete="if(!args.validationFailed) PF('dlgPreview').hide();" />
<p:commandButton value="Fermer" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgPreview').hide();"
type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,588 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Événements - UnionFlow</ui:define>
<ui:define name="content">
<div class="ui-fluid">
<!-- En-tête principal avec disposition Freya stricte -->
<div class="card">
<div class="formgrid grid">
<div class="field col-12 lg:col-8">
<h2 class="text-primary font-bold mb-2">
<i class="pi pi-calendar text-blue-500 mr-2"></i>
Gestion des Événements
</h2>
<p class="text-600 mt-0">
Planification et suivi des activités associatives •
<span class="font-semibold">#{evenementsBean.statistiques.totalEvenements} événements</span>
<span class="font-semibold text-green-600">#{evenementsBean.statistiques.evenementsActifs} actifs</span>
</p>
</div>
<div class="field col-12 lg:col-4 text-right">
<h:form id="formActionsEntete">
<p:commandButton icon="pi pi-plus"
title="Nouvel événement"
styleClass="ui-button-success ui-button-sm mr-3"
onclick="PF('dlgNouvelEvenement').show();" />
<p:commandButton icon="pi pi-calendar"
title="Planning mensuel"
styleClass="ui-button-info ui-button-outlined ui-button-sm mr-3"
onclick="PF('dlgPlanningMensuel').show();" />
<p:commandButton icon="pi pi-download"
title="Exporter"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
action="#{evenementsBean.exporterEvenements}" />
</h:form>
</div>
</div>
</div>
<!-- KPIs avec grille Freya stricte -->
<div class="formgrid grid">
<!-- KPI 1: Total Événements -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Total Événements" />
<ui:param name="value" value="#{evenementsBean.statistiques.totalEvenements}" />
<ui:param name="icon" value="pi-calendar" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="growthValue" value="#{evenementsBean.statistiques.evenementsCeMois}" />
<ui:param name="growthLabel" value="ce mois" />
<ui:param name="growthType" value="number" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 2: Événements Actifs -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Événements Actifs" />
<ui:param name="value" value="#{evenementsBean.statistiques.evenementsActifs}" />
<ui:param name="icon" value="pi-check" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="progressValue" value="#{evenementsBean.statistiques.tauxParticipationMoyen}" />
<ui:param name="noDataLabel" value="#{evenementsBean.statistiques.tauxParticipationMoyen}% de participation" />
<ui:param name="showGrowth" value="false" />
</ui:include>
<!-- KPI 3: Participants Inscrits -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Participants" />
<ui:param name="value" value="#{evenementsBean.statistiques.participantsTotal}" />
<ui:param name="icon" value="pi-users" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="statusIcon" value="pi-info-circle" />
<ui:param name="statusLabel" value="Moyenne" />
<ui:param name="statusValue" value="#{evenementsBean.statistiques.moyenneParticipants}/événement" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 4: Budget Total -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Budget Total" />
<ui:param name="value" value="#{evenementsBean.statistiques.budgetTotal}" />
<ui:param name="icon" value="pi-dollar" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="statusIcon" value="pi-trending-up" />
<ui:param name="statusLabel" value="Suivi budgétaire" />
<ui:param name="statusValue" value="optimal" />
<ui:param name="showProgress" value="false" />
</ui:include>
</div>
<!-- Calendrier visuel des événements avec structure Freya -->
<div class="card">
<h5 class="mb-3">
<i class="pi pi-calendar text-blue-500 mr-2"></i>
Événements à Venir
</h5>
<div class="formgrid grid">
<ui:repeat value="#{evenementsBean.evenementsProchains}" var="event" varStatus="status">
<div class="field col-12 md:col-6 lg:col-4">
<div class="surface-50 border-round-lg p-3 hover:surface-100 transition-colors transition-duration-150">
<div class="flex align-items-start justify-content-between mb-3">
<div class="flex align-items-center">
<div class="flex align-items-center justify-content-center bg-primary-100 border-round-lg mr-3"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi #{event.typeIcon} text-primary-600"></i>
</div>
<div>
<h6 class="text-900 font-medium m-0 mb-1">#{event.titre}</h6>
<p:tag value="#{event.typeLibelle}"
severity="#{event.typeSeverity}"
styleClass="text-xs" />
</div>
</div>
<span class="text-500 text-sm font-semibold">#{event.joursRestants}j</span>
</div>
<div class="text-600 mb-3">
<div class="flex align-items-center mb-2">
<i class="pi pi-calendar text-blue-500 mr-2"></i>
<span class="text-sm">#{event.dateDebutFormatee}</span>
</div>
<div class="flex align-items-center mb-2">
<i class="pi pi-map-marker text-orange-500 mr-2"></i>
<span class="text-sm">#{event.lieu}</span>
</div>
<div class="flex align-items-center">
<i class="pi pi-users text-green-500 mr-2"></i>
<span class="text-sm">#{event.participantsInscrits}/#{event.capaciteMax} participants</span>
</div>
</div>
<div class="flex justify-content-between align-items-center">
<div class="flex-1 mr-3">
<p:progressBar value="#{event.tauxInscription}"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem;" />
<div class="text-500 text-xs mt-1">#{event.tauxInscription}% rempli</div>
</div>
<h:form>
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
title="Voir détails">
<f:setPropertyActionListener target="#{evenementsBean.evenementSelectionne}" value="#{event}" />
</p:commandButton>
</h:form>
</div>
</div>
</div>
</ui:repeat>
</div>
</div>
<!-- Section Filtres avec structure Freya -->
<div class="card">
<h5 class="mb-3">
<i class="pi pi-filter text-blue-500 mr-2"></i>
Filtres et Recherche
</h5>
<h:form id="formFiltres">
<div class="formgrid grid">
<!-- Ligne 1: 4 champs principaux -->
<div class="field col-12 md:col-6 lg:col-3">
<label for="searchTitre" class="block text-900 font-medium mb-2">Titre de l'événement</label>
<p:inputText id="searchTitre"
value="#{evenementsBean.filtres.titre}"
placeholder="Rechercher par titre..."
styleClass="w-full">
<p:ajax event="keyup" delay="300"
update=":formTableEvenements:dtEvenements" />
</p:inputText>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="filterType" class="block text-900 font-medium mb-2">Type d'événement</label>
<p:selectOneMenu id="filterType"
value="#{evenementsBean.filtres.type}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Réunion" itemValue="REUNION" />
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
<f:selectItem itemLabel="Action Sociale" itemValue="ACTION_SOCIALE" />
<f:selectItem itemLabel="Assemblée Générale" itemValue="ASSEMBLEE_GENERALE" />
<f:selectItem itemLabel="Événement Festif" itemValue="EVENEMENT_FESTIF" />
<p:ajax update=":formTableEvenements:dtEvenements" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="filterStatut" class="block text-900 font-medium mb-2">Statut</label>
<p:selectOneMenu id="filterStatut"
value="#{evenementsBean.filtres.statut}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="Planifié" itemValue="PLANIFIE" />
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
<f:selectItem itemLabel="Terminé" itemValue="TERMINE" />
<f:selectItem itemLabel="Annulé" itemValue="ANNULE" />
<p:ajax update=":formTableEvenements:dtEvenements" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="filterPriorite" class="block text-900 font-medium mb-2">Priorité</label>
<p:selectOneMenu id="filterPriorite"
value="#{evenementsBean.filtres.priorite}"
styleClass="w-full">
<f:selectItem itemLabel="Toutes les priorités" itemValue="" />
<f:selectItem itemLabel="Faible" itemValue="FAIBLE" />
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="Élevée" itemValue="ELEVEE" />
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
<p:ajax update=":formTableEvenements:dtEvenements" />
</p:selectOneMenu>
</div>
<!-- Ligne 2: Période et Organisateur -->
<div class="field col-12 md:col-6 lg:col-4">
<label for="filterDateDebut" class="block text-900 font-medium mb-2">Période</label>
<div class="flex gap-2">
<p:datePicker id="filterDateDebut"
value="#{evenementsBean.filtres.dateDebut}"
placeholder="Date début"
styleClass="w-full">
<p:ajax update=":formTableEvenements:dtEvenements" />
</p:datePicker>
<p:datePicker id="filterDateFin"
value="#{evenementsBean.filtres.dateFin}"
placeholder="Date fin"
styleClass="w-full">
<p:ajax update=":formTableEvenements:dtEvenements" />
</p:datePicker>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-4">
<label for="filterOrganisateur" class="block text-900 font-medium mb-2">Organisateur</label>
<p:inputText id="filterOrganisateur"
value="#{evenementsBean.filtres.organisateur}"
placeholder="Filtrer par organisateur..."
styleClass="w-full">
<p:ajax event="keyup" delay="300"
update=":formTableEvenements:dtEvenements" />
</p:inputText>
</div>
<div class="field col-12 md:col-12 lg:col-4">
<label class="block text-900 font-medium mb-2">&#160;</label>
<div class="flex justify-content-start">
<p:commandButton value="Réinitialiser"
icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary ui-button-sm"
action="#{evenementsBean.reinitialiserFiltres}"
update="@form :formTableEvenements:dtEvenements" />
</div>
</div>
</div>
</h:form>
</div>
<!-- Table des Événements avec structure Freya -->
<div class="card">
<h:form id="formTableEvenements">
<div class="flex align-items-center justify-content-between mb-3">
<h5 class="m-0">
<i class="pi pi-list text-primary mr-2"></i>
Liste des Événements
</h5>
<div class="flex gap-3 align-items-center">
<p:commandButton value="Actions groupées"
icon="pi pi-bars"
styleClass="ui-button-warning ui-button-sm"
onclick="PF('dlgActionsGroupees').show();"
disabled="#{empty evenementsBean.evenementsSelectionnes}" />
<p:commandButton value="Export Excel"
icon="pi pi-file-excel"
styleClass="ui-button-success ui-button-outlined ui-button-sm"
action="#{evenementsBean.exporterExcel}" />
</div>
</div>
<p:dataTable id="dtEvenements"
value="#{evenementsBean.evenementsFiltres}"
var="evenement"
selection="#{evenementsBean.evenementsSelectionnes}"
rowKey="#{evenement.id}"
paginator="true"
rows="20"
paginatorPosition="bottom"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,20,50,100"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords} événements"
styleClass="p-datatable-sm p-datatable-gridlines p-datatable-striped"
emptyMessage="Aucun événement trouvé">
<p:column selectionMode="multiple" style="width:3rem" exportable="false"/>
<p:column headerText="Événement" sortBy="#{evenement.titre}" filterBy="#{evenement.titre}">
<div class="flex align-items-center">
<div class="flex align-items-center justify-content-center bg-primary-100 border-circle mr-2"
style="width: 2rem; height: 2rem;">
<i class="pi #{evenement.typeEvenementIcon} text-primary-600"></i>
</div>
<div>
<div class="text-900 font-medium">#{evenement.titre}</div>
<div class="text-500 text-xs">#{evenement.description}</div>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{evenement.typeEvenement}" filterBy="#{evenement.typeEvenement}" style="width:8rem">
<p:tag value="#{evenement.typeEvenementLibelle}"
severity="#{evenement.typeEvenementSeverity}"
icon="pi #{evenement.typeEvenementIcon}"
styleClass="text-xs" />
</p:column>
<p:column headerText="Date et Heure" sortBy="#{evenement.dateDebut}" style="width:10rem">
<div>
<div class="text-900 font-medium text-sm">#{evenement.dateDebutFormatee}</div>
<div class="text-500 text-xs">#{evenement.heureDebutFormatee} - #{evenement.heureFinFormatee}</div>
</div>
</p:column>
<p:column headerText="Lieu" style="width:10rem">
<div>
<div class="text-900 font-medium text-sm">#{evenement.lieu}</div>
<div class="text-500 text-xs">#{evenement.adresse}</div>
</div>
</p:column>
<p:column headerText="Organisateur">
<div class="flex align-items-center" rendered="#{evenement.organisateur != null}">
<div class="bg-300 border-circle mr-2" style="width: 1.5rem; height: 1.5rem;"></div>
<div>
<div class="text-900 text-sm">#{evenement.organisateur}</div>
<div class="text-500 text-xs">#{evenement.organisateurEmail}</div>
</div>
</div>
<span class="text-400 text-xs" rendered="#{evenement.organisateur == null}">
Aucun organisateur
</span>
</p:column>
<p:column headerText="Participants" sortBy="#{evenement.participantsInscrits}" style="width:8rem; text-align:center">
<div class="text-center">
<div class="text-900 font-bold">#{evenement.participantsInscrits}</div>
<div class="text-500 text-xs mb-1">/#{evenement.capaciteMax} places</div>
<p:progressBar value="#{evenement.tauxInscription}"
showValue="false"
styleClass="surface-200"
style="height: 0.3rem;" />
</div>
</p:column>
<p:column headerText="Budget" sortBy="#{evenement.budget}" style="width:8rem">
<div class="text-900 font-bold text-right">#{evenement.budgetFormatte}</div>
</p:column>
<p:column headerText="Priorité" sortBy="#{evenement.priorite}" filterBy="#{evenement.priorite}" style="width:7rem">
<p:tag value="#{evenement.priorite}"
severity="#{evenement.prioriteSeverity}"
styleClass="text-xs w-full" />
</p:column>
<p:column headerText="Statut" sortBy="#{evenement.statut}" filterBy="#{evenement.statut}" style="width:8rem">
<p:tag value="#{evenement.statut}"
severity="#{evenement.statutSeverity}"
icon="pi #{evenement.statutIcon}"
styleClass="text-xs w-full" />
</p:column>
<p:column headerText="Actions" style="width:8rem" exportable="false">
<h:form id="formActions#{evenement.id}">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
onclick="PF('dlgDetailsEvenement').show();"
title="Voir détails">
<f:setPropertyActionListener target="#{evenementsBean.evenementSelectionne}" value="#{evenement}" />
</p:commandButton>
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-warning ui-button-sm"
onclick="PF('dlgModifierEvenement').show();"
title="Modifier">
<f:setPropertyActionListener target="#{evenementsBean.evenementSelectionne}" value="#{evenement}" />
</p:commandButton>
<p:commandButton icon="pi pi-cog"
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
onclick="PF('dlgActionsEvenement').show();"
title="Actions">
<f:setPropertyActionListener target="#{evenementsBean.evenementSelectionne}" value="#{evenement}" />
</p:commandButton>
</div>
</h:form>
</p:column>
</p:dataTable>
</h:form>
</div>
</div>
<!-- Dialogs avec structure Freya -->
<!-- Dialog Nouvel Événement -->
<p:dialog header="Créer un Nouvel Événement"
widgetVar="dlgNouvelEvenement"
modal="true"
width="800"
height="auto"
resizable="false">
<h:form id="formNouvelEvenement">
<div class="ui-fluid formgrid grid">
<div class="field col-12 md:col-6">
<label for="newTitre" class="block text-900 font-medium mb-2">Titre de l'événement *</label>
<p:inputText id="newTitre"
value="#{evenementsBean.nouvelEvenement.titre}"
required="true"
placeholder="Ex: Assemblée Générale 2024" />
</div>
<div class="field col-12 md:col-6">
<label for="newType" class="block text-900 font-medium mb-2">Type d'événement *</label>
<p:selectOneMenu id="newType"
value="#{evenementsBean.nouvelEvenement.typeEvenement}"
required="true">
<f:selectItem itemLabel="Sélectionner un type" itemValue="" />
<f:selectItem itemLabel="Réunion" itemValue="REUNION" />
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
<f:selectItem itemLabel="Action Sociale" itemValue="ACTION_SOCIALE" />
<f:selectItem itemLabel="Assemblée Générale" itemValue="ASSEMBLEE_GENERALE" />
<f:selectItem itemLabel="Événement Festif" itemValue="EVENEMENT_FESTIF" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<label for="newDateDebut" class="block text-900 font-medium mb-2">Date de début *</label>
<p:datePicker id="newDateDebut"
value="#{evenementsBean.nouvelEvenement.dateDebut}"
required="true" />
</div>
<div class="field col-12 md:col-6">
<label for="newDateFin" class="block text-900 font-medium mb-2">Date de fin</label>
<p:datePicker id="newDateFin"
value="#{evenementsBean.nouvelEvenement.dateFin}" />
</div>
<div class="field col-12 md:col-6">
<label for="newLieu" class="block text-900 font-medium mb-2">Lieu *</label>
<p:inputText id="newLieu"
value="#{evenementsBean.nouvelEvenement.lieu}"
required="true"
placeholder="Ex: Salle de conférence" />
</div>
<div class="field col-12 md:col-6">
<label for="newCapacite" class="block text-900 font-medium mb-2">Capacité maximum</label>
<p:inputNumber id="newCapacite"
value="#{evenementsBean.nouvelEvenement.capaciteMax}"
placeholder="100" />
</div>
<div class="field col-12">
<label for="newAdresse" class="block text-900 font-medium mb-2">Adresse complète</label>
<p:inputTextarea id="newAdresse"
value="#{evenementsBean.nouvelEvenement.adresse}"
rows="2"
placeholder="Adresse complète de l'événement..." />
</div>
<div class="field col-12">
<label for="newDescription" class="block text-900 font-medium mb-2">Description</label>
<p:inputTextarea id="newDescription"
value="#{evenementsBean.nouvelEvenement.description}"
rows="3"
placeholder="Description détaillée de l'événement..." />
</div>
<div class="field col-12 md:col-4">
<label for="newPriorite" class="block text-900 font-medium mb-2">Priorité</label>
<p:selectOneMenu id="newPriorite"
value="#{evenementsBean.nouvelEvenement.priorite}">
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
<f:selectItem itemLabel="Faible" itemValue="FAIBLE" />
<f:selectItem itemLabel="Élevée" itemValue="ELEVEE" />
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-4">
<label for="newOrganisateur" class="block text-900 font-medium mb-2">Organisateur</label>
<p:inputText id="newOrganisateur"
value="#{evenementsBean.nouvelEvenement.organisateur}"
placeholder="Nom de l'organisateur" />
</div>
<div class="field col-12 md:col-4">
<label for="newBudget" class="block text-900 font-medium mb-2">Budget estimé</label>
<p:inputNumber id="newBudget"
value="#{evenementsBean.nouvelEvenement.budget}"
mode="currency"
currency="XOF"
locale="fr-CI"
placeholder="50000" />
</div>
</div>
<div class="flex justify-content-end gap-2 mt-3">
<p:commandButton value="Annuler"
icon="pi pi-times"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
onclick="PF('dlgNouvelEvenement').hide();"
type="button" />
<p:commandButton value="Créer l'événement"
icon="pi pi-check"
styleClass="ui-button-success ui-button-sm"
action="#{evenementsBean.creerEvenement}"
update="@form :formTableEvenements:dtEvenements"
oncomplete="if(!args.validationFailed) PF('dlgNouvelEvenement').hide();" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Actions Événement -->
<p:dialog header="Actions sur l'Événement"
widgetVar="dlgActionsEvenement"
modal="true"
width="400"
height="auto"
resizable="false">
<h:form id="formActionsEvenement">
<div class="surface-50 border-round-lg p-3 mb-3">
<div class="text-500 text-sm mb-1">Événement sélectionné</div>
<div class="text-900 font-bold">#{evenementsBean.evenementSelectionne.titre}</div>
<div class="text-500 text-sm">#{evenementsBean.evenementSelectionne.dateDebutFormatee}</div>
</div>
<div class="flex flex-column gap-2">
<p:commandButton value="Gérer les participants"
icon="pi pi-users"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
action="#{evenementsBean.gererParticipants}" />
<p:commandButton value="Envoyer invitations"
icon="pi pi-send"
styleClass="ui-button-success ui-button-outlined ui-button-sm w-full"
action="#{evenementsBean.envoyerInvitations}" />
<p:commandButton value="Rapports de participation"
icon="pi pi-chart-bar"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full"
action="#{evenementsBean.voirRapports}" />
<p:commandButton value="Planning mensuel"
icon="pi pi-calendar"
styleClass="ui-button-warning ui-button-outlined ui-button-sm w-full"
onclick="PF('dlgPlanningMensuel').show();" />
<p:commandButton value="Dupliquer l'événement"
icon="pi pi-copy"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
action="#{evenementsBean.dupliquerEvenement}" />
<hr class="surface-border" />
<p:commandButton value="Annuler l'événement"
icon="pi pi-ban"
styleClass="ui-button-danger ui-button-sm w-full"
onclick="return confirm('ATTENTION: Confirmer l\'annulation ?');"
action="#{evenementsBean.annulerEvenement}"
rendered="#{evenementsBean.evenementSelectionne.statut != 'ANNULE'}" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,430 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Événements - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-calendar text-blue-500 mr-2"></i>
Gestion des Événements
</h3>
<p class="text-600 m-0">#{evenementBean.totalEvenements} événements • #{evenementBean.evenementsActifs} actifs • #{evenementBean.prochainEvenement}</p>
</div>
<div class="flex gap-2">
<p:commandButton value="Nouvel événement"
icon="pi pi-plus"
styleClass="ui-button-success"
action="/pages/admin/evenements/creation?faces-redirect=true" />
<p:commandButton value="Calendrier"
icon="pi pi-calendar-plus"
styleClass="ui-button-outlined ui-button-info"
action="#{evenementBean.voirCalendrier}" />
<p:commandButton value="Import/Export"
icon="pi pi-download"
styleClass="ui-button-outlined ui-button-secondary"
action="#{evenementBean.importExport}" />
</div>
</div>
</div>
</div>
</div>
<!-- Statistiques -->
<div class="grid">
<div class="col-12 md:col-3">
<div class="card bg-blue-100 border-left-3 border-blue-500">
<div class="flex justify-content-between">
<div>
<div class="text-blue-900 font-bold text-2xl">#{evenementBean.evenementsActifs}</div>
<div class="text-blue-700">Événements Actifs</div>
</div>
<div class="bg-blue-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-calendar text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-green-100 border-left-3 border-green-500">
<div class="flex justify-content-between">
<div>
<div class="text-green-900 font-bold text-2xl">#{evenementBean.totalParticipants}</div>
<div class="text-green-700">Participants Inscrits</div>
</div>
<div class="bg-green-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-users text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-purple-100 border-left-3 border-purple-500">
<div class="flex justify-content-between">
<div>
<div class="text-purple-900 font-bold text-2xl">#{evenementBean.revenusEvenements}</div>
<div class="text-purple-700">Revenus Événements</div>
</div>
<div class="bg-purple-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-dollar text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-orange-100 border-left-3 border-orange-500">
<div class="flex justify-content-between">
<div>
<div class="text-orange-900 font-bold text-2xl">#{evenementBean.tauxParticipation}%</div>
<div class="text-orange-700">Taux Participation</div>
</div>
<div class="bg-orange-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-chart-pie text-xl"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Prochains événements (aperçu rapide) -->
<div class="card">
<h5>
<i class="pi pi-clock mr-2"></i>
Prochains Événements
</h5>
<div class="grid">
<ui:repeat value="#{evenementBean.prochainsEvenements}" var="event" varStatus="status">
<div class="col-12 md:col-6 lg:col-4">
<div class="surface-card border-round p-3 border-left-3 #{event.prioriteColor}">
<div class="flex align-items-start justify-content-between mb-2">
<div>
<span class="text-500 font-medium">#{event.dateFormatee}</span>
<div class="text-900 font-medium text-xl mt-1">#{event.titre}</div>
</div>
<p:tag value="#{event.statut}" severity="#{event.statutSeverity}" />
</div>
<div class="text-600 mb-3">
<i class="pi pi-map-marker mr-1"></i>
#{event.lieu}
</div>
<div class="flex align-items-center justify-content-between">
<span class="text-green-500 font-bold">
#{event.inscrits}/#{event.placesMax} inscrits
</span>
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-sm"
action="#{evenementBean.voirEvenement(event)}" />
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-sm"
action="#{evenementBean.modifierEvenement(event)}" />
</div>
</div>
</div>
</div>
</ui:repeat>
</div>
</div>
<!-- Liste complète des événements -->
<div class="card">
<h:form id="formEvenements">
<h5>Tous les Événements</h5>
<!-- Filtres -->
<p:toolbar>
<p:toolbarGroup>
<div class="flex align-items-center gap-2">
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<p:inputText placeholder="Rechercher..."
value="#{evenementBean.searchFilter}">
<p:ajax event="keyup" update="dtEvenements" />
</p:inputText>
</span>
<p:selectOneMenu value="#{evenementBean.statutFilter}">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="Planifié" itemValue="PLANIFIE" />
<f:selectItem itemLabel="Ouvert aux inscriptions" itemValue="OUVERT" />
<f:selectItem itemLabel="Complet" itemValue="COMPLET" />
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
<f:selectItem itemLabel="Terminé" itemValue="TERMINE" />
<f:selectItem itemLabel="Annulé" itemValue="ANNULE" />
<p:ajax update="dtEvenements" />
</p:selectOneMenu>
<p:selectOneMenu value="#{evenementBean.typeFilter}">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Réunion" itemValue="REUNION" />
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
<f:selectItem itemLabel="Loisir" itemValue="LOISIR" />
<f:selectItem itemLabel="Cérémonie" itemValue="CEREMONIE" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
<p:ajax update="dtEvenements" />
</p:selectOneMenu>
<p:calendar value="#{evenementBean.dateFilter}"
pattern="dd/MM/yyyy" showIcon="true"
placeholder="Filtrer par date">
<p:ajax event="dateSelect" update="dtEvenements" />
</p:calendar>
</div>
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:commandButton icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary"
action="#{evenementBean.actualiser}"
update="@form"
title="Actualiser" />
</p:toolbarGroup>
</p:toolbar>
<!-- DataTable -->
<p:dataTable id="dtEvenements"
var="evenement"
value="#{evenementBean.evenements}"
paginator="true"
rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="5,10,25,50"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
selection="#{evenementBean.selectedEvenements}"
rowKey="#{evenement.id}"
selectionMode="multiple"
styleClass="mt-3">
<p:column selectionMode="multiple" style="width:50px" />
<p:column headerText="Titre" sortBy="#{evenement.titre}">
<div class="flex align-items-center">
<div class="border-round p-2 mr-3" style="background: #{evenement.couleurCategorie};">
<i class="pi #{evenement.iconeType} text-white"></i>
</div>
<div>
<div class="font-medium text-900">#{evenement.titre}</div>
<small class="text-600">#{evenement.typeEvenementLibelle}</small>
</div>
</div>
</p:column>
<p:column headerText="Date/Heure" sortBy="#{evenement.dateDebut}" style="width:180px">
<div>
<div class="font-medium">#{evenement.dateDebut}</div>
<small class="text-600">#{evenement.heureDebut} - #{evenement.heureFin}</small>
</div>
</p:column>
<p:column headerText="Lieu" sortBy="#{evenement.lieu}">
<div class="flex align-items-center">
<i class="pi pi-map-marker text-500 mr-2"></i>
<span>#{evenement.lieu}</span>
</div>
</p:column>
<p:column headerText="Statut" sortBy="#{evenement.statut}" style="width:120px">
<p:tag value="#{evenement.statut}"
severity="#{evenement.statutSeverity}"
icon="pi #{evenement.statutIcon}" />
</p:column>
<p:column headerText="Participants" style="width:120px">
<div class="text-center">
<div class="font-bold">#{evenement.nombreInscrits}/#{evenement.placesMax}</div>
<p:progressBar value="#{evenement.tauxRemplissage}"
labelTemplate=""
styleClass="h-1rem" />
</div>
</p:column>
<p:column headerText="Prix" sortBy="#{evenement.prix}" style="width:100px">
<h:outputText value="#{evenement.prix}" styleClass="font-bold" rendered="#{evenement.prix > 0}">
<f:convertNumber type="currency" currencySymbol="FCFA " />
</h:outputText>
<span class="text-green-500 font-medium" rendered="#{evenement.prix == 0}">Gratuit</span>
</p:column>
<p:column headerText="Organisateur" sortBy="#{evenement.organisateur}">
<h:outputText value="#{evenement.organisateur}" />
</p:column>
<p:column headerText="Actions" style="width:200px">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
action="#{evenementBean.voirEvenement(evenement)}"
title="Voir détails" />
<p:commandButton icon="pi pi-users"
styleClass="ui-button-rounded ui-button-text ui-button-success"
action="#{evenementBean.gererParticipants(evenement)}"
title="Gérer participants" />
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-warning"
action="#{evenementBean.modifierEvenement(evenement)}"
title="Modifier" />
<p:commandButton icon="pi pi-copy"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
action="#{evenementBean.dupliquerEvenement(evenement)}"
title="Dupliquer" />
<p:commandButton icon="pi pi-times"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
action="#{evenementBean.annulerEvenement(evenement)}"
onclick="return confirm('Êtes-vous sûr de vouloir annuler cet événement ?');"
title="Annuler"
disabled="#{evenement.statut == 'TERMINE' or evenement.statut == 'ANNULE'}" />
</div>
</p:column>
</p:dataTable>
<!-- Actions groupées -->
<div class="mt-3 flex justify-content-between align-items-center">
<div>
<span class="text-600">#{evenementBean.selectedEvenements.size()} événement(s) sélectionné(s)</span>
</div>
<div class="flex gap-2">
<p:commandButton value="Notification groupée"
icon="pi pi-bell"
styleClass="ui-button-outlined ui-button-info"
action="#{evenementBean.notificationGroupee}"
disabled="#{empty evenementBean.selectedEvenements}" />
<p:commandButton value="Exporter sélection"
icon="pi pi-file-excel"
styleClass="ui-button-outlined ui-button-success"
action="#{evenementBean.exporterSelection}"
disabled="#{empty evenementBean.selectedEvenements}" />
<p:commandButton value="Annuler sélection"
icon="pi pi-ban"
styleClass="ui-button-outlined ui-button-danger"
action="#{evenementBean.annulerSelection}"
onclick="return confirm('Êtes-vous sûr de vouloir annuler les événements sélectionnés ?');"
disabled="#{empty evenementBean.selectedEvenements}" />
</div>
</div>
</h:form>
</div>
<!-- Calendrier intégré (optionnel) -->
<div class="card">
<h5>
<i class="pi pi-calendar mr-2"></i>
Vue Calendrier
</h5>
<p:schedule value="#{evenementBean.eventModel}"
widgetVar="schedule"
timeZone="GMT+0"
clientTimeZone="GMT+0"
locale="fr"
style="height: 600px;"
view="month">
<p:ajax event="eventSelect" listener="#{evenementBean.onEventSelect}" />
<p:ajax event="dateSelect" listener="#{evenementBean.onDateSelect}" />
<p:ajax event="eventMove" listener="#{evenementBean.onEventMove}" />
<p:ajax event="eventResize" listener="#{evenementBean.onEventResize}" />
</p:schedule>
</div>
<!-- Dialog Détails événement -->
<p:dialog header="Détails de l'événement" widgetVar="dlgDetails" modal="true" width="700" height="500">
<h:form id="formDetails" rendered="#{evenementBean.evenementSelectionne != null}">
<div class="grid">
<div class="col-12 md:col-6">
<div class="field">
<label class="font-medium">Titre</label>
<div class="text-900">#{evenementBean.evenementSelectionne.titre}</div>
</div>
<div class="field">
<label class="font-medium">Type</label>
<div class="text-900">#{evenementBean.evenementSelectionne.typeEvenementLibelle}</div>
</div>
<div class="field">
<label class="font-medium">Date et heure</label>
<div class="text-900">
#{evenementBean.evenementSelectionne.dateComplete}
</div>
</div>
<div class="field">
<label class="font-medium">Lieu</label>
<div class="text-900">#{evenementBean.evenementSelectionne.lieu}</div>
</div>
</div>
<div class="col-12 md:col-6">
<div class="field">
<label class="font-medium">Statut</label>
<div>
<p:tag value="#{evenementBean.evenementSelectionne.statut}"
severity="#{evenementBean.evenementSelectionne.statutSeverity}" />
</div>
</div>
<div class="field">
<label class="font-medium">Participants</label>
<div class="text-900">
#{evenementBean.evenementSelectionne.nombreInscrits}/#{evenementBean.evenementSelectionne.placesMax}
</div>
</div>
<div class="field">
<label class="font-medium">Prix</label>
<div class="text-900">
<h:outputText value="#{evenementBean.evenementSelectionne.prix}" rendered="#{evenementBean.evenementSelectionne.prix > 0}">
<f:convertNumber type="currency" currencySymbol="FCFA " />
</h:outputText>
<span class="text-green-500" rendered="#{evenementBean.evenementSelectionne.prix == 0}">Gratuit</span>
</div>
</div>
<div class="field">
<label class="font-medium">Organisateur</label>
<div class="text-900">#{evenementBean.evenementSelectionne.organisateur}</div>
</div>
</div>
<div class="col-12">
<div class="field">
<label class="font-medium">Description</label>
<div class="text-900 line-height-3">#{evenementBean.evenementSelectionne.description}</div>
</div>
</div>
</div>
<div class="flex gap-2 mt-4">
<p:commandButton value="Modifier" icon="pi pi-pencil"
styleClass="ui-button-warning"
action="#{evenementBean.modifierEvenement(evenementBean.evenementSelectionne)}"
oncomplete="PF('dlgDetails').hide();" />
<p:commandButton value="Gérer participants" icon="pi pi-users"
styleClass="ui-button-success"
action="#{evenementBean.gererParticipants(evenementBean.evenementSelectionne)}"
oncomplete="PF('dlgDetails').hide();" />
<p:commandButton value="Fermer" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgDetails').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,517 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Participants - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-users text-blue-500 mr-2"></i>
Gestion des Participants
</h3>
<p class="text-600 m-0">#{participantBean.evenement.titre} • #{participantBean.dateEvenement} • #{participantBean.nombreInscrits}/#{participantBean.placesMax} places</p>
</div>
<div class="flex gap-2">
<p:commandButton value="Inscrire membre"
icon="pi pi-user-plus"
styleClass="ui-button-success"
onclick="PF('dlgInscrireMembre').show();" />
<p:commandButton value="Liste d'attente"
icon="pi pi-clock"
styleClass="ui-button-outlined ui-button-warning"
action="#{participantBean.gererListeAttente}" />
<p:commandButton value="Retour à l'événement"
icon="pi pi-arrow-left"
styleClass="ui-button-outlined ui-button-secondary"
action="#{participantBean.retourEvenement}" />
</div>
</div>
</div>
</div>
</div>
<!-- Statistiques -->
<div class="grid">
<div class="col-12 md:col-3">
<div class="card bg-blue-100 border-left-3 border-blue-500">
<div class="flex justify-content-between">
<div>
<div class="text-blue-900 font-bold text-2xl">#{participantBean.nombreInscrits}</div>
<div class="text-blue-700">Inscrits Confirmés</div>
</div>
<div class="bg-blue-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-check text-xl"></i>
</div>
</div>
<div class="mt-2">
<p:progressBar value="#{participantBean.tauxRemplissage}"
labelTemplate=""
styleClass="h-1rem" />
<small class="text-600">#{participantBean.tauxRemplissage}% de remplissage</small>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-orange-100 border-left-3 border-orange-500">
<div class="flex justify-content-between">
<div>
<div class="text-orange-900 font-bold text-2xl">#{participantBean.enAttente}</div>
<div class="text-orange-700">En Attente</div>
</div>
<div class="bg-orange-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-clock text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-green-100 border-left-3 border-green-500">
<div class="flex justify-content-between">
<div>
<div class="text-green-900 font-bold text-2xl">#{participantBean.montantCollecte}</div>
<div class="text-green-700">Collecté</div>
</div>
<div class="bg-green-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-dollar text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card bg-purple-100 border-left-3 border-purple-500">
<div class="flex justify-content-between">
<div>
<div class="text-purple-900 font-bold text-2xl">#{participantBean.accompagnateurs}</div>
<div class="text-purple-700">Accompagnateurs</div>
</div>
<div class="bg-purple-500 text-white border-round text-center"
style="width: 3rem; height: 3rem; line-height: 3rem;">
<i class="pi pi-user-plus text-xl"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Actions rapides -->
<div class="card">
<h5>Actions Rapides</h5>
<div class="grid">
<div class="col-12 md:col-4">
<div class="surface-50 p-3 border-round text-center">
<i class="pi pi-envelope text-blue-500 text-2xl mb-2"></i>
<div class="font-medium mb-2">Notifications</div>
<p:commandButton value="Envoyer rappel général"
icon="pi pi-send"
styleClass="ui-button-outlined ui-button-info w-full mb-2"
action="#{participantBean.envoyerRappelGeneral}" />
<p:commandButton value="Info dernière minute"
icon="pi pi-exclamation-triangle"
styleClass="ui-button-outlined ui-button-warning w-full"
onclick="PF('dlgInfoDernierMinute').show();" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="surface-50 p-3 border-round text-center">
<i class="pi pi-qrcode text-green-500 text-2xl mb-2"></i>
<div class="font-medium mb-2">Check-in</div>
<p:commandButton value="Scanner QR Code"
icon="pi pi-camera"
styleClass="ui-button-outlined ui-button-success w-full mb-2"
onclick="PF('dlgScannerQR').show();" />
<p:commandButton value="Check-in manuel"
icon="pi pi-check"
styleClass="ui-button-outlined ui-button-secondary w-full"
onclick="PF('dlgCheckinManuel').show();" />
</div>
</div>
<div class="col-12 md:col-4">
<div class="surface-50 p-3 border-round text-center">
<i class="pi pi-file text-purple-500 text-2xl mb-2"></i>
<div class="font-medium mb-2">Rapports</div>
<p:commandButton value="Feuille d'émargement"
icon="pi pi-file-pdf"
styleClass="ui-button-outlined ui-button-danger w-full mb-2"
action="#{participantBean.genererEmargement}" />
<p:commandButton value="Liste participants"
icon="pi pi-file-excel"
styleClass="ui-button-outlined ui-button-success w-full"
action="#{participantBean.exporterListe}" />
</div>
</div>
</div>
</div>
<!-- Liste des participants -->
<div class="card">
<h:form id="formParticipants">
<h5>Liste des Participants</h5>
<!-- Filtres -->
<p:toolbar>
<p:toolbarGroup>
<div class="flex align-items-center gap-2">
<span class="p-input-icon-left">
<i class="pi pi-search"></i>
<p:inputText placeholder="Rechercher..."
value="#{participantBean.searchFilter}">
<p:ajax event="keyup" update="dtParticipants" />
</p:inputText>
</span>
<p:selectOneMenu value="#{participantBean.statutFilter}">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="Confirmé" itemValue="CONFIRME" />
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
<f:selectItem itemLabel="Présent" itemValue="PRESENT" />
<f:selectItem itemLabel="Absent" itemValue="ABSENT" />
<f:selectItem itemLabel="Annulé" itemValue="ANNULE" />
<p:ajax update="dtParticipants" />
</p:selectOneMenu>
<p:selectOneMenu value="#{participantBean.typeFilter}">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Membres" itemValue="MEMBRE" />
<f:selectItem itemLabel="Accompagnateurs" itemValue="ACCOMPAGNATEUR" />
<f:selectItem itemLabel="Invités" itemValue="INVITE" />
<p:ajax update="dtParticipants" />
</p:selectOneMenu>
<p:selectOneMenu value="#{participantBean.paiementFilter}">
<f:selectItem itemLabel="Tous paiements" itemValue="" />
<f:selectItem itemLabel="Payé" itemValue="PAYE" />
<f:selectItem itemLabel="Non payé" itemValue="NON_PAYE" />
<f:selectItem itemLabel="Gratuit" itemValue="GRATUIT" />
<p:ajax update="dtParticipants" />
</p:selectOneMenu>
</div>
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:commandButton icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary"
action="#{participantBean.actualiser}"
update="@form"
title="Actualiser" />
</p:toolbarGroup>
</p:toolbar>
<!-- DataTable -->
<p:dataTable id="dtParticipants"
var="participant"
value="#{participantBean.participants}"
paginator="true"
rows="15"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
rowsPerPageTemplate="10,15,25,50"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
selection="#{participantBean.selectedParticipants}"
rowKey="#{participant.id}"
selectionMode="multiple"
styleClass="mt-3">
<p:column selectionMode="multiple" style="width:50px" />
<p:column headerText="Participant" sortBy="#{participant.nom}">
<div class="flex align-items-center">
<div class="border-circle overflow-hidden mr-3"
style="width: 40px; height: 40px;">
<h:graphicImage value="#{participant.photoUrl}"
style="width: 100%; height: 100%; object-fit: cover;"
rendered="#{participant.photoUrl != null}" />
<div class="bg-primary text-white flex align-items-center justify-content-center w-full h-full"
rendered="#{participant.photoUrl == null}">
<span style="font-size: 0.9rem;">#{participant.initiales}</span>
</div>
</div>
<div>
<div class="font-medium text-900">#{participant.nomComplet}</div>
<div class="text-600 text-sm">
<span>#{participant.numeroMembre}</span>
<span class="mx-2"></span>
<span>#{participant.telephone}</span>
</div>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{participant.type}" style="width:120px">
<p:tag value="#{participant.type}"
severity="#{participant.typeSeverity}"
icon="pi #{participant.typeIcon}" />
</p:column>
<p:column headerText="Statut" sortBy="#{participant.statut}" style="width:120px">
<p:tag value="#{participant.statut}"
severity="#{participant.statutSeverity}"
icon="pi #{participant.statutIcon}" />
</p:column>
<p:column headerText="Inscription" sortBy="#{participant.dateInscription}" style="width:140px">
<div>
<div class="font-medium">#{participant.dateInscription}</div>
<small class="text-600">#{participant.heureInscription}</small>
</div>
</p:column>
<p:column headerText="Paiement" style="width:120px">
<div class="text-center">
<div class="font-bold #{participant.paiementColor}">#{participant.montantPaye}</div>
<p:tag value="#{participant.statutPaiement}"
severity="#{participant.paiementSeverity}"
styleClass="text-xs" />
</div>
</p:column>
<p:column headerText="Accomp." style="width:80px; text-align: center;">
<span class="bg-purple-100 text-purple-800 border-round px-2 py-1 text-sm font-medium"
rendered="#{participant.nombreAccompagnateurs > 0}">
#{participant.nombreAccompagnateurs}
</span>
<span class="text-400" rendered="#{participant.nombreAccompagnateurs == 0}">-</span>
</p:column>
<p:column headerText="Check-in" style="width:100px; text-align: center;">
<i class="pi pi-check-circle text-green-500 text-xl"
rendered="#{participant.presente}"
title="Présent depuis #{participant.heureCheckin}" />
<i class="pi pi-times-circle text-red-400 text-xl"
rendered="#{!participant.presente and participant.statut == 'CONFIRME'}"
title="Pas encore arrivé" />
<span class="text-400" rendered="#{participant.statut != 'CONFIRME'}">-</span>
</p:column>
<p:column headerText="Actions" style="width:180px">
<div class="flex gap-1">
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success"
action="#{participantBean.confirmerParticipant(participant)}"
title="Confirmer"
rendered="#{participant.statut == 'EN_ATTENTE'}" />
<p:commandButton icon="pi pi-qrcode"
styleClass="ui-button-rounded ui-button-text ui-button-info"
action="#{participantBean.checkinParticipant(participant)}"
title="Check-in"
rendered="#{!participant.presente and participant.statut == 'CONFIRME'}" />
<p:commandButton icon="pi pi-undo"
styleClass="ui-button-rounded ui-button-text ui-button-warning"
action="#{participantBean.annulerCheckin(participant)}"
title="Annuler check-in"
rendered="#{participant.presente}" />
<p:commandButton icon="pi pi-envelope"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
action="#{participantBean.envoyerNotification(participant)}"
title="Notifier" />
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-warning"
onclick="#{participantBean.preparerModification(participant)}; PF('dlgModifierParticipant').show();"
title="Modifier" />
<p:commandButton icon="pi pi-times"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
action="#{participantBean.annulerInscription(participant)}"
onclick="return confirm('Êtes-vous sûr de vouloir annuler cette inscription ?');"
title="Annuler inscription" />
</div>
</p:column>
</p:dataTable>
<!-- Actions groupées -->
<div class="mt-3 flex justify-content-between align-items-center">
<div>
<span class="text-600">#{participantBean.selectedParticipants.size()} participant(s) sélectionné(s)</span>
</div>
<div class="flex gap-2">
<p:commandButton value="Check-in groupé"
icon="pi pi-check-circle"
styleClass="ui-button-outlined ui-button-success"
action="#{participantBean.checkinGroupe}"
disabled="#{empty participantBean.selectedParticipants}" />
<p:commandButton value="Notification groupée"
icon="pi pi-bell"
styleClass="ui-button-outlined ui-button-info"
onclick="PF('dlgNotificationGroupee').show();"
disabled="#{empty participantBean.selectedParticipants}" />
<p:commandButton value="Exporter sélection"
icon="pi pi-file-excel"
styleClass="ui-button-outlined ui-button-secondary"
action="#{participantBean.exporterSelection}"
disabled="#{empty participantBean.selectedParticipants}" />
</div>
</div>
</h:form>
</div>
<!-- Dialog Inscrire Membre -->
<p:dialog header="Inscrire un Membre" widgetVar="dlgInscrireMembre" modal="true" width="600">
<h:form id="formInscrireMembre">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="membreSelect" value="Sélectionner le membre" />
<p:autoComplete id="membreSelect"
value="#{participantBean.membreAInscrire}"
completeMethod="#{participantBean.rechercherMembres}"
var="membre" itemLabel="#{membre.nomComplet}" itemValue="#{membre}"
converter="membreConverter"
placeholder="Taper le nom du membre..."
scrollHeight="200">
<p:column>
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-2"
style="width: 30px; height: 30px;">
<span style="font-size: 0.8rem;">#{membre.initiales}</span>
</div>
<div>
<div class="font-medium">#{membre.nomComplet}</div>
<small class="text-600">#{membre.numeroMembre} • #{membre.typeMembre}</small>
</div>
</div>
</p:column>
</p:autoComplete>
</div>
<div class="field">
<p:outputLabel for="accompagnateursNb" value="Nombre d'accompagnateurs" />
<p:inputNumber id="accompagnateursNb"
value="#{participantBean.nombreAccompagnateursInscription}"
symbol="" min="0" max="#{participantBean.maxAccompagnateurs}" />
</div>
<div class="field" rendered="#{participantBean.evenement.payant}">
<p:outputLabel value="Montant à payer" />
<div class="font-bold text-2xl text-green-500">#{participantBean.montantAPayer} FCFA</div>
<small class="text-600">#{participantBean.detailTarification}</small>
</div>
<div class="field">
<p:outputLabel for="commentaire" value="Commentaire" />
<p:inputTextarea id="commentaire"
value="#{participantBean.commentaireInscription}"
rows="3" placeholder="Commentaire optionnel..." />
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Inscrire" icon="pi pi-check"
styleClass="ui-button-success"
action="#{participantBean.inscrireMembre}"
update="@form :formParticipants"
oncomplete="if(!args.validationFailed) PF('dlgInscrireMembre').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgInscrireMembre').hide();" type="button" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Check-in Manuel -->
<p:dialog header="Check-in Manuel" widgetVar="dlgCheckinManuel" modal="true" width="500">
<h:form id="formCheckinManuel">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="participantCheckin" value="Participant" />
<p:autoComplete id="participantCheckin"
value="#{participantBean.participantCheckin}"
completeMethod="#{participantBean.rechercherParticipants}"
var="p" itemLabel="#{p.nomComplet}" itemValue="#{p}"
converter="participantConverter"
placeholder="Taper le nom du participant...">
<p:column>
<div class="flex align-items-center">
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center mr-2"
style="width: 30px; height: 30px;">
<span style="font-size: 0.8rem;">#{p.initiales}</span>
</div>
<div>
<div class="font-medium">#{p.nomComplet}</div>
<small class="text-600">#{p.numeroMembre}</small>
</div>
</div>
</p:column>
</p:autoComplete>
</div>
<div class="field">
<p:outputLabel for="heureArrivee" value="Heure d'arrivée" />
<p:calendar id="heureArrivee"
value="#{participantBean.heureCheckin}"
pattern="HH:mm" timeOnly="true" />
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Confirmer" icon="pi pi-check"
styleClass="ui-button-success"
action="#{participantBean.effectuerCheckinManuel}"
update="@form :formParticipants"
oncomplete="if(!args.validationFailed) PF('dlgCheckinManuel').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgCheckinManuel').hide();" type="button" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Info Dernière Minute -->
<p:dialog header="Information Dernière Minute" widgetVar="dlgInfoDernierMinute" modal="true" width="600">
<h:form id="formInfoDernierMinute">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="sujetInfo" value="Sujet" />
<p:inputText id="sujetInfo" value="#{participantBean.sujetInfo}"
placeholder="Ex: Changement de lieu, horaire..." />
</div>
<div class="field">
<p:outputLabel for="messageInfo" value="Message" />
<p:inputTextarea id="messageInfo" value="#{participantBean.messageInfo}"
rows="4" placeholder="Votre message d'information..." />
</div>
<div class="field">
<p:outputLabel for="prioriteInfo" value="Priorité" />
<p:selectOneMenu id="prioriteInfo" value="#{participantBean.prioriteInfo}">
<f:selectItem itemLabel="🔴 Urgente" itemValue="URGENTE" />
<f:selectItem itemLabel="🟡 Importante" itemValue="IMPORTANTE" />
<f:selectItem itemLabel="🟢 Normale" itemValue="NORMALE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:selectBooleanCheckbox id="envoyerSMS" value="#{participantBean.envoyerSMS}" />
<p:outputLabel for="envoyerSMS" value=" Envoyer par SMS (recommandé pour urgent)" />
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Envoyer" icon="pi pi-send"
styleClass="ui-button-warning"
action="#{participantBean.envoyerInfoDernierMinute}"
update="@form"
oncomplete="if(!args.validationFailed) PF('dlgInfoDernierMinute').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgInfoDernierMinute').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,385 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Caisse de l'Entité - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-wallet text-purple-500 mr-2"></i>
Caisse de l'Entité
</h3>
<p class="text-600 m-0">#{caisseBean.nomEntite} • Dernière mise à jour: #{caisseBean.derniereMAJ}</p>
</div>
<div class="flex gap-2">
<p:commandButton value="Nouvelle entrée"
icon="pi pi-plus-circle"
styleClass="ui-button-success"
onclick="PF('dlgNouvelleEntree').show();" />
<p:commandButton value="Nouvelle sortie"
icon="pi pi-minus-circle"
styleClass="ui-button-danger"
onclick="PF('dlgNouvelleSortie').show();" />
<p:commandButton value="Rapprochement"
icon="pi pi-sync"
styleClass="ui-button-outlined ui-button-info"
action="#{caisseBean.rapprochement}" />
</div>
</div>
</div>
</div>
</div>
<!-- Soldes et Statistiques -->
<div class="formgrid grid">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Solde Principal" />
<ui:param name="value" value="#{caisseBean.soldePrincipal}" />
<ui:param name="icon" value="pi-wallet" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Entrées (30j)" />
<ui:param name="value" value="#{caisseBean.totalEntrees}" />
<ui:param name="icon" value="pi-arrow-down" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Sorties (30j)" />
<ui:param name="value" value="#{caisseBean.totalSorties}" />
<ui:param name="icon" value="pi-arrow-up" />
<ui:param name="iconColor" value="red-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Wave Money" />
<ui:param name="value" value="#{caisseBean.soldeWaveMoney}" />
<ui:param name="icon" value="pi-mobile" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
</div>
<!-- Graphiques -->
<div class="grid">
<div class="col-12 md:col-8">
<div class="card">
<h5>Évolution du Solde</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique temporaire</div></div><!--chart
-->
</div>
</div>
<div class="col-12 md:col-4">
<div class="card">
<h5>Répartition par Catégorie</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique temporaire</div></div><!--chart
-->
</div>
</div>
</div>
<!-- Journal de Caisse -->
<div class="card">
<h:form id="formCaisse">
<h5>Journal de Caisse</h5>
<!-- Filtres -->
<p:toolbar>
<p:toolbarGroup>
<div class="flex align-items-center gap-2">
<p:calendar id="dateDebut" value="#{caisseBean.dateDebut}"
pattern="dd/MM/yyyy" showIcon="true"
placeholder="Date début">
<p:ajax event="dateSelect" update="dtMouvements" />
</p:calendar>
<p:calendar id="dateFin" value="#{caisseBean.dateFin}"
pattern="dd/MM/yyyy" showIcon="true"
placeholder="Date fin">
<p:ajax event="dateSelect" update="dtMouvements" />
</p:calendar>
<p:selectOneMenu value="#{caisseBean.typeFilter}">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="Entrées" itemValue="ENTREE" />
<f:selectItem itemLabel="Sorties" itemValue="SORTIE" />
<p:ajax update="dtMouvements" />
</p:selectOneMenu>
<p:selectOneMenu value="#{caisseBean.categorieFilter}">
<f:selectItem itemLabel="Toutes catégories" itemValue="" />
<f:selectItem itemLabel="Cotisations" itemValue="COTISATION" />
<f:selectItem itemLabel="Événements" itemValue="EVENEMENT" />
<f:selectItem itemLabel="Aides" itemValue="AIDE" />
<f:selectItem itemLabel="Frais admin" itemValue="FRAIS_ADMIN" />
<f:selectItem itemLabel="Autres" itemValue="AUTRE" />
<p:ajax update="dtMouvements" />
</p:selectOneMenu>
</div>
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:commandButton value="Imprimer"
icon="pi pi-print"
styleClass="ui-button-outlined ui-button-secondary mr-2"
action="#{caisseBean.imprimer}" />
<p:commandButton value="Exporter"
icon="pi pi-file-excel"
styleClass="ui-button-outlined ui-button-success"
action="#{caisseBean.exporter}" />
</p:toolbarGroup>
</p:toolbar>
<!-- DataTable Mouvements -->
<p:dataTable id="dtMouvements"
var="mouvement"
value="#{caisseBean.mouvements}"
paginator="true"
rows="15"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
rowKey="#{mouvement.id}"
styleClass="mt-3">
<p:column headerText="Date" sortBy="#{mouvement.date}" style="width:120px">
<h:outputText value="#{mouvement.date}">
<f:convertDateTime pattern="dd/MM/yyyy HH:mm" type="localDateTime" />
</h:outputText>
</p:column>
<p:column headerText="Référence" sortBy="#{mouvement.reference}" style="width:120px">
<h:outputText value="#{mouvement.reference}" styleClass="font-mono" />
</p:column>
<p:column headerText="Libellé" sortBy="#{mouvement.libelle}">
<h:outputText value="#{mouvement.libelle}" />
</p:column>
<p:column headerText="Catégorie" sortBy="#{mouvement.categorie}" style="width:150px">
<p:tag value="#{mouvement.categorie}" styleClass="#{mouvement.categorieClass}" />
</p:column>
<p:column headerText="Entrée" style="width:120px">
<h:outputText value="#{mouvement.montantEntree}"
styleClass="text-green-600 font-bold"
rendered="#{mouvement.type == 'ENTREE'}">
<f:convertNumber type="currency" currencySymbol="+" />
</h:outputText>
</p:column>
<p:column headerText="Sortie" style="width:120px">
<h:outputText value="#{mouvement.montantSortie}"
styleClass="text-red-600 font-bold"
rendered="#{mouvement.type == 'SORTIE'}">
<f:convertNumber type="currency" currencySymbol="-" />
</h:outputText>
</p:column>
<p:column headerText="Solde" style="width:120px">
<h:outputText value="#{mouvement.soldeApres}" styleClass="font-bold">
<f:convertNumber type="currency" currencySymbol="" />
</h:outputText>
</p:column>
<p:column headerText="Mode" style="width:100px">
<div class="flex align-items-center">
<i class="pi #{mouvement.modeIcon} mr-2"></i>
<span>#{mouvement.modePaiement}</span>
</div>
</p:column>
<p:column headerText="Validé" style="width:80px; text-align: center;">
<i class="pi pi-check-circle text-green-500"
rendered="#{mouvement.valide}"
title="Validé le #{mouvement.dateValidation}" />
<i class="pi pi-clock text-orange-500"
rendered="#{!mouvement.valide}"
title="En attente de validation" />
</p:column>
<p:column headerText="Actions" style="width:120px">
<div class="flex gap-2">
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success"
action="#{caisseBean.validerMouvement(mouvement)}"
title="Valider"
rendered="#{!mouvement.valide}" />
<p:commandButton icon="pi pi-file"
styleClass="ui-button-rounded ui-button-text ui-button-info"
action="#{caisseBean.voirJustificatif(mouvement)}"
title="Justificatif" />
<p:commandButton icon="pi pi-times"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
action="#{caisseBean.annulerMouvement(mouvement)}"
onclick="return confirm('Êtes-vous sûr de vouloir annuler ce mouvement ?');"
title="Annuler"
rendered="#{!mouvement.valide}" />
</div>
</p:column>
</p:dataTable>
<!-- Totaux -->
<div class="mt-3 p-3 surface-100 border-round">
<div class="grid">
<div class="col-12 md:col-4">
<div class="text-center">
<div class="text-600">Total Entrées</div>
<div class="text-2xl font-bold text-green-600">#{caisseBean.totalEntreesPeriode}</div>
</div>
</div>
<div class="col-12 md:col-4">
<div class="text-center">
<div class="text-600">Total Sorties</div>
<div class="text-2xl font-bold text-red-600">#{caisseBean.totalSortiesPeriode}</div>
</div>
</div>
<div class="col-12 md:col-4">
<div class="text-center">
<div class="text-600">Solde Période</div>
<div class="text-2xl font-bold text-purple-600">#{caisseBean.soldePeriode}</div>
</div>
</div>
</div>
</div>
</h:form>
</div>
<!-- Dialog Nouvelle Entrée -->
<p:dialog header="Nouvelle Entrée" widgetVar="dlgNouvelleEntree" modal="true" width="500">
<h:form id="formNouvelleEntree">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="libelleEntree" value="Libellé" />
<p:inputText id="libelleEntree" value="#{caisseBean.nouvelleEntree.libelle}" required="true" />
</div>
<div class="field">
<p:outputLabel for="montantEntree" value="Montant" />
<p:inputNumber id="montantEntree" value="#{caisseBean.nouvelleEntree.montant}"
symbol=" FCFA" symbolPosition="s" required="true" />
</div>
<div class="field">
<p:outputLabel for="categorieEntree" value="Catégorie" />
<p:selectOneMenu id="categorieEntree" value="#{caisseBean.nouvelleEntree.categorie}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Cotisations" itemValue="COTISATION" />
<f:selectItem itemLabel="Événements" itemValue="EVENEMENT" />
<f:selectItem itemLabel="Dons" itemValue="DON" />
<f:selectItem itemLabel="Autres" itemValue="AUTRE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="modeEntree" value="Mode de paiement" />
<p:selectOneMenu id="modeEntree" value="#{caisseBean.nouvelleEntree.modePaiement}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
<f:selectItem itemLabel="Wave Money" itemValue="WAVE" />
<f:selectItem itemLabel="Virement" itemValue="VIREMENT" />
<f:selectItem itemLabel="Chèque" itemValue="CHEQUE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="justificatifEntree" value="Justificatif" />
<p:fileUpload id="justificatifEntree" mode="simple" skinSimple="true" />
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Enregistrer" icon="pi pi-check"
styleClass="ui-button-success"
action="#{caisseBean.enregistrerEntree}"
update="@form :formCaisse"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleEntree').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgNouvelleEntree').hide();" type="button" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Nouvelle Sortie -->
<p:dialog header="Nouvelle Sortie" widgetVar="dlgNouvelleSortie" modal="true" width="500">
<h:form id="formNouvelleSortie">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="libelleSortie" value="Libellé" />
<p:inputText id="libelleSortie" value="#{caisseBean.nouvelleSortie.libelle}" required="true" />
</div>
<div class="field">
<p:outputLabel for="montantSortie" value="Montant" />
<p:inputNumber id="montantSortie" value="#{caisseBean.nouvelleSortie.montant}"
symbol=" FCFA" symbolPosition="s" required="true" />
</div>
<div class="field">
<p:outputLabel for="categorieSortie" value="Catégorie" />
<p:selectOneMenu id="categorieSortie" value="#{caisseBean.nouvelleSortie.categorie}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Aides" itemValue="AIDE" />
<f:selectItem itemLabel="Frais administratifs" itemValue="FRAIS_ADMIN" />
<f:selectItem itemLabel="Événements" itemValue="EVENEMENT" />
<f:selectItem itemLabel="Autres" itemValue="AUTRE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="beneficiaireSortie" value="Bénéficiaire" />
<p:inputText id="beneficiaireSortie" value="#{caisseBean.nouvelleSortie.beneficiaire}" />
</div>
<div class="field">
<p:outputLabel for="modeSortie" value="Mode de paiement" />
<p:selectOneMenu id="modeSortie" value="#{caisseBean.nouvelleSortie.modePaiement}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
<f:selectItem itemLabel="Wave Money" itemValue="WAVE" />
<f:selectItem itemLabel="Virement" itemValue="VIREMENT" />
<f:selectItem itemLabel="Chèque" itemValue="CHEQUE" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="justificatifSortie" value="Justificatif" />
<p:fileUpload id="justificatifSortie" mode="simple" skinSimple="true" />
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Enregistrer" icon="pi pi-check"
styleClass="ui-button-danger"
action="#{caisseBean.enregistrerSortie}"
update="@form :formCaisse"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleSortie').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgNouvelleSortie').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,449 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Rapports Financiers - UnionFlow</ui:define>
<ui:define name="content">
<!-- En-tête -->
<div class="grid">
<div class="col-12">
<div class="card">
<div class="flex align-items-center justify-content-between">
<div>
<h3 class="mb-2">
<i class="pi pi-chart-bar text-indigo-500 mr-2"></i>
Rapports Financiers
</h3>
<p class="text-600 m-0">Analyse complète de la situation financière • #{rapportBean.periodeAnalyse}</p>
</div>
<div class="flex gap-2">
<p:commandButton value="Générer rapport PDF"
icon="pi pi-file-pdf"
styleClass="ui-button-danger"
action="#{rapportBean.genererPDF}" />
<p:commandButton value="Exporter Excel"
icon="pi pi-file-excel"
styleClass="ui-button-success"
action="#{rapportBean.exporterExcel}" />
<p:commandButton value="Imprimer"
icon="pi pi-print"
styleClass="ui-button-outlined ui-button-secondary"
onclick="window.print();" />
</div>
</div>
</div>
</div>
</div>
<!-- Sélection de période -->
<div class="card">
<h:form id="formPeriode">
<div class="flex align-items-center gap-3">
<p:selectOneMenu value="#{rapportBean.typePeriode}" style="width: 200px;">
<f:selectItem itemLabel="Cette année" itemValue="ANNEE" />
<f:selectItem itemLabel="Ce trimestre" itemValue="TRIMESTRE" />
<f:selectItem itemLabel="Ce mois" itemValue="MOIS" />
<f:selectItem itemLabel="Période personnalisée" itemValue="CUSTOM" />
<p:ajax update="@form :kpiPanel :graphsPanel :detailsPanel" />
</p:selectOneMenu>
<p:calendar id="dateDebut" value="#{rapportBean.dateDebut}"
pattern="dd/MM/yyyy" showIcon="true"
placeholder="Date début"
disabled="#{rapportBean.typePeriode != 'CUSTOM'}">
<p:ajax event="dateSelect" update=":kpiPanel :graphsPanel :detailsPanel" />
</p:calendar>
<p:calendar id="dateFin" value="#{rapportBean.dateFin}"
pattern="dd/MM/yyyy" showIcon="true"
placeholder="Date fin"
disabled="#{rapportBean.typePeriode != 'CUSTOM'}">
<p:ajax event="dateSelect" update=":kpiPanel :graphsPanel :detailsPanel" />
</p:calendar>
<p:commandButton value="Actualiser"
icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-info"
action="#{rapportBean.actualiser}"
update=":kpiPanel :graphsPanel :detailsPanel" />
</div>
</h:form>
</div>
<!-- KPIs Financiers -->
<h:panelGroup id="kpiPanel">
<div class="formgrid grid">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Revenus Totaux" />
<ui:param name="value" value="#{rapportBean.revenusTotaux}" />
<ui:param name="icon" value="pi-dollar" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="growthValue" value="#{rapportBean.croissanceRevenus}" />
<ui:param name="growthLabel" value="vs période précédente" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Dépenses Totales" />
<ui:param name="value" value="#{rapportBean.depensesTotales}" />
<ui:param name="icon" value="pi-shopping-cart" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="growthValue" value="#{rapportBean.croissanceDepenses}" />
<ui:param name="growthLabel" value="vs période précédente" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Bénéfice Net" />
<ui:param name="value" value="#{rapportBean.beneficeNet}" />
<ui:param name="icon" value="pi-chart-line" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="progressValue" value="#{rapportBean.margePercentage}" />
<ui:param name="showGrowth" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Trésorerie" />
<ui:param name="value" value="#{rapportBean.tresorerie}" />
<ui:param name="icon" value="pi-wallet" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="statusIcon" value="pi-info-circle" />
<ui:param name="statusLabel" value="Jours d'autonomie" />
<ui:param name="statusValue" value="#{rapportBean.joursAutonomie}" />
<ui:param name="showProgress" value="false" />
</ui:include>
</div>
</h:panelGroup>
<!-- Graphiques -->
<h:panelGroup id="graphsPanel">
<div class="grid">
<!-- Évolution Revenus/Dépenses -->
<div class="col-12 md:col-6">
<div class="card">
<h5>Évolution Revenus vs Dépenses</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique en cours de développement</div></div>
</div>
</div>
<!-- Répartition des Revenus -->
<div class="col-12 md:col-6">
<div class="card">
<h5>Sources de Revenus</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique en cours de développement</div></div>
</div>
</div>
<!-- Répartition des Dépenses -->
<div class="col-12 md:col-6">
<div class="card">
<h5>Catégories de Dépenses</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique en cours de développement</div></div>
</div>
</div>
<!-- Cash Flow -->
<div class="col-12 md:col-6">
<div class="card">
<h5>Cash Flow Mensuel</h5>
<div class="surface-100 p-4 border-round text-center"><div class="text-2xl font-bold text-primary mb-2">📊</div><div class="text-600">Graphique en cours de développement</div></div>
</div>
</div>
</div>
</h:panelGroup>
<!-- Analyse Détaillée -->
<h:panelGroup id="detailsPanel">
<div class="grid">
<!-- Top Contributeurs -->
<div class="col-12 md:col-6">
<div class="card">
<h5>Top 10 Contributeurs</h5>
<ui:repeat value="#{rapportBean.topContributeurs}" var="contributeur" varStatus="status">
<div class="flex align-items-center justify-content-between p-3 mb-2 border-round"
style="background: var(--surface-50);">
<div class="flex align-items-center">
<div class="bg-primary text-white border-round text-center mr-3"
style="width: 2rem; height: 2rem; line-height: 2rem;">
#{status.index + 1}
</div>
<div>
<div class="font-medium">#{contributeur.nom}</div>
<small class="text-600">#{contributeur.numeroMembre}</small>
</div>
</div>
<div class="text-right">
<div class="font-bold text-primary">#{contributeur.montantTotal}</div>
<small class="text-600">#{contributeur.nombreContributions} contributions</small>
</div>
</div>
</ui:repeat>
</div>
</div>
<!-- Prévisions -->
<div class="col-12 md:col-6">
<div class="card">
<h5>Prévisions Financières</h5>
<div class="surface-50 p-3 border-round mb-3">
<div class="flex align-items-center justify-content-between mb-2">
<span class="font-medium">Revenus prévus (3 mois)</span>
<span class="font-bold text-green-500">#{rapportBean.revenusPrevus3Mois}</span>
</div>
<div class="flex align-items-center justify-content-between mb-2">
<span class="font-medium">Dépenses prévues (3 mois)</span>
<span class="font-bold text-orange-500">#{rapportBean.depensesPrevues3Mois}</span>
</div>
<div class="flex align-items-center justify-content-between">
<span class="font-medium">Solde prévisionnel</span>
<span class="font-bold text-primary">#{rapportBean.soldePrevisionnel}</span>
</div>
</div>
<h6>Recommandations</h6>
<ui:repeat value="#{rapportBean.recommandations}" var="recommandation">
<div class="flex align-items-start mb-2">
<i class="pi pi-lightbulb text-yellow-500 mr-2 mt-1"></i>
<span>#{recommandation}</span>
</div>
</ui:repeat>
</div>
</div>
</div>
<!-- Tableau Détaillé des Transactions -->
<div class="card">
<h:form id="formTransactions">
<h5>Détail des Transactions</h5>
<p:tabView>
<p:tab title="Revenus">
<p:dataTable var="revenu" value="#{rapportBean.detailRevenus}"
paginator="true" rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}">
<p:column headerText="Date" sortBy="#{revenu.date}" style="width:120px">
<h:outputText value="#{revenu.date}">
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
</h:outputText>
</p:column>
<p:column headerText="Catégorie" sortBy="#{revenu.categorie}">
<p:tag value="#{revenu.categorie}" styleClass="#{revenu.categorieClass}" />
</p:column>
<p:column headerText="Description" sortBy="#{revenu.description}">
<h:outputText value="#{revenu.description}" />
</p:column>
<p:column headerText="Montant" sortBy="#{revenu.montant}" style="width:150px">
<h:outputText value="#{revenu.montant}" styleClass="font-bold text-green-500">
<f:convertNumber type="currency" currencySymbol="FCFA " />
</h:outputText>
</p:column>
<p:column headerText="Mode" style="width:120px">
<div class="flex align-items-center">
<i class="pi #{revenu.modeIcon} mr-2"></i>
<span>#{revenu.modePaiement}</span>
</div>
</p:column>
</p:dataTable>
</p:tab>
<p:tab title="Dépenses">
<p:dataTable var="depense" value="#{rapportBean.detailDepenses}"
paginator="true" rows="10"
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}"
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}">
<p:column headerText="Date" sortBy="#{depense.date}" style="width:120px">
<h:outputText value="#{depense.date}">
<f:convertDateTime pattern="dd/MM/yyyy" type="localDate" />
</h:outputText>
</p:column>
<p:column headerText="Catégorie" sortBy="#{depense.categorie}">
<p:tag value="#{depense.categorie}" styleClass="#{depense.categorieClass}" />
</p:column>
<p:column headerText="Description" sortBy="#{depense.description}">
<h:outputText value="#{depense.description}" />
</p:column>
<p:column headerText="Bénéficiaire" sortBy="#{depense.beneficiaire}">
<h:outputText value="#{depense.beneficiaire}" />
</p:column>
<p:column headerText="Montant" sortBy="#{depense.montant}" style="width:150px">
<h:outputText value="#{depense.montant}" styleClass="font-bold text-red-500">
<f:convertNumber type="currency" currencySymbol="FCFA " />
</h:outputText>
</p:column>
<p:column headerText="Justificatif" style="width:100px; text-align:center;">
<p:commandButton icon="pi pi-file"
styleClass="ui-button-rounded ui-button-text"
action="#{rapportBean.voirJustificatif(depense)}"
rendered="#{depense.hasJustificatif}" />
</p:column>
</p:dataTable>
</p:tab>
</p:tabView>
</h:form>
</div>
<!-- Ratios et Indicateurs -->
<div class="card">
<h5>Indicateurs Clés de Performance</h5>
<div class="formgrid grid">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Taux de Recouvrement" />
<ui:param name="value" value="#{rapportBean.tauxRecouvrement}%" />
<ui:param name="icon" value="pi-percentage" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Ratio de Couverture" />
<ui:param name="value" value="#{rapportBean.ratioCouverture}" />
<ui:param name="icon" value="pi-shield" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Coût Moyen/Membre" />
<ui:param name="value" value="#{rapportBean.coutMoyenMembre}" />
<ui:param name="icon" value="pi-user-minus" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Revenu Moyen/Membre" />
<ui:param name="value" value="#{rapportBean.revenuMoyenMembre}" />
<ui:param name="icon" value="pi-user-plus" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
</div>
</div>
</h:panelGroup>
<!-- Actions d'export -->
<div class="card">
<div class="flex justify-content-center gap-3">
<p:commandButton value="Envoyer par email"
icon="pi pi-envelope"
styleClass="ui-button-outlined ui-button-info"
onclick="PF('dlgEmail').show();" />
<p:commandButton value="Programmer rapport automatique"
icon="pi pi-calendar"
styleClass="ui-button-outlined ui-button-warning"
onclick="PF('dlgProgrammer').show();" />
<p:commandButton value="Archiver"
icon="pi pi-save"
styleClass="ui-button-outlined ui-button-secondary"
action="#{rapportBean.archiver}" />
</div>
</div>
<!-- Dialog Email -->
<p:dialog header="Envoyer le rapport par email" widgetVar="dlgEmail" modal="true" width="500">
<h:form id="formEmail">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="destinataires" value="Destinataires" />
<p:chips id="destinataires" value="#{rapportBean.destinataires}" />
</div>
<div class="field">
<p:outputLabel for="message" value="Message" />
<p:inputTextarea id="message" value="#{rapportBean.messageEmail}" rows="5" />
</div>
<div class="field">
<p:selectBooleanCheckbox id="inclurePDF" value="#{rapportBean.inclurePDF}" />
<p:outputLabel for="inclurePDF" value=" Inclure le rapport PDF" />
</div>
<div class="field">
<p:selectBooleanCheckbox id="inclureExcel" value="#{rapportBean.inclureExcel}" />
<p:outputLabel for="inclureExcel" value=" Inclure le fichier Excel" />
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Envoyer" icon="pi pi-send"
styleClass="ui-button-info"
action="#{rapportBean.envoyerEmail}"
oncomplete="PF('dlgEmail').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgEmail').hide();" type="button" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Programmer -->
<p:dialog header="Programmer rapport automatique" widgetVar="dlgProgrammer" modal="true" width="500">
<h:form id="formProgrammer">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="frequence" value="Fréquence" />
<p:selectOneMenu id="frequence" value="#{rapportBean.frequence}">
<f:selectItem itemLabel="Quotidien" itemValue="QUOTIDIEN" />
<f:selectItem itemLabel="Hebdomadaire" itemValue="HEBDOMADAIRE" />
<f:selectItem itemLabel="Mensuel" itemValue="MENSUEL" />
<f:selectItem itemLabel="Trimestriel" itemValue="TRIMESTRIEL" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="jourEnvoi" value="Jour d'envoi" />
<p:selectOneMenu id="jourEnvoi" value="#{rapportBean.jourEnvoi}">
<f:selectItem itemLabel="Lundi" itemValue="1" />
<f:selectItem itemLabel="Mardi" itemValue="2" />
<f:selectItem itemLabel="Mercredi" itemValue="3" />
<f:selectItem itemLabel="Jeudi" itemValue="4" />
<f:selectItem itemLabel="Vendredi" itemValue="5" />
</p:selectOneMenu>
</div>
<div class="field">
<p:outputLabel for="heureEnvoi" value="Heure d'envoi" />
<p:inputText id="heureEnvoi" value="#{rapportBean.heureEnvoi}" placeholder="09:00" />
</div>
<div class="field">
<p:outputLabel for="destinatairesProg" value="Destinataires" />
<p:chips id="destinatairesProg" value="#{rapportBean.destinatairesProgrammes}" />
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Programmer" icon="pi pi-check"
styleClass="ui-button-warning"
action="#{rapportBean.programmerRapport}"
oncomplete="PF('dlgProgrammer').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgProgrammer').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,566 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Rapports et Statistiques - UnionFlow</ui:define>
<ui:define name="content">
<div class="ui-fluid">
<!-- En-tête avec disposition Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<div class="formgrid grid">
<div class="field col-12 lg:col-8">
<h2 class="text-primary font-bold mb-2">
<i class="pi pi-chart-bar text-blue-500 mr-2"></i>
Rapports et Statistiques
</h2>
<p class="text-600 mt-0">Analyse des données et indicateurs de performance</p>
</div>
<div class="field col-12 lg:col-4 text-right">
<h:form id="formActionsEntete">
<div class="formgrid grid">
<div class="field col-12 md:col-4">
<p:commandButton value="Générer"
icon="pi pi-file-pdf"
styleClass="ui-button-success ui-button-sm w-full"
onclick="PF('dlgGenererRapport').show();" />
</div>
<div class="field col-12 md:col-4">
<p:commandButton value="Planifier"
icon="pi pi-calendar-plus"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
onclick="PF('dlgPlanifierRapport').show();" />
</div>
<div class="field col-12 md:col-4">
<p:commandButton value="Exporter"
icon="pi pi-download"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full"
action="#{rapportsBean.exporterDonnees}" />
</div>
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Sélecteur de période avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-calendar text-blue-500 mr-2"></i>
Période d'Analyse
</h5>
<h:form id="formPeriode">
<div class="ui-fluid">
<div class="formgrid grid">
<div class="field col-12 md:col-3">
<p:outputLabel for="periodeRapide" value="Période rapide" />
<p:selectOneMenu id="periodeRapide" value="#{rapportsBean.periodeRapide}">
<f:selectItem itemLabel="Personnalisée" itemValue="" />
<f:selectItem itemLabel="7 derniers jours" itemValue="7_JOURS" />
<f:selectItem itemLabel="30 derniers jours" itemValue="30_JOURS" />
<f:selectItem itemLabel="3 derniers mois" itemValue="3_MOIS" />
<f:selectItem itemLabel="6 derniers mois" itemValue="6_MOIS" />
<f:selectItem itemLabel="Cette année" itemValue="ANNEE_COURANTE" />
<f:selectItem itemLabel="Année dernière" itemValue="ANNEE_PRECEDENTE" />
<p:ajax update="@form :indicateursGlobaux :graphiquesEvolution" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-3">
<p:outputLabel for="dateDebut" value="Date début" />
<p:datePicker id="dateDebut" value="#{rapportsBean.dateDebut}"
placeholder="Date de début">
<p:ajax update=":indicateursGlobaux :graphiquesEvolution" />
</p:datePicker>
</div>
<div class="field col-12 md:col-3">
<p:outputLabel for="dateFin" value="Date fin" />
<p:datePicker id="dateFin" value="#{rapportsBean.dateFin}"
placeholder="Date de fin">
<p:ajax update=":indicateursGlobaux :graphiquesEvolution" />
</p:datePicker>
</div>
<div class="field col-12 md:col-3">
<p:outputLabel for="groupeComparaison" value="Comparer avec" />
<p:selectOneMenu id="groupeComparaison" value="#{rapportsBean.groupeComparaison}">
<f:selectItem itemLabel="Aucune comparaison" itemValue="" />
<f:selectItem itemLabel="Période précédente" itemValue="PERIODE_PRECEDENTE" />
<f:selectItem itemLabel="Même période année passée" itemValue="ANNEE_PASSEE" />
<f:selectItem itemLabel="Moyenne historique" itemValue="MOYENNE_HISTORIQUE" />
<p:ajax update=":indicateursGlobaux" />
</p:selectOneMenu>
</div>
</div>
</div>
</h:form>
</div>
</div>
<!-- Indicateurs globaux avec Freya stricte -->
<p:outputPanel id="indicateursGlobaux">
<div class="formgrid grid">
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Total Membres</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-users text-blue-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{rapportsBean.indicateurs.totalMembres}</div>
<div class="flex align-items-center mb-2">
<i class="pi pi-arrow-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+#{rapportsBean.indicateurs.croissanceMembres}%</span>
<span class="text-500 text-xs">ce mois</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Revenus Total</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-dollar text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{rapportsBean.indicateurs.revenus}</div>
<div class="flex align-items-center mb-2">
<i class="pi pi-arrow-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+#{rapportsBean.indicateurs.croissanceRevenus}%</span>
<span class="text-500 text-xs">ce mois</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Événements</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-calendar text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{rapportsBean.indicateurs.totalEvenements}</div>
<div class="flex align-items-center mb-2">
<i class="pi pi-arrow-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+#{rapportsBean.indicateurs.croissanceEvenements}%</span>
<span class="text-500 text-xs">ce mois</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Aides Accordées</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-heart text-purple-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{rapportsBean.indicateurs.totalAides}</div>
<div class="flex align-items-center mb-2">
<i class="pi pi-arrow-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+#{rapportsBean.indicateurs.croissanceAides}%</span>
<span class="text-500 text-xs">ce mois</span>
</div>
</div>
</div>
</div>
</div>
</p:outputPanel>
<!-- Graphiques d'évolution avec Freya stricte -->
<p:outputPanel id="graphiquesEvolution">
<div class="formgrid grid">
<div class="field col-12 md:col-8">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-chart-line text-blue-500 mr-2"></i>
Évolution des Membres et Revenus
</h5>
<div class="surface-100 border-round-lg p-4">
<div class="grid">
<ui:repeat value="#{rapportsBean.evolutionMensuelle}" var="mois" varStatus="status">
<div class="col-12 md:col-2">
<div class="text-center">
<div class="text-600 text-sm mb-2">#{mois.libelle}</div>
<div class="flex flex-column align-items-center gap-2">
<div class="bg-blue-500 border-round" style="width: 20px; height: #{mois.hauteurMembres}px;"></div>
<div class="text-blue-700 font-bold text-sm">#{mois.membres}</div>
<div class="bg-green-500 border-round" style="width: 20px; height: #{mois.hauteurRevenus}px;"></div>
<div class="text-green-700 font-bold text-xs">#{mois.revenus}M</div>
</div>
</div>
</div>
</ui:repeat>
</div>
<div class="flex justify-content-center gap-4 mt-3">
<div class="flex align-items-center">
<div class="bg-blue-500 border-round mr-2" style="width: 12px; height: 12px;"></div>
<span class="text-600 text-sm">Membres</span>
</div>
<div class="flex align-items-center">
<div class="bg-green-500 border-round mr-2" style="width: 12px; height: 12px;"></div>
<span class="text-600 text-sm">Revenus (M FCFA)</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-4">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-target text-green-500 mr-2"></i>
Objectifs vs Réalisations
</h5>
<div class="grid">
<ui:repeat value="#{rapportsBean.objectifs}" var="objectif" varStatus="status">
<div class="col-12">
<div class="flex align-items-center justify-content-between mb-2">
<span class="text-900 font-medium">#{objectif.libelle}</span>
<span class="text-600 text-sm">#{objectif.pourcentage}%</span>
</div>
<p:progressBar value="#{objectif.pourcentage}" style="height: 8px;"
styleClass="mb-3">
<f:facet name="label">#{objectif.pourcentage}%</f:facet>
</p:progressBar>
<div class="flex justify-content-between text-xs text-600 mb-3">
<span>Réalisé: #{objectif.realise}</span>
<span>Objectif: #{objectif.cible}</span>
</div>
</div>
</ui:repeat>
</div>
</div>
</div>
</div>
</div>
</p:outputPanel>
<!-- Répartitions et analyses avec Freya stricte -->
<div class="formgrid grid">
<div class="field col-12 md:col-6">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-users text-purple-500 mr-2"></i>
Répartition des Membres
</h5>
<div class="grid">
<ui:repeat value="#{rapportsBean.repartitionMembres}" var="categorie" varStatus="status">
<div class="col-12">
<div class="flex align-items-center justify-content-between mb-2">
<div class="flex align-items-center">
<div class="bg-#{categorie.couleur} border-round mr-3"
style="width: 12px; height: 12px;"></div>
<span class="text-900">#{categorie.libelle}</span>
</div>
<div class="text-right">
<div class="text-900 font-bold">#{categorie.nombre}</div>
<div class="text-600 text-sm">#{categorie.pourcentage}%</div>
</div>
</div>
<p:progressBar value="#{categorie.pourcentage}" style="height: 6px;"
styleClass="mb-3" />
</div>
</ui:repeat>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-dollar text-green-500 mr-2"></i>
Analyse des Revenus
</h5>
<div class="grid">
<ui:repeat value="#{rapportsBean.sourceRevenus}" var="source" varStatus="status">
<div class="col-12">
<div class="flex align-items-center justify-content-between mb-2">
<div class="flex align-items-center">
<div class="bg-#{source.couleur} text-white border-round flex align-items-center justify-content-center mr-3"
style="width: 2rem; height: 2rem;">
<i class="pi #{source.icon} text-sm"></i>
</div>
<span class="text-900">#{source.libelle}</span>
</div>
<div class="text-right">
<div class="text-900 font-bold">#{source.montant}</div>
<div class="text-600 text-sm">#{source.pourcentage}%</div>
</div>
</div>
<p:progressBar value="#{source.pourcentage}" style="height: 6px;"
styleClass="mb-3" />
</div>
</ui:repeat>
</div>
</div>
</div>
</div>
</div>
<!-- Tableaux de performance avec Freya stricte -->
<div class="formgrid grid">
<div class="field col-12 md:col-6">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-trophy text-yellow-500 mr-2"></i>
Top Entités Performantes
</h5>
<p:dataTable value="#{rapportsBean.topEntites}" var="entite"
styleClass="p-datatable-sm"
emptyMessage="Aucune donnée disponible">
<p:column headerText="Rang" width="60">
<div class="text-center">
<p:tag value="#{entite.rang}"
severity="#{entite.rang == 1 ? 'warning' : (entite.rang le 3 ? 'info' : 'secondary')}" />
</div>
</p:column>
<p:column headerText="Entité">
<div class="flex align-items-center">
<div class="bg-primary text-white border-round flex align-items-center justify-content-center mr-2"
style="width: 24px; height: 24px;">
<i class="pi #{entite.typeIcon} text-xs"></i>
</div>
<span class="text-900 font-medium">#{entite.nom}</span>
</div>
</p:column>
<p:column headerText="Score" width="80">
<div class="text-center">
<span class="text-900 font-bold">#{entite.score}</span>
</div>
</p:column>
<p:column headerText="Évolution" width="80">
<div class="text-center">
<i class="pi #{entite.tendance == 'UP' ? 'pi-arrow-up text-green-500' : (entite.tendance == 'DOWN' ? 'pi-arrow-down text-red-500' : 'pi-minus text-600')}"></i>
</div>
</p:column>
</p:dataTable>
</div>
</div>
</div>
<div class="field col-12 md:col-6">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-chart-bar text-blue-500 mr-2"></i>
Indicateurs Clés de Performance
</h5>
<div class="formgrid grid">
<ui:repeat value="#{rapportsBean.kpis}" var="kpi" varStatus="status">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="#{kpi.libelle}" />
<ui:param name="value" value="#{kpi.valeur}" />
<ui:param name="icon" value="#{kpi.icon}" />
<ui:param name="iconColor" value="#{kpi.couleur}" />
<ui:param name="growthValue" value="#{kpi.variation}" />
<ui:param name="growthLabel" value="variation" />
<ui:param name="progressValue" value="#{kpi.progression}" />
<ui:param name="colSize" value="col-12" />
</ui:include>
</ui:repeat>
</div>
</div>
</div>
</div>
</div>
<!-- Alertes et recommandations avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-exclamation-triangle text-orange-500 mr-2"></i>
Alertes et Recommandations
</h5>
<div class="formgrid grid">
<ui:repeat value="#{rapportsBean.alertes}" var="alerte" varStatus="status">
<div class="field col-12 md:col-6">
<div class="surface-100 border-round-lg p-3 hover:surface-200 transition-colors transition-duration-150 border-left-3 border-#{alerte.severiteCouleur}">
<div class="flex align-items-start">
<div class="bg-#{alerte.severiteCouleur} text-white border-round flex align-items-center justify-content-center mr-3"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi #{alerte.icon}"></i>
</div>
<div class="flex-1">
<h6 class="text-900 m-0 mb-2">#{alerte.titre}</h6>
<div class="text-600 mb-2 text-sm">#{alerte.description}</div>
<div class="flex align-items-center justify-content-between">
<p:tag value="#{alerte.priorite}" severity="#{alerte.severite}" />
<span class="text-600 text-xs">#{alerte.dateDetection}</span>
</div>
</div>
</div>
</div>
</div>
</ui:repeat>
</div>
</div>
</div>
<!-- Historique des rapports avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-file-text text-blue-500 mr-2"></i>
Historique des Rapports
</h5>
<p:dataTable value="#{rapportsBean.historiqueRapports}" var="rapport"
paginator="true" rows="10"
styleClass="p-datatable-sm"
emptyMessage="Aucun rapport généré">
<p:column headerText="Date génération" sortBy="#{rapport.dateGeneration}" width="150">
<span class="text-900">#{rapport.dateGenerationFormatee}</span>
</p:column>
<p:column headerText="Type de rapport">
<div class="flex align-items-center">
<i class="pi #{rapport.typeIcon} text-#{rapport.typeCouleur} mr-2"></i>
<span class="text-900">#{rapport.typeLibelle}</span>
</div>
</p:column>
<p:column headerText="Période couverte" width="200">
<span class="text-600">#{rapport.periodeCouverte}</span>
</p:column>
<p:column headerText="Généré par" width="150">
<span class="text-900">#{rapport.generePar}</span>
</p:column>
<p:column headerText="Statut" width="100">
<p:tag value="#{rapport.statut}" severity="#{rapport.statutSeverity}" />
</p:column>
<p:column headerText="Actions" width="120">
<h:form>
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
title="Voir le rapport"
action="#{rapportsBean.voirRapport(rapport)}" />
<p:commandButton icon="pi pi-download"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
title="Télécharger"
action="#{rapportsBean.telechargerRapport(rapport)}" />
<p:commandButton icon="pi pi-share-alt"
styleClass="ui-button-rounded ui-button-text ui-button-primary"
title="Partager"
onclick="PF('dlgPartagerRapport').show();">
<f:setPropertyActionListener target="#{rapportsBean.rapportSelectionne}" value="#{rapport}" />
</p:commandButton>
</div>
</h:form>
</p:column>
</p:dataTable>
</div>
</div>
<!-- Dialog Générer Rapport avec Freya stricte -->
<p:dialog header="Générer un Nouveau Rapport" widgetVar="dlgGenererRapport" modal="true" width="600">
<h:form id="formGenererRapport">
<div class="ui-fluid">
<div class="formgrid grid">
<div class="field col-12 md:col-6">
<p:outputLabel for="typeRapport" value="Type de rapport" />
<p:selectOneMenu id="typeRapport" value="#{rapportsBean.nouveauRapport.type}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="📊 Rapport Financier" itemValue="FINANCIER" />
<f:selectItem itemLabel="👥 Rapport Membres" itemValue="MEMBRES" />
<f:selectItem itemLabel="📅 Rapport Activités" itemValue="ACTIVITES" />
<f:selectItem itemLabel="🎯 Rapport Performance" itemValue="PERFORMANCE" />
<f:selectItem itemLabel="📈 Rapport Complet" itemValue="COMPLET" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="formatRapport" value="Format de sortie" />
<p:selectOneMenu id="formatRapport" value="#{rapportsBean.nouveauRapport.format}">
<f:selectItem itemLabel="PDF" itemValue="PDF" />
<f:selectItem itemLabel="Excel" itemValue="EXCEL" />
<f:selectItem itemLabel="PowerPoint" itemValue="POWERPOINT" />
<f:selectItem itemLabel="HTML" itemValue="HTML" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="periodeRapport" value="Période du rapport" />
<p:selectOneMenu id="periodeRapport" value="#{rapportsBean.nouveauRapport.periode}">
<f:selectItem itemLabel="7 derniers jours" itemValue="7_JOURS" />
<f:selectItem itemLabel="30 derniers jours" itemValue="30_JOURS" />
<f:selectItem itemLabel="3 derniers mois" itemValue="3_MOIS" />
<f:selectItem itemLabel="6 derniers mois" itemValue="6_MOIS" />
<f:selectItem itemLabel="Cette année" itemValue="ANNEE_COURANTE" />
<f:selectItem itemLabel="Personnalisée" itemValue="PERSONNALISEE" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="niveauDetail" value="Niveau de détail" />
<p:selectOneMenu id="niveauDetail" value="#{rapportsBean.nouveauRapport.detail}">
<f:selectItem itemLabel="Résumé exécutif" itemValue="RESUME" />
<f:selectItem itemLabel="Standard" itemValue="STANDARD" />
<f:selectItem itemLabel="Détaillé" itemValue="DETAILLE" />
<f:selectItem itemLabel="Complet avec annexes" itemValue="COMPLET" />
</p:selectOneMenu>
</div>
<div class="field col-12">
<p:outputLabel for="commentairesRapport" value="Commentaires et notes" />
<p:inputTextarea id="commentairesRapport" value="#{rapportsBean.nouveauRapport.commentaires}"
rows="3" placeholder="Ajouter des commentaires ou instructions spécifiques..." />
</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Générer maintenant" icon="pi pi-play"
styleClass="ui-button-success"
action="#{rapportsBean.genererRapport}"
update="@form"
oncomplete="if(!args.validationFailed) PF('dlgGenererRapport').hide();" />
<p:commandButton value="Programmer" icon="pi pi-calendar"
styleClass="ui-button-info"
onclick="PF('dlgGenererRapport').hide(); PF('dlgPlanifierRapport').show();"
type="button" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgGenererRapport').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">UnionFlow - Administration Settings</ui:define>
<ui:define name="content">
<div class="grid">
<div class="col-12">
<div class="card">
<h2>Administration - Settings</h2>
<p>Page d'administration en cours de développement...</p>
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
</div>
</div>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">UnionFlow - Administration Users</ui:define>
<ui:define name="content">
<div class="grid">
<div class="col-12">
<div class="card">
<h2>Administration - Users</h2>
<p>Page d'administration en cours de développement...</p>
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
</div>
</div>
</div>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,398 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/main-template.xhtml">
<ui:define name="title">Gestion des Utilisateurs - UnionFlow</ui:define>
<ui:define name="content">
<div class="ui-fluid">
<!-- En-tête avec disposition Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<div class="formgrid grid">
<div class="field col-12 lg:col-8">
<h2 class="text-primary font-bold mb-2">
<i class="pi pi-users text-blue-500 mr-2"></i>
Gestion des Utilisateurs
</h2>
<p class="text-600 mt-0">Administration des comptes et permissions utilisateurs</p>
</div>
<div class="field col-12 lg:col-4 text-right">
<h:form id="formActionsEntete">
<div class="formgrid grid">
<div class="field col-12 md:col-4">
<p:commandButton value="Nouvel Utilisateur"
icon="pi pi-user-plus"
styleClass="ui-button-success ui-button-sm w-full"
onclick="PF('dlgNouvelUtilisateur').show();" />
</div>
<div class="field col-12 md:col-4">
<p:commandButton value="Importer"
icon="pi pi-upload"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
onclick="PF('dlgImporterUtilisateurs').show();" />
</div>
<div class="field col-12 md:col-4">
<p:commandButton value="Exporter"
icon="pi pi-download"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full"
action="#{utilisateursBean.exporterUtilisateurs}" />
</div>
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Statistiques utilisateurs avec Freya stricte -->
<div class="formgrid grid">
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Total Utilisateurs</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-users text-blue-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.totalUtilisateurs}</div>
<div class="flex align-items-center mb-2">
<div class="bg-blue-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">Comptes actifs</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Connectés</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-circle-fill text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.utilisateursConnectes}</div>
<div class="flex align-items-center mb-2">
<div class="bg-green-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">En ligne maintenant</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Administrateurs</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-shield text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.administrateurs}</div>
<div class="flex align-items-center mb-2">
<div class="bg-orange-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">Privilèges élevés</span>
</div>
</div>
</div>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Désactivés</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-ban text-red-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{utilisateursBean.statistiques.utilisateursDesactives}</div>
<div class="flex align-items-center mb-2">
<div class="bg-red-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-500 text-xs">Comptes suspendus</span>
</div>
</div>
</div>
</div>
</div>
<!-- Filtres et recherche avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<h5 class="text-900 font-bold mb-4">
<i class="pi pi-search text-blue-500 mr-2"></i>
Recherche et Filtres
</h5>
<h:form id="formFiltres">
<div class="ui-fluid">
<div class="formgrid grid">
<div class="field col-12 md:col-4">
<p:outputLabel for="searchNom" value="Nom ou Email" />
<p:inputText id="searchNom" value="#{utilisateursBean.filtres.recherche}"
placeholder="Rechercher par nom ou email...">
<p:ajax event="keyup" update="dtUtilisateurs" />
</p:inputText>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterRole" value="Rôle" />
<p:selectOneMenu id="filterRole" value="#{utilisateursBean.filtres.role}">
<f:selectItem itemLabel="Tous les rôles" itemValue="" />
<f:selectItem itemLabel="Super Admin" itemValue="SUPER_ADMIN" />
<f:selectItem itemLabel="Admin" itemValue="ADMIN" />
<f:selectItem itemLabel="Gestionnaire" itemValue="GESTIONNAIRE" />
<f:selectItem itemLabel="Utilisateur" itemValue="USER" />
<p:ajax update="dtUtilisateurs" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterStatut" value="Statut" />
<p:selectOneMenu id="filterStatut" value="#{utilisateursBean.filtres.statut}">
<f:selectItem itemLabel="Tous statuts" itemValue="" />
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
<f:selectItem itemLabel="Inactif" itemValue="INACTIF" />
<f:selectItem itemLabel="Suspendu" itemValue="SUSPENDU" />
<f:selectItem itemLabel="En attente" itemValue="ATTENTE" />
<p:ajax update="dtUtilisateurs" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterConnexion" value="Dernière connexion" />
<p:selectOneMenu id="filterConnexion" value="#{utilisateursBean.filtres.connexion}">
<f:selectItem itemLabel="Toutes" itemValue="" />
<f:selectItem itemLabel="Aujourd'hui" itemValue="AUJOURD_HUI" />
<f:selectItem itemLabel="Cette semaine" itemValue="SEMAINE" />
<f:selectItem itemLabel="Ce mois" itemValue="MOIS" />
<f:selectItem itemLabel="Plus de 30 jours" itemValue="PLUS_30_JOURS" />
<p:ajax update="dtUtilisateurs" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-2">
<p:outputLabel for="filterOrganisation" value="Organisation" />
<p:selectOneMenu id="filterOrganisation" value="#{utilisateursBean.filtres.organisation}">
<f:selectItem itemLabel="Toutes" itemValue="" />
<f:selectItems value="#{utilisateursBean.organisationsDisponibles}"
var="org"
itemLabel="#{org.nom}"
itemValue="#{org.id}" />
<p:ajax update="dtUtilisateurs" />
</p:selectOneMenu>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Rechercher"
icon="pi pi-search"
styleClass="ui-button-primary ui-button-sm"
action="#{utilisateursBean.rechercher}"
update="dtUtilisateurs" />
<p:commandButton value="Réinitialiser"
icon="pi pi-refresh"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
action="#{utilisateursBean.reinitialiserFiltres}"
update="@form dtUtilisateurs" />
</div>
</div>
</h:form>
</div>
</div>
<!-- Liste des utilisateurs avec Freya stricte -->
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4">
<div class="flex align-items-center justify-content-between mb-4">
<h5 class="text-900 font-bold m-0">
<i class="pi pi-users text-blue-500 mr-2"></i>
Utilisateurs (#{utilisateursBean.utilisateursFiltres.size()})
</h5>
<div class="flex align-items-center gap-2">
<h:form id="formActionsGroupees">
<p:commandButton value="Actions groupées"
icon="pi pi-cog"
styleClass="ui-button-outlined ui-button-warning"
onclick="PF('dlgActionsGroupees').show();"
disabled="#{empty utilisateursBean.utilisateursSelectionnes}" />
</h:form>
</div>
</div>
<p:dataTable id="dtUtilisateurs"
value="#{utilisateursBean.utilisateursFiltres}"
var="utilisateur"
selection="#{utilisateursBean.utilisateursSelectionnes}"
rowKey="#{utilisateur.id}"
paginator="true"
rows="15"
paginatorPosition="both"
sortMode="single"
styleClass="p-datatable-sm"
emptyMessage="Aucun utilisateur trouvé">
<p:column selectionMode="multiple" width="40" />
<p:column headerText="Utilisateur" sortBy="#{utilisateur.nom}" width="300">
<div class="flex align-items-center">
<div class="surface-200 border-circle flex align-items-center justify-content-center mr-3"
style="width: 40px; height: 40px;">
<i class="pi pi-user text-600"></i>
</div>
<div>
<div class="text-900 font-medium">#{utilisateur.nomComplet}</div>
<div class="text-600 text-sm">#{utilisateur.email}</div>
</div>
</div>
</p:column>
<p:column headerText="Rôle" sortBy="#{utilisateur.role}" width="120">
<p:tag value="#{utilisateur.roleLibelle}" severity="#{utilisateur.roleSeverity}" />
</p:column>
<p:column headerText="Organisation" sortBy="#{utilisateur.organisation}" width="150">
<span class="text-900">#{utilisateur.organisationNom}</span>
</p:column>
<p:column headerText="Statut" sortBy="#{utilisateur.statut}" width="100">
<p:tag value="#{utilisateur.statutLibelle}" severity="#{utilisateur.statutSeverity}" />
</p:column>
<p:column headerText="Dernière connexion" sortBy="#{utilisateur.derniereConnexion}" width="140">
<div class="text-900 text-sm">#{utilisateur.derniereConnexionFormatee}</div>
<div class="text-600 text-xs">#{utilisateur.derniereConnexionRelative}</div>
</p:column>
<p:column headerText="Date création" sortBy="#{utilisateur.dateCreation}" width="120">
<span class="text-900 text-sm">#{utilisateur.dateCreationFormatee}</span>
</p:column>
<p:column headerText="Actions" width="150">
<h:form id="formActions#{utilisateur.id}">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info"
title="Voir profil"
onclick="PF('dlgVoirUtilisateur').show();">
<f:setPropertyActionListener target="#{utilisateursBean.utilisateurSelectionne}" value="#{utilisateur}" />
</p:commandButton>
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-warning"
title="Modifier"
onclick="PF('dlgModifierUtilisateur').show();">
<f:setPropertyActionListener target="#{utilisateursBean.utilisateurSelectionne}" value="#{utilisateur}" />
</p:commandButton>
<p:commandButton icon="pi pi-key"
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
title="Gérer permissions"
onclick="PF('dlgPermissions').show();">
<f:setPropertyActionListener target="#{utilisateursBean.utilisateurSelectionne}" value="#{utilisateur}" />
</p:commandButton>
<p:commandButton icon="pi pi-ban"
styleClass="ui-button-rounded ui-button-text ui-button-danger"
title="Désactiver"
onclick="return confirm('Êtes-vous sûr de vouloir désactiver cet utilisateur ?');"
action="#{utilisateursBean.desactiverUtilisateur(utilisateur)}"
rendered="#{utilisateur.statut != 'INACTIF'}" />
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success"
title="Activer"
action="#{utilisateursBean.activerUtilisateur(utilisateur)}"
rendered="#{utilisateur.statut == 'INACTIF'}" />
</div>
</h:form>
</p:column>
</p:dataTable>
</div>
</div>
<!-- Dialog Nouvel Utilisateur avec Freya stricte -->
<p:dialog header="Nouvel Utilisateur" widgetVar="dlgNouvelUtilisateur" modal="true" width="600">
<h:form id="formNouvelUtilisateur">
<div class="ui-fluid">
<div class="formgrid grid">
<div class="field col-12 md:col-6">
<p:outputLabel for="newNom" value="Nom" />
<p:inputText id="newNom" value="#{utilisateursBean.nouvelUtilisateur.nom}"
required="true" placeholder="Nom de famille" />
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newPrenom" value="Prénom" />
<p:inputText id="newPrenom" value="#{utilisateursBean.nouvelUtilisateur.prenom}"
required="true" placeholder="Prénom" />
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newEmail" value="Email" />
<p:inputText id="newEmail" value="#{utilisateursBean.nouvelUtilisateur.email}"
required="true" placeholder="adresse@email.com" />
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newTelephone" value="Téléphone" />
<p:inputText id="newTelephone" value="#{utilisateursBean.nouvelUtilisateur.telephone}"
placeholder="+225 XX XX XX XX" />
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newRole" value="Rôle" />
<p:selectOneMenu id="newRole" value="#{utilisateursBean.nouvelUtilisateur.role}" required="true">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="👤 Utilisateur" itemValue="USER" />
<f:selectItem itemLabel="⚙️ Gestionnaire" itemValue="GESTIONNAIRE" />
<f:selectItem itemLabel="🛠️ Administrateur" itemValue="ADMIN" />
<f:selectItem itemLabel="🛡️ Super Admin" itemValue="SUPER_ADMIN" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<p:outputLabel for="newOrganisation" value="Organisation" />
<p:selectOneMenu id="newOrganisation" value="#{utilisateursBean.nouvelUtilisateur.organisationId}">
<f:selectItem itemLabel="Aucune organisation" itemValue="" />
<f:selectItems value="#{utilisateursBean.organisationsDisponibles}"
var="org"
itemLabel="#{org.nom}"
itemValue="#{org.id}" />
</p:selectOneMenu>
</div>
<div class="field col-12">
<p:outputLabel for="newMotDePasse" value="Mot de passe temporaire" />
<p:password id="newMotDePasse" value="#{utilisateursBean.nouvelUtilisateur.motDePasse}"
required="true" placeholder="Mot de passe temporaire" />
</div>
<div class="field col-12">
<div class="flex align-items-center">
<p:selectBooleanCheckbox id="newEnvoyerEmail" value="#{utilisateursBean.nouvelUtilisateur.envoyerEmail}" />
<p:outputLabel for="newEnvoyerEmail" value="Envoyer les informations de connexion par email" styleClass="ml-2" />
</div>
</div>
</div>
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Créer l'utilisateur" icon="pi pi-check"
styleClass="ui-button-success"
action="#{utilisateursBean.creerUtilisateur}"
update="@form dtUtilisateurs"
oncomplete="if(!args.validationFailed) PF('dlgNouvelUtilisateur').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgNouvelUtilisateur').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</div>
</ui:define>
</ui:composition>