Ajout des Dockerfiles et configuration de production pour déploiement unionflow

This commit is contained in:
dahoud
2025-12-09 19:37:23 +00:00
parent 1e835ba2c3
commit bba28595f6
40 changed files with 1762 additions and 1652 deletions

View File

@@ -123,6 +123,13 @@
<version>1.0.0</version>
</dependency>
<!-- Lions User Manager Client - Module réutilisable de gestion d'utilisateurs Keycloak -->
<dependency>
<groupId>dev.lions.user.manager</groupId>
<artifactId>lions-user-manager-client-quarkus-primefaces-freya</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Scheduler pour le rafraîchissement des tokens -->
<dependency>
<groupId>io.quarkus</groupId>

View File

@@ -82,20 +82,42 @@ public interface MembreService {
@GET
@Path("/export")
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
@Produces({"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "text/csv", "application/pdf", "application/json"})
byte[] exporterExcel(
@QueryParam("format") @DefaultValue("EXCEL") String format,
@QueryParam("associationId") UUID associationId,
@QueryParam("statut") String statut
@QueryParam("statut") String statut,
@QueryParam("type") String type,
@QueryParam("dateAdhesionDebut") String dateAdhesionDebut,
@QueryParam("dateAdhesionFin") String dateAdhesionFin,
@QueryParam("colonnes") List<String> colonnesExport,
@QueryParam("inclureHeaders") @DefaultValue("true") boolean inclureHeaders,
@QueryParam("formaterDates") @DefaultValue("true") boolean formaterDates,
@QueryParam("inclureStatistiques") @DefaultValue("false") boolean inclureStatistiques,
@QueryParam("motDePasse") String motDePasse
);
@GET
@Path("/export/count")
@Produces(MediaType.APPLICATION_JSON)
Long compterMembresPourExport(
@QueryParam("associationId") UUID associationId,
@QueryParam("statut") String statut,
@QueryParam("type") String type,
@QueryParam("dateAdhesionDebut") String dateAdhesionDebut,
@QueryParam("dateAdhesionFin") String dateAdhesionFin
);
@POST
@Path("/import")
@Consumes(MediaType.MULTIPART_FORM_DATA)
ResultatImportDTO importerDonnees(
@FormParam("file") java.io.InputStream fileInputStream,
@FormParam("associationId") UUID associationId
);
@Produces(MediaType.APPLICATION_JSON)
ResultatImportDTO importerDonnees(MembreImportMultipartForm form);
@GET
@Path("/import/modele")
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
byte[] telechargerModeleImport();
@GET
@Path("/autocomplete/villes")

View File

@@ -114,7 +114,7 @@ public class AuditBean implements Serializable {
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des logs: " + e.getMessage());
e.printStackTrace();
LOGGER.log(java.util.logging.Level.SEVERE, "Détails de l'erreur de chargement des logs d'audit", e);
tousLesLogs = new ArrayList<>();
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
"Erreur lors du chargement des logs: " + e.getMessage());

View File

@@ -5,8 +5,6 @@ import jakarta.inject.Named;
import jakarta.annotation.PostConstruct;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
@@ -42,51 +40,58 @@ public class DemandesBean implements Serializable {
private String commentaireAssignation;
// Statistiques
private int enAttente = 12;
private int urgentes = 5;
private int traitees = 143;
private int delaiMoyenTraitement = 3;
private int enAttente = 0;
private int urgentes = 0;
private int traitees = 0;
private int delaiMoyenTraitement = 0;
@PostConstruct
public void init() {
initializeDemandes();
initializeGestionnaires();
initializeNouvelleDemande();
calculerStatistiques();
selectedDemandes = new ArrayList<>();
}
private void initializeDemandes() {
demandes = new ArrayList<>();
String[] objets = {
"Demande d'aide financière urgente", "Certificat de membership",
"Mutation vers club Dakar", "Réclamation cotisation",
"Aide médicale famille", "Certificat de bonne conduite"
};
String[] types = {"AIDE_FINANCIERE", "CERTIFICAT", "MUTATION", "RECLAMATION", "AIDE_FINANCIERE", "CERTIFICAT"};
String[] statuts = {"EN_ATTENTE", "EN_COURS", "APPROUVEE", "EN_ATTENTE", "URGENTE", "EN_COURS"};
String[] priorites = {"URGENTE", "NORMALE", "NORMALE", "BASSE", "URGENTE", "NORMALE"};
String[] demandeurs = {"Marie Kouassi", "Paul Traoré", "Fatou Sanogo", "Jean Ouattara", "Aissata Koné", "Ibrahim Touré"};
for (int i = 0; i < objets.length; i++) {
Demande demande = new Demande();
demande.setId(UUID.fromString(String.format("00000000-0000-0000-0000-%012d", i + 1)));
demande.setReference("DEM-2024-" + String.format("%04d", i + 1));
demande.setObjet(objets[i]);
demande.setType(types[i]);
demande.setStatut(statuts[i]);
demande.setPriorite(priorites[i]);
demande.setNomDemandeur(demandeurs[i]);
demande.setNumeroMembre("M" + String.format("%06d", 1000 + i));
demande.setTelephoneDemandeur("+225 07 " + String.format("%02d", 10 + i) + " " + String.format("%02d", 20 + i) + " " + String.format("%02d", 30 + i));
demande.setDateDepot(LocalDate.now().minusDays(i * 2));
demande.setDateEcheance(LocalDate.now().plusDays(7 + i));
demande.setHeureDepot(LocalDateTime.now().minusHours(i * 3).format(DateTimeFormatter.ofPattern("HH:mm")));
if (i % 3 != 0) demande.setAssigneA("Gestionnaire " + (i % 3 + 1));
demandes.add(demande);
// TODO: Charger depuis le backend via DemandeAideService
// Pour l'instant, liste vide - les données viendront du backend
}
private void calculerStatistiques() {
if (demandes == null || demandes.isEmpty()) {
enAttente = 0;
urgentes = 0;
traitees = 0;
delaiMoyenTraitement = 0;
return;
}
// Calculer depuis les données réelles
enAttente = (int) demandes.stream()
.filter(d -> "EN_ATTENTE".equals(d.getStatut()))
.count();
urgentes = (int) demandes.stream()
.filter(d -> "URGENTE".equals(d.getPriorite()))
.count();
traitees = (int) demandes.stream()
.filter(d -> "APPROUVEE".equals(d.getStatut()) || "REJETEE".equals(d.getStatut()))
.count();
// Calculer le délai moyen de traitement
long totalJours = demandes.stream()
.filter(d -> d.getDateDepot() != null && "APPROUVEE".equals(d.getStatut()))
.mapToLong(d -> ChronoUnit.DAYS.between(d.getDateDepot(), LocalDate.now()))
.sum();
long countTraitees = demandes.stream()
.filter(d -> d.getDateDepot() != null && "APPROUVEE".equals(d.getStatut()))
.count();
delaiMoyenTraitement = countTraitees > 0 ? (int) (totalJours / countTraitees) : 0;
// Initialiser les sous-listes
demandesUrgentes = demandes.stream()
.filter(d -> "URGENTE".equals(d.getPriorite()) || "EN_ATTENTE".equals(d.getStatut()))
@@ -94,6 +99,11 @@ public class DemandesBean implements Serializable {
.collect(Collectors.toList());
dernieresDemandes = demandes.stream()
.sorted((d1, d2) -> {
if (d1.getDateDepot() == null) return 1;
if (d2.getDateDepot() == null) return -1;
return d2.getDateDepot().compareTo(d1.getDateDepot());
})
.limit(4)
.collect(Collectors.toList());
}
@@ -181,6 +191,8 @@ public class DemandesBean implements Serializable {
public void actualiser() {
LOGGER.info("Actualisation des données");
initializeDemandes();
calculerStatistiques();
}
public void filtrerUrgentes() {

View File

@@ -147,7 +147,7 @@ public class EvenementsBean implements Serializable {
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des événements: " + e.getMessage());
e.printStackTrace();
LOGGER.log(java.util.logging.Level.SEVERE, "Détails de l'erreur de chargement des événements", e);
tousLesEvenements = new ArrayList<>();
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
"Erreur lors du chargement des événements: " + e.getMessage());
@@ -522,7 +522,7 @@ public class EvenementsBean implements Serializable {
} catch (Exception e) {
LOGGER.severe("Erreur lors de la création de l'événement: " + e.getMessage());
e.printStackTrace();
LOGGER.log(java.util.logging.Level.SEVERE, "Détails de l'erreur de création d'événement", e);
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
"Erreur lors de la création de l'événement: " + e.getMessage());
}

View File

@@ -385,6 +385,51 @@ public class SuperAdminBean implements Serializable {
public int getUtilisateursActifs() { return utilisateursActifs; }
public void setUtilisateursActifs(int utilisateursActifs) { this.utilisateursActifs = utilisateursActifs; }
/**
* Calcule les pourcentages pour les progress bars (jauges) basés sur des objectifs réalistes
*/
private void calculerPourcentagesJauges() {
// Objectif : 1000 membres (100%)
int objectifMembres = 1000;
pourcentageMembres = totalMembres > 0 ? Math.min(100, (totalMembres * 100) / objectifMembres) : 0;
// Objectif : 50 organisations (100%)
int objectifOrganisations = 50;
pourcentageOrganisations = totalEntites > 0 ? Math.min(100, (totalEntites * 100) / objectifOrganisations) : 0;
// Objectif : 10 000 000 FCFA de revenus (100%)
// Pour l'instant, si revenus = 0, on met 0%
try {
String revenusStr = revenusGlobaux.replaceAll("[^0-9]", "");
if (!revenusStr.isEmpty()) {
long revenusLong = Long.parseLong(revenusStr);
long objectifRevenus = 10_000_000L; // 10 millions FCFA
pourcentageRevenus = revenusLong > 0 ? Math.min(100, (int) ((revenusLong * 100) / objectifRevenus)) : 0;
} else {
pourcentageRevenus = 0;
}
} catch (Exception e) {
pourcentageRevenus = 0;
}
// Objectif : 100 activités journalières (100%)
int objectifActivite = 100;
pourcentageActivite = activiteJournaliere > 0 ? Math.min(100, (activiteJournaliere * 100) / objectifActivite) : 0;
}
// Getters pour les pourcentages des jauges
public int getPourcentageMembres() { return pourcentageMembres; }
public void setPourcentageMembres(int pourcentageMembres) { this.pourcentageMembres = pourcentageMembres; }
public int getPourcentageOrganisations() { return pourcentageOrganisations; }
public void setPourcentageOrganisations(int pourcentageOrganisations) { this.pourcentageOrganisations = pourcentageOrganisations; }
public int getPourcentageRevenus() { return pourcentageRevenus; }
public void setPourcentageRevenus(int pourcentageRevenus) { this.pourcentageRevenus = pourcentageRevenus; }
public int getPourcentageActivite() { return pourcentageActivite; }
public void setPourcentageActivite(int pourcentageActivite) { this.pourcentageActivite = pourcentageActivite; }
// Classes internes
public static class Alerte {
private UUID id;

View File

@@ -23,14 +23,14 @@
<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-icon.xhtml">
<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="@form" />
<ui:param name="update" value=":formFiltres :formTableau:tableauAudit" />
<ui:param name="title" value="Actualiser" />
<ui:param name="rounded" value="true" />
<ui:param name="text" value="false" />
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</div>
</h:form>
@@ -39,32 +39,44 @@
<!-- Statistiques -->
<div class="grid">
<ui:include src="/templates/components/cards/stat-card.xhtml">
<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="label" value="Événements Totaux" />
<ui:param name="icon" value="pi pi-history" />
<ui:param name="bgColor" value="blue" />
<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/stat-card.xhtml">
<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="label" value="Connexions Réussies" />
<ui:param name="icon" value="pi pi-check-circle" />
<ui:param name="bgColor" value="green" />
<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/stat-card.xhtml">
<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="label" value="Tentatives Échouées" />
<ui:param name="icon" value="pi pi-times-circle" />
<ui:param name="bgColor" value="orange" />
<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/stat-card.xhtml">
<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="label" value="Alertes Sécurité" />
<ui:param name="icon" value="pi pi-exclamation-triangle" />
<ui:param name="bgColor" value="red" />
<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>
@@ -181,7 +193,7 @@
<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="@form :formTableau:tableauAudit" />
<ui:param name="update" value=":formFiltres :formTableau:tableauAudit" />
<ui:param name="outlined" value="true" />
</ui:include>
</div>
@@ -258,12 +270,15 @@
<p:column headerText="Actions" style="width: 6%" styleClass="text-center">
<div class="flex justify-content-center gap-1">
<p:commandButton icon="pi pi-eye"
title="Voir les détails"
styleClass="p-button-sm p-button-rounded p-button-info"
action="#{auditBean.selectionnerLog(log)}"
update=":formDetails:dlgDetails"
oncomplete="PF('dlgDetails').show();" />
<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>
@@ -380,10 +395,12 @@
</div>
<f:facet name="footer">
<p:commandButton value="Fermer"
icon="pi pi-times"
onclick="PF('dlgDetails').hide();"
styleClass="p-button-outlined" />
<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>
@@ -423,14 +440,17 @@
<f:facet name="footer">
<div class="flex justify-content-end gap-2">
<p:commandButton value="Annuler"
styleClass="p-button-outlined"
onclick="PF('exportDialog').hide();"
type="button" />
<p:commandButton value="Exporter"
icon="pi pi-download"
styleClass="p-button-success"
action="#{auditBean.exporter}" />
<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>

View File

@@ -47,144 +47,83 @@
<!-- KPIs Financiers avec grille Freya stricte -->
<div class="formgrid grid">
<!-- KPI 1: Montant Collecté -->
<div class="field col-12 md:col-6 lg:col-3 xl:col-2">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Collecté ce mois</span>
<div class="flex align-items-center justify-content-center bg-green-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-check text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">#{cotisationsGestionBean.montantCollecte}</div>
<p:progressBar value="#{cotisationsGestionBean.progressionMensuelle}"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem;" />
<div class="text-500 text-xs mt-2">
<i class="pi pi-arrow-up text-green-500 text-xs"></i>
#{cotisationsGestionBean.progressionMensuelle}% de l'objectif
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3 xl:col-2">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Membres à jour</span>
<div class="flex align-items-center justify-content-center bg-blue-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-xl mb-2">#{cotisationsGestionBean.membresAJour}</div>
<p:progressBar value="#{cotisationsGestionBean.pourcentageMembresAJour}"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem;" />
<div class="text-500 text-xs mt-2">
<i class="pi pi-circle-fill text-blue-500 text-xs"></i>
#{cotisationsGestionBean.pourcentageMembresAJour}% conformes
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3 xl:col-2">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">En attente</span>
<div class="flex align-items-center justify-content-center bg-orange-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-clock text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">#{cotisationsGestionBean.montantEnAttente}</div>
<div class="text-orange-600 font-semibold text-sm">
#{cotisationsGestionBean.nombreCotisationsEnAttente} cotisations
</div>
<div class="text-500 text-xs mt-2">
<i class="pi pi-exclamation-triangle text-orange-500 text-xs"></i>
À traiter rapidement
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3 xl:col-2">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Impayés</span>
<div class="flex align-items-center justify-content-center bg-red-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-exclamation-circle text-red-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">#{cotisationsGestionBean.montantImpayes}</div>
<div class="text-red-600 font-semibold text-sm">
#{cotisationsGestionBean.joursRetardMoyen}j de retard moy.
</div>
<div class="text-500 text-xs mt-2">
<i class="pi pi-arrow-down text-red-500 text-xs"></i>
Action requise
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3 xl:col-2">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Revenus 2024</span>
<div class="flex align-items-center justify-content-center bg-purple-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-chart-line text-purple-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">#{cotisationsGestionBean.revenus2024}</div>
<div class="text-green-600 font-semibold text-sm">
<i class="pi pi-arrow-up text-green-500"></i>
#{cotisationsGestionBean.croissanceAnnuelle}
</div>
<div class="text-500 text-xs mt-2">
Croissance annuelle
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3 xl:col-2">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Prélèvements Auto</span>
<div class="flex align-items-center justify-content-center bg-teal-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-mobile text-teal-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">#{cotisationsGestionBean.prelevementsActifs}</div>
<div class="text-teal-600 font-semibold text-sm">
#{cotisationsGestionBean.montantPrelevementsPrevu} FCFA/mois
</div>
<div class="text-500 text-xs mt-2">
<i class="pi pi-sync text-teal-500 text-xs"></i>
Automatique
</div>
</div>
</div>
</div>
<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 -->

View File

@@ -10,127 +10,89 @@
<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-heart text-red-500 mr-2"></i>
Gestion des Demandes d'Aide
</h2>
<p class="text-600 mt-0">
Traitement et suivi des demandes d'assistance •
<span class="font-semibold">#{demandeBean.demandes.size()} demandes</span>
<span class="font-semibold text-orange-600">#{demandeBean.enAttente} en attente</span>
</p>
</div>
<div class="field col-12 lg:col-4 text-right">
<!-- 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">
<p:commandButton icon="pi pi-plus"
title="Nouvelle demande"
styleClass="ui-button-success ui-button-sm mr-3"
onclick="PF('dlgNouvelleDemande').show();" />
<p:commandButton icon="pi pi-upload"
title="Import demandes"
styleClass="ui-button-info ui-button-outlined ui-button-sm mr-3"
onclick="PF('dlgImportDemandes').show();" />
<p:commandButton icon="pi pi-download"
title="Exporter"
styleClass="ui-button-secondary ui-button-outlined ui-button-sm"
action="#{demandeBean.exporterDemandes}" />
<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>
</div>
</div>
</div>
</ui:define>
</ui:include>
<!-- KPIs avec grille Freya stricte et alignement parfait -->
<!-- KPIs avec composant réutilisable -->
<div class="formgrid grid">
<!-- KPI 1: En Attente -->
<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: 8rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">En Attente</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-clock text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{demandeBean.enAttente}</div>
<div class="flex align-items-center">
<i class="pi pi-arrow-up text-orange-500 text-sm mr-2"></i>
<span class="text-orange-600 font-semibold text-sm mr-2">+3</span>
<span class="text-500 text-xs">depuis hier</span>
</div>
</div>
</div>
</div>
<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 -->
<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: 8rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Urgentes</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-exclamation-triangle text-red-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{demandeBean.urgentes}</div>
<div class="flex align-items-center">
<p:progressBar value="33"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem; width: 100%;" />
</div>
<div class="text-500 text-xs mt-2">33% du total</div>
</div>
</div>
</div>
<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 -->
<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: 8rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Traité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-check text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{demandeBean.traitees}</div>
<div class="flex align-items-center">
<i class="pi pi-trending-up text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm">92% résolution</span>
</div>
</div>
</div>
</div>
<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 -->
<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: 8rem;">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Délai Moyen</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-blue-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{demandeBean.delaiMoyenTraitement} jours</div>
<div class="flex align-items-center">
<i class="pi pi-trending-down text-green-500 text-sm mr-2"></i>
<span class="text-green-600 font-semibold text-sm">-25% ce mois</span>
</div>
</div>
</div>
</div>
<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 avec proportion dorée -->
<!-- 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">
@@ -170,14 +132,22 @@
</div>
<h:form>
<div class="flex gap-2">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
title="Voir détails"
action="#{demandeBean.voirDemande(demande)}" />
<p:commandButton icon="pi pi-check"
styleClass="ui-button-rounded ui-button-text ui-button-success ui-button-sm"
title="Traiter"
action="#{demandeBean.traiterDemande(demande)}" />
<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>
@@ -186,10 +156,14 @@
<div class="mt-3">
<h:form>
<p:commandButton value="Voir toutes les urgentes"
icon="pi pi-arrow-right"
styleClass="ui-button-outlined ui-button-danger ui-button-sm w-full"
action="#{demandeBean.filtrerUrgentes}" />
<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>
@@ -229,10 +203,14 @@
</div>
<h:form>
<div class="flex gap-2">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
title="Voir détails"
action="#{demandeBean.voirDemande(demande)}" />
<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>
@@ -243,46 +221,48 @@
</div>
</div>
<!-- Section Filtres avec structure Freya et compatibilité mode nuit -->
<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-filter text-blue-500 mr-2"></i>
Filtres et Recherche
</h5>
<!-- 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">
<!-- Ligne 1: Champs de recherche principaux -->
<div class="field col-12 md:col-6 lg:col-3">
<label for="searchFilter" class="block text-900 font-medium mb-2">Rechercher</label>
<p:inputText id="searchFilter"
value="#{demandeBean.searchFilter}"
placeholder="Rechercher..."
styleClass="w-full">
<p:ajax event="keyup" delay="300" update=":formDemandes:dtDemandes" />
</p:inputText>
<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">
<label for="statutFilter" class="block text-900 font-medium mb-2">Statut</label>
<p:selectOneMenu id="statutFilter"
value="#{demandeBean.statutFilter}"
styleClass="w-full">
<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" />
</p:selectOneMenu>
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="typeFilter" class="block text-900 font-medium mb-2">Type</label>
<p:selectOneMenu id="typeFilter"
value="#{demandeBean.typeFilter}"
styleClass="w-full">
<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" />
@@ -290,48 +270,59 @@
<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" />
</p:selectOneMenu>
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6 lg:col-3">
<label for="prioriteFilter" class="block text-900 font-medium mb-2">Priorité</label>
<p:selectOneMenu id="prioriteFilter"
value="#{demandeBean.prioriteFilter}"
styleClass="w-full">
<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" />
</p:selectOneMenu>
</ui:define>
</ui:include>
</div>
<!-- Ligne 2: Date et bouton réinitialiser -->
<div class="field col-12 md:col-6 lg:col-4">
<label for="dateFilter" class="block text-900 font-medium mb-2">Date</label>
<p:datePicker id="dateFilter"
value="#{demandeBean.dateFilter}"
placeholder="Filtrer par date"
styleClass="w-full">
<p:ajax update=":formDemandes:dtDemandes" />
</p:datePicker>
</div>
<div class="field col-12 md:col-6 lg:col-8">
<label class="block text-900 font-medium mb-2">&#160;</label>
<p:commandButton icon="pi pi-refresh"
value="Réinitialiser"
styleClass="ui-button-outlined ui-button-secondary ui-button-sm"
action="#{demandeBean.actualiser}"
update="@form :formDemandes:dtDemandes" />
<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 avec structure Freya et mode nuit -->
<!-- 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">
@@ -341,25 +332,36 @@
Toutes les Demandes
</h5>
<div class="flex gap-3 align-items-center">
<p:commandButton value="Assigner en lot"
icon="pi pi-users"
styleClass="ui-button-outlined ui-button-secondary ui-button-sm"
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 ui-button-sm"
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 ui-button-sm"
action="#{demandeBean.exporterSelection}"
disabled="#{empty demandeBean.selectedDemandes}" />
<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 avec style Freya -->
<!-- DataTable -->
<p:dataTable id="dtDemandes"
var="demande"
value="#{demandeBean.demandes}"
@@ -445,38 +447,63 @@
<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">
<p:commandButton icon="pi pi-eye"
styleClass="ui-button-rounded ui-button-text ui-button-info ui-button-sm"
action="#{demandeBean.voirDemande(demande)}"
title="Voir détails" />
<p:commandButton icon="pi pi-user"
styleClass="ui-button-rounded ui-button-text ui-button-secondary ui-button-sm"
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 ui-button-sm"
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 ui-button-sm"
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 ui-button-sm"
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 ui-button-sm"
action="#{demandeBean.voirPiecesJointes(demande)}"
title="Pièces jointes"
rendered="#{demande.hasPiecesJointes}" />
<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>
@@ -485,17 +512,15 @@
</div>
</div>
<!-- Dialogs avec structure Freya -->
<!-- Dialog Nouvelle Demande -->
<p:dialog header="Nouvelle Demande"
widgetVar="dlgNouvelleDemande"
modal="true"
width="800"
height="auto"
resizable="false">
<h:form id="formNouvelleDemande">
<div class="ui-fluid formgrid grid">
<!-- 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"
@@ -503,7 +528,8 @@
completeMethod="#{demandeBean.rechercherMembres}"
var="membre" itemLabel="#{membre.nomComplet}" itemValue="#{membre}"
converter="membreConverter"
placeholder="Rechercher un membre...">
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"
@@ -520,8 +546,12 @@
</div>
<div class="field col-12 md:col-6">
<label for="typeDemande" class="block text-900 font-medium mb-2">Type de demande *</label>
<p:selectOneMenu id="typeDemande" value="#{demandeBean.nouvelleDemande.type}" required="true">
<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" />
@@ -529,46 +559,65 @@
<f:selectItem itemLabel="Mutation" itemValue="MUTATION" />
<f:selectItem itemLabel="Réclamation" itemValue="RECLAMATION" />
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
</p:selectOneMenu>
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6">
<label for="objetDemande" class="block text-900 font-medium mb-2">Objet *</label>
<p:inputText id="objetDemande" value="#{demandeBean.nouvelleDemande.objet}"
required="true" placeholder="Résumé de la demande" />
<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">
<label for="prioriteDemande" class="block text-900 font-medium mb-2">Priorité</label>
<p:selectOneMenu id="prioriteDemande" value="#{demandeBean.nouvelleDemande.priorite}">
<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" />
</p:selectOneMenu>
</ui:define>
</ui:include>
</div>
<div class="field col-12 md:col-6">
<label for="dateEcheanceDemande" class="block text-900 font-medium mb-2">Date d'échéance</label>
<p:datePicker id="dateEcheanceDemande"
value="#{demandeBean.nouvelleDemande.dateEcheance}" />
<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">
<label for="assignerA" class="block text-900 font-medium mb-2">Assigner à</label>
<p:selectOneMenu id="assignerA" value="#{demandeBean.nouvelleDemande.assigneA}">
<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}" />
</p:selectOneMenu>
</ui:define>
</ui:include>
</div>
<div class="field col-12">
<label for="descriptionDemande" class="block text-900 font-medium mb-2">Description détaillée</label>
<p:inputTextarea id="descriptionDemande" value="#{demandeBean.nouvelleDemande.description}"
rows="4" placeholder="Décrivez la demande en détail..." />
<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">
@@ -579,47 +628,59 @@
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>
<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('dlgNouvelleDemande').hide();"
type="button" />
<p:commandButton value="Créer la demande"
icon="pi pi-check"
styleClass="ui-button-success ui-button-sm"
action="#{demandeBean.creerDemande}"
update="@form :formDemandes"
oncomplete="if(!args.validationFailed) PF('dlgNouvelleDemande').hide();" />
</div>
</h:form>
</p:dialog>
<!-- Dialog Assignation en Lot -->
<p:dialog header="Assignation en Lot"
widgetVar="dlgAssignationLot"
modal="true"
width="500"
height="auto"
resizable="false">
<h:form id="formAssignationLot">
<div class="ui-fluid formgrid grid">
<!-- 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">
<label for="gestionnaireAssignation" class="block text-900 font-medium mb-2">Assigner à *</label>
<p:selectOneMenu id="gestionnaireAssignation" value="#{demandeBean.gestionnaireAssignation}" required="true">
<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}" />
</p:selectOneMenu>
</ui:define>
</ui:include>
</div>
<div class="field col-12">
<label for="commentaireAssignation" class="block text-900 font-medium mb-2">Commentaire</label>
<p:inputTextarea id="commentaireAssignation" value="#{demandeBean.commentaireAssignation}"
rows="3" placeholder="Commentaire optionnel..." />
<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">
@@ -629,23 +690,25 @@
</div>
</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('dlgAssignationLot').hide();"
type="button" />
<p:commandButton value="Assigner"
icon="pi pi-check"
styleClass="ui-button-warning ui-button-sm"
action="#{demandeBean.effectuerAssignationLot}"
update="@form :formDemandes"
oncomplete="if(!args.validationFailed) PF('dlgAssignationLot').hide();" />
</div>
</h:form>
</p:dialog>
</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

@@ -47,85 +47,51 @@
<!-- KPIs avec grille Freya stricte -->
<div class="formgrid grid">
<!-- KPI 1: Total Événements -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Total Événements</span>
<div class="flex align-items-center justify-content-center bg-blue-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-calendar text-blue-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-2">#{evenementsBean.statistiques.totalEvenements}</div>
<div class="flex align-items-center">
<i class="pi pi-arrow-up text-green-500 text-sm mr-1"></i>
<span class="text-green-600 font-semibold text-sm mr-2">+#{evenementsBean.statistiques.evenementsCeMois}</span>
<span class="text-500 text-xs">ce mois</span>
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Événements Actifs</span>
<div class="flex align-items-center justify-content-center bg-green-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-check text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-2">#{evenementsBean.statistiques.evenementsActifs}</div>
<p:progressBar value="#{evenementsBean.statistiques.tauxParticipationMoyen}"
showValue="false"
styleClass="surface-200 mt-2"
style="height: 0.5rem;" />
<div class="text-500 text-xs mt-2">#{evenementsBean.statistiques.tauxParticipationMoyen}% de participation</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Participants</span>
<div class="flex align-items-center justify-content-center bg-orange-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-users text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-2">#{evenementsBean.statistiques.participantsTotal}</div>
<div class="text-orange-600 font-semibold text-sm">
Moyenne: #{evenementsBean.statistiques.moyenneParticipants}/événement
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Budget Total</span>
<div class="flex align-items-center justify-content-center bg-purple-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-dollar text-purple-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">#{evenementsBean.statistiques.budgetTotal}</div>
<div class="flex align-items-center">
<i class="pi pi-trending-up text-purple-500 text-sm mr-1"></i>
<span class="text-purple-600 text-sm">Suivi budgétaire optimal</span>
</div>
</div>
</div>
</div>
<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>

View File

@@ -41,66 +41,42 @@
</div>
<!-- Soldes et Statistiques -->
<div class="grid">
<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">#{caisseBean.soldePrincipal}</div>
<div class="text-purple-700">Solde Principal</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-wallet text-xl"></i>
</div>
</div>
</div>
</div>
<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>
<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">#{caisseBean.totalEntrees}</div>
<div class="text-green-700">Entrées (30j)</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-arrow-down text-xl"></i>
</div>
</div>
</div>
</div>
<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>
<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">#{caisseBean.totalSorties}</div>
<div class="text-red-700">Sorties (30j)</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-arrow-up text-xl"></i>
</div>
</div>
</div>
</div>
<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>
<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">#{caisseBean.soldeWaveMoney}</div>
<div class="text-blue-700">Wave Money</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-mobile text-xl"></i>
</div>
</div>
</div>
</div>
<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 -->

View File

@@ -77,53 +77,46 @@
<!-- KPIs Financiers -->
<h:panelGroup id="kpiPanel">
<div class="grid">
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-900 text-xl mb-3 font-medium">Revenus Totaux</div>
<div class="text-primary text-5xl font-bold mb-3">#{rapportBean.revenusTotaux}</div>
<div class="flex align-items-center justify-content-center">
<i class="pi pi-arrow-up text-green-500 mr-2"></i>
<span class="text-green-500 font-medium">+#{rapportBean.croissanceRevenus}%</span>
<span class="text-600 ml-2">vs période précédente</span>
</div>
</div>
</div>
<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>
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-900 text-xl mb-3 font-medium">penses Totales</div>
<div class="text-orange-500 text-5xl font-bold mb-3">#{rapportBean.depensesTotales}</div>
<div class="flex align-items-center justify-content-center">
<i class="pi pi-arrow-down text-red-500 mr-2"></i>
<span class="text-red-500 font-medium">+#{rapportBean.croissanceDepenses}%</span>
<span class="text-600 ml-2">vs période précédente</span>
</div>
</div>
</div>
<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>
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-900 text-xl mb-3 font-medium">Bénéfice Net</div>
<div class="text-green-500 text-5xl font-bold mb-3">#{rapportBean.beneficeNet}</div>
<div class="flex align-items-center justify-content-center">
<p:progressBar value="#{rapportBean.margePercentage}"
labelTemplate="Marge: {value}%"
styleClass="w-full" />
</div>
</div>
</div>
<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>
<div class="col-12 md:col-3">
<div class="card text-center">
<div class="text-900 text-xl mb-3 font-medium">Trésorerie</div>
<div class="text-purple-500 text-5xl font-bold mb-3">#{rapportBean.tresorerie}</div>
<div class="flex align-items-center justify-content-center">
<i class="pi pi-info-circle text-blue-500 mr-2"></i>
<span class="text-600">#{rapportBean.joursAutonomie} jours d'autonomie</span>
</div>
</div>
</div>
<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>
@@ -309,31 +302,42 @@
<!-- Ratios et Indicateurs -->
<div class="card">
<h5>Indicateurs Clés de Performance</h5>
<div class="grid">
<div class="col-12 md:col-3">
<div class="text-center p-3 surface-50 border-round">
<div class="text-3xl font-bold text-primary mb-2">#{rapportBean.tauxRecouvrement}%</div>
<div class="text-600">Taux de Recouvrement</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="text-center p-3 surface-50 border-round">
<div class="text-3xl font-bold text-green-500 mb-2">#{rapportBean.ratioCouverture}</div>
<div class="text-600">Ratio de Couverture</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="text-center p-3 surface-50 border-round">
<div class="text-3xl font-bold text-orange-500 mb-2">#{rapportBean.coutMoyenMembre}</div>
<div class="text-600">Coût Moyen/Membre</div>
</div>
</div>
<div class="col-12 md:col-3">
<div class="text-center p-3 surface-50 border-round">
<div class="text-3xl font-bold text-purple-500 mb-2">#{rapportBean.revenuMoyenMembre}</div>
<div class="text-600">Revenu Moyen/Membre</div>
</div>
</div>
<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>

View File

@@ -377,26 +377,18 @@
<i class="pi pi-chart-bar text-blue-500 mr-2"></i>
Indicateurs Clés de Performance
</h5>
<div class="grid">
<div class="formgrid grid">
<ui:repeat value="#{rapportsBean.kpis}" var="kpi" varStatus="status">
<div class="col-12">
<div class="surface-100 border-round-lg p-3 mb-3 hover:surface-200 transition-colors transition-duration-150">
<div class="flex align-items-center justify-content-between mb-2">
<div class="flex align-items-center">
<i class="pi #{kpi.icon} text-#{kpi.couleur} mr-2"></i>
<span class="text-900 font-medium">#{kpi.libelle}</span>
</div>
<div class="text-#{kpi.couleur} font-bold text-xl">#{kpi.valeur}</div>
</div>
<div class="flex align-items-center justify-content-between">
<p:progressBar value="#{kpi.progression}" style="width: 60%; height: 4px;" />
<div class="flex align-items-center">
<i class="pi #{kpi.tendance == 'UP' ? 'pi-arrow-up text-green-500' : (kpi.tendance == 'DOWN' ? 'pi-arrow-down text-red-500' : 'pi-minus text-600')} mr-1 text-sm"></i>
<span class="text-600 text-sm">#{kpi.variation}%</span>
</div>
</div>
</div>
</div>
<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>

View File

@@ -130,100 +130,50 @@
</div>
<!-- 1. MEMBRES : L'humain d'abord - le plus important -->
<div class="col-12 md:col-6 lg:col-3">
<div class="card bg-gradient-blue border-left-4 border-blue-500">
<div class="flex justify-content-between align-items-start mb-3">
<div>
<span class="text-blue-600 font-semibold text-sm uppercase">Communauté</span>
<div class="text-900 font-bold text-3xl mt-2">#{dashboardBean.activeMembers}</div>
<span class="text-700 text-sm">Membres actifs</span>
</div>
<div class="bg-blue-500 text-white border-round-xl flex align-items-center justify-content-center"
style="width:3.5rem;height:3.5rem">
<i class="pi pi-users text-2xl"></i>
</div>
</div>
<div class="flex align-items-center">
<i class="pi pi-arrow-up text-green-500 mr-1"></i>
<span class="text-green-500 font-bold">+#{dashboardBean.membresEvolutionPourcent}%</span>
<span class="text-600 text-sm ml-2">ce mois</span>
</div>
<p:progressBar value="#{dashboardBean.tauxActivite}" style="height: 4px; margin-top: 8px;"
styleClass="bg-blue-200" />
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Membres Actifs" />
<ui:param name="value" value="#{dashboardBean.activeMembers}" />
<ui:param name="icon" value="pi-users" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="growthValue" value="#{dashboardBean.membresEvolutionPourcent}" />
<ui:param name="growthLabel" value="ce mois" />
<ui:param name="progressValue" value="#{dashboardBean.tauxActivite}" />
</ui:include>
<!-- 2. FINANCES : Santé financière - crucial pour la survie -->
<div class="col-12 md:col-6 lg:col-3">
<div class="card bg-gradient-green border-left-4 border-green-500">
<div class="flex justify-content-between align-items-start mb-3">
<div>
<span class="text-green-600 font-semibold text-sm uppercase">Trésorerie</span>
<div class="text-900 font-bold text-2xl mt-2">#{dashboardBean.totalCotisations}</div>
<span class="text-700 text-sm">FCFA collectés</span>
</div>
<div class="bg-green-500 text-white border-round-xl flex align-items-center justify-content-center"
style="width:3.5rem;height:3.5rem">
<i class="pi pi-dollar text-2xl"></i>
</div>
</div>
<div class="flex align-items-center">
<i class="pi pi-arrow-up text-green-500 mr-1"></i>
<span class="text-green-500 font-bold">+#{dashboardBean.cotisationsEvolutionPourcent}%</span>
<span class="text-600 text-sm ml-2">vs mois dernier</span>
</div>
<p:progressBar value="#{dashboardBean.tauxObjectifCotisations}" style="height: 4px; margin-top: 8px;"
styleClass="bg-green-200" />
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="FCFA Collectés" />
<ui:param name="value" value="#{dashboardBean.totalCotisations}" />
<ui:param name="icon" value="pi-dollar" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="growthValue" value="#{dashboardBean.cotisationsEvolutionPourcent}" />
<ui:param name="growthLabel" value="vs mois dernier" />
<ui:param name="progressValue" value="#{dashboardBean.tauxObjectifCotisations}" />
</ui:include>
<!-- 3. SOLIDARITÉ : Impact social - raison d'être -->
<div class="col-12 md:col-6 lg:col-3">
<div class="card bg-gradient-purple border-left-4 border-purple-500">
<div class="flex justify-content-between align-items-start mb-3">
<div>
<span class="text-purple-600 font-semibold text-sm uppercase">Solidarité</span>
<div class="text-900 font-bold text-2xl mt-2">#{dashboardBean.aidesDistribuees}</div>
<span class="text-700 text-sm">FCFA distribués</span>
</div>
<div class="bg-purple-500 text-white border-round-xl flex align-items-center justify-content-center"
style="width:3.5rem;height:3.5rem">
<i class="pi pi-heart text-2xl"></i>
</div>
</div>
<div class="flex align-items-center">
<div class="bg-orange-500 border-round mr-1" style="width: 8px; height: 8px;"></div>
<span class="text-orange-500 font-bold">#{dashboardBean.pendingAides}</span>
<span class="text-600 text-sm ml-2">demandes en attente</span>
</div>
<p:progressBar value="#{dashboardBean.tauxAidesTraitees}" style="height: 4px; margin-top: 8px;"
styleClass="bg-purple-200" />
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="FCFA Distribués" />
<ui:param name="value" value="#{dashboardBean.aidesDistribuees}" />
<ui:param name="icon" value="pi-heart" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="statusIcon" value="pi-circle-fill" />
<ui:param name="statusLabel" value="Demandes en attente" />
<ui:param name="statusValue" value="#{dashboardBean.pendingAides}" />
<ui:param name="progressValue" value="#{dashboardBean.tauxAidesTraitees}" />
</ui:include>
<!-- 4. ENGAGEMENT : Vitalité de l'organisation -->
<div class="col-12 md:col-6 lg:col-3">
<div class="card bg-gradient-orange border-left-4 border-orange-500">
<div class="flex justify-content-between align-items-start mb-3">
<div>
<span class="text-orange-600 font-semibold text-sm uppercase">Engagement</span>
<div class="text-900 font-bold text-3xl mt-2">#{dashboardBean.tauxParticipation}%</div>
<span class="text-700 text-sm">Taux de participation</span>
</div>
<div class="bg-orange-500 text-white border-round-xl flex align-items-center justify-content-center"
style="width:3.5rem;height:3.5rem">
<i class="pi pi-chart-line text-2xl"></i>
</div>
</div>
<div class="flex align-items-center">
<i class="pi pi-calendar text-orange-500 mr-1"></i>
<span class="text-orange-500 font-bold">#{dashboardBean.upcomingEvents}</span>
<span class="text-600 text-sm ml-2">événements prévus</span>
</div>
<p:progressBar value="#{dashboardBean.tauxEngagement}" style="height: 4px; margin-top: 8px;"
styleClass="bg-orange-200" />
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Taux de Participation" />
<ui:param name="value" value="#{dashboardBean.tauxParticipation}%" />
<ui:param name="icon" value="pi-chart-line" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="statusIcon" value="pi-calendar" />
<ui:param name="statusLabel" value="Événements prévus" />
<ui:param name="statusValue" value="#{dashboardBean.upcomingEvents}" />
<ui:param name="progressValue" value="#{dashboardBean.tauxEngagement}" />
</ui:include>
<!-- Tendances financières et analyses -->
<div class="col-12 lg:col-8">

View File

@@ -43,62 +43,45 @@
<!-- Résumé cotisations -->
<div class="grid mb-3">
<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">#{membreCotisationBean.cotisationsPayees}</div>
<div class="text-green-700">Payé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-orange-100 border-left-3 border-orange-500">
<div class="flex justify-content-between">
<div>
<div class="text-orange-900 font-bold text-2xl">#{membreCotisationBean.cotisationsEnAttente}</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">#{membreCotisationBean.montantDu}</div>
<div class="text-red-700">Montant Dû</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-blue-100 border-left-3 border-blue-500">
<div class="flex justify-content-between">
<div>
<div class="text-blue-900 font-bold text-2xl">#{membreCotisationBean.totalVerse}</div>
<div class="text-blue-700">Total Versé</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-dollar text-xl"></i>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Payées" />
<ui:param name="value" value="#{membreCotisationBean.cotisationsPayees}" />
<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-3" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="En Attente" />
<ui:param name="value" value="#{membreCotisationBean.cotisationsEnAttente}" />
<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-3" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Montant Dû" />
<ui:param name="value" value="#{membreCotisationBean.montantDu}" />
<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-3" />
</ui:include>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Total Versé" />
<ui:param name="value" value="#{membreCotisationBean.totalVerse}" />
<ui:param name="icon" value="pi-dollar" />
<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-3" />
</ui:include>
</div>
<!-- Liste des cotisations -->
@@ -127,11 +110,14 @@
</div>
</p:toolbarGroup>
<p:toolbarGroup align="right">
<p:commandButton icon="pi pi-refresh"
styleClass="ui-button-outlined ui-button-secondary"
action="#{membreCotisationBean.actualiser}"
update="@form"
title="Actualiser"/>
<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="#{membreCotisationBean.actualiser}" />
<ui:param name="update" value=":formCotisations:dtCotisations" />
<ui:param name="title" value="Actualiser" />
<ui:param name="outlined" value="true" />
</ui:include>
</p:toolbarGroup>
</p:toolbar>

View File

@@ -378,16 +378,15 @@
</div>
<div class="flex flex-wrap gap-2">
<p:commandButton
value="🎯 Inscrire le membre"
icon="pi pi-user-plus"
action="#{membreInscriptionBean.inscrire}"
update="@form"
process="@form"
onclick="PF('statusDialog').show();"
oncomplete="PF('statusDialog').hide();"
styleClass="ui-button-success"
title="Soumettre l'inscription" />
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="🎯 Inscrire le membre" />
<ui:param name="icon" value="pi pi-user-plus" />
<ui:param name="action" value="#{membreInscriptionBean.inscrire}" />
<ui:param name="update" value="messages" />
<ui:param name="onclick" value="PF('statusDialog').show();" />
<ui:param name="oncomplete" value="PF('statusDialog').hide();" />
<ui:param name="title" value="Soumettre l'inscription" />
</ui:include>
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="💾 Enregistrer brouillon" />

View File

@@ -155,11 +155,15 @@
<div class="col-12 md:col-auto">
<div class="field">
<label class="invisible">Actualiser</label>
<p:commandButton icon="pi pi-refresh"
action="#{membreListeBean.actualiser}"
update="@form"
title="Actualiser"
styleClass="ui-button-outlined ui-button-secondary w-full" />
<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="#{membreListeBean.actualiser}" />
<ui:param name="update" value=":formMembres:dtMembres" />
<ui:param name="title" value="Actualiser" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full" />
</ui:include>
</div>
</div>
@@ -278,7 +282,7 @@
<ui:include src="/templates/components/buttons/button-icon.xhtml">
<ui:param name="icon" value="pi pi-envelope" />
<ui:param name="action" value="#{membreListeBean.contacterMembre(membre)}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formMembres :formContact" />
<ui:param name="oncomplete" value="PF('dlgContact').show();" />
<ui:param name="title" value="Contacter" />
<ui:param name="severity" value="" />
@@ -322,7 +326,7 @@
<ui:param name="value" value="Rappel cotisations" />
<ui:param name="icon" value="pi pi-bell" />
<ui:param name="action" value="#{membreListeBean.rappelCotisationsGroupe}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formMembres" />
<ui:param name="outlined" value="true" />
<ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
</ui:include>
@@ -422,7 +426,7 @@
<ui:param name="value" value="Réinitialiser" />
<ui:param name="icon" value="pi pi-refresh" />
<ui:param name="action" value="#{membreListeBean.reinitialiserFiltres}" />
<ui:param name="update" value="@form :formMembres:dtMembres" />
<ui:param name="update" value=":formFiltresAvances :formMembres:dtMembres" />
<ui:param name="outlined" value="true" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
@@ -478,7 +482,7 @@
<ui:param name="value" value="Envoyer" />
<ui:param name="icon" value="pi pi-send" />
<ui:param name="action" value="#{membreListeBean.envoyerMessageGroupe}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formMessageGroupe :formMembres" />
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgMessageGroupe').hide();" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
@@ -521,7 +525,7 @@
<ui:param name="value" value="Importer" />
<ui:param name="icon" value="pi pi-upload" />
<ui:param name="action" value="#{membreListeBean.importerMembres}" />
<ui:param name="update" value="@form :formMembres" />
<ui:param name="update" value=":formImportExport :formMembres" />
</ui:include>
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="Télécharger modèle" />
@@ -634,14 +638,14 @@
<ui:param name="value" value="Annuler" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="action" value="#{membreListeBean.annulerContact}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formContact" />
<ui:param name="oncomplete" value="PF('dlgContact').hide();" />
</ui:include>
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="Envoyer" />
<ui:param name="icon" value="pi pi-send" />
<ui:param name="action" value="#{membreListeBean.envoyerMessageContact}" />
<ui:param name="update" value="@form :formMembres" />
<ui:param name="update" value=":formContact :formMembres" />
<ui:param name="oncomplete" value="if(!args.validationFailed) { PF('dlgContact').hide(); }" />
</ui:include>
</div>

View File

@@ -17,23 +17,15 @@
<div class="flex align-items-start">
<!-- Photo de profil -->
<div class="mr-4">
<div class="border-circle overflow-hidden" style="width: 120px; height: 120px;">
<h:graphicImage value="#{membreProfilBean.membre.photoUrl}"
style="width: 100%; height: 100%; object-fit: cover;"
rendered="#{membreProfilBean.membre.photoUrl != null}" />
<div class="bg-primary text-white flex align-items-center justify-content-center w-full h-full"
rendered="#{membreProfilBean.membre.photoUrl == null}">
<span style="font-size: 2.5rem;">#{membreProfilBean.membre.initiales}</span>
</div>
</div>
<h:form id="formPhoto" enctype="multipart/form-data">
<p:fileUpload mode="simple" skinSimple="true"
label="Changer photo" chooseLabel="Modifier"
accept="image/*" maxFileSize="2000000"
listener="#{membreProfilBean.changerPhoto}"
update="@form"
styleClass="mt-2 w-full" />
</h:form>
<ui:include src="/templates/components/profile-photo.xhtml">
<ui:param name="photoId" value="photoProfil" />
<ui:param name="photoUrl" value="#{membreProfilBean.membre.photoUrl}" />
<ui:param name="initiales" value="#{membreProfilBean.membre.initiales}" />
<ui:param name="formId" value="formPhoto" />
<ui:param name="listener" value="#{membreProfilBean.changerPhoto}" />
<ui:param name="update" value=":photoProfil" />
<ui:param name="size" value="120" />
</ui:include>
</div>
<!-- Informations principales -->
@@ -47,10 +39,11 @@
<div class="grid">
<div class="col-12 md:col-6">
<div class="mb-2">
<span class="font-medium text-900">Numéro membre:</span>
<span class="ml-2 font-bold text-primary">#{membreProfilBean.membre.numeroMembre}</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Numéro membre" />
<ui:param name="value" value="#{membreProfilBean.membre.numeroMembre}" />
<ui:param name="valueClass" value="font-bold text-primary" />
</ui:include>
<div class="mb-2">
<span class="font-medium text-900">Type:</span>
<p:tag value="#{membreProfilBean.membre.typeMembre}"
@@ -58,25 +51,26 @@
icon="pi #{membreProfilBean.membre.typeIcon}"
styleClass="ml-2" />
</div>
<div class="mb-2">
<span class="font-medium text-900">Entité:</span>
<span class="ml-2">#{membreProfilBean.membre.entite}</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Entité" />
<ui:param name="value" value="#{membreProfilBean.membre.entite}" />
</ui:include>
</div>
<div class="col-12 md:col-6">
<div class="mb-2">
<span class="font-medium text-900">Adhésion:</span>
<span class="ml-2">#{membreProfilBean.membre.dateAdhesion}</span>
<small class="text-600 ml-1">(#{membreProfilBean.membre.anciennete})</small>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Adhésion" />
<ui:param name="value" value="#{membreProfilBean.membre.dateAdhesion}" />
<ui:param name="suffix" value="(#{membreProfilBean.membre.anciennete})" />
</ui:include>
<div class="mb-2">
<span class="font-medium text-900">Cotisations:</span>
<span class="ml-2 #{membreProfilBean.membre.cotisationColor}">#{membreProfilBean.membre.cotisationStatut}</span>
</div>
<div class="mb-2">
<span class="font-medium text-900">Participation:</span>
<span class="ml-2 font-bold text-blue-500">#{membreProfilBean.membre.tauxParticipation}%</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Participation" />
<ui:param name="value" value="#{membreProfilBean.membre.tauxParticipation}%" />
<ui:param name="valueClass" value="font-bold text-blue-500" />
</ui:include>
</div>
</div>
</div>
@@ -118,65 +112,45 @@
<!-- Statistiques et KPIs -->
<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">#{membreProfilBean.statistiques.evenementsParticipes}</div>
<div class="text-blue-700">Événements</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-calendar text-lg"></i>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Événements" />
<ui:param name="value" value="#{membreProfilBean.statistiques.evenementsParticipes}" />
<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-3" />
</ui:include>
<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">#{membreProfilBean.statistiques.cotisationsPayees}</div>
<div class="text-green-700">Cotisations</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-dollar text-lg"></i>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Cotisations" />
<ui:param name="value" value="#{membreProfilBean.statistiques.cotisationsPayees}" />
<ui:param name="icon" value="pi-dollar" />
<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-3" />
</ui:include>
<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">#{membreProfilBean.statistiques.aidesRecues}</div>
<div class="text-orange-700">Aides reçues</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-heart text-lg"></i>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Aides reçues" />
<ui:param name="value" value="#{membreProfilBean.statistiques.aidesRecues}" />
<ui:param name="icon" value="pi-heart" />
<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-3" />
</ui:include>
<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">#{membreProfilBean.statistiques.scoreEngagement}</div>
<div class="text-purple-700">Score engagement</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-star text-lg"></i>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Score engagement" />
<ui:param name="value" value="#{membreProfilBean.statistiques.scoreEngagement}" />
<ui:param name="icon" value="pi-star" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
<ui:param name="colSize" value="col-12 md:col-3" />
</ui:include>
</div>
<!-- Contenu principal avec onglets -->
@@ -188,52 +162,52 @@
<div class="col-12 md:col-6">
<h6 class="mb-3">Informations de base</h6>
<div class="surface-50 p-3 border-round">
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Nom complet:</span>
<span>#{membreProfilBean.membre.nomComplet}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Date de naissance:</span>
<span>#{membreProfilBean.membre.dateNaissance}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Genre:</span>
<span>#{membreProfilBean.membre.genre}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Situation familiale:</span>
<span>#{membreProfilBean.membre.situationFamiliale}</span>
</div>
<div class="flex justify-content-between align-items-center">
<span class="font-medium">Profession:</span>
<span>#{membreProfilBean.membre.profession}</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Nom complet" />
<ui:param name="value" value="#{membreProfilBean.membre.nomComplet}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Date de naissance" />
<ui:param name="value" value="#{membreProfilBean.membre.dateNaissance}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Genre" />
<ui:param name="value" value="#{membreProfilBean.membre.genre}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Situation familiale" />
<ui:param name="value" value="#{membreProfilBean.membre.situationFamiliale}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Profession" />
<ui:param name="value" value="#{membreProfilBean.membre.profession}" />
</ui:include>
</div>
</div>
<div class="col-12 md:col-6">
<h6 class="mb-3">Coordonnées</h6>
<div class="surface-50 p-3 border-round">
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Email:</span>
<span>#{membreProfilBean.membre.email}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Téléphone:</span>
<span>#{membreProfilBean.membre.telephone}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Adresse:</span>
<span>#{membreProfilBean.membre.adresse}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Ville:</span>
<span>#{membreProfilBean.membre.ville}</span>
</div>
<div class="flex justify-content-between align-items-center">
<span class="font-medium">Pays:</span>
<span>#{membreProfilBean.membre.pays}</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Email" />
<ui:param name="value" value="#{membreProfilBean.membre.email}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Téléphone" />
<ui:param name="value" value="#{membreProfilBean.membre.telephone}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Adresse" />
<ui:param name="value" value="#{membreProfilBean.membre.adresse}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Ville" />
<ui:param name="value" value="#{membreProfilBean.membre.ville}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Pays" />
<ui:param name="value" value="#{membreProfilBean.membre.pays}" />
</ui:include>
</div>
</div>
@@ -272,20 +246,20 @@
<p:tag value="#{membreProfilBean.cotisations.statutActuel}"
severity="#{membreProfilBean.cotisations.statutSeverity}" />
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Dernier paiement:</span>
<span>#{membreProfilBean.cotisations.dernierPaiement}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Prochaine échéance:</span>
<span class="#{membreProfilBean.cotisations.prochaineEcheanceClass}">
#{membreProfilBean.cotisations.prochaineEcheance}
</span>
</div>
<div class="flex justify-content-between align-items-center">
<span class="font-medium">Total payé cette année:</span>
<span class="font-bold text-green-500">#{membreProfilBean.cotisations.totalAnnee}</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Dernier paiement" />
<ui:param name="value" value="#{membreProfilBean.cotisations.dernierPaiement}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Prochaine échéance" />
<ui:param name="value" value="#{membreProfilBean.cotisations.prochaineEcheance}" />
<ui:param name="valueClass" value="#{membreProfilBean.cotisations.prochaineEcheanceClass}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Total payé cette année" />
<ui:param name="value" value="#{membreProfilBean.cotisations.totalAnnee}" />
<ui:param name="valueClass" value="font-bold text-green-500" />
</ui:include>
</div>
<h:form id="formCotisationsActions">
@@ -363,29 +337,31 @@
<div class="col-12 md:col-4">
<h6 class="mb-3">Statistiques participation</h6>
<div class="surface-50 p-3 border-round">
<div class="flex justify-content-between align-items-center mb-3">
<span class="font-medium">Taux de participation:</span>
<span class="font-bold text-blue-500">#{membreProfilBean.statistiques.tauxParticipation}%</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Taux de participation" />
<ui:param name="value" value="#{membreProfilBean.statistiques.tauxParticipation}%" />
<ui:param name="valueClass" value="font-bold text-blue-500" />
</ui:include>
<p:progressBar value="#{membreProfilBean.statistiques.tauxParticipation}"
labelTemplate="" styleClass="mb-3" />
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Cette année:</span>
<span>#{membreProfilBean.statistiques.evenementsAnnee}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">Total:</span>
<span>#{membreProfilBean.statistiques.evenementsTotal}</span>
</div>
<div class="flex justify-content-between align-items-center mb-2">
<span class="font-medium">En tant qu'organisateur:</span>
<span>#{membreProfilBean.statistiques.evenementsOrganises}</span>
</div>
<div class="flex justify-content-between align-items-center">
<span class="font-medium">Absences:</span>
<span class="text-red-500">#{membreProfilBean.statistiques.absences}</span>
</div>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Cette année" />
<ui:param name="value" value="#{membreProfilBean.statistiques.evenementsAnnee}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Total" />
<ui:param name="value" value="#{membreProfilBean.statistiques.evenementsTotal}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="En tant qu'organisateur" />
<ui:param name="value" value="#{membreProfilBean.statistiques.evenementsOrganises}" />
</ui:include>
<ui:include src="/templates/components/forms/detail-field-row.xhtml">
<ui:param name="label" value="Absences" />
<ui:param name="value" value="#{membreProfilBean.statistiques.absences}" />
<ui:param name="valueClass" value="text-red-500" />
</ui:include>
</div>
</div>
</div>
@@ -554,7 +530,7 @@
<ui:param name="value" value="Enregistrer" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="action" value="#{membreProfilBean.sauvegarderModifications}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formModifierProfil :photoProfil" />
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgModifierProfil').hide();" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
@@ -570,20 +546,24 @@
<p:dialog header="Contacter #{membreProfilBean.membre.prenom}" widgetVar="dlgContacter" modal="true" width="500">
<h:form id="formContacter">
<div class="ui-fluid">
<div class="field">
<p:outputLabel for="sujetContact" value="Sujet" />
<p:inputText id="sujetContact" value="#{membreProfilBean.contact.sujet}" required="true" />
</div>
<ui:include src="/templates/components/forms/form-field-text.xhtml">
<ui:param name="id" value="sujetContact" />
<ui:param name="label" value="Sujet" />
<ui:param name="value" value="#{membreProfilBean.contact.sujet}" />
<ui:param name="required" value="true" />
</ui:include>
<div class="field">
<p:outputLabel for="messageContact" value="Message" />
<p:inputTextarea id="messageContact" value="#{membreProfilBean.contact.message}"
rows="5" required="true" />
</div>
<ui:include src="/templates/components/forms/form-field-textarea.xhtml">
<ui:param name="id" value="messageContact" />
<ui:param name="label" value="Message" />
<ui:param name="value" value="#{membreProfilBean.contact.message}" />
<ui:param name="required" value="true" />
<ui:param name="rows" value="5" />
</ui:include>
<div class="field">
<p:outputLabel for="canalContact" value="Canal de communication" />
<p:selectCheckboxMenu id="canalContact" value="#{membreProfilBean.contact.canaux}" multiple="true">
<p:selectCheckboxMenu id="canalContact" value="#{membreProfilBean.contact.canaux}" multiple="true" styleClass="w-full">
<f:selectItem itemLabel="📧 Email" itemValue="EMAIL" />
<f:selectItem itemLabel="📱 SMS" itemValue="SMS" />
<f:selectItem itemLabel="💬 WhatsApp" itemValue="WHATSAPP" />
@@ -592,14 +572,18 @@
</div>
<div class="flex gap-2 mt-3">
<p:commandButton value="Envoyer" icon="pi pi-send"
styleClass="ui-button-success"
action="#{membreProfilBean.envoyerMessage}"
update="@form"
oncomplete="if(!args.validationFailed) PF('dlgContacter').hide();" />
<p:commandButton value="Annuler" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgContacter').hide();" type="button" />
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="Envoyer" />
<ui:param name="icon" value="pi pi-send" />
<ui:param name="action" value="#{membreProfilBean.envoyerMessage}" />
<ui:param name="update" value=":formContacter" />
<ui:param name="oncomplete" value="if(!args.validationFailed) PF('dlgContacter').hide();" />
</ui:include>
<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('dlgContacter').hide();" />
</ui:include>
</div>
</h:form>
</p:dialog>
@@ -609,46 +593,65 @@
<h:form id="formActions">
<div class="grid">
<div class="col-12">
<p:commandButton value="Suspendre membre"
icon="pi pi-ban"
styleClass="ui-button-danger w-full mb-2"
action="#{membreProfilBean.suspendre}"
onclick="return confirm('Êtes-vous sûr de vouloir suspendre ce membre ?');"
rendered="#{membreProfilBean.membre.statut == 'ACTIF'}" />
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Suspendre membre" />
<ui:param name="icon" value="pi pi-ban" />
<ui:param name="action" value="#{membreProfilBean.suspendre}" />
<ui:param name="onclick" value="return confirm('Êtes-vous sûr de vouloir suspendre ce membre ?');" />
<ui:param name="styleClass" value="ui-button-danger w-full mb-2" />
<ui:param name="rendered" value="#{membreProfilBean.membre.statut == 'ACTIF'}" />
</ui:include>
<p:commandButton value="Réactiver membre"
icon="pi pi-check"
styleClass="ui-button-success w-full mb-2"
action="#{membreProfilBean.reactiver}"
rendered="#{membreProfilBean.membre.statut == 'SUSPENDU'}" />
<ui:include src="/templates/components/buttons/button-success.xhtml">
<ui:param name="value" value="Réactiver membre" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="action" value="#{membreProfilBean.reactiver}" />
<ui:param name="styleClass" value="w-full mb-2" />
<ui:param name="rendered" value="#{membreProfilBean.membre.statut == 'SUSPENDU'}" />
</ui:include>
<p:commandButton value="Changer de type"
icon="pi pi-user-edit"
styleClass="ui-button-outlined ui-button-warning w-full mb-2"
onclick="PF('dlgChangerType').show();" />
<ui:include src="/templates/components/buttons/button-warning.xhtml">
<ui:param name="value" value="Changer de type" />
<ui:param name="icon" value="pi pi-user-edit" />
<ui:param name="onclick" value="PF('dlgChangerType').show();" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full mb-2" />
</ui:include>
<p:commandButton value="Transférer vers entité"
icon="pi pi-arrow-right"
styleClass="ui-button-outlined ui-button-info w-full mb-2"
onclick="PF('dlgTransferer').show();" />
<ui:include src="/templates/components/buttons/button-info.xhtml">
<ui:param name="value" value="Transférer vers entité" />
<ui:param name="icon" value="pi pi-arrow-right" />
<ui:param name="onclick" value="PF('dlgTransferer').show();" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full mb-2" />
</ui:include>
<p:commandButton value="Exporter données"
icon="pi pi-download"
styleClass="ui-button-outlined ui-button-secondary w-full mb-2"
action="#{membreProfilBean.exporterDonnees}" />
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Exporter données" />
<ui:param name="icon" value="pi pi-download" />
<ui:param name="action" value="#{membreProfilBean.exporterDonnees}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full mb-2" />
<ui:param name="update" value="none" />
</ui:include>
<p:commandButton value="Supprimer membre"
icon="pi pi-trash"
styleClass="ui-button-outlined ui-button-danger w-full"
onclick="return confirm('ATTENTION: Cette action est irréversible. Confirmer la suppression ?');"
action="#{membreProfilBean.supprimer}" />
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
<ui:param name="value" value="Supprimer membre" />
<ui:param name="icon" value="pi pi-trash" />
<ui:param name="action" value="#{membreProfilBean.supprimer}" />
<ui:param name="onclick" value="return confirm('ATTENTION: Cette action est irréversible. Confirmer la suppression ?');" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-danger w-full" />
</ui:include>
</div>
</div>
<div class="flex justify-content-end mt-3">
<p:commandButton value="Fermer" icon="pi pi-times"
styleClass="ui-button-secondary"
onclick="PF('dlgActions').hide();" type="button" />
<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('dlgActions').hide();" />
</ui:include>
</div>
</h:form>
</p:dialog>

View File

@@ -36,32 +36,44 @@
<!-- Statistiques de recherche -->
<div class="grid">
<ui:include src="/templates/components/cards/stat-card.xhtml">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Total Membres" />
<ui:param name="value" value="#{membreRechercheBean.statistiques.totalMembres}" />
<ui:param name="label" value="Total Membres" />
<ui:param name="icon" value="pi pi-users" />
<ui:param name="bgColor" value="blue" />
<ui:param name="icon" value="pi-users" />
<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/stat-card.xhtml">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Résultats trouvés" />
<ui:param name="value" value="#{membreRechercheBean.statistiques.resultatsActuels}" />
<ui:param name="label" value="Résultats trouvés" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="bgColor" value="green" />
<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>
<ui:include src="/templates/components/cards/stat-card.xhtml">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Filtres actifs" />
<ui:param name="value" value="#{membreRechercheBean.statistiques.filtresActifs}" />
<ui:param name="label" value="Filtres actifs" />
<ui:param name="icon" value="pi pi-filter" />
<ui:param name="bgColor" value="orange" />
<ui:param name="icon" value="pi-filter" />
<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/stat-card.xhtml">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Temps de recherche" />
<ui:param name="value" value="#{membreRechercheBean.statistiques.tempsRecherche}ms" />
<ui:param name="label" value="Temps de recherche" />
<ui:param name="icon" value="pi pi-clock" />
<ui:param name="bgColor" value="purple" />
<ui:param name="icon" value="pi-clock" />
<ui:param name="iconColor" value="purple-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>
@@ -325,7 +337,7 @@
<ui:param name="value" value="Réinitialiser" />
<ui:param name="icon" value="pi pi-refresh" />
<ui:param name="action" value="#{membreRechercheBean.reinitialiserFiltres}" />
<ui:param name="update" value="@form :formResultats:dtResultats @(.search-summary)" />
<ui:param name="update" value=":formRechercheAvancee :formResultats:dtResultats @(.search-summary)" />
<ui:param name="outlined" value="true" />
</ui:include>
<ui:include src="/templates/components/buttons/button-info.xhtml">
@@ -389,14 +401,14 @@
<div class="flex align-items-center justify-content-between">
<span>Liste des membres</span>
<div class="flex gap-2">
<ui:include src="/templates/components/buttons/button-icon.xhtml">
<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="#{membreRechercheBean.actualiserResultats}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formResultats:dtResultats" />
<ui:param name="title" value="Actualiser" />
<ui:param name="rounded" value="true" />
<ui:param name="text" value="false" />
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/buttons/button-icon.xhtml">
<ui:param name="icon" value="pi pi-cog" />
@@ -572,7 +584,7 @@
<ui:param name="value" value="Sauvegarder" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="action" value="#{membreRechercheBean.sauvegarderRecherche}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formSauvegarderRecherche" />
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgSauvegarderRecherche').hide();" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">
@@ -622,7 +634,7 @@
<ui:include src="/templates/components/buttons/button-icon.xhtml">
<ui:param name="icon" value="pi pi-trash" />
<ui:param name="action" value="#{membreRechercheBean.supprimerRecherche(recherche)}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formRecherchesSauvegardees" />
<ui:param name="onclick" value="return confirm('Supprimer cette recherche ?');" />
<ui:param name="title" value="Supprimer" />
<ui:param name="severity" value="danger" />
@@ -685,7 +697,7 @@
<ui:param name="value" value="Envoyer" />
<ui:param name="icon" value="pi pi-send" />
<ui:param name="action" value="#{membreRechercheBean.envoyerMessageGroupe}" />
<ui:param name="update" value="@form" />
<ui:param name="update" value=":formMessageGroupe :formResultats" />
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgMessageGroupe').hide();" />
</ui:include>
<ui:include src="/templates/components/buttons/button-secondary.xhtml">

View File

@@ -57,23 +57,18 @@
<!-- KPIs Activités -->
<div class="card">
<h5>Indicateurs d'Activité</h5>
<div class="grid">
<div class="formgrid grid">
<ui:repeat value="#{rapportsBean.kpis}" var="kpi">
<div class="col-12 md:col-4">
<div class="surface-100 border-round-lg p-4">
<div class="flex align-items-center justify-content-between mb-3">
<div class="flex align-items-center gap-2">
<i class="#{kpi.icon} text-2xl text-#{kpi.couleur}"></i>
<span class="font-semibold">#{kpi.libelle}</span>
</div>
</div>
<div class="text-3xl font-bold text-#{kpi.couleur} mb-2">#{kpi.valeur}</div>
<div class="flex align-items-center gap-2">
<i class="#{kpi.variation > 0 ? 'pi pi-arrow-up text-green-500' : kpi.variation < 0 ? 'pi pi-arrow-down text-red-500' : 'pi pi-minus text-gray-500'}"></i>
<span class="text-sm">#{kpi.variation}%</span>
</div>
</div>
</div>
<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="colSize" value="col-12 md:col-4" />
<ui:param name="showProgress" value="false" />
</ui:include>
</ui:repeat>
</div>
</div>

View File

@@ -150,23 +150,18 @@
<!-- KPIs Financiers -->
<div class="card">
<h5>Indicateurs Clés de Performance</h5>
<div class="grid">
<div class="formgrid grid">
<ui:repeat value="#{rapportsBean.kpis}" var="kpi">
<div class="col-12 md:col-4">
<div class="surface-100 border-round-lg p-4">
<div class="flex align-items-center justify-content-between mb-3">
<div class="flex align-items-center gap-2">
<i class="#{kpi.icon} text-2xl text-#{kpi.couleur}"></i>
<span class="font-semibold">#{kpi.libelle}</span>
</div>
</div>
<div class="text-3xl font-bold text-#{kpi.couleur} mb-2">#{kpi.valeur}</div>
<div class="flex align-items-center gap-2">
<i class="#{kpi.variation > 0 ? 'pi pi-arrow-up text-green-500' : kpi.variation < 0 ? 'pi pi-arrow-down text-red-500' : 'pi pi-minus text-gray-500'}"></i>
<span class="text-sm">#{kpi.variation}%</span>
</div>
</div>
</div>
<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="colSize" value="col-12 md:col-4" />
<ui:param name="showProgress" value="false" />
</ui:include>
</ui:repeat>
</div>
</div>

View File

@@ -38,19 +38,23 @@
</ui:include>
<!-- Statistiques membres -->
<div class="grid">
<ui:include src="/templates/components/cards/stat-card.xhtml">
<div class="formgrid grid">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Total Membres" />
<ui:param name="value" value="#{rapportsBean.indicateurs.totalMembres}" />
<ui:param name="label" value="Total Membres" />
<ui:param name="icon" value="pi pi-users" />
<ui:param name="bgColor" value="blue" />
<ui:param name="icon" value="pi-users" />
<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/stat-card.xhtml">
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Croissance" />
<ui:param name="value" value="#{rapportsBean.indicateurs.croissanceMembres}%" />
<ui:param name="label" value="Croissance" />
<ui:param name="icon" value="pi pi-arrow-up" />
<ui:param name="bgColor" value="green" />
<ui:param name="icon" value="pi-arrow-up" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="showGrowth" value="false" />
<ui:param name="showProgress" value="false" />
</ui:include>
</div>

View File

@@ -47,88 +47,51 @@
<!-- KPIs Système avec grille Freya stricte -->
<div class="formgrid grid">
<!-- KPI 1: Statut Système -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Statut Système</span>
<div class="flex align-items-center justify-content-center bg-green-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-check-circle text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">Opérationnel</div>
<div class="flex align-items-center">
<div class="bg-green-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-green-600 font-semibold text-sm mr-2">Uptime</span>
<span class="text-500 text-xs">#{configurationBean.tempsActivite}</span>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Statut Système" />
<ui:param name="value" value="Opérationnel" />
<ui:param name="icon" value="pi-check-circle" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="statusIcon" value="pi-circle-fill" />
<ui:param name="statusLabel" value="Uptime" />
<ui:param name="statusValue" value="#{configurationBean.tempsActivite}" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 2: Utilisateurs Connectés -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Utilisateurs Actifs</span>
<div class="flex align-items-center justify-content-center bg-blue-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-2">#{configurationBean.utilisateursConnectes}</div>
<div class="flex align-items-center">
<i class="pi pi-clock text-blue-500 text-sm mr-1"></i>
<span class="text-blue-600 font-semibold text-sm mr-2">Sessions</span>
<span class="text-500 text-xs">#{configurationBean.sessionsActives} actives</span>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Utilisateurs Actifs" />
<ui:param name="value" value="#{configurationBean.utilisateursConnectes}" />
<ui:param name="icon" value="pi-users" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="statusIcon" value="pi-clock" />
<ui:param name="statusLabel" value="Sessions" />
<ui:param name="statusValue" value="#{configurationBean.sessionsActives} actives" />
<ui:param name="showProgress" value="false" />
</ui:include>
<!-- KPI 3: Performance Système -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Performance</span>
<div class="flex align-items-center justify-content-center bg-orange-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-chart-line text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">CPU #{configurationBean.cpuUtilisation}%</div>
<p:progressBar value="#{configurationBean.cpuUtilisation}"
showValue="false"
styleClass="surface-200 mt-2"
style="height: 0.5rem;" />
<div class="text-500 text-xs mt-2">Mémoire: #{configurationBean.memoireUtilisee}%</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Performance" />
<ui:param name="value" value="CPU #{configurationBean.cpuUtilisation}%" />
<ui:param name="icon" value="pi-chart-line" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="progressValue" value="#{configurationBean.cpuUtilisation}" />
<ui:param name="noDataLabel" value="Mémoire: #{configurationBean.memoireUtilisee}%" />
<ui:param name="showGrowth" value="false" />
</ui:include>
<!-- KPI 4: Dernière Sauvegarde -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Dernière Sauvegarde</span>
<div class="flex align-items-center justify-content-center bg-purple-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-save text-purple-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-lg mb-2">#{configurationBean.derniereSauvegarde}</div>
<div class="flex align-items-center">
<i class="pi pi-database text-purple-500 text-sm mr-1"></i>
<span class="text-purple-600 font-semibold text-sm mr-2">Auto</span>
<span class="text-500 text-xs">#{configurationBean.frequenceSauvegarde}</span>
</div>
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Dernière Sauvegarde" />
<ui:param name="value" value="#{configurationBean.derniereSauvegarde}" />
<ui:param name="icon" value="pi-save" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="statusIcon" value="pi-database" />
<ui:param name="statusLabel" value="Auto" />
<ui:param name="statusValue" value="#{configurationBean.frequenceSauvegarde}" />
<ui:param name="showProgress" value="false" />
</ui:include>
</div>
<!-- Configuration Générale avec structure Freya -->

View File

@@ -48,116 +48,51 @@
<!-- KPIs Principaux avec grille Freya stricte et alignement parfait -->
<div class="formgrid grid">
<!-- KPI 1: Membres Actifs -->
<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">Membres Actifs</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">#{superAdminBean.totalMembres}</div>
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.croissanceMembres != null and superAdminBean.croissanceMembres != '0'}">
<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">+#{superAdminBean.croissanceMembres}%</span>
<span class="text-500 text-xs">ce mois</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.croissanceMembres == null or superAdminBean.croissanceMembres == '0'}">
Données non disponibles
</div>
<p:progressBar value="87"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem; width: 100%;" />
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Membres Actifs" />
<ui:param name="value" value="#{superAdminBean.totalMembres}" />
<ui:param name="icon" value="pi-users" />
<ui:param name="iconColor" value="blue-600" />
<ui:param name="growthValue" value="#{superAdminBean.croissanceMembres}" />
<ui:param name="growthLabel" value="ce mois" />
<ui:param name="progressValue" value="#{superAdminBean.pourcentageMembres}" />
</ui:include>
<!-- KPI 2: Organisations -->
<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">Organisations</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-sitemap text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{superAdminBean.totalEntites}</div>
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.nouvellesEntites > 0}">
<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">+#{superAdminBean.nouvellesEntites}</span>
<span class="text-500 text-xs">nouvelles</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.nouvellesEntites == 0}">
Aucune nouvelle entité ce mois
</div>
<p:progressBar value="92"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem; width: 100%;" />
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Organisations" />
<ui:param name="value" value="#{superAdminBean.totalEntites}" />
<ui:param name="icon" value="pi-sitemap" />
<ui:param name="iconColor" value="green-600" />
<ui:param name="growthValue" value="#{superAdminBean.nouvellesEntites}" />
<ui:param name="growthLabel" value="nouvelles" />
<ui:param name="growthType" value="number" />
<ui:param name="noDataLabel" value="Aucune nouvelle entité ce mois" />
<ui:param name="progressValue" value="#{superAdminBean.pourcentageOrganisations}" />
</ui:include>
<!-- KPI 3: Revenus Globaux -->
<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 (FCFA)</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-purple-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{superAdminBean.revenusGlobaux}</div>
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.croissanceRevenus != null and superAdminBean.croissanceRevenus != '0'}">
<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">+#{superAdminBean.croissanceRevenus}%</span>
<span class="text-500 text-xs">vs mois dernier</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.croissanceRevenus == null or superAdminBean.croissanceRevenus == '0'}">
Données non disponibles
</div>
<p:progressBar value="78"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem; width: 100%;" />
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Revenus (FCFA)" />
<ui:param name="value" value="#{superAdminBean.revenusGlobaux}" />
<ui:param name="icon" value="pi-dollar" />
<ui:param name="iconColor" value="purple-600" />
<ui:param name="growthValue" value="#{superAdminBean.croissanceRevenus}" />
<ui:param name="growthLabel" value="vs mois dernier" />
<ui:param name="progressValue" value="#{superAdminBean.pourcentageRevenus}" />
</ui:include>
<!-- KPI 4: Activité du Jour -->
<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">Activité du Jour</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-chart-line text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-3">#{superAdminBean.activiteJournaliere}</div>
<div class="flex align-items-center mb-2" rendered="#{superAdminBean.utilisateursActifs > 0}">
<div class="bg-green-500 border-circle mr-2" style="width: 8px; height: 8px;"></div>
<span class="text-green-600 font-semibold text-sm mr-2">En ligne</span>
<span class="text-500 text-xs">#{superAdminBean.utilisateursActifs} actifs</span>
</div>
<div class="text-500 text-xs" rendered="#{superAdminBean.utilisateursActifs == 0}">
Aucun utilisateur actif
</div>
<p:progressBar value="65"
showValue="false"
styleClass="surface-200"
style="height: 0.5rem; width: 100%;" />
</div>
</div>
</div>
<ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Activité du Jour" />
<ui:param name="value" value="#{superAdminBean.activiteJournaliere}" />
<ui:param name="icon" value="pi-chart-line" />
<ui:param name="iconColor" value="orange-600" />
<ui:param name="statusIcon" value="pi-check-circle" />
<ui:param name="statusLabel" value="En ligne" />
<ui:param name="statusValue" value="#{superAdminBean.utilisateursActifs} actifs" />
<ui:param name="progressValue" value="#{superAdminBean.pourcentageActivite}" />
</ui:include>
</div>
<!-- Section Analytics et Actions avec disposition Freya stricte -->

View File

@@ -46,85 +46,50 @@
<!-- KPIs avec grille Freya stricte -->
<div class="formgrid grid">
<!-- KPI 1: Total Entités -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Total Entités</span>
<div class="flex align-items-center justify-content-center bg-blue-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-building text-blue-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-2">#{entitesGestionBean.statistiques.totalEntites}</div>
<div class="flex align-items-center">
<i class="pi pi-arrow-up text-green-500 text-sm mr-1"></i>
<span class="text-green-600 font-semibold text-sm">+8</span>
<span class="text-500 text-xs ml-2">ce mois</span>
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Entités Actives</span>
<div class="flex align-items-center justify-content-center bg-green-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-check text-green-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-2">#{entitesGestionBean.statistiques.entitesActives}</div>
<p:progressBar value="92"
showValue="false"
styleClass="surface-200 mt-2"
style="height: 0.5rem;" />
<div class="text-500 text-xs mt-2">92% d'activité</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<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 bg-orange-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-users text-orange-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-2xl mb-2">#{entitesGestionBean.statistiques.totalMembres}</div>
<div class="text-orange-600 font-semibold text-sm">
Moyenne: #{entitesGestionBean.statistiques.moyenneMembresParEntite}/entité
</div>
</div>
</div>
</div>
<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 -->
<div class="field col-12 md:col-6 lg:col-3">
<div class="card surface-50 border-round-lg">
<div class="p-3">
<div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">Revenus Totaux</span>
<div class="flex align-items-center justify-content-center bg-purple-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-dollar text-purple-600 text-lg"></i>
</div>
</div>
<div class="text-900 font-bold text-xl mb-2">#{entitesGestionBean.statistiques.revenus}</div>
<div class="flex align-items-center">
<i class="pi pi-arrow-up text-green-500 text-sm mr-1"></i>
<span class="text-green-600 text-sm">+15% vs année dernière</span>
</div>
</div>
</div>
</div>
<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 -->

View File

@@ -10,16 +10,35 @@
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<ui:fragment rendered="#{not empty update and update != 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
update="#{update}"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
type="button"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-info #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{empty update or update == 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
ajax="false"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
type="button"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-info #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"

View File

@@ -20,22 +20,37 @@
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<ui:fragment rendered="#{not empty update and update != 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
update="#{update}"
onclick="#{onclick}"
type="button"
oncomplete="#{oncomplete}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-primary #{not empty styleClass ? styleClass : ''}"
styleClass="ui-button-primary #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{empty update or update == 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
ajax="false"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-primary #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"
icon="#{icon}"
outcome="#{outcome}"
styleClass="ui-button-primary #{styleClass}"
styleClass="ui-button-primary #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
</ui:fragment>

View File

@@ -21,16 +21,33 @@
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<ui:fragment rendered="#{not empty update and update != 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
update="#{update}"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-secondary #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{empty update or update == 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
ajax="false"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-secondary #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"

View File

@@ -10,15 +10,33 @@
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<ui:fragment rendered="#{not empty update and update != 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
update="#{update}"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-success #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{empty update or update == 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
ajax="false"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-success #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"

View File

@@ -10,16 +10,35 @@
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<ui:fragment rendered="#{not empty update and update != 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
update="#{update}"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
type="button"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-warning #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{empty update or update == 'none'}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
ajax="false"
onclick="#{onclick}"
oncomplete="#{oncomplete}"
type="button"
disabled="#{not empty disabled and disabled}"
rendered="#{empty rendered or rendered}"
styleClass="ui-button-warning #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{not empty styleClass ? styleClass : ''}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"

View File

@@ -47,8 +47,14 @@
<p:menuitem id="m_liste_membres" value="Liste des Membres" icon="pi pi-list" outcome="/pages/secure/membre/liste" />
<p:menuitem id="m_recherche_membres" value="Recherche Avancée" icon="pi pi-search" outcome="/pages/secure/membre/recherche" />
<p:menuitem id="m_profil_membre" value="Mon Profil" icon="pi pi-user" outcome="/pages/secure/membre/profil" />
<p:menuitem id="m_import_membres" value="Import en Masse" icon="pi pi-upload" url="#" />
<p:menuitem id="m_export_membres" value="Export Membres" icon="pi pi-download" url="#" />
<p:menuitem id="m_import_membres" value="Import en Masse" icon="pi pi-upload" outcome="/pages/secure/membre/import" />
<p:menuitem id="m_export_membres" value="Export Membres" icon="pi pi-download" outcome="/pages/secure/membre/export" />
<p:separator />
<!-- Lions User Manager - Gestion Keycloak -->
<p:menuitem id="m_user_manager_list" value="Utilisateurs Keycloak" icon="pi pi-users-cog" outcome="/pages/user-manager/users/list" />
<p:menuitem id="m_user_manager_create" value="Nouvel Utilisateur" icon="pi pi-user-plus" outcome="/pages/user-manager/users/create" />
<p:menuitem id="m_user_manager_roles" value="Gestion des Rôles" icon="pi pi-shield" outcome="/pages/user-manager/roles/list" />
<p:menuitem id="m_user_manager_audit" value="Journal d'Audit" icon="pi pi-history" outcome="/pages/user-manager/audit/logs" />
</p:submenu>
<!-- Gestion des Organisations -->

View File

@@ -1,14 +1,101 @@
# Configuration UnionFlow Client - Profil Production
# Ce fichier est chargé automatiquement quand le profil 'prod' est actif
# Configuration UnionFlow Client - PRODUCTION
# Ce fichier est utilisé avec le profil Quarkus "prod"
# Configuration logging pour production
quarkus.log.console.level=WARN
# Configuration HTTP
quarkus.http.port=8086
quarkus.http.host=0.0.0.0
quarkus.http.root-path=/
quarkus.http.so-reuse-port=true
quarkus.http.tcp-quick-ack=true
quarkus.http.tcp-cork=true
# Configuration MyFaces pour production
# Configuration Session HTTP - Production
quarkus.http.session-timeout=60m
quarkus.http.session-cookie-same-site=strict
quarkus.http.session-cookie-http-only=true
quarkus.http.session-cookie-secure=true
# Configuration logging - Production
quarkus.log.console.enable=true
quarkus.log.console.level=INFO
quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{2.}] (%t) %s%e%n
quarkus.log.category."dev.lions.unionflow".level=INFO
quarkus.log.category."org.primefaces".level=WARN
quarkus.log.category."org.apache.myfaces".level=WARN
# MyFaces Configuration - Production
quarkus.myfaces.project-stage=Production
quarkus.myfaces.serialize-state-in-session=true
quarkus.myfaces.state-saving-method=server
quarkus.myfaces.number-of-views-in-session=50
quarkus.myfaces.number-of-sequential-views-in-session=10
quarkus.myfaces.serialize-state-in-session=false
quarkus.myfaces.client-view-state-timeout=3600000
quarkus.myfaces.view-expired-exception-handler-redirect-page=/
quarkus.myfaces.check-id-production-mode=true
quarkus.myfaces.strict-xhtml-links=true
quarkus.myfaces.refresh-transient-build-on-pss=true
quarkus.myfaces.resource-max-time-expires=604800000
quarkus.myfaces.resource-buffer-size=2048
# Configuration Keycloak pour production
%prod.quarkus.oidc.tls.verification=required
%prod.quarkus.oidc.authentication.redirect-path=/auth/callback
# PrimeFaces Configuration - Production
primefaces.THEME=none
primefaces.FONT_AWESOME=true
primefaces.CLIENT_SIDE_VALIDATION=true
primefaces.MOVE_SCRIPTS_TO_BOTTOM=true
primefaces.CSP=true
primefaces.UPLOADER=commons
primefaces.AUTO_UPDATE=false
primefaces.CACHE_PROVIDER=org.primefaces.cache.DefaultCacheProvider
primefaces.RESOURCE_HANDLER=org.primefaces.application.resource.PrimeResourceHandler
# OmniFaces Configuration - Production
omnifaces.CDN_RESOURCE_HANDLER_DISABLED=true
omnifaces.COMBINED_RESOURCE_HANDLER_DISABLED=false
# Configuration Backend UnionFlow - Production
unionflow.backend.url=${UNIONFLOW_BACKEND_URL:https://api.lions.dev/unionflow}
# Configuration REST Client - Production
quarkus.rest-client."unionflow-api".url=${unionflow.backend.url}
quarkus.rest-client."unionflow-api".scope=jakarta.inject.Singleton
quarkus.rest-client."unionflow-api".connect-timeout=5000
quarkus.rest-client."unionflow-api".read-timeout=30000
quarkus.rest-client."unionflow-api".providers=dev.lions.unionflow.client.service.RestClientExceptionMapper,dev.lions.unionflow.client.security.JwtClientRequestFilter
# Configuration Keycloak OIDC - Production
quarkus.oidc.enabled=true
quarkus.oidc.auth-server-url=${KEYCLOAK_AUTH_SERVER_URL:https://security.lions.dev/realms/unionflow}
quarkus.oidc.client-id=unionflow-client
quarkus.oidc.credentials.secret=${KEYCLOAK_CLIENT_SECRET}
quarkus.oidc.application-type=web-app
quarkus.oidc.authentication.redirect-path=/auth/callback
quarkus.oidc.authentication.restore-path-after-redirect=true
quarkus.oidc.authentication.scopes=openid,profile,email,roles
quarkus.oidc.token.issuer=https://security.lions.dev/realms/unionflow
quarkus.oidc.tls.verification=required
quarkus.oidc.authentication.cookie-same-site=strict
quarkus.oidc.authentication.java-script-auto-redirect=false
quarkus.oidc.discovery-enabled=true
quarkus.oidc.verify-access-token=true
# Activation de la sécurité
quarkus.security.auth.enabled=true
# Chemins publics (non protégés par OIDC) - Production
quarkus.http.auth.permission.public.paths=/,/index.xhtml,/pages/public/*,/auth/*,/q/*,/q/oidc/*,/favicon.ico,/resources/*,/META-INF/resources/*,/images/*,/jakarta.faces.resource/*,/javax.faces.resource/*
quarkus.http.auth.permission.public.policy=permit
# Tous les autres chemins nécessitent une authentification
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
# Configuration Session - Production
unionflow.session.timeout=${SESSION_TIMEOUT:1800}
unionflow.session.remember-me.duration=${REMEMBER_ME_DURATION:604800}
# Configuration de sécurité - Production
unionflow.security.enable-csrf=${ENABLE_CSRF:true}
unionflow.security.password.min-length=${PASSWORD_MIN_LENGTH:8}
unionflow.security.password.require-special-chars=${PASSWORD_REQUIRE_SPECIAL:true}
unionflow.security.max-login-attempts=${MAX_LOGIN_ATTEMPTS:5}
unionflow.security.lockout-duration=${LOCKOUT_DURATION:300}

View File

@@ -1,5 +1,6 @@
package dev.lions.unionflow.server.api.dto.membre;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
@@ -56,10 +57,12 @@ public class MembreSearchResultDTO {
/** Indique si c'est la première page */
@Schema(description = "Indique si c'est la première page")
@JsonProperty("isFirst")
private boolean isFirst;
/** Indique si c'est la dernière page */
@Schema(description = "Indique si c'est la dernière page")
@JsonProperty("isLast")
private boolean isLast;
/** Critères de recherche utilisés */
@@ -181,19 +184,42 @@ public class MembreSearchResultDTO {
* @return Résultat vide
*/
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria) {
return empty(criteria, 20, 0);
}
/**
* Factory method pour créer un résultat vide avec pageSize spécifique
*
* @param criteria Critères de recherche
* @param pageSize Taille de la page
* @param currentPage Page actuelle
* @return Résultat vide
*/
public static MembreSearchResultDTO empty(MembreSearchCriteria criteria, int pageSize, int currentPage) {
MembreSearchResultDTO result = new MembreSearchResultDTO();
result.setMembres(List.of());
result.setTotalElements(0L);
result.setTotalPages(0);
result.setCurrentPage(0);
result.setPageSize(20);
result.setCurrentPage(currentPage);
result.setPageSize(pageSize);
result.setNumberOfElements(0);
result.setHasNext(false);
result.setHasPrevious(false);
result.setFirst(true);
result.setLast(true);
result.isFirst = true; // Assignation directe pour éviter les problèmes avec les setters Lombok
result.isLast = true; // Assignation directe pour éviter les problèmes avec les setters Lombok
result.setCriteria(criteria);
result.setExecutionTimeMs(0L);
// Initialiser statistics avec des valeurs vides
result.setStatistics(SearchStatistics.builder()
.membresActifs(0)
.membresInactifs(0)
.ageMoyen(0.0)
.ageMin(0)
.ageMax(0)
.nombreOrganisations(0)
.nombreRegions(0)
.ancienneteMoyenne(0.0)
.build());
return result;
}
}

View File

@@ -216,6 +216,20 @@
</configuration>
</plugin>
<!-- Maven Surefire pour les tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<systemPropertyVariables>
<!-- Exclure les migrations Flyway du classpath des tests -->
<quarkus.flyway.enabled>false</quarkus.flyway.enabled>
<quarkus.flyway.migrate-at-start>false</quarkus.flyway.migrate-at-start>
</systemPropertyVariables>
</configuration>
</plugin>
<!-- Jacoco pour la couverture de code -->
<plugin>
<groupId>org.jacoco</groupId>

View File

@@ -78,6 +78,10 @@ public abstract class BaseRepository<T extends BaseEntity> {
*/
@Transactional
public void delete(T entity) {
// Si l'entité n'est pas dans le contexte de persistance, la merger d'abord
if (!entityManager.contains(entity)) {
entity = entityManager.merge(entity);
}
entityManager.remove(entity);
}
@@ -90,7 +94,11 @@ public abstract class BaseRepository<T extends BaseEntity> {
public boolean deleteById(UUID id) {
T entity = findById(id);
if (entity != null) {
delete(entity);
// S'assurer que l'entité est dans le contexte de persistance
if (!entityManager.contains(entity)) {
entity = entityManager.merge(entity);
}
entityManager.remove(entity);
return true;
}
return false;

View File

@@ -360,7 +360,7 @@ public class MembreResource {
public Response searchMembresAdvanced(
@RequestBody(
description = "Critères de recherche avancée",
required = true,
required = false,
content =
@Content(
mediaType = MediaType.APPLICATION_JSON,
@@ -632,7 +632,7 @@ public class MembreResource {
List<MembreDTO> membres = membreService.listerMembresPourExport(
associationId, statut, type, dateAdhesionDebut, dateAdhesionFin);
return Response.ok(membres.size()).build();
return Response.ok(Map.of("count", membres.size())).build();
} catch (Exception e) {
LOG.errorf(e, "Erreur lors du comptage des membres");
return Response.status(Response.Status.INTERNAL_SERVER_ERROR)

View File

@@ -345,7 +345,7 @@ public class MembreService {
long totalElements = countQueryTyped.getSingleResult();
if (totalElements == 0) {
return MembreSearchResultDTO.empty(criteria);
return MembreSearchResultDTO.empty(criteria, page.size, page.index);
}
// Ajout du tri et pagination
@@ -488,7 +488,10 @@ public class MembreService {
}
return sort.getColumns().stream()
.map(column -> "m." + column.getName() + " " + column.getDirection().name())
.map(column -> {
String direction = column.getDirection() == Sort.Direction.Descending ? "DESC" : "ASC";
return "m." + column.getName() + " " + direction;
})
.collect(Collectors.joining(", "));
}

View File

@@ -5,19 +5,27 @@
quarkus.datasource.db-kind=h2
quarkus.datasource.username=sa
quarkus.datasource.password=
quarkus.datasource.jdbc.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
quarkus.datasource.jdbc.url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;MODE=PostgreSQL
# Configuration Hibernate pour tests
quarkus.hibernate-orm.database.generation=drop-and-create
# Désactiver l'exécution de import.sql pendant les tests
quarkus.hibernate-orm.sql-load-script=
# Désactiver complètement l'exécution des scripts SQL au démarrage
quarkus.hibernate-orm.sql-load-script-source=none
# Empêcher Hibernate d'exécuter les scripts SQL automatiquement
# Note: Ne pas définir quarkus.hibernate-orm.sql-load-script car une chaîne vide peut causer des problèmes
# Configuration Flyway pour tests (désactivé)
# Configuration Flyway pour tests (désactivé complètement)
quarkus.flyway.migrate-at-start=false
quarkus.flyway.enabled=false
quarkus.flyway.baseline-on-migrate=false
# Note: Ne pas définir quarkus.flyway.locations car une chaîne vide cause une erreur de configuration
# Configuration Keycloak pour tests (désactivé)
quarkus.oidc.tenant-enabled=false
quarkus.keycloak.policy-enforcer.enable=false
# Configuration HTTP pour tests
quarkus.http.port=0
quarkus.http.test-port=0

View File

@@ -104,6 +104,7 @@ class MembreResourceAdvancedSearchTest {
void testAdvancedSearchPagination() {
MembreSearchCriteria criteria =
MembreSearchCriteria.builder()
.statut("ACTIF") // Ajouter un critère valide
.includeInactifs(true) // Inclure tous les membres
.build();
@@ -286,7 +287,11 @@ class MembreResourceAdvancedSearchTest {
roles = {"SUPER_ADMIN"})
@DisplayName("POST /api/membres/search/advanced doit retourner des statistiques complètes")
void testAdvancedSearchStatistics() {
MembreSearchCriteria criteria = MembreSearchCriteria.builder().includeInactifs(true).build();
MembreSearchCriteria criteria =
MembreSearchCriteria.builder()
.statut("ACTIF") // Ajouter un critère valide
.includeInactifs(true)
.build();
given()
.contentType(ContentType.JSON)

View File

@@ -105,13 +105,21 @@ class MembreServiceAdvancedSearchTest {
if (testMembres != null) {
testMembres.forEach(membre -> {
if (membre.getId() != null) {
membreRepository.delete(membre);
// Recharger l'entité depuis la base pour éviter l'erreur "detached entity"
membreRepository.findByIdOptional(membre.getId()).ifPresent(m -> {
// Utiliser deleteById pour éviter les problèmes avec les entités détachées
membreRepository.deleteById(m.getId());
});
}
});
}
if (testOrganisation != null && testOrganisation.getId() != null) {
organisationRepository.delete(testOrganisation);
// Recharger l'entité depuis la base pour éviter l'erreur "detached entity"
organisationRepository.findByIdOptional(testOrganisation.getId()).ifPresent(o -> {
// Utiliser deleteById pour éviter les problèmes avec les entités détachées
organisationRepository.deleteById(o.getId());
});
}
}