fix(client): version 1.0.4, accesseurs JavaBean sur OrganisationSummaryResponse (compat JSF/EL)

This commit is contained in:
dahoud
2026-04-11 02:00:48 +00:00
parent 05b97f04cd
commit 237922891d
30 changed files with 898 additions and 220 deletions

View File

@@ -7,7 +7,7 @@
<parent> <parent>
<groupId>dev.lions.unionflow</groupId> <groupId>dev.lions.unionflow</groupId>
<artifactId>unionflow-parent</artifactId> <artifactId>unionflow-parent</artifactId>
<version>1.0.3</version> <version>1.0.4</version>
<relativePath>../unionflow-server-api/parent-pom.xml</relativePath> <relativePath>../unionflow-server-api/parent-pom.xml</relativePath>
</parent> </parent>
@@ -129,7 +129,7 @@
<dependency> <dependency>
<groupId>dev.lions.unionflow</groupId> <groupId>dev.lions.unionflow</groupId>
<artifactId>unionflow-server-api</artifactId> <artifactId>unionflow-server-api</artifactId>
<version>1.0.3</version> <version>1.0.4</version>
</dependency> </dependency>
<!-- Lions User Manager Client - Module réutilisable de gestion d'utilisateurs Keycloak --> <!-- Lions User Manager Client - Module réutilisable de gestion d'utilisateurs Keycloak -->

View File

@@ -1,5 +1,9 @@
package dev.lions.unionflow.client.api.dto; package dev.lions.unionflow.client.api.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
@@ -7,29 +11,33 @@ import java.time.LocalDate;
/** /**
* DTO received from the backend for the member dashboard synthesis. * DTO received from the backend for the member dashboard synthesis.
*/ */
public record MembreDashboardResponse( @Data
String prenom, @NoArgsConstructor
String nom, @AllArgsConstructor
LocalDate dateInscription, public class MembreDashboardResponse implements Serializable {
private String prenom;
private String nom;
private LocalDate dateInscription;
// Cotisations // Cotisations
BigDecimal mesCotisationsPaiement, private BigDecimal mesCotisationsPaiement;
String statutCotisations, private String statutCotisations;
Integer tauxCotisationsPerso, private Integer tauxCotisationsPerso;
// Epargne // Epargne
BigDecimal monSoldeEpargne, private BigDecimal monSoldeEpargne;
BigDecimal evolutionEpargneNombre, private BigDecimal evolutionEpargneNombre;
String evolutionEpargne, private String evolutionEpargne;
Integer objectifEpargne, private Integer objectifEpargne;
// Evenements // Evenements
Integer mesEvenementsInscrits, private Integer mesEvenementsInscrits;
Integer evenementsAVenir, private Integer evenementsAVenir;
Integer tauxParticipationPerso, private Integer tauxParticipationPerso;
// Aides // Aides
Integer mesDemandesAide, private Integer mesDemandesAide;
Integer aidesEnCours, private Integer aidesEnCours;
Integer tauxAidesApprouvees) implements Serializable { private Integer tauxAidesApprouvees;
} }

View File

