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,641 @@
<!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 Entités Enhanced - UnionFlow</ui:define>
<ui:define name="head">
<style>
.subscription-card {
transition: transform 0.2s ease;
}
.subscription-card:hover {
transform: translateY(-2px);
}
.quota-progress {
height: 6px;
border-radius: 3px;
overflow: hidden;
}
.quota-danger { background-color: #ef4444; }
.quota-warning { background-color: #f59e0b; }
.quota-success { background-color: #10b981; }
.expiration-alert { border-left: 4px solid #ef4444; }
.quota-alert { border-left: 4px solid #f59e0b; }
.forfait-starter { background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); }
.forfait-standard { background: linear-gradient(135deg, #10b981 0%, #047857 100%); }
.forfait-premium { background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); }
.forfait-cristal { background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%); }
</style>
</ui:define>
<ui:define name="content">
<!-- En-tête avec actions -->>
<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-building text-blue-500 mr-2"></i>
Gestion des Entités - Stratégie Volume
</h3>
<p class="text-600 m-0">Administration complète avec suivi des souscriptions et quotas</p>
</div>
<h:form id="formActionsEntete">
<div class="flex gap-2">
<p:commandButton value="Nouvelle entité"
icon="pi pi-plus"
styleClass="p-button-success"
onclick="PF('dlgNouvelleEntite').show();" />
<p:commandButton value="Gestion Quotas"
icon="pi pi-users"
styleClass="p-button-outlined p-button-warning"
action="#{entitesGestionBean.gererQuotas}" />
<p:commandButton value="Relances"
icon="pi pi-send"
styleClass="p-button-outlined p-button-info"
action="#{entitesGestionBean.envoyerRelancesSouscriptions}" />
<p:commandButton value="Exporter"
icon="pi pi-download"
styleClass="p-button-outlined p-button-secondary"
action="#{entitesGestionBean.exporterEntites}" />
</div>
</h:form>
</div>
</div>
</div>
</div>
<!-- Statistiques enrichies avec souscriptions -->>
<div class="grid">
<div class="col-12 md:col-3">
<div class="card subscription-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">#{entitesGestionBean.statistiques.totalEntites}</div>
<div class="text-blue-700 mb-2">Total Entités</div>
<div class="text-blue-600 text-sm">
<i class="pi pi-check-circle mr-1"></i>
#{entitesGestionBean.statistiques.entitesActives} actives
</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-building text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card subscription-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">#{entitesGestionBean.statistiques.totalMembres}</div>
<div class="text-green-700 mb-2">Total Membres</div>
<div class="text-green-600 text-sm">
<i class="pi pi-trending-up mr-1"></i>
Moyenne: 146/entité
</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 subscription-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">#{entitesGestionBean.statistiques.souscriptionsExpirantes}</div>
<div class="text-orange-700 mb-2">Expirations Proches</div>
<div class="text-orange-600 text-sm">
<i class="pi pi-clock mr-1"></i>
Sous 30 jours
</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-exclamation-triangle text-xl"></i>
</div>
</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="card subscription-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">#{entitesGestionBean.statistiques.entitesQuotaAtteint}</div>
<div class="text-purple-700 mb-2">Quotas Atteints</div>
<div class="text-purple-600 text-sm">
<i class="pi pi-info-circle mr-1"></i>
Nécessitent upgrade
</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-chart-pie text-xl"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Analyse des forfaits -->>
<div class="grid">
<div class="col-12 lg:col-8">
<div class="card">
<h5>Répartition par Forfait - Nouvelle Grille Tarifaire</h5>
<div class="grid">
<div class="col-6 md:col-3">
<div class="forfait-starter text-white p-3 border-round text-center">
<div class="font-bold text-2xl mb-1">44</div>
<div class="text-blue-100 text-sm mb-2">Starter</div>
<div class="text-blue-200 text-xs mb-1">2K FCFA/mois</div>
<div class="text-blue-200 text-xs">100 membres max</div>
</div>
</div>
<div class="col-6 md:col-3">
<div class="forfait-standard text-white p-3 border-round text-center">
<div class="font-bold text-2xl mb-1">60</div>
<div class="text-green-100 text-sm mb-2">Standard</div>
<div class="text-green-200 text-xs mb-1">3K FCFA/mois</div>
<div class="text-green-200 text-xs">200 membres max</div>
</div>
</div>
<div class="col-6 md:col-3">
<div class="forfait-premium text-white p-3 border-round text-center">
<div class="font-bold text-2xl mb-1">20</div>
<div class="text-orange-100 text-sm mb-2">Premium</div>
<div class="text-orange-200 text-xs mb-1">4K FCFA/mois</div>
<div class="text-orange-200 text-xs">500 membres max</div>
</div>
</div>
<div class="col-6 md:col-3">
<div class="forfait-cristal text-white p-3 border-round text-center">
<div class="font-bold text-2xl mb-1">3</div>
<div class="text-purple-100 text-sm mb-2">Cristal</div>
<div class="text-purple-200 text-xs mb-1">5K FCFA/mois</div>
<div class="text-purple-200 text-xs">2000 membres max</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 lg:col-4">
<div class="card">
<h5>Performance Commerciale</h5>
<div class="grid">
<div class="col-6">
<div class="text-center p-3 surface-100 border-round">
<div class="text-2xl font-bold text-green-500 mb-1">#{entitesGestionBean.statistiques.revenus}</div>
<div class="text-600 text-sm">Revenus Mensuels</div>
</div>
</div>
<div class="col-6">
<div class="text-center p-3 surface-100 border-round">
<div class="text-2xl font-bold text-blue-500 mb-1">#{entitesGestionBean.statistiques.tauxRenouvellementFormat}</div>
<div class="text-600 text-sm">Taux Renouvellement</div>
</div>
</div>
</div>
<div class="mt-3 p-3 surface-50 border-round">
<div class="text-900 font-medium mb-2">Forfait le plus populaire</div>
<div class="flex align-items-center">
<p:tag value="#{entitesGestionBean.statistiques.formulairePopulaire}" severity="success" />
<span class="text-600 text-sm ml-2">60 souscriptions</span>
</div>
</div>
</div>
</div>
</div>
<!-- Filtres enrichis -->>
<div class="card">
<h5>Filtres et Recherche Avancée</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="searchNom" value="Nom de l'entité" />
<p:inputText id="searchNom" value="#{entitesGestionBean.filtres.nom}"
placeholder="Rechercher par nom...">
<p:ajax event="keyup" update="dtEntites @(.stats-summary)" />
</p:inputText>
</div>
</div>
<div class="col-12 md:col-2">
<div class="field">
<p:outputLabel for="filterType" value="Type" />
<p:selectOneMenu id="filterType" value="#{entitesGestionBean.filtres.type}">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="Association" itemValue="ASSOCIATION" />
<f:selectItem itemLabel="Club" itemValue="CLUB" />
<f:selectItem itemLabel="Groupe" itemValue="GROUPE" />
<f:selectItem itemLabel="Branche" itemValue="BRANCHE" />
<p:ajax update="dtEntites @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-2">
<div class="field">
<p:outputLabel for="filterStatut" value="Statut" />
<p:selectOneMenu id="filterStatut" value="#{entitesGestionBean.filtres.statut}">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="Active" itemValue="ACTIVE" />
<f:selectItem itemLabel="Inactive" itemValue="INACTIVE" />
<f:selectItem itemLabel="Suspendue" itemValue="SUSPENDUE" />
<p:ajax update="dtEntites @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-2">
<div class="field">
<p:outputLabel for="filterRegion" value="Région" />
<p:selectOneMenu id="filterRegion" value="#{entitesGestionBean.filtres.region}">
<f:selectItem itemLabel="Toutes" itemValue="" />
<f:selectItem itemLabel="Région 1" itemValue="REGION_1" />
<f:selectItem itemLabel="Région 2" itemValue="REGION_2" />
<f:selectItem itemLabel="Région 3" itemValue="REGION_3" />
<p:ajax update="dtEntites @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel value="Actions rapides" />
<div class="flex gap-2 mt-1">
<p:commandButton value="Rechercher"
icon="pi pi-search"
styleClass="p-button-primary p-button-sm"
action="#{entitesGestionBean.rechercher}"
update="dtEntites @(.stats-summary)" />
<p:commandButton value="Reset"
icon="pi pi-refresh"
styleClass="p-button-outlined p-button-secondary p-button-sm"
action="#{entitesGestionBean.reinitialiserFiltres}"
update="@form dtEntites @(.stats-summary)" />
</div>
</div>
</div>
</div>
<!-- Filtres avancés - Section extensible -->
<p:togglePanel id="filtresAvances" header="Filtres Avancés (Souscriptions &amp; Financier)"
styleClass="mt-3" collapsed="true">
<div class="grid mt-2">
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="filterForfait" value="Forfait" />
<p:selectOneMenu id="filterForfait" value="#{entitesGestionBean.filtres.forfait}">
<f:selectItem itemLabel="Tous les forfaits" itemValue="" />
<f:selectItem itemLabel="Starter (2K)" itemValue="Starter" />
<f:selectItem itemLabel="Standard (3K)" itemValue="Standard" />
<f:selectItem itemLabel="Premium (4K)" itemValue="Premium" />
<f:selectItem itemLabel="Cristal (5K)" itemValue="Cristal" />
<p:ajax update="dtEntites @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="filterQuota" value="Alerte Quota" />
<p:selectOneMenu id="filterQuota" value="#{entitesGestionBean.filtres.alerteQuota}">
<f:selectItem itemLabel="Toutes" itemValue="" />
<f:selectItem itemLabel="Quota proche/atteint" itemValue="OUI" />
<f:selectItem itemLabel="Quota normal" itemValue="NON" />
<p:ajax update="dtEntites @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="filterExpiration" value="Expiration Proche" />
<p:selectOneMenu id="filterExpiration" value="#{entitesGestionBean.filtres.alerteExpiration}">
<f:selectItem itemLabel="Toutes" itemValue="" />
<f:selectItem itemLabel="Expire sous 30j" itemValue="OUI" />
<f:selectItem itemLabel="Valide >30j" itemValue="NON" />
<p:ajax update="dtEntites @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
<div class="col-12 md:col-3">
<div class="field">
<p:outputLabel for="filterStatutSouscription" value="Statut Souscription" />
<p:selectOneMenu id="filterStatutSouscription" value="#{entitesGestionBean.filtres.statutSouscription}">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="Active" itemValue="ACTIVE" />
<f:selectItem itemLabel="Expirée" itemValue="EXPIRED" />
<f:selectItem itemLabel="Suspendue" itemValue="SUSPENDED" />
<p:ajax update="dtEntites @(.stats-summary)" />
</p:selectOneMenu>
</div>
</div>
</div>
</p:togglePanel>
</div>
</div>
</h:form>
</div>
<!-- Table enrichie des entités -->>
<div class="card">
<div class="flex align-items-center justify-content-between mb-3">
<h5 class="m-0">Entités avec Souscriptions (#{entitesGestionBean.entitesFiltrees.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="p-button-outlined p-button-warning"
onclick="PF('dlgActionsGroupees').show();"
disabled="#{empty entitesGestionBean.entitesSelectionnees}" />
</h:form>
<span class="text-600 text-sm stats-summary">
#{entitesGestionBean.entitesFiltrees.size()} sur #{entitesGestionBean.toutesLesEntites.size()} entités
</span>
</div>
</div>
<p:dataTable id="dtEntites"
value="#{entitesGestionBean.entitesFiltrees}"
var="entite"
selection="#{entitesGestionBean.entitesSelectionnees}"
rowKey="#{entite.id}"
paginator="true"
rows="15"
paginatorPosition="both"
sortMode="single"
styleClass="p-datatable-sm"
emptyMessage="Aucune entité trouvée">
<p:column selectionMode="multiple" width="40" />
<p:column headerText="Entité" sortBy="#{entite.nom}" width="220">
<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 #{entite.typeIcon}"></i>
</div>
<div>
<div class="text-900 font-medium">#{entite.nom}</div>
<div class="text-600 text-sm">#{entite.codeEntite}</div>
</div>
</div>
</p:column>
<p:column headerText="Forfait" sortBy="#{entite.forfaitSouscrit}" width="120">
<div class="text-center">
<p:tag value="#{entite.forfaitSouscrit}"
severity="#{entite.forfaitCouleur}"
icon="pi #{entite.forfaitIcone}" />
<div class="text-600 text-xs mt-1">#{entite.montantMensuel}</div>
</div>
</p:column>
<p:column headerText="Quota Membres" sortBy="#{entite.membresUtilises}" width="140">
<div class="text-center">
<div class="text-900 font-bold mb-1">#{entite.membresUtilises}/#{entite.membresQuota}</div>
<div class="quota-progress #{entite.quotaAtteint ? 'quota-danger' : entite.quotaProche ? 'quota-warning' : 'quota-success'}">
<div style="width: #{entite.pourcentageUtilisationQuota}%; height: 100%; background: rgba(255,255,255,0.8);"></div>
</div>
<div class="text-600 text-xs mt-1">#{entite.pourcentageUtilisationQuota}%</div>
</div>
</p:column>
<p:column headerText="Expiration" sortBy="#{entite.dateExpirationSouscription}" width="120">
<div class="text-center">
<div class="text-900 text-sm mb-1">
#{entite.dateExpirationSouscription != null ? entite.dateExpirationSouscription.format(java.time.format.DateTimeFormatter.ofPattern('dd/MM/yyyy')) : 'N/A'}
</div>
<div class="text-#{entite.expirationProche ? 'red' : 'green'}-600 text-xs">
<i class="pi pi-clock mr-1"></i>
#{entite.joursAvantExpiration} jours
</div>
</div>
</p:column>
<p:column headerText="Région" sortBy="#{entite.region}" width="100">
<span class="text-900">#{entite.region}</span>
</p:column>
<p:column headerText="Statut" sortBy="#{entite.statut}" width="100">
<p:tag value="#{entite.statut}"
severity="#{entite.statutSeverity}"
icon="pi #{entite.statutIcon}" />
</p:column>
<p:column headerText="Actions" width="150">
<h:form id="formActions#{entite.id}">
<div class="flex gap-1">
<p:commandButton icon="pi pi-eye"
styleClass="p-button-rounded p-button-text p-button-info"
action="#{entitesGestionBean.voirEntite(entite)}"
title="Voir détails" />
<p:commandButton icon="pi pi-refresh"
styleClass="p-button-rounded p-button-text p-button-success"
onclick="PF('dlgRenouvelerSouscription').show();"
title="Renouveler"
rendered="#{entite.expirationProche}">
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
</p:commandButton>
<p:commandButton icon="pi pi-arrow-up"
styleClass="p-button-rounded p-button-text p-button-warning"
onclick="PF('dlgUpgraderForfait').show();"
title="Upgrader"
rendered="#{entite.quotaProche}">
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
</p:commandButton>
<p:commandButton icon="pi pi-cog"
styleClass="p-button-rounded p-button-text p-button-secondary"
onclick="PF('dlgActionsEntite').show();"
title="Actions">
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
</p:commandButton>
</div>
</h:form>
</p:column>
</p:dataTable>
</div>
<!-- Dialog Renouveler Souscription -->>
<p:dialog header="Renouveler la Souscription" widgetVar="dlgRenouvelerSouscription" modal="true" width="500">
<h:form id="formRenouvelerSouscription">
<div class="ui-fluid">
<div class="text-center mb-4">
<i class="pi pi-refresh text-green-500 text-4xl mb-2"></i>
<h4>Confirmer le renouvellement</h4>
<p class="text-600">
Entité: <strong>#{entitesGestionBean.entiteSelectionne.nom}</strong><br/>
Forfait: <strong>#{entitesGestionBean.entiteSelectionne.forfaitSouscrit}</strong><br/>
Montant: <strong>#{entitesGestionBean.entiteSelectionne.montantMensuel}</strong>
</p>
</div>
<div class="flex gap-2 justify-content-center">
<p:commandButton value="Confirmer" icon="pi pi-check"
styleClass="p-button-success"
action="#{entitesGestionBean.renouvelerSouscription}"
update="dtEntites @(.stats-summary)"
oncomplete="PF('dlgRenouvelerSouscription').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="p-button-secondary"
onclick="PF('dlgRenouvelerSouscription').hide();" type="button" />
</div>
</div>
</h:form>
</p:dialog>
<!-- Dialog Upgrader Forfait -->>
<p:dialog header="Upgrader le Forfait" widgetVar="dlgUpgraderForfait" modal="true" width="500">
<h:form id="formUpgraderForfait">
<div class="ui-fluid">
<div class="text-center mb-4">
<i class="pi pi-arrow-up text-orange-500 text-4xl mb-2"></i>
<h4>Upgrader le forfait</h4>
<p class="text-600">
Entité: <strong>#{entitesGestionBean.entiteSelectionne.nom}</strong><br/>
Forfait actuel: <strong>#{entitesGestionBean.entiteSelectionne.forfaitSouscrit}</strong><br/>
Quota utilisé: <strong>#{entitesGestionBean.entiteSelectionne.pourcentageUtilisationQuota}%</strong>
</p>
</div>
<div class="flex gap-2 justify-content-center">
<p:commandButton value="Upgrader" icon="pi pi-arrow-up"
styleClass="p-button-warning"
action="#{entitesGestionBean.upgraderForfait}"
update="dtEntites @(.stats-summary)"
oncomplete="PF('dlgUpgraderForfait').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="p-button-secondary"
onclick="PF('dlgUpgraderForfait').hide();" type="button" />
</div>
</div>
</h:form>
</p:dialog>
<!-- Dialog Actions Groupées -->>
<p:dialog header="Actions Groupées" widgetVar="dlgActionsGroupees" modal="true" width="600">
<h:form id="formActionsGroupees">
<div class="ui-fluid">
<div class="text-center mb-4">
<i class="pi pi-cog text-orange-500 text-4xl mb-2"></i>
<h4>Actions sur #{entitesGestionBean.entitesSelectionnees.size()} entités sélectionnées</h4>
</div>
<div class="grid">
<div class="col-12 md:col-6">
<h6>Actions de Souscription</h6>
<p:commandButton value="Renouveler toutes"
icon="pi pi-refresh"
styleClass="p-button-success w-full mb-2"
action="#{entitesGestionBean.renouvelerSouscriptionsGroupees}"
update="dtEntites @(.stats-summary)"
oncomplete="PF('dlgActionsGroupees').hide();"
onclick="return confirm('Renouveler les souscriptions de toutes les entités sélectionnées ?');" />
<p:commandButton value="Envoyer relances"
icon="pi pi-send"
styleClass="p-button-info w-full mb-2"
action="#{entitesGestionBean.envoyerRelancesSouscriptions}"
oncomplete="PF('dlgActionsGroupees').hide();" />
<p:commandButton value="Proposer upgrade"
icon="pi pi-arrow-up"
styleClass="p-button-warning w-full mb-2"
action="#{entitesGestionBean.proposerUpgradeGroupees}"
oncomplete="PF('dlgActionsGroupees').hide();" />
</div>
<div class="col-12 md:col-6">
<h6>Actions Administratives</h6>
<p:commandButton value="Suspendre toutes"
icon="pi pi-ban"
styleClass="p-button-danger w-full mb-2"
action="#{entitesGestionBean.suspendreEntitesGroupees}"
update="dtEntites @(.stats-summary)"
oncomplete="PF('dlgActionsGroupees').hide();"
onclick="return confirm('ATTENTION: Suspendre toutes les entités sélectionnées ?');" />
<p:commandButton value="Réactiver toutes"
icon="pi pi-check"
styleClass="p-button-success w-full mb-2"
action="#{entitesGestionBean.reactiverEntitesGroupees}"
update="dtEntites @(.stats-summary)"
oncomplete="PF('dlgActionsGroupees').hide();" />
<p:commandButton value="Exporter sélection"
icon="pi pi-download"
styleClass="p-button-secondary w-full mb-2"
action="#{entitesGestionBean.exporterEntites}" />
</div>
</div>
<div class="flex justify-content-end mt-4 pt-3 border-top-1 surface-border">
<p:commandButton value="Fermer" icon="pi pi-times"
styleClass="p-button-secondary"
onclick="PF('dlgActionsGroupees').hide();" type="button" />
</div>
</div>
</h:form>
</p:dialog>
<!-- Dialog Actions Entité (conservé de l'original) -->>
<p:dialog header="Actions sur l'Entité" widgetVar="dlgActionsEntite" modal="true" width="400">
<h:form id="formActionsEntite">
<div class="grid">
<div class="col-12">
<p:commandButton value="Gérer les membres"
icon="pi pi-users"
styleClass="p-button-outlined p-button-info w-full mb-2"
action="#{entitesGestionBean.gererMembres}" />
<p:commandButton value="Configuration"
icon="pi pi-cog"
styleClass="p-button-outlined p-button-warning w-full mb-2"
action="#{entitesGestionBean.configurerEntite}" />
<p:commandButton value="Rapports"
icon="pi pi-chart-bar"
styleClass="p-button-outlined p-button-secondary w-full mb-2"
action="#{entitesGestionBean.voirRapports}" />
<p:commandButton value="Suspendre"
icon="pi pi-ban"
styleClass="p-button-outlined p-button-danger w-full mb-2"
action="#{entitesGestionBean.suspendreEntite}"
onclick="return confirm('Êtes-vous sûr de vouloir suspendre cette entité ?');"
rendered="#{entitesGestionBean.entiteSelectionne.statut == 'ACTIVE'}" />
<p:commandButton value="Réactiver"
icon="pi pi-check"
styleClass="p-button-outlined p-button-success w-full mb-2"
action="#{entitesGestionBean.reactiverEntite}"
rendered="#{entitesGestionBean.entiteSelectionne.statut == 'SUSPENDUE'}" />
</div>
</div>
<div class="flex justify-content-end mt-3">
<p:commandButton value="Fermer" icon="pi pi-times"
styleClass="p-button-secondary"
onclick="PF('dlgActionsEntite').hide();" type="button" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>

View File

@@ -0,0 +1,433 @@
<!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 Entités - 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-building text-blue-500 mr-2"></i>
Gestion des Entités
</h2>
<p class="text-600 mt-0">
Administration complète des clubs et entités Lions •
<span class="font-semibold">#{entitesGestionBean.statistiques.totalEntites} entités</span>
<span class="font-semibold text-green-600">#{entitesGestionBean.statistiques.entitesActives} actives</span>
</p>
</div>
<div class="field col-12 lg:col-4 text-right">
<h:form id="formActionsEntete">
<p:commandButton icon="pi pi-plus"
title="Nouvelle entité"
styleClass="ui-button-success ui-button-sm mr-3"
onclick="PF('dlgNouvelleEntite').show();" />
<p:commandButton icon="pi pi-upload"
title="Import Excel"
styleClass="ui-button-info ui-button-outlined ui-button-sm mr-3"
onclick="PF('dlgImportEntites').show();" />
<p:commandButton icon="pi pi-download"
title="Exporter"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
action="#{entitesGestionBean.exporterEntites}" />
</h:form>
</div>
</div>
</div>
<!-- KPIs avec grille Freya stricte -->
<div class="formgrid grid">
<!-- KPI 1: Total Entités -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Total Entités" />
<ui:param name="value" value="#{entitesGestionBean.statistiques.totalEntites}" />
<ui:param name="icon" value="pi-building" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="growthValue" value="8" />
<ui:param name="growthLabel" value="ce mois" />
<ui:param name="growthType" value="number" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 2: Entités Actives -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Entités Actives" />
<ui:param name="value" value="#{entitesGestionBean.statistiques.entitesActives}" />
<ui:param name="icon" value="pi-check" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="progressValue" value="92" />
<ui:param name="noDataLabel" value="92% d'activité" />
<ui:param name="showGrowth" value="false" />
</ui:include>
<!-- KPI 3: Total Membres -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Total Membres" />
<ui:param name="value" value="#{entitesGestionBean.statistiques.totalMembres}" />
<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="#{entitesGestionBean.statistiques.moyenneMembresParEntite}/entité" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 4: Revenus Totaux -->
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Revenus Totaux" />
<ui:param name="value" value="#{entitesGestionBean.statistiques.revenus}" />
<ui:param name="icon" value="pi-dollar" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="growthValue" value="15" />
<ui:param name="growthLabel" value="vs année dernière" />
<ui:param name="showProgress" value="false" />
</ui:include>
</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">
<div class="field col-12 md:col-6 lg:col-3">
<label for="searchNom" class="block text-900 font-medium mb-2">Nom de l'entité</label>
<span class="p-input-icon-left w-full">
<i class="pi pi-search"></i>
<p:inputText id="searchNom"
value="#{entitesGestionBean.filtres.nom}"
placeholder="Rechercher par nom..."
styleClass="w-full">
<p:ajax event="keyup" delay="300"
update=":formTableEntites:dtEntites" />
</p:inputText>
</span>
</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'entité</label>
<p:selectOneMenu id="filterType"
value="#{entitesGestionBean.filtres.type}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les types" itemValue="" />
<f:selectItem itemLabel="Club Lions" itemValue="CLUB_LIONS" />
<f:selectItem itemLabel="LEO Club" itemValue="LEO_CLUB" />
<f:selectItem itemLabel="Branche" itemValue="BRANCHE" />
<p:ajax update=":formTableEntites:dtEntites" />
</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="#{entitesGestionBean.filtres.statut}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItem itemLabel="Active" itemValue="ACTIVE" />
<f:selectItem itemLabel="Inactive" itemValue="INACTIVE" />
<f:selectItem itemLabel="Suspendue" itemValue="SUSPENDUE" />
<p:ajax update=":formTableEntites:dtEntites" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="filterRegion" class="block text-900 font-medium mb-2">Région</label>
<p:selectOneMenu id="filterRegion"
value="#{entitesGestionBean.filtres.region}"
styleClass="w-full">
<f:selectItem itemLabel="Toutes les régions" itemValue="" />
<f:selectItem itemLabel="Dakar" itemValue="DAKAR" />
<f:selectItem itemLabel="Thiès" itemValue="THIES" />
<f:selectItem itemLabel="Kaolack" itemValue="KAOLACK" />
<f:selectItem itemLabel="Saint-Louis" itemValue="SAINT_LOUIS" />
<p:ajax update=":formTableEntites:dtEntites" />
</p:selectOneMenu>
</div>
</div>
<div class="flex justify-content-end mt-3">
<p:commandButton value="Réinitialiser"
icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary ui-button-sm"
action="#{entitesGestionBean.reinitialiserFiltres}"
update="@form :formTableEntites:dtEntites" />
</div>
</h:form>
</div>
<!-- Table des Entités avec structure Freya -->
<div class="card">
<h:form id="formTableEntites">
<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 Entités
</h5>
<div>
<p:commandButton value="Actions groupées"
icon="pi pi-bars"
styleClass="ui-button-warning ui-button-sm mr-2"
onclick="PF('dlgActionsGroupees').show();"
disabled="#{empty entitesGestionBean.entitesSelectionnees}" />
<p:commandButton value="Export Excel"
icon="pi pi-file-excel"
styleClass="ui-button-success ui-button-outlined ui-button-sm"
action="#{entitesGestionBean.exporterExcel}" />
</div>
</div>
<p:dataTable id="dtEntites"
value="#{entitesGestionBean.entitesFiltrees}"
var="entite"
selection="#{entitesGestionBean.entitesSelectionnees}"
rowKey="#{entite.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} entités"
styleClass="p-datatable-sm p-datatable-gridlines p-datatable-striped"
emptyMessage="Aucune entité trouvée">
<p:column selectionMode="multiple" style="width:3rem" exportable="false"/>
<p:column headerText="Entité" sortBy="#{entite.nom}" filterBy="#{entite.nom}">
<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 #{entite.typeIcon} text-primary-600"></i>
</div>
<div>
<div class="text-900 font-medium">#{entite.nom}</div>
<div class="text-500 text-xs">#{entite.codeEntite}</div>
</div>
</div>
</p:column>
<p:column headerText="Type" sortBy="#{entite.type}" filterBy="#{entite.type}" style="width:8rem">
<p:tag value="#{entite.typeLibelle}"
severity="#{entite.typeSeverity}"
icon="pi #{entite.typeIcon}"
styleClass="text-xs" />
</p:column>
<p:column headerText="Région" sortBy="#{entite.region}" style="width:8rem">
<span class="text-900 font-medium">#{entite.region}</span>
</p:column>
<p:column headerText="Membres" sortBy="#{entite.nombreMembres}" style="width:6rem; text-align:center">
<div class="text-center">
<div class="text-900 font-bold">#{entite.nombreMembres}</div>
<div class="text-500 text-xs">membres</div>
</div>
</p:column>
<p:column headerText="Administrateur">
<div class="flex align-items-center" rendered="#{entite.administrateur != null}">
<div class="bg-300 border-circle mr-2" style="width: 1.5rem; height: 1.5rem;"></div>
<div>
<div class="text-900 text-sm">#{entite.administrateur.nomComplet}</div>
<div class="text-500 text-xs">#{entite.administrateur.email}</div>
</div>
</div>
<span class="text-400 text-xs" rendered="#{entite.administrateur == null}">
Aucun administrateur
</span>
</p:column>
<p:column headerText="Dernière activité" sortBy="#{entite.derniereActivite}" style="width:10rem">
<div class="text-900 text-sm">#{entite.derniereActiviteFormatee}</div>
<div class="text-500 text-xs">#{entite.derniereActiviteRelative}</div>
</p:column>
<p:column headerText="Statut" sortBy="#{entite.statut}" filterBy="#{entite.statut}" style="width:7rem">
<p:tag value="#{entite.statut}"
severity="#{entite.statutSeverity}"
icon="pi #{entite.statutIcon}"
styleClass="text-xs w-full" />
</p:column>
<p:column headerText="Actions" style="width:8rem" exportable="false">
<h:form id="formActions#{entite.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"
action="#{entitesGestionBean.voirEntite(entite)}"
title="Voir détails" />
<p:commandButton icon="pi pi-pencil"
styleClass="ui-button-rounded ui-button-text ui-button-warning ui-button-sm"
onclick="PF('dlgModifierEntite').show();"
title="Modifier">
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
</p:commandButton>
<p:commandButton icon="pi pi-cog"
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
onclick="PF('dlgActionsEntite').show();"
title="Actions">
<f:setPropertyActionListener target="#{entitesGestionBean.entiteSelectionne}" value="#{entite}" />
</p:commandButton>
</div>
</h:form>
</p:column>
</p:dataTable>
</h:form>
</div>
</div>
<!-- Dialogs avec structure Freya -->
<!-- Dialog Nouvelle Entité -->
<p:dialog header="Créer une Nouvelle Entité"
widgetVar="dlgNouvelleEntite"
modal="true"
width="700"
height="auto"
resizable="false">
<h:form id="formNouvelleEntite">
<div class="ui-fluid formgrid grid">
<div class="field col-12 md:col-6">
<label for="newNom" class="block text-900 font-medium mb-2">Nom de l'entité *</label>
<p:inputText id="newNom"
value="#{entitesGestionBean.nouvelleEntite.nom}"
required="true"
placeholder="Ex: Lions Club Dakar Centre" />
</div>
<div class="field col-12 md:col-6">
<label for="newType" class="block text-900 font-medium mb-2">Type d'entité *</label>
<p:selectOneMenu id="newType"
value="#{entitesGestionBean.nouvelleEntite.type}"
required="true">
<f:selectItem itemLabel="Sélectionner un type" itemValue="" />
<f:selectItem itemLabel="Club Lions" itemValue="CLUB_LIONS" />
<f:selectItem itemLabel="LEO Club" itemValue="LEO_CLUB" />
<f:selectItem itemLabel="Branche" itemValue="BRANCHE" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<label for="newRegion" class="block text-900 font-medium mb-2">Région *</label>
<p:selectOneMenu id="newRegion"
value="#{entitesGestionBean.nouvelleEntite.region}"
required="true">
<f:selectItem itemLabel="Sélectionner une région" itemValue="" />
<f:selectItem itemLabel="Dakar" itemValue="DAKAR" />
<f:selectItem itemLabel="Thiès" itemValue="THIES" />
<f:selectItem itemLabel="Kaolack" itemValue="KAOLACK" />
<f:selectItem itemLabel="Saint-Louis" itemValue="SAINT_LOUIS" />
</p:selectOneMenu>
</div>
<div class="field col-12 md:col-6">
<label for="newTelephone" class="block text-900 font-medium mb-2">Téléphone</label>
<p:inputText id="newTelephone"
value="#{entitesGestionBean.nouvelleEntite.telephone}"
placeholder="77 123 45 67" />
</div>
<div class="field col-12">
<label for="newEmail" class="block text-900 font-medium mb-2">Email</label>
<p:inputText id="newEmail"
value="#{entitesGestionBean.nouvelleEntite.email}"
placeholder="contact@lionsclub-dakar.sn" />
</div>
<div class="field col-12">
<label for="newAdresse" class="block text-900 font-medium mb-2">Adresse</label>
<p:inputTextarea id="newAdresse"
value="#{entitesGestionBean.nouvelleEntite.adresse}"
rows="2"
placeholder="Adresse complète de l'entité..." />
</div>
<div class="field col-12">
<label for="newDescription" class="block text-900 font-medium mb-2">Description</label>
<p:inputTextarea id="newDescription"
value="#{entitesGestionBean.nouvelleEntite.description}"
rows="3"
placeholder="Description de l'entité..." />
</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('dlgNouvelleEntite').hide();"
type="button" />
<p:commandButton value="Créer l'entité"
icon="pi pi-check"
styleClass="ui-button-success ui-button-sm"
action="#{entitesGestionBean.creerEntite}"
update="@form :formTableEntites:dtEntites"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleEntite').hide();" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Actions Entité -->
<p:dialog header="Actions sur l'Entité"
widgetVar="dlgActionsEntite"
modal="true"
width="400"
height="auto"
resizable="false">
<h:form id="formActionsEntite">
<div class="surface-50 border-round-lg p-3 mb-3">
<div class="text-500 text-sm mb-1">Entité sélectionnée</div>
<div class="text-900 font-bold">#{entitesGestionBean.entiteSelectionne.nom}</div>
<div class="text-500 text-sm">#{entitesGestionBean.entiteSelectionne.codeEntite}</div>
</div>
<div class="flex flex-column gap-2">
<p:commandButton value="Gérer les membres"
icon="pi pi-users"
styleClass="ui-button-info ui-button-outlined ui-button-sm w-full"
action="#{entitesGestionBean.gererMembres}" />
<p:commandButton value="Configuration"
icon="pi pi-cog"
styleClass="ui-button-warning ui-button-outlined ui-button-sm w-full"
action="#{entitesGestionBean.configurerEntite}" />
<p:commandButton value="Rapports"
icon="pi pi-chart-bar"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm w-full"
action="#{entitesGestionBean.voirRapports}" />
<p:commandButton value="Suspendre"
icon="pi pi-ban"
styleClass="ui-button-danger ui-button-outlined ui-button-sm w-full"
action="#{entitesGestionBean.suspendreEntite}"
onclick="return confirm('Êtes-vous sûr de vouloir suspendre cette entité ?');"
rendered="#{entitesGestionBean.entiteSelectionne.statut == 'ACTIVE'}" />
<p:commandButton value="Réactiver"
icon="pi pi-check"
styleClass="ui-button-success ui-button-outlined ui-button-sm w-full"
action="#{entitesGestionBean.reactiverEntite}"
rendered="#{entitesGestionBean.entiteSelectionne.statut == 'SUSPENDUE'}" />
<hr class="surface-border" />
<p:commandButton value="Supprimer"
icon="pi pi-trash"
styleClass="ui-button-danger ui-button-sm w-full"
onclick="return confirm('ATTENTION: Cette action est irréversible. Confirmer la suppression ?');"
action="#{entitesGestionBean.supprimerEntite}" />
</div>
</h:form>
</p:dialog>
</ui:define>
</ui:composition>