@@ -152,11 +152,11 @@ public class AdhesionsBean implements Serializable {
items.add(new SelectItem(null, "Sélectionner une organisation")); items.add(new SelectItem(null, "Sélectionner une organisation"));
if (listeAssociations != null) { if (listeAssociations != null) {
for (OrganisationSummaryResponse assoc : listeAssociations) { for (OrganisationSummaryResponse assoc : listeAssociations) {
String label = assoc.nom(); String label = assoc.getNom();
if (assoc.typeOrganisation() != null) { if (assoc.getTypeOrganisation() != null) {
label += " (" + assoc.typeOrganisation() + ")"; label += " (" + assoc.getTypeOrganisation() + ")";
} }
items.add(new SelectItem(assoc.id(), label)); items.add(new SelectItem(assoc.getId(), label));
} }
} }
return items; return items;

View File

@@ -680,7 +680,7 @@ public class CotisationsBean implements Serializable {
try { try {
IntentionStatutResponse statut = paiementClientService.getStatutIntention(waveIntentionId); IntentionStatutResponse statut = paiementClientService.getStatutIntention(waveIntentionId);
this.waveStatut = statut.statut(); this.waveStatut = statut.getStatut();
if ("COMPLETEE".equals(waveStatut)) { if ("COMPLETEE".equals(waveStatut)) {
waveDialogOuvert = false; waveDialogOuvert = false;

View File

@@ -352,8 +352,8 @@ public class CotisationsGestionBean implements Serializable {
if (response != null && response.getData() != null) { if (response != null && response.getData() != null) {
for (OrganisationSummaryResponse assoc : response.getData()) { for (OrganisationSummaryResponse assoc : response.getData()) {
Organisation org = new Organisation(); Organisation org = new Organisation();
org.setId(assoc.id()); org.setId(assoc.getId());
org.setNom(assoc.nom()); org.setNom(assoc.getNom());
listeOrganisations.add(org); listeOrganisations.add(org);
} }
} }
@@ -391,7 +391,7 @@ public class CotisationsGestionBean implements Serializable {
for (OrganisationSummaryResponse assoc : associations.stream().limit(5).collect(Collectors.toList())) { for (OrganisationSummaryResponse assoc : associations.stream().limit(5).collect(Collectors.toList())) {
List<CotisationResponse> cotisationsOrg = cotisationsDTO.stream() List<CotisationResponse> cotisationsOrg = cotisationsDTO.stream()
.filter(c -> c.getOrganisationId() != null && c.getOrganisationId().equals(assoc.id())) .filter(c -> c.getOrganisationId() != null && c.getOrganisationId().equals(assoc.getId()))
.collect(Collectors.toList()); .collect(Collectors.toList());
long total = cotisationsOrg.size(); long total = cotisationsOrg.size();
@@ -404,7 +404,7 @@ public class CotisationsGestionBean implements Serializable {
.reduce(BigDecimal.ZERO, BigDecimal::add); .reduce(BigDecimal.ZERO, BigDecimal::add);
OrganisationPerformante org = new OrganisationPerformante(); OrganisationPerformante org = new OrganisationPerformante();
org.setNom(assoc.nom()); org.setNom(assoc.getNom());
org.setTauxRecouvrement(taux); org.setTauxRecouvrement(taux);
org.setMontantCollecte(formatMontant(montantCollecte)); org.setMontantCollecte(formatMontant(montantCollecte));
org.setNombreMembresAJour((int) payees); org.setNombreMembresAJour((int) payees);

View File

@@ -94,22 +94,22 @@ public class DashboardMembreBean implements Serializable {
try { try {
MembreDashboardResponse data = dashboardClient.getMonDashboard(); MembreDashboardResponse data = dashboardClient.getMonDashboard();
if (data != null) { if (data != null) {
this.prenomMembre = data.prenom(); this.prenomMembre = data.getPrenom();
this.nomMembre = data.nom(); this.nomMembre = data.getNom();
this.dateInscription = data.dateInscription(); this.dateInscription = data.getDateInscription();
this.mesCotisationsPaiement = formatMontant(data.mesCotisationsPaiement()); this.mesCotisationsPaiement = formatMontant(data.getMesCotisationsPaiement());
this.statutCotisations = data.statutCotisations() != null ? data.statutCotisations() : "Non disponible"; this.statutCotisations = data.getStatutCotisations() != null ? data.getStatutCotisations() : "Non disponible";
this.tauxCotisationsPerso = data.tauxCotisationsPerso(); this.tauxCotisationsPerso = data.getTauxCotisationsPerso();
this.monSoldeEpargne = formatMontant(data.monSoldeEpargne()); this.monSoldeEpargne = formatMontant(data.getMonSoldeEpargne());
this.evolutionEpargneNombre = formatMontant(data.evolutionEpargneNombre()); this.evolutionEpargneNombre = formatMontant(data.getEvolutionEpargneNombre());
this.evolutionEpargne = data.evolutionEpargne() != null ? data.evolutionEpargne() : "+0%"; this.evolutionEpargne = data.getEvolutionEpargne() != null ? data.getEvolutionEpargne() : "+0%";
this.objectifEpargne = data.objectifEpargne(); this.objectifEpargne = data.getObjectifEpargne();
this.mesEvenementsInscrits = data.mesEvenementsInscrits() != null ? data.mesEvenementsInscrits() : 0; this.mesEvenementsInscrits = data.getMesEvenementsInscrits() != null ? data.getMesEvenementsInscrits() : 0;
this.evenementsAVenir = data.evenementsAVenir() != null ? data.evenementsAVenir() : 0; this.evenementsAVenir = data.getEvenementsAVenir() != null ? data.getEvenementsAVenir() : 0;
this.tauxParticipationPerso = data.tauxParticipationPerso(); this.tauxParticipationPerso = data.getTauxParticipationPerso();
this.mesDemandesAide = data.mesDemandesAide() != null ? data.mesDemandesAide() : 0; this.mesDemandesAide = data.getMesDemandesAide() != null ? data.getMesDemandesAide() : 0;
this.aidesEnCours = data.aidesEnCours() != null ? data.aidesEnCours() : 0; this.aidesEnCours = data.getAidesEnCours() != null ? data.getAidesEnCours() : 0;
this.tauxAidesApprouvees = data.tauxAidesApprouvees(); this.tauxAidesApprouvees = data.getTauxAidesApprouvees();
} }
} catch (Exception e) { } catch (Exception e) {
LOG.error("Erreur chargement KPI dashboard", e); LOG.error("Erreur chargement KPI dashboard", e);

View File

@@ -113,10 +113,10 @@ public class EntitesGestionBean implements Serializable {
associations = response.getData(); associations = response.getData();
} }
statistiques.setTotalEntites(associations.size()); statistiques.setTotalEntites(associations.size());
long actives = associations.stream().filter(a -> "ACTIVE".equals(a.statut())).count(); long actives = associations.stream().filter(a -> "ACTIVE".equals(a.getStatut())).count();
statistiques.setEntitesActives((int) actives); statistiques.setEntitesActives((int) actives);
int totalMembres = associations.stream() int totalMembres = associations.stream()
.mapToInt(a -> a.nombreMembres() != null ? a.nombreMembres() : 0) .mapToInt(a -> a.getNombreMembres() != null ? a.getNombreMembres() : 0)
.sum(); .sum();
statistiques.setTotalMembres(totalMembres); statistiques.setTotalMembres(totalMembres);
double moyenne = associations.isEmpty() ? 0 : (double) totalMembres / associations.size(); double moyenne = associations.isEmpty() ? 0 : (double) totalMembres / associations.size();
@@ -154,15 +154,15 @@ public class EntitesGestionBean implements Serializable {
private Entite convertToEntite(OrganisationSummaryResponse dto) { private Entite convertToEntite(OrganisationSummaryResponse dto) {
Entite entite = new Entite(); Entite entite = new Entite();
entite.setId(dto.id()); entite.setId(dto.getId());
entite.setNom(dto.nom()); entite.setNom(dto.getNom());
entite.setCodeEntite(dto.nomCourt()); // Using nomCourt as code entite.setCodeEntite(dto.getNomCourt()); // Using nomCourt as code
entite.setType(dto.typeOrganisation()); entite.setType(dto.getTypeOrganisation());
entite.setTypeLibelle(typeCatalogueService.resolveLibelle(dto.typeOrganisation())); entite.setTypeLibelle(typeCatalogueService.resolveLibelle(dto.getTypeOrganisation()));
entite.setRegion(null); // Not available in Summary entite.setRegion(null); // Not available in Summary
entite.setStatut(dto.statut()); entite.setStatut(dto.getStatut());
entite.setNombreMembres(dto.nombreMembres() != null ? dto.nombreMembres() : 0); entite.setNombreMembres(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0);
entite.setMembresUtilises(dto.nombreMembres() != null ? dto.nombreMembres() : 0); entite.setMembresUtilises(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0);
entite.setAdresse(null); // Not available in Summary entite.setAdresse(null); // Not available in Summary
entite.setTelephone(null); // Not available in Summary entite.setTelephone(null); // Not available in Summary
entite.setEmail(null); // Not available in Summary entite.setEmail(null); // Not available in Summary
@@ -170,7 +170,7 @@ public class EntitesGestionBean implements Serializable {
entite.setDerniereActivite(null); // Not available in Summary entite.setDerniereActivite(null); // Not available in Summary
try { try {
SouscriptionStatutResponse souscription = souscriptionService.obtenirActive(dto.id()); SouscriptionStatutResponse souscription = souscriptionService.obtenirActive(dto.getId());
if (souscription != null) { if (souscription != null) {
entite.setForfaitSouscrit( entite.setForfaitSouscrit(
souscription.getPlanCommercial() != null ? souscription.getPlanCommercial() : "Non défini"); souscription.getPlanCommercial() != null ? souscription.getPlanCommercial() : "Non défini");
@@ -572,7 +572,7 @@ public class EntitesGestionBean implements Serializable {
for (OrganisationSummaryResponse assoc : associations) { for (OrganisationSummaryResponse assoc : associations) {
try { try {
SouscriptionStatutResponse souscription = souscriptionService.obtenirActive(assoc.id()); SouscriptionStatutResponse souscription = souscriptionService.obtenirActive(assoc.getId());
if (souscription != null) { if (souscription != null) {
totalSouscriptions++; totalSouscriptions++;
if ("ACTIVE".equals(souscription.getStatut())) { if ("ACTIVE".equals(souscription.getStatut())) {

View File

@@ -98,8 +98,8 @@ public class MembreExportBean implements Serializable {
: new ArrayList<>(); : new ArrayList<>();
for (OrganisationSummaryResponse assoc : associations) { for (OrganisationSummaryResponse assoc : associations) {
OrganisationResponse org = new OrganisationResponse(); OrganisationResponse org = new OrganisationResponse();
org.setId(assoc.id()); org.setId(assoc.getId());
org.setNom(assoc.nom()); org.setNom(assoc.getNom());
org.setVille(null /* ville not in Summary */); org.setVille(null /* ville not in Summary */);
organisationsDisponibles.add(org); organisationsDisponibles.add(org);
} }

View File

@@ -81,8 +81,8 @@ public class MembreImportBean implements Serializable {
: new ArrayList<>(); : new ArrayList<>();
for (OrganisationSummaryResponse assoc : associations) { for (OrganisationSummaryResponse assoc : associations) {
OrganisationResponse org = new OrganisationResponse(); OrganisationResponse org = new OrganisationResponse();
org.setId(assoc.id()); org.setId(assoc.getId());
org.setNom(assoc.nom()); org.setNom(assoc.getNom());
org.setVille(null /* ville not in Summary */); org.setVille(null /* ville not in Summary */);
organisationsDisponibles.add(org); organisationsDisponibles.add(org);
} }

View File

@@ -97,7 +97,7 @@ public class MembreLazyDataModel extends LazyDataModelBase<MembreSummaryResponse
@Override @Override
public String getRowKey(MembreSummaryResponse object) { public String getRowKey(MembreSummaryResponse object) {
return object != null && object.id() != null ? object.id().toString() : null; return object != null && object.getId() != null ? object.getId().toString() : null;
} }
@Override @Override

View File

@@ -148,8 +148,8 @@ public class MembreRechercheBean implements Serializable {
if (response != null && response.getData() != null) { if (response != null && response.getData() != null) {
for (dev.lions.unionflow.server.api.dto.organisation.response.OrganisationSummaryResponse assoc : response.getData()) { for (dev.lions.unionflow.server.api.dto.organisation.response.OrganisationSummaryResponse assoc : response.getData()) {
Entite entite = new Entite(); Entite entite = new Entite();
entite.setId(assoc.id()); entite.setId(assoc.getId());
entite.setNom(assoc.nom()); entite.setNom(assoc.getNom());
entitesDisponibles.add(entite); entitesDisponibles.add(entite);
} }
} }

View File

@@ -70,9 +70,9 @@ public class MessagingBean implements Serializable {
public void ouvrirConversation(ConversationResponse conversation) { public void ouvrirConversation(ConversationResponse conversation) {
this.conversationActive = conversation; this.conversationActive = conversation;
chargerMessages(conversation.id()); chargerMessages(conversation.getId());
try { try {
conversationService.marquerCommeLue(conversation.id()); conversationService.marquerCommeLue(conversation.getId());
} catch (Exception e) { } catch (Exception e) {
LOGGER.warning("Impossible de marquer comme lue: " + e.getMessage()); LOGGER.warning("Impossible de marquer comme lue: " + e.getMessage());
} }
@@ -94,7 +94,7 @@ public class MessagingBean implements Serializable {
} }
try { try {
SendMessageRequest request = SendMessageRequest.builder() SendMessageRequest request = SendMessageRequest.builder()
.conversationId(conversationActive.id()) .conversationId(conversationActive.getId())
.content(contenuMessage.trim()) .content(contenuMessage.trim())
.build(); .build();
MessageResponse envoye = messageService.envoyer(request); MessageResponse envoye = messageService.envoyer(request);
@@ -135,7 +135,7 @@ public class MessagingBean implements Serializable {
public void archiverConversation(ConversationResponse conversation) { public void archiverConversation(ConversationResponse conversation) {
try { try {
conversationService.archiver(conversation.id(), !conversation.isArchived()); conversationService.archiver(conversation.getId(), !conversation.isArchived());
chargerConversations(); chargerConversations();
} catch (Exception e) { } catch (Exception e) {
ajouterMessageErreur("Impossible de modifier la conversation."); ajouterMessageErreur("Impossible de modifier la conversation.");
@@ -144,7 +144,7 @@ public class MessagingBean implements Serializable {
public void basculerSilence(ConversationResponse conversation) { public void basculerSilence(ConversationResponse conversation) {
try { try {
conversationService.basculerSilence(conversation.id()); conversationService.basculerSilence(conversation.getId());
chargerConversations(); chargerConversations();
} catch (Exception e) { } catch (Exception e) {
ajouterMessageErreur("Impossible de modifier le silence."); ajouterMessageErreur("Impossible de modifier le silence.");
@@ -153,7 +153,7 @@ public class MessagingBean implements Serializable {
public void basculerEpinglage(ConversationResponse conversation) { public void basculerEpinglage(ConversationResponse conversation) {
try { try {
conversationService.basculerEpinglage(conversation.id()); conversationService.basculerEpinglage(conversation.getId());
chargerConversations(); chargerConversations();
} catch (Exception e) { } catch (Exception e) {
ajouterMessageErreur("Impossible de modifier l'épinglage."); ajouterMessageErreur("Impossible de modifier l'épinglage.");
@@ -162,7 +162,7 @@ public class MessagingBean implements Serializable {
public void supprimerMessage(MessageResponse message) { public void supprimerMessage(MessageResponse message) {
try { try {
messageService.supprimer(message.id()); messageService.supprimer(message.getId());
messagesConversationActive.remove(message); messagesConversationActive.remove(message);
ajouterMessageSucces("Message supprimé."); ajouterMessageSucces("Message supprimé.");
} catch (Exception e) { } catch (Exception e) {
@@ -173,7 +173,7 @@ public class MessagingBean implements Serializable {
public void actualiser() { public void actualiser() {
chargerConversations(); chargerConversations();
if (conversationActive != null) { if (conversationActive != null) {
chargerMessages(conversationActive.id()); chargerMessages(conversationActive.getId());
} }
} }

View File

@@ -82,7 +82,7 @@ public class OrganisationStatistiquesBean implements Serializable {
long total = organisations.size(); long total = organisations.size();
long actives = organisations.stream() long actives = organisations.stream()
.filter(o -> o.statut() != null && StatutOrganisationConstants.ACTIVE.equals(o.statut())) .filter(o -> o.getStatut() != null && StatutOrganisationConstants.ACTIVE.equals(o.getStatut()))
.count(); .count();
long inactives = total - actives; long inactives = total - actives;

View File

@@ -159,7 +159,7 @@ public class OrganisationsBean implements Serializable {
totalOrganisations = toutes.size(); totalOrganisations = toutes.size();
organisationsActives = toutes.stream() organisationsActives = toutes.stream()
.filter(o -> o.statut() != null && StatutOrganisationConstants.ACTIVE.equals(o.statut())) .filter(o -> o.getStatut() != null && StatutOrganisationConstants.ACTIVE.equals(o.getStatut()))
.count(); .count();
organisationsInactives = totalOrganisations - organisationsActives; organisationsInactives = totalOrganisations - organisationsActives;
@@ -321,7 +321,7 @@ public class OrganisationsBean implements Serializable {
public void preparerModification(OrganisationSummaryResponse org) { public void preparerModification(OrganisationSummaryResponse org) {
try { try {
organisationSelectionnee = retryService.executeWithRetrySupplier( organisationSelectionnee = retryService.executeWithRetrySupplier(
() -> organisationService.obtenirParId(org.id()), () -> organisationService.obtenirParId(org.getId()),
"chargement de l'organisation pour modification"); "chargement de l'organisation pour modification");
} catch (Exception e) { } catch (Exception e) {
errorHandler.handleException(e, "lors du chargement de l'organisation", null); errorHandler.handleException(e, "lors du chargement de l'organisation", null);
@@ -368,9 +368,9 @@ public class OrganisationsBean implements Serializable {
*/ */
public void preparerSuppression(OrganisationSummaryResponse org) { public void preparerSuppression(OrganisationSummaryResponse org) {
OrganisationResponse full = new OrganisationResponse(); OrganisationResponse full = new OrganisationResponse();
full.setId(org.id()); full.setId(org.getId());
full.setNom(org.nom()); full.setNom(org.getNom());
full.setStatut(org.statut()); full.setStatut(org.getStatut());
organisationPourSuppression = full; organisationPourSuppression = full;
} }
@@ -399,9 +399,9 @@ public class OrganisationsBean implements Serializable {
*/ */
public void preparerBasculerStatut(OrganisationSummaryResponse org) { public void preparerBasculerStatut(OrganisationSummaryResponse org) {
OrganisationResponse full = new OrganisationResponse(); OrganisationResponse full = new OrganisationResponse();
full.setId(org.id()); full.setId(org.getId());
full.setNom(org.nom()); full.setNom(org.getNom());
full.setStatut(org.statut()); full.setStatut(org.getStatut());
organisationPourStatut = full; organisationPourStatut = full;
} }
@@ -609,22 +609,22 @@ public class OrganisationsBean implements Serializable {
.filter(org -> { .filter(org -> {
if (rechercheGlobale != null && !rechercheGlobale.trim().isEmpty()) { if (rechercheGlobale != null && !rechercheGlobale.trim().isEmpty()) {
String recherche = rechercheGlobale.toLowerCase(); String recherche = rechercheGlobale.toLowerCase();
return (org.nom() != null && org.nom().toLowerCase().contains(recherche)) || return (org.getNom() != null && org.getNom().toLowerCase().contains(recherche)) ||
(org.nomCourt() != null && org.nomCourt().toLowerCase().contains(recherche)) || (org.getNomCourt() != null && org.getNomCourt().toLowerCase().contains(recherche)) ||
(org.typeOrganisationLibelle() != null (org.getTypeOrganisationLibelle() != null
&& org.typeOrganisationLibelle().toLowerCase().contains(recherche)); && org.getTypeOrganisationLibelle().toLowerCase().contains(recherche));
} }
return true; return true;
}) })
.filter(org -> { .filter(org -> {
if (filtreStatut != null && !filtreStatut.trim().isEmpty()) { if (filtreStatut != null && !filtreStatut.trim().isEmpty()) {
return filtreStatut.equals(org.statut()); return filtreStatut.equals(org.getStatut());
} }
return true; return true;
}) })
.filter(org -> { .filter(org -> {
if (filtreType != null && !filtreType.trim().isEmpty()) { if (filtreType != null && !filtreType.trim().isEmpty()) {
return filtreType.equals(org.typeOrganisation()); return filtreType.equals(org.getTypeOrganisation());
} }
return true; return true;
}) })

View File

@@ -339,17 +339,17 @@ public class SuperAdminBean implements Serializable {
: new ArrayList<>(); : new ArrayList<>();
topEntites = associations.stream() topEntites = associations.stream()
.sorted((a1, a2) -> { .sorted((a1, a2) -> {
int m1 = a1.nombreMembres() != null ? a1.nombreMembres() : 0; int m1 = a1.getNombreMembres() != null ? a1.getNombreMembres() : 0;
int m2 = a2.nombreMembres() != null ? a2.nombreMembres() : 0; int m2 = a2.getNombreMembres() != null ? a2.getNombreMembres() : 0;
return Integer.compare(m2, m1); return Integer.compare(m2, m1);
}) })
.limit(5) .limit(5)
.map(a -> { .map(a -> {
Entite entite = new Entite(); Entite entite = new Entite();
entite.setId(a.id()); entite.setId(a.getId());
entite.setNom(a.nom()); entite.setNom(a.getNom());
entite.setTypeEntite(a.typeOrganisation()); entite.setTypeEntite(a.getTypeOrganisation());
entite.setNombreMembres(a.nombreMembres() != null ? a.nombreMembres() : 0); entite.setNombreMembres(a.getNombreMembres() != null ? a.getNombreMembres() : 0);
return entite; return entite;
}) })
.collect(java.util.stream.Collectors.toList()); .collect(java.util.stream.Collectors.toList());

View File

@@ -91,8 +91,8 @@ public class UtilisateursBean implements Serializable {
: new ArrayList<>(); : new ArrayList<>();
for (OrganisationSummaryResponse assoc : associations) { for (OrganisationSummaryResponse assoc : associations) {
Organisation org = new Organisation(); Organisation org = new Organisation();
org.setId(assoc.id()); org.setId(assoc.getId());
org.setNom(assoc.nom()); org.setNom(assoc.getNom());
organisationsDisponibles.add(org); organisationsDisponibles.add(org);
} }
} catch (Exception e) { } catch (Exception e) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -13,7 +13,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<!-- Obsolète : apple-mobile-web-app-capable. Remplacé par mobile-web-app-capable --> <!-- Obsolète : apple-mobile-web-app-capable. Remplacé par mobile-web-app-capable -->
<meta name="mobile-web-app-capable" content="yes" /> <meta name="mobile-web-app-capable" content="yes" />
<link rel="icon" href="#{request.contextPath}/resources/freya-layout/images/favicon.ico" type="image/x-icon" /> <link rel="icon" href="#{request.contextPath}/resources/freya-layout/images/unionflow-logo.png" type="image/png" />
</f:facet> </f:facet>
<title>UnionFlow - Plateforme de Gestion Intégrée pour Mutuelles, Associations et Clubs</title> <title>UnionFlow - Plateforme de Gestion Intégrée pour Mutuelles, Associations et Clubs</title>
@@ -23,6 +23,7 @@
<h:outputStylesheet name="css/primeflex.min.css" library="freya-layout" /> <h:outputStylesheet name="css/primeflex.min.css" library="freya-layout" />
<h:outputStylesheet name="css/layout-#{guestPreferences.layout}.css" library="freya-layout" /> <h:outputStylesheet name="css/layout-#{guestPreferences.layout}.css" library="freya-layout" />
<h:outputStylesheet name="primefaces-freya-#{guestPreferences.componentTheme}/theme.css" /> <h:outputStylesheet name="primefaces-freya-#{guestPreferences.componentTheme}/theme.css" />
<h:outputStylesheet name="css/topbar-elite.css" />
<meta name="description" content="UnionFlow : La solution complète de gestion pour les mutuelles, associations, clubs (informatiques, juridiques, etc.) et organisations similaires. Gestion des membres, cotisations, événements, solidarité et analytics." /> <meta name="description" content="UnionFlow : La solution complète de gestion pour les mutuelles, associations, clubs (informatiques, juridiques, etc.) et organisations similaires. Gestion des membres, cotisations, événements, solidarité et analytics." />
</h:head> </h:head>
@@ -31,8 +32,13 @@
<!-- Landing Topbar --> <!-- Landing Topbar -->
<div class="landing-topbar"> <div class="landing-topbar">
<div class="landing-topbar-left"> <div class="landing-topbar-left">
<h:link id="logolink" outcome="/pages/secure/dashboard" styleClass="logo"> <h:link id="logolink" outcome="/pages/secure/dashboard" styleClass="logo unionflow-brand unionflow-brand--landing">
<p:graphicImage name="images/logo-freya.svg" library="freya-layout" /> <h:graphicImage value="#{request.contextPath}/resources/freya-layout/images/unionflow-logo.png"
alt="Logo UnionFlow"
styleClass="unionflow-brand-icon" />
<span class="unionflow-brand-text">
<span class="unionflow-brand-name">UNIONFLOW</span>
</span>
</h:link> </h:link>
<ul class="landing-menu"> <ul class="landing-menu">
@@ -75,8 +81,8 @@
<div id="home" class="landing-banner"> <div id="home" class="landing-banner">
<div class="landing-banner-content"> <div class="landing-banner-content">
<span class="title">UnionFlow</span> <span class="title">UnionFlow</span>
<h3>Plateforme de Gestion Intégrée pour Mutuelles, Associations et Clubs<br/> <h3>Fédérez vos membres. Sécurisez vos flux. Pilotez l'avenir.<br/>
Simplifiez la gestion de votre organisation avec une solution complète et moderne</h3> Oubliez la gestion manuelle. La plateforme technologique financière qui apporte transparence et rigueur à votre organisation.</h3>
<a href="#{request.contextPath}/pages/secure/dashboard.xhtml" <a href="#{request.contextPath}/pages/secure/dashboard.xhtml"
style="display:inline-flex;align-items:center;gap:.6rem; style="display:inline-flex;align-items:center;gap:.6rem;
padding:1rem 2.5rem;border-radius:8px; padding:1rem 2.5rem;border-radius:8px;
@@ -103,8 +109,8 @@
<div class="feature-card"> <div class="feature-card">
<span>1</span> <span>1</span>
<div class="card-content"> <div class="card-content">
<h3>Gestion des Membres</h3> <h3>Maîtrisez votre Base Membres</h3>
<h5>Inscription, profils détaillés, gestion des statuts, historique des adhésions et suivi complet de chaque membre.</h5> <h5>Finies les listes papier perdues. Centralisez les profils, gérez les statuts et gardez le contact avec votre communauté.</h5>
</div> </div>
</div> </div>
</div> </div>
@@ -118,8 +124,8 @@
<div class="feature-card"> <div class="feature-card">
<span>2</span> <span>2</span>
<div class="card-content"> <div class="card-content">
<h3>Gestion des Cotisations</h3> <h3>Sécurisez vos Collectes</h3>
<h5>Types variés (mensuelle, annuelle, adhésion, événement, formation, projet, solidarité), suivi des paiements et rappels automatiques. <strong>Paiements sécurisés via Wave</strong> (bientôt disponible).</h5> <h5>Automatisez vos appels à cotisation, suivez vos tontines en temps réel et intégrez <strong>les paiements par mobile money (ex: Wave)</strong>.</h5>
<div style="margin-top: 10px;"> <div style="margin-top: 10px;">
<!-- Image locale du client (servie depuis META-INF/resources/images) --> <!-- Image locale du client (servie depuis META-INF/resources/images) -->
<h:graphicImage value="#{request.contextPath}/images/logo-wave.png" style="max-height: 30px; width: auto;" alt="Wave - Paiements mobiles" /> <h:graphicImage value="#{request.contextPath}/images/logo-wave.png" style="max-height: 30px; width: auto;" alt="Wave - Paiements mobiles" />
@@ -134,8 +140,8 @@
<div class="feature-card"> <div class="feature-card">
<span>3</span> <span>3</span>
<div class="card-content"> <div class="card-content">
<h3>Organisation<br/>d'Événements</h3> <h3>Faites vivre<br/>vos Réunions et AG</h3>
<h5>Assemblées générales, réunions, formations, conférences, ateliers, séminaires, événements sociaux avec gestion des inscriptions.</h5> <h5>Gérez l'organisation des assemblées générales, traquez les présences lors des réunions statutaires et boostez l'engagement.</h5>
</div> </div>
</div> </div>
</div> </div>
@@ -150,8 +156,8 @@
<div class="feature-card"> <div class="feature-card">
<span>4</span> <span>4</span>
<div class="card-content"> <div class="card-content">
<h3>Système de Solidarité</h3> <h3>L'entraide Transparente</h3>
<h5>Gestion complète des demandes d'aide, propositions, évaluations, suivi des statuts et coordination des actions solidaires.</h5> <h5>Sécurisez la gestion de vos cas sociaux (décès, maladie). Approuvez et décaissez les aides avec une traçabilité totale.</h5>
</div> </div>
</div> </div>
</div> </div>
@@ -162,8 +168,8 @@
<div class="feature-card"> <div class="feature-card">
<span>5</span> <span>5</span>
<div class="card-content"> <div class="card-content">
<h3>Gestion des Organisations</h3> <h3>Scalabilité Absolue</h3>
<h5>Gestion des clubs et unions avec hiérarchie organisationnelle, statistiques détaillées, rapports et vue d'ensemble complète.</h5> <h5>Conçu pour évoluer : d'une amicale de quartier à un district international du Lions ou Rotary Club avec des milliers de membres.</h5>
</div> </div>
</div> </div>
</div> </div>
@@ -176,8 +182,8 @@
<div class="feature-card"> <div class="feature-card">
<span>6</span> <span>6</span>
<div class="card-content"> <div class="card-content">
<h3>Analytics &amp; Rapports</h3> <h3>Reporting et Audit</h3>
<h5>Tableaux de bord interactifs, KPIs en temps réel, analyses approfondies et rapports personnalisables pour une prise de décision éclairée.</h5> <h5>Générez des états financiers en un clic pour vos comptabilités et instaurez une gouvernance irréprochable.</h5>
</div> </div>
</div> </div>
</div> </div>
@@ -188,9 +194,9 @@
<!-- Benefits Section --> <!-- Benefits Section -->
<div id="benefits" class="landing-pricing"> <div id="benefits" class="landing-pricing">
<div class="section-header"> <div class="section-header">
<span class="title">Pourquoi choisir UnionFlow ?</span> <span class="title">La technologie au service de la gouvernance</span>
<h3>Une plateforme robuste et moderne bâtie pour les organisations du monde entier<br/> <h3>Toute la rigueur exigée par les institutions, accessible depuis votre mobile<br/>
avec une sensibilité particulière pour les réalités africaines.</h3> conçu avec une fine compréhension des réalités associatives africaines et mondiales.</h3>
</div> </div>
<!-- Grille des avantages --> <!-- Grille des avantages -->
@@ -214,15 +220,15 @@
<ul style="list-style:none;padding:0;margin:0;"> <ul style="list-style:none;padding:0;margin:0;">
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;"> <li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
<i class="pi pi-check" style="color:var(--green-500);"></i> <i class="pi pi-check" style="color:var(--green-500);"></i>
OpenID Connect via Keycloak Infrastructure hautement sécurisée
</li> </li>
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;"> <li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
<i class="pi pi-check" style="color:var(--green-500);"></i> <i class="pi pi-check" style="color:var(--green-500);"></i>
Contrôle d'accès granulaire par rôle Chaque action est loggée et traçable
</li> </li>
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);font-size:.85rem;"> <li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);font-size:.85rem;">
<i class="pi pi-check" style="color:var(--green-500);"></i> <i class="pi pi-check" style="color:var(--green-500);"></i>
Chiffrement de bout en bout Droits de validation croisée stricts
</li> </li>
</ul> </ul>
</div> </div>
@@ -269,16 +275,16 @@
<i class="pi pi-server" style="color:var(--purple-600);font-size:1.25rem;"></i> <i class="pi pi-server" style="color:var(--purple-600);font-size:1.25rem;"></i>
</div> </div>
<h3 style="color:var(--text-color);font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;"> <h3 style="color:var(--text-color);font-size:1.1rem;font-weight:700;margin:0 0 .75rem 0;">
Architecture cloud-native Architecture ultra-rapide
</h3> </h3>
<p style="color:var(--text-color-secondary);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;"> <p style="color:var(--text-color-secondary);line-height:1.7;margin:0 0 1.25rem 0;font-size:.9rem;">
Bâtie sur Quarkus et une architecture microservices, la plateforme monte en Bâtie sur des technologies cloud de dernière génération, la plateforme reste
charge automatiquement et garantit une haute disponibilité. fluide et instantanée même avec des milliers de transactions.
</p> </p>
<ul style="list-style:none;padding:0;margin:0;"> <ul style="list-style:none;padding:0;margin:0;">
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;"> <li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
<i class="pi pi-check" style="color:var(--green-500);"></i> <i class="pi pi-check" style="color:var(--green-500);"></i>
Microservices Quarkus haute performance Temps de réponse quasi-instantané
</li> </li>
<li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;"> <li style="display:flex;align-items:center;gap:.5rem;color:var(--text-color-secondary);margin-bottom:.4rem;font-size:.85rem;">
<i class="pi pi-check" style="color:var(--green-500);"></i> <i class="pi pi-check" style="color:var(--green-500);"></i>

View File

@@ -15,9 +15,9 @@
<div class="card"> <div class="card">
<div class="flex align-items-center justify-content-between"> <div class="flex align-items-center justify-content-between">
<div class="flex align-items-center"> <div class="flex align-items-center">
<div class="bg-blue-100 border-circle flex align-items-center justify-content-center mr-3" <div class="uf-bg-navy-light border-circle flex align-items-center justify-content-center mr-3"
style="width:60px;height:60px;"> style="width:60px;height:60px;">
<i class="pi pi-user text-blue-600 text-3xl"></i> <i class="pi pi-user uf-text-navy text-3xl"></i>
</div> </div>
<div> <div>
<h4 class="m-0 text-900">Bienvenue, #{dashboardMembreBean.prenomMembre}</h4> <h4 class="m-0 text-900">Bienvenue, #{dashboardMembreBean.prenomMembre}</h4>
@@ -42,7 +42,7 @@
<ui:param name="title" value="Mes Cotisations" /> <ui:param name="title" value="Mes Cotisations" />
<ui:param name="value" value="#{dashboardMembreBean.statutCotisations}" /> <ui:param name="value" value="#{dashboardMembreBean.statutCotisations}" />
<ui:param name="icon" value="pi-wallet" /> <ui:param name="icon" value="pi-wallet" />
<ui:param name="iconColor" value="green-600" /> <ui:param name="iconColor" value="uf-text-forest" />
<ui:param name="growthValue" value="#{dashboardMembreBean.mesCotisationsPaiement}" /> <ui:param name="growthValue" value="#{dashboardMembreBean.mesCotisationsPaiement}" />
<ui:param name="growthLabel" value="FCFA payés ce mois" /> <ui:param name="growthLabel" value="FCFA payés ce mois" />
<ui:param name="growthType" value="number" /> <ui:param name="growthType" value="number" />
@@ -55,7 +55,7 @@
<ui:param name="title" value="Mon Épargne" /> <ui:param name="title" value="Mon Épargne" />
<ui:param name="value" value="#{dashboardMembreBean.monSoldeEpargne} FCFA" /> <ui:param name="value" value="#{dashboardMembreBean.monSoldeEpargne} FCFA" />
<ui:param name="icon" value="pi-money-bill" /> <ui:param name="icon" value="pi-money-bill" />
<ui:param name="iconColor" value="blue-600" /> <ui:param name="iconColor" value="uf-text-navy" />
<ui:param name="growthValue" value="#{dashboardMembreBean.evolutionEpargneNombre}" /> <ui:param name="growthValue" value="#{dashboardMembreBean.evolutionEpargneNombre}" />
<ui:param name="growthLabel" value="FCFA ce mois" /> <ui:param name="growthLabel" value="FCFA ce mois" />
<ui:param name="growthType" value="number" /> <ui:param name="growthType" value="number" />
@@ -68,7 +68,7 @@
<ui:param name="title" value="Mes Événements" /> <ui:param name="title" value="Mes Événements" />
<ui:param name="value" value="#{dashboardMembreBean.mesEvenementsInscrits}" /> <ui:param name="value" value="#{dashboardMembreBean.mesEvenementsInscrits}" />
<ui:param name="icon" value="pi-calendar" /> <ui:param name="icon" value="pi-calendar" />
<ui:param name="iconColor" value="purple-600" /> <ui:param name="iconColor" value="uf-text-gold" />
<ui:param name="growthValue" value="#{dashboardMembreBean.evenementsAVenir}" /> <ui:param name="growthValue" value="#{dashboardMembreBean.evenementsAVenir}" />
<ui:param name="growthLabel" value="à venir" /> <ui:param name="growthLabel" value="à venir" />
<ui:param name="growthType" value="number" /> <ui:param name="growthType" value="number" />
@@ -81,7 +81,7 @@
<ui:param name="title" value="Mes Aides" /> <ui:param name="title" value="Mes Aides" />
<ui:param name="value" value="#{dashboardMembreBean.mesDemandesAide}" /> <ui:param name="value" value="#{dashboardMembreBean.mesDemandesAide}" />
<ui:param name="icon" value="pi-heart" /> <ui:param name="icon" value="pi-heart" />
<ui:param name="iconColor" value="orange-600" /> <ui:param name="iconColor" value="uf-text-crimson" />
<ui:param name="growthValue" value="#{dashboardMembreBean.aidesEnCours}" /> <ui:param name="growthValue" value="#{dashboardMembreBean.aidesEnCours}" />
<ui:param name="growthLabel" value="en traitement" /> <ui:param name="growthLabel" value="en traitement" />
<ui:param name="growthType" value="number" /> <ui:param name="growthType" value="number" />
@@ -149,7 +149,7 @@
<span>#{cotisAtt.periode}</span> <span>#{cotisAtt.periode}</span>
</p:column> </p:column>
<p:column headerText="Montant dû"> <p:column headerText="Montant dû">
<span class="font-medium text-orange-600">#{cotisAtt.montantFormatte} FCFA</span> <span class="font-medium uf-text-gold">#{cotisAtt.montantFormatte} FCFA</span>
</p:column> </p:column>
<p:column headerText="Échéance" style="width:110px"> <p:column headerText="Échéance" style="width:110px">
<h:outputText value="#{cotisAtt.dateEcheance}"> <h:outputText value="#{cotisAtt.dateEcheance}">
@@ -228,23 +228,23 @@
<div class="card"> <div class="card">
<h5>Statut de mes cotisations</h5> <h5>Statut de mes cotisations</h5>
<div class="flex flex-column gap-3"> <div class="flex flex-column gap-3">
<div class="flex align-items-center justify-content-between p-3 border-round surface-50"> <div class="flex align-items-center justify-content-between p-3 border-round surface-50 border-1 uf-border-forest mb-2">
<div class="flex align-items-center"> <div class="flex align-items-center">
<i class="pi pi-check-circle text-green-500 text-xl mr-3"></i> <i class="pi pi-check-circle uf-text-forest text-xl mr-3"></i>
<span class="text-900 font-medium">Total historique</span> <span class="text-900 font-medium">Total historique</span>
</div> </div>
<p:badge value="#{dashboardMembreBean.mesCotisations.size()}" severity="success"/> <p:badge value="#{dashboardMembreBean.mesCotisations.size()}" severity="success"/>
</div> </div>
<div class="flex align-items-center justify-content-between p-3 border-round surface-50"> <div class="flex align-items-center justify-content-between p-3 border-round surface-50 border-1 uf-border-gold mb-2">
<div class="flex align-items-center"> <div class="flex align-items-center">
<i class="pi pi-clock text-orange-500 text-xl mr-3"></i> <i class="pi pi-clock uf-text-gold text-xl mr-3"></i>
<span class="text-900 font-medium">En attente</span> <span class="text-900 font-medium">En attente</span>
</div> </div>
<p:badge value="#{dashboardMembreBean.mesCotisationsEnAttente.size()}" severity="warning"/> <p:badge value="#{dashboardMembreBean.mesCotisationsEnAttente.size()}" severity="warning"/>
</div> </div>
<div class="flex align-items-center justify-content-between p-3 border-round surface-50"> <div class="flex align-items-center justify-content-between p-3 border-round surface-50 border-1 uf-border-navy">
<div class="flex align-items-center"> <div class="flex align-items-center">
<i class="pi pi-chart-line text-blue-500 text-xl mr-3"></i> <i class="pi pi-chart-line uf-text-navy text-xl mr-3"></i>
<span class="text-900 font-medium">Taux de paiement</span> <span class="text-900 font-medium">Taux de paiement</span>
</div> </div>
<span class="text-900 font-bold"> <span class="text-900 font-bold">

View File

@@ -56,21 +56,21 @@
<div class="col-12"> <div class="col-12">
<div class="card surface-50 border-round"> <div class="card surface-50 border-round">
<h5 class="text-900 font-bold mb-3"> <h5 class="text-900 font-bold mb-3">
<i class="pi pi-exclamation-circle text-orange-500 mr-2"></i> <i class="pi pi-exclamation-circle uf-text-gold mr-2"></i>
Actions requises aujourd'hui Actions requises aujourd'hui
</h5> </h5>
<div class="grid"> <div class="grid">
<!-- URGENT : Cotisations en retard --> <!-- URGENT : Cotisations en retard -->
<div class="col-12 md:col-6 lg:col-3"> <div class="col-12 md:col-6 lg:col-3">
<div class="surface-card border-round p-3 border-left-3 border-red-500 hover-elevate-2"> <div class="uf-alert-card p-3 uf-border-left-crimson" style="border-left-width: 4px; border-left-style: solid;">
<div class="flex align-items-center"> <div class="flex align-items-center">
<div class="bg-red-100 border-round flex align-items-center justify-content-center mr-3" <div class="uf-bg-crimson-light border-round flex align-items-center justify-content-center mr-3"
style="width: 2.5rem; height: 2.5rem;"> style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-exclamation-triangle text-red-600"></i> <i class="pi pi-exclamation-triangle uf-text-crimson"></i>
</div> </div>
<div class="flex-1"> <div class="flex-1">
<div class="text-red-900 font-bold text-2xl">#{dashboardBean.cotisationsRetard}</div> <div class="uf-text-crimson font-bold text-2xl">#{dashboardBean.cotisationsRetard}</div>
<div class="text-red-700 text-sm font-medium">Cotisations en retard</div> <div class="text-700 text-sm font-medium">Cotisations en retard</div>
</div> </div>
</div> </div>
</div> </div>
@@ -78,15 +78,15 @@
<!-- IMPORTANT : Adhésions à renouveler --> <!-- IMPORTANT : Adhésions à renouveler -->
<div class="col-12 md:col-6 lg:col-3"> <div class="col-12 md:col-6 lg:col-3">
<div class="surface-card border-round p-3 border-left-3 border-orange-500 hover-elevate-2"> <div class="uf-alert-card p-3 uf-border-left-gold" style="border-left-width: 4px; border-left-style: solid;">
<div class="flex align-items-center"> <div class="flex align-items-center">
<div class="bg-orange-100 border-round flex align-items-center justify-content-center mr-3" <div class="uf-bg-gold-light border-round flex align-items-center justify-content-center mr-3"
style="width: 2.5rem; height: 2.5rem;"> style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-clock text-orange-600"></i> <i class="pi pi-clock uf-text-gold"></i>
</div> </div>
<div class="flex-1"> <div class="flex-1">
<div class="text-orange-900 font-bold text-2xl">#{dashboardBean.adhesionsExpiration}</div> <div class="text-900 font-bold text-2xl">#{dashboardBean.adhesionsExpiration}</div>
<div class="text-orange-700 text-sm font-medium">Expire dans 7 jours</div> <div class="text-700 text-sm font-medium">Expire dans 7 jours</div>
</div> </div>
</div> </div>
</div> </div>
@@ -94,15 +94,15 @@
<!-- À TRAITER : Demandes en attente --> <!-- À TRAITER : Demandes en attente -->
<div class="col-12 md:col-6 lg:col-3"> <div class="col-12 md:col-6 lg:col-3">
<div class="surface-card border-round p-3 border-left-3 border-blue-500 hover-elevate-2"> <div class="uf-alert-card p-3 uf-border-left-navy" style="border-left-width: 4px; border-left-style: solid;">
<div class="flex align-items-center"> <div class="flex align-items-center">
<div class="bg-blue-100 border-round flex align-items-center justify-content-center mr-3" <div class="uf-bg-navy-light border-round flex align-items-center justify-content-center mr-3"
style="width: 2.5rem; height: 2.5rem;"> style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-inbox text-blue-600"></i> <i class="pi pi-inbox uf-text-navy"></i>
</div> </div>
<div class="flex-1"> <div class="flex-1">
<div class="text-blue-900 font-bold text-2xl">#{dashboardBean.demandesToTraiter}</div> <div class="uf-text-navy font-bold text-2xl">#{dashboardBean.demandesToTraiter}</div>
<div class="text-blue-700 text-sm font-medium">Demandes en attente</div> <div class="text-700 text-sm font-medium">Demandes en attente</div>
</div> </div>
</div> </div>
</div> </div>
@@ -110,15 +110,15 @@
<!-- SUCCÈS : Tâches complétées --> <!-- SUCCÈS : Tâches complétées -->
<div class="col-12 md:col-6 lg:col-3"> <div class="col-12 md:col-6 lg:col-3">
<div class="surface-card border-round p-3 border-left-3 border-green-500 hover-elevate-2"> <div class="uf-alert-card p-3 uf-border-left-forest" style="border-left-width: 4px; border-left-style: solid;">
<div class="flex align-items-center"> <div class="flex align-items-center">
<div class="bg-green-100 border-round flex align-items-center justify-content-center mr-3" <div class="uf-bg-forest-light border-round flex align-items-center justify-content-center mr-3"
style="width: 2.5rem; height: 2.5rem;"> style="width: 2.5rem; height: 2.5rem;">
<i class="pi pi-check-circle text-green-600"></i> <i class="pi pi-check-circle uf-text-forest"></i>
</div> </div>
<div class="flex-1"> <div class="flex-1">
<div class="text-green-900 font-bold text-2xl">#{dashboardBean.tachesCompletees}</div> <div class="uf-text-forest font-bold text-2xl">#{dashboardBean.tachesCompletees}</div>
<div class="text-green-700 text-sm font-medium">Complétées aujourd'hui</div> <div class="text-700 text-sm font-medium">Complétées aujourd'hui</div>
</div> </div>
</div> </div>
</div> </div>
@@ -131,7 +131,7 @@
<!-- KPIs principaux - Ordre psychologique optimal --> <!-- KPIs principaux - Ordre psychologique optimal -->
<div class="col-12"> <div class="col-12">
<h5 class="text-900 font-bold mb-3"> <h5 class="text-900 font-bold mb-3">
<i class="pi pi-chart-bar text-primary mr-2"></i> <i class="pi pi-chart-bar uf-text-forest mr-2"></i>
Vue d'ensemble Vue d'ensemble
</h5> </h5>
</div> </div>
@@ -143,7 +143,7 @@
<ui:param name="title" value="Membres Actifs" /> <ui:param name="title" value="Membres Actifs" />
<ui:param name="value" value="#{dashboardBean.activeMembers}" /> <ui:param name="value" value="#{dashboardBean.activeMembers}" />
<ui:param name="icon" value="pi-users" /> <ui:param name="icon" value="pi-users" />
<ui:param name="iconColor" value="blue-600" /> <ui:param name="iconColor" value="uf-text-navy" />
<ui:param name="growthValue" value="#{dashboardBean.membresEvolutionPourcent}" /> <ui:param name="growthValue" value="#{dashboardBean.membresEvolutionPourcent}" />
<ui:param name="growthLabel" value="ce mois" /> <ui:param name="growthLabel" value="ce mois" />
<ui:param name="progressValue" value="#{dashboardBean.tauxActivite}" /> <ui:param name="progressValue" value="#{dashboardBean.tauxActivite}" />
@@ -157,7 +157,7 @@
<ui:param name="title" value="FCFA Collectés" /> <ui:param name="title" value="FCFA Collectés" />
<ui:param name="value" value="#{dashboardBean.totalCotisations}" /> <ui:param name="value" value="#{dashboardBean.totalCotisations}" />
<ui:param name="icon" value="pi-dollar" /> <ui:param name="icon" value="pi-dollar" />
<ui:param name="iconColor" value="green-600" /> <ui:param name="iconColor" value="uf-text-forest" />
<ui:param name="growthValue" value="#{dashboardBean.cotisationsEvolutionPourcent}" /> <ui:param name="growthValue" value="#{dashboardBean.cotisationsEvolutionPourcent}" />
<ui:param name="growthLabel" value="vs mois dernier" /> <ui:param name="growthLabel" value="vs mois dernier" />
<ui:param name="progressValue" value="#{dashboardBean.tauxObjectifCotisations}" /> <ui:param name="progressValue" value="#{dashboardBean.tauxObjectifCotisations}" />
@@ -171,7 +171,7 @@
<ui:param name="title" value="FCFA Distribués" /> <ui:param name="title" value="FCFA Distribués" />
<ui:param name="value" value="#{dashboardBean.aidesDistribuees}" /> <ui:param name="value" value="#{dashboardBean.aidesDistribuees}" />
<ui:param name="icon" value="pi-heart" /> <ui:param name="icon" value="pi-heart" />
<ui:param name="iconColor" value="purple-600" /> <ui:param name="iconColor" value="uf-text-gold" />
<ui:param name="statusIcon" value="pi-circle-fill" /> <ui:param name="statusIcon" value="pi-circle-fill" />
<ui:param name="statusLabel" value="Demandes en attente" /> <ui:param name="statusLabel" value="Demandes en attente" />
<ui:param name="statusValue" value="#{dashboardBean.pendingAides}" /> <ui:param name="statusValue" value="#{dashboardBean.pendingAides}" />
@@ -185,8 +185,8 @@
<ui:include src="/templates/components/cards/kpi-card.xhtml"> <ui:include src="/templates/components/cards/kpi-card.xhtml">
<ui:param name="title" value="Taux de Participation" /> <ui:param name="title" value="Taux de Participation" />
<ui:param name="value" value="#{dashboardBean.tauxParticipation}%" /> <ui:param name="value" value="#{dashboardBean.tauxParticipation}%" />
<ui:param name="icon" value="pi-chart-line" /> <ui:param name="icon" value="pi-calendar" />
<ui:param name="iconColor" value="orange-600" /> <ui:param name="iconColor" value="uf-text-navy" />
<ui:param name="statusIcon" value="pi-calendar" /> <ui:param name="statusIcon" value="pi-calendar" />
<ui:param name="statusLabel" value="Événements prévus" /> <ui:param name="statusLabel" value="Événements prévus" />
<ui:param name="statusValue" value="#{dashboardBean.upcomingEvents}" /> <ui:param name="statusValue" value="#{dashboardBean.upcomingEvents}" />
@@ -469,8 +469,8 @@
<div class="flex flex-column gap-3"> <div class="flex flex-column gap-3">
<!-- Valider adhésions : SECRETAIRE, ADMIN --> <!-- Valider adhésions : SECRETAIRE, ADMIN -->
<ui:fragment rendered="#{menuBean.isSecretaire() or menuBean.isAdminOrganisation() or menuBean.isSuperAdmin()}"> <ui:fragment rendered="#{menuBean.isSecretaire() or menuBean.isAdminOrganisation() or menuBean.isSuperAdmin()}">
<div class="flex align-items-center p-3 border-round bg-blue-50 border-blue-200"> <div class="flex align-items-center p-3 border-round uf-bg-navy-light border-1 uf-border-navy">
<i class="pi pi-check-circle text-blue-500 text-xl mr-3"></i> <i class="pi pi-check-circle uf-text-navy text-xl mr-3"></i>
<div class="flex-1"> <div class="flex-1">
<div class="text-900 font-medium">Valider #{dashboardBean.adhesionsPendantes} adhésions</div> <div class="text-900 font-medium">Valider #{dashboardBean.adhesionsPendantes} adhésions</div>
<small class="text-600">Demandes en attente de validation</small> <small class="text-600">Demandes en attente de validation</small>
@@ -485,8 +485,8 @@
<!-- Relancer cotisations : TRESORIER, SECRETAIRE, ADMIN --> <!-- Relancer cotisations : TRESORIER, SECRETAIRE, ADMIN -->
<ui:fragment rendered="#{menuBean.isTresorier() or menuBean.isSecretaire() or menuBean.isAdminOrganisation() or menuBean.isSuperAdmin()}"> <ui:fragment rendered="#{menuBean.isTresorier() or menuBean.isSecretaire() or menuBean.isAdminOrganisation() or menuBean.isSuperAdmin()}">
<div class="flex align-items-center p-3 border-round bg-orange-50 border-orange-200"> <div class="flex align-items-center p-3 border-round uf-bg-gold-light border-1 uf-border-gold">
<i class="pi pi-exclamation-triangle text-orange-500 text-xl mr-3"></i> <i class="pi pi-exclamation-triangle uf-text-gold text-xl mr-3"></i>
<div class="flex-1"> <div class="flex-1">
<div class="text-900 font-medium">Relancer #{dashboardBean.cotisationsRetard} cotisations</div> <div class="text-900 font-medium">Relancer #{dashboardBean.cotisationsRetard} cotisations</div>
<small class="text-600">Paiements en retard</small> <small class="text-600">Paiements en retard</small>
@@ -501,8 +501,8 @@
<!-- Traiter aides : RESPONSABLE_SOCIAL, ADMIN --> <!-- Traiter aides : RESPONSABLE_SOCIAL, ADMIN -->
<ui:fragment rendered="#{menuBean.isResponsableSocial() or menuBean.isAdminOrganisation() or menuBean.isSuperAdmin()}"> <ui:fragment rendered="#{menuBean.isResponsableSocial() or menuBean.isAdminOrganisation() or menuBean.isSuperAdmin()}">
<div class="flex align-items-center p-3 border-round bg-green-50 border-green-200"> <div class="flex align-items-center p-3 border-round uf-bg-forest-light border-1 uf-border-forest">
<i class="pi pi-heart text-green-500 text-xl mr-3"></i> <i class="pi pi-heart uf-text-forest text-xl mr-3"></i>
<div class="flex-1"> <div class="flex-1">
<div class="text-900 font-medium">Traiter #{dashboardBean.aidesEnAttente} aides</div> <div class="text-900 font-medium">Traiter #{dashboardBean.aidesEnAttente} aides</div>
<small class="text-600">Demandes d'aide à examiner</small> <small class="text-600">Demandes d'aide à examiner</small>
@@ -561,20 +561,20 @@
<h:panelGroup id="financialSummary" layout="block" styleClass="grid"> <h:panelGroup id="financialSummary" layout="block" styleClass="grid">
<div class="col-12 md:col-3"> <div class="col-12 md:col-3">
<div class="text-center p-3 border-round bg-green-50"> <div class="text-center p-3 border-round uf-bg-forest-light">
<div class="text-green-600 font-medium text-xl">#{dashboardBean.recettesMois} FCFA</div> <div class="uf-text-forest font-medium text-xl">#{dashboardBean.recettesMois} FCFA</div>
<div class="text-500">Recettes totales</div> <div class="text-500">Recettes totales</div>
</div> </div>
</div> </div>
<div class="col-12 md:col-3"> <div class="col-12 md:col-3">
<div class="text-center p-3 border-round bg-red-50"> <div class="text-center p-3 border-round uf-bg-crimson-light">
<div class="text-red-600 font-medium text-xl">#{dashboardBean.depensesMois} FCFA</div> <div class="uf-text-crimson font-medium text-xl">#{dashboardBean.depensesMois} FCFA</div>
<div class="text-500">Dépenses totales</div> <div class="text-500">Dépenses totales</div>
</div> </div>
</div> </div>
<div class="col-12 md:col-3"> <div class="col-12 md:col-3">
<div class="text-center p-3 border-round bg-blue-50"> <div class="text-center p-3 border-round uf-bg-navy-light">
<div class="text-blue-600 font-medium text-xl">#{dashboardBean.soldeMois} FCFA</div> <div class="uf-text-navy font-medium text-xl">#{dashboardBean.soldeMois} FCFA</div>
<div class="text-500">Solde net</div> <div class="text-500">Solde net</div>
</div> </div>
</div> </div>

View File

@@ -53,7 +53,7 @@
<ui:param name="title" value="Membres Actifs" /> <ui:param name="title" value="Membres Actifs" />
<ui:param name="value" value="#{superAdminBean.totalMembres}" /> <ui:param name="value" value="#{superAdminBean.totalMembres}" />
<ui:param name="icon" value="pi-users" /> <ui:param name="icon" value="pi-users" />
<ui:param name="iconColor" value="blue-600" /> <ui:param name="iconColor" value="uf-text-navy" />
<ui:param name="growthValue" value="#{superAdminBean.croissanceMembres}" /> <ui:param name="growthValue" value="#{superAdminBean.croissanceMembres}" />
<ui:param name="growthLabel" value="ce mois" /> <ui:param name="growthLabel" value="ce mois" />
<ui:param name="progressValue" value="#{superAdminBean.pourcentageMembres}" /> <ui:param name="progressValue" value="#{superAdminBean.pourcentageMembres}" />
@@ -63,7 +63,7 @@
<ui:param name="title" value="Organisations" /> <ui:param name="title" value="Organisations" />
<ui:param name="value" value="#{superAdminBean.totalEntites}" /> <ui:param name="value" value="#{superAdminBean.totalEntites}" />
<ui:param name="icon" value="pi-sitemap" /> <ui:param name="icon" value="pi-sitemap" />
<ui:param name="iconColor" value="green-600" /> <ui:param name="iconColor" value="uf-text-forest" />
<ui:param name="growthValue" value="#{superAdminBean.nouvellesEntites}" /> <ui:param name="growthValue" value="#{superAdminBean.nouvellesEntites}" />
<ui:param name="growthLabel" value="nouvelles" /> <ui:param name="growthLabel" value="nouvelles" />
<ui:param name="growthType" value="number" /> <ui:param name="growthType" value="number" />
@@ -75,7 +75,7 @@
<ui:param name="title" value="Revenus (FCFA)" /> <ui:param name="title" value="Revenus (FCFA)" />
<ui:param name="value" value="#{superAdminBean.revenusGlobaux}" /> <ui:param name="value" value="#{superAdminBean.revenusGlobaux}" />
<ui:param name="icon" value="pi-dollar" /> <ui:param name="icon" value="pi-dollar" />
<ui:param name="iconColor" value="purple-600" /> <ui:param name="iconColor" value="uf-text-gold" />
<ui:param name="growthValue" value="#{superAdminBean.croissanceRevenus}" /> <ui:param name="growthValue" value="#{superAdminBean.croissanceRevenus}" />
<ui:param name="growthLabel" value="vs mois dernier" /> <ui:param name="growthLabel" value="vs mois dernier" />
<ui:param name="progressValue" value="#{superAdminBean.pourcentageRevenus}" /> <ui:param name="progressValue" value="#{superAdminBean.pourcentageRevenus}" />
@@ -85,7 +85,7 @@
<ui:param name="title" value="Activité du Jour" /> <ui:param name="title" value="Activité du Jour" />
<ui:param name="value" value="#{superAdminBean.activiteJournaliere}" /> <ui:param name="value" value="#{superAdminBean.activiteJournaliere}" />
<ui:param name="icon" value="pi-chart-line" /> <ui:param name="icon" value="pi-chart-line" />
<ui:param name="iconColor" value="orange-600" /> <ui:param name="iconColor" value="uf-text-navy" />
<ui:param name="statusIcon" value="pi-check-circle" /> <ui:param name="statusIcon" value="pi-check-circle" />
<ui:param name="statusLabel" value="En ligne" /> <ui:param name="statusLabel" value="En ligne" />
<ui:param name="statusValue" value="#{superAdminBean.utilisateursActifs} actifs" /> <ui:param name="statusValue" value="#{superAdminBean.utilisateursActifs} actifs" />
@@ -165,16 +165,16 @@
<div class="card"> <div class="card">
<div class="flex align-items-center justify-content-between mb-3"> <div class="flex align-items-center justify-content-between mb-3">
<h5 class="m-0"> <h5 class="m-0">
<i class="pi pi-exclamation-triangle text-orange-500 mr-2"></i> <i class="pi pi-exclamation-triangle uf-text-crimson mr-2"></i>
Alertes Système Alertes Système
</h5> </h5>
<p:tag value="#{superAdminBean.alertesCount} alertes" severity="warning" styleClass="text-xs" /> <p:tag value="#{superAdminBean.alertesCount} alertes" severity="warning" styleClass="text-xs" />
</div> </div>
<ui:repeat value="#{superAdminBean.alertesRecentes}" var="alerte" varStatus="status"> <ui:repeat value="#{superAdminBean.alertesRecentes}" var="alerte" varStatus="status">
<div class="flex align-items-center p-3 mb-2 border-round border-left-3 border-orange-400" <div class="uf-alert-card flex align-items-center p-3 mb-2 border-round uf-border-left-crimson"
style="background: var(--surface-50);"> style="background: var(--surface-50); border-left-width: 4px; border-left-style: solid;">
<i class="pi #{alerte.icone} text-orange-500 text-xl mr-3"></i> <i class="pi #{alerte.icone} uf-text-crimson text-xl mr-3"></i>
<div class="flex-1"> <div class="flex-1">
<div class="font-medium text-900">#{alerte.titre}</div> <div class="font-medium text-900">#{alerte.titre}</div>
<small class="text-500">#{alerte.entite} • #{alerte.date}</small> <small class="text-500">#{alerte.entite} • #{alerte.date}</small>
@@ -283,9 +283,9 @@
</div> </div>
<ui:repeat value="#{superAdminBean.activitesRecentes}" var="activite" varStatus="status"> <ui:repeat value="#{superAdminBean.activitesRecentes}" var="activite" varStatus="status">
<div class="flex align-items-start p-3 mb-2 border-round border-left-3 border-blue-300" <div class="flex align-items-start p-3 mb-2 border-round uf-border-left-navy"
style="background: var(--surface-50);"> style="background: var(--surface-50); border-left-width: 4px; border-left-style: solid;">
<i class="pi pi-history text-blue-500 text-xl mr-3 mt-1"></i> <i class="pi pi-history uf-text-navy text-xl mr-3 mt-1"></i>
<div class="flex-1"> <div class="flex-1">
<div class="font-medium text-900 mb-1">#{activite.description}</div> <div class="font-medium text-900 mb-1">#{activite.description}</div>
<div class="text-600 text-sm">#{activite.entite}</div> <div class="text-600 text-sm">#{activite.entite}</div>
@@ -326,26 +326,26 @@
</div> </div>
<div class="grid"> <div class="grid">
<div class="col-12 md:col-3"> <div class="col-12 md:col-3">
<div class="text-center p-3 border-round bg-green-50"> <div class="text-center p-3 border-round uf-bg-forest-light">
<div class="text-green-600 font-medium text-xl">#{superAdminBean.revenus.mensuel}</div> <div class="uf-text-forest font-medium text-xl">#{superAdminBean.revenus.mensuel}</div>
<div class="text-500">Revenus ce mois</div> <div class="text-500">Revenus ce mois</div>
</div> </div>
</div> </div>
<div class="col-12 md:col-3"> <div class="col-12 md:col-3">
<div class="text-center p-3 border-round bg-blue-50"> <div class="text-center p-3 border-round uf-bg-navy-light">
<div class="text-blue-600 font-medium text-xl">#{superAdminBean.revenus.annuel}</div> <div class="uf-text-navy font-medium text-xl">#{superAdminBean.revenus.annuel}</div>
<div class="text-500">Revenus annuels</div> <div class="text-500">Revenus annuels</div>
</div> </div>
</div> </div>
<div class="col-12 md:col-3"> <div class="col-12 md:col-3">
<div class="text-center p-3 border-round bg-purple-50"> <div class="text-center p-3 border-round uf-bg-gold-light">
<div class="text-purple-600 font-medium text-xl">#{superAdminBean.revenus.croissance}%</div> <div class="uf-text-gold font-medium text-xl">#{superAdminBean.revenus.croissance}%</div>
<div class="text-500">Croissance annuelle</div> <div class="text-500">Croissance annuelle</div>
</div> </div>
</div> </div>
<div class="col-12 md:col-3"> <div class="col-12 md:col-3">
<div class="text-center p-3 border-round bg-orange-50"> <div class="text-center p-3 border-round uf-bg-crimson-light">
<div class="text-orange-600 font-medium text-xl">#{superAdminBean.revenus.moyenne}</div> <div class="uf-text-crimson font-medium text-xl">#{superAdminBean.revenus.moyenne}</div>
<div class="text-500">Revenu moyen / entité</div> <div class="text-500">Revenu moyen / entité</div>
</div> </div>
</div> </div>

View File

@@ -0,0 +1,110 @@
/* ==========================================================================
UnionFlow Premium Dashboard Design System (Banking / Governance aesthetic)
========================================================================== */
/* 1. Custom Color Tokens (Overrides for PrimeFlex) */
/* Primary Blue (Bleu Tech/Moderne) */
.uf-text-navy { color: var(--primary-color, #4F46E5) !important; }
.uf-bg-navy { background-color: var(--primary-color, #4F46E5) !important; }
.uf-bg-navy-light { background-color: rgba(79, 70, 229, 0.08) !important; }
.uf-border-navy { border-color: var(--primary-color, #4F46E5) !important; }
.uf-border-left-navy { border-left-color: var(--primary-color, #4F46E5) !important; }
/* Forest Green (Vert Forêt) */
.uf-text-forest { color: #126A54 !important; }
.uf-bg-forest { background-color: #126A54 !important; }
.uf-bg-forest-light { background-color: rgba(18, 106, 84, 0.08) !important; }
.uf-border-forest { border-color: #126A54 !important; }
.uf-border-left-forest { border-left-color: #126A54 !important; }
/* Premium Gold (Or) */
.uf-text-gold { color: #E6C57A !important; }
.uf-bg-gold { background-color: #E6C57A !important; }
.uf-bg-gold-light { background-color: rgba(230, 197, 122, 0.15) !important; }
.uf-border-gold { border-color: #E6C57A !important; }
.uf-border-left-gold { border-left-color: #E6C57A !important; }
/* Critical Premium Red (Deep Burgundy/Carmine instead of bright aggressive red) */
.uf-text-crimson { color: #C92A2A !important; }
.uf-bg-crimson { background-color: #C92A2A !important; }
.uf-bg-crimson-light { background-color: rgba(201, 42, 42, 0.06) !important; }
.uf-border-crimson { border-color: #C92A2A !important; }
.uf-border-left-crimson { border-left-color: #C92A2A !important; }
/* Neutral Premium (Deep Gray) */
.uf-text-neutral { color: #334155 !important; }
.uf-bg-neutral-light { background-color: #F8FAFC !important; }
/* 2. Premium Card Styles (Glassmorphism & Shadows) */
/* Modernizing the default cards */
.layout-content .card {
border-radius: 16px;
border: 1px solid rgba(79, 70, 229, 0.08); /* Primary color low opacity */
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.02);
background: #FFFFFF;
transition: box-shadow 0.3s ease;
}
.layout-content .card:hover {
box-shadow: 0 6px 24px rgba(79, 70, 229, 0.1);
}
/* KPI Overview Cards (Elevated, Interactive) */
.uf-kpi-card {
border-radius: 12px;
border: 1px solid rgba(0,0,0,0.03) !important;
background: #FFFFFF !important;
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275), box-shadow 0.3s ease !important;
}
.uf-kpi-card:hover {
transform: translateY(-5px) !important;
box-shadow: 0 15px 35px rgba(79, 70, 229, 0.15) !important;
}
/* Alert/Action Cards (With left border) */
.uf-alert-card {
border-radius: 10px;
border: 1px solid rgba(0,0,0,0.02);
background: #FFFFFF;
transition: all 0.25s ease;
}
.uf-alert-card:hover {
transform: translateX(4px);
box-shadow: 0 8px 20px rgba(0,0,0,0.05);
}
/* Icon Containers in Cards */
.uf-icon-box {
width: 3rem;
height: 3rem;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
/* 3. Specialized Elements */
/* Activity Timeline/DataTables in Dashboard */
.ui-datatable .ui-datatable-header {
background: transparent !important;
border-bottom: 2px solid rgba(79, 70, 229, 0.1) !important;
border-top: none !important;
border-left: none !important;
border-right: none !important;
color: var(--primary-color, #4F46E5) !important;
}
.ui-tag.ui-tag-success { background: #126A54; }
.ui-tag.ui-tag-warning { background: #E6C57A; color: var(--primary-color, #4F46E5); }
.ui-tag.ui-tag-info { background: var(--primary-color, #4F46E5); }
.ui-tag.ui-tag-danger { background: #C92A2A; }
/* Progress bars */
.bg-gray-200 { background-color: #EDF2F7 !important; }

View File

@@ -913,3 +913,554 @@
color: var(--primary-color, #6366f1); color: var(--primary-color, #6366f1);
font-size: 0.875rem; font-size: 0.875rem;
} }
/* ═══════════════════════════════════════════════════════════════════ */
/* UNIONFLOW BRAND IDENTITY — EXHAUSTIVE DARK/LIGHT MODE SUPPORT */
/* Charte: #0B304A (Bleu Nuit), #126A54 (Vert Forêt), */
/* #E6C57A (Or Premium), #F4F6F8 (Fond), #E8EAEC */
/* */
/* Freya theme axes: */
/* 1. topbarTheme → .layout-topbar-light | .layout-topbar-dark */
/* 2. menuTheme → .layout-menu-light | .layout-menu-dark */
/* 3. darkMode → layout-light.css | layout-dark.css */
/* 4. menuMode → .layout-sidebar | .layout-static */
/* .layout-horizontal | .layout-slim */
/* ═══════════════════════════════════════════════════════════════════ */
/* ──────────────────────────────────────────────────
1. BASE — Brand Composition (Logo + Text)
Now uses .unionflow-topbar-brand (outside of
.layout-topbar-logo to avoid Freya display:none)
────────────────────────────────────────────────── */
.unionflow-topbar-brand,
.unionflow-brand {
display: flex !important;
align-items: center;
gap: 0.625rem;
text-decoration: none !important;
height: auto !important;
}
.unionflow-brand-icon {
width: 36px;
height: 36px;
object-fit: contain;
flex-shrink: 0;
border-radius: 4px;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.unionflow-topbar-brand:hover .unionflow-brand-icon,
.unionflow-brand:hover .unionflow-brand-icon {
transform: scale(1.05) rotate(-2deg);
}
.unionflow-brand-text {
display: flex;
flex-direction: column;
line-height: 1;
gap: 0.1875rem;
}
.unionflow-brand-name {
font-size: 1.125rem;
font-weight: 800;
letter-spacing: 0.15em;
text-transform: uppercase;
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
transition: color 0.2s ease;
}
.unionflow-brand-slogan {
font-size: 0.5625rem;
font-weight: 600;
letter-spacing: 0.12em;
text-transform: uppercase;
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
transition: color 0.2s ease;
}
/* ──────────────────────────────────────────────────
2. TOPBAR — Dark mode (default: gradient/dark bg)
Classes: .layout-topbar-dark, .unionflow-elite
────────────────────────────────────────────────── */
.layout-topbar-dark .unionflow-brand-name,
.unionflow-elite .unionflow-brand-name {
color: #FFFFFF;
}
.layout-topbar-dark .unionflow-brand-slogan,
.unionflow-elite .unionflow-brand-slogan {
color: rgba(230, 197, 122, 0.9); /* Or Premium #E6C57A */
}
/* ──────────────────────────────────────────────────
3. TOPBAR — Light mode (white bg)
Class: .layout-topbar-light
────────────────────────────────────────────────── */
.layout-topbar-light .unionflow-brand-name {
color: #0B304A; /* Bleu Nuit */
}
.layout-topbar-light .unionflow-brand-slogan {
color: #126A54; /* Vert Forêt */
}
/* ──────────────────────────────────────────────────
4. SIDEBAR BRAND — Single source of branding
Collapsed (62px): icon only
Expanded (230px): icon + UNIONFLOW + slogan + v1.0
────────────────────────────────────────────────── */
/* --- Logo link container --- */
.sidebar-logo-link {
display: flex;
align-items: center;
gap: 0.5rem;
text-decoration: none !important;
overflow: hidden;
flex: 1;
min-width: 0;
}
.sidebar-logo-link:hover .unionflow-sidebar-icon {
transform: scale(1.08);
}
/* --- Icon (always visible — 24px for visual parity with menu icons) --- */
.unionflow-sidebar-icon {
width: 24px !important;
height: 24px !important;
object-fit: contain;
border-radius: 3px;
border: 0 none !important;
flex-shrink: 0;
transition: all 0.2s ease;
}
/* Override Freya's .menu-wrapper .sidebar-logo img { width:17px; height:20px } */
.menu-wrapper .sidebar-logo .unionflow-sidebar-icon {
width: 24px !important;
height: 24px !important;
}
/* --- Text block (hidden when collapsed) --- */
.unionflow-sidebar-text {
display: flex;
flex-direction: column;
line-height: 1;
gap: 0.125rem;
white-space: nowrap;
overflow: hidden;
visibility: hidden;
opacity: 0;
width: 0;
transition: opacity 0.2s ease, visibility 0.2s ease;
}
.unionflow-sidebar-name {
font-size: 0.9375rem;
font-weight: 800;
letter-spacing: 0.15em;
text-transform: uppercase;
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
}
.unionflow-sidebar-slogan {
font-size: 0.5rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
opacity: 0.7;
}
/* --- Version badge (hidden when collapsed) --- */
.unionflow-sidebar-version {
display: inline-flex;
align-items: center;
padding: 0;
border-radius: 8px;
font-size: 0.625rem;
font-weight: 600;
white-space: nowrap;
visibility: hidden;
opacity: 0;
width: 0;
overflow: hidden;
transition: opacity 0.2s ease, visibility 0.2s ease;
}
/* ──────────────────────────────────────────────────
4b. SIDEBAR EXPANDED — Show full brand
Triggered by: layout-static, layout-sidebar-active (hover)
────────────────────────────────────────────────── */
@media (min-width: 992px) {
/* Expanded: icon grows slightly */
.layout-wrapper.layout-static .menu-wrapper .sidebar-logo .unionflow-sidebar-icon,
.menu-wrapper.layout-sidebar-active .sidebar-logo .unionflow-sidebar-icon {
width: 30px !important;
height: 30px !important;
}
/* Expanded: show text */
.layout-wrapper.layout-static .menu-wrapper .sidebar-logo .unionflow-sidebar-text,
.menu-wrapper.layout-sidebar-active .sidebar-logo .unionflow-sidebar-text {
visibility: visible;
opacity: 1;
width: auto;
}
/* Expanded: show version badge */
.layout-wrapper.layout-static .menu-wrapper .sidebar-logo .unionflow-sidebar-version,
.menu-wrapper.layout-sidebar-active .sidebar-logo .unionflow-sidebar-version {
visibility: visible;
opacity: 1;
width: auto;
padding: 0.125rem 0.4rem;
}
}
/* ──────────────────────────────────────────────────
5. SIDEBAR — Menu Dark theme
Class: .layout-menu-dark (menu bg = #293241)
────────────────────────────────────────────────── */
.layout-menu-dark .unionflow-sidebar-name {
color: #FFFFFF;
}
.layout-menu-dark .unionflow-sidebar-slogan {
color: rgba(230, 197, 122, 0.85); /* Or Premium */
}
.layout-menu-dark .unionflow-sidebar-version {
background: rgba(255, 255, 255, 0.15);
color: rgba(255, 255, 255, 0.9);
}
.layout-menu-dark .sidebar-logo-link {
color: #E9E9E9;
}
/* ──────────────────────────────────────────────────
6. SIDEBAR — Menu Light theme
Class: .layout-menu-light (menu bg = white)
────────────────────────────────────────────────── */
.layout-menu-light .unionflow-sidebar-name {
color: #0B304A; /* Bleu Nuit */
}
.layout-menu-light .unionflow-sidebar-slogan {
color: #126A54; /* Vert Forêt */
}
.layout-menu-light .unionflow-sidebar-version {
background: rgba(11, 48, 74, 0.1);
color: #0B304A;
}
.layout-menu-light .sidebar-logo-link {
color: #0B304A;
}
/* ──────────────────────────────────────────────────
9. LANDING PAGE — Variant Premium Unionflow
────────────────────────────────────────────────── */
/* App background */
.landing-body {
background-color: #F4F6F8 !important; /* Très léger gris/bleu pour le fond de page */
}
/* Banner (Hero section) - Deep Blue modern gradient instead of the generic mountain */
.landing-body .landing-banner {
background: linear-gradient(135deg, #0B304A 0%, #154B73 50%, #126A54 100%) !important;
position: relative;
overflow: hidden;
}
/* Add a subtle geometric overlay effect to the banner for depth */
.landing-body .landing-banner::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.03) 0%, transparent 60%);
opacity: 0.8;
pointer-events: none;
animation: rotate-slow 60s linear infinite;
}
@keyframes rotate-slow {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Typography on Banner */
.landing-body .landing-banner .landing-banner-content .title {
color: #FFFFFF !important;
text-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
font-weight: 800 !important;
letter-spacing: -0.02em;
}
.landing-body .landing-banner .landing-banner-content h3 {
color: rgba(255, 255, 255, 0.9) !important;
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
font-weight: 400 !important;
letter-spacing: 0;
}
/* Topbar on Landing */
.landing-body .landing-topbar {
background: rgba(255, 255, 255, 0.95) !important;
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(11, 48, 74, 0.05);
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.03);
}
/* Override Freya's tiny 16px landing logo */
.landing-body .landing-topbar .landing-topbar-left .logo.unionflow-brand--landing {
display: flex !important;
align-items: center !important;
gap: 0.75rem !important;
text-decoration: none !important;
}
.landing-body .landing-topbar .landing-topbar-left .logo.unionflow-brand--landing img.unionflow-brand-icon {
width: 36px !important;
height: 36px !important;
}
.landing-body .landing-topbar .landing-topbar-left .logo.unionflow-brand--landing .unionflow-brand-name {
font-size: 1.35rem !important;
letter-spacing: 0.15em !important;
color: #0B304A !important;
font-weight: 800 !important;
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif !important;
}
.landing-body .landing-topbar .landing-menu > li > a {
color: #0B304A !important;
font-family: 'Inter', 'Segoe UI', Roboto, sans-serif;
text-transform: uppercase;
letter-spacing: 0.05em;
font-size: 0.75rem !important;
transition: color 0.3s ease;
}
.landing-body .landing-topbar .landing-menu > li > a:hover {
color: #E6C57A !important; /* Premium Gold */
}
/* Topbar Secondary Button - Premium Hover */
.landing-body .landing-topbar-right a[href*="dashboard"] {
border: 2px solid #0B304A !important;
color: #0B304A !important;
transition: all 0.3s ease !important;
}
.landing-body .landing-topbar-right a[href*="dashboard"]:hover {
background: transparent !important;
border-color: #E6C57A !important; /* Premium Gold */
color: #E6C57A !important;
box-shadow: 0 4px 15px rgba(230, 197, 122, 0.2);
}
/* Banner CTA Button - Premium Gold */
.landing-body .landing-banner-content a[href*="dashboard"] {
background: linear-gradient(135deg, #E6C57A 0%, #D4AF37 100%) !important;
color: #0B304A !important;
border: none !important;
box-shadow: 0 8px 24px rgba(230, 197, 122, 0.4) !important;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.landing-body .landing-banner-content a[href*="dashboard"]:hover {
transform: translateY(-4px) !important;
box-shadow: 0 12px 30px rgba(230, 197, 122, 0.6) !important;
}
/* Feature Cards - Glassmorphism & Shadows */
.landing-body .landing-features {
background: transparent !important;
}
.landing-body .feature-card {
background: #FFFFFF !important;
border: 1px solid rgba(11, 48, 74, 0.05) !important;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.04) !important;
border-radius: 20px !important;
transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275), box-shadow 0.4s ease !important;
}
.landing-body .feature-card:hover {
transform: translateY(-12px) !important; /* Increased lift */
box-shadow: 0 25px 60px rgba(11, 48, 74, 0.12) !important;
}
.landing-body .feature-card h3 {
color: #0B304A !important;
font-weight: 700 !important;
}
.landing-body .feature-card h5 {
color: rgba(11, 48, 74, 0.7) !important;
}
/* Feature Icon numbers styling */
.landing-body .feature > span {
color: #E6C57A !important; /* Premium Gold */
font-weight: 800 !important;
font-size: 28px !important;
}
/* Sub-section headings */
.landing-body .section-header .title {
color: #0B304A !important;
font-weight: 800 !important;
}
.landing-body .section-header h3 {
color: rgba(11, 48, 74, 0.7) !important;
}
/* Benefit Icons Scale-up */
.landing-body .landing-pricing h3 + p + ul {
margin-top: 1rem !important;
}
.landing-body .landing-pricing .pi {
font-size: 1.5rem !important; /* Bumped from 1.25 to 1.5 for presence */
}
/* Bottom banner trust section */
.landing-body .landing-pricing > div:last-of-type > div {
background: linear-gradient(135deg, #0B304A 0%, #126A54 100%) !important;
border-radius: 24px !important;
box-shadow: 0 15px 40px rgba(11, 48, 74, 0.2) !important;
}
/* Final CTA */
.landing-body .mt-5 > a {
background: #0B304A !important;
color: #FFFFFF !important;
box-shadow: 0 4px 18px rgba(11, 48, 74, 0.3) !important;
}
.landing-body .mt-5 > a:hover {
transform: translateY(-3px) !important;
box-shadow: 0 10px 30px rgba(11, 48, 74, 0.4) !important;
background: #154B73 !important;
}
/* Footer styling */
.landing-body .layout-footer {
border-top: 1px solid rgba(11, 48, 74, 0.05);
}
.landing-body .layout-footer .footer-menutitle {
color: #0B304A !important;
font-weight: 700;
}
.landing-body .layout-footer ul > li,
.landing-body .layout-footer ul > li > a {
color: rgba(11, 48, 74, 0.6) !important;
}
.landing-body .layout-footer ul > li > a:hover {
color: #126A54 !important;
}
@media (max-width: 991px) {
.unionflow-brand--landing .unionflow-brand-icon {
width: 32px;
height: 32px;
}
.unionflow-brand--landing .unionflow-brand-name {
font-size: 1.1rem;
}
}
/* ──────────────────────────────────────────────────
10. EXCEPTION PAGES — 404, Access Denied, Error
────────────────────────────────────────────────── */
.exception-body .exception-topbar .unionflow-brand-icon {
width: 38px;
height: 38px;
}
.exception-body .exception-topbar .unionflow-brand-name {
color: #0B304A;
}
.exception-body .exception-topbar .unionflow-brand-slogan {
color: #126A54;
}
/* ──────────────────────────────────────────────────
11. RESPONSIVE BREAKPOINTS
────────────────────────────────────────────────── */
@media (max-width: 991px) {
/* On tablets: smaller icon, keep text */
.unionflow-brand-icon {
width: 30px;
height: 30px;
}
.unionflow-brand-name {
font-size: 1rem;
}
.unionflow-brand-slogan {
font-size: 0.5rem;
}
}
@media (max-width: 768px) {
/* On small tablets: hide text, only icon */
.unionflow-brand-text {
display: none;
}
.unionflow-brand-icon {
width: 30px;
height: 30px;
}
}
@media (max-width: 576px) {
/* On phones: even smaller icon */
.unionflow-brand-icon {
width: 26px;
height: 26px;
}
.unionflow-brand--landing .unionflow-brand-icon {
width: 32px;
height: 32px;
}
/* Still show name on landing for brand recognition */
.unionflow-brand--landing .unionflow-brand-text {
display: flex;
}
.unionflow-brand--landing .unionflow-brand-name {
font-size: 1.1rem;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -80,14 +80,14 @@
<ui:param name="noDataLabel" value="Données non disponibles" /> <ui:param name="noDataLabel" value="Données non disponibles" />
<div class="field #{colSize}"> <div class="field #{colSize}">
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200"> <div class="card uf-kpi-card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
<div class="p-4" style="min-height: 9rem;"> <div class="p-4" style="min-height: 9rem;">
<!-- Header: Titre et Icône --> <!-- Header: Titre et Icône -->
<div class="flex align-items-center justify-content-between mb-3"> <div class="flex align-items-center justify-content-between mb-3">
<span class="block text-600 font-medium text-sm">#{title}</span> <span class="block text-600 font-medium text-sm">#{title}</span>
<div class="flex align-items-center justify-content-center surface-100 border-round-lg" <div class="flex align-items-center justify-content-center surface-100 border-round-lg"
style="width: 2.5rem; height: 2.5rem;"> style="width: 2.5rem; height: 2.5rem;">
<i class="pi #{icon} text-#{iconColor} text-lg"></i> <i class="pi #{icon} #{iconColor.startsWith('uf-') ? '' : 'text-'}#{iconColor} text-lg"></i>
</div> </div>
</div> </div>

View File

@@ -7,8 +7,15 @@
<div class="menu-wrapper"> <div class="menu-wrapper">
<div class="sidebar-logo"> <div class="sidebar-logo">
<a href="dashboard.xhtml"> <a href="dashboard.xhtml" class="sidebar-logo-link">
<p:graphicImage name="images/logo-freya-single.svg" library="freya-layout" /> <h:graphicImage value="#{request.contextPath}/resources/freya-layout/images/unionflow-logo.png"
alt="UnionFlow"
styleClass="unionflow-sidebar-icon" />
<span class="unionflow-sidebar-text">
<span class="unionflow-sidebar-name">UNIONFLOW</span>
<span class="unionflow-sidebar-slogan">Connecter · Unir · Avancer</span>
</span>
<span class="unionflow-sidebar-version">v1.0</span>
</a> </a>
<a href="#" class="sidebar-pin" title="Toggle Menu"> <a href="#" class="sidebar-pin" title="Toggle Menu">
<span class="pin"></span> <span class="pin"></span>

View File

@@ -21,13 +21,7 @@
<a href="#" class="menu-button"> <a href="#" class="menu-button">
<i class="pi pi-bars"/> <i class="pi pi-bars"/>
</a> </a>
<h:link id="logolink" outcome="/pages/secure/dashboard" styleClass="layout-topbar-logo"> <h:link id="logolink" outcome="/pages/secure/dashboard" styleClass="layout-topbar-logo" style="display:none"/>
<p:graphicImage name="images/#{guestPreferences.lightLogo ? 'logo-freya-white.svg' : 'logo-freya.svg'}"
library="freya-layout"
alt="UnionFlow"
title="Retour au tableau de bord"/>
</h:link>
<span class="app-version">v1.0</span>
</div> </div>
<!-- CENTER - Menu --> <!-- CENTER - Menu -->

View File

@@ -13,7 +13,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<!-- Obsolète : apple-mobile-web-app-capable. Remplacé par mobile-web-app-capable --> <!-- Obsolète : apple-mobile-web-app-capable. Remplacé par mobile-web-app-capable -->
<meta name="mobile-web-app-capable" content="yes" /> <meta name="mobile-web-app-capable" content="yes" />
<link rel="icon" href="#{request.contextPath}/resources/freya-layout/images/favicon.ico" type="image/x-icon"></link> <link rel="icon" href="#{request.contextPath}/resources/freya-layout/images/unionflow-logo.png" type="image/png"></link>
</f:facet> </f:facet>
<title><ui:insert name="title">UnionFlow</ui:insert></title> <title><ui:insert name="title">UnionFlow</ui:insert></title>
<h:outputScript name="js/layout.js" library="freya-layout" /> <h:outputScript name="js/layout.js" library="freya-layout" />
@@ -52,6 +52,8 @@
<h:outputStylesheet name="css/primeflex.min.css" library="freya-layout" /> <h:outputStylesheet name="css/primeflex.min.css" library="freya-layout" />
<h:outputStylesheet name="css/layout-#{guestPreferences.layout}.css" library="freya-layout" /> <h:outputStylesheet name="css/layout-#{guestPreferences.layout}.css" library="freya-layout" />
<h:outputStylesheet name="primefaces-freya-#{guestPreferences.componentTheme}/theme.css" /> <h:outputStylesheet name="primefaces-freya-#{guestPreferences.componentTheme}/theme.css" />
<h:outputStylesheet name="css/topbar-elite.css" />
<h:outputStylesheet name="css/dashboard-premium.css" />
</h:body> </h:body>
</html> </html>

View File

@@ -12,7 +12,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
<!-- Obsolète : apple-mobile-web-app-capable. Remplacé par mobile-web-app-capable --> <!-- Obsolète : apple-mobile-web-app-capable. Remplacé par mobile-web-app-capable -->
<meta name="mobile-web-app-capable" content="yes"/> <meta name="mobile-web-app-capable" content="yes"/>
<link rel="icon" type="image/x-icon" href="#{resource['images/favicon.ico']}"/> <link rel="icon" type="image/png" href="#{resource['freya-layout:images/unionflow-logo.png']}"/>
</f:facet> </f:facet>
<title> <title>