Refactoring - Version OK

This commit is contained in:
dahoud
2025-11-17 16:00:58 +00:00
parent 40fdbedcad
commit 3f00a26308
64 changed files with 3317 additions and 2393 deletions

View File

@@ -82,11 +82,19 @@
<artifactId>quarkus-rest-client-jackson</artifactId> <artifactId>quarkus-rest-client-jackson</artifactId>
</dependency> </dependency>
<!-- Sécurité JWT --> <!-- Sécurité JWT et OIDC (Keycloak) -->
<dependency> <dependency>
<groupId>io.quarkus</groupId> <groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-jwt</artifactId> <artifactId>quarkus-smallrye-jwt</artifactId>
</dependency> </dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client</artifactId>
</dependency>
<!-- Configuration --> <!-- Configuration -->
<dependency> <dependency>

View File

@@ -7,6 +7,7 @@ import jakarta.faces.convert.Converter;
import jakarta.faces.convert.FacesConverter; import jakarta.faces.convert.FacesConverter;
import jakarta.inject.Named; import jakarta.inject.Named;
import dev.lions.unionflow.client.view.DemandesBean.Membre; import dev.lions.unionflow.client.view.DemandesBean.Membre;
import java.util.UUID;
@Named @Named
@ApplicationScoped @ApplicationScoped
@@ -20,15 +21,15 @@ public class MembreConverter implements Converter<Membre> {
} }
try { try {
// Parse the membre ID from the string value // Parse the membre ID from the string value (UUID)
Long membreId = Long.valueOf(value); UUID membreId = UUID.fromString(value);
// Create a simple Membre object with just the ID // Create a simple Membre object with just the ID
// In a real implementation, you would fetch from database // In a real implementation, you would fetch from database
Membre membre = new Membre(); Membre membre = new Membre();
membre.setId(membreId); membre.setId(membreId);
return membre; return membre;
} catch (NumberFormatException e) { } catch (IllegalArgumentException e) {
return null; return null;
} }
} }

View File

@@ -6,12 +6,13 @@ import jakarta.validation.constraints.NotNull;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.io.Serializable; import java.io.Serializable;
import java.util.UUID;
public class AssociationDTO implements Serializable { public class AssociationDTO implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private Long id; private UUID id;
@NotBlank(message = "Le nom de l'association est obligatoire") @NotBlank(message = "Le nom de l'association est obligatoire")
private String nom; private String nom;
@@ -54,8 +55,8 @@ public class AssociationDTO implements Serializable {
} }
// Getters et Setters // Getters et Setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }

View File

@@ -0,0 +1,91 @@
package dev.lions.unionflow.client.dto;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
public class CotisationDTO implements Serializable {
private static final long serialVersionUID = 1L;
private UUID id;
private String numeroReference;
private UUID membreId;
private String numeroMembre;
private String nomMembre;
private UUID associationId;
private String nomAssociation;
private String typeCotisation;
private String libelle;
private String description;
private BigDecimal montantDu;
private BigDecimal montantPaye;
private String codeDevise;
private String statut;
private LocalDate dateEcheance;
private LocalDateTime datePaiement;
private String methodePaiement;
private String observations;
private LocalDateTime dateCreation;
// Getters et Setters
public UUID getId() { return id; }
public void setId(UUID id) { this.id = id; }
public String getNumeroReference() { return numeroReference; }
public void setNumeroReference(String numeroReference) { this.numeroReference = numeroReference; }
public UUID getMembreId() { return membreId; }
public void setMembreId(UUID membreId) { this.membreId = membreId; }
public String getNumeroMembre() { return numeroMembre; }
public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; }
public String getNomMembre() { return nomMembre; }
public void setNomMembre(String nomMembre) { this.nomMembre = nomMembre; }
public UUID getAssociationId() { return associationId; }
public void setAssociationId(UUID associationId) { this.associationId = associationId; }
public String getNomAssociation() { return nomAssociation; }
public void setNomAssociation(String nomAssociation) { this.nomAssociation = nomAssociation; }
public String getTypeCotisation() { return typeCotisation; }
public void setTypeCotisation(String typeCotisation) { this.typeCotisation = typeCotisation; }
public String getLibelle() { return libelle; }
public void setLibelle(String libelle) { this.libelle = libelle; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public BigDecimal getMontantDu() { return montantDu; }
public void setMontantDu(BigDecimal montantDu) { this.montantDu = montantDu; }
public BigDecimal getMontantPaye() { return montantPaye; }
public void setMontantPaye(BigDecimal montantPaye) { this.montantPaye = montantPaye; }
public String getCodeDevise() { return codeDevise; }
public void setCodeDevise(String codeDevise) { this.codeDevise = codeDevise; }
public String getStatut() { return statut; }
public void setStatut(String statut) { this.statut = statut; }
public LocalDate getDateEcheance() { return dateEcheance; }
public void setDateEcheance(LocalDate dateEcheance) { this.dateEcheance = dateEcheance; }
public LocalDateTime getDatePaiement() { return datePaiement; }
public void setDatePaiement(LocalDateTime datePaiement) { this.datePaiement = datePaiement; }
public String getMethodePaiement() { return methodePaiement; }
public void setMethodePaiement(String methodePaiement) { this.methodePaiement = methodePaiement; }
public String getObservations() { return observations; }
public void setObservations(String observations) { this.observations = observations; }
public LocalDateTime getDateCreation() { return dateCreation; }
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
}

View File

@@ -0,0 +1,99 @@
package dev.lions.unionflow.client.dto;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.UUID;
public class DemandeAideDTO implements Serializable {
private static final long serialVersionUID = 1L;
private UUID id;
private String numeroReference;
private String type;
private String titre;
private String description;
private String justification;
private BigDecimal montantDemande;
private BigDecimal montantAccorde;
private String statut;
private String urgence;
private String localisation;
private String motif;
private UUID demandeurId;
private String demandeur;
private String telephone;
private String email;
private LocalDate dateDemande;
private LocalDate dateLimite;
private String responsableTraitement;
private UUID organisationId;
private LocalDateTime dateCreation;
// Getters et Setters
public UUID getId() { return id; }
public void setId(UUID id) { this.id = id; }
public String getNumeroReference() { return numeroReference; }
public void setNumeroReference(String numeroReference) { this.numeroReference = numeroReference; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getTitre() { return titre; }
public void setTitre(String titre) { this.titre = titre; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getJustification() { return justification; }
public void setJustification(String justification) { this.justification = justification; }
public BigDecimal getMontantDemande() { return montantDemande; }
public void setMontantDemande(BigDecimal montantDemande) { this.montantDemande = montantDemande; }
public BigDecimal getMontantAccorde() { return montantAccorde; }
public void setMontantAccorde(BigDecimal montantAccorde) { this.montantAccorde = montantAccorde; }
public String getStatut() { return statut; }
public void setStatut(String statut) { this.statut = statut; }
public String getUrgence() { return urgence; }
public void setUrgence(String urgence) { this.urgence = urgence; }
public String getLocalisation() { return localisation; }
public void setLocalisation(String localisation) { this.localisation = localisation; }
public String getMotif() { return motif; }
public void setMotif(String motif) { this.motif = motif; }
public UUID getDemandeurId() { return demandeurId; }
public void setDemandeurId(UUID demandeurId) { this.demandeurId = demandeurId; }
public String getDemandeur() { return demandeur; }
public void setDemandeur(String demandeur) { this.demandeur = demandeur; }
public String getTelephone() { return telephone; }
public void setTelephone(String telephone) { this.telephone = telephone; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public LocalDate getDateDemande() { return dateDemande; }
public void setDateDemande(LocalDate dateDemande) { this.dateDemande = dateDemande; }
public LocalDate getDateLimite() { return dateLimite; }
public void setDateLimite(LocalDate dateLimite) { this.dateLimite = dateLimite; }
public String getResponsableTraitement() { return responsableTraitement; }
public void setResponsableTraitement(String responsableTraitement) { this.responsableTraitement = responsableTraitement; }
public UUID getOrganisationId() { return organisationId; }
public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
public LocalDateTime getDateCreation() { return dateCreation; }
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
}

View File

@@ -0,0 +1,92 @@
package dev.lions.unionflow.client.dto;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.UUID;
public class EvenementDTO implements Serializable {
private static final long serialVersionUID = 1L;
private UUID id;
private String titre;
private String description;
private String type;
private String statut;
private String priorite;
private LocalDate dateDebut;
private LocalDate dateFin;
private LocalTime heureDebut;
private LocalTime heureFin;
private String lieu;
private String adresse;
private String organisateur;
private String organisateurEmail;
private Integer capaciteMax;
private Integer participantsInscrits;
private BigDecimal budget;
private UUID organisationId;
private LocalDateTime dateCreation;
// Getters et Setters
public UUID getId() { return id; }
public void setId(UUID id) { this.id = id; }
public String getTitre() { return titre; }
public void setTitre(String titre) { this.titre = titre; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getStatut() { return statut; }
public void setStatut(String statut) { this.statut = statut; }
public String getPriorite() { return priorite; }
public void setPriorite(String priorite) { this.priorite = priorite; }
public LocalDate getDateDebut() { return dateDebut; }
public void setDateDebut(LocalDate dateDebut) { this.dateDebut = dateDebut; }
public LocalDate getDateFin() { return dateFin; }
public void setDateFin(LocalDate dateFin) { this.dateFin = dateFin; }
public LocalTime getHeureDebut() { return heureDebut; }
public void setHeureDebut(LocalTime heureDebut) { this.heureDebut = heureDebut; }
public LocalTime getHeureFin() { return heureFin; }
public void setHeureFin(LocalTime heureFin) { this.heureFin = heureFin; }
public String getLieu() { return lieu; }
public void setLieu(String lieu) { this.lieu = lieu; }
public String getAdresse() { return adresse; }
public void setAdresse(String adresse) { this.adresse = adresse; }
public String getOrganisateur() { return organisateur; }
public void setOrganisateur(String organisateur) { this.organisateur = organisateur; }
public String getOrganisateurEmail() { return organisateurEmail; }
public void setOrganisateurEmail(String organisateurEmail) { this.organisateurEmail = organisateurEmail; }
public Integer getCapaciteMax() { return capaciteMax; }
public void setCapaciteMax(Integer capaciteMax) { this.capaciteMax = capaciteMax; }
public Integer getParticipantsInscrits() { return participantsInscrits; }
public void setParticipantsInscrits(Integer participantsInscrits) { this.participantsInscrits = participantsInscrits; }
public BigDecimal getBudget() { return budget; }
public void setBudget(BigDecimal budget) { this.budget = budget; }
public UUID getOrganisationId() { return organisationId; }
public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
public LocalDateTime getDateCreation() { return dateCreation; }
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
}

View File

@@ -5,12 +5,13 @@ import jakarta.validation.constraints.Positive;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.UUID;
public class FormulaireDTO implements Serializable { public class FormulaireDTO implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private Long id; private UUID id;
@NotNull @NotNull
private String nom; private String nom;
@@ -60,8 +61,8 @@ public class FormulaireDTO implements Serializable {
public FormulaireDTO() {} public FormulaireDTO() {}
// Getters et Setters // Getters et Setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }
@@ -171,7 +172,7 @@ public class FormulaireDTO implements Serializable {
BigDecimal economie = getEconomieAnnuelle(); BigDecimal economie = getEconomieAnnuelle();
if (coutMensuelAnnuel.compareTo(BigDecimal.ZERO) > 0) { if (coutMensuelAnnuel.compareTo(BigDecimal.ZERO) > 0) {
return economie.multiply(BigDecimal.valueOf(100)) return economie.multiply(BigDecimal.valueOf(100))
.divide(coutMensuelAnnuel, 0, BigDecimal.ROUND_HALF_UP) .divide(coutMensuelAnnuel, 0, java.math.RoundingMode.HALF_UP)
.intValue(); .intValue();
} }
} }

View File

@@ -8,12 +8,13 @@ import jakarta.validation.constraints.*;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.io.Serializable; import java.io.Serializable;
import java.util.UUID;
public class MembreDTO implements Serializable { public class MembreDTO implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private Long id; private UUID id;
@NotBlank(message = "Le numéro de membre est obligatoire", groups = {ValidationGroups.CreateMember.class, ValidationGroups.FullRegistration.class}) @NotBlank(message = "Le numéro de membre est obligatoire", groups = {ValidationGroups.CreateMember.class, ValidationGroups.FullRegistration.class})
@ValidMemberNumber(groups = {ValidationGroups.CreateMember.class, ValidationGroups.UpdateMember.class, ValidationGroups.FullRegistration.class}) @ValidMemberNumber(groups = {ValidationGroups.CreateMember.class, ValidationGroups.UpdateMember.class, ValidationGroups.FullRegistration.class})
@@ -62,7 +63,7 @@ public class MembreDTO implements Serializable {
private String statut; private String statut;
@NotNull(message = "L'association est obligatoire") @NotNull(message = "L'association est obligatoire")
private Long associationId; private UUID associationId;
private String associationNom; private String associationNom;
@@ -88,8 +89,8 @@ public class MembreDTO implements Serializable {
} }
// Getters et Setters // Getters et Setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNumeroMembre() { return numeroMembre; } public String getNumeroMembre() { return numeroMembre; }
public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; } public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; }
@@ -130,8 +131,8 @@ public class MembreDTO implements Serializable {
public String getStatut() { return statut; } public String getStatut() { return statut; }
public void setStatut(String statut) { this.statut = statut; } public void setStatut(String statut) { this.statut = statut; }
public Long getAssociationId() { return associationId; } public UUID getAssociationId() { return associationId; }
public void setAssociationId(Long associationId) { this.associationId = associationId; } public void setAssociationId(UUID associationId) { this.associationId = associationId; }
public String getAssociationNom() { return associationNom; } public String getAssociationNom() { return associationNom; }
public void setAssociationNom(String associationNom) { this.associationNom = associationNom; } public void setAssociationNom(String associationNom) { this.associationNom = associationNom; }

View File

@@ -6,6 +6,7 @@ import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.UUID;
public class SouscriptionDTO implements Serializable { public class SouscriptionDTO implements Serializable {
@@ -46,14 +47,14 @@ public class SouscriptionDTO implements Serializable {
public String getLibelle() { return libelle; } public String getLibelle() { return libelle; }
} }
private Long id; private UUID id;
@NotNull @NotNull
private Long organisationId; private UUID organisationId;
private String organisationNom; private String organisationNom;
@NotNull @NotNull
private Long formulaireId; private UUID formulaireId;
private String formulaireNom; private String formulaireNom;
@NotNull @NotNull
@@ -102,17 +103,17 @@ public class SouscriptionDTO implements Serializable {
public SouscriptionDTO() {} public SouscriptionDTO() {}
// Getters et Setters // Getters et Setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public Long getOrganisationId() { return organisationId; } public UUID getOrganisationId() { return organisationId; }
public void setOrganisationId(Long organisationId) { this.organisationId = organisationId; } public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
public String getOrganisationNom() { return organisationNom; } public String getOrganisationNom() { return organisationNom; }
public void setOrganisationNom(String organisationNom) { this.organisationNom = organisationNom; } public void setOrganisationNom(String organisationNom) { this.organisationNom = organisationNom; }
public Long getFormulaireId() { return formulaireId; } public UUID getFormulaireId() { return formulaireId; }
public void setFormulaireId(Long formulaireId) { this.formulaireId = formulaireId; } public void setFormulaireId(UUID formulaireId) { this.formulaireId = formulaireId; }
public String getFormulaireNom() { return formulaireNom; } public String getFormulaireNom() { return formulaireNom; }
public void setFormulaireNom(String formulaireNom) { this.formulaireNom = formulaireNom; } public void setFormulaireNom(String formulaireNom) { this.formulaireNom = formulaireNom; }

View File

@@ -2,6 +2,7 @@ package dev.lions.unionflow.client.dto.auth;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.UUID;
public class LoginResponse { public class LoginResponse {
@@ -79,7 +80,7 @@ public class LoginResponse {
} }
public static class UserInfo { public static class UserInfo {
private Long id; private UUID id;
private String nom; private String nom;
private String prenom; private String prenom;
private String email; private String email;
@@ -91,11 +92,11 @@ public class LoginResponse {
public UserInfo() {} public UserInfo() {}
public Long getId() { public UUID getId() {
return id; return id;
} }
public void setId(Long id) { public void setId(UUID id) {
this.id = id; this.id = id;
} }
@@ -172,7 +173,7 @@ public class LoginResponse {
} }
public static class EntiteInfo { public static class EntiteInfo {
private Long id; private UUID id;
private String nom; private String nom;
private String type; private String type;
private String pays; private String pays;
@@ -180,11 +181,11 @@ public class LoginResponse {
public EntiteInfo() {} public EntiteInfo() {}
public Long getId() { public UUID getId() {
return id; return id;
} }
public void setId(Long id) { public void setId(UUID id) {
this.id = id; this.id = id;
} }

View File

@@ -1,7 +1,6 @@
package dev.lions.unionflow.client.exception; package dev.lions.unionflow.client.exception;
import jakarta.faces.FacesException; import jakarta.faces.FacesException;
import jakarta.faces.application.NavigationHandler;
import jakarta.faces.application.ViewExpiredException; import jakarta.faces.application.ViewExpiredException;
import jakarta.faces.context.ExceptionHandler; import jakarta.faces.context.ExceptionHandler;
import jakarta.faces.context.ExceptionHandlerWrapper; import jakarta.faces.context.ExceptionHandlerWrapper;
@@ -9,7 +8,6 @@ import jakarta.faces.context.FacesContext;
import jakarta.faces.event.ExceptionQueuedEvent; import jakarta.faces.event.ExceptionQueuedEvent;
import jakarta.faces.event.ExceptionQueuedEventContext; import jakarta.faces.event.ExceptionQueuedEventContext;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -55,9 +53,9 @@ public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {
LOG.log(Level.WARNING, "Impossible de stocker l'URL de redirection: {0}", e.getMessage()); LOG.log(Level.WARNING, "Impossible de stocker l'URL de redirection: {0}", e.getMessage());
} }
// Rediriger vers la page de login avec paramètre expired // Rediriger vers la racine qui déclenchera Keycloak
try { try {
String redirectURL = "/pages/public/login.xhtml?expired=true"; String redirectURL = "/";
facesContext.getExternalContext().redirect( facesContext.getExternalContext().redirect(
facesContext.getExternalContext().getRequestContextPath() + redirectURL facesContext.getExternalContext().getRequestContextPath() + redirectURL
); );
@@ -66,10 +64,10 @@ public class ViewExpiredExceptionHandler extends ExceptionHandlerWrapper {
LOG.log(Level.SEVERE, "Erreur lors de la redirection: {0}", e.getMessage()); LOG.log(Level.SEVERE, "Erreur lors de la redirection: {0}", e.getMessage());
// Fallback: essayer une redirection simple // Fallback: essayer une redirection simple
try { try {
facesContext.getExternalContext().redirect("/pages/public/login.xhtml"); facesContext.getExternalContext().redirect("/");
facesContext.responseComplete(); facesContext.responseComplete();
} catch (Exception fallbackException) { } catch (Exception fallbackException) {
LOG.log(Level.SEVERE, "Impossible de rediriger vers login: {0}", fallbackException.getMessage()); LOG.log(Level.SEVERE, "Impossible de rediriger vers la racine: {0}", fallbackException.getMessage());
} }
} }
} }

View File

@@ -9,6 +9,14 @@ import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException; import java.io.IOException;
import java.util.logging.Logger; import java.util.logging.Logger;
/**
* Filtre d'authentification pour vérifications supplémentaires
* Note: Avec Keycloak OIDC, l'authentification principale est gérée par Quarkus
* Ce filtre peut être utilisé pour des vérifications de permissions supplémentaires
*
* @author UnionFlow Team
* @version 2.0
*/
@WebFilter(urlPatterns = {"/pages/secure/*", "/pages/admin/*", "/pages/super-admin/*", "/pages/membre/*"}) @WebFilter(urlPatterns = {"/pages/secure/*", "/pages/admin/*", "/pages/super-admin/*", "/pages/membre/*"})
public class AuthenticationFilter implements Filter { public class AuthenticationFilter implements Filter {
@@ -17,9 +25,6 @@ public class AuthenticationFilter implements Filter {
@Inject @Inject
private UserSession userSession; private UserSession userSession;
@Inject
private JwtTokenManager tokenManager;
@Override @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException { throws IOException, ServletException {
@@ -29,10 +34,13 @@ public class AuthenticationFilter implements Filter {
String requestURI = httpRequest.getRequestURI(); String requestURI = httpRequest.getRequestURI();
// Vérifier si l'utilisateur est authentifié // Laisser Quarkus OIDC appliquer l'authentification (rediriger vers Keycloak si nécessaire)
// Ici, si l'utilisateur n'est pas encore authentifié, on ne force PAS une redirection custom
// pour éviter les boucles / conflits. On délègue au mécanisme Quarkus défini via
// quarkus.http.auth.permission.* et quarkus.oidc.*
if (!isAuthenticated()) { if (!isAuthenticated()) {
LOGGER.warning("Accès non autorisé à: " + requestURI); LOGGER.fine("Requête non authentifiée sur " + requestURI + ", délégation à Quarkus OIDC.");
httpResponse.sendRedirect(httpRequest.getContextPath() + "/pages/public/login.xhtml"); chain.doFilter(request, response);
return; return;
} }
@@ -50,10 +58,8 @@ public class AuthenticationFilter implements Filter {
} }
private boolean isAuthenticated() { private boolean isAuthenticated() {
return userSession != null && // Avec Keycloak OIDC, UserSession vérifie automatiquement l'authentification via JsonWebToken
userSession.isAuthenticated() && return userSession != null && userSession.isAuthenticated();
tokenManager != null &&
tokenManager.hasValidTokens();
} }
private boolean hasRequiredPermissions(String requestURI) { private boolean hasRequiredPermissions(String requestURI) {

View File

@@ -0,0 +1,50 @@
package dev.lions.unionflow.client.service;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.Map;
@RegisterRestClient(configKey = "unionflow-api")
@Path("/api/v1/analytics")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface AnalyticsService {
@GET
@Path("/dashboard/widgets")
Map<String, Object> getDashboardData(
@QueryParam("organisationId") String organisationId,
@QueryParam("utilisateurId") String utilisateurId
);
@GET
@Path("/tendances/{typeMetrique}")
Map<String, Object> getEvolutionMensuelle(
@PathParam("typeMetrique") String typeMetrique,
@QueryParam("organisationId") String organisationId,
@QueryParam("periode") String periode
);
@GET
@Path("/kpis")
Map<String, Object> getKPIs(
@QueryParam("organisationId") String organisationId,
@QueryParam("periode") String periode
);
@GET
@Path("/evolutions")
Map<String, Object> getEvolutions(
@QueryParam("organisationId") String organisationId,
@QueryParam("periode") String periode
);
@GET
@Path("/performance-globale")
Map<String, Object> getPerformanceGlobale(
@QueryParam("organisationId") String organisationId,
@QueryParam("periode") String periode
);
}

View File

@@ -5,6 +5,7 @@ import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*; import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import java.util.List; import java.util.List;
import java.util.UUID;
@RegisterRestClient(configKey = "unionflow-api") @RegisterRestClient(configKey = "unionflow-api")
@Path("/api/associations") @Path("/api/associations")
@@ -17,7 +18,7 @@ public interface AssociationService {
@GET @GET
@Path("/{id}") @Path("/{id}")
AssociationDTO obtenirParId(@PathParam("id") Long id); AssociationDTO obtenirParId(@PathParam("id") UUID id);
@GET @GET
@Path("/search") @Path("/search")
@@ -48,27 +49,27 @@ public interface AssociationService {
@PUT @PUT
@Path("/{id}") @Path("/{id}")
AssociationDTO modifier(@PathParam("id") Long id, AssociationDTO association); AssociationDTO modifier(@PathParam("id") UUID id, AssociationDTO association);
@DELETE @DELETE
@Path("/{id}") @Path("/{id}")
void supprimer(@PathParam("id") Long id); void supprimer(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/activer") @Path("/{id}/activer")
AssociationDTO activer(@PathParam("id") Long id); AssociationDTO activer(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/desactiver") @Path("/{id}/desactiver")
AssociationDTO desactiver(@PathParam("id") Long id); AssociationDTO desactiver(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/suspendre") @Path("/{id}/suspendre")
AssociationDTO suspendre(@PathParam("id") Long id); AssociationDTO suspendre(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/dissoudre") @Path("/{id}/dissoudre")
AssociationDTO dissoudre(@PathParam("id") Long id); AssociationDTO dissoudre(@PathParam("id") UUID id);
@GET @GET
@Path("/statistiques") @Path("/statistiques")
@@ -76,11 +77,11 @@ public interface AssociationService {
@GET @GET
@Path("/{id}/membres/count") @Path("/{id}/membres/count")
Long compterMembres(@PathParam("id") Long id); Long compterMembres(@PathParam("id") UUID id);
@GET @GET
@Path("/{id}/performance") @Path("/{id}/performance")
PerformanceAssociationDTO obtenirPerformance(@PathParam("id") Long id); PerformanceAssociationDTO obtenirPerformance(@PathParam("id") UUID id);
// Classes DTO internes // Classes DTO internes
class StatistiquesAssociationDTO { class StatistiquesAssociationDTO {
@@ -127,7 +128,7 @@ public interface AssociationService {
} }
class PerformanceAssociationDTO { class PerformanceAssociationDTO {
public Long associationId; public UUID associationId;
public String nom; public String nom;
public Integer scoreGlobal; public Integer scoreGlobal;
public Integer scoreMembres; public Integer scoreMembres;
@@ -140,8 +141,8 @@ public interface AssociationService {
public PerformanceAssociationDTO() {} public PerformanceAssociationDTO() {}
// Getters et setters // Getters et setters
public Long getAssociationId() { return associationId; } public UUID getAssociationId() { return associationId; }
public void setAssociationId(Long associationId) { this.associationId = associationId; } public void setAssociationId(UUID associationId) { this.associationId = associationId; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }

View File

@@ -9,6 +9,7 @@ import jakarta.ws.rs.client.Entity;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.config.inject.ConfigProperty; import org.eclipse.microprofile.config.inject.ConfigProperty;
import java.util.UUID;
import java.util.logging.Logger; import java.util.logging.Logger;
@ApplicationScoped @ApplicationScoped
@@ -100,9 +101,15 @@ public class AuthenticationService {
private LoginResponse createDemoLoginResponse(LoginRequest request) { private LoginResponse createDemoLoginResponse(LoginRequest request) {
LoginResponse.UserInfo userInfo = new LoginResponse.UserInfo(); LoginResponse.UserInfo userInfo = new LoginResponse.UserInfo();
// UUIDs fixes pour la démonstration (pour cohérence entre les sessions)
UUID superAdminId = UUID.fromString("00000000-0000-0000-0000-000000000001");
UUID adminId = UUID.fromString("00000000-0000-0000-0000-000000000002");
UUID membreId = UUID.fromString("00000000-0000-0000-0000-000000000003");
UUID entiteId = UUID.fromString("00000000-0000-0000-0000-000000000010");
switch (request.getUsername()) { switch (request.getUsername()) {
case "superadmin": case "superadmin":
userInfo.setId(1L); userInfo.setId(superAdminId);
userInfo.setNom("Diallo"); userInfo.setNom("Diallo");
userInfo.setPrenom("Amadou"); userInfo.setPrenom("Amadou");
userInfo.setEmail("amadou.diallo@unionflow.sn"); userInfo.setEmail("amadou.diallo@unionflow.sn");
@@ -112,7 +119,7 @@ public class AuthenticationService {
break; break;
case "admin": case "admin":
userInfo.setId(2L); userInfo.setId(adminId);
userInfo.setNom("Traoré"); userInfo.setNom("Traoré");
userInfo.setPrenom("Fatou"); userInfo.setPrenom("Fatou");
userInfo.setEmail("fatou.traore@association-example.sn"); userInfo.setEmail("fatou.traore@association-example.sn");
@@ -122,7 +129,7 @@ public class AuthenticationService {
// Entité de démonstration // Entité de démonstration
LoginResponse.EntiteInfo entite = new LoginResponse.EntiteInfo(); LoginResponse.EntiteInfo entite = new LoginResponse.EntiteInfo();
entite.setId(1L); entite.setId(entiteId);
entite.setNom("Association des Jeunes Entrepreneurs"); entite.setNom("Association des Jeunes Entrepreneurs");
entite.setType("Association"); entite.setType("Association");
entite.setPays("Sénégal"); entite.setPays("Sénégal");
@@ -131,7 +138,7 @@ public class AuthenticationService {
break; break;
default: default:
userInfo.setId(3L); userInfo.setId(membreId);
userInfo.setNom("Ndiaye"); userInfo.setNom("Ndiaye");
userInfo.setPrenom("Moussa"); userInfo.setPrenom("Moussa");
userInfo.setEmail("moussa.ndiaye@exemple.sn"); userInfo.setEmail("moussa.ndiaye@exemple.sn");
@@ -141,7 +148,7 @@ public class AuthenticationService {
// Entité de démonstration // Entité de démonstration
LoginResponse.EntiteInfo entiteMembre = new LoginResponse.EntiteInfo(); LoginResponse.EntiteInfo entiteMembre = new LoginResponse.EntiteInfo();
entiteMembre.setId(1L); entiteMembre.setId(entiteId);
entiteMembre.setNom("Association des Jeunes Entrepreneurs"); entiteMembre.setNom("Association des Jeunes Entrepreneurs");
entiteMembre.setType("Association"); entiteMembre.setType("Association");
entiteMembre.setPays("Sénégal"); entiteMembre.setPays("Sénégal");

View File

@@ -0,0 +1,46 @@
package dev.lions.unionflow.client.service;
import dev.lions.unionflow.client.dto.CotisationDTO;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
import java.util.UUID;
@RegisterRestClient(configKey = "unionflow-api")
@Path("/api/cotisations")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface CotisationService {
@GET
List<CotisationDTO> listerToutes(
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@GET
@Path("/{id}")
CotisationDTO obtenirParId(@PathParam("id") UUID id);
@GET
@Path("/search")
List<CotisationDTO> rechercher(
@QueryParam("membreId") UUID membreId,
@QueryParam("statut") String statut,
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@POST
CotisationDTO creer(CotisationDTO cotisation);
@PUT
@Path("/{id}")
CotisationDTO modifier(@PathParam("id") UUID id, CotisationDTO cotisation);
@DELETE
@Path("/{id}")
void supprimer(@PathParam("id") UUID id);
}

View File

@@ -0,0 +1,55 @@
package dev.lions.unionflow.client.service;
import dev.lions.unionflow.client.dto.DemandeAideDTO;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
import java.util.UUID;
@RegisterRestClient(configKey = "unionflow-api")
@Path("/api/demandes-aide")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface DemandeAideService {
@GET
List<DemandeAideDTO> listerToutes(
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@GET
@Path("/{id}")
DemandeAideDTO obtenirParId(@PathParam("id") UUID id);
@GET
@Path("/search")
List<DemandeAideDTO> rechercher(
@QueryParam("statut") String statut,
@QueryParam("type") String type,
@QueryParam("urgence") String urgence,
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@POST
DemandeAideDTO creer(DemandeAideDTO demande);
@PUT
@Path("/{id}")
DemandeAideDTO modifier(@PathParam("id") UUID id, DemandeAideDTO demande);
@DELETE
@Path("/{id}")
void supprimer(@PathParam("id") UUID id);
@PUT
@Path("/{id}/approuver")
DemandeAideDTO approuver(@PathParam("id") UUID id);
@PUT
@Path("/{id}/rejeter")
DemandeAideDTO rejeter(@PathParam("id") UUID id);
}

View File

@@ -0,0 +1,54 @@
package dev.lions.unionflow.client.service;
import dev.lions.unionflow.client.dto.EvenementDTO;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
import java.util.UUID;
@RegisterRestClient(configKey = "unionflow-api")
@Path("/api/evenements")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface EvenementService {
@GET
List<EvenementDTO> listerTous(
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@GET
@Path("/{id}")
EvenementDTO obtenirParId(@PathParam("id") UUID id);
@GET
@Path("/search")
List<EvenementDTO> rechercher(
@QueryParam("titre") String titre,
@QueryParam("type") String type,
@QueryParam("statut") String statut,
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@GET
@Path("/a-venir")
List<EvenementDTO> listerAVenir(
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@POST
EvenementDTO creer(EvenementDTO evenement);
@PUT
@Path("/{id}")
EvenementDTO modifier(@PathParam("id") UUID id, EvenementDTO evenement);
@DELETE
@Path("/{id}")
void supprimer(@PathParam("id") UUID id);
}

View File

@@ -0,0 +1,50 @@
package dev.lions.unionflow.client.service;
import dev.lions.unionflow.client.dto.FormulaireDTO;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
import java.util.UUID;
@RegisterRestClient(configKey = "unionflow-api")
@Path("/api/formulaires")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface FormulaireService {
@GET
List<FormulaireDTO> listerTous();
@GET
@Path("/{id}")
FormulaireDTO obtenirParId(@PathParam("id") UUID id);
@GET
@Path("/actifs")
List<FormulaireDTO> listerActifs();
@GET
@Path("/populaires")
List<FormulaireDTO> listerPopulaires();
@POST
FormulaireDTO creer(FormulaireDTO formulaire);
@PUT
@Path("/{id}")
FormulaireDTO modifier(@PathParam("id") UUID id, FormulaireDTO formulaire);
@DELETE
@Path("/{id}")
void supprimer(@PathParam("id") UUID id);
@PUT
@Path("/{id}/activer")
FormulaireDTO activer(@PathParam("id") UUID id);
@PUT
@Path("/{id}/desactiver")
FormulaireDTO desactiver(@PathParam("id") UUID id);
}

View File

@@ -5,6 +5,7 @@ import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*; import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.MediaType;
import java.util.List; import java.util.List;
import java.util.UUID;
@RegisterRestClient(configKey = "unionflow-api") @RegisterRestClient(configKey = "unionflow-api")
@Path("/api/membres") @Path("/api/membres")
@@ -17,7 +18,7 @@ public interface MembreService {
@GET @GET
@Path("/{id}") @Path("/{id}")
MembreDTO obtenirParId(@PathParam("id") Long id); MembreDTO obtenirParId(@PathParam("id") UUID id);
@GET @GET
@Path("/numero/{numeroMembre}") @Path("/numero/{numeroMembre}")
@@ -31,14 +32,14 @@ public interface MembreService {
@QueryParam("email") String email, @QueryParam("email") String email,
@QueryParam("telephone") String telephone, @QueryParam("telephone") String telephone,
@QueryParam("statut") String statut, @QueryParam("statut") String statut,
@QueryParam("associationId") Long associationId, @QueryParam("associationId") UUID associationId,
@QueryParam("page") @DefaultValue("0") int page, @QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size @QueryParam("size") @DefaultValue("20") int size
); );
@GET @GET
@Path("/association/{associationId}") @Path("/association/{associationId}")
List<MembreDTO> listerParAssociation(@PathParam("associationId") Long associationId); List<MembreDTO> listerParAssociation(@PathParam("associationId") UUID associationId);
@GET @GET
@Path("/actifs") @Path("/actifs")
@@ -53,27 +54,27 @@ public interface MembreService {
@PUT @PUT
@Path("/{id}") @Path("/{id}")
MembreDTO modifier(@PathParam("id") Long id, MembreDTO membre); MembreDTO modifier(@PathParam("id") UUID id, MembreDTO membre);
@DELETE @DELETE
@Path("/{id}") @Path("/{id}")
void supprimer(@PathParam("id") Long id); void supprimer(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/activer") @Path("/{id}/activer")
MembreDTO activer(@PathParam("id") Long id); MembreDTO activer(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/desactiver") @Path("/{id}/desactiver")
MembreDTO desactiver(@PathParam("id") Long id); MembreDTO desactiver(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/suspendre") @Path("/{id}/suspendre")
MembreDTO suspendre(@PathParam("id") Long id); MembreDTO suspendre(@PathParam("id") UUID id);
@PUT @PUT
@Path("/{id}/radier") @Path("/{id}/radier")
MembreDTO radier(@PathParam("id") Long id); MembreDTO radier(@PathParam("id") UUID id);
@GET @GET
@Path("/statistiques") @Path("/statistiques")
@@ -84,7 +85,7 @@ public interface MembreService {
@Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") @Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
byte[] exporterExcel( byte[] exporterExcel(
@QueryParam("format") @DefaultValue("EXCEL") String format, @QueryParam("format") @DefaultValue("EXCEL") String format,
@QueryParam("associationId") Long associationId, @QueryParam("associationId") UUID associationId,
@QueryParam("statut") String statut @QueryParam("statut") String statut
); );
@@ -93,7 +94,7 @@ public interface MembreService {
@Consumes(MediaType.MULTIPART_FORM_DATA) @Consumes(MediaType.MULTIPART_FORM_DATA)
ResultatImportDTO importerDonnees( ResultatImportDTO importerDonnees(
@FormParam("file") java.io.InputStream fileInputStream, @FormParam("file") java.io.InputStream fileInputStream,
@FormParam("associationId") Long associationId @FormParam("associationId") UUID associationId
); );
// Classes DTO internes pour les réponses spécialisées // Classes DTO internes pour les réponses spécialisées

View File

@@ -0,0 +1,46 @@
package dev.lions.unionflow.client.service;
import dev.lions.unionflow.client.dto.SouscriptionDTO;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import java.util.List;
import java.util.UUID;
@RegisterRestClient(configKey = "unionflow-api")
@Path("/api/souscriptions")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public interface SouscriptionService {
@GET
List<SouscriptionDTO> listerToutes(
@QueryParam("organisationId") UUID organisationId,
@QueryParam("page") @DefaultValue("0") int page,
@QueryParam("size") @DefaultValue("20") int size
);
@GET
@Path("/{id}")
SouscriptionDTO obtenirParId(@PathParam("id") UUID id);
@GET
@Path("/organisation/{organisationId}/active")
SouscriptionDTO obtenirActive(@PathParam("organisationId") UUID organisationId);
@POST
SouscriptionDTO creer(SouscriptionDTO souscription);
@PUT
@Path("/{id}")
SouscriptionDTO modifier(@PathParam("id") UUID id, SouscriptionDTO souscription);
@DELETE
@Path("/{id}")
void supprimer(@PathParam("id") UUID id);
@PUT
@Path("/{id}/renouveler")
SouscriptionDTO renouveler(@PathParam("id") UUID id);
}

View File

@@ -1,20 +1,30 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.FormulaireDTO; import dev.lions.unionflow.client.dto.FormulaireDTO;
import dev.lions.unionflow.client.dto.SouscriptionDTO; import dev.lions.unionflow.client.service.FormulaireService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
@Named("adminFormulaireBean") @Named("adminFormulaireBean")
@SessionScoped @SessionScoped
public class AdminFormulaireBean implements Serializable { public class AdminFormulaireBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(AdminFormulaireBean.class.getName());
@Inject
@RestClient
private FormulaireService formulaireService;
private List<FormulaireDTO> formulaires; private List<FormulaireDTO> formulaires;
private FormulaireDTO formulaireSelectionne; private FormulaireDTO formulaireSelectionne;
@@ -27,106 +37,18 @@ public class AdminFormulaireBean implements Serializable {
private BigDecimal revenusFormulaires = BigDecimal.ZERO; private BigDecimal revenusFormulaires = BigDecimal.ZERO;
private String formulairePlusPopulaire = ""; private String formulairePlusPopulaire = "";
public AdminFormulaireBean() { @PostConstruct
public void init() {
initializeData(); initializeData();
} }
private void initializeData() { private void initializeData() {
formulaires = new ArrayList<>(); formulaires = new ArrayList<>();
try {
// Formulaire STARTER formulaires = formulaireService.listerTous();
FormulaireDTO starter = new FormulaireDTO(); } catch (Exception e) {
starter.setId(1L); LOGGER.severe("Erreur lors du chargement des formulaires: " + e.getMessage());
starter.setNom("Starter"); }
starter.setDescription("Parfait pour les petites associations débutantes");
starter.setQuotaMaxMembres(100);
starter.setPrixMensuel(new BigDecimal("2000"));
starter.setPrixAnnuel(new BigDecimal("20000"));
starter.setCouleurTheme("bg-blue-500");
starter.setIconeFormulaire("pi-star");
starter.setActif(true);
starter.setGestionMembres(true);
starter.setGestionCotisations(true);
starter.setNotificationsEmail(true);
starter.setDateCreation(LocalDateTime.now().minusMonths(6));
starter.setCreePar("Super Admin");
formulaires.add(starter);
// Formulaire STANDARD
FormulaireDTO standard = new FormulaireDTO();
standard.setId(2L);
standard.setNom("Standard");
standard.setDescription("Idéal pour les associations en croissance");
standard.setQuotaMaxMembres(200);
standard.setPrixMensuel(new BigDecimal("3000"));
standard.setPrixAnnuel(new BigDecimal("30000"));
standard.setCouleurTheme("bg-green-500");
standard.setIconeFormulaire("pi-users");
standard.setActif(true);
standard.setRecommande(true);
standard.setGestionMembres(true);
standard.setGestionCotisations(true);
standard.setGestionEvenements(true);
standard.setGestionAides(true);
standard.setNotificationsEmail(true);
standard.setGestionDocuments(true);
standard.setDateCreation(LocalDateTime.now().minusMonths(6));
standard.setCreePar("Super Admin");
formulaires.add(standard);
// Formulaire PREMIUM
FormulaireDTO premium = new FormulaireDTO();
premium.setId(3L);
premium.setNom("Premium");
premium.setDescription("Solution complète pour les grandes organisations");
premium.setQuotaMaxMembres(500);
premium.setPrixMensuel(new BigDecimal("4000"));
premium.setPrixAnnuel(new BigDecimal("40000"));
premium.setCouleurTheme("bg-purple-500");
premium.setIconeFormulaire("pi-crown");
premium.setActif(true);
premium.setGestionMembres(true);
premium.setGestionCotisations(true);
premium.setGestionEvenements(true);
premium.setGestionAides(true);
premium.setRapportsAvances(true);
premium.setSupportPrioritaire(true);
premium.setSauvegardeAutomatique(true);
premium.setPersonnalisationAvancee(true);
premium.setIntegrationPaiement(true);
premium.setNotificationsEmail(true);
premium.setNotificationsSMS(true);
premium.setGestionDocuments(true);
premium.setDateCreation(LocalDateTime.now().minusMonths(6));
premium.setCreePar("Super Admin");
formulaires.add(premium);
// Formulaire CRISTAL - Pour les très grandes organisations
FormulaireDTO cristal = new FormulaireDTO();
cristal.setId(4L);
cristal.setNom("Cristal");
cristal.setDescription("Solution premium pour les fédérations et grandes entités");
cristal.setQuotaMaxMembres(2000);
cristal.setPrixMensuel(new BigDecimal("5000"));
cristal.setPrixAnnuel(new BigDecimal("50000"));
cristal.setCouleurTheme("bg-indigo-500");
cristal.setIconeFormulaire("pi-diamond");
cristal.setActif(true);
cristal.setGestionMembres(true);
cristal.setGestionCotisations(true);
cristal.setGestionEvenements(true);
cristal.setGestionAides(true);
cristal.setRapportsAvances(true);
cristal.setSupportPrioritaire(true);
cristal.setSauvegardeAutomatique(true);
cristal.setPersonnalisationAvancee(true);
cristal.setIntegrationPaiement(true);
cristal.setNotificationsEmail(true);
cristal.setNotificationsSMS(true);
cristal.setGestionDocuments(true);
cristal.setDateCreation(LocalDateTime.now().minusMonths(6));
cristal.setCreePar("Super Admin");
formulaires.add(cristal);
// Initialiser les statistiques // Initialiser les statistiques
totalSouscriptions = 127; // Plus d'entités avec prix accessibles totalSouscriptions = 127; // Plus d'entités avec prix accessibles
@@ -154,12 +76,8 @@ public class AdminFormulaireBean implements Serializable {
public void sauvegarderFormulaire() { public void sauvegarderFormulaire() {
if (modeCreation) { if (modeCreation) {
// Générer un nouvel ID // Générer un nouvel ID UUID
Long nouvelId = formulaires.stream() nouveauFormulaire.setId(UUID.randomUUID());
.mapToLong(FormulaireDTO::getId)
.max()
.orElse(0L) + 1;
nouveauFormulaire.setId(nouvelId);
nouveauFormulaire.setDateCreation(LocalDateTime.now()); nouveauFormulaire.setDateCreation(LocalDateTime.now());
nouveauFormulaire.setCreePar("Admin"); nouveauFormulaire.setCreePar("Admin");
@@ -197,7 +115,7 @@ public class AdminFormulaireBean implements Serializable {
public void dupliquerFormulaire(FormulaireDTO formulaire) { public void dupliquerFormulaire(FormulaireDTO formulaire) {
FormulaireDTO copie = cloneFormulaire(formulaire); FormulaireDTO copie = cloneFormulaire(formulaire);
copie.setId(null); copie.setId(UUID.randomUUID());
copie.setNom(formulaire.getNom() + " (Copie)"); copie.setNom(formulaire.getNom() + " (Copie)");
copie.setDateCreation(LocalDateTime.now()); copie.setDateCreation(LocalDateTime.now());
copie.setCreePar("Admin"); copie.setCreePar("Admin");

View File

@@ -5,14 +5,15 @@ import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.logging.Logger;
@Named("configurationBean") @Named("configurationBean")
@SessionScoped @SessionScoped
public class ConfigurationBean implements Serializable { public class ConfigurationBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(ConfigurationBean.class.getName());
private ConfigurationGenerale general; private ConfigurationGenerale general;
private ConfigurationSecurite securite; private ConfigurationSecurite securite;
@@ -178,84 +179,85 @@ public class ConfigurationBean implements Serializable {
// Actions générales // Actions générales
public void sauvegarderTout() { public void sauvegarderTout() {
System.out.println("Configuration complète sauvegardée à " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"))); LOGGER.info("Configuration complète sauvegardée à " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")));
} }
public void reinitialiser() { public void reinitialiser() {
init(); init();
System.out.println("Configuration réinitialisée aux valeurs par défaut"); LOGGER.info("Configuration réinitialisée aux valeurs par défaut");
} }
public void exporterConfiguration() { public void exporterConfiguration() {
System.out.println("Export de la configuration généré"); LOGGER.info("Export de la configuration généré");
} }
// Actions par section // Actions par section
public void sauvegarderGeneral() { public void sauvegarderGeneral() {
System.out.println("Configuration générale sauvegardée"); LOGGER.info("Configuration générale sauvegardée");
} }
public void sauvegarderSecurite() { public void sauvegarderSecurite() {
System.out.println("Configuration sécurité sauvegardée"); LOGGER.info("Configuration sécurité sauvegardée");
} }
public void sauvegarderEmail() { public void sauvegarderEmail() {
System.out.println("Configuration email sauvegardée"); LOGGER.info("Configuration email sauvegardée");
} }
// Actions pour la page système // Actions pour la page système
public void sauvegarderConfiguration() { public void sauvegarderConfiguration() {
System.out.println("Configuration système sauvegardée"); LOGGER.info("Configuration système sauvegardée");
} }
public void restaurerDefauts() { public void restaurerDefauts() {
nomApplication = "UnionFlow"; nomApplication = "UnionFlow";
versionSysteme = "1.0.0"; versionSysteme = "1.0.0";
environnement = "DEV"; environnement = "DEV";
System.out.println("Configuration système restaurée aux valeurs par défaut"); LOGGER.info("Configuration système restaurée aux valeurs par défaut");
} }
public void testerConnexionBDD() { public void testerConnexionBDD() {
System.out.println("Test de connexion BDD: " + typeBDD + "://" + serveurBDD + ":" + portBDD + "/" + nomBDD); // Le test de connexion BDD sera implémenté via l'API backend
// TODO: Implémenter le test réel // Pour l'instant, log uniquement
LOGGER.info("Test de connexion BDD: " + typeBDD + "://" + serveurBDD + ":" + portBDD + "/" + nomBDD);
} }
public void testerEmail() { public void testerEmail() {
System.out.println("Test d'envoi d'email via " + serveurSMTP + ":" + portSMTP); // Le test d'email sera implémenté via l'API backend
// TODO: Implémenter le test réel // Pour l'instant, log uniquement
System.out.println("Test email envoyé avec succès"); LOGGER.info("Test d'envoi d'email via " + serveurSMTP + ":" + portSMTP);
} }
public void forcerSauvegarde() { public void forcerSauvegarde() {
System.out.println("Sauvegarde forcée du système"); // La sauvegarde sera déclenchée via l'API backend
LOGGER.info("Sauvegarde forcée du système");
derniereSauvegarde = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm")); derniereSauvegarde = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm"));
// TODO: Déclencher une sauvegarde immédiate
} }
public void redemarrerServices() { public void redemarrerServices() {
System.out.println("Redémarrage des services système en cours..."); // Le redémarrage des services sera géré via l'API backend
// TODO: Redémarrer les services critiques LOGGER.info("Redémarrage des services système en cours...");
} }
public void sauvegarderPaiements() { public void sauvegarderPaiements() {
System.out.println("Configuration paiements sauvegardée"); LOGGER.info("Configuration paiements sauvegardée");
} }
public void sauvegarderSysteme() { public void sauvegarderSysteme() {
System.out.println("Configuration système sauvegardée"); LOGGER.info("Configuration système sauvegardée");
} }
// Actions système // Actions système
public void viderCache() { public void viderCache() {
System.out.println("Cache vidé avec succès"); LOGGER.info("Cache vidé avec succès");
} }
public void optimiserBaseDonnees() { public void optimiserBaseDonnees() {
System.out.println("Optimisation de la base de données en cours..."); LOGGER.info("Optimisation de la base de données en cours...");
} }
public void sauvegarderBaseDonnees() { public void sauvegarderBaseDonnees() {
System.out.println("Sauvegarde de la base de données initiée"); LOGGER.info("Sauvegarde de la base de données initiée");
} }
public String voirLogsSysteme() { public String voirLogsSysteme() {
@@ -665,35 +667,35 @@ public class ConfigurationBean implements Serializable {
// Méthodes d'actions // Méthodes d'actions
public void actualiserMonitoring() { public void actualiserMonitoring() {
calculerMetriquesSysteme(); calculerMetriquesSysteme();
System.out.println("Monitoring actualisé"); LOGGER.info("Monitoring actualisé");
} }
public void nettoyerCache() { public void nettoyerCache() {
System.out.println("Cache système nettoyé"); LOGGER.info("Cache système nettoyé");
} }
public void auditSysteme() { public void auditSysteme() {
System.out.println("Audit système lancé"); LOGGER.info("Audit système lancé");
} }
public void appliquerConfigGenerale() { public void appliquerConfigGenerale() {
System.out.println("Configuration générale appliquée"); LOGGER.info("Configuration générale appliquée");
} }
public void appliquerConfigBDD() { public void appliquerConfigBDD() {
System.out.println("Configuration BDD appliquée"); LOGGER.info("Configuration BDD appliquée");
} }
public void appliquerConfigEmail() { public void appliquerConfigEmail() {
System.out.println("Configuration email appliquée"); LOGGER.info("Configuration email appliquée");
} }
public void appliquerConfigSecurite() { public void appliquerConfigSecurite() {
System.out.println("Configuration sécurité appliquée"); LOGGER.info("Configuration sécurité appliquée");
} }
public void sauvegarderAlertes() { public void sauvegarderAlertes() {
System.out.println("Configuration des alertes sauvegardée"); LOGGER.info("Configuration des alertes sauvegardée");
} }
public static class ConfigurationSysteme { public static class ConfigurationSysteme {

View File

@@ -1,8 +1,12 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.CotisationDTO;
import dev.lions.unionflow.client.service.CotisationService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -10,14 +14,21 @@ import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.logging.Logger;
@Named("cotisationsBean") @Named("cotisationsBean")
@SessionScoped @SessionScoped
public class CotisationsBean implements Serializable { public class CotisationsBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(CotisationsBean.class.getName());
@Inject
@RestClient
private CotisationService cotisationService;
private List<Cotisation> toutesLesCotisations; private List<Cotisation> toutesLesCotisations;
private List<Cotisation> cotisationsFiltrees; private List<Cotisation> cotisationsFiltrees;
@@ -33,8 +44,8 @@ public class CotisationsBean implements Serializable {
@PostConstruct @PostConstruct
public void init() { public void init() {
initializeFiltres(); initializeFiltres();
initializeStatistiques();
initializeCotisations(); initializeCotisations();
initializeStatistiques();
initializeNouvelleCotisation(); initializeNouvelleCotisation();
initializeEvolutionPaiements(); initializeEvolutionPaiements();
initializeRepartitionMethodes(); initializeRepartitionMethodes();
@@ -49,12 +60,40 @@ public class CotisationsBean implements Serializable {
private void initializeStatistiques() { private void initializeStatistiques() {
statistiques = new StatistiquesFinancieres(); statistiques = new StatistiquesFinancieres();
statistiques.setTotalCollecte(new BigDecimal("45750000")); try {
statistiques.setObjectifAnnuel(new BigDecimal("60000000")); List<CotisationDTO> cotisationsDTO = cotisationService.listerToutes(0, 1000);
statistiques.setTauxRecouvrement(76.25); BigDecimal totalCollecte = cotisationsDTO.stream()
statistiques.setCotisationsEnRetard(23); .filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
statistiques.setMontantRetard(new BigDecimal("3850000")); .map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
statistiques.setMoyenneMensuelle(new BigDecimal("3812500")); .reduce(BigDecimal.ZERO, BigDecimal::add);
statistiques.setTotalCollecte(totalCollecte);
statistiques.setObjectifAnnuel(totalCollecte.multiply(new BigDecimal("1.3")));
long total = cotisationsDTO.size();
long payees = cotisationsDTO.stream().filter(c -> "PAYEE".equals(c.getStatut())).count();
double tauxRecouvrement = total > 0 ? (double) payees / total * 100.0 : 0.0;
statistiques.setTauxRecouvrement(tauxRecouvrement);
long enRetard = cotisationsDTO.stream().filter(c -> "EN_RETARD".equals(c.getStatut())).count();
statistiques.setCotisationsEnRetard((int) enRetard);
BigDecimal montantRetard = cotisationsDTO.stream()
.filter(c -> "EN_RETARD".equals(c.getStatut()))
.map(c -> c.getMontantDu() != null ? c.getMontantDu() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
statistiques.setMontantRetard(montantRetard);
BigDecimal moyenneMensuelle = totalCollecte.divide(new BigDecimal("12"), 2, java.math.RoundingMode.HALF_UP);
statistiques.setMoyenneMensuelle(moyenneMensuelle);
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des statistiques: " + e.getMessage());
statistiques.setTotalCollecte(BigDecimal.ZERO);
statistiques.setObjectifAnnuel(BigDecimal.ZERO);
statistiques.setTauxRecouvrement(0.0);
statistiques.setCotisationsEnRetard(0);
statistiques.setMontantRetard(BigDecimal.ZERO);
statistiques.setMoyenneMensuelle(BigDecimal.ZERO);
}
} }
private void initializeEvolutionPaiements() { private void initializeEvolutionPaiements() {
@@ -142,63 +181,32 @@ public class CotisationsBean implements Serializable {
private void initializeCotisations() { private void initializeCotisations() {
toutesLesCotisations = new ArrayList<>(); toutesLesCotisations = new ArrayList<>();
try {
String[] membres = { List<CotisationDTO> cotisationsDTO = cotisationService.listerToutes(0, 1000);
"Jean Kouassi", "Marie Traoré", "Ahmed Diallo", "Fatou Sanogo", "Paul Ouattara", for (CotisationDTO dto : cotisationsDTO) {
"Aissata Koné", "Ibrahim Touré", "Aminata Bakayoko", "Yves Koffi", "Mariam Coulibaly", Cotisation cotisation = convertToCotisation(dto);
"Seydou Cissé", "Adjoa Mensah", "Kwame Asante", "Ama Gyamfi", "Kofi Adjei"
};
String[] clubs = {
"Association Alpha", "Club Beta", "Groupe Gamma",
"Association Delta", "Club Epsilon", "Groupe Zeta",
"Association Eta", "Club Theta", "Groupe Iota"
};
String[] types = {"MENSUELLE", "TRIMESTRIELLE", "ANNUELLE", "EXCEPTIONNELLE"};
String[] statuts = {"PAYEE", "EN_ATTENTE", "EN_RETARD", "PARTIELLEMENT_PAYEE"};
String[] methodes = {"WAVE_MONEY", "ESPECES", "CHEQUE", "VIREMENT"};
BigDecimal[] montants = {
new BigDecimal("150000"), new BigDecimal("125000"), new BigDecimal("100000"),
new BigDecimal("175000"), new BigDecimal("200000"), new BigDecimal("75000"),
new BigDecimal("120000"), new BigDecimal("180000"), new BigDecimal("95000")
};
for (int i = 0; i < 50; i++) {
Cotisation cotisation = new Cotisation();
cotisation.setId((long) (i + 1));
cotisation.setNumeroMembre("M" + String.format("%04d", (i % membres.length) + 1));
cotisation.setNomMembre(membres[i % membres.length]);
cotisation.setClub(clubs[i % clubs.length]);
cotisation.setTypeCotisation(types[i % types.length]);
cotisation.setMontantDu(montants[i % montants.length]);
if (i % 5 == 0) {
cotisation.setStatut("EN_RETARD");
cotisation.setMontantPaye(BigDecimal.ZERO);
} else if (i % 8 == 0) {
cotisation.setStatut("PARTIELLEMENT_PAYEE");
cotisation.setMontantPaye(cotisation.getMontantDu().multiply(new BigDecimal("0.5")));
} else if (i % 12 == 0) {
cotisation.setStatut("EN_ATTENTE");
cotisation.setMontantPaye(BigDecimal.ZERO);
} else {
cotisation.setStatut("PAYEE");
cotisation.setMontantPaye(cotisation.getMontantDu());
}
cotisation.setMethodePaiement(methodes[i % methodes.length]);
cotisation.setDateEcheance(LocalDate.now().minusDays(i * 2).plusMonths(1));
if (!cotisation.getStatut().equals("EN_ATTENTE")) {
cotisation.setDatePaiement(LocalDateTime.now().minusDays(i + 1));
}
cotisation.setObservations(i % 7 == 0 ? "Paiement en plusieurs fois autorisé" : "");
toutesLesCotisations.add(cotisation); toutesLesCotisations.add(cotisation);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des cotisations: " + e.getMessage());
}
}
private Cotisation convertToCotisation(CotisationDTO dto) {
Cotisation cotisation = new Cotisation();
cotisation.setId(dto.getId());
cotisation.setNumeroMembre(dto.getNumeroMembre());
cotisation.setNomMembre(dto.getNomMembre());
cotisation.setClub(dto.getNomAssociation());
cotisation.setTypeCotisation(dto.getTypeCotisation());
cotisation.setMontantDu(dto.getMontantDu());
cotisation.setMontantPaye(dto.getMontantPaye());
cotisation.setStatut(dto.getStatut());
cotisation.setMethodePaiement(dto.getMethodePaiement());
cotisation.setDateEcheance(dto.getDateEcheance());
cotisation.setDatePaiement(dto.getDatePaiement());
cotisation.setObservations(dto.getObservations());
return cotisation;
} }
private void initializeNouvelleCotisation() { private void initializeNouvelleCotisation() {
@@ -269,7 +277,7 @@ public class CotisationsBean implements Serializable {
public void enregistrerCotisation() { public void enregistrerCotisation() {
Cotisation nouvelleCot = new Cotisation(); Cotisation nouvelleCot = new Cotisation();
nouvelleCot.setId((long) (toutesLesCotisations.size() + 1)); nouvelleCot.setId(UUID.randomUUID());
nouvelleCot.setNumeroMembre(nouvelleCotisation.getNumeroMembre()); nouvelleCot.setNumeroMembre(nouvelleCotisation.getNumeroMembre());
nouvelleCot.setNomMembre(nouvelleCotisation.getNomMembre()); nouvelleCot.setNomMembre(nouvelleCotisation.getNomMembre());
nouvelleCot.setClub(nouvelleCotisation.getClub()); nouvelleCot.setClub(nouvelleCotisation.getClub());
@@ -283,7 +291,7 @@ public class CotisationsBean implements Serializable {
toutesLesCotisations.add(nouvelleCot); toutesLesCotisations.add(nouvelleCot);
appliquerFiltres(); appliquerFiltres();
System.out.println("Nouvelle cotisation enregistrée pour: " + nouvelleCot.getNomMembre()); LOGGER.info("Nouvelle cotisation enregistrée pour: " + nouvelleCot.getNomMembre());
initializeNouvelleCotisation(); initializeNouvelleCotisation();
} }
@@ -292,7 +300,7 @@ public class CotisationsBean implements Serializable {
cotisationSelectionnee.setStatut("PAYEE"); cotisationSelectionnee.setStatut("PAYEE");
cotisationSelectionnee.setMontantPaye(cotisationSelectionnee.getMontantDu()); cotisationSelectionnee.setMontantPaye(cotisationSelectionnee.getMontantDu());
cotisationSelectionnee.setDatePaiement(LocalDateTime.now()); cotisationSelectionnee.setDatePaiement(LocalDateTime.now());
System.out.println("Cotisation marquée comme payée: " + cotisationSelectionnee.getNomMembre()); LOGGER.info("Cotisation marquée comme payée: " + cotisationSelectionnee.getNomMembre());
} }
} }
@@ -300,26 +308,26 @@ public class CotisationsBean implements Serializable {
if (cotisationSelectionnee != null) { if (cotisationSelectionnee != null) {
cotisationSelectionnee.setStatut("PARTIELLEMENT_PAYEE"); cotisationSelectionnee.setStatut("PARTIELLEMENT_PAYEE");
cotisationSelectionnee.setDatePaiement(LocalDateTime.now()); cotisationSelectionnee.setDatePaiement(LocalDateTime.now());
System.out.println("Paiement partiel enregistré: " + cotisationSelectionnee.getNomMembre()); LOGGER.info("Paiement partiel enregistré: " + cotisationSelectionnee.getNomMembre());
} }
} }
public void envoyerRappel() { public void envoyerRappel() {
if (cotisationSelectionnee != null) { if (cotisationSelectionnee != null) {
System.out.println("Rappel envoyé à: " + cotisationSelectionnee.getNomMembre()); LOGGER.info("Rappel envoyé à: " + cotisationSelectionnee.getNomMembre());
} }
} }
public void envoyerRappelsGroupes() { public void envoyerRappelsGroupes() {
System.out.println("Rappels envoyés à " + cotisationsSelectionnees.size() + " membres"); LOGGER.info("Rappels envoyés à " + cotisationsSelectionnees.size() + " membres");
} }
public void exporterCotisations() { public void exporterCotisations() {
System.out.println("Export de " + cotisationsFiltrees.size() + " cotisations"); LOGGER.info("Export de " + cotisationsFiltrees.size() + " cotisations");
} }
public void genererRapportFinancier() { public void genererRapportFinancier() {
System.out.println("Rapport financier généré"); LOGGER.info("Rapport financier généré");
} }
// Getters et Setters // Getters et Setters
@@ -355,7 +363,7 @@ public class CotisationsBean implements Serializable {
// Classes internes // Classes internes
public static class Cotisation { public static class Cotisation {
private Long id; private UUID id;
private String numeroMembre; private String numeroMembre;
private String nomMembre; private String nomMembre;
private String club; private String club;
@@ -369,8 +377,8 @@ public class CotisationsBean implements Serializable {
private String observations; private String observations;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNumeroMembre() { return numeroMembre; } public String getNumeroMembre() { return numeroMembre; }
public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; } public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; }
@@ -474,7 +482,7 @@ public class CotisationsBean implements Serializable {
public int getPourcentagePaye() { public int getPourcentagePaye() {
if (montantDu.equals(BigDecimal.ZERO)) return 0; if (montantDu.equals(BigDecimal.ZERO)) return 0;
return montantPaye.multiply(new BigDecimal("100")).divide(montantDu, 0, BigDecimal.ROUND_HALF_UP).intValue(); return montantPaye.multiply(new BigDecimal("100")).divide(montantDu, 0, java.math.RoundingMode.HALF_UP).intValue();
} }
public long getJoursRetard() { public long getJoursRetard() {

View File

@@ -1,21 +1,38 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.CotisationDTO;
import dev.lions.unionflow.client.dto.AssociationDTO;
import dev.lions.unionflow.client.service.CotisationService;
import dev.lions.unionflow.client.service.AssociationService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.logging.Logger;
@Named("cotisationsGestionBean") @Named("cotisationsGestionBean")
@SessionScoped @SessionScoped
public class CotisationsGestionBean implements Serializable { public class CotisationsGestionBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(CotisationsGestionBean.class.getName());
@Inject
@RestClient
private CotisationService cotisationService;
@Inject
@RestClient
private AssociationService associationService;
// Propriétés principales // Propriétés principales
private String periodeActuelle; private String periodeActuelle;
@@ -71,96 +88,158 @@ public class CotisationsGestionBean implements Serializable {
} }
private void initializeKPIs() { private void initializeKPIs() {
this.periodeActuelle = "Décembre 2024"; try {
this.tauxRecouvrement = new BigDecimal("87.3"); List<CotisationDTO> cotisationsDTO = cotisationService.listerToutes(0, 1000);
this.totalMembresActifs = 18547;
this.montantCollecte = "2,845,000 FCFA"; BigDecimal totalCollecte = cotisationsDTO.stream()
this.objectifMensuel = "3,200,000 FCFA"; .filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
this.progressionMensuelle = 89; .map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
this.membresAJour = "16,205"; .reduce(BigDecimal.ZERO, BigDecimal::add);
this.pourcentageMembresAJour = 87;
this.montantEnAttente = "785,000 FCFA";
this.nombreCotisationsEnAttente = 1247;
this.montantImpayes = "425,000 FCFA";
this.joursRetardMoyen = 12;
this.revenus2024 = "34,200,000 FCFA";
this.croissanceAnnuelle = "+15.3%";
this.prelevementsActifs = "8,450";
this.montantPrelevementsPrevu = "42,250,000";
this.membresPrelevementActif = 8450; long total = cotisationsDTO.size();
this.montantPrelevementMensuel = "42,250,000 FCFA"; long payees = cotisationsDTO.stream().filter(c -> "PAYEE".equals(c.getStatut())).count();
this.prochainPrelevement = "01/01/2025"; double taux = total > 0 ? (double) payees / total * 100.0 : 0.0;
long enAttente = cotisationsDTO.stream().filter(c -> "EN_ATTENTE".equals(c.getStatut())).count();
BigDecimal montantAttente = cotisationsDTO.stream()
.filter(c -> "EN_ATTENTE".equals(c.getStatut()))
.map(c -> c.getMontantDu() != null ? c.getMontantDu() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
long enRetard = cotisationsDTO.stream().filter(c -> "EN_RETARD".equals(c.getStatut())).count();
BigDecimal montantImpayes = cotisationsDTO.stream()
.filter(c -> "EN_RETARD".equals(c.getStatut()))
.map(c -> c.getMontantDu() != null ? c.getMontantDu() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
this.periodeActuelle = LocalDate.now().format(DateTimeFormatter.ofPattern("MMMM yyyy"));
this.tauxRecouvrement = new BigDecimal(String.format("%.1f", taux));
this.totalMembresActifs = (int) total;
this.montantCollecte = formatMontant(totalCollecte);
this.objectifMensuel = formatMontant(totalCollecte.multiply(new BigDecimal("1.15")));
this.progressionMensuelle = (int) (taux);
this.membresAJour = String.valueOf(payees);
this.pourcentageMembresAJour = (int) taux;
this.montantEnAttente = formatMontant(montantAttente);
this.nombreCotisationsEnAttente = (int) enAttente;
this.montantImpayes = formatMontant(montantImpayes);
this.joursRetardMoyen = 12; // À calculer depuis les dates
this.revenus2024 = formatMontant(totalCollecte.multiply(new BigDecimal("12")));
this.croissanceAnnuelle = "+15.3%"; // À calculer
this.prelevementsActifs = "0";
this.montantPrelevementsPrevu = "0";
this.membresPrelevementActif = 0;
this.montantPrelevementMensuel = "0 FCFA";
this.prochainPrelevement = LocalDate.now().plusMonths(1).format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des KPIs: " + e.getMessage());
this.periodeActuelle = LocalDate.now().format(DateTimeFormatter.ofPattern("MMMM yyyy"));
this.tauxRecouvrement = BigDecimal.ZERO;
this.totalMembresActifs = 0;
this.montantCollecte = "0 FCFA";
this.objectifMensuel = "0 FCFA";
this.progressionMensuelle = 0;
this.membresAJour = "0";
this.pourcentageMembresAJour = 0;
this.montantEnAttente = "0 FCFA";
this.nombreCotisationsEnAttente = 0;
this.montantImpayes = "0 FCFA";
this.joursRetardMoyen = 0;
this.revenus2024 = "0 FCFA";
this.croissanceAnnuelle = "0%";
this.prelevementsActifs = "0";
this.montantPrelevementsPrevu = "0";
this.membresPrelevementActif = 0;
this.montantPrelevementMensuel = "0 FCFA";
this.prochainPrelevement = LocalDate.now().plusMonths(1).format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
}
this.cotisationsSelectionnees = new ArrayList<>(); this.cotisationsSelectionnees = new ArrayList<>();
this.montantTotalSelectionne = "0 FCFA"; this.montantTotalSelectionne = "0 FCFA";
} }
private String formatMontant(BigDecimal montant) {
if (montant == null) return "0 FCFA";
return String.format("%,.0f FCFA", montant.doubleValue());
}
private void initializeFiltres() { private void initializeFiltres() {
this.filtres = new FiltresCotisations(); this.filtres = new FiltresCotisations();
this.listeOrganisations = new ArrayList<>(); this.listeOrganisations = new ArrayList<>();
try {
// Simulation d'organisations List<AssociationDTO> associations = associationService.listerToutes();
for (int i = 1; i <= 127; i++) { for (AssociationDTO assoc : associations) {
Organisation org = new Organisation(); Organisation org = new Organisation();
org.setId((long) i); org.setId(assoc.getId());
org.setNom("Organisation " + i); org.setNom(assoc.getNom());
listeOrganisations.add(org); listeOrganisations.add(org);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des organisations: " + e.getMessage());
}
} }
private void initializeData() { private void initializeData() {
this.cotisationsFiltrees = new ArrayList<>(); this.cotisationsFiltrees = new ArrayList<>();
try {
// Simulation de données de cotisations pour les 127 organisations List<CotisationDTO> cotisationsDTO = cotisationService.listerToutes(0, 1000);
for (int i = 1; i <= 500; i++) { for (CotisationDTO dto : cotisationsDTO) {
CotisationAdmin cotisation = new CotisationAdmin(); CotisationAdmin cotisation = convertToCotisationAdmin(dto);
cotisation.setId((long) i);
cotisation.setNomOrganisation("Organisation " + ((i % 127) + 1));
cotisation.setRegionOrganisation("Région " + ((i % 12) + 1));
cotisation.setIconeOrganisation("pi-building");
cotisation.setNomCompletMembre("Membre " + i);
cotisation.setNumeroMembre("M" + String.format("%06d", i));
cotisation.setInitialesMembre(getInitiales("Membre " + i));
cotisation.setTypeMembre(i % 3 == 0 ? "Membre Actif" : "Membre Associé");
cotisation.setType(getTypeCotisation(i));
cotisation.setPeriode(getperiode(i));
cotisation.setAnnee("2024");
cotisation.setMontant(new BigDecimal(getMontantCotisation(i)));
cotisation.setStatut(getStatutCotisation(i));
cotisation.setDateEcheance(LocalDate.now().minusDays(i % 60));
if (cotisation.getStatut().equals("PAYE")) {
cotisation.setDatePaiement(cotisation.getDateEcheance().plusDays(i % 10));
cotisation.setModePaiement(getModePaiement(i));
}
cotisationsFiltrees.add(cotisation); cotisationsFiltrees.add(cotisation);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des cotisations: " + e.getMessage());
}
}
private CotisationAdmin convertToCotisationAdmin(CotisationDTO dto) {
CotisationAdmin cotisation = new CotisationAdmin();
cotisation.setId(dto.getId());
cotisation.setNomOrganisation(dto.getNomAssociation());
cotisation.setNomCompletMembre(dto.getNomMembre());
cotisation.setNumeroMembre(dto.getNumeroMembre());
cotisation.setType(dto.getTypeCotisation());
cotisation.setMontant(dto.getMontantDu());
cotisation.setStatut(dto.getStatut());
cotisation.setDateEcheance(dto.getDateEcheance());
cotisation.setDatePaiement(dto.getDatePaiement() != null ? dto.getDatePaiement().toLocalDate() : null);
cotisation.setModePaiement(dto.getMethodePaiement());
if (dto.getNomMembre() != null && !dto.getNomMembre().isEmpty()) {
cotisation.setInitialesMembre(getInitiales(dto.getNomMembre()));
}
return cotisation;
} }
private void initializeTopOrganisations() { private void initializeTopOrganisations() {
this.topOrganisations = new ArrayList<>(); this.topOrganisations = new ArrayList<>();
try {
List<AssociationDTO> associations = associationService.listerActives();
List<CotisationDTO> cotisationsDTO = cotisationService.listerToutes(0, 1000);
String[] noms = {"Lions Club Dakar Centre", "Association Thiès Nord", "Groupe Kaolack Est", for (AssociationDTO assoc : associations.stream().limit(5).collect(Collectors.toList())) {
"Lions Club Saint-Louis", "Association Louga Centre"}; List<CotisationDTO> cotisationsOrg = cotisationsDTO.stream()
int[] taux = {98, 95, 92, 89, 87}; .filter(c -> c.getAssociationId() != null && c.getAssociationId().equals(assoc.getId()))
String[] montants = {"485K", "420K", "380K", "365K", "340K"}; .collect(Collectors.toList());
int[] membres = {156, 134, 128, 145, 120};
int[] totaux = {160, 145, 140, 165, 135}; long total = cotisationsOrg.size();
long payees = cotisationsOrg.stream().filter(c -> "PAYEE".equals(c.getStatut())).count();
int taux = total > 0 ? (int) ((double) payees / total * 100.0) : 0;
BigDecimal montantCollecte = cotisationsOrg.stream()
.filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
.map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
for (int i = 0; i < noms.length; i++) {
OrganisationPerformante org = new OrganisationPerformante(); OrganisationPerformante org = new OrganisationPerformante();
org.setNom(noms[i]); org.setNom(assoc.getNom());
org.setTauxRecouvrement(taux[i]); org.setTauxRecouvrement(taux);
org.setMontantCollecte(montants[i]); org.setMontantCollecte(formatMontant(montantCollecte));
org.setNombreMembresAJour(membres[i]); org.setNombreMembresAJour((int) payees);
org.setTotalMembres(totaux[i]); org.setTotalMembres((int) total);
topOrganisations.add(org); topOrganisations.add(org);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des top organisations: " + e.getMessage());
}
} }
private void initializeNouvelleCampagne() { private void initializeNouvelleCampagne() {
@@ -217,95 +296,95 @@ public class CotisationsGestionBean implements Serializable {
// Actions principales // Actions principales
public void creerCampagne() { public void creerCampagne() {
System.out.println("Création de la campagne: " + nouvelleCampagne.getNom()); LOGGER.info("Création de la campagne: " + nouvelleCampagne.getNom());
// Logique de création de campagne // Logique de création de campagne
initializeNouvelleCampagne(); // Reset pour nouvelle campagne initializeNouvelleCampagne(); // Reset pour nouvelle campagne
} }
public void relancesGroupees() { public void relancesGroupees() {
System.out.println("Envoi de relances groupées"); LOGGER.info("Envoi de relances groupées");
} }
public void exporterTout() { public void exporterTout() {
System.out.println("Export global des cotisations"); LOGGER.info("Export global des cotisations");
} }
public void appliquerFiltres() { public void appliquerFiltres() {
// Logique de filtrage // Logique de filtrage
System.out.println("Application des filtres"); LOGGER.info("Application des filtres");
} }
public void reinitialiserFiltres() { public void reinitialiserFiltres() {
this.filtres = new FiltresCotisations(); this.filtres = new FiltresCotisations();
System.out.println("Réinitialisation des filtres"); LOGGER.info("Réinitialisation des filtres");
} }
public void exporterExcel() { public void exporterExcel() {
System.out.println("Export Excel des cotisations filtrées"); LOGGER.info("Export Excel des cotisations filtrées");
} }
// Actions sur cotisations individuelles // Actions sur cotisations individuelles
public void enregistrerPaiement(CotisationAdmin cotisation) { public void enregistrerPaiement(CotisationAdmin cotisation) {
System.out.println("Enregistrement paiement pour: " + cotisation.getNumeroMembre()); LOGGER.info("Enregistrement paiement pour: " + cotisation.getNumeroMembre());
} }
public void genererRecu(CotisationAdmin cotisation) { public void genererRecu(CotisationAdmin cotisation) {
System.out.println("Génération reçu pour: " + cotisation.getNumeroMembre()); LOGGER.info("Génération reçu pour: " + cotisation.getNumeroMembre());
} }
public void envoyerRappel(CotisationAdmin cotisation) { public void envoyerRappel(CotisationAdmin cotisation) {
System.out.println("Envoi rappel pour: " + cotisation.getNumeroMembre()); LOGGER.info("Envoi rappel pour: " + cotisation.getNumeroMembre());
} }
public void voirDetails(CotisationAdmin cotisation) { public void voirDetails(CotisationAdmin cotisation) {
System.out.println("Affichage détails pour: " + cotisation.getNumeroMembre()); LOGGER.info("Affichage détails pour: " + cotisation.getNumeroMembre());
} }
// Actions groupées // Actions groupées
public void marquerPayeesGroupees() { public void marquerPayeesGroupees() {
System.out.println("Marquage " + cotisationsSelectionnees.size() + " cotisations comme payées"); LOGGER.info("Marquage " + cotisationsSelectionnees.size() + " cotisations comme payées");
} }
public void envoyerRelancesGroupees() { public void envoyerRelancesGroupees() {
System.out.println("Envoi relances pour " + cotisationsSelectionnees.size() + " cotisations"); LOGGER.info("Envoi relances pour " + cotisationsSelectionnees.size() + " cotisations");
} }
public void genererRecusGroupes() { public void genererRecusGroupes() {
System.out.println("Génération reçus pour " + cotisationsSelectionnees.size() + " cotisations"); LOGGER.info("Génération reçus pour " + cotisationsSelectionnees.size() + " cotisations");
} }
public void annulerCotisationsGroupees() { public void annulerCotisationsGroupees() {
System.out.println("Annulation " + cotisationsSelectionnees.size() + " cotisations"); LOGGER.info("Annulation " + cotisationsSelectionnees.size() + " cotisations");
} }
// Wave Money // Wave Money
public void lancerPrelevements() { public void lancerPrelevements() {
System.out.println("Lancement des prélèvements Wave Money"); LOGGER.info("Lancement des prélèvements Wave Money");
} }
public void testerAPIWave() { public void testerAPIWave() {
System.out.println("Test de l'API Wave Money"); LOGGER.info("Test de l'API Wave Money");
} }
public void voirHistoriquePrelevements() { public void voirHistoriquePrelevements() {
System.out.println("Affichage historique des prélèvements"); LOGGER.info("Affichage historique des prélèvements");
} }
// Actions rapides // Actions rapides
public void genererRapportMensuel() { public void genererRapportMensuel() {
System.out.println("Génération rapport mensuel"); LOGGER.info("Génération rapport mensuel");
} }
public void configurerRelancesAuto() { public void configurerRelancesAuto() {
System.out.println("Configuration relances automatiques"); LOGGER.info("Configuration relances automatiques");
} }
public void gererTypesCotisations() { public void gererTypesCotisations() {
System.out.println("Gestion des types de cotisations"); LOGGER.info("Gestion des types de cotisations");
} }
public void tableauDeBord() { public void tableauDeBord() {
System.out.println("Affichage tableau de bord"); LOGGER.info("Affichage tableau de bord");
} }
// Getters et Setters // Getters et Setters
@@ -415,7 +494,7 @@ public class CotisationsGestionBean implements Serializable {
// Classes internes pour les données // Classes internes pour les données
public static class CotisationAdmin { public static class CotisationAdmin {
private Long id; private UUID id;
private String nomOrganisation; private String nomOrganisation;
private String regionOrganisation; private String regionOrganisation;
private String iconeOrganisation; private String iconeOrganisation;
@@ -433,8 +512,8 @@ public class CotisationsGestionBean implements Serializable {
private String modePaiement; private String modePaiement;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNomOrganisation() { return nomOrganisation; } public String getNomOrganisation() { return nomOrganisation; }
public void setNomOrganisation(String nomOrganisation) { this.nomOrganisation = nomOrganisation; } public void setNomOrganisation(String nomOrganisation) { this.nomOrganisation = nomOrganisation; }
@@ -633,11 +712,11 @@ public class CotisationsGestionBean implements Serializable {
} }
public static class Organisation { public static class Organisation {
private Long id; private UUID id;
private String nom; private String nom;
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }

View File

@@ -1,22 +1,33 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.DemandeAideDTO;
import dev.lions.unionflow.client.service.DemandeAideService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.logging.Logger;
@Named("demandesAideBean") @Named("demandesAideBean")
@SessionScoped @SessionScoped
public class DemandesAideBean implements Serializable { public class DemandesAideBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(DemandesAideBean.class.getName());
@Inject
@RestClient
private DemandeAideService demandeAideService;
private List<DemandeAide> toutesLesDemandes; private List<DemandeAide> toutesLesDemandes;
private List<DemandeAide> demandesFiltrees; private List<DemandeAide> demandesFiltrees;
@@ -46,10 +57,25 @@ public class DemandesAideBean implements Serializable {
private void initializeStatistiques() { private void initializeStatistiques() {
statistiques = new StatistiquesDemandes(); statistiques = new StatistiquesDemandes();
statistiques.setTotalDemandes(156); try {
statistiques.setDemandesEnAttente(23); List<DemandeAideDTO> demandesDTO = demandeAideService.listerToutes(0, 1000);
statistiques.setDemandesApprouvees(89); statistiques.setTotalDemandes(demandesDTO.size());
statistiques.setMontantTotalAide("12 850 000 FCFA"); long enAttente = demandesDTO.stream().filter(d -> "EN_ATTENTE".equals(d.getStatut())).count();
statistiques.setDemandesEnAttente((int) enAttente);
long approuvees = demandesDTO.stream().filter(d -> "APPROUVEE".equals(d.getStatut())).count();
statistiques.setDemandesApprouvees((int) approuvees);
BigDecimal montantTotal = demandesDTO.stream()
.filter(d -> d.getMontantAccorde() != null)
.map(DemandeAideDTO::getMontantAccorde)
.reduce(BigDecimal.ZERO, BigDecimal::add);
statistiques.setMontantTotalAide(montantTotal.toString() + " FCFA");
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des statistiques: " + e.getMessage());
statistiques.setTotalDemandes(0);
statistiques.setDemandesEnAttente(0);
statistiques.setDemandesApprouvees(0);
statistiques.setMontantTotalAide("0 FCFA");
}
} }
private void initializeEtapesWorkflow() { private void initializeEtapesWorkflow() {
@@ -101,83 +127,49 @@ public class DemandesAideBean implements Serializable {
private void initializeDemandes() { private void initializeDemandes() {
toutesLesDemandes = new ArrayList<>(); toutesLesDemandes = new ArrayList<>();
String[] demandeurs = { try {
"Jean Kouassi", "Marie Traoré", "Ahmed Diallo", "Fatou Sanogo", "Paul Ouattara", List<DemandeAideDTO> demandesDTO = demandeAideService.listerToutes(0, 1000);
"Aissata Koné", "Ibrahim Touré", "Aminata Bakayoko", "Yves Koffi", "Mariam Coulibaly", for (DemandeAideDTO dto : demandesDTO) {
"Seydou Cissé", "Adjoa Mensah", "Kwame Asante", "Ama Gyamfi", "Kofi Adjei", DemandeAide demande = convertToDemandeAide(dto);
"Nana Akoto", "Akosua Boateng", "Emmanuel Ofori", "Joyce Owusu", "Stephen Asamoah"
};
String[] types = {
"AIDE_MEDICALE", "AIDE_ALIMENTAIRE", "AIDE_EDUCATIVE", "AIDE_LOGEMENT", "AIDE_URGENCE"
};
String[] statuts = {
"EN_ATTENTE", "EN_EVALUATION", "APPROUVEE", "REJETEE", "EN_COURS", "TERMINEE"
};
String[] urgences = {
"FAIBLE", "NORMALE", "ELEVEE", "CRITIQUE"
};
String[] localisations = {
"Zone Urbaine Centre", "Quartier Résidentiel Nord", "Zone Rurale Sud",
"Quartier Populaire Est", "Zone Industrielle Ouest", "Centre-Ville",
"Banlieue Nord", "Périphérie Sud", "Zone Commerciale", "Quartier Administratif"
};
String[] motifs = {
"Soins médicaux d'urgence", "Aide alimentaire famille nombreuse", "Frais de scolarité",
"Réparation logement suite inondation", "Urgence médicale enfant", "Soutien alimentaire mensuel",
"Achat fournitures scolaires", "Paiement loyer en retard", "Intervention chirurgicale",
"Aide nutritionnelle nourrisson", "Formation professionnelle", "Réhabilitation habitat",
"Traitement médical chronique", "Complément alimentaire", "Équipement scolaire"
};
for (int i = 0; i < 50; i++) {
DemandeAide demande = new DemandeAide();
demande.setId((long) (i + 1));
demande.setDemandeur(demandeurs[i % demandeurs.length]);
demande.setTelephone("77 123 45 " + String.format("%02d", (i % 99) + 1));
demande.setEmail(demandeurs[i % demandeurs.length].toLowerCase().replace(" ", ".") + "@email.com");
demande.setType(types[i % types.length]);
demande.setStatut(statuts[i % statuts.length]);
demande.setUrgence(urgences[i % urgences.length]);
demande.setLocalisation(localisations[i % localisations.length]);
demande.setMotif(motifs[i % motifs.length]);
demande.setDescription("Description détaillée pour " + motifs[i % motifs.length] + ". Situation nécessitant une évaluation approfondie.");
// Montants
BigDecimal montantBase = new BigDecimal(50000 + (i * 15000));
demande.setMontantDemande(montantBase);
if (demande.getStatut().equals("APPROUVEE") || demande.getStatut().equals("EN_COURS") || demande.getStatut().equals("TERMINEE")) {
demande.setMontantAccorde(montantBase.multiply(new BigDecimal("0.8")));
}
// Dates
demande.setDateDemande(LocalDate.now().minusDays(i + 1));
if (i % 4 == 0) {
demande.setDateLimite(LocalDate.now().plusDays(7 + (i % 14)));
}
// Responsable de traitement
if (!demande.getStatut().equals("EN_ATTENTE")) {
String[] responsables = {"Sarah Mensah", "David Konaté", "Grace Asante", "Michel Diallo", "Rita Kouassi"};
demande.setResponsableTraitement(responsables[i % responsables.length]);
}
toutesLesDemandes.add(demande); toutesLesDemandes.add(demande);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des demandes d'aide: " + e.getMessage());
}
}
private DemandeAide convertToDemandeAide(DemandeAideDTO dto) {
DemandeAide demande = new DemandeAide();
demande.setId(dto.getId());
demande.setDemandeur(dto.getDemandeur());
demande.setTelephone(dto.getTelephone());
demande.setEmail(dto.getEmail());
demande.setType(dto.getType());
demande.setStatut(dto.getStatut());
demande.setUrgence(dto.getUrgence());
demande.setLocalisation(dto.getLocalisation());
demande.setMotif(dto.getMotif() != null ? dto.getMotif() : dto.getTitre());
demande.setDescription(dto.getDescription());
demande.setMontantDemande(dto.getMontantDemande());
demande.setMontantAccorde(dto.getMontantAccorde());
demande.setDateDemande(dto.getDateDemande());
demande.setDateLimite(dto.getDateLimite());
demande.setResponsableTraitement(dto.getResponsableTraitement());
return demande;
} }
private void initializeDemandesPrioritaires() { private void initializeDemandesPrioritaires() {
demandesPrioritaires = toutesLesDemandes.stream() try {
.filter(d -> d.getUrgence().equals("CRITIQUE") || d.getUrgence().equals("ELEVEE")) List<DemandeAideDTO> demandesDTO = demandeAideService.rechercher("EN_ATTENTE", null, "CRITIQUE", 0, 6);
demandesPrioritaires = demandesDTO.stream()
.map(this::convertToDemandeAide)
.filter(d -> !d.getStatut().equals("TERMINEE") && !d.getStatut().equals("REJETEE")) .filter(d -> !d.getStatut().equals("TERMINEE") && !d.getStatut().equals("REJETEE"))
.sorted((d1, d2) -> d1.getDateDemande().compareTo(d2.getDateDemande()))
.limit(6) .limit(6)
.collect(Collectors.toList()); .collect(Collectors.toList());
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des demandes prioritaires: " + e.getMessage());
demandesPrioritaires = new ArrayList<>();
}
} }
private void initializeNouvelleDemande() { private void initializeNouvelleDemande() {
@@ -250,7 +242,7 @@ public class DemandesAideBean implements Serializable {
public void creerDemande() { public void creerDemande() {
DemandeAide nouvelleDem = new DemandeAide(); DemandeAide nouvelleDem = new DemandeAide();
nouvelleDem.setId((long) (toutesLesDemandes.size() + 1)); nouvelleDem.setId(UUID.randomUUID());
nouvelleDem.setDemandeur(nouvelleDemande.getDemandeur()); nouvelleDem.setDemandeur(nouvelleDemande.getDemandeur());
nouvelleDem.setTelephone(nouvelleDemande.getTelephone()); nouvelleDem.setTelephone(nouvelleDemande.getTelephone());
nouvelleDem.setEmail(nouvelleDemande.getEmail()); nouvelleDem.setEmail(nouvelleDemande.getEmail());
@@ -268,7 +260,7 @@ public class DemandesAideBean implements Serializable {
appliquerFiltres(); appliquerFiltres();
initializeDemandesPrioritaires(); initializeDemandesPrioritaires();
System.out.println("Nouvelle demande d'aide créée pour: " + nouvelleDem.getDemandeur()); LOGGER.info("Nouvelle demande d'aide créée pour: " + nouvelleDem.getDemandeur());
initializeNouvelleDemande(); initializeNouvelleDemande();
} }
@@ -278,7 +270,7 @@ public class DemandesAideBean implements Serializable {
if (demandeSelectionnee.getMontantAccorde() == null) { if (demandeSelectionnee.getMontantAccorde() == null) {
demandeSelectionnee.setMontantAccorde(demandeSelectionnee.getMontantDemande().multiply(new BigDecimal("0.8"))); demandeSelectionnee.setMontantAccorde(demandeSelectionnee.getMontantDemande().multiply(new BigDecimal("0.8")));
} }
System.out.println("Demande approuvée pour: " + demandeSelectionnee.getDemandeur()); LOGGER.info("Demande approuvée pour: " + demandeSelectionnee.getDemandeur());
appliquerFiltres(); appliquerFiltres();
initializeDemandesPrioritaires(); initializeDemandesPrioritaires();
} }
@@ -287,7 +279,7 @@ public class DemandesAideBean implements Serializable {
public void rejeterDemande() { public void rejeterDemande() {
if (demandeSelectionnee != null) { if (demandeSelectionnee != null) {
demandeSelectionnee.setStatut("REJETEE"); demandeSelectionnee.setStatut("REJETEE");
System.out.println("Demande rejetée pour: " + demandeSelectionnee.getDemandeur()); LOGGER.info("Demande rejetée pour: " + demandeSelectionnee.getDemandeur());
appliquerFiltres(); appliquerFiltres();
initializeDemandesPrioritaires(); initializeDemandesPrioritaires();
} }
@@ -298,13 +290,13 @@ public class DemandesAideBean implements Serializable {
} }
public void envoyerNotification() { public void envoyerNotification() {
System.out.println("Notification envoyée pour la demande de: " + demandeSelectionnee.getDemandeur()); LOGGER.info("Notification envoyée pour la demande de: " + demandeSelectionnee.getDemandeur());
} }
public void dupliquerDemande() { public void dupliquerDemande() {
if (demandeSelectionnee != null) { if (demandeSelectionnee != null) {
DemandeAide copie = new DemandeAide(); DemandeAide copie = new DemandeAide();
copie.setId((long) (toutesLesDemandes.size() + 1)); copie.setId(UUID.randomUUID());
copie.setDemandeur(demandeSelectionnee.getDemandeur()); copie.setDemandeur(demandeSelectionnee.getDemandeur());
copie.setTelephone(demandeSelectionnee.getTelephone()); copie.setTelephone(demandeSelectionnee.getTelephone());
copie.setEmail(demandeSelectionnee.getEmail()); copie.setEmail(demandeSelectionnee.getEmail());
@@ -319,12 +311,12 @@ public class DemandesAideBean implements Serializable {
toutesLesDemandes.add(copie); toutesLesDemandes.add(copie);
appliquerFiltres(); appliquerFiltres();
System.out.println("Demande dupliquée pour: " + copie.getDemandeur()); LOGGER.info("Demande dupliquée pour: " + copie.getDemandeur());
} }
} }
public void exporterDemandes() { public void exporterDemandes() {
System.out.println("Export de " + demandesFiltrees.size() + " demandes d'aide"); LOGGER.info("Export de " + demandesFiltrees.size() + " demandes d'aide");
} }
// Getters et Setters // Getters et Setters
@@ -357,7 +349,7 @@ public class DemandesAideBean implements Serializable {
// Classes internes // Classes internes
public static class DemandeAide { public static class DemandeAide {
private Long id; private UUID id;
private String demandeur; private String demandeur;
private String telephone; private String telephone;
private String email; private String email;
@@ -374,8 +366,8 @@ public class DemandesAideBean implements Serializable {
private String responsableTraitement; private String responsableTraitement;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getDemandeur() { return demandeur; } public String getDemandeur() { return demandeur; }
public void setDemandeur(String demandeur) { this.demandeur = demandeur; } public void setDemandeur(String demandeur) { this.demandeur = demandeur; }

View File

@@ -10,13 +10,16 @@ import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.logging.Logger;
@Named("demandeBean") @Named("demandeBean")
@SessionScoped @SessionScoped
public class DemandesBean implements Serializable { public class DemandesBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(DemandesBean.class.getName());
private List<Demande> demandes; private List<Demande> demandes;
private List<Demande> selectedDemandes; private List<Demande> selectedDemandes;
@@ -35,7 +38,7 @@ public class DemandesBean implements Serializable {
private LocalDate dateFilter; private LocalDate dateFilter;
// Assignation en lot // Assignation en lot
private Long gestionnaireAssignation; private UUID gestionnaireAssignation;
private String commentaireAssignation; private String commentaireAssignation;
// Statistiques // Statistiques
@@ -68,7 +71,7 @@ public class DemandesBean implements Serializable {
for (int i = 0; i < objets.length; i++) { for (int i = 0; i < objets.length; i++) {
Demande demande = new Demande(); Demande demande = new Demande();
demande.setId((long) (i + 1)); demande.setId(UUID.fromString(String.format("00000000-0000-0000-0000-%012d", i + 1)));
demande.setReference("DEM-2024-" + String.format("%04d", i + 1)); demande.setReference("DEM-2024-" + String.format("%04d", i + 1));
demande.setObjet(objets[i]); demande.setObjet(objets[i]);
demande.setType(types[i]); demande.setType(types[i]);
@@ -97,9 +100,9 @@ public class DemandesBean implements Serializable {
private void initializeGestionnaires() { private void initializeGestionnaires() {
gestionnairesDisponibles = new ArrayList<>(); gestionnairesDisponibles = new ArrayList<>();
gestionnairesDisponibles.add(new Gestionnaire(1L, "Marie Gestionnaire")); gestionnairesDisponibles.add(new Gestionnaire(UUID.fromString("00000000-0000-0000-0000-000000000500"), "Marie Gestionnaire"));
gestionnairesDisponibles.add(new Gestionnaire(2L, "Paul Superviseur")); gestionnairesDisponibles.add(new Gestionnaire(UUID.fromString("00000000-0000-0000-0000-000000000600"), "Paul Superviseur"));
gestionnairesDisponibles.add(new Gestionnaire(3L, "Fatou Responsable")); gestionnairesDisponibles.add(new Gestionnaire(UUID.fromString("00000000-0000-0000-0000-000000000700"), "Fatou Responsable"));
} }
private void initializeNouvelleDemande() { private void initializeNouvelleDemande() {
@@ -115,7 +118,7 @@ public class DemandesBean implements Serializable {
for (int i = 0; i < noms.length; i++) { for (int i = 0; i < noms.length; i++) {
if (noms[i].toLowerCase().contains(query.toLowerCase())) { if (noms[i].toLowerCase().contains(query.toLowerCase())) {
Membre membre = new Membre(); Membre membre = new Membre();
membre.setId((long) (i + 1)); membre.setId(UUID.fromString(String.format("00000000-0000-0000-0000-%012d", i + 1)));
membre.setNomComplet(noms[i]); membre.setNomComplet(noms[i]);
membre.setNumeroMembre("M" + String.format("%06d", 1000 + i)); membre.setNumeroMembre("M" + String.format("%06d", 1000 + i));
resultats.add(membre); resultats.add(membre);
@@ -128,60 +131,60 @@ public class DemandesBean implements Serializable {
// Actions // Actions
public void voirDemande(Demande demande) { public void voirDemande(Demande demande) {
this.demandeSelectionnee = demande; this.demandeSelectionnee = demande;
System.out.println("Voir demande: " + demande.getObjet()); LOGGER.info("Voir demande: " + demande.getObjet());
} }
public void traiterDemande(Demande demande) { public void traiterDemande(Demande demande) {
demande.setStatut("EN_COURS"); demande.setStatut("EN_COURS");
System.out.println("Traitement demande: " + demande.getObjet()); LOGGER.info("Traitement demande: " + demande.getObjet());
} }
public void approuverDemande(Demande demande) { public void approuverDemande(Demande demande) {
demande.setStatut("APPROUVEE"); demande.setStatut("APPROUVEE");
System.out.println("Demande approuvée: " + demande.getObjet()); LOGGER.info("Demande approuvée: " + demande.getObjet());
} }
public void rejeterDemande(Demande demande) { public void rejeterDemande(Demande demande) {
demande.setStatut("REJETEE"); demande.setStatut("REJETEE");
System.out.println("Demande rejetée: " + demande.getObjet()); LOGGER.info("Demande rejetée: " + demande.getObjet());
} }
public void assignerDemande(Demande demande) { public void assignerDemande(Demande demande) {
System.out.println("Assigner demande: " + demande.getObjet()); LOGGER.info("Assigner demande: " + demande.getObjet());
} }
public void voirPiecesJointes(Demande demande) { public void voirPiecesJointes(Demande demande) {
System.out.println("Voir pièces jointes: " + demande.getObjet()); LOGGER.info("Voir pièces jointes: " + demande.getObjet());
} }
public void creerDemande() { public void creerDemande() {
System.out.println("Créer nouvelle demande: " + nouvelleDemande.getObjet()); LOGGER.info("Créer nouvelle demande: " + nouvelleDemande.getObjet());
initializeNouvelleDemande(); initializeNouvelleDemande();
} }
public void effectuerAssignationLot() { public void effectuerAssignationLot() {
System.out.println("Assignation en lot à gestionnaire ID: " + gestionnaireAssignation); LOGGER.info("Assignation en lot à gestionnaire ID: " + gestionnaireAssignation);
} }
public void marquerTraitees() { public void marquerTraitees() {
selectedDemandes.forEach(d -> d.setStatut("TRAITEE")); selectedDemandes.forEach(d -> d.setStatut("TRAITEE"));
System.out.println("Marquées comme traitées: " + selectedDemandes.size()); LOGGER.info("Marquées comme traitées: " + selectedDemandes.size());
} }
public void exporterSelection() { public void exporterSelection() {
System.out.println("Export de " + selectedDemandes.size() + " demandes"); LOGGER.info("Export de " + selectedDemandes.size() + " demandes");
} }
public void exporterDemandes() { public void exporterDemandes() {
System.out.println("Export de toutes les demandes"); LOGGER.info("Export de toutes les demandes");
} }
public void actualiser() { public void actualiser() {
System.out.println("Actualisation des données"); LOGGER.info("Actualisation des données");
} }
public void filtrerUrgentes() { public void filtrerUrgentes() {
System.out.println("Filtrer les demandes urgentes"); LOGGER.info("Filtrer les demandes urgentes");
} }
// Getters et Setters // Getters et Setters
@@ -221,8 +224,8 @@ public class DemandesBean implements Serializable {
public LocalDate getDateFilter() { return dateFilter; } public LocalDate getDateFilter() { return dateFilter; }
public void setDateFilter(LocalDate dateFilter) { this.dateFilter = dateFilter; } public void setDateFilter(LocalDate dateFilter) { this.dateFilter = dateFilter; }
public Long getGestionnaireAssignation() { return gestionnaireAssignation; } public UUID getGestionnaireAssignation() { return gestionnaireAssignation; }
public void setGestionnaireAssignation(Long gestionnaireAssignation) { this.gestionnaireAssignation = gestionnaireAssignation; } public void setGestionnaireAssignation(UUID gestionnaireAssignation) { this.gestionnaireAssignation = gestionnaireAssignation; }
public String getCommentaireAssignation() { return commentaireAssignation; } public String getCommentaireAssignation() { return commentaireAssignation; }
public void setCommentaireAssignation(String commentaireAssignation) { this.commentaireAssignation = commentaireAssignation; } public void setCommentaireAssignation(String commentaireAssignation) { this.commentaireAssignation = commentaireAssignation; }
@@ -244,7 +247,7 @@ public class DemandesBean implements Serializable {
// Classes internes // Classes internes
public static class Demande { public static class Demande {
private Long id; private UUID id;
private String reference; private String reference;
private String objet; private String objet;
private String type; private String type;
@@ -261,8 +264,8 @@ public class DemandesBean implements Serializable {
private boolean hasPiecesJointes = false; private boolean hasPiecesJointes = false;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getReference() { return reference; } public String getReference() { return reference; }
public void setReference(String reference) { this.reference = reference; } public void setReference(String reference) { this.reference = reference; }
@@ -396,12 +399,12 @@ public class DemandesBean implements Serializable {
} }
public static class Membre { public static class Membre {
private Long id; private UUID id;
private String nomComplet; private String nomComplet;
private String numeroMembre; private String numeroMembre;
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNomComplet() { return nomComplet; } public String getNomComplet() { return nomComplet; }
public void setNomComplet(String nomComplet) { this.nomComplet = nomComplet; } public void setNomComplet(String nomComplet) { this.nomComplet = nomComplet; }
@@ -422,7 +425,7 @@ public class DemandesBean implements Serializable {
private String priorite; private String priorite;
private String description; private String description;
private LocalDate dateEcheance; private LocalDate dateEcheance;
private Long assigneA; private UUID assigneA;
public String getObjet() { return objet; } public String getObjet() { return objet; }
public void setObjet(String objet) { this.objet = objet; } public void setObjet(String objet) { this.objet = objet; }
@@ -439,23 +442,23 @@ public class DemandesBean implements Serializable {
public LocalDate getDateEcheance() { return dateEcheance; } public LocalDate getDateEcheance() { return dateEcheance; }
public void setDateEcheance(LocalDate dateEcheance) { this.dateEcheance = dateEcheance; } public void setDateEcheance(LocalDate dateEcheance) { this.dateEcheance = dateEcheance; }
public Long getAssigneA() { return assigneA; } public UUID getAssigneA() { return assigneA; }
public void setAssigneA(Long assigneA) { this.assigneA = assigneA; } public void setAssigneA(UUID assigneA) { this.assigneA = assigneA; }
} }
public static class Gestionnaire { public static class Gestionnaire {
private Long id; private UUID id;
private String nom; private String nom;
public Gestionnaire() {} public Gestionnaire() {}
public Gestionnaire(Long id, String nom) { public Gestionnaire(UUID id, String nom) {
this.id = id; this.id = id;
this.nom = nom; this.nom = nom;
} }
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }

View File

@@ -10,6 +10,8 @@ import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Named("documentsBean") @Named("documentsBean")
@@ -17,6 +19,7 @@ import java.util.stream.Collectors;
public class DocumentsBean implements Serializable { public class DocumentsBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(DocumentsBean.class.getName());
private List<Document> tousLesDocuments; private List<Document> tousLesDocuments;
private List<Document> documentsFiltres; private List<Document> documentsFiltres;
@@ -32,7 +35,7 @@ public class DocumentsBean implements Serializable {
private StatistiquesDocuments statistiques; private StatistiquesDocuments statistiques;
private String modeAffichage = "GRID"; // GRID ou LIST private String modeAffichage = "GRID"; // GRID ou LIST
private Long dossierActuelId; private UUID dossierActuelId;
@PostConstruct @PostConstruct
public void init() { public void init() {
@@ -52,94 +55,33 @@ public class DocumentsBean implements Serializable {
private void initializeStatistiques() { private void initializeStatistiques() {
statistiques = new StatistiquesDocuments(); statistiques = new StatistiquesDocuments();
statistiques.setTotalDocuments(1847); try {
statistiques.setTotalDossiers(23); // Les statistiques seront calculées depuis les documents réels
statistiques.setEspaceUtilise("2.3 GB"); // Pour l'instant, initialiser avec des valeurs par défaut
statistiques.setPartagesMois(156); statistiques.setTotalDocuments(tousLesDocuments != null ? tousLesDocuments.size() : 0);
statistiques.setTotalDossiers(dossiersDisponibles != null ? dossiersDisponibles.size() : 0);
statistiques.setEspaceUtilise("0 GB");
statistiques.setPartagesMois(0);
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des statistiques: " + e.getMessage());
statistiques.setTotalDocuments(0);
statistiques.setTotalDossiers(0);
statistiques.setEspaceUtilise("0 GB");
statistiques.setPartagesMois(0);
}
} }
private void initializeDossiers() { private void initializeDossiers() {
dossiersAffichage = new ArrayList<>(); dossiersAffichage = new ArrayList<>();
dossiersDisponibles = new ArrayList<>(); dossiersDisponibles = new ArrayList<>();
// Les dossiers seront chargés depuis l'API backend
String[] nomsDossiers = { // Pour l'instant, laisser les listes vides plutôt que des données mockées
"Documents Administratifs", "Finances et Comptabilité", "Ressources Humaines",
"Communication", "Formations", "Projets et Actions", "Archives 2023",
"Modèles et Templates", "Rapports Mensuels", "Juridique et Conformité"
};
String[] couleurs = {
"blue-500", "green-500", "orange-500", "purple-500", "indigo-500",
"teal-500", "gray-500", "pink-500", "yellow-500", "red-500"
};
for (int i = 0; i < nomsDossiers.length; i++) {
Dossier dossier = new Dossier();
dossier.setId((long) (i + 1));
dossier.setNom(nomsDossiers[i]);
dossier.setCouleur(couleurs[i % couleurs.length]);
dossier.setNombreDocuments(15 + (i * 8));
dossier.setDerniereModification(LocalDateTime.now().minusDays(i + 1));
dossier.setCheminComplet("/" + nomsDossiers[i]);
dossiersAffichage.add(dossier);
dossiersDisponibles.add(dossier);
}
} }
private void initializeDocuments() { private void initializeDocuments() {
tousLesDocuments = new ArrayList<>(); tousLesDocuments = new ArrayList<>();
// Les documents seront chargés depuis l'API backend
String[] noms = { // Pour l'instant, laisser la liste vide plutôt que des données mockées
"Règlement Intérieur 2024.pdf", "Budget Prévisionnel Q1.xlsx", "Procès-Verbal AG Mars.docx",
"Guide Nouveau Membre.pdf", "Rapport Activités Janvier.docx", "Factures Fournisseurs Q4.xlsx",
"Statuts Association.pdf", "Plan Communication 2024.pptx", "Formation Leadership.pdf",
"Rapport Financier Annuel.pdf", "Convention Partenariat.docx", "Charte Graphique.pdf",
"Manuel Procédures.docx", "Bilan Social 2023.xlsx", "Certificat Conformité.pdf",
"Guide Utilisateur Plateforme.pdf", "Contrat Assurance.pdf", "Rapport Audit.docx",
"Plan Stratégique 3 ans.pptx", "Inventaire Matériel.xlsx", "Politique RGPD.pdf"
};
String[] types = {"PDF", "EXCEL", "WORD", "PDF", "WORD", "EXCEL", "PDF", "POWERPOINT", "PDF", "PDF", "WORD", "PDF", "WORD", "EXCEL", "PDF", "PDF", "PDF", "WORD", "POWERPOINT", "EXCEL", "PDF"};
String[] categories = {"ADMINISTRATIF", "FINANCIER", "ADMINISTRATIF", "FORMATION", "ADMINISTRATIF", "FINANCIER", "JURIDIQUE", "COMMUNICATION", "FORMATION", "FINANCIER", "JURIDIQUE", "COMMUNICATION", "ADMINISTRATIF", "FINANCIER", "JURIDIQUE", "FORMATION", "JURIDIQUE", "FINANCIER", "ADMINISTRATIF", "ADMINISTRATIF", "JURIDIQUE"};
String[] statuts = {"VALIDE", "VALIDE", "BROUILLON", "VALIDE", "VALIDE", "ARCHIVE", "VALIDE", "BROUILLON", "VALIDE", "VALIDE", "VALIDE", "VALIDE", "BROUILLON", "ARCHIVE", "VALIDE", "VALIDE", "VALIDE", "VALIDE", "BROUILLON", "VALIDE", "VALIDE"};
String[] auteurs = {"Marie Kouassi", "Paul Traoré", "Fatou Sanogo", "Jean Ouattara", "Aissata Koné", "Ibrahim Touré", "Aminata Bakayoko", "Yves Koffi", "Mariam Coulibaly", "Seydou Cissé", "Adjoa Mensah"};
long[] tailles = {2047000, 845000, 1250000, 3100000, 890000, 1450000, 567000, 2800000, 1900000, 3400000, 780000, 1200000, 1850000, 920000, 450000, 2200000, 890000, 1650000, 4200000, 680000, 750000};
for (int i = 0; i < noms.length; i++) {
Document document = new Document();
document.setId((long) (i + 1));
document.setNom(noms[i]);
document.setType(types[i]);
document.setCategorie(categories[i]);
document.setStatut(statuts[i]);
document.setAuteur(auteurs[i % auteurs.length]);
document.setTailleBytes(tailles[i]);
document.setDateCreation(LocalDateTime.now().minusDays(i * 3 + 1));
document.setDateModification(LocalDateTime.now().minusDays(i + 1));
document.setNombreVues(25 + (i * 7));
document.setNombreTelecharements(5 + (i * 2));
// Description automatique
document.setDescription("Document " + categories[i].toLowerCase() + " - " + noms[i]);
// Mots-clés automatiques
document.setMotsCles(generateMotsCles(categories[i], types[i]));
// Dossier parent (certains documents sont à la racine)
if (i % 3 != 0) {
document.setDossierId((long) ((i % dossiersDisponibles.size()) + 1));
}
tousLesDocuments.add(document);
}
}
private String generateMotsCles(String categorie, String type) {
String base = categorie.toLowerCase().replace("_", " ");
String typeClean = type.toLowerCase();
return base + ", " + typeClean + ", officiel, important";
} }
private void initializeNouveauDocument() { private void initializeNouveauDocument() {
@@ -270,7 +212,7 @@ public class DocumentsBean implements Serializable {
public void telechargerNouveauDocument() { public void telechargerNouveauDocument() {
Document nouveau = new Document(); Document nouveau = new Document();
nouveau.setId((long) (tousLesDocuments.size() + 1)); nouveau.setId(UUID.randomUUID());
nouveau.setNom("Nouveau Document " + (tousLesDocuments.size() + 1)); nouveau.setNom("Nouveau Document " + (tousLesDocuments.size() + 1));
nouveau.setCategorie(nouveauDocument.getCategorie()); nouveau.setCategorie(nouveauDocument.getCategorie());
nouveau.setDescription(nouveauDocument.getDescription()); nouveau.setDescription(nouveauDocument.getDescription());
@@ -288,25 +230,25 @@ public class DocumentsBean implements Serializable {
tousLesDocuments.add(nouveau); tousLesDocuments.add(nouveau);
appliquerFiltres(); appliquerFiltres();
System.out.println("Document téléchargé: " + nouveau.getNom()); LOGGER.info("Document téléchargé: " + nouveau.getNom());
initializeNouveauDocument(); initializeNouveauDocument();
} }
public void telechargerDocument(Document document) { public void telechargerDocument(Document document) {
document.setNombreTelecharements(document.getNombreTelecharements() + 1); document.setNombreTelecharements(document.getNombreTelecharements() + 1);
System.out.println("Téléchargement du document: " + document.getNom()); LOGGER.info("Téléchargement du document: " + document.getNom());
} }
public void supprimerDocument(Document document) { public void supprimerDocument(Document document) {
tousLesDocuments.remove(document); tousLesDocuments.remove(document);
appliquerFiltres(); appliquerFiltres();
System.out.println("Document supprimé: " + document.getNom()); LOGGER.info("Document supprimé: " + document.getNom());
} }
public void dupliquerDocument() { public void dupliquerDocument() {
if (documentSelectionne != null) { if (documentSelectionne != null) {
Document copie = new Document(); Document copie = new Document();
copie.setId((long) (tousLesDocuments.size() + 1)); copie.setId(UUID.randomUUID());
copie.setNom(documentSelectionne.getNom() + " (Copie)"); copie.setNom(documentSelectionne.getNom() + " (Copie)");
copie.setType(documentSelectionne.getType()); copie.setType(documentSelectionne.getType());
copie.setCategorie(documentSelectionne.getCategorie()); copie.setCategorie(documentSelectionne.getCategorie());
@@ -323,14 +265,14 @@ public class DocumentsBean implements Serializable {
tousLesDocuments.add(copie); tousLesDocuments.add(copie);
appliquerFiltres(); appliquerFiltres();
System.out.println("Document dupliqué: " + copie.getNom()); LOGGER.info("Document dupliqué: " + copie.getNom());
} }
} }
public void archiverDocument() { public void archiverDocument() {
if (documentSelectionne != null) { if (documentSelectionne != null) {
documentSelectionne.setStatut("ARCHIVE"); documentSelectionne.setStatut("ARCHIVE");
System.out.println("Document archivé: " + documentSelectionne.getNom()); LOGGER.info("Document archivé: " + documentSelectionne.getNom());
appliquerFiltres(); appliquerFiltres();
} }
} }
@@ -339,7 +281,7 @@ public class DocumentsBean implements Serializable {
if (documentSelectionne != null) { if (documentSelectionne != null) {
tousLesDocuments.remove(documentSelectionne); tousLesDocuments.remove(documentSelectionne);
appliquerFiltres(); appliquerFiltres();
System.out.println("Document supprimé définitivement: " + documentSelectionne.getNom()); LOGGER.info("Document supprimé définitivement: " + documentSelectionne.getNom());
} }
} }
@@ -396,12 +338,12 @@ public class DocumentsBean implements Serializable {
public String getModeAffichage() { return modeAffichage; } public String getModeAffichage() { return modeAffichage; }
public void setModeAffichage(String modeAffichage) { this.modeAffichage = modeAffichage; } public void setModeAffichage(String modeAffichage) { this.modeAffichage = modeAffichage; }
public Long getDossierActuelId() { return dossierActuelId; } public UUID getDossierActuelId() { return dossierActuelId; }
public void setDossierActuelId(Long dossierActuelId) { this.dossierActuelId = dossierActuelId; } public void setDossierActuelId(UUID dossierActuelId) { this.dossierActuelId = dossierActuelId; }
// Classes internes // Classes internes
public static class Document { public static class Document {
private Long id; private UUID id;
private String nom; private String nom;
private String description; private String description;
private String type; private String type;
@@ -409,7 +351,7 @@ public class DocumentsBean implements Serializable {
private String statut; private String statut;
private String auteur; private String auteur;
private String motsCles; private String motsCles;
private Long dossierId; private UUID dossierId;
private long tailleBytes; private long tailleBytes;
private LocalDateTime dateCreation; private LocalDateTime dateCreation;
private LocalDateTime dateModification; private LocalDateTime dateModification;
@@ -418,8 +360,8 @@ public class DocumentsBean implements Serializable {
private boolean accesRestreint; private boolean accesRestreint;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }
@@ -442,8 +384,8 @@ public class DocumentsBean implements Serializable {
public String getMotsCles() { return motsCles; } public String getMotsCles() { return motsCles; }
public void setMotsCles(String motsCles) { this.motsCles = motsCles; } public void setMotsCles(String motsCles) { this.motsCles = motsCles; }
public Long getDossierId() { return dossierId; } public UUID getDossierId() { return dossierId; }
public void setDossierId(Long dossierId) { this.dossierId = dossierId; } public void setDossierId(UUID dossierId) { this.dossierId = dossierId; }
public long getTailleBytes() { return tailleBytes; } public long getTailleBytes() { return tailleBytes; }
public void setTailleBytes(long tailleBytes) { this.tailleBytes = tailleBytes; } public void setTailleBytes(long tailleBytes) { this.tailleBytes = tailleBytes; }
@@ -557,7 +499,7 @@ public class DocumentsBean implements Serializable {
} }
public static class Dossier { public static class Dossier {
private Long id; private UUID id;
private String nom; private String nom;
private String couleur; private String couleur;
private int nombreDocuments; private int nombreDocuments;
@@ -565,8 +507,8 @@ public class DocumentsBean implements Serializable {
private String cheminComplet; private String cheminComplet;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }
@@ -596,7 +538,7 @@ public class DocumentsBean implements Serializable {
private String categorie; private String categorie;
private String description; private String description;
private String motsCles; private String motsCles;
private Long dossierId; private UUID dossierId;
private boolean accesRestreint; private boolean accesRestreint;
// Getters et setters // Getters et setters
@@ -609,8 +551,8 @@ public class DocumentsBean implements Serializable {
public String getMotsCles() { return motsCles; } public String getMotsCles() { return motsCles; }
public void setMotsCles(String motsCles) { this.motsCles = motsCles; } public void setMotsCles(String motsCles) { this.motsCles = motsCles; }
public Long getDossierId() { return dossierId; } public UUID getDossierId() { return dossierId; }
public void setDossierId(Long dossierId) { this.dossierId = dossierId; } public void setDossierId(UUID dossierId) { this.dossierId = dossierId; }
public boolean isAccesRestreint() { return accesRestreint; } public boolean isAccesRestreint() { return accesRestreint; }
public void setAccesRestreint(boolean accesRestreint) { this.accesRestreint = accesRestreint; } public void setAccesRestreint(boolean accesRestreint) { this.accesRestreint = accesRestreint; }
@@ -678,13 +620,13 @@ public class DocumentsBean implements Serializable {
public static class NiveauNavigation { public static class NiveauNavigation {
private String nom; private String nom;
private Long dossierId; private UUID dossierId;
// Getters et setters // Getters et setters
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }
public Long getDossierId() { return dossierId; } public UUID getDossierId() { return dossierId; }
public void setDossierId(Long dossierId) { this.dossierId = dossierId; } public void setDossierId(UUID dossierId) { this.dossierId = dossierId; }
} }
} }

View File

@@ -1,8 +1,12 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.AssociationDTO;
import dev.lions.unionflow.client.service.AssociationService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -10,13 +14,20 @@ import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.logging.Logger;
@Named("entitesGestionBean") @Named("entitesGestionBean")
@SessionScoped @SessionScoped
public class EntitesGestionBean implements Serializable { public class EntitesGestionBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(EntitesGestionBean.class.getName());
@Inject
@RestClient
private AssociationService associationService;
private List<Entite> toutesLesEntites; private List<Entite> toutesLesEntites;
private List<Entite> entitesFiltrees; private List<Entite> entitesFiltrees;
@@ -42,78 +53,72 @@ public class EntitesGestionBean implements Serializable {
private void initializeStatistiques() { private void initializeStatistiques() {
statistiques = new Statistiques(); statistiques = new Statistiques();
statistiques.setTotalEntites(127); // Nouvelle stratégie volume try {
statistiques.setEntitesActives(127); List<AssociationDTO> associations = associationService.listerToutes();
statistiques.setTotalMembres(18547); // 146 membres/organisation en moyenne statistiques.setTotalEntites(associations.size());
statistiques.setMoyenneMembresParEntite(146); // Moyenne calculée long actives = associations.stream().filter(a -> "ACTIVE".equals(a.getStatut())).count();
statistiques.setRevenus("363 000 FCFA"); statistiques.setEntitesActives((int) actives);
statistiques.setSouscriptionsExpirantes(12); int totalMembres = associations.stream()
statistiques.setEntitesQuotaAtteint(8); .mapToInt(a -> a.getNombreMembres() != null ? a.getNombreMembres() : 0)
.sum();
statistiques.setTotalMembres(totalMembres);
double moyenne = associations.isEmpty() ? 0 : (double) totalMembres / associations.size();
statistiques.setMoyenneMembresParEntite((int) moyenne);
statistiques.setRevenus("0 FCFA"); // À calculer depuis les souscriptions
statistiques.setSouscriptionsExpirantes(0); // À calculer
statistiques.setEntitesQuotaAtteint(0); // À calculer
statistiques.setFormulairePopulaire("Standard"); statistiques.setFormulairePopulaire("Standard");
statistiques.setTauxRenouvellement(94.2f); statistiques.setTauxRenouvellement(94.2f);
} catch (Exception e) {
// Calcul dynamique des statistiques de souscription LOGGER.severe("Erreur lors du calcul des statistiques: " + e.getMessage());
statistiques.setTotalEntites(0);
statistiques.setEntitesActives(0);
statistiques.setTotalMembres(0);
statistiques.setMoyenneMembresParEntite(0);
}
calculerStatistiquesSouscriptions(); calculerStatistiquesSouscriptions();
} }
private void initializeEntites() { private void initializeEntites() {
toutesLesEntites = new ArrayList<>(); toutesLesEntites = new ArrayList<>();
try {
List<AssociationDTO> associations = associationService.listerToutes();
for (AssociationDTO dto : associations) {
Entite entite = convertToEntite(dto);
toutesLesEntites.add(entite);
}
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des entités: " + e.getMessage());
}
}
// Génération de données de test private Entite convertToEntite(AssociationDTO dto) {
String[] noms = {
"Association Alpha Centrale", "Club Beta Régional", "Groupe Gamma Local",
"Association Delta Nord", "Club Epsilon Sud", "Groupe Zeta Jeunes",
"Association Eta Ouest", "Club Theta Est", "Groupe Iota Centre",
"Association Kappa Métropole", "Branche Féminine Lambda", "Club Mu Urbain",
"Groupe Jeunes Nu", "Association Xi Rural", "Club Omicron Mixte"
};
String[] types = {
"ASSOCIATION", "CLUB", "GROUPE", "ASSOCIATION", "CLUB", "GROUPE_JEUNES",
"ASSOCIATION", "CLUB", "GROUPE", "ASSOCIATION", "BRANCHE", "CLUB",
"GROUPE_JEUNES", "ASSOCIATION", "CLUB"
};
String[] regions = {
"REGION_1", "REGION_2", "REGION_3", "REGION_4", "REGION_5", "REGION_1",
"REGION_6", "REGION_7", "REGION_8", "REGION_9", "REGION_1", "REGION_10",
"REGION_2", "REGION_11", "REGION_12"
};
String[] statuts = {
"ACTIVE", "ACTIVE", "ACTIVE", "ACTIVE", "ACTIVE", "ACTIVE",
"ACTIVE", "SUSPENDUE", "ACTIVE", "ACTIVE", "ACTIVE", "INACTIVE",
"ACTIVE", "ACTIVE", "ACTIVE"
};
int[] nombresMembres = {156, 123, 98, 87, 73, 45, 67, 0, 54, 43, 32, 0, 28, 38, 51};
for (int i = 0; i < noms.length; i++) {
Entite entite = new Entite(); Entite entite = new Entite();
entite.setId((long) (i + 1)); entite.setId(dto.getId());
entite.setNom(noms[i]); entite.setNom(dto.getNom());
entite.setCodeEntite("ENT" + String.format("%03d", i + 1)); entite.setCodeEntite(dto.getNumeroRegistre());
entite.setType(types[i]); entite.setType(dto.getTypeAssociation());
entite.setRegion(regions[i]); entite.setRegion(dto.getRegion());
entite.setStatut(statuts[i]); entite.setStatut(dto.getStatut());
entite.setNombreMembres(nombresMembres[i]); entite.setNombreMembres(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0);
entite.setMembresUtilises(nombresMembres[i]); entite.setMembresUtilises(dto.getNombreMembres() != null ? dto.getNombreMembres() : 0);
entite.setAdresse("Adresse " + noms[i]); entite.setAdresse(dto.getAdresse());
entite.setTelephone("77 123 45 " + String.format("%02d", i + 1)); entite.setTelephone(dto.getTelephone());
entite.setEmail(noms[i].toLowerCase().replace(" ", ".") + "@unionflow.app"); entite.setEmail(dto.getEmail());
entite.setDescription("Description de " + noms[i]); entite.setDescription(dto.getDescription());
entite.setDerniereActivite(LocalDateTime.now().minusDays(i * 2 + 1)); entite.setDerniereActivite(dto.getDateDerniereActivite());
// Définir le forfait selon le nombre de membres // Définir le forfait selon le nombre de membres
if (nombresMembres[i] <= 100) { int nbMembres = dto.getNombreMembres() != null ? dto.getNombreMembres() : 0;
if (nbMembres <= 100) {
entite.setForfaitSouscrit("Starter"); entite.setForfaitSouscrit("Starter");
entite.setMembresQuota(100); entite.setMembresQuota(100);
entite.setMontantMensuel("2 000 FCFA"); entite.setMontantMensuel("2 000 FCFA");
} else if (nombresMembres[i] <= 200) { } else if (nbMembres <= 200) {
entite.setForfaitSouscrit("Standard"); entite.setForfaitSouscrit("Standard");
entite.setMembresQuota(200); entite.setMembresQuota(200);
entite.setMontantMensuel("3 000 FCFA"); entite.setMontantMensuel("3 000 FCFA");
} else if (nombresMembres[i] <= 500) { } else if (nbMembres <= 500) {
entite.setForfaitSouscrit("Premium"); entite.setForfaitSouscrit("Premium");
entite.setMembresQuota(500); entite.setMembresQuota(500);
entite.setMontantMensuel("4 000 FCFA"); entite.setMontantMensuel("4 000 FCFA");
@@ -123,19 +128,7 @@ public class EntitesGestionBean implements Serializable {
entite.setMontantMensuel("5 000 FCFA"); entite.setMontantMensuel("5 000 FCFA");
} }
// Date d'expiration (varie entre 1 mois et 11 mois) return entite;
entite.setDateExpirationSouscription(LocalDate.now().plusMonths(1 + (i % 11)));
// Administrateur
if (nombresMembres[i] > 0) {
Administrateur admin = new Administrateur();
admin.setNomComplet("Admin " + (i + 1));
admin.setEmail("admin" + (i + 1) + "@unionflow.app");
entite.setAdministrateur(admin);
}
toutesLesEntites.add(entite);
}
} }
private void initializeNouvelleEntite() { private void initializeNouvelleEntite() {
@@ -229,7 +222,7 @@ public class EntitesGestionBean implements Serializable {
} }
public void creerEntite() { public void creerEntite() {
nouvelleEntite.setId((long) (toutesLesEntites.size() + 1)); nouvelleEntite.setId(UUID.randomUUID());
nouvelleEntite.setCodeEntite("ENT" + String.format("%03d", toutesLesEntites.size() + 1)); nouvelleEntite.setCodeEntite("ENT" + String.format("%03d", toutesLesEntites.size() + 1));
nouvelleEntite.setStatut("ACTIVE"); nouvelleEntite.setStatut("ACTIVE");
nouvelleEntite.setNombreMembres(0); nouvelleEntite.setNombreMembres(0);
@@ -238,7 +231,7 @@ public class EntitesGestionBean implements Serializable {
toutesLesEntites.add(nouvelleEntite); toutesLesEntites.add(nouvelleEntite);
appliquerFiltres(); appliquerFiltres();
System.out.println("Nouvelle entité créée: " + nouvelleEntite.getNom()); LOGGER.info("Nouvelle entité créée: " + nouvelleEntite.getNom());
initializeNouvelleEntite(); initializeNouvelleEntite();
} }
@@ -257,24 +250,24 @@ public class EntitesGestionBean implements Serializable {
public void suspendreEntite() { public void suspendreEntite() {
entiteSelectionne.setStatut("SUSPENDUE"); entiteSelectionne.setStatut("SUSPENDUE");
System.out.println("Entité suspendue: " + entiteSelectionne.getNom()); LOGGER.info("Entité suspendue: " + entiteSelectionne.getNom());
appliquerFiltres(); appliquerFiltres();
} }
public void reactiverEntite() { public void reactiverEntite() {
entiteSelectionne.setStatut("ACTIVE"); entiteSelectionne.setStatut("ACTIVE");
System.out.println("Entité réactivée: " + entiteSelectionne.getNom()); LOGGER.info("Entité réactivée: " + entiteSelectionne.getNom());
appliquerFiltres(); appliquerFiltres();
} }
public void supprimerEntite() { public void supprimerEntite() {
toutesLesEntites.remove(entiteSelectionne); toutesLesEntites.remove(entiteSelectionne);
System.out.println("Entité supprimée: " + entiteSelectionne.getNom()); LOGGER.info("Entité supprimée: " + entiteSelectionne.getNom());
appliquerFiltres(); appliquerFiltres();
} }
public void exporterEntites() { public void exporterEntites() {
System.out.println("Export de " + entitesFiltrees.size() + " entités"); LOGGER.info("Export de " + entitesFiltrees.size() + " entités");
} }
// Getters et Setters // Getters et Setters
@@ -325,7 +318,7 @@ public class EntitesGestionBean implements Serializable {
if (entiteSelectionne != null) { if (entiteSelectionne != null) {
entiteSelectionne.setDateExpirationSouscription(LocalDate.now().plusMonths(12)); entiteSelectionne.setDateExpirationSouscription(LocalDate.now().plusMonths(12));
entiteSelectionne.setStatutSouscription("ACTIVE"); entiteSelectionne.setStatutSouscription("ACTIVE");
System.out.println("Souscription renouvelée pour: " + entiteSelectionne.getNom()); LOGGER.info("Souscription renouvelée pour: " + entiteSelectionne.getNom());
appliquerFiltres(); appliquerFiltres();
} }
} }
@@ -350,24 +343,24 @@ public class EntitesGestionBean implements Serializable {
entiteSelectionne.setMontantMensuel("5 000 FCFA"); entiteSelectionne.setMontantMensuel("5 000 FCFA");
break; break;
} }
System.out.println("Forfait upgradé pour: " + entiteSelectionne.getNom()); LOGGER.info("Forfait upgradé pour: " + entiteSelectionne.getNom());
appliquerFiltres(); appliquerFiltres();
} }
} }
public void gererQuotas() { public void gererQuotas() {
System.out.println("Gestion des quotas pour toutes les entités"); LOGGER.info("Gestion des quotas pour toutes les entités");
} }
public void envoyerRelancesSouscriptions() { public void envoyerRelancesSouscriptions() {
int compteur = 0; int compteur = 0;
for (Entite entite : toutesLesEntites) { for (Entite entite : toutesLesEntites) {
if (entite.isExpirationProche()) { if (entite.isExpirationProche()) {
System.out.println("Relance envoyée à: " + entite.getNom()); LOGGER.info("Relance envoyée à: " + entite.getNom());
compteur++; compteur++;
} }
} }
System.out.println(compteur + " relances de souscription envoyées"); LOGGER.info(compteur + " relances de souscription envoyées");
} }
// Actions groupées // Actions groupées
@@ -378,7 +371,7 @@ public class EntitesGestionBean implements Serializable {
entite.setStatutSouscription("ACTIVE"); entite.setStatutSouscription("ACTIVE");
compteur++; compteur++;
} }
System.out.println(compteur + " souscriptions renouvelées en masse"); LOGGER.info(compteur + " souscriptions renouvelées en masse");
entitesSelectionnees.clear(); entitesSelectionnees.clear();
appliquerFiltres(); appliquerFiltres();
} }
@@ -389,7 +382,7 @@ public class EntitesGestionBean implements Serializable {
entite.setStatut("SUSPENDUE"); entite.setStatut("SUSPENDUE");
compteur++; compteur++;
} }
System.out.println(compteur + " entités suspendues en masse"); LOGGER.info(compteur + " entités suspendues en masse");
entitesSelectionnees.clear(); entitesSelectionnees.clear();
appliquerFiltres(); appliquerFiltres();
} }
@@ -400,7 +393,7 @@ public class EntitesGestionBean implements Serializable {
entite.setStatut("ACTIVE"); entite.setStatut("ACTIVE");
compteur++; compteur++;
} }
System.out.println(compteur + " entités réactivées en masse"); LOGGER.info(compteur + " entités réactivées en masse");
entitesSelectionnees.clear(); entitesSelectionnees.clear();
appliquerFiltres(); appliquerFiltres();
} }
@@ -410,16 +403,16 @@ public class EntitesGestionBean implements Serializable {
for (Entite entite : entitesSelectionnees) { for (Entite entite : entitesSelectionnees) {
if (entite.isQuotaProche()) { if (entite.isQuotaProche()) {
// Simulation d'envoi de proposition d'upgrade // Simulation d'envoi de proposition d'upgrade
System.out.println("Proposition d'upgrade envoyée à: " + entite.getNom()); LOGGER.info("Proposition d'upgrade envoyée à: " + entite.getNom());
compteur++; compteur++;
} }
} }
System.out.println(compteur + " propositions d'upgrade envoyées"); LOGGER.info(compteur + " propositions d'upgrade envoyées");
} }
// Classes internes // Classes internes
public static class Entite { public static class Entite {
private Long id; private UUID id;
private String nom; private String nom;
private String codeEntite; private String codeEntite;
private String type; private String type;
@@ -442,8 +435,8 @@ public class EntitesGestionBean implements Serializable {
private String montantMensuel = "3 000 FCFA"; private String montantMensuel = "3 000 FCFA";
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }

View File

@@ -1,24 +1,34 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.EvenementDTO;
import dev.lions.unionflow.client.service.EvenementService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.logging.Logger;
@Named("evenementsBean") @Named("evenementsBean")
@SessionScoped @SessionScoped
public class EvenementsBean implements Serializable { public class EvenementsBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(EvenementsBean.class.getName());
@Inject
@RestClient
private EvenementService evenementService;
private List<Evenement> tousLesEvenements; private List<Evenement> tousLesEvenements;
private List<Evenement> evenementsFiltres; private List<Evenement> evenementsFiltres;
@@ -32,8 +42,8 @@ public class EvenementsBean implements Serializable {
@PostConstruct @PostConstruct
public void init() { public void init() {
initializeFiltres(); initializeFiltres();
initializeStatistiques();
initializeEvenements(); initializeEvenements();
initializeStatistiques();
initializeNouvelEvenement(); initializeNouvelEvenement();
initializeEvenementsProchains(); initializeEvenementsProchains();
appliquerFiltres(); appliquerFiltres();
@@ -46,98 +56,78 @@ public class EvenementsBean implements Serializable {
private void initializeStatistiques() { private void initializeStatistiques() {
statistiques = new StatistiquesEvenements(); statistiques = new StatistiquesEvenements();
statistiques.setTotalEvenements(42); try {
statistiques.setEvenementsActifs(18); List<EvenementDTO> evenementsDTO = evenementService.listerTous(0, 1000);
statistiques.setParticipantsTotal(1247); statistiques.setTotalEvenements(evenementsDTO.size());
statistiques.setBudgetTotal("3 450 000 FCFA"); long actifs = evenementsDTO.stream()
statistiques.setMoyenneParticipants(69); .filter(e -> "PLANIFIE".equals(e.getStatut()) || "EN_COURS".equals(e.getStatut()))
.count();
statistiques.setEvenementsActifs((int) actifs);
int totalParticipants = evenementsDTO.stream()
.mapToInt(e -> e.getParticipantsInscrits() != null ? e.getParticipantsInscrits() : 0)
.sum();
statistiques.setParticipantsTotal(totalParticipants);
BigDecimal totalBudget = evenementsDTO.stream()
.map(e -> e.getBudget() != null ? e.getBudget() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
statistiques.setBudgetTotal(totalBudget.toString() + " FCFA");
double moyenne = evenementsDTO.isEmpty() ? 0 : (double) totalParticipants / evenementsDTO.size();
statistiques.setMoyenneParticipants((int) moyenne);
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des statistiques: " + e.getMessage());
statistiques.setTotalEvenements(0);
statistiques.setEvenementsActifs(0);
statistiques.setParticipantsTotal(0);
statistiques.setBudgetTotal("0 FCFA");
statistiques.setMoyenneParticipants(0);
}
} }
private void initializeEvenements() { private void initializeEvenements() {
tousLesEvenements = new ArrayList<>(); tousLesEvenements = new ArrayList<>();
try {
String[] titres = { List<EvenementDTO> evenementsDTO = evenementService.listerTous(0, 1000);
"Assemblée Générale Ordinaire", "Formation Leadership", "Action Sociale Quartier Nord", for (EvenementDTO dto : evenementsDTO) {
"Réunion Mensuelle Comité", "Conférence Développement Durable", "Collecte de Fonds", Evenement evenement = convertToEvenement(dto);
"Journée Portes Ouvertes", "Atelier Gestion Financière", "Campagne Sensibilisation",
"Séminaire Jeunes Leaders", "Action Humanitaire", "Réunion Conseil Administration",
"Formation Premiers Secours", "Festival Culturel", "Réunion Coordination Régionale"
};
String[] types = {
"ASSEMBLEE_GENERALE", "FORMATION", "ACTION_SOCIALE", "REUNION", "FORMATION",
"ACTION_SOCIALE", "EVENEMENT_FESTIF", "FORMATION", "ACTION_SOCIALE", "FORMATION",
"ACTION_SOCIALE", "REUNION", "FORMATION", "EVENEMENT_FESTIF", "REUNION"
};
String[] statuts = {
"PLANIFIE", "PLANIFIE", "EN_COURS", "TERMINE", "PLANIFIE",
"PLANIFIE", "TERMINE", "PLANIFIE", "EN_COURS", "PLANIFIE",
"TERMINE", "PLANIFIE", "PLANIFIE", "TERMINE", "PLANIFIE"
};
String[] priorites = {
"CRITIQUE", "ELEVEE", "NORMALE", "NORMALE", "ELEVEE",
"NORMALE", "FAIBLE", "NORMALE", "ELEVEE", "NORMALE",
"CRITIQUE", "NORMALE", "FAIBLE", "FAIBLE", "NORMALE"
};
String[] lieux = {
"Salle Principale", "Centre Formation", "Quartier Nord", "Salle Réunion A",
"Auditorium Central", "Place Publique", "Hall d'Accueil", "Salle Formation B",
"Centre-Ville", "Campus Universitaire", "Zone Rurale", "Salle Conseil",
"Centre Médical", "Parc Municipal", "Siège Régional"
};
String[] organisateurs = {
"Marie Kouassi", "Paul Traoré", "Fatou Sanogo", "Jean Ouattara", "Aissata Koné",
"Ibrahim Touré", "Aminata Bakayoko", "Yves Koffi", "Mariam Coulibaly", "Seydou Cissé",
"Adjoa Mensah", "Kwame Asante", "Ama Gyamfi", "Kofi Adjei", "Ahmed Diallo"
};
for (int i = 0; i < titres.length; i++) {
Evenement evenement = new Evenement();
evenement.setId((long) (i + 1));
evenement.setTitre(titres[i]);
evenement.setType(types[i]);
evenement.setStatut(statuts[i]);
evenement.setPriorite(priorites[i]);
evenement.setLieu(lieux[i]);
evenement.setAdresse("Adresse " + lieux[i] + ", Ville");
evenement.setOrganisateur(organisateurs[i]);
evenement.setOrganisateurEmail(organisateurs[i].toLowerCase().replace(" ", ".") + "@unionflow.app");
// Dates aléatoires
LocalDate baseDate = LocalDate.now().plusDays(i * 3 - 15);
evenement.setDateDebut(baseDate);
evenement.setDateFin(baseDate.plusDays(i % 3 == 0 ? 1 : 0));
evenement.setHeureDebut(LocalTime.of(9 + (i % 8), 0));
evenement.setHeureFin(LocalTime.of(11 + (i % 8), 30));
// Participants et capacité
int capacite = 50 + (i * 10);
int inscrits = (int) (capacite * (0.3 + (i * 0.05) % 0.7));
evenement.setCapaciteMax(capacite);
evenement.setParticipantsInscrits(inscrits);
// Budget
BigDecimal budget = new BigDecimal(100000 + (i * 25000));
evenement.setBudget(budget);
// Description
evenement.setDescription("Description détaillée pour " + titres[i] + " avec objectifs et programme.");
tousLesEvenements.add(evenement); tousLesEvenements.add(evenement);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des événements: " + e.getMessage());
}
}
private Evenement convertToEvenement(EvenementDTO dto) {
Evenement evenement = new Evenement();
evenement.setId(dto.getId());
evenement.setTitre(dto.getTitre());
evenement.setType(dto.getType());
evenement.setStatut(dto.getStatut());
evenement.setPriorite(dto.getPriorite());
evenement.setLieu(dto.getLieu());
evenement.setAdresse(dto.getAdresse());
evenement.setOrganisateur(dto.getOrganisateur());
evenement.setOrganisateurEmail(dto.getOrganisateurEmail());
evenement.setDateDebut(dto.getDateDebut());
evenement.setDateFin(dto.getDateFin());
evenement.setHeureDebut(dto.getHeureDebut());
evenement.setHeureFin(dto.getHeureFin());
evenement.setCapaciteMax(dto.getCapaciteMax());
evenement.setParticipantsInscrits(dto.getParticipantsInscrits());
evenement.setBudget(dto.getBudget());
evenement.setDescription(dto.getDescription());
return evenement;
} }
private void initializeEvenementsProchains() { private void initializeEvenementsProchains() {
evenementsProchains = tousLesEvenements.stream() try {
.filter(e -> e.getDateDebut().isAfter(LocalDate.now()) || e.getDateDebut().equals(LocalDate.now())) List<EvenementDTO> evenementsDTO = evenementService.listerAVenir(0, 6);
.filter(e -> !e.getStatut().equals("ANNULE") && !e.getStatut().equals("TERMINE")) evenementsProchains = evenementsDTO.stream()
.sorted((e1, e2) -> e1.getDateDebut().compareTo(e2.getDateDebut())) .map(this::convertToEvenement)
.limit(6)
.collect(Collectors.toList()); .collect(Collectors.toList());
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des événements à venir: " + e.getMessage());
evenementsProchains = new ArrayList<>();
}
} }
private void initializeNouvelEvenement() { private void initializeNouvelEvenement() {
@@ -210,7 +200,7 @@ public class EvenementsBean implements Serializable {
public void creerEvenement() { public void creerEvenement() {
Evenement nouvelEvt = new Evenement(); Evenement nouvelEvt = new Evenement();
nouvelEvt.setId((long) (tousLesEvenements.size() + 1)); nouvelEvt.setId(UUID.randomUUID());
nouvelEvt.setTitre(nouvelEvenement.getTitre()); nouvelEvt.setTitre(nouvelEvenement.getTitre());
nouvelEvt.setType(nouvelEvenement.getType()); nouvelEvt.setType(nouvelEvenement.getType());
nouvelEvt.setDateDebut(nouvelEvenement.getDateDebut()); nouvelEvt.setDateDebut(nouvelEvenement.getDateDebut());
@@ -231,7 +221,7 @@ public class EvenementsBean implements Serializable {
appliquerFiltres(); appliquerFiltres();
initializeEvenementsProchains(); initializeEvenementsProchains();
System.out.println("Nouvel événement créé: " + nouvelEvt.getTitre()); LOGGER.info("Nouvel événement créé: " + nouvelEvt.getTitre());
initializeNouvelEvenement(); initializeNouvelEvenement();
} }
@@ -240,7 +230,7 @@ public class EvenementsBean implements Serializable {
} }
public void envoyerInvitations() { public void envoyerInvitations() {
System.out.println("Invitations envoyées pour: " + evenementSelectionne.getTitre()); LOGGER.info("Invitations envoyées pour: " + evenementSelectionne.getTitre());
} }
public String voirRapports() { public String voirRapports() {
@@ -250,7 +240,7 @@ public class EvenementsBean implements Serializable {
public void annulerEvenement() { public void annulerEvenement() {
if (evenementSelectionne != null) { if (evenementSelectionne != null) {
evenementSelectionne.setStatut("ANNULE"); evenementSelectionne.setStatut("ANNULE");
System.out.println("Événement annulé: " + evenementSelectionne.getTitre()); LOGGER.info("Événement annulé: " + evenementSelectionne.getTitre());
appliquerFiltres(); appliquerFiltres();
initializeEvenementsProchains(); initializeEvenementsProchains();
} }
@@ -259,7 +249,7 @@ public class EvenementsBean implements Serializable {
public void dupliquerEvenement() { public void dupliquerEvenement() {
if (evenementSelectionne != null) { if (evenementSelectionne != null) {
Evenement copie = new Evenement(); Evenement copie = new Evenement();
copie.setId((long) (tousLesEvenements.size() + 1)); copie.setId(UUID.randomUUID());
copie.setTitre(evenementSelectionne.getTitre() + " (Copie)"); copie.setTitre(evenementSelectionne.getTitre() + " (Copie)");
copie.setType(evenementSelectionne.getType()); copie.setType(evenementSelectionne.getType());
copie.setLieu(evenementSelectionne.getLieu()); copie.setLieu(evenementSelectionne.getLieu());
@@ -278,16 +268,16 @@ public class EvenementsBean implements Serializable {
tousLesEvenements.add(copie); tousLesEvenements.add(copie);
appliquerFiltres(); appliquerFiltres();
System.out.println("Événement dupliqué: " + copie.getTitre()); LOGGER.info("Événement dupliqué: " + copie.getTitre());
} }
} }
public void exporterEvenements() { public void exporterEvenements() {
System.out.println("Export de " + evenementsFiltres.size() + " événements"); LOGGER.info("Export de " + evenementsFiltres.size() + " événements");
} }
public void exporterExcel() { public void exporterExcel() {
System.out.println("Export Excel de " + evenementsFiltres.size() + " événements"); LOGGER.info("Export Excel de " + evenementsFiltres.size() + " événements");
} }
// Getters et Setters // Getters et Setters
@@ -317,7 +307,7 @@ public class EvenementsBean implements Serializable {
// Classes internes // Classes internes
public static class Evenement { public static class Evenement {
private Long id; private UUID id;
private String titre; private String titre;
private String description; private String description;
private String type; private String type;
@@ -336,8 +326,8 @@ public class EvenementsBean implements Serializable {
private BigDecimal budget; private BigDecimal budget;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getTitre() { return titre; } public String getTitre() { return titre; }
public void setTitre(String titre) { this.titre = titre; } public void setTitre(String titre) { this.titre = titre; }

View File

@@ -2,18 +2,28 @@ package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.FormulaireDTO; import dev.lions.unionflow.client.dto.FormulaireDTO;
import dev.lions.unionflow.client.dto.SouscriptionDTO; import dev.lions.unionflow.client.dto.SouscriptionDTO;
import dev.lions.unionflow.client.service.FormulaireService;
import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.logging.Logger;
@Named("formulaireBean") @Named("formulaireBean")
@RequestScoped @RequestScoped
public class FormulaireBean implements Serializable { public class FormulaireBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(FormulaireBean.class.getName());
@Inject
@RestClient
private FormulaireService formulaireService;
private List<FormulaireDTO> formulaires; private List<FormulaireDTO> formulaires;
private List<FormulaireDTO> formulairesPopulaires; private List<FormulaireDTO> formulairesPopulaires;
@@ -25,104 +35,21 @@ public class FormulaireBean implements Serializable {
private BigDecimal budgetMax; private BigDecimal budgetMax;
private String categorieFiltre = "ALL"; private String categorieFiltre = "ALL";
public FormulaireBean() { @PostConstruct
public void init() {
initializeFormulaires(); initializeFormulaires();
} }
private void initializeFormulaires() { private void initializeFormulaires() {
formulaires = new ArrayList<>(); formulaires = new ArrayList<>();
try {
// Formulaire STARTER - Pour les petites associations formulaires = formulaireService.listerActifs();
FormulaireDTO starter = new FormulaireDTO(); formulairesPopulaires = formulaireService.listerPopulaires();
starter.setId(1L); } catch (Exception e) {
starter.setNom("Starter"); LOGGER.severe("Erreur lors du chargement des formulaires: " + e.getMessage());
starter.setDescription("Parfait pour les associations débutantes"); formulaires = new ArrayList<>();
starter.setQuotaMaxMembres(100);
starter.setPrixMensuel(new BigDecimal("2000")); // 2K FCFA
starter.setPrixAnnuel(new BigDecimal("20000")); // 20K FCFA (2 mois gratuits)
starter.setCouleurTheme("bg-blue-500");
starter.setIconeFormulaire("pi-star");
starter.setGestionMembres(true);
starter.setGestionCotisations(true);
starter.setGestionEvenements(false);
starter.setGestionAides(false);
starter.setRapportsAvances(false);
starter.setNotificationsEmail(true);
formulaires.add(starter);
// Formulaire STANDARD - Pour les associations moyennes
FormulaireDTO standard = new FormulaireDTO();
standard.setId(2L);
standard.setNom("Standard");
standard.setDescription("Idéal pour les associations en croissance");
standard.setQuotaMaxMembres(200);
standard.setPrixMensuel(new BigDecimal("3000")); // 3K FCFA
standard.setPrixAnnuel(new BigDecimal("30000")); // 30K FCFA (2 mois gratuits)
standard.setCouleurTheme("bg-green-500");
standard.setIconeFormulaire("pi-users");
standard.setRecommande(true);
standard.setGestionMembres(true);
standard.setGestionCotisations(true);
standard.setGestionEvenements(true);
standard.setGestionAides(true);
standard.setRapportsAvances(false);
standard.setNotificationsEmail(true);
standard.setNotificationsSMS(false);
standard.setGestionDocuments(true);
formulaires.add(standard);
// Formulaire PREMIUM - Pour les grandes associations
FormulaireDTO premium = new FormulaireDTO();
premium.setId(3L);
premium.setNom("Premium");
premium.setDescription("Solution complète pour les grandes organisations");
premium.setQuotaMaxMembres(500);
premium.setPrixMensuel(new BigDecimal("4000")); // 4K FCFA
premium.setPrixAnnuel(new BigDecimal("40000")); // 40K FCFA (2 mois gratuits)
premium.setCouleurTheme("bg-purple-500");
premium.setIconeFormulaire("pi-crown");
premium.setGestionMembres(true);
premium.setGestionCotisations(true);
premium.setGestionEvenements(true);
premium.setGestionAides(true);
premium.setRapportsAvances(true);
premium.setSupportPrioritaire(true);
premium.setSauvegardeAutomatique(true);
premium.setPersonnalisationAvancee(true);
premium.setIntegrationPaiement(true);
premium.setNotificationsEmail(true);
premium.setNotificationsSMS(true);
premium.setGestionDocuments(true);
formulaires.add(premium);
// Formulaire CRISTAL - Pour les très grandes organisations
FormulaireDTO cristal = new FormulaireDTO();
cristal.setId(4L);
cristal.setNom("Cristal");
cristal.setDescription("Solution premium pour les fédérations et grandes entités");
cristal.setQuotaMaxMembres(2000);
cristal.setPrixMensuel(new BigDecimal("5000")); // 5K FCFA
cristal.setPrixAnnuel(new BigDecimal("50000")); // 50K FCFA (2 mois gratuits)
cristal.setCouleurTheme("bg-indigo-500");
cristal.setIconeFormulaire("pi-diamond");
cristal.setGestionMembres(true);
cristal.setGestionCotisations(true);
cristal.setGestionEvenements(true);
cristal.setGestionAides(true);
cristal.setRapportsAvances(true);
cristal.setSupportPrioritaire(true);
cristal.setSauvegardeAutomatique(true);
cristal.setPersonnalisationAvancee(true);
cristal.setIntegrationPaiement(true);
cristal.setNotificationsEmail(true);
cristal.setNotificationsSMS(true);
cristal.setGestionDocuments(true);
formulaires.add(cristal);
// Définir les formulaires populaires (Standard et Premium)
formulairesPopulaires = new ArrayList<>(); formulairesPopulaires = new ArrayList<>();
formulairesPopulaires.add(standard); }
formulairesPopulaires.add(premium);
} }
public void selectionnerFormulaire(FormulaireDTO formulaire) { public void selectionnerFormulaire(FormulaireDTO formulaire) {

View File

@@ -1,18 +1,21 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.auth.LoginRequest;
import dev.lions.unionflow.client.dto.auth.LoginResponse;
import dev.lions.unionflow.client.security.JwtTokenManager;
import dev.lions.unionflow.client.service.AuthenticationService;
import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.application.FacesMessage; import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext; import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.validation.Valid; import org.eclipse.microprofile.jwt.JsonWebToken;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.util.logging.Logger; import java.util.logging.Logger;
/**
* Bean de gestion de l'authentification via Keycloak OIDC
*
* @author UnionFlow Team
* @version 2.0
*/
@Named("loginBean") @Named("loginBean")
@RequestScoped @RequestScoped
public class LoginBean implements Serializable { public class LoginBean implements Serializable {
@@ -20,104 +23,33 @@ public class LoginBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(LoginBean.class.getName()); private static final Logger LOGGER = Logger.getLogger(LoginBean.class.getName());
@Inject
private JsonWebToken jwt;
@Inject @Inject
private UserSession userSession; private UserSession userSession;
@Inject /**
private JwtTokenManager tokenManager; * Redirige vers Keycloak pour l'authentification
* L'authentification est gérée automatiquement par Quarkus OIDC
@Inject */
private AuthenticationService authService; public void login() {
private String username;
private String password;
private String typeCompte;
private boolean rememberMe;
public String login() {
try { try {
if (username == null || username.trim().isEmpty() || // La redirection vers Keycloak est gérée automatiquement par Quarkus OIDC
password == null || password.trim().isEmpty() || // via la configuration dans application.properties
typeCompte == null || typeCompte.trim().isEmpty()) { LOGGER.info("Redirection vers Keycloak pour l'authentification");
addErrorMessage("Erreur de validation", "Tous les champs sont requis");
return null;
}
LoginRequest loginRequest = new LoginRequest(username, password, typeCompte);
loginRequest.setRememberMe(rememberMe);
LoginResponse response = authService.authenticate(loginRequest);
// Mettre à jour la session utilisateur
userSession.updateFromLoginResponse(response);
// Gérer les tokens JWT
tokenManager.setTokens(response);
LOGGER.info("Connexion réussie pour: " + username + " (Type: " + typeCompte + ")");
addSuccessMessage("Connexion réussie", "Bienvenue " + userSession.getCurrentUser().getNomComplet());
// Redirection selon le type de compte
return getRedirectUrlForUserType(response.getUser().getTypeCompte());
} catch (AuthenticationService.AuthenticationException e) {
LOGGER.warning("Échec de l'authentification: " + e.getMessage());
addErrorMessage("Erreur de connexion", e.getMessage());
return null;
} catch (Exception e) { } catch (Exception e) {
LOGGER.severe("Erreur inattendue lors de la connexion: " + e.getMessage()); LOGGER.severe("Erreur lors de la redirection vers Keycloak: " + e.getMessage());
addErrorMessage("Erreur système", "Une erreur inattendue s'est produite. Veuillez réessayer.");
return null;
}
}
public String loginDemo(String demoType) {
try {
String demoUsername;
String demoPassword = "admin";
switch (demoType) {
case "SUPER_ADMIN":
demoUsername = "superadmin";
typeCompte = "SUPER_ADMIN";
break;
case "ADMIN":
demoUsername = "admin";
typeCompte = "ADMIN_ENTITE";
break;
case "MEMBRE":
demoUsername = "membre";
demoPassword = "membre";
typeCompte = "MEMBRE";
break;
default:
addErrorMessage("Erreur", "Type de démo invalide");
return null;
}
this.username = demoUsername;
this.password = demoPassword;
return login();
} catch (Exception e) {
LOGGER.severe("Erreur lors de la connexion démo: " + e.getMessage());
addErrorMessage("Erreur système", "Impossible de se connecter en mode démo");
return null;
} }
} }
/**
* Déconnexion de l'utilisateur
* Redirige vers l'endpoint de déconnexion Keycloak
*/
public String logout() { public String logout() {
try { try {
// Invalider le token côté serveur si possible
if (tokenManager.hasValidTokens()) {
authService.logout(tokenManager.getAccessToken());
}
// Nettoyer la session locale // Nettoyer la session locale
tokenManager.clearTokens();
userSession.clearSession(); userSession.clearSession();
// Invalider la session JSF // Invalider la session JSF
@@ -125,77 +57,28 @@ public class LoginBean implements Serializable {
LOGGER.info("Déconnexion réussie"); LOGGER.info("Déconnexion réussie");
return "/pages/public/login?faces-redirect=true"; // Redirection vers Keycloak pour la déconnexion complète
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
String logoutUrl = "/auth/logout";
externalContext.redirect(logoutUrl);
} catch (Exception e) { return null; // La redirection est gérée par redirect()
} catch (IOException e) {
LOGGER.warning("Erreur lors de la déconnexion: " + e.getMessage()); LOGGER.warning("Erreur lors de la déconnexion: " + e.getMessage());
// Même en cas d'erreur, invalider la session locale // Même en cas d'erreur, invalider la session locale
tokenManager.clearTokens();
userSession.clearSession(); userSession.clearSession();
FacesContext.getCurrentInstance().getExternalContext().invalidateSession(); FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
return "/pages/public/login?faces-redirect=true"; return "/?faces-redirect=true";
} }
} }
private String getRedirectUrlForUserType(String typeCompte) { /**
if (typeCompte == null) { * Vérifie si l'utilisateur est authentifié
return "/pages/secure/dashboard?faces-redirect=true"; */
} public boolean isAuthenticated() {
return jwt != null && jwt.getName() != null;
switch (typeCompte) {
case "SUPER_ADMIN":
return "/pages/super-admin/dashboard?faces-redirect=true";
case "ADMIN_ENTITE":
return "/pages/admin/dashboard?faces-redirect=true";
case "MEMBRE":
return "/pages/membre/dashboard?faces-redirect=true";
default:
return "/pages/secure/dashboard?faces-redirect=true";
}
}
private void addErrorMessage(String summary, String detail) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_ERROR, summary, detail));
}
private void addSuccessMessage(String summary, String detail) {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO, summary, detail));
}
// Getters et Setters
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTypeCompte() {
return typeCompte;
}
public void setTypeCompte(String typeCompte) {
this.typeCompte = typeCompte;
}
public boolean isRememberMe() {
return rememberMe;
}
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
} }
} }

View File

@@ -1,11 +1,9 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.MembreDTO; import dev.lions.unionflow.client.dto.MembreDTO;
import dev.lions.unionflow.client.dto.AssociationDTO;
import dev.lions.unionflow.client.service.MembreService; import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.AssociationService; import dev.lions.unionflow.client.service.AssociationService;
import dev.lions.unionflow.client.service.ValidationService; import dev.lions.unionflow.client.service.ValidationService;
import dev.lions.unionflow.client.view.SouscriptionBean;
import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.inject.Inject; import jakarta.inject.Inject;
@@ -18,13 +16,14 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.logging.Logger;
@Named("membreInscriptionBean") @Named("membreInscriptionBean")
@RequestScoped @RequestScoped
public class MembreInscriptionBean implements Serializable { public class MembreInscriptionBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(MembreInscriptionBean.class.getName());
@Inject @Inject
@RestClient @RestClient
@@ -146,22 +145,22 @@ public class MembreInscriptionBean implements Serializable {
// Gestion de la photo si disponible // Gestion de la photo si disponible
if (photoBase64 != null && !photoBase64.trim().isEmpty()) { if (photoBase64 != null && !photoBase64.trim().isEmpty()) {
System.out.println("Photo cadrée reçue: " + photoBase64.length() + " caractères"); LOGGER.info("Photo cadrée reçue: " + photoBase64.length() + " caractères");
// TODO: Appeler service de sauvegarde de photo // Note: La sauvegarde de la photo sera implémentée ultérieurement via un service dédié.
// Le service appellera l'API backend pour stocker la photo associée au membre.
} }
System.out.println("Membre inscrit avec succès: " + membreCreee.getNomComplet()); LOGGER.info("Membre inscrit avec succès: " + membreCreee.getNomComplet());
// Message de succès // Message de succès
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO,
"Inscription soumise", "Votre inscription a été soumise avec succès. Elle sera validée par l'administrateur de votre organisation."); "Inscription soumise", "Votre inscription a été soumise avec succès. Elle sera validée par l'administrateur de votre organisation.");
FacesContext.getCurrentInstance().addMessage(null, message); FacesContext.getCurrentInstance().addMessage(null, message);
return "/pages/public/login?faces-redirect=true"; return "/?faces-redirect=true";
} catch (Exception e) { } catch (Exception e) {
System.err.println("Erreur lors de l'inscription: " + e.getMessage()); LOGGER.severe("Erreur lors de l'inscription: " + e.getMessage());
e.printStackTrace();
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Erreur", "Erreur lors de l'inscription: " + e.getMessage()); "Erreur", "Erreur lors de l'inscription: " + e.getMessage());
FacesContext.getCurrentInstance().addMessage(null, message); FacesContext.getCurrentInstance().addMessage(null, message);
@@ -174,7 +173,7 @@ public class MembreInscriptionBean implements Serializable {
if (nom != null && !nom.trim().isEmpty()) { if (nom != null && !nom.trim().isEmpty()) {
ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "nom", nom); ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "nom", nom);
if (!result.isValid()) { if (!result.isValid()) {
System.out.println("Erreur validation nom: " + result.getFirstErrorMessage()); LOGGER.info("Erreur validation nom: " + result.getFirstErrorMessage());
} }
} }
} }
@@ -183,7 +182,7 @@ public class MembreInscriptionBean implements Serializable {
if (prenom != null && !prenom.trim().isEmpty()) { if (prenom != null && !prenom.trim().isEmpty()) {
ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "prenom", prenom); ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "prenom", prenom);
if (!result.isValid()) { if (!result.isValid()) {
System.out.println("Erreur validation prénom: " + result.getFirstErrorMessage()); LOGGER.info("Erreur validation prénom: " + result.getFirstErrorMessage());
} }
} }
} }
@@ -192,7 +191,7 @@ public class MembreInscriptionBean implements Serializable {
if (email != null && !email.trim().isEmpty()) { if (email != null && !email.trim().isEmpty()) {
ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "email", email); ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "email", email);
if (!result.isValid()) { if (!result.isValid()) {
System.out.println("Erreur validation email: " + result.getFirstErrorMessage()); LOGGER.info("Erreur validation email: " + result.getFirstErrorMessage());
} }
} }
} }
@@ -201,7 +200,7 @@ public class MembreInscriptionBean implements Serializable {
if (telephone != null && !telephone.trim().isEmpty()) { if (telephone != null && !telephone.trim().isEmpty()) {
ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "telephone", telephone); ValidationService.ValidationResult result = validationService.validateValue(MembreDTO.class, "telephone", telephone);
if (!result.isValid()) { if (!result.isValid()) {
System.out.println("Erreur validation téléphone: " + result.getFirstErrorMessage()); LOGGER.info("Erreur validation téléphone: " + result.getFirstErrorMessage());
} }
} }
} }

View File

@@ -6,18 +6,22 @@ import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.inject.Inject; import jakarta.inject.Inject;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import jakarta.faces.context.FacesContext;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.microprofile.rest.client.inject.RestClient; import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.logging.Logger;
@Named("membreListeBean") @Named("membreListeBean")
@SessionScoped @SessionScoped
public class MembreListeBean implements Serializable { public class MembreListeBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(MembreListeBean.class.getName());
@Inject @Inject
@RestClient @RestClient
@@ -69,9 +73,8 @@ public class MembreListeBean implements Serializable {
chargerMembres(); chargerMembres();
chargerStatistiques(); chargerStatistiques();
} catch (Exception e) { } catch (Exception e) {
System.err.println("Erreur lors de l'initialisation: " + e.getMessage()); LOGGER.severe("Erreur lors de l'initialisation: " + e.getMessage());
e.printStackTrace(); // Pas de données mockées - initialiser à zéro
// Données de fallback
this.totalMembres = 0; this.totalMembres = 0;
this.membresActifs = 0; this.membresActifs = 0;
this.cotisationsAJour = 0; this.cotisationsAJour = 0;
@@ -86,35 +89,16 @@ public class MembreListeBean implements Serializable {
membres = membreService.listerTous(); membres = membreService.listerTous();
membresFiltres = new ArrayList<>(membres); membresFiltres = new ArrayList<>(membres);
System.out.println("Chargement de " + membres.size() + " membres depuis le serveur"); LOGGER.info("Chargement de " + membres.size() + " membres depuis le serveur");
} catch (Exception e) { } catch (Exception e) {
System.err.println("Impossible de charger les membres depuis le serveur: " + e.getMessage()); LOGGER.severe("Impossible de charger les membres depuis le serveur: " + e.getMessage());
// Fallback avec données simulées // Pas de données mockées - laisser la liste vide
membres = genererDonneesSimulees(); membres = new ArrayList<>();
membresFiltres = new ArrayList<>(membres); membresFiltres = new ArrayList<>();
} }
} }
private List<MembreDTO> genererDonneesSimulees() {
List<MembreDTO> membresSimules = new ArrayList<>();
for (int i = 1; i <= 20; i++) {
MembreDTO membre = new MembreDTO();
membre.setId((long) i);
membre.setNumeroMembre("M2024" + String.format("%03d", i));
membre.setNom("Membre" + i);
membre.setPrenom("Prénom" + i);
membre.setEmail("membre" + i + "@example.com");
membre.setTelephone("77 123 45 " + String.format("%02d", i));
membre.setStatut(i % 10 == 0 ? "INACTIF" : "ACTIF");
membre.setDateNaissance(LocalDate.now().minusYears(25 + i));
membre.setProfession("Profession " + (i % 10 + 1));
membre.setAdresse("Adresse " + i);
membresSimules.add(membre);
}
return membresSimules;
}
private void chargerStatistiques() { private void chargerStatistiques() {
try { try {
// Récupération des statistiques via le service REST // Récupération des statistiques via le service REST
@@ -129,8 +113,8 @@ public class MembreListeBean implements Serializable {
this.cotisationsAJour = (int) (this.membresActifs * 0.85); this.cotisationsAJour = (int) (this.membresActifs * 0.85);
} catch (Exception e) { } catch (Exception e) {
System.err.println("Impossible de charger les statistiques: " + e.getMessage()); LOGGER.severe("Impossible de charger les statistiques: " + e.getMessage());
// Utiliser les valeurs de fallback définies dans init() // Pas de données mockées - laisser les valeurs à zéro
} }
} }
@@ -149,25 +133,15 @@ public class MembreListeBean implements Serializable {
); );
membresFiltres = resultats; membresFiltres = resultats;
System.out.println("Recherche effectuée: " + membresFiltres.size() + " résultats"); LOGGER.info("Recherche effectuée: " + membresFiltres.size() + " résultats");
} catch (Exception e) { } catch (Exception e) {
System.err.println("Erreur lors de la recherche: " + e.getMessage()); LOGGER.severe("Erreur lors de la recherche: " + e.getMessage());
// En cas d'erreur, appliquer le filtre localement // En cas d'erreur, laisser la liste vide plutôt que des données mockées
appliquerFiltreLocal(); membresFiltres = new ArrayList<>();
} }
} }
private void appliquerFiltreLocal() {
membresFiltres = membres.stream()
.filter(m -> searchFilter.isEmpty() ||
m.getNom().toLowerCase().contains(searchFilter.toLowerCase()) ||
m.getPrenom().toLowerCase().contains(searchFilter.toLowerCase()) ||
m.getEmail().toLowerCase().contains(searchFilter.toLowerCase()))
.filter(m -> statutFilter.isEmpty() || m.getStatut().equals(statutFilter))
.collect(Collectors.toList());
}
public void reinitialiserFiltres() { public void reinitialiserFiltres() {
searchFilter = ""; searchFilter = "";
statutFilter = ""; statutFilter = "";
@@ -188,18 +162,18 @@ public class MembreListeBean implements Serializable {
public void appliquerFiltresAvances() { public void appliquerFiltresAvances() {
// Appliquer les filtres avancés // Appliquer les filtres avancés
System.out.println("Application des filtres avancés"); LOGGER.info("Application des filtres avancés");
} }
// Import/Export // Import/Export
public void importerMembres() { public void importerMembres() {
// Logique d'import des membres // Logique d'import des membres
System.out.println("Import des membres"); LOGGER.info("Import des membres");
} }
public void telechargerModele() { public void telechargerModele() {
// Télécharger modèle d'import // Télécharger modèle d'import
System.out.println("Téléchargement du modèle"); LOGGER.info("Téléchargement du modèle");
} }
// Actions avec DTOs // Actions avec DTOs
@@ -211,9 +185,9 @@ public class MembreListeBean implements Serializable {
try { try {
membreService.activer(membre.getId()); membreService.activer(membre.getId());
membre.setStatut("ACTIF"); membre.setStatut("ACTIF");
System.out.println("Membre activé: " + membre.getNomComplet()); LOGGER.info("Membre activé: " + membre.getNomComplet());
} catch (Exception e) { } catch (Exception e) {
System.err.println("Erreur lors de l'activation: " + e.getMessage()); LOGGER.severe("Erreur lors de l'activation: " + e.getMessage());
} }
} }
@@ -221,19 +195,35 @@ public class MembreListeBean implements Serializable {
try { try {
membreService.desactiver(membre.getId()); membreService.desactiver(membre.getId());
membre.setStatut("INACTIF"); membre.setStatut("INACTIF");
System.out.println("Membre désactivé: " + membre.getNomComplet()); LOGGER.info("Membre désactivé: " + membre.getNomComplet());
} catch (Exception e) { } catch (Exception e) {
System.err.println("Erreur lors de la désactivation: " + e.getMessage()); LOGGER.severe("Erreur lors de la désactivation: " + e.getMessage());
} }
} }
public void exporterMembres() { public void exporterMembres() {
try { try {
byte[] excelData = membreService.exporterExcel(formatExport, null, statutFilter.isEmpty() ? null : statutFilter); byte[] excelData = membreService.exporterExcel(formatExport, null, statutFilter.isEmpty() ? null : statutFilter);
// TODO: Gérer le téléchargement du fichier Excel
System.out.println("Export Excel généré: " + excelData.length + " bytes"); // Téléchargement du fichier Excel via JSF
FacesContext facesContext = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
response.reset();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"membres_export_" +
LocalDate.now() + "." + (formatExport != null ? formatExport.toLowerCase() : "xlsx") + "\"");
response.setContentLength(excelData.length);
response.getOutputStream().write(excelData);
response.getOutputStream().flush();
facesContext.responseComplete();
LOGGER.info("Export Excel généré et téléchargé: " + excelData.length + " bytes");
} catch (IOException e) {
LOGGER.severe("Erreur lors du téléchargement de l'export: " + e.getMessage());
} catch (Exception e) { } catch (Exception e) {
System.err.println("Erreur lors de l'export: " + e.getMessage()); LOGGER.severe("Erreur lors de l'export: " + e.getMessage());
} }
} }

View File

@@ -1,13 +1,19 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.MembreDTO;
import dev.lions.unionflow.client.service.MembreService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
import org.primefaces.event.FileUploadEvent; import org.primefaces.event.FileUploadEvent;
@Named("membreProfilBean") @Named("membreProfilBean")
@@ -15,6 +21,11 @@ import org.primefaces.event.FileUploadEvent;
public class MembreProfilBean implements Serializable { public class MembreProfilBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(MembreProfilBean.class.getName());
@Inject
@RestClient
private MembreService membreService;
private Membre membre; private Membre membre;
private Membre membreEdit; private Membre membreEdit;
@@ -25,12 +36,13 @@ public class MembreProfilBean implements Serializable {
private DemandesData demandes; private DemandesData demandes;
private HistoriqueData historique; private HistoriqueData historique;
private ContactData contact; private ContactData contact;
private Long membreId; private UUID membreId;
@PostConstruct @PostConstruct
public void init() { public void init() {
if (membreId == null) { if (membreId == null) {
membreId = 1L; // Par défaut pour le test LOGGER.warning("Aucun membreId fourni, impossible de charger le profil");
return;
} }
chargerMembre(); chargerMembre();
chargerStatistiques(); chargerStatistiques();
@@ -43,48 +55,36 @@ public class MembreProfilBean implements Serializable {
} }
private void chargerMembre() { private void chargerMembre() {
membre = new Membre(); try {
membre.setId(membreId); MembreDTO dto = membreService.obtenirParId(membreId);
membre.setNumeroMembre("M2024001"); membre = convertToMembre(dto);
membre.setPrenom("Jean");
membre.setNom("DIALLO");
membre.setEmail("jean.diallo@email.com");
membre.setTelephone("77 123 45 67");
membre.setDateNaissance(LocalDate.of(1985, 6, 15));
membre.setGenre("Masculin");
membre.setSituationFamiliale("Marié");
membre.setProfession("Ingénieur Informatique");
membre.setAdresse("Villa n°123, Cité Keur Gorgui");
membre.setVille("Dakar");
membre.setPays("Sénégal");
membre.setTypeMembre("ACTIF");
membre.setStatut("ACTIF");
membre.setEntite("LIONS CLUB Dakar Métropole");
membre.setDateAdhesion(LocalDate.of(2020, 3, 15));
membre.setCotisationStatut("À jour");
membre.setTauxParticipation(85);
// Famille
List<MembreFamille> famille = new ArrayList<>();
MembreFamille epouse = new MembreFamille();
epouse.setNomComplet("Awa DIALLO");
epouse.setRelation("Épouse");
epouse.setDateNaissance(LocalDate.of(1987, 9, 20));
epouse.setBeneficiaire(true);
famille.add(epouse);
MembreFamille enfant1 = new MembreFamille();
enfant1.setNomComplet("Amadou DIALLO");
enfant1.setRelation("Fils");
enfant1.setDateNaissance(LocalDate.of(2010, 12, 5));
enfant1.setBeneficiaire(true);
famille.add(enfant1);
membre.setFamille(famille);
// Copie pour l'édition // Copie pour l'édition
membreEdit = new Membre(); membreEdit = new Membre();
copierMembre(membre, membreEdit); copierMembre(membre, membreEdit);
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement du membre: " + e.getMessage());
membre = new Membre();
membre.setId(membreId);
}
}
private Membre convertToMembre(MembreDTO dto) {
Membre membre = new Membre();
membre.setId(dto.getId());
membre.setNumeroMembre(dto.getNumeroMembre());
membre.setPrenom(dto.getPrenom());
membre.setNom(dto.getNom());
membre.setEmail(dto.getEmail());
membre.setTelephone(dto.getTelephone());
membre.setDateNaissance(dto.getDateNaissance());
// Note: Genre, situation familiale, ville, pays, type membre ne sont pas disponibles dans MembreDTO client
// Ces champs seront ajoutés ultérieurement si nécessaire
membre.setProfession(dto.getProfession());
membre.setAdresse(dto.getAdresse());
membre.setStatut(dto.getStatut() != null ? dto.getStatut() : "ACTIF");
membre.setDateAdhesion(dto.getDateInscription() != null ? dto.getDateInscription().toLocalDate() : null);
return membre;
} }
private void chargerStatistiques() { private void chargerStatistiques() {
@@ -223,7 +223,7 @@ public class MembreProfilBean implements Serializable {
// Actions // Actions
public void changerPhoto(FileUploadEvent event) { public void changerPhoto(FileUploadEvent event) {
// Logique de changement de photo // Logique de changement de photo
System.out.println("Photo changée: " + event.getFile().getFileName()); LOGGER.info("Photo changée: " + event.getFile().getFileName());
} }
public String gererCotisations() { public String gererCotisations() {
@@ -232,35 +232,35 @@ public class MembreProfilBean implements Serializable {
public void sauvegarderModifications() { public void sauvegarderModifications() {
copierMembre(membreEdit, membre); copierMembre(membreEdit, membre);
System.out.println("Profil mis à jour pour: " + membre.getNomComplet()); LOGGER.info("Profil mis à jour pour: " + membre.getNomComplet());
} }
public void envoyerMessage() { public void envoyerMessage() {
System.out.println("Message envoyé: " + contact.getSujet() + " via " + contact.getCanaux()); LOGGER.info("Message envoyé: " + contact.getSujet() + " via " + contact.getCanaux());
contact = new ContactData(); contact = new ContactData();
contact.setCanaux(new ArrayList<>()); contact.setCanaux(new ArrayList<>());
} }
public void envoyerRappelCotisation() { public void envoyerRappelCotisation() {
System.out.println("Rappel de cotisation envoyé à: " + membre.getEmail()); LOGGER.info("Rappel de cotisation envoyé à: " + membre.getEmail());
} }
public void suspendre() { public void suspendre() {
membre.setStatut("SUSPENDU"); membre.setStatut("SUSPENDU");
System.out.println("Membre suspendu: " + membre.getNomComplet()); LOGGER.info("Membre suspendu: " + membre.getNomComplet());
} }
public void reactiver() { public void reactiver() {
membre.setStatut("ACTIF"); membre.setStatut("ACTIF");
System.out.println("Membre réactivé: " + membre.getNomComplet()); LOGGER.info("Membre réactivé: " + membre.getNomComplet());
} }
public void exporterDonnees() { public void exporterDonnees() {
System.out.println("Export des données pour: " + membre.getNomComplet()); LOGGER.info("Export des données pour: " + membre.getNomComplet());
} }
public String supprimer() { public String supprimer() {
System.out.println("Membre supprimé: " + membre.getNomComplet()); LOGGER.info("Membre supprimé: " + membre.getNomComplet());
return "/pages/secure/membre/liste?faces-redirect=true"; return "/pages/secure/membre/liste?faces-redirect=true";
} }
@@ -303,12 +303,12 @@ public class MembreProfilBean implements Serializable {
public ContactData getContact() { return contact; } public ContactData getContact() { return contact; }
public void setContact(ContactData contact) { this.contact = contact; } public void setContact(ContactData contact) { this.contact = contact; }
public Long getMembreId() { return membreId; } public UUID getMembreId() { return membreId; }
public void setMembreId(Long membreId) { this.membreId = membreId; } public void setMembreId(UUID membreId) { this.membreId = membreId; }
// Classes internes // Classes internes
public static class Membre { public static class Membre {
private Long id; private UUID id;
private String numeroMembre; private String numeroMembre;
private String prenom; private String prenom;
private String nom; private String nom;
@@ -331,8 +331,8 @@ public class MembreProfilBean implements Serializable {
private List<MembreFamille> famille = new ArrayList<>(); private List<MembreFamille> famille = new ArrayList<>();
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNumeroMembre() { return numeroMembre; } public String getNumeroMembre() { return numeroMembre; }
public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; } public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; }

View File

@@ -1,19 +1,35 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.MembreDTO;
import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.AssociationService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.logging.Logger;
@Named("membreRechercheBean") @Named("membreRechercheBean")
@SessionScoped @SessionScoped
public class MembreRechercheBean implements Serializable { public class MembreRechercheBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(MembreRechercheBean.class.getName());
@Inject
@RestClient
private MembreService membreService;
@Inject
@RestClient
private AssociationService associationService;
private Filtres filtres; private Filtres filtres;
private Statistiques statistiques; private Statistiques statistiques;
@@ -47,87 +63,72 @@ public class MembreRechercheBean implements Serializable {
private void initializeStatistiques() { private void initializeStatistiques() {
statistiques = new Statistiques(); statistiques = new Statistiques();
statistiques.setTotalMembres(234); try {
List<MembreDTO> membres = membreService.listerTous();
statistiques.setTotalMembres(membres.size());
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des statistiques: " + e.getMessage());
statistiques.setTotalMembres(0);
}
statistiques.setResultatsActuels(0); statistiques.setResultatsActuels(0);
statistiques.setFiltresActifs(0); statistiques.setFiltresActifs(0);
statistiques.setTempsRecherche(25); statistiques.setTempsRecherche(0);
} }
private void initializeDonnees() { private void initializeDonnees() {
tousLesMembres = new ArrayList<>(); tousLesMembres = new ArrayList<>();
selectedMembres = new ArrayList<>(); selectedMembres = new ArrayList<>();
// Génération de données de test try {
String[] noms = {"DIALLO", "FALL", "NDIAYE", "DIOUF", "SARR", "BA", "SALL", "TOURE", "GUEYE", "NDOUR"}; List<MembreDTO> membresDTO = membreService.listerTous();
String[] prenoms = {"Amadou", "Fatou", "Ousmane", "Awa", "Mamadou", "Aida", "Ibrahima", "Mariam", "Moussa", "Khady"}; for (MembreDTO dto : membresDTO) {
String[] professions = {"Enseignant", "Médecin", "Ingénieur", "Commerçant", "Agriculteur", "Fonctionnaire", "Artisan", "Avocat"}; Membre membre = convertToMembre(dto);
String[] villes = {"Dakar", "Thiès", "Kaolack", "Saint-Louis", "Ziguinchor", "Diourbel", "Tambacounda"};
String[] typesMembre = {"ACTIF", "ASSOCIE", "BIENFAITEUR", "HONORAIRE"};
String[] statuts = {"ACTIF", "INACTIF", "SUSPENDU"};
String[] entites = {"LIONS CLUB Dakar Métropole", "LIONS CLUB Thiès", "LIONS CLUB Kaolack"};
for (int i = 1; i <= 50; i++) {
Membre membre = new Membre();
membre.setId((long) i);
membre.setNumeroMembre("M2024" + String.format("%03d", i));
membre.setNom(noms[i % noms.length]);
membre.setPrenom(prenoms[i % prenoms.length]);
membre.setEmail(membre.getPrenom().toLowerCase() + "." + membre.getNom().toLowerCase() + "@email.com");
membre.setTelephone("77 123 45 " + String.format("%02d", i));
membre.setProfession(professions[i % professions.length]);
membre.setVille(villes[i % villes.length]);
membre.setTypeMembre(typesMembre[i % typesMembre.length]);
membre.setStatut(statuts[i % statuts.length]);
membre.setEntite(entites[i % entites.length]);
membre.setDateAdhesion(LocalDate.now().minusMonths(i));
membre.setCotisationStatut(i % 5 == 0 ? "En retard" : "À jour");
membre.setTauxParticipation(60 + (i % 40));
membre.setEvenementsAnnee(i % 15 + 2);
membre.setGenre(i % 2 == 0 ? "M" : "F");
membre.setAge(25 + (i % 40));
membre.setADesEnfants(i % 3 == 0);
membre.setARecuAides(i % 7 == 0);
tousLesMembres.add(membre); tousLesMembres.add(membre);
} }
resultats = new ArrayList<>(tousLesMembres); resultats = new ArrayList<>(tousLesMembres);
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des membres: " + e.getMessage());
resultats = new ArrayList<>();
}
}
private Membre convertToMembre(MembreDTO dto) {
Membre membre = new Membre();
membre.setId(dto.getId());
membre.setNumeroMembre(dto.getNumeroMembre());
membre.setNom(dto.getNom());
membre.setPrenom(dto.getPrenom());
membre.setEmail(dto.getEmail());
membre.setTelephone(dto.getTelephone());
membre.setProfession(dto.getProfession());
membre.setVille(""); // Ville non disponible dans MembreDTO
membre.setTypeMembre("ACTIF"); // Type membre non disponible dans MembreDTO
if (dto.getStatut() != null) {
membre.setStatut(dto.getStatut());
} else {
membre.setStatut("ACTIF");
}
membre.setDateAdhesion(dto.getDateInscription() != null ? dto.getDateInscription().toLocalDate() : null);
return membre;
} }
private void initializeEntites() { private void initializeEntites() {
entitesDisponibles = new ArrayList<>(); entitesDisponibles = new ArrayList<>();
for (int i = 1; i <= 5; i++) { try {
List<dev.lions.unionflow.client.dto.AssociationDTO> associations = associationService.listerActives();
for (dev.lions.unionflow.client.dto.AssociationDTO assoc : associations) {
Entite entite = new Entite(); Entite entite = new Entite();
entite.setId((long) i); entite.setId(assoc.getId());
entite.setNom("LIONS CLUB " + (i == 1 ? "Dakar Métropole" : entite.setNom(assoc.getNom());
i == 2 ? "Thiès" :
i == 3 ? "Kaolack" :
i == 4 ? "Saint-Louis" : "Ziguinchor"));
entitesDisponibles.add(entite); entitesDisponibles.add(entite);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des entités: " + e.getMessage());
}
} }
private void initializeRecherchesSauvegardees() { private void initializeRecherchesSauvegardees() {
recherchesSauvegardees = new ArrayList<>(); recherchesSauvegardees = new ArrayList<>();
RechercheSauvegardee recherche1 = new RechercheSauvegardee();
recherche1.setId(1L);
recherche1.setNom("Membres actifs 2024");
recherche1.setDescription("Tous les membres actifs adhérés en 2024");
recherche1.setNombreCriteres(3);
recherche1.setDateCreation(LocalDate.now().minusDays(5));
recherche1.setPublique(true);
recherchesSauvegardees.add(recherche1);
RechercheSauvegardee recherche2 = new RechercheSauvegardee();
recherche2.setId(2L);
recherche2.setNom("Cotisations en retard");
recherche2.setDescription("Membres avec cotisations en retard");
recherche2.setNombreCriteres(2);
recherche2.setDateCreation(LocalDate.now().minusDays(2));
recherche2.setPublique(false);
recherchesSauvegardees.add(recherche2);
nouvelleRechercheSauvegardee = new RechercheSauvegardee(); nouvelleRechercheSauvegardee = new RechercheSauvegardee();
} }
@@ -140,9 +141,25 @@ public class MembreRechercheBean implements Serializable {
public void effectuerRecherche() { public void effectuerRecherche() {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
resultats = tousLesMembres.stream() try {
.filter(this::appliquerFiltres) List<MembreDTO> membresDTO = membreService.rechercher(
filtres.getNom(),
filtres.getPrenom(),
filtres.getEmail(),
filtres.getTelephone(),
filtres.getStatuts() != null && !filtres.getStatuts().isEmpty() ? filtres.getStatuts().get(0) : null,
null,
0,
100
);
resultats = membresDTO.stream()
.map(this::convertToMembre)
.collect(Collectors.toList()); .collect(Collectors.toList());
} catch (Exception e) {
LOGGER.severe("Erreur lors de la recherche: " + e.getMessage());
resultats = new ArrayList<>();
}
long endTime = System.currentTimeMillis(); long endTime = System.currentTimeMillis();
@@ -309,22 +326,22 @@ public class MembreRechercheBean implements Serializable {
} }
public void contacterMembre(Membre membre) { public void contacterMembre(Membre membre) {
System.out.println("Contacter le membre: " + membre.getNomComplet()); LOGGER.info("Contacter le membre: " + membre.getNomComplet());
} }
public void ajouterAuGroupe(Membre membre) { public void ajouterAuGroupe(Membre membre) {
System.out.println("Ajouter au groupe: " + membre.getNomComplet()); LOGGER.info("Ajouter au groupe: " + membre.getNomComplet());
} }
// Gestion des recherches sauvegardées // Gestion des recherches sauvegardées
public void sauvegarderRecherche() { public void sauvegarderRecherche() {
nouvelleRechercheSauvegardee.setId((long) (recherchesSauvegardees.size() + 1)); nouvelleRechercheSauvegardee.setId(UUID.randomUUID());
nouvelleRechercheSauvegardee.setNombreCriteres(compterFiltresActifs()); nouvelleRechercheSauvegardee.setNombreCriteres(compterFiltresActifs());
nouvelleRechercheSauvegardee.setDateCreation(LocalDate.now()); nouvelleRechercheSauvegardee.setDateCreation(LocalDate.now());
recherchesSauvegardees.add(nouvelleRechercheSauvegardee); recherchesSauvegardees.add(nouvelleRechercheSauvegardee);
System.out.println("Recherche sauvegardée: " + nouvelleRechercheSauvegardee.getNom()); LOGGER.info("Recherche sauvegardée: " + nouvelleRechercheSauvegardee.getNom());
nouvelleRechercheSauvegardee = new RechercheSauvegardee(); nouvelleRechercheSauvegardee = new RechercheSauvegardee();
} }
@@ -341,17 +358,17 @@ public class MembreRechercheBean implements Serializable {
} }
effectuerRecherche(); effectuerRecherche();
System.out.println("Recherche chargée: " + recherche.getNom()); LOGGER.info("Recherche chargée: " + recherche.getNom());
} }
public void supprimerRecherche(RechercheSauvegardee recherche) { public void supprimerRecherche(RechercheSauvegardee recherche) {
recherchesSauvegardees.remove(recherche); recherchesSauvegardees.remove(recherche);
System.out.println("Recherche supprimée: " + recherche.getNom()); LOGGER.info("Recherche supprimée: " + recherche.getNom());
} }
// Actions groupées // Actions groupées
public void envoyerMessageGroupe() { public void envoyerMessageGroupe() {
System.out.println("Message '" + messageGroupe.getSujet() + "' envoyé à " + LOGGER.info("Message '" + messageGroupe.getSujet() + "' envoyé à " +
selectedMembres.size() + " membres via " + messageGroupe.getCanaux()); selectedMembres.size() + " membres via " + messageGroupe.getCanaux());
messageGroupe = new MessageGroupe(); messageGroupe = new MessageGroupe();
@@ -359,7 +376,7 @@ public class MembreRechercheBean implements Serializable {
} }
public void exporterSelection() { public void exporterSelection() {
System.out.println("Export de " + selectedMembres.size() + " membres sélectionnés"); LOGGER.info("Export de " + selectedMembres.size() + " membres sélectionnés");
} }
// Méthodes d'autocomplétion // Méthodes d'autocomplétion
@@ -514,7 +531,7 @@ public class MembreRechercheBean implements Serializable {
} }
public static class Membre { public static class Membre {
private Long id; private UUID id;
private String numeroMembre; private String numeroMembre;
private String nom; private String nom;
private String prenom; private String prenom;
@@ -536,8 +553,8 @@ public class MembreRechercheBean implements Serializable {
private boolean aRecuAides; private boolean aRecuAides;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNumeroMembre() { return numeroMembre; } public String getNumeroMembre() { return numeroMembre; }
public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; } public void setNumeroMembre(String numeroMembre) { this.numeroMembre = numeroMembre; }
@@ -661,18 +678,18 @@ public class MembreRechercheBean implements Serializable {
} }
public static class Entite { public static class Entite {
private Long id; private UUID id;
private String nom; private String nom;
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }
} }
public static class RechercheSauvegardee { public static class RechercheSauvegardee {
private Long id; private UUID id;
private String nom; private String nom;
private String description; private String description;
private int nombreCriteres; private int nombreCriteres;
@@ -680,8 +697,8 @@ public class MembreRechercheBean implements Serializable {
private boolean publique; private boolean publique;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }

View File

@@ -1,6 +1,5 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.security.JwtTokenManager;
import jakarta.enterprise.context.RequestScoped; import jakarta.enterprise.context.RequestScoped;
import jakarta.faces.context.FacesContext; import jakarta.faces.context.FacesContext;
import jakarta.inject.Inject; import jakarta.inject.Inject;
@@ -9,6 +8,12 @@ import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.util.logging.Logger; import java.util.logging.Logger;
/**
* Bean de navigation avec authentification Keycloak OIDC
*
* @author UnionFlow Team
* @version 2.0
*/
@Named("navigationBean") @Named("navigationBean")
@RequestScoped @RequestScoped
public class NavigationBean implements Serializable { public class NavigationBean implements Serializable {
@@ -19,9 +24,6 @@ public class NavigationBean implements Serializable {
@Inject @Inject
private UserSession userSession; private UserSession userSession;
@Inject
private JwtTokenManager tokenManager;
public void checkAuthentication() throws IOException { public void checkAuthentication() throws IOException {
FacesContext context = FacesContext.getCurrentInstance(); FacesContext context = FacesContext.getCurrentInstance();
@@ -32,15 +34,16 @@ public class NavigationBean implements Serializable {
context.getExternalContext().getRequestContextPath() + dashboardUrl context.getExternalContext().getRequestContextPath() + dashboardUrl
); );
} else { } else {
// L'utilisateur n'est pas connecté, rediriger vers la page de login // L'utilisateur n'est pas connecté, rediriger vers la racine qui déclenchera Keycloak
context.getExternalContext().redirect( context.getExternalContext().redirect(
context.getExternalContext().getRequestContextPath() + "/pages/public/login.xhtml" context.getExternalContext().getRequestContextPath() + "/"
); );
} }
} }
public String redirectToLogin() { public String redirectToLogin() {
return "/pages/public/login?faces-redirect=true"; // Redirection vers la racine qui déclenchera automatiquement Keycloak
return "/?faces-redirect=true";
} }
public String goToDashboard() { public String goToDashboard() {
@@ -78,10 +81,8 @@ public class NavigationBean implements Serializable {
} }
private boolean isUserAuthenticated() { private boolean isUserAuthenticated() {
return userSession != null && // Avec Keycloak OIDC, UserSession vérifie automatiquement l'authentification via JsonWebToken
userSession.isAuthenticated() && return userSession != null && userSession.isAuthenticated();
tokenManager != null &&
tokenManager.hasValidTokens();
} }
private String getDashboardUrlForUserType() { private String getDashboardUrlForUserType() {

View File

@@ -1,20 +1,57 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.service.AnalyticsService;
import dev.lions.unionflow.client.service.MembreService;
import dev.lions.unionflow.client.service.CotisationService;
import dev.lions.unionflow.client.service.EvenementService;
import dev.lions.unionflow.client.service.DemandeAideService;
import dev.lions.unionflow.client.service.AssociationService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.logging.Logger;
@Named("rapportsBean") @Named("rapportsBean")
@SessionScoped @SessionScoped
public class RapportsBean implements Serializable { public class RapportsBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(RapportsBean.class.getName());
@Inject
@RestClient
private AnalyticsService analyticsService;
@Inject
@RestClient
private MembreService membreService;
@Inject
@RestClient
private CotisationService cotisationService;
@Inject
@RestClient
private EvenementService evenementService;
@Inject
@RestClient
private DemandeAideService demandeAideService;
@Inject
@RestClient
private AssociationService associationService;
private String organisationId; // À injecter depuis la session
private String periodeRapide; private String periodeRapide;
private LocalDate dateDebut; private LocalDate dateDebut;
@@ -57,260 +94,212 @@ public class RapportsBean implements Serializable {
private void initializeIndicateurs() { private void initializeIndicateurs() {
indicateurs = new IndicateursGlobaux(); indicateurs = new IndicateursGlobaux();
indicateurs.setTotalMembres(1247); try {
indicateurs.setCroissanceMembres(8.5); int totalMembres = membreService.listerTous().size();
indicateurs.setRevenus("45 750 000 FCFA"); int totalEvenements = evenementService.listerTous(0, 1000).size();
indicateurs.setCroissanceRevenus(12.3);
indicateurs.setTotalEvenements(42); BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
indicateurs.setCroissanceEvenements(15.7); .filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
indicateurs.setTotalAides("12 850 000 FCFA"); .map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
indicateurs.setCroissanceAides(22.1); .reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal totalAides = demandeAideService.listerToutes(0, 1000).stream()
.filter(d -> d.getMontantAccorde() != null)
.map(d -> d.getMontantAccorde())
.reduce(BigDecimal.ZERO, BigDecimal::add);
indicateurs.setTotalMembres(totalMembres);
indicateurs.setCroissanceMembres(0.0); // À calculer depuis les données historiques
indicateurs.setRevenus(formatMontantCourt(totalRevenus) + " FCFA");
indicateurs.setCroissanceRevenus(0.0); // À calculer depuis les données historiques
indicateurs.setTotalEvenements(totalEvenements);
indicateurs.setCroissanceEvenements(0.0); // À calculer depuis les données historiques
indicateurs.setTotalAides(formatMontantCourt(totalAides) + " FCFA");
indicateurs.setCroissanceAides(0.0); // À calculer depuis les données historiques
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des indicateurs: " + e.getMessage());
indicateurs.setTotalMembres(0);
indicateurs.setCroissanceMembres(0.0);
indicateurs.setRevenus("0 FCFA");
indicateurs.setCroissanceRevenus(0.0);
indicateurs.setTotalEvenements(0);
indicateurs.setCroissanceEvenements(0.0);
indicateurs.setTotalAides("0 FCFA");
indicateurs.setCroissanceAides(0.0);
}
} }
private void initializeEvolutionMensuelle() { private void initializeEvolutionMensuelle() {
evolutionMensuelle = new ArrayList<>(); evolutionMensuelle = new ArrayList<>();
String[] mois = {"Jan", "Fév", "Mar", "Avr", "Mai", "Jun"}; try {
int[] membres = {1150, 1180, 1205, 1225, 1240, 1247}; if (organisationId != null && dateDebut != null && dateFin != null) {
double[] revenus = {3.2, 3.8, 4.1, 4.5, 3.9, 4.2}; String periode = "CUSTOM"; // À mapper depuis dateDebut/dateFin
analyticsService.getEvolutionMensuelle("NOMBRE_MEMBRES_ACTIFS", organisationId, periode);
for (int i = 0; i < mois.length; i++) { // Traiter les données de l'API
EvolutionMensuelle evolution = new EvolutionMensuelle(); // Pour l'instant, initialiser avec des données vides
evolution.setLibelle(mois[i]);
evolution.setMembres(membres[i]);
evolution.setRevenus(revenus[i]);
evolution.setHauteurMembres((int) ((membres[i] - 1100) / 2));
evolution.setHauteurRevenus((int) (revenus[i] * 15));
evolutionMensuelle.add(evolution);
} }
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement de l'évolution mensuelle: " + e.getMessage());
}
// Si pas de données, laisser la liste vide plutôt que des données mockées
} }
private void initializeObjectifs() { private void initializeObjectifs() {
objectifs = new ArrayList<>(); objectifs = new ArrayList<>();
try {
int totalMembres = membreService.listerTous().size();
int totalEvenements = evenementService.listerTous(0, 1000).size();
int totalDemandes = demandeAideService.listerToutes(0, 1000).size();
BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
.filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
.map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
Objectif obj1 = new Objectif(); Objectif obj1 = new Objectif();
obj1.setLibelle("Nouveaux Membres"); obj1.setLibelle("Nouveaux Membres");
obj1.setRealise("247"); obj1.setRealise(String.valueOf(totalMembres));
obj1.setCible("300"); obj1.setCible(String.valueOf((int) (totalMembres * 1.2))); // Objectif 20% supérieur
obj1.setPourcentage(82); obj1.setPourcentage(totalMembres > 0 ? (int) ((double) totalMembres / (totalMembres * 1.2) * 100) : 0);
objectifs.add(obj1); objectifs.add(obj1);
Objectif obj2 = new Objectif(); Objectif obj2 = new Objectif();
obj2.setLibelle("Revenus Cotisations"); obj2.setLibelle("Revenus Cotisations");
obj2.setRealise("38.5M"); obj2.setRealise(formatMontantCourt(totalRevenus));
obj2.setCible("45M"); obj2.setCible(formatMontantCourt(totalRevenus.multiply(new BigDecimal("1.2"))));
obj2.setPourcentage(86); obj2.setPourcentage(83); // À calculer
objectifs.add(obj2); objectifs.add(obj2);
Objectif obj3 = new Objectif(); Objectif obj3 = new Objectif();
obj3.setLibelle("Événements Organisés"); obj3.setLibelle("Événements Organisés");
obj3.setRealise("42"); obj3.setRealise(String.valueOf(totalEvenements));
obj3.setCible("50"); obj3.setCible(String.valueOf((int) (totalEvenements * 1.2)));
obj3.setPourcentage(84); obj3.setPourcentage(totalEvenements > 0 ? (int) ((double) totalEvenements / (totalEvenements * 1.2) * 100) : 0);
objectifs.add(obj3); objectifs.add(obj3);
Objectif obj4 = new Objectif(); Objectif obj4 = new Objectif();
obj4.setLibelle("Aides Accordées"); obj4.setLibelle("Aides Accordées");
obj4.setRealise("156"); obj4.setRealise(String.valueOf(totalDemandes));
obj4.setCible("200"); obj4.setCible(String.valueOf((int) (totalDemandes * 1.3)));
obj4.setPourcentage(78); obj4.setPourcentage(totalDemandes > 0 ? (int) ((double) totalDemandes / (totalDemandes * 1.3) * 100) : 0);
objectifs.add(obj4); objectifs.add(obj4);
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des objectifs: " + e.getMessage());
}
}
private String formatMontantCourt(BigDecimal montant) {
if (montant == null) return "0";
double millions = montant.doubleValue() / 1_000_000.0;
if (millions >= 1) {
return String.format("%.1fM", millions);
}
return String.format("%.0fK", montant.doubleValue() / 1_000.0);
} }
private void initializeRepartitions() { private void initializeRepartitions() {
repartitionMembres = new ArrayList<>(); repartitionMembres = new ArrayList<>();
try {
List<dev.lions.unionflow.client.dto.MembreDTO> membres = membreService.listerTous();
long actifs = membres.stream().filter(m -> "ACTIF".equals(m.getStatut())).count();
long inactifs = membres.stream().filter(m -> "INACTIF".equals(m.getStatut())).count();
long total = membres.size();
RepartitionMembres actifs = new RepartitionMembres(); if (total > 0) {
actifs.setLibelle("Membres Actifs"); RepartitionMembres actifsRep = new RepartitionMembres();
actifs.setNombre(987); actifsRep.setLibelle("Membres Actifs");
actifs.setPourcentage(79.2); actifsRep.setNombre((int) actifs);
actifs.setCouleur("green-500"); actifsRep.setPourcentage((double) actifs / total * 100.0);
repartitionMembres.add(actifs); actifsRep.setCouleur("green-500");
repartitionMembres.add(actifsRep);
RepartitionMembres inactifs = new RepartitionMembres(); RepartitionMembres inactifsRep = new RepartitionMembres();
inactifs.setLibelle("Membres Inactifs"); inactifsRep.setLibelle("Membres Inactifs");
inactifs.setNombre(185); inactifsRep.setNombre((int) inactifs);
inactifs.setPourcentage(14.8); inactifsRep.setPourcentage((double) inactifs / total * 100.0);
inactifs.setCouleur("orange-500"); inactifsRep.setCouleur("orange-500");
repartitionMembres.add(inactifs); repartitionMembres.add(inactifsRep);
}
RepartitionMembres nouveaux = new RepartitionMembres(); } catch (Exception e) {
nouveaux.setLibelle("Nouveaux Membres"); LOGGER.severe("Erreur lors du calcul de la répartition des membres: " + e.getMessage());
nouveaux.setNombre(75); }
nouveaux.setPourcentage(6.0);
nouveaux.setCouleur("blue-500");
repartitionMembres.add(nouveaux);
sourceRevenus = new ArrayList<>(); sourceRevenus = new ArrayList<>();
try {
BigDecimal totalRevenus = cotisationService.listerToutes(0, 1000).stream()
.filter(c -> "PAYEE".equals(c.getStatut()) || "PARTIELLEMENT_PAYEE".equals(c.getStatut()))
.map(c -> c.getMontantPaye() != null ? c.getMontantPaye() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
if (totalRevenus.compareTo(BigDecimal.ZERO) > 0) {
SourceRevenus cotisations = new SourceRevenus(); SourceRevenus cotisations = new SourceRevenus();
cotisations.setLibelle("Cotisations"); cotisations.setLibelle("Cotisations");
cotisations.setMontant("28.5M FCFA"); cotisations.setMontant(formatMontantCourt(totalRevenus));
cotisations.setPourcentage(62.3); cotisations.setPourcentage(100.0); // Pour l'instant, uniquement cotisations
cotisations.setCouleur("blue-500"); cotisations.setCouleur("blue-500");
cotisations.setIcon("pi-users"); cotisations.setIcon("pi-users");
sourceRevenus.add(cotisations); sourceRevenus.add(cotisations);
}
SourceRevenus evenements = new SourceRevenus(); } catch (Exception e) {
evenements.setLibelle("Événements"); LOGGER.severe("Erreur lors du calcul des sources de revenus: " + e.getMessage());
evenements.setMontant("12.8M FCFA"); }
evenements.setPourcentage(28.0);
evenements.setCouleur("green-500");
evenements.setIcon("pi-calendar");
sourceRevenus.add(evenements);
SourceRevenus dons = new SourceRevenus();
dons.setLibelle("Dons & Subventions");
dons.setMontant("4.4M FCFA");
dons.setPourcentage(9.7);
dons.setCouleur("purple-500");
dons.setIcon("pi-heart");
sourceRevenus.add(dons);
} }
private void initializeTopEntites() { private void initializeTopEntites() {
topEntites = new ArrayList<>(); topEntites = new ArrayList<>();
try {
String[] noms = { List<dev.lions.unionflow.client.dto.AssociationDTO> associations = associationService.listerActives();
"Association Alpha Centrale", "Club Beta Régional", "Groupe Gamma Local", topEntites = associations.stream()
"Association Delta Nord", "Club Epsilon Sud" .sorted((a1, a2) -> {
}; int m1 = a1.getNombreMembres() != null ? a1.getNombreMembres() : 0;
int m2 = a2.getNombreMembres() != null ? a2.getNombreMembres() : 0;
String[] icons = {"pi-users", "pi-home", "pi-sitemap", "pi-users", "pi-home"}; return Integer.compare(m2, m1);
int[] scores = {95, 89, 84, 78, 72}; })
String[] tendances = {"UP", "UP", "STABLE", "DOWN", "UP"}; .limit(5)
.map(a -> {
for (int i = 0; i < noms.length; i++) {
TopEntite entite = new TopEntite(); TopEntite entite = new TopEntite();
entite.setRang(i + 1); entite.setRang(0); // À calculer
entite.setNom(noms[i]); entite.setNom(a.getNom());
entite.setTypeIcon(icons[i]); entite.setTypeIcon("pi-users");
entite.setScore(scores[i]); entite.setScore(0); // À calculer depuis les métriques
entite.setTendance(tendances[i]); entite.setTendance("STABLE"); // À calculer
topEntites.add(entite); return entite;
})
.collect(java.util.stream.Collectors.toList());
// Assigner les rangs
for (int i = 0; i < topEntites.size(); i++) {
topEntites.get(i).setRang(i + 1);
}
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des top entités: " + e.getMessage());
} }
} }
private void initializeKPIs() { private void initializeKPIs() {
kpis = new ArrayList<>(); kpis = new ArrayList<>();
try {
KPI participation = new KPI(); if (organisationId != null && dateDebut != null && dateFin != null) {
participation.setLibelle("Taux de Participation"); String periode = "CUSTOM"; // À mapper depuis dateDebut/dateFin
participation.setValeur("84%"); analyticsService.getKPIs(organisationId, periode);
participation.setProgression(84); // Traiter les données de l'API
participation.setVariation(5.2); // Pour l'instant, laisser la liste vide plutôt que des données mockées
participation.setTendance("UP"); }
participation.setIcon("pi-users"); } catch (Exception e) {
participation.setCouleur("blue-500"); LOGGER.severe("Erreur lors du chargement des KPIs: " + e.getMessage());
kpis.add(participation); }
KPI satisfaction = new KPI();
satisfaction.setLibelle("Satisfaction Membres");
satisfaction.setValeur("92%");
satisfaction.setProgression(92);
satisfaction.setVariation(3.1);
satisfaction.setTendance("UP");
satisfaction.setIcon("pi-star");
satisfaction.setCouleur("green-500");
kpis.add(satisfaction);
KPI retention = new KPI();
retention.setLibelle("Taux de Rétention");
retention.setValeur("88%");
retention.setProgression(88);
retention.setVariation(-1.8);
retention.setTendance("DOWN");
retention.setIcon("pi-refresh");
retention.setCouleur("orange-500");
kpis.add(retention);
KPI croissance = new KPI();
croissance.setLibelle("Croissance Mensuelle");
croissance.setValeur("2.1%");
croissance.setProgression(75);
croissance.setVariation(0.8);
croissance.setTendance("UP");
croissance.setIcon("pi-chart-line");
croissance.setCouleur("purple-500");
kpis.add(croissance);
} }
private void initializeAlertes() { private void initializeAlertes() {
alertes = new ArrayList<>(); alertes = new ArrayList<>();
// Les alertes seront calculées depuis les données réelles
Alerte baisseCotisations = new Alerte(); // Pour l'instant, laisser la liste vide plutôt que des données mockées
baisseCotisations.setTitre("Baisse des Cotisations");
baisseCotisations.setDescription("Les cotisations ont diminué de 8% ce mois-ci par rapport au mois précédent.");
baisseCotisations.setPriorite("HAUTE");
baisseCotisations.setSeverite("warning");
baisseCotisations.setSeveriteCouleur("orange-500");
baisseCotisations.setIcon("pi-exclamation-triangle");
baisseCotisations.setDateDetection("Il y a 2 jours");
alertes.add(baisseCotisations);
Alerte objectifManque = new Alerte();
objectifManque.setTitre("Objectif Membres Non Atteint");
objectifManque.setDescription("L'objectif de nouveaux membres risque de ne pas être atteint ce trimestre.");
objectifManque.setPriorite("MOYENNE");
objectifManque.setSeverite("info");
objectifManque.setSeveriteCouleur("blue-500");
objectifManque.setIcon("pi-info-circle");
objectifManque.setDateDetection("Il y a 5 jours");
alertes.add(objectifManque);
Alerte budgetDepasse = new Alerte();
budgetDepasse.setTitre("Budget Événements Dépassé");
budgetDepasse.setDescription("Le budget alloué aux événements a été dépassé de 15% ce mois-ci.");
budgetDepasse.setPriorite("CRITIQUE");
budgetDepasse.setSeverite("danger");
budgetDepasse.setSeveriteCouleur("red-500");
budgetDepasse.setIcon("pi-exclamation-circle");
budgetDepasse.setDateDetection("Hier");
alertes.add(budgetDepasse);
Alerte performance = new Alerte();
performance.setTitre("Performance Excellente");
performance.setDescription("Félicitations ! La satisfaction des membres a atteint un niveau record de 92%.");
performance.setPriorite("INFO");
performance.setSeverite("success");
performance.setSeveriteCouleur("green-500");
performance.setIcon("pi-check-circle");
performance.setDateDetection("Il y a 1 semaine");
alertes.add(performance);
} }
private void initializeHistoriqueRapports() { private void initializeHistoriqueRapports() {
historiqueRapports = new ArrayList<>(); historiqueRapports = new ArrayList<>();
// L'historique des rapports sera chargé depuis la base de données
String[] types = {"FINANCIER", "MEMBRES", "ACTIVITES", "PERFORMANCE", "COMPLET"}; // Pour l'instant, laisser la liste vide plutôt que des données mockées
String[] typesLibelles = {"Rapport Financier", "Rapport Membres", "Rapport Activités", "Rapport Performance", "Rapport Complet"};
String[] typeIcons = {"pi-dollar", "pi-users", "pi-calendar", "pi-chart-bar", "pi-file"};
String[] typeCouleurs = {"green-500", "blue-500", "orange-500", "purple-500", "indigo-500"};
String[] generesPar = {"Marie Kouassi", "Paul Traoré", "Fatou Sanogo", "Jean Ouattara", "Aissata Koné"};
String[] statuts = {"GENERE", "EN_COURS", "GENERE", "GENERE", "PLANIFIE"};
for (int i = 0; i < 15; i++) {
HistoriqueRapport rapport = new HistoriqueRapport();
rapport.setId((long) (i + 1));
rapport.setType(types[i % types.length]);
rapport.setTypeLibelle(typesLibelles[i % typesLibelles.length]);
rapport.setTypeIcon(typeIcons[i % typeIcons.length]);
rapport.setTypeCouleur(typeCouleurs[i % typeCouleurs.length]);
rapport.setDateGeneration(LocalDate.now().minusDays(i * 7 + 1));
rapport.setPeriodeCouverte(getDescriptionPeriode(i));
rapport.setGenerePar(generesPar[i % generesPar.length]);
rapport.setStatut(statuts[i % statuts.length]);
historiqueRapports.add(rapport);
}
}
private String getDescriptionPeriode(int index) {
return switch (index % 5) {
case 0 -> "Dernières 4 semaines";
case 1 -> "Trimestre en cours";
case 2 -> "6 derniers mois";
case 3 -> "Année en cours";
default -> "Période personnalisée";
};
} }
private void initializeNouveauRapport() { private void initializeNouveauRapport() {
@@ -322,10 +311,10 @@ public class RapportsBean implements Serializable {
// Actions // Actions
public void genererRapport() { public void genererRapport() {
System.out.println("Génération du rapport " + nouveauRapport.getType() + " en format " + nouveauRapport.getFormat()); LOGGER.info("Génération du rapport " + nouveauRapport.getType() + " en format " + nouveauRapport.getFormat());
HistoriqueRapport nouveauHistorique = new HistoriqueRapport(); HistoriqueRapport nouveauHistorique = new HistoriqueRapport();
nouveauHistorique.setId((long) (historiqueRapports.size() + 1)); nouveauHistorique.setId(UUID.randomUUID());
nouveauHistorique.setType(nouveauRapport.getType()); nouveauHistorique.setType(nouveauRapport.getType());
nouveauHistorique.setTypeLibelle(getTypeLibelle(nouveauRapport.getType())); nouveauHistorique.setTypeLibelle(getTypeLibelle(nouveauRapport.getType()));
nouveauHistorique.setTypeIcon(getTypeIcon(nouveauRapport.getType())); nouveauHistorique.setTypeIcon(getTypeIcon(nouveauRapport.getType()));
@@ -389,11 +378,11 @@ public class RapportsBean implements Serializable {
} }
public void telechargerRapport(HistoriqueRapport rapport) { public void telechargerRapport(HistoriqueRapport rapport) {
System.out.println("Téléchargement du rapport: " + rapport.getTypeLibelle()); LOGGER.info("Téléchargement du rapport: " + rapport.getTypeLibelle());
} }
public void exporterDonnees() { public void exporterDonnees() {
System.out.println("Export des données statistiques"); LOGGER.info("Export des données statistiques");
} }
// Getters et Setters // Getters et Setters
@@ -656,7 +645,7 @@ public class RapportsBean implements Serializable {
} }
public static class HistoriqueRapport { public static class HistoriqueRapport {
private Long id; private UUID id;
private String type; private String type;
private String typeLibelle; private String typeLibelle;
private String typeIcon; private String typeIcon;
@@ -667,8 +656,8 @@ public class RapportsBean implements Serializable {
private String statut; private String statut;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getType() { return type; } public String getType() { return type; }
public void setType(String type) { this.type = type; } public void setType(String type) { this.type = type; }

View File

@@ -1,20 +1,30 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.AssociationDTO;
import dev.lions.unionflow.client.dto.FormulaireDTO;
import dev.lions.unionflow.client.dto.SouscriptionDTO; import dev.lions.unionflow.client.dto.SouscriptionDTO;
import dev.lions.unionflow.client.service.SouscriptionService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
@Named("souscriptionBean") @Named("souscriptionBean")
@SessionScoped @SessionScoped
public class SouscriptionBean implements Serializable { public class SouscriptionBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(SouscriptionBean.class.getName());
@Inject
@RestClient
private SouscriptionService souscriptionService;
private UUID organisationId; // À injecter depuis la session
private List<SouscriptionDTO> souscriptionsOrganisation; private List<SouscriptionDTO> souscriptionsOrganisation;
private SouscriptionDTO souscriptionActive; private SouscriptionDTO souscriptionActive;
@@ -31,33 +41,31 @@ public class SouscriptionBean implements Serializable {
private boolean alerteQuotaProche = false; private boolean alerteQuotaProche = false;
private int joursAvantExpiration = 0; private int joursAvantExpiration = 0;
public SouscriptionBean() { @PostConstruct
public void init() {
if (organisationId != null) {
initializeData(); initializeData();
} else {
LOGGER.warning("Aucun organisationId fourni, impossible de charger les souscriptions");
souscriptionsOrganisation = new ArrayList<>();
}
} }
private void initializeData() { private void initializeData() {
// Simulation d'une souscription active pour démonstration try {
souscriptionActive = new SouscriptionDTO(); souscriptionsOrganisation = souscriptionService.listerToutes(organisationId, 0, 100);
souscriptionActive.setId(1L); souscriptionActive = souscriptionService.obtenirActive(organisationId);
souscriptionActive.setOrganisationId(1L); if (souscriptionActive == null && !souscriptionsOrganisation.isEmpty()) {
souscriptionActive.setOrganisationNom("LIONS CLUB Dakar Métropole"); souscriptionActive = souscriptionsOrganisation.stream()
souscriptionActive.setFormulaireId(2L); .filter(s -> s.getStatut() == SouscriptionDTO.StatutSouscription.ACTIVE)
souscriptionActive.setFormulaireNom("Standard"); .findFirst()
souscriptionActive.setStatut(SouscriptionDTO.StatutSouscription.ACTIVE); .orElse(null);
souscriptionActive.setTypeFacturation(SouscriptionDTO.TypeFacturation.ANNUEL); }
souscriptionActive.setDateDebut(LocalDate.now().minusMonths(3));
souscriptionActive.setDateFin(LocalDate.now().plusMonths(9));
souscriptionActive.setQuotaMaxMembres(200);
souscriptionActive.setMembresActuels(87);
souscriptionActive.setMontantSouscription(new java.math.BigDecimal("30000"));
souscriptionActive.setNotificationExpiration(true);
souscriptionActive.setNotificationQuotaAtteint(true);
// Calculer les statistiques
updateStatistiques(); updateStatistiques();
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des souscriptions: " + e.getMessage());
souscriptionsOrganisation = new ArrayList<>(); souscriptionsOrganisation = new ArrayList<>();
souscriptionsOrganisation.add(souscriptionActive); }
} }
private void updateStatistiques() { private void updateStatistiques() {

View File

@@ -1,8 +1,12 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.AssociationDTO;
import dev.lions.unionflow.client.service.AssociationService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate; import java.time.LocalDate;
@@ -10,12 +14,19 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.logging.Logger;
@Named("superAdminBean") @Named("superAdminBean")
@SessionScoped @SessionScoped
public class SuperAdminBean implements Serializable { public class SuperAdminBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(SuperAdminBean.class.getName());
@Inject
@RestClient
private AssociationService associationService;
private String nomComplet; private String nomComplet;
private String derniereConnexion; private String derniereConnexion;
@@ -71,31 +82,43 @@ public class SuperAdminBean implements Serializable {
} }
private void initializeKPIs() { private void initializeKPIs() {
totalEntites = 127; // Ajusté avec la stratégie volume try {
totalAdministrateurs = 127; List<AssociationDTO> associations = associationService.listerToutes();
totalMembres = 18547; // Moyenne 146 membres par entité totalEntites = associations.size();
revenusGlobaux = "363 000 FCFA"; totalAdministrateurs = associations.size(); // À calculer depuis les utilisateurs
alertesCount = 8; int totalMembresCalc = associations.stream()
croissanceEntites = "12"; .mapToInt(a -> a.getNombreMembres() != null ? a.getNombreMembres() : 0)
activiteJournaliere = 1247; .sum();
totalMembres = totalMembresCalc;
revenusGlobaux = "0 FCFA"; // À calculer depuis les souscriptions
alertesCount = 0; // À calculer
croissanceEntites = "0"; // À calculer
activiteJournaliere = 0; // À calculer
// Initialiser les métriques de souscription // Initialiser les métriques de souscription
totalSouscriptions = 127; totalSouscriptions = 0; // À calculer depuis les souscriptions
souscriptionsActives = 127; souscriptionsActives = 0; // À calculer
souscriptionsExpirantSous30Jours = 12; souscriptionsExpirantSous30Jours = 0; // À calculer
tauxConversion = 68.5f; tauxConversion = 0.0f; // À calculer
// Revenus par forfait - nouvelle grille tarifaire // Revenus par forfait - À calculer depuis les souscriptions
revenusStarter = new BigDecimal("88000"); // 44 organisations * 2000 FCFA revenusStarter = BigDecimal.ZERO;
revenusStandard = new BigDecimal("180000"); // 60 organisations * 3000 FCFA revenusStandard = BigDecimal.ZERO;
revenusPremmium = new BigDecimal("80000"); // 20 organisations * 4000 FCFA revenusPremmium = BigDecimal.ZERO;
revenusCristal = new BigDecimal("15000"); // 3 organisations * 5000 FCFA revenusCristal = BigDecimal.ZERO;
// Métriques système // Métriques système
disponibiliteSysteme = 99.8f; disponibiliteSysteme = 99.8f;
tempsReponsMoyen = 145; // ms tempsReponsMoyen = 145; // ms
ticketsSupportOuverts = 8; ticketsSupportOuverts = 0; // À calculer
satisfactionClient = 4.7f; // /5 satisfactionClient = 4.7f; // /5
} catch (Exception e) {
LOGGER.severe("Erreur lors du calcul des KPIs: " + e.getMessage());
totalEntites = 0;
totalAdministrateurs = 0;
totalMembres = 0;
revenusGlobaux = "0 FCFA";
}
} }
private void initializeAlertes() { private void initializeAlertes() {
@@ -103,7 +126,7 @@ public class SuperAdminBean implements Serializable {
// Alertes critiques de souscription // Alertes critiques de souscription
Alerte alerte1 = new Alerte(); Alerte alerte1 = new Alerte();
alerte1.setId(1L); alerte1.setId(UUID.fromString("00000000-0000-0000-0000-00000000a001"));
alerte1.setTitre("12 souscriptions expirent sous 30 jours"); alerte1.setTitre("12 souscriptions expirent sous 30 jours");
alerte1.setEntite("Système - Souscriptions"); alerte1.setEntite("Système - Souscriptions");
alerte1.setDate("Aujourd'hui"); alerte1.setDate("Aujourd'hui");
@@ -112,7 +135,7 @@ public class SuperAdminBean implements Serializable {
alertesRecentes.add(alerte1); alertesRecentes.add(alerte1);
Alerte alerte2 = new Alerte(); Alerte alerte2 = new Alerte();
alerte2.setId(2L); alerte2.setId(UUID.fromString("00000000-0000-0000-0000-00000000a002"));
alerte2.setTitre("Quota membre atteint"); alerte2.setTitre("Quota membre atteint");
alerte2.setEntite("Club Sportif Thiès (Standard)"); alerte2.setEntite("Club Sportif Thiès (Standard)");
alerte2.setDate("Il y a 2h"); alerte2.setDate("Il y a 2h");
@@ -121,7 +144,7 @@ public class SuperAdminBean implements Serializable {
alertesRecentes.add(alerte2); alertesRecentes.add(alerte2);
Alerte alerte3 = new Alerte(); Alerte alerte3 = new Alerte();
alerte3.setId(3L); alerte3.setId(UUID.fromString("00000000-0000-0000-0000-00000000a003"));
alerte3.setTitre("Pic d'inscriptions détecté"); alerte3.setTitre("Pic d'inscriptions détecté");
alerte3.setEntite("Association des Femmes Kaolack"); alerte3.setEntite("Association des Femmes Kaolack");
alerte3.setDate("Il y a 4h"); alerte3.setDate("Il y a 4h");
@@ -130,7 +153,7 @@ public class SuperAdminBean implements Serializable {
alertesRecentes.add(alerte3); alertesRecentes.add(alerte3);
Alerte alerte4 = new Alerte(); Alerte alerte4 = new Alerte();
alerte4.setId(4L); alerte4.setId(UUID.fromString("00000000-0000-0000-0000-00000000a004"));
alerte4.setTitre("Performance système dégradée"); alerte4.setTitre("Performance système dégradée");
alerte4.setEntite("Système - Infrastructure"); alerte4.setEntite("Système - Infrastructure");
alerte4.setDate("Il y a 6h"); alerte4.setDate("Il y a 6h");
@@ -139,7 +162,7 @@ public class SuperAdminBean implements Serializable {
alertesRecentes.add(alerte4); alertesRecentes.add(alerte4);
Alerte alerte5 = new Alerte(); Alerte alerte5 = new Alerte();
alerte5.setId(5L); alerte5.setId(UUID.fromString("00000000-0000-0000-0000-00000000a005"));
alerte5.setTitre("Demande d'upgrade Premium"); alerte5.setTitre("Demande d'upgrade Premium");
alerte5.setEntite("Mutuelle Santé Dakar"); alerte5.setEntite("Mutuelle Santé Dakar");
alerte5.setDate("Hier"); alerte5.setDate("Hier");
@@ -148,7 +171,7 @@ public class SuperAdminBean implements Serializable {
alertesRecentes.add(alerte5); alertesRecentes.add(alerte5);
Alerte alerte6 = new Alerte(); Alerte alerte6 = new Alerte();
alerte6.setId(6L); alerte6.setId(UUID.fromString("00000000-0000-0000-0000-00000000a006"));
alerte6.setTitre("8 tickets support en attente"); alerte6.setTitre("8 tickets support en attente");
alerte6.setEntite("Support Client"); alerte6.setEntite("Support Client");
alerte6.setDate("Il y a 1h"); alerte6.setDate("Il y a 1h");
@@ -159,18 +182,26 @@ public class SuperAdminBean implements Serializable {
private void initializeEntites() { private void initializeEntites() {
topEntites = new ArrayList<>(); topEntites = new ArrayList<>();
try {
String[] noms = {"LIONS CLUB Dakar Métropole", "LIONS CLUB Thiès", "LIONS CLUB Kaolack", "LIONS CLUB Saint-Louis", "LIONS CLUB Ziguinchor"}; List<AssociationDTO> associations = associationService.listerActives();
String[] types = {"Club Principal", "Club Régional", "Club Régional", "Club Régional", "Club Régional"}; topEntites = associations.stream()
int[] membres = {156, 123, 98, 87, 73}; .sorted((a1, a2) -> {
int m1 = a1.getNombreMembres() != null ? a1.getNombreMembres() : 0;
for (int i = 0; i < 5; i++) { int m2 = a2.getNombreMembres() != null ? a2.getNombreMembres() : 0;
return Integer.compare(m2, m1);
})
.limit(5)
.map(a -> {
Entite entite = new Entite(); Entite entite = new Entite();
entite.setId((long) (i + 1)); entite.setId(a.getId());
entite.setNom(noms[i]); entite.setNom(a.getNom());
entite.setTypeEntite(types[i]); entite.setTypeEntite(a.getTypeAssociation());
entite.setNombreMembres(membres[i]); entite.setNombreMembres(a.getNombreMembres() != null ? a.getNombreMembres() : 0);
topEntites.add(entite); return entite;
})
.collect(java.util.stream.Collectors.toList());
} catch (Exception e) {
LOGGER.severe("Erreur lors du chargement des top entités: " + e.getMessage());
} }
} }
@@ -245,7 +276,7 @@ public class SuperAdminBean implements Serializable {
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
Activite activite = new Activite(); Activite activite = new Activite();
activite.setId((long) (i + 1)); activite.setId(UUID.randomUUID());
activite.setDescription(descriptions[i]); activite.setDescription(descriptions[i]);
activite.setEntite(entites[i]); activite.setEntite(entites[i]);
activite.setIcone(icones[i]); activite.setIcone(icones[i]);
@@ -320,7 +351,7 @@ public class SuperAdminBean implements Serializable {
} }
public void voirAlerte(Alerte alerte) { public void voirAlerte(Alerte alerte) {
System.out.println("Voir alerte: " + alerte.getTitre()); LOGGER.info("Voir alerte: " + alerte.getTitre());
} }
public String voirToutesAlertes() { public String voirToutesAlertes() {
@@ -332,7 +363,7 @@ public class SuperAdminBean implements Serializable {
} }
public void exporterRapportFinancier() { public void exporterRapportFinancier() {
System.out.println("Export du rapport financier généré"); LOGGER.info("Export du rapport financier généré");
} }
// Getters et Setters // Getters et Setters
@@ -452,7 +483,7 @@ public class SuperAdminBean implements Serializable {
// Classes internes // Classes internes
public static class Alerte { public static class Alerte {
private Long id; private UUID id;
private String titre; private String titre;
private String entite; private String entite;
private String date; private String date;
@@ -460,8 +491,8 @@ public class SuperAdminBean implements Serializable {
private String couleur; private String couleur;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getTitre() { return titre; } public String getTitre() { return titre; }
public void setTitre(String titre) { this.titre = titre; } public void setTitre(String titre) { this.titre = titre; }
@@ -480,14 +511,14 @@ public class SuperAdminBean implements Serializable {
} }
public static class Entite { public static class Entite {
private Long id; private UUID id;
private String nom; private String nom;
private String typeEntite; private String typeEntite;
private int nombreMembres; private int nombreMembres;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }
@@ -532,7 +563,7 @@ public class SuperAdminBean implements Serializable {
} }
public static class Activite { public static class Activite {
private Long id; private UUID id;
private String description; private String description;
private String entite; private String entite;
private String date; private String date;
@@ -541,8 +572,8 @@ public class SuperAdminBean implements Serializable {
private String details; private String details;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getDescription() { return description; } public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; } public void setDescription(String description) { this.description = description; }

View File

@@ -1,12 +1,21 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.auth.LoginResponse;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import org.eclipse.microprofile.jwt.JsonWebToken;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.logging.Logger; import java.util.logging.Logger;
/**
* Gestion de la session utilisateur avec Keycloak OIDC
*
* @author UnionFlow Team
* @version 2.0
*/
@Named("userSession") @Named("userSession")
@SessionScoped @SessionScoped
public class UserSession implements Serializable { public class UserSession implements Serializable {
@@ -14,6 +23,9 @@ public class UserSession implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(UserSession.class.getName()); private static final Logger LOGGER = Logger.getLogger(UserSession.class.getName());
@Inject
private JsonWebToken jwt;
private String username; private String username;
private boolean authenticated = false; private boolean authenticated = false;
private String typeCompte; private String typeCompte;
@@ -27,39 +39,149 @@ public class UserSession implements Serializable {
clearSession(); clearSession();
} }
public void updateFromLoginResponse(LoginResponse loginResponse) { /**
if (loginResponse != null && loginResponse.getUser() != null) { * Initialise la session depuis le token OIDC Keycloak
LoginResponse.UserInfo userInfo = loginResponse.getUser(); * Appelé automatiquement après l'authentification
*/
public void initializeFromOidcToken() {
if (jwt != null && jwt.getName() != null) {
this.authenticated = true; this.authenticated = true;
this.username = userInfo.getUsername(); this.username = jwt.getClaim("preferred_username");
this.typeCompte = userInfo.getTypeCompte(); if (this.username == null) {
this.roles = userInfo.getRoles(); this.username = jwt.getName();
this.permissions = userInfo.getPermissions(); }
// Récupérer les informations du token
String email = jwt.getClaim("email");
String givenName = jwt.getClaim("given_name");
String familyName = jwt.getClaim("family_name");
// Récupérer les rôles depuis le token
this.roles = extractRolesFromToken();
this.typeCompte = determineTypeCompte();
// Mettre à jour les informations utilisateur // Mettre à jour les informations utilisateur
this.currentUser = new CurrentUser(); this.currentUser = new CurrentUser();
this.currentUser.setId(userInfo.getId()); this.currentUser.setUsername(this.username);
this.currentUser.setNom(userInfo.getNom()); this.currentUser.setEmail(email);
this.currentUser.setPrenom(userInfo.getPrenom()); this.currentUser.setPrenom(givenName);
this.currentUser.setEmail(userInfo.getEmail()); this.currentUser.setNom(familyName);
this.currentUser.setUsername(userInfo.getUsername());
// Mettre à jour les informations de l'entité // Générer un ID depuis le subject du token
if (userInfo.getEntite() != null) { String subject = jwt.getSubject();
this.entite = new EntiteInfo(); if (subject != null) {
this.entite.setId(userInfo.getEntite().getId()); try {
this.entite.setNom(userInfo.getEntite().getNom()); this.currentUser.setId(UUID.fromString(subject));
this.entite.setType(userInfo.getEntite().getType()); } catch (IllegalArgumentException e) {
this.entite.setPays(userInfo.getEntite().getPays()); // Si le subject n'est pas un UUID, générer un UUID déterministe
this.entite.setVille(userInfo.getEntite().getVille()); this.currentUser.setId(UUID.nameUUIDFromBytes(subject.getBytes()));
}
} }
LOGGER.info("Session utilisateur mise à jour pour: " + userInfo.getUsername() + LOGGER.info("Session utilisateur initialisée depuis Keycloak pour: " + this.username +
" (Type: " + typeCompte + ")"); " (Type: " + typeCompte + ")");
} }
} }
/**
* Extrait les rôles depuis le token JWT
*/
private List<String> extractRolesFromToken() {
List<String> extractedRoles = new ArrayList<>();
// Rôles dans "realm_access.roles"
try {
Object realmAccess = jwt.getClaim("realm_access");
if (realmAccess instanceof java.util.Map) {
@SuppressWarnings("unchecked")
java.util.Map<String, Object> realmMap = (java.util.Map<String, Object>) realmAccess;
Object rolesObj = realmMap.get("roles");
if (rolesObj instanceof List) {
@SuppressWarnings("unchecked")
List<String> realmRoles = (List<String>) rolesObj;
extractedRoles.addAll(realmRoles);
LOGGER.info("Rôles extraits depuis realm_access.roles: " + realmRoles);
} else {
// Fallback: si realm_access est directement une liste de rôles
if (realmAccess instanceof List) {
@SuppressWarnings("unchecked")
List<String> realmRoles = (List<String>) realmAccess;
extractedRoles.addAll(realmRoles);
LOGGER.info("Rôles extraits depuis realm_access (liste directe): " + realmRoles);
}
}
} else if (realmAccess instanceof List) {
// Fallback: si realm_access est directement une liste de rôles
@SuppressWarnings("unchecked")
List<String> realmRoles = (List<String>) realmAccess;
extractedRoles.addAll(realmRoles);
LOGGER.info("Rôles extraits depuis realm_access (liste): " + realmRoles);
}
} catch (Exception e) {
LOGGER.warning("Erreur lors de l'extraction des rôles realm: " + e.getMessage());
}
// Rôles dans "resource_access"
try {
Object resourceAccess = jwt.getClaim("resource_access");
if (resourceAccess instanceof java.util.Map) {
@SuppressWarnings("unchecked")
java.util.Map<String, Object> resourceMap = (java.util.Map<String, Object>) resourceAccess;
for (Object value : resourceMap.values()) {
if (value instanceof java.util.Map) {
@SuppressWarnings("unchecked")
java.util.Map<String, Object> clientMap = (java.util.Map<String, Object>) value;
Object rolesObj = clientMap.get("roles");
if (rolesObj instanceof List) {
@SuppressWarnings("unchecked")
List<String> clientRoles = (List<String>) rolesObj;
extractedRoles.addAll(clientRoles);
LOGGER.info("Rôles extraits depuis resource_access: " + clientRoles);
}
}
}
}
} catch (Exception e) {
LOGGER.warning("Erreur lors de l'extraction des rôles client: " + e.getMessage());
}
// Fallback: essayer d'extraire les rôles depuis le claim "roles" directement
if (extractedRoles.isEmpty()) {
try {
Object rolesClaim = jwt.getClaim("roles");
if (rolesClaim instanceof List) {
@SuppressWarnings("unchecked")
List<String> directRoles = (List<String>) rolesClaim;
extractedRoles.addAll(directRoles);
LOGGER.info("Rôles extraits depuis claim 'roles': " + directRoles);
}
} catch (Exception e) {
LOGGER.warning("Erreur lors de l'extraction des rôles depuis claim 'roles': " + e.getMessage());
}
}
LOGGER.info("Total des rôles extraits: " + extractedRoles);
return extractedRoles;
}
/**
* Détermine le type de compte depuis les rôles
*/
private String determineTypeCompte() {
if (roles == null || roles.isEmpty()) {
return "MEMBRE";
}
if (roles.contains("SUPER_ADMIN") || roles.contains("super-admin")) {
return "SUPER_ADMIN";
}
if (roles.contains("ADMIN") || roles.contains("admin") || roles.contains("ADMIN_ENTITE")) {
return "ADMIN_ENTITE";
}
return "MEMBRE";
}
public void clearSession() { public void clearSession() {
this.authenticated = false; this.authenticated = false;
this.username = null; this.username = null;
@@ -120,7 +242,11 @@ public class UserSession implements Serializable {
} }
public boolean isAuthenticated() { public boolean isAuthenticated() {
return authenticated; // Vérifier via JsonWebToken
if (jwt != null && jwt.getName() != null && !authenticated) {
initializeFromOidcToken();
}
return authenticated || (jwt != null && jwt.getName() != null);
} }
public void setAuthenticated(boolean authenticated) { public void setAuthenticated(boolean authenticated) {
@@ -169,7 +295,7 @@ public class UserSession implements Serializable {
// Classes internes // Classes internes
public static class CurrentUser implements Serializable { public static class CurrentUser implements Serializable {
private Long id; private UUID id;
private String nom; private String nom;
private String prenom; private String prenom;
private String email; private String email;
@@ -194,11 +320,11 @@ public class UserSession implements Serializable {
} }
// Getters et Setters // Getters et Setters
public Long getId() { public UUID getId() {
return id; return id;
} }
public void setId(Long id) { public void setId(UUID id) {
this.id = id; this.id = id;
} }
@@ -236,7 +362,7 @@ public class UserSession implements Serializable {
} }
public static class EntiteInfo implements Serializable { public static class EntiteInfo implements Serializable {
private Long id; private UUID id;
private String nom; private String nom;
private String type; private String type;
private String pays; private String pays;
@@ -254,11 +380,11 @@ public class UserSession implements Serializable {
} }
// Getters et Setters // Getters et Setters
public Long getId() { public UUID getId() {
return id; return id;
} }
public void setId(Long id) { public void setId(UUID id) {
this.id = id; this.id = id;
} }

View File

@@ -1,21 +1,32 @@
package dev.lions.unionflow.client.view; package dev.lions.unionflow.client.view;
import dev.lions.unionflow.client.dto.AssociationDTO;
import dev.lions.unionflow.client.service.AssociationService;
import jakarta.enterprise.context.SessionScoped; import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named; import jakarta.inject.Named;
import jakarta.annotation.PostConstruct; import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.logging.Logger;
@Named("utilisateursBean") @Named("utilisateursBean")
@SessionScoped @SessionScoped
public class UtilisateursBean implements Serializable { public class UtilisateursBean implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger LOGGER = Logger.getLogger(UtilisateursBean.class.getName());
@Inject
@RestClient
private AssociationService associationService;
private List<Utilisateur> tousLesUtilisateurs; private List<Utilisateur> tousLesUtilisateurs;
private List<Utilisateur> utilisateursFiltres; private List<Utilisateur> utilisateursFiltres;
@@ -30,9 +41,9 @@ public class UtilisateursBean implements Serializable {
@PostConstruct @PostConstruct
public void init() { public void init() {
initializeFiltres(); initializeFiltres();
initializeStatistiques();
initializeOrganisations(); initializeOrganisations();
initializeUtilisateurs(); initializeUtilisateurs();
initializeStatistiques();
initializeNouvelUtilisateur(); initializeNouvelUtilisateur();
appliquerFiltres(); appliquerFiltres();
} }
@@ -44,77 +55,33 @@ public class UtilisateursBean implements Serializable {
private void initializeStatistiques() { private void initializeStatistiques() {
statistiques = new StatistiquesUtilisateurs(); statistiques = new StatistiquesUtilisateurs();
statistiques.setTotalUtilisateurs(47); // Les statistiques seront calculées depuis l'API backend quand elle sera disponible
statistiques.setUtilisateursConnectes(12); statistiques.setTotalUtilisateurs(tousLesUtilisateurs != null ? tousLesUtilisateurs.size() : 0);
statistiques.setAdministrateurs(8); statistiques.setUtilisateursConnectes(0);
statistiques.setUtilisateursDesactives(3); statistiques.setAdministrateurs(0);
statistiques.setUtilisateursDesactives(0);
} }
private void initializeOrganisations() { private void initializeOrganisations() {
organisationsDisponibles = new ArrayList<>(); organisationsDisponibles = new ArrayList<>();
try {
Organisation org1 = new Organisation(); List<AssociationDTO> associations = associationService.listerActives();
org1.setId(1L); for (AssociationDTO assoc : associations) {
org1.setNom("Direction Générale"); Organisation org = new Organisation();
organisationsDisponibles.add(org1); org.setId(assoc.getId());
org.setNom(assoc.getNom());
Organisation org2 = new Organisation(); organisationsDisponibles.add(org);
org2.setId(2L); }
org2.setNom("Services Financiers"); } catch (Exception e) {
organisationsDisponibles.add(org2); LOGGER.severe("Erreur lors du chargement des organisations: " + e.getMessage());
}
Organisation org3 = new Organisation();
org3.setId(3L);
org3.setNom("Ressources Humaines");
organisationsDisponibles.add(org3);
Organisation org4 = new Organisation();
org4.setId(4L);
org4.setNom("Communication");
organisationsDisponibles.add(org4);
} }
private void initializeUtilisateurs() { private void initializeUtilisateurs() {
tousLesUtilisateurs = new ArrayList<>(); tousLesUtilisateurs = new ArrayList<>();
// Les utilisateurs seront chargés depuis l'API backend quand elle sera disponible
String[] noms = { // Pour l'instant, retourner une liste vide
"Koffi", "Asante", "Mensah", "Diallo", "Touré", "Koné", "Ouattara", "Traoré", LOGGER.info("Initialisation des utilisateurs - API backend non disponible");
"Sanogo", "Bakayoko", "Coulibaly", "Cissé", "Gyamfi", "Adjei", "Akoto",
"Boateng", "Ofori", "Owusu", "Asamoah", "Yeboah"
};
String[] prenoms = {
"Kwame", "Ama", "Kofi", "Akosua", "Yaw", "Adwoa", "Kweku", "Afia",
"Kwadwo", "Akua", "Yaa", "Kwabena", "Efua", "Kojo", "Ama",
"Kwesi", "Esi", "Kwaku", "Abena", "Fiifi"
};
String[] roles = {"USER", "GESTIONNAIRE", "ADMIN", "SUPER_ADMIN"};
String[] statuts = {"ACTIF", "INACTIF", "SUSPENDU", "ATTENTE"};
for (int i = 0; i < 30; i++) {
Utilisateur utilisateur = new Utilisateur();
utilisateur.setId((long) (i + 1));
utilisateur.setNom(noms[i % noms.length]);
utilisateur.setPrenom(prenoms[i % prenoms.length]);
utilisateur.setEmail(prenoms[i % prenoms.length].toLowerCase() + "." +
noms[i % noms.length].toLowerCase() + "@unionflow.org");
utilisateur.setTelephone("+225 " + String.format("%02d", (i % 99) + 1) + " " +
String.format("%02d", (i % 99) + 1) + " " +
String.format("%02d", (i % 99) + 1) + " " +
String.format("%02d", (i % 99) + 1));
utilisateur.setRole(roles[i % roles.length]);
utilisateur.setStatut(statuts[i % statuts.length]);
utilisateur.setOrganisationId(organisationsDisponibles.get(i % organisationsDisponibles.size()).getId());
utilisateur.setDateCreation(LocalDateTime.now().minusDays(i + 1));
// Dernière connexion variable
if (i % 4 != 0) { // 75% des utilisateurs ont une dernière connexion
utilisateur.setDerniereConnexion(LocalDateTime.now().minusHours(i + 1).minusMinutes(i * 5));
}
tousLesUtilisateurs.add(utilisateur);
}
} }
private void initializeNouvelUtilisateur() { private void initializeNouvelUtilisateur() {
@@ -170,38 +137,26 @@ public class UtilisateursBean implements Serializable {
} }
public void creerUtilisateur() { public void creerUtilisateur() {
Utilisateur nouvelUtil = new Utilisateur(); // À implémenter quand l'API backend sera disponible
nouvelUtil.setId((long) (tousLesUtilisateurs.size() + 1)); LOGGER.info("Création d'utilisateur - API backend non disponible");
nouvelUtil.setNom(nouvelUtilisateur.getNom());
nouvelUtil.setPrenom(nouvelUtilisateur.getPrenom());
nouvelUtil.setEmail(nouvelUtilisateur.getEmail());
nouvelUtil.setTelephone(nouvelUtilisateur.getTelephone());
nouvelUtil.setRole(nouvelUtilisateur.getRole());
nouvelUtil.setOrganisationId(nouvelUtilisateur.getOrganisationId());
nouvelUtil.setStatut("ACTIF");
nouvelUtil.setDateCreation(LocalDateTime.now());
tousLesUtilisateurs.add(nouvelUtil);
appliquerFiltres();
System.out.println("Nouvel utilisateur créé: " + nouvelUtil.getNomComplet());
initializeNouvelUtilisateur(); initializeNouvelUtilisateur();
} }
public void activerUtilisateur(Utilisateur utilisateur) { public void activerUtilisateur(Utilisateur utilisateur) {
utilisateur.setStatut("ACTIF"); // À implémenter quand l'API backend sera disponible
System.out.println("Utilisateur activé: " + utilisateur.getNomComplet()); LOGGER.info("Activation d'utilisateur - API backend non disponible");
appliquerFiltres(); appliquerFiltres();
} }
public void desactiverUtilisateur(Utilisateur utilisateur) { public void desactiverUtilisateur(Utilisateur utilisateur) {
utilisateur.setStatut("INACTIF"); // À implémenter quand l'API backend sera disponible
System.out.println("Utilisateur désactivé: " + utilisateur.getNomComplet()); LOGGER.info("Désactivation d'utilisateur - API backend non disponible");
appliquerFiltres(); appliquerFiltres();
} }
public void exporterUtilisateurs() { public void exporterUtilisateurs() {
System.out.println("Export de " + utilisateursFiltres.size() + " utilisateurs"); // À implémenter quand l'API backend sera disponible
LOGGER.info("Export d'utilisateurs - API backend non disponible");
} }
// Getters et Setters // Getters et Setters
@@ -231,20 +186,20 @@ public class UtilisateursBean implements Serializable {
// Classes internes // Classes internes
public static class Utilisateur { public static class Utilisateur {
private Long id; private UUID id;
private String nom; private String nom;
private String prenom; private String prenom;
private String email; private String email;
private String telephone; private String telephone;
private String role; private String role;
private String statut; private String statut;
private Long organisationId; private UUID organisationId;
private LocalDateTime dateCreation; private LocalDateTime dateCreation;
private LocalDateTime derniereConnexion; private LocalDateTime derniereConnexion;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }
@@ -264,8 +219,8 @@ public class UtilisateursBean implements Serializable {
public String getStatut() { return statut; } public String getStatut() { return statut; }
public void setStatut(String statut) { this.statut = statut; } public void setStatut(String statut) { this.statut = statut; }
public Long getOrganisationId() { return organisationId; } public UUID getOrganisationId() { return organisationId; }
public void setOrganisationId(Long organisationId) { this.organisationId = organisationId; } public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
public LocalDateTime getDateCreation() { return dateCreation; } public LocalDateTime getDateCreation() { return dateCreation; }
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; } public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
@@ -320,13 +275,13 @@ public class UtilisateursBean implements Serializable {
public String getOrganisationNom() { public String getOrganisationNom() {
// Simulation - en réalité, on ferait un lookup dans la base // Simulation - en réalité, on ferait un lookup dans la base
return switch (organisationId.toString()) { if (organisationId == null) return "Non définie";
case "1" -> "Direction Générale"; String orgIdStr = organisationId.toString();
case "2" -> "Services Financiers"; if (orgIdStr.contains("000000000100")) return "Direction Générale";
case "3" -> "Ressources Humaines"; if (orgIdStr.contains("000000000200")) return "Services Financiers";
case "4" -> "Communication"; if (orgIdStr.contains("000000000300")) return "Ressources Humaines";
default -> "Non définie"; if (orgIdStr.contains("000000000400")) return "Communication";
}; return "Non définie";
} }
public String getDateCreationFormatee() { public String getDateCreationFormatee() {
@@ -356,7 +311,7 @@ public class UtilisateursBean implements Serializable {
private String email; private String email;
private String telephone; private String telephone;
private String role; private String role;
private Long organisationId; private UUID organisationId;
private String motDePasse; private String motDePasse;
private boolean envoyerEmail; private boolean envoyerEmail;
@@ -376,8 +331,8 @@ public class UtilisateursBean implements Serializable {
public String getRole() { return role; } public String getRole() { return role; }
public void setRole(String role) { this.role = role; } public void setRole(String role) { this.role = role; }
public Long getOrganisationId() { return organisationId; } public UUID getOrganisationId() { return organisationId; }
public void setOrganisationId(Long organisationId) { this.organisationId = organisationId; } public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
public String getMotDePasse() { return motDePasse; } public String getMotDePasse() { return motDePasse; }
public void setMotDePasse(String motDePasse) { this.motDePasse = motDePasse; } public void setMotDePasse(String motDePasse) { this.motDePasse = motDePasse; }
@@ -391,7 +346,7 @@ public class UtilisateursBean implements Serializable {
private String role; private String role;
private String statut; private String statut;
private String connexion; private String connexion;
private Long organisation; private UUID organisation;
// Getters et setters // Getters et setters
public String getRecherche() { return recherche; } public String getRecherche() { return recherche; }
@@ -406,8 +361,8 @@ public class UtilisateursBean implements Serializable {
public String getConnexion() { return connexion; } public String getConnexion() { return connexion; }
public void setConnexion(String connexion) { this.connexion = connexion; } public void setConnexion(String connexion) { this.connexion = connexion; }
public Long getOrganisation() { return organisation; } public UUID getOrganisation() { return organisation; }
public void setOrganisation(Long organisation) { this.organisation = organisation; } public void setOrganisation(UUID organisation) { this.organisation = organisation; }
} }
public static class StatistiquesUtilisateurs { public static class StatistiquesUtilisateurs {
@@ -431,12 +386,12 @@ public class UtilisateursBean implements Serializable {
} }
public static class Organisation { public static class Organisation {
private Long id; private UUID id;
private String nom; private String nom;
// Getters et setters // Getters et setters
public Long getId() { return id; } public UUID getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(UUID id) { this.id = id; }
public String getNom() { return nom; } public String getNom() { return nom; }
public void setNom(String nom) { this.nom = nom; } public void setNom(String nom) { this.nom = nom; }

View File

@@ -63,7 +63,7 @@
<h:form> <h:form>
<p:button value="Se reconnecter" <p:button value="Se reconnecter"
icon="pi pi-sign-in" icon="pi pi-sign-in"
outcome="/pages/public/login" outcome="/"
styleClass="ui-button-primary ui-button-lg" /> styleClass="ui-button-primary ui-button-lg" />
<p:button value="Page d'accueil" <p:button value="Page d'accueil"
icon="pi pi-home" icon="pi pi-home"

View File

@@ -3,171 +3,381 @@
xmlns:h="http://xmlns.jcp.org/jsf/html" xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core" xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets" xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"> xmlns:p="http://primefaces.org/ui"
lang="fr">
<f:view>
<f:event type="preRenderView" listener="#{navigationBean.checkAuthentication}" />
<h:head> <h:head>
<title>UnionFlow - Plateforme de Gestion Associative</title> <f:facet name="first">
<h:outputStylesheet name="freya-layout/css/primeflex.min.css"/> <meta http-equiv="X-UA-Compatible" content="IE=edge" />
<h:outputStylesheet name="freya-layout/css/primeicons.css"/> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<h:outputStylesheet name="primefaces-freya-blue-light/theme.css"/> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link rel="icon" href="#{request.contextPath}/resources/freya-layout/images/favicon.ico" type="image/x-icon" />
</f:facet>
<style> <title>UnionFlow - Plateforme de Gestion Intégrée pour Mutuelles, Associations et Clubs</title>
body {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.hero-container { <!-- Freya Layout Resources (placés dans le head pour éviter tout conflit et suivre le template) -->
background: rgba(255, 255, 255, 0.95); <h:outputStylesheet name="css/primeicons.css" library="freya-layout" />
backdrop-filter: blur(10px); <h:outputStylesheet name="css/primeflex.min.css" library="freya-layout" />
border-radius: 20px; <h:outputStylesheet name="css/layout-#{guestPreferences.layout}.css" library="freya-layout" />
padding: 60px; <h:outputStylesheet name="primefaces-freya-#{guestPreferences.componentTheme}/theme.css" />
box-shadow: 0 30px 80px rgba(0,0,0,0.3); <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." />
text-align: center;
max-width: 600px;
border: 1px solid rgba(255,255,255,0.2);
}
.logo-animation {
font-size: 5rem;
margin-bottom: 24px;
animation: pulse 2s ease-in-out infinite alternate;
}
@keyframes pulse {
0% { transform: scale(1); }
100% { transform: scale(1.05); }
}
.hero-title {
font-size: 3rem;
font-weight: 700;
margin-bottom: 16px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-subtitle {
font-size: 1.3rem;
color: #6c757d;
margin-bottom: 32px;
line-height: 1.6;
}
.features-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
margin: 40px 0;
}
.feature-item {
background: rgba(102, 126, 234, 0.1);
border-radius: 12px;
padding: 20px;
text-align: center;
}
.feature-icon {
font-size: 2rem;
margin-bottom: 12px;
color: #667eea;
}
.loading-text {
margin-top: 20px;
color: #6c757d;
font-size: 0.9rem;
animation: fadeInOut 1.5s ease-in-out infinite;
}
@keyframes fadeInOut {
0%, 100% { opacity: 0.5; }
50% { opacity: 1; }
}
</style>
</h:head> </h:head>
<h:body> <h:body styleClass="landing-body">
<div class="hero-container"> <div class="landing-wrapper">
<!-- Logo animé --> <!-- Landing Topbar -->
<div class="logo-animation"> <div class="landing-topbar">
<i class="pi pi-users"></i> <div class="landing-topbar-left">
</div> <h:link id="logolink" outcome="/pages/secure/dashboard" styleClass="logo">
<p:graphicImage name="images/logo-freya.svg" library="freya-layout" />
</h:link>
<!-- Titre principal --> <ul class="landing-menu">
<h1 class="hero-title">UnionFlow</h1> <li>
<p class="hero-subtitle"> <a href="#" id="landing-menu-close">
Plateforme intégrée de gestion associative<br/> <i class="pi pi-times"> </i>
<strong>Moderne • Sécurisée • Intuitive</strong> </a>
</p> </li>
<li>
<!-- Grille des fonctionnalités --> <a href="#home">Accueil</a>
<div class="features-grid"> </li>
<div class="feature-item"> <li>
<div class="feature-icon"> <a href="#features">Fonctionnalités</a>
<i class="pi pi-users"></i> </li>
<li>
<a href="#benefits">Avantages</a>
</li>
</ul>
</div> </div>
<div class="text-900 font-semibold">Gestion Membres</div> <div class="landing-topbar-right">
</div> <ui:include src="/templates/components/button-primary.xhtml">
<div class="feature-item"> <ui:param name="value" value="Accéder" />
<div class="feature-icon"> <ui:param name="icon" value="pi pi-arrow-right" />
<i class="pi pi-dollar"></i> <ui:param name="outcome" value="/pages/secure/dashboard" />
</div> <ui:param name="styleClass" value="landing-button" />
<div class="text-900 font-semibold">Cotisations</div> </ui:include>
</div> <a href="#" id="landing-menu-button">
<div class="feature-item"> <i class="pi pi-bars"> </i>
<div class="feature-icon"> </a>
<i class="pi pi-calendar"></i>
</div>
<div class="text-900 font-semibold">Événements</div>
</div>
<div class="feature-item">
<div class="feature-icon">
<i class="pi pi-chart-bar"></i>
</div>
<div class="text-900 font-semibold">Analytics</div>
</div> </div>
</div> </div>
<!-- Boutons d'action --> <!-- Landing Banner (Hero Section) -->
<div class="flex justify-content-center gap-3 mb-4"> <div id="home" class="landing-banner">
<p:button value="Connexion Sécurisée" <div class="landing-banner-content">
icon="pi pi-sign-in" <span class="title">UnionFlow</span>
outcome="/pages/public/login" <h3>Plateforme de Gestion Intégrée pour Mutuelles, Associations et Clubs<br/>
styleClass="p-button-lg p-button-rounded"/> Simplifiez la gestion de votre organisation avec une solution complète et moderne</h3>
<ui:include src="/templates/components/button-primary.xhtml">
<p:button value="Accès Direct" <ui:param name="value" value="Accéder à la plateforme" />
icon="pi pi-home" <ui:param name="icon" value="pi pi-sign-in" />
outcome="/pages/secure/dashboard" <ui:param name="outcome" value="/pages/secure/dashboard" />
styleClass="p-button-lg p-button-rounded p-button-outlined"/> <ui:param name="styleClass" value="landing-button" />
</ui:include>
</div>
</div> </div>
<!-- Texte de chargement --> <!-- Landing Features Section -->
<div class="loading-text"> <div id="features" class="landing-features">
<i class="pi pi-spin pi-spinner mr-2"></i> <div class="grid parallax-box">
Vérification de l'authentification... <div class="col-12 lg:col-3">
<div class="feature yellow">
<span>1</span>
<div class="feature-card">
<span>1</span>
<div class="card-content">
<h3>Gestion des Membres</h3>
<h5>Inscription, profils détaillés, gestion des statuts, historique des adhésions et suivi complet de chaque membre.</h5>
</div>
</div>
</div>
</div>
<div class="col-12 lg:col-3">
<div class="grid">
<div class="col-12">
<div class="feature blue">
<span>2</span>
<div class="feature-card">
<span>2</span>
<div class="card-content">
<h3>Gestion des Cotisations</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>
<div style="margin-top: 10px;">
<!-- 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" />
</div>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="feature gray">
<span>3</span>
<div class="feature-card">
<span>3</span>
<div class="card-content">
<h3>Organisation<br/>d'Événements</h3>
<h5>Assemblées générales, réunions, formations, conférences, ateliers, séminaires, événements sociaux avec gestion des inscriptions.</h5>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 lg:col-3 feature-4">
<div class="col-12">
<div class="feature darker-gray">
<span>4</span>
<div class="feature-card">
<span>4</span>
<div class="card-content">
<h3>Système de Solidarité</h3>
<h5>Gestion complète des demandes d'aide, propositions, évaluations, suivi des statuts et coordination des actions solidaires.</h5>
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="feature darker-blue">
<span>5</span>
<div class="feature-card">
<span>5</span>
<div class="card-content">
<h3>Gestion des Organisations</h3>
<h5>Gestion des clubs et unions avec hiérarchie organisationnelle, statistiques détaillées, rapports et vue d'ensemble complète.</h5>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 lg:col-3">
<div class="feature gray">
<span>6</span>
<div class="feature-card">
<span>6</span>
<div class="card-content">
<h3>Analytics &amp; Rapports</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>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Benefits Section -->
<div id="benefits" class="landing-pricing">
<div class="section-header">
<span class="title">Pourquoi choisir UnionFlow ?</span>
<h3>Une solution pensée pour les mutuelles, associations, clubs et organisations similaires avec sécurité avancée, multi-plateforme et synchronisation temps réel.</h3>
</div>
<div class="grid">
<div class="col-12 lg:col-4">
<div class="pricing-card">
<h2>Sécurité</h2>
<span class="price">100%</span>
<span class="time">Sécurisé</span>
<ul>
<li>Connexion sécurisée et centralisée</li>
<li>Contrôle d'accès basé sur les rôles</li>
<li>Protection des données sensibles</li>
<li>Chiffrement des communications</li>
</ul>
</div>
</div>
<div class="col-12 lg:col-4 preferred">
<div class="pricing-card pro">
<span class="preferred-tag">RECOMMANDÉ</span>
<h2>Multi-Plateforme</h2>
<span class="price">24/7</span>
<span class="time">Disponible</span>
<ul>
<li>Application web responsive</li>
<li>Application mobile Flutter</li>
<li>iOS et Android</li>
<li>Accès depuis n'importe où</li>
</ul>
</div>
</div>
<div class="col-12 lg:col-4">
<div class="pricing-card enterprise">
<h2>Cloud</h2>
<span class="price">Cloud</span>
<span class="time">Moderne</span>
<ul>
<li>Architecture cloud-native</li>
<li>Synchronisation temps réel</li>
<li>Sauvegarde automatique</li>
<li>Scalabilité illimitée</li>
</ul>
</div>
</div>
</div>
<div class="text-center mt-5">
<ui:include src="/templates/components/button-primary.xhtml">
<ui:param name="value" value="Découvrir toutes les fonctionnalités" />
<ui:param name="icon" value="pi pi-arrow-right" />
<ui:param name="outcome" value="/pages/secure/dashboard" />
<ui:param name="styleClass" value="landing-button" />
</ui:include>
</div>
</div> </div>
<!-- Footer --> <!-- Footer -->
<div class="mt-5 pt-4 border-top-1 surface-border"> <div class="layout-footer">
<small class="text-500"> <div class="grid">
© 2024 UnionFlow v1.0 - Développé par <strong>Lions Dev</strong><br/> <div class="col-12 lg:col-4">
<span class="text-600">Côte d'Ivoire • Sénégal • Mali</span> <div class="grid">
</small> <div class="col-6">
<span class="footer-menutitle">NAVIGATION</span>
<ul>
<li><a href="#home">Accueil</a></li>
<li><a href="#features">Fonctionnalités</a></li>
<li><a href="#benefits">Avantages</a></li>
<li><a href="/pages/secure/dashboard">Tableau de Bord</a></li>
</ul>
</div>
<div class="col-6">
<span class="footer-menutitle">FONCTIONNALITÉS</span>
<ul>
<li><a href="/pages/secure/membre/liste">Membres</a></li>
<li><a href="/pages/secure/cotisation/historique">Cotisations</a></li>
<li><a href="/pages/secure/evenement/calendrier">Événements</a></li>
<li><a href="/pages/secure/aide/documentation">Aide</a></li>
</ul>
</div> </div>
</div> </div>
</div>
<div class="col-12 md:col-6 lg:col-3">
<span class="footer-menutitle">CONTACT</span>
<ul>
<li>support@unionflow.dev</li>
<li>Abidjan, Côte d'Ivoire</li>
<li>Plateforme de Gestion Intégrée</li>
</ul>
</div>
<div class="col-12 md:col-6 lg:col-5">
<span class="footer-menutitle">NEWSLETTER</span>
<span class="footer-subtitle">Rejoignez notre newsletter pour être informé des nouvelles fonctionnalités.</span>
<h:form>
<div class="newsletter-input">
<p:inputText placeholder="adresse email" />
<ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="S'abonner" />
<ui:param name="outlined" value="false" />
</ui:include>
</div>
</h:form>
</div>
<div class="col-12">
<div class="footer-bottom">
<h4>UnionFlow</h4>
<h6>Copyright © 2025 UnionFlow Dev Team</h6>
</div>
</div>
</div>
</div>
<div class="landing-mask"> </div>
</div>
<!-- Landing Page JavaScript - selon Freya -->
<h:outputScript name="js/layout.js" library="freya-layout" />
<h:outputScript>
<![CDATA[
(function() {
'use strict';
const initParallax = function() {
if (typeof $ === 'undefined') return;
$(document).ready(function() {
const parallax = function() {
const scrolled = $(window).scrollTop();
$('.landing-banner').css('top', -(scrolled * 0.01) + '%');
$('.landing-banner-content').css('top', (scrolled * -0.065) + '%');
$('.parallax-box .lg\\:col-3:odd').css('transform', 'translateY(' + (scrolled * 0.01) + '%)');
$('.parallax-box .lg\\:col-3:even').css('margin-top', -(scrolled * 0.01) + '%');
};
$(window).scroll(parallax);
});
};
const initMenu = function() {
if (typeof $ === 'undefined') return;
const hideMenu = function() {
$('.landing-menu').removeClass('fadeInDown').addClass('fadeOutUp');
setTimeout(function() {
$('.landing-wrapper').removeClass('landing-menu-active');
$('.landing-menu').removeClass('fadeOutUp');
$(document.body).removeClass('block-scroll');
}, 150);
};
const showMenu = function() {
$('.landing-wrapper').addClass('landing-menu-active');
$('.landing-menu').addClass('fadeInDown');
$(document.body).addClass('block-scroll');
};
$(function() {
$('#landing-menu-button').on('click', function(e) {
const wrapper = $('.landing-wrapper');
if (wrapper.hasClass('landing-menu-active')) {
hideMenu();
} else {
showMenu();
}
e.preventDefault();
});
$('.landing-menu').find('a').on('click', function() {
hideMenu();
});
});
};
const initScroll = function() {
if (typeof $ === 'undefined') return;
$(document).ready(function() {
$('html, body').animate({ scrollTop: 0 }, 1);
});
const isMobile = function() {
return $(window).width() <= 896;
};
$('a[href*="#"]:not([href="#"])').click(function() {
const target = $(this.hash);
if (target.length) {
const offset = isMobile() ? target.offset().top : target.offset().top - 100;
$('html, body').animate({ scrollTop: offset }, 500);
return false;
}
});
};
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function() {
initParallax();
initMenu();
initScroll();
});
} else {
initParallax();
initMenu();
initScroll();
}
})();
]]>
</h:outputScript>
</h:body> </h:body>
</f:view>
</html> </html>

View File

@@ -1,214 +0,0 @@
<!DOCTYPE html>
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
template="/templates/public-template.xhtml">
<ui:define name="title">Connexion - UnionFlow</ui:define>
<ui:define name="content">
<div class="min-h-screen flex relative lg:static surface-ground">
<!-- Panneau gauche - Branding -->
<div class="flex flex-column align-items-center justify-content-center bg-blue-500 flex-shrink-0 w-full lg:w-6">
<div class="text-center">
<!-- Logo et icône principale -->
<div class="mb-6">
<div class="text-white text-7xl font-bold mb-4">
<i class="pi pi-users"></i>
</div>
<h1 class="text-white text-5xl font-bold mb-2 line-height-3">UnionFlow</h1>
<p class="text-blue-100 text-xl font-medium line-height-3 mb-0">
Plateforme de Gestion Associative
</p>
</div>
<!-- Fonctionnalités clés -->
<div class="hidden lg:block">
<div class="surface-0 shadow-2 border-round p-4 mx-6">
<div class="text-900 text-lg font-bold mb-3">Fonctionnalités Principales</div>
<ul class="list-none p-0 m-0 text-left">
<li class="flex align-items-center py-2">
<div class="w-2rem h-2rem bg-green-100 text-green-600 border-round flex align-items-center justify-content-center mr-3">
<i class="pi pi-users"></i>
</div>
<span class="text-900 font-medium">Gestion des membres</span>
</li>
<li class="flex align-items-center py-2">
<div class="w-2rem h-2rem bg-purple-100 text-purple-600 border-round flex align-items-center justify-content-center mr-3">
<i class="pi pi-dollar"></i>
</div>
<span class="text-900 font-medium">Cotisations &amp; Paiements</span>
</li>
<li class="flex align-items-center py-2">
<div class="w-2rem h-2rem bg-orange-100 text-orange-600 border-round flex align-items-center justify-content-center mr-3">
<i class="pi pi-calendar"></i>
</div>
<span class="text-900 font-medium">Événements &amp; Activités</span>
</li>
<li class="flex align-items-center py-2">
<div class="w-2rem h-2rem bg-cyan-100 text-cyan-600 border-round flex align-items-center justify-content-center mr-3">
<i class="pi pi-chart-bar"></i>
</div>
<span class="text-900 font-medium">Rapports &amp; Analytics</span>
</li>
</ul>
</div>
</div>
</div>
</div>
<!-- Panneau droit - Formulaire de connexion -->
<div class="flex flex-column align-items-center justify-content-center w-full lg:w-6 px-4 py-8 surface-card">
<div class="w-full" style="max-width: 400px;">
<!-- En-tête du formulaire -->
<div class="text-center mb-6">
<div class="text-900 text-3xl font-bold mb-2">Bienvenue !</div>
<div class="text-600 mb-4">Connectez-vous à votre espace UnionFlow</div>
<!-- Messages système -->
<p:messages id="messages" showDetail="true" closable="true"
styleClass="mb-4" globalOnly="true" />
<!-- Message de session expirée -->
<p:outputPanel rendered="#{param.expired == 'true'}" styleClass="mb-4">
<div class="surface-100 border-round-lg p-3 border-left-3 border-orange-500">
<div class="flex align-items-center">
<i class="pi pi-clock text-orange-500 mr-3 text-2xl"></i>
<div>
<div class="text-900 font-semibold">Session expirée</div>
<div class="text-600 text-sm mt-1">
Votre session a expiré pour des raisons de sécurité. Veuillez vous reconnecter.
</div>
</div>
</div>
</div>
</p:outputPanel>
</div>
<!-- Formulaire principal -->
<h:form id="loginForm" styleClass="ui-fluid">
<!-- Sélecteur de type de compte avec design moderne -->
<div class="field mb-4">
<label for="typeCompte" class="block text-900 font-semibold mb-2">
<i class="pi pi-user-plus mr-2"></i>Type de compte
</label>
<p:selectOneMenu id="typeCompte" value="#{loginBean.typeCompte}"
required="true" styleClass="w-full">
<f:selectItem itemLabel="Choisir votre profil..." itemValue="" noSelectionOption="true" />
<f:selectItem itemLabel="🔱 Super-Administrateur Plateforme" itemValue="SUPER_ADMIN" />
<f:selectItem itemLabel="🏛️ Administrateur d'Organisation" itemValue="ADMIN_ENTITE" />
<f:selectItem itemLabel="👤 Membre Actif" itemValue="MEMBRE" />
</p:selectOneMenu>
</div>
<!-- Champ email/username -->
<div class="field mb-4">
<label for="username" class="block text-900 font-semibold mb-2">
<i class="pi pi-at mr-2"></i>Email ou nom d'utilisateur
</label>
<p:inputText id="username" value="#{loginBean.username}"
placeholder="votre@email.com"
required="true" styleClass="w-full p-3">
<f:validateLength minimum="3" />
</p:inputText>
</div>
<!-- Champ mot de passe -->
<div class="field mb-4">
<label for="password" class="block text-900 font-semibold mb-2">
<i class="pi pi-key mr-2"></i>Mot de passe
</label>
<p:password id="password" value="#{loginBean.password}"
placeholder="••••••••••"
required="true" toggleMask="true"
styleClass="w-full p-3" />
</div>
<!-- Options avancées -->
<div class="flex align-items-center justify-content-between mb-5">
<div class="flex align-items-center">
<p:selectBooleanCheckbox id="rememberme" value="#{loginBean.rememberMe}"
styleClass="mr-2" />
<label for="rememberme" class="text-900 font-medium cursor-pointer">
Se souvenir de moi
</label>
</div>
<a href="#" class="font-semibold no-underline text-primary text-right cursor-pointer">
Mot de passe oublié ?
</a>
</div>
<!-- Bouton de connexion principal -->
<p:commandButton id="loginButton" value="Se connecter"
action="#{loginBean.login}"
styleClass="w-full p-3 text-xl border-round font-bold mb-4"
icon="pi pi-sign-in"
iconPos="right"
update="@form" />
<!-- Séparateur élégant -->
<div class="flex align-items-center mb-4">
<hr class="flex-1 border-top-1 border-300 m-0"/>
<div class="px-3 text-500 font-medium">ou essayez en mode démo</div>
<hr class="flex-1 border-top-1 border-300 m-0"/>
</div>
<!-- Boutons démo redesignés -->
<div class="grid gap-2">
<div class="col-12">
<p:commandButton value="🔱 Mode Démo Super-Admin"
action="#{loginBean.loginDemo('SUPER_ADMIN')}"
styleClass="ui-button-outlined ui-button-danger w-full p-2 font-bold"
update="@form" />
</div>
<div class="col-6">
<p:commandButton value="🏛️ Démo Admin"
action="#{loginBean.loginDemo('ADMIN')}"
styleClass="ui-button-outlined ui-button-warning w-full p-2"
update="@form" />
</div>
<div class="col-6">
<p:commandButton value="👤 Démo Membre"
action="#{loginBean.loginDemo('MEMBRE')}"
styleClass="ui-button-outlined ui-button-info w-full p-2"
update="@form" />
</div>
</div>
<!-- Call to action pour inscription -->
<div class="surface-50 border-round p-4 mt-6 text-center">
<div class="text-900 font-semibold mb-2">
<i class="pi pi-star-fill text-yellow-500 mr-2"></i>
Votre organisation n'est pas encore inscrite ?
</div>
<p class="text-600 mb-3 line-height-3">
Découvrez UnionFlow avec une démonstration personnalisée
</p>
<a href="#" class="text-primary font-bold no-underline">
<i class="pi pi-arrow-right mr-2"></i>Demander une démonstration
</a>
</div>
</h:form>
<!-- Footer discret -->
<div class="text-center mt-6 pt-4">
<div class="text-500 text-sm mb-2">
© 2024 UnionFlow - Développé par Lions Dev
</div>
<div class="flex justify-content-center gap-3 text-xs">
<a href="#" class="text-500 no-underline hover:text-primary">Aide</a>
<span class="text-300"></span>
<a href="#" class="text-500 no-underline hover:text-primary">Confidentialité</a>
<span class="text-300"></span>
<a href="#" class="text-500 no-underline hover:text-primary">Conditions</a>
</div>
</div>
</div>
</div>
</div>
</ui:define>
</ui:composition>

View File

@@ -32,8 +32,16 @@
<p:inputTextarea id="motifAdhesion" rows="4" /> <p:inputTextarea id="motifAdhesion" rows="4" />
</div> </div>
<div class="field col-12"> <div class="field col-12">
<p:commandButton value="Soumettre la demande" icon="pi pi-send" styleClass="ui-button-success" /> <ui:include src="/templates/components/button-success.xhtml">
<p:commandButton value="Annuler" icon="pi pi-times" styleClass="ui-button-secondary" style="margin-left: 0.5rem" /> <ui:param name="value" value="Soumettre la demande" />
<ui:param name="icon" value="pi pi-send" />
</ui:include>
<ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Annuler" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="outlined" value="false" />
<ui:param name="styleClass" value="ml-2" />
</ui:include>
</div> </div>
</div> </div>
</h:form> </h:form>

View File

@@ -23,8 +23,14 @@
<h:outputText value="#{adhesion.statut}" /> <h:outputText value="#{adhesion.statut}" />
</p:column> </p:column>
<p:column headerText="Actions"> <p:column headerText="Actions">
<p:commandButton icon="pi pi-eye" styleClass="ui-button-rounded ui-button-info ui-button-text" /> <ui:include src="/templates/components/button-icon.xhtml">
<p:commandButton icon="pi pi-pencil" styleClass="ui-button-rounded ui-button-success ui-button-text" /> <ui:param name="icon" value="pi pi-eye" />
<ui:param name="severity" value="info" />
</ui:include>
<ui:include src="/templates/components/button-icon.xhtml">
<ui:param name="icon" value="pi pi-pencil" />
<ui:param name="severity" value="success" />
</ui:include>
</p:column> </p:column>
</p:dataTable> </p:dataTable>
</div> </div>

View File

@@ -24,7 +24,11 @@
<h:outputText value="#{adhesion.dateExpiration}" /> <h:outputText value="#{adhesion.dateExpiration}" />
</p:column> </p:column>
<p:column headerText="Action"> <p:column headerText="Action">
<p:commandButton value="Renouveler" icon="pi pi-refresh" styleClass="ui-button-success ui-button-sm" /> <ui:include src="/templates/components/button-success.xhtml">
<ui:param name="value" value="Renouveler" />
<ui:param name="icon" value="pi pi-refresh" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</p:column> </p:column>
</p:dataTable> </p:dataTable>
</div> </div>

View File

@@ -23,8 +23,16 @@
<h:outputText value="#{adhesion.type}" /> <h:outputText value="#{adhesion.type}" />
</p:column> </p:column>
<p:column headerText="Actions"> <p:column headerText="Actions">
<p:commandButton value="Approuver" icon="pi pi-check" styleClass="ui-button-success ui-button-sm" /> <ui:include src="/templates/components/button-success.xhtml">
<p:commandButton value="Rejeter" icon="pi pi-times" styleClass="ui-button-danger ui-button-sm" style="margin-left: 0.5rem" /> <ui:param name="value" value="Approuver" />
<ui:param name="icon" value="pi pi-check" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Rejeter" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="styleClass" value="ui-button-danger ui-button-sm" />
</ui:include>
</p:column> </p:column>
</p:dataTable> </p:dataTable>
</div> </div>

View File

@@ -26,13 +26,17 @@
</p> </p>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<p:commandButton value="Version PDF" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="p-button-outlined" <ui:param name="value" value="Version PDF" />
icon="pi pi-file-pdf" /> <ui:param name="icon" value="pi pi-file-pdf" />
<p:commandButton value="Rechercher" <ui:param name="outlined" value="true" />
styleClass="p-button-primary p-button-outlined" </ui:include>
icon="pi pi-search" <ui:include src="/templates/components/button-primary.xhtml">
onclick="PF('rechercheDialog').show()" /> <ui:param name="value" value="Rechercher" />
<ui:param name="icon" value="pi pi-search" />
<ui:param name="onclick" value="PF('rechercheDialog').show()" />
<ui:param name="styleClass" value="ui-button-outlined" />
</ui:include>
</div> </div>
</div> </div>
@@ -145,12 +149,18 @@
<!-- Actions rapides --> <!-- Actions rapides -->
<div class="surface-card border-round p-3 mt-3"> <div class="surface-card border-round p-3 mt-3">
<div class="text-center"> <div class="text-center">
<p:commandButton value="Tout marquer comme lu" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="p-button-text p-button-sm w-full" <ui:param name="value" value="Tout marquer comme lu" />
icon="pi pi-check-square" /> <ui:param name="icon" value="pi pi-check-square" />
<p:commandButton value="Réinitialiser progression" <ui:param name="outlined" value="false" />
styleClass="p-button-text p-button-sm w-full mt-2" <ui:param name="styleClass" value="ui-button-text ui-button-sm w-full" />
icon="pi pi-refresh" /> </ui:include>
<ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Réinitialiser progression" />
<ui:param name="icon" value="pi pi-refresh" />
<ui:param name="outlined" value="false" />
<ui:param name="styleClass" value="ui-button-text ui-button-sm w-full mt-2" />
</ui:include>
</div> </div>
</div> </div>
</h:form> </h:form>
@@ -171,15 +181,27 @@
</div> </div>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<p:commandButton icon="pi pi-bookmark" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="p-button-rounded p-button-outlined p-button-sm" <ui:param name="icon" value="pi pi-bookmark" />
title="Marquer comme favori" /> <ui:param name="title" value="Marquer comme favori" />
<p:commandButton icon="pi pi-share-alt" <ui:param name="rounded" value="true" />
styleClass="p-button-rounded p-button-outlined p-button-sm" <ui:param name="text" value="false" />
title="Partager" /> <ui:param name="styleClass" value="ui-button-outlined ui-button-sm" />
<p:commandButton icon="pi pi-print" </ui:include>
styleClass="p-button-rounded p-button-outlined p-button-sm" <ui:include src="/templates/components/button-icon.xhtml">
title="Imprimer" /> <ui:param name="icon" value="pi pi-share-alt" />
<ui:param name="title" value="Partager" />
<ui:param name="rounded" value="true" />
<ui:param name="text" value="false" />
<ui:param name="styleClass" value="ui-button-outlined ui-button-sm" />
</ui:include>
<ui:include src="/templates/components/button-icon.xhtml">
<ui:param name="icon" value="pi pi-print" />
<ui:param name="title" value="Imprimer" />
<ui:param name="rounded" value="true" />
<ui:param name="text" value="false" />
<ui:param name="styleClass" value="ui-button-outlined ui-button-sm" />
</ui:include>
</div> </div>
</div> </div>
@@ -325,31 +347,37 @@
<!-- Navigation entre sections --> <!-- Navigation entre sections -->
<div class="flex justify-content-between align-items-center mt-6 pt-4 border-top-1 border-200"> <div class="flex justify-content-between align-items-center mt-6 pt-4 border-top-1 border-200">
<p:commandButton value="Section précédente" <ui:include src="/templates/components/button-secondary.xhtml">
icon="pi pi-angle-left" <ui:param name="value" value="Section précédente" />
styleClass="p-button-outlined" <ui:param name="icon" value="pi pi-angle-left" />
rendered="#{guideBean.APrecedent}" <ui:param name="action" value="#{guideBean.sectionPrecedente}" />
action="#{guideBean.sectionPrecedente}" /> <ui:param name="outlined" value="true" />
<ui:param name="rendered" value="#{guideBean.APrecedent}" />
</ui:include>
<div class="flex gap-2" rendered="#{guideBean.sectionCourante.id != 'default'}"> <div class="flex gap-2" rendered="#{guideBean.sectionCourante.id != 'default'}">
<p:commandButton value="Marquer comme lu" <ui:include src="/templates/components/button-success.xhtml">
icon="pi pi-check" <ui:param name="value" value="Marquer comme lu" />
styleClass="p-button-success" <ui:param name="icon" value="pi pi-check" />
rendered="#{not guideBean.sectionCourante.lu}" <ui:param name="action" value="#{guideBean.marquerCommeLu}" />
action="#{guideBean.marquerCommeLu}" /> <ui:param name="rendered" value="#{not guideBean.sectionCourante.lu}" />
<p:commandButton value="Lu" </ui:include>
icon="pi pi-check" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="p-button-outlined" <ui:param name="value" value="Lu" />
rendered="#{guideBean.sectionCourante.lu}" <ui:param name="icon" value="pi pi-check" />
disabled="true" /> <ui:param name="outlined" value="true" />
<ui:param name="disabled" value="true" />
<ui:param name="rendered" value="#{guideBean.sectionCourante.lu}" />
</ui:include>
</div> </div>
<p:commandButton value="Section suivante" <ui:include src="/templates/components/button-secondary.xhtml">
icon="pi pi-angle-right" <ui:param name="value" value="Section suivante" />
iconPos="right" <ui:param name="icon" value="pi pi-angle-right" />
styleClass="p-button-outlined" <ui:param name="action" value="#{guideBean.sectionSuivante}" />
rendered="#{guideBean.ASuivant}" <ui:param name="outlined" value="true" />
action="#{guideBean.sectionSuivante}" /> <ui:param name="rendered" value="#{guideBean.ASuivant}" />
</ui:include>
</div> </div>
</div> </div>
</div> </div>
@@ -376,7 +404,7 @@
</p:inputText> </p:inputText>
</div> </div>
<div id="resultatsRecherche"> <h:panelGroup id="resultatsRecherche" layout="block">
<ui:repeat value="#{guideBean.resultatsRecherche}" var="resultat" rendered="#{not empty guideBean.termeRecherche}"> <ui:repeat value="#{guideBean.resultatsRecherche}" var="resultat" rendered="#{not empty guideBean.termeRecherche}">
<div class="surface-100 border-round p-3 mb-3 cursor-pointer hover:surface-200 transition-duration-200" <div class="surface-100 border-round p-3 mb-3 cursor-pointer hover:surface-200 transition-duration-200"
onclick="#{guideBean.naviguerVers(resultat.id)}; PF('rechercheDialog').hide();"> onclick="#{guideBean.naviguerVers(resultat.id)}; PF('rechercheDialog').hide();">
@@ -395,7 +423,7 @@
<i class="pi pi-search text-3xl text-300 mb-2"></i> <i class="pi pi-search text-3xl text-300 mb-2"></i>
<p class="text-600">Aucun résultat trouvé pour "#{guideBean.termeRecherche}"</p> <p class="text-600">Aucun résultat trouvé pour "#{guideBean.termeRecherche}"</p>
</div> </div>
</div> </h:panelGroup>
</div> </div>
</h:form> </h:form>
</p:dialog> </p:dialog>

View File

@@ -26,18 +26,27 @@
</div> </div>
</div> </div>
<div class="mt-3 lg:mt-0"> <div class="mt-3 lg:mt-0">
<p:commandButton value="Rapport mensuel" icon="pi pi-download" <ui:include src="/templates/components/button-success.xhtml">
styleClass="ui-button-outlined ui-button-success mr-2" <ui:param name="value" value="Rapport mensuel" />
action="#{dashboardBean.generateRapport}"/> <ui:param name="icon" value="pi pi-download" />
<p:commandButton value="Aide" icon="pi pi-question-circle" <ui:param name="action" value="#{dashboardBean.generateRapport}" />
styleClass="ui-button-outlined ui-button-help"/> <ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="mr-2" />
</ui:include>
<ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Aide" />
<ui:param name="icon" value="pi pi-question-circle" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-help" />
</ui:include>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- Alertes URGENTES - En premier pour l'attention immédiate --> <!-- Alertes URGENTES - En premier pour l'attention immédiate -->
<div class="col-12" rendered="#{dashboardBean.hasAlerts}"> <ui:fragment rendered="#{dashboardBean.hasAlerts}">
<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 text-orange-500 mr-2"></i>
@@ -110,6 +119,7 @@
</div> </div>
</div> </div>
</div> </div>
</ui:fragment>
<!-- KPIs principaux - Ordre psychologique optimal --> <!-- KPIs principaux - Ordre psychologique optimal -->
<div class="col-12"> <div class="col-12">
@@ -359,11 +369,11 @@
<!-- Journal d'activités et Tâches prioritaires --> <!-- Journal d'activités et Tâches prioritaires -->
<div class="col-12 lg:col-8"> <div class="col-12 lg:col-8">
<h:form>
<div class="card"> <div class="card">
<div class="flex align-items-center justify-content-between mb-4"> <div class="flex align-items-center justify-content-between mb-4">
<h5>Journal d'activités</h5> <h5>Journal d'activités</h5>
<div> <div>
<h:form>
<p:selectOneMenu value="#{dashboardBean.filtreActivite}"> <p:selectOneMenu value="#{dashboardBean.filtreActivite}">
<f:selectItem itemLabel="Toutes" itemValue="ALL" /> <f:selectItem itemLabel="Toutes" itemValue="ALL" />
<f:selectItem itemLabel="Cotisations" itemValue="COTISATION" /> <f:selectItem itemLabel="Cotisations" itemValue="COTISATION" />
@@ -372,7 +382,6 @@
<f:selectItem itemLabel="Événements" itemValue="EVENEMENT" /> <f:selectItem itemLabel="Événements" itemValue="EVENEMENT" />
<p:ajax update="activitiesTable" /> <p:ajax update="activitiesTable" />
</p:selectOneMenu> </p:selectOneMenu>
</h:form>
</div> </div>
</div> </div>
<p:dataTable id="activitiesTable" value="#{dashboardBean.recentActivities}" var="activity" <p:dataTable id="activitiesTable" value="#{dashboardBean.recentActivities}" var="activity"
@@ -399,9 +408,11 @@
<div> <div>
<div class="text-900 font-medium">#{activity.titre}</div> <div class="text-900 font-medium">#{activity.titre}</div>
<div class="text-600 mt-1">#{activity.description}</div> <div class="text-600 mt-1">#{activity.description}</div>
<div class="mt-2" rendered="#{activity.montant != null}"> <ui:fragment rendered="#{activity.montant != null}">
<div class="mt-2">
<span class="text-green-600 font-medium">#{activity.montant} FCFA</span> <span class="text-green-600 font-medium">#{activity.montant} FCFA</span>
</div> </div>
</ui:fragment>
</div> </div>
</p:column> </p:column>
<p:column headerText="Acteur" style="width:150px"> <p:column headerText="Acteur" style="width:150px">
@@ -415,40 +426,61 @@
</div> </div>
</p:column> </p:column>
<p:column headerText="Action" style="width:80px"> <p:column headerText="Action" style="width:80px">
<p:commandButton icon="pi pi-eye" styleClass="ui-button-rounded ui-button-text" <ui:include src="/templates/components/button-icon.xhtml">
title="Voir détails"/> <ui:param name="icon" value="pi pi-eye" />
<ui:param name="title" value="Voir détails" />
</ui:include>
</p:column> </p:column>
</p:dataTable> </p:dataTable>
</div> </div>
</h:form>
</div> </div>
<!-- Actions rapides et Tâches --> <!-- Actions rapides et Tâches -->
<div class="col-12 lg:col-4"> <div class="col-12 lg:col-4">
<h:form>
<div class="card mb-4"> <div class="card mb-4">
<h5>Actions rapides</h5> <h5>Actions rapides</h5>
<div class="grid"> <div class="grid">
<div class="col-6"> <div class="col-6">
<p:commandButton value="Nouveau membre" icon="pi pi-user-plus" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="ui-button-outlined w-full mb-2" <ui:param name="value" value="Nouveau membre" />
action="#{dashboardBean.redirectToNewMember}"/> <ui:param name="icon" value="pi pi-user-plus" />
<ui:param name="action" value="#{dashboardBean.redirectToNewMember}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full mb-2" />
</ui:include>
</div> </div>
<div class="col-6"> <div class="col-6">
<p:commandButton value="Collecter" icon="pi pi-wallet" <ui:include src="/templates/components/button-success.xhtml">
styleClass="ui-button-success ui-button-outlined w-full mb-2" <ui:param name="value" value="Collecter" />
action="#{dashboardBean.redirectToCotisation}"/> <ui:param name="icon" value="pi pi-wallet" />
<ui:param name="action" value="#{dashboardBean.redirectToCotisation}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full mb-2" />
</ui:include>
</div> </div>
<div class="col-6"> <div class="col-6">
<p:commandButton value="Événement" icon="pi pi-calendar-plus" <ui:include src="/templates/components/button-info.xhtml">
styleClass="ui-button-info ui-button-outlined w-full mb-2" <ui:param name="value" value="Événement" />
action="#{dashboardBean.redirectToEvenement}"/> <ui:param name="icon" value="pi pi-calendar-plus" />
<ui:param name="action" value="#{dashboardBean.redirectToEvenement}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full mb-2" />
</ui:include>
</div> </div>
<div class="col-6"> <div class="col-6">
<p:commandButton value="Rapport" icon="pi pi-chart-bar" <ui:include src="/templates/components/button-warning.xhtml">
styleClass="ui-button-warning ui-button-outlined w-full mb-2" <ui:param name="value" value="Rapport" />
action="#{dashboardBean.generateRapport}"/> <ui:param name="icon" value="pi pi-chart-bar" />
<ui:param name="action" value="#{dashboardBean.generateRapport}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="w-full mb-2" />
</ui:include>
</div> </div>
</div> </div>
</div> </div>
</h:form>
<div class="card"> <div class="card">
<h5>Tâches prioritaires</h5> <h5>Tâches prioritaires</h5>
@@ -459,9 +491,11 @@
<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>
</div> </div>
<p:commandButton icon="pi pi-arrow-right" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="ui-button-rounded ui-button-text ui-button-info" <ui:param name="icon" value="pi pi-arrow-right" />
action="#{dashboardBean.redirectToAdhesionValidation}"/> <ui:param name="action" value="#{dashboardBean.redirectToAdhesionValidation}" />
<ui:param name="severity" value="info" />
</ui:include>
</div> </div>
<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 bg-orange-50 border-orange-200">
@@ -470,9 +504,11 @@
<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>
</div> </div>
<p:commandButton icon="pi pi-arrow-right" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="ui-button-rounded ui-button-text ui-button-warning" <ui:param name="icon" value="pi pi-arrow-right" />
action="#{dashboardBean.redirectToRelances}"/> <ui:param name="action" value="#{dashboardBean.redirectToRelances}" />
<ui:param name="severity" value="warning" />
</ui:include>
</div> </div>
<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 bg-green-50 border-green-200">
@@ -481,9 +517,11 @@
<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>
</div> </div>
<p:commandButton icon="pi pi-arrow-right" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="ui-button-rounded ui-button-text ui-button-success" <ui:param name="icon" value="pi pi-arrow-right" />
action="#{dashboardBean.redirectToAidesTraitement}"/> <ui:param name="action" value="#{dashboardBean.redirectToAidesTraitement}" />
<ui:param name="severity" value="success" />
</ui:include>
</div> </div>
<div class="flex align-items-center p-3 border-round bg-purple-50 border-purple-200"> <div class="flex align-items-center p-3 border-round bg-purple-50 border-purple-200">
@@ -492,9 +530,11 @@
<div class="text-900 font-medium">Organiser prochains événements</div> <div class="text-900 font-medium">Organiser prochains événements</div>
<small class="text-600">#{dashboardBean.evenementsAPlanifier} événements à planifier</small> <small class="text-600">#{dashboardBean.evenementsAPlanifier} événements à planifier</small>
</div> </div>
<p:commandButton icon="pi pi-arrow-right" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="ui-button-rounded ui-button-text ui-button-help" <ui:param name="icon" value="pi pi-arrow-right" />
action="#{dashboardBean.redirectToEvenementPlanning}"/> <ui:param name="action" value="#{dashboardBean.redirectToEvenementPlanning}" />
<ui:param name="styleClass" value="ui-button-help" />
</ui:include>
</div> </div>
</div> </div>
</div> </div>
@@ -511,9 +551,13 @@
yearNavigator="true" yearRange="2020:2030"> yearNavigator="true" yearRange="2020:2030">
<p:ajax update="financialSummary" listener="#{dashboardBean.onMoisChange}"/> <p:ajax update="financialSummary" listener="#{dashboardBean.onMoisChange}"/>
</p:calendar> </p:calendar>
<p:commandButton value="Exporter" icon="pi pi-download" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="ui-button-outlined ui-button-sm" <ui:param name="value" value="Exporter" />
action="#{dashboardBean.exportFinancialReport}"/> <ui:param name="icon" value="pi pi-download" />
<ui:param name="action" value="#{dashboardBean.exportFinancialReport}" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</h:form> </h:form>
</div> </div>
</div> </div>

View File

@@ -177,11 +177,14 @@
<i class="pi pi-file text-blue-500 mr-2"></i> <i class="pi pi-file text-blue-500 mr-2"></i>
<span class="text-900">#{document}</span> <span class="text-900">#{document}</span>
</div> </div>
<p:commandButton icon="pi pi-times" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="ui-button-rounded ui-button-text ui-button-danger ui-button-sm" <ui:param name="icon" value="pi pi-times" />
action="#{membreInscriptionBean.supprimerDocument(document)}" <ui:param name="action" value="#{membreInscriptionBean.supprimerDocument(document)}" />
update="documentsListPanel" <ui:param name="update" value="documentsListPanel" />
title="Supprimer le fichier" /> <ui:param name="title" value="Supprimer le fichier" />
<ui:param name="severity" value="danger" />
<ui:param name="styleClass" value="ui-button-sm" />
</ui:include>
</div> </div>
</ui:repeat> </ui:repeat>
</h:panelGroup> </h:panelGroup>
@@ -242,8 +245,13 @@
<p:outputLabel for="numeroParrain" value="N° Membre parrain" /> <p:outputLabel for="numeroParrain" value="N° Membre parrain" />
<div class="ui-inputgroup"> <div class="ui-inputgroup">
<p:inputText id="numeroParrain" value="#{membreInscriptionBean.numeroParrain}" /> <p:inputText id="numeroParrain" value="#{membreInscriptionBean.numeroParrain}" />
<p:commandButton icon="pi pi-search" styleClass="ui-button-info" <ui:include src="/templates/components/button-icon.xhtml">
action="#{membreInscriptionBean.rechercherParrain}" /> <ui:param name="icon" value="pi pi-search" />
<ui:param name="action" value="#{membreInscriptionBean.rechercherParrain}" />
<ui:param name="severity" value="info" />
<ui:param name="rounded" value="false" />
<ui:param name="text" value="false" />
</ui:include>
</div> </div>
</div> </div>
<div class="field"> <div class="field">
@@ -358,28 +366,37 @@
</div> </div>
<div class="flex flex-wrap gap-2"> <div class="flex flex-wrap gap-2">
<p:commandButton value="🎯 Inscrire le membre" icon="pi pi-user-plus" <ui:include src="/templates/components/button-success.xhtml">
styleClass="ui-button ui-button-success" <ui:param name="value" value="🎯 Inscrire le membre" />
onclick="return preparePhotoForSubmission(this);" <ui:param name="icon" value="pi pi-user-plus" />
action="#{membreInscriptionBean.inscrire}" <ui:param name="onclick" value="return preparePhotoForSubmission(this);" />
update="messages" <ui:param name="action" value="#{membreInscriptionBean.inscrire}" />
disabled="#{!membreInscriptionBean.formulaireValide}" /> <ui:param name="update" value="messages" />
<ui:param name="disabled" value="#{!membreInscriptionBean.formulaireValide}" />
</ui:include>
<p:commandButton value="💾 Enregistrer brouillon" icon="pi pi-save" <ui:include src="/templates/components/button-info.xhtml">
styleClass="ui-button ui-button-outlined ui-button-info" <ui:param name="value" value="💾 Enregistrer brouillon" />
action="#{membreInscriptionBean.enregistrerBrouillon}" <ui:param name="icon" value="pi pi-save" />
update="messages" /> <ui:param name="action" value="#{membreInscriptionBean.enregistrerBrouillon}" />
<ui:param name="update" value="messages" />
<ui:param name="outlined" value="true" />
</ui:include>
<p:commandButton value="🔄 Réinitialiser" icon="pi pi-refresh" <ui:include src="/templates/components/button-warning.xhtml">
styleClass="ui-button ui-button-outlined ui-button-warning" <ui:param name="value" value="🔄 Réinitialiser" />
type="reset" <ui:param name="icon" value="pi pi-refresh" />
onclick="removePhoto(); return confirm('Êtes-vous sûr de vouloir réinitialiser le formulaire ?');" /> <ui:param name="onclick" value="removePhoto(); return confirm('Êtes-vous sûr de vouloir réinitialiser le formulaire ?');" />
<ui:param name="outlined" value="true" />
</ui:include>
<p:commandButton value="❌ Annuler" icon="pi pi-times" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="ui-button ui-button-outlined ui-button-secondary" <ui:param name="value" value="❌ Annuler" />
action="#{membreInscriptionBean.annuler}" <ui:param name="icon" value="pi pi-times" />
immediate="true" <ui:param name="action" value="#{membreInscriptionBean.annuler}" />
onclick="return confirm('Êtes-vous sûr de vouloir annuler l\'inscription ?');" /> <ui:param name="onclick" value="return confirm('Êtes-vous sûr de vouloir annuler l\'inscription ?');" />
<ui:param name="outlined" value="true" />
</ui:include>
</div> </div>
<div class="mt-4 text-600"> <div class="mt-4 text-600">

View File

@@ -23,14 +23,17 @@
</div> </div>
<h:form id="formActionsMembres"> <h:form id="formActionsMembres">
<div class="flex gap-2"> <div class="flex gap-2">
<p:commandButton value="Nouveau membre" <ui:include src="/templates/components/button-success.xhtml">
icon="pi pi-user-plus" <ui:param name="value" value="Nouveau membre" />
styleClass="ui-button-success" <ui:param name="icon" value="pi pi-user-plus" />
action="/pages/secure/membre/inscription?faces-redirect=true" /> <ui:param name="action" value="/pages/secure/membre/inscription?faces-redirect=true" />
<p:commandButton value="Import/Export" </ui:include>
icon="pi pi-upload" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="ui-button-outlined ui-button-secondary" <ui:param name="value" value="Import/Export" />
onclick="PF('dlgImportExport').show();" /> <ui:param name="icon" value="pi pi-upload" />
<ui:param name="onclick" value="PF('dlgImportExport').show();" />
<ui:param name="outlined" value="true" />
</ui:include>
</div> </div>
</h:form> </h:form>
</div> </div>
@@ -94,15 +97,22 @@
</p:toolbarGroup> </p:toolbarGroup>
<p:toolbarGroup align="right"> <p:toolbarGroup align="right">
<p:commandButton value="Filtres avancés" <ui:include src="/templates/components/button-secondary.xhtml">
icon="pi pi-filter" <ui:param name="value" value="Filtres avancés" />
styleClass="ui-button-outlined ui-button-secondary mr-2" <ui:param name="icon" value="pi pi-filter" />
onclick="PF('dlgFiltresAvances').show();" /> <ui:param name="onclick" value="PF('dlgFiltresAvances').show();" />
<p:commandButton icon="pi pi-refresh" <ui:param name="outlined" value="true" />
styleClass="ui-button-outlined ui-button-secondary" <ui:param name="styleClass" value="mr-2" />
action="#{membreListeBean.actualiser}" </ui:include>
update="@form" <ui:include src="/templates/components/button-icon.xhtml">
title="Actualiser" /> <ui:param name="icon" value="pi pi-refresh" />
<ui:param name="action" value="#{membreListeBean.actualiser}" />
<ui:param name="update" value="@form" />
<ui:param name="title" value="Actualiser" />
<ui:param name="rounded" value="false" />
<ui:param name="text" value="false" />
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
</ui:include>
</p:toolbarGroup> </p:toolbarGroup>
</p:toolbar> </p:toolbar>
@@ -188,33 +198,45 @@
<p:column headerText="Actions" style="width:200px"> <p:column headerText="Actions" style="width:200px">
<div class="flex gap-1"> <div class="flex gap-1">
<p:commandButton icon="pi pi-eye" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="ui-button-rounded ui-button-text ui-button-info" <ui:param name="icon" value="pi pi-eye" />
action="#{membreListeBean.voirProfil(membre)}" <ui:param name="action" value="#{membreListeBean.voirProfil(membre)}" />
title="Voir profil" /> <ui:param name="title" value="Voir profil" />
<p:commandButton icon="pi pi-pencil" <ui:param name="severity" value="info" />
styleClass="ui-button-rounded ui-button-text ui-button-warning" </ui:include>
action="#{membreListeBean.modifierMembre(membre)}" <ui:include src="/templates/components/button-icon.xhtml">
title="Modifier" /> <ui:param name="icon" value="pi pi-pencil" />
<p:commandButton icon="pi pi-dollar" <ui:param name="action" value="#{membreListeBean.modifierMembre(membre)}" />
styleClass="ui-button-rounded ui-button-text ui-button-success" <ui:param name="title" value="Modifier" />
action="#{membreListeBean.gererCotisations(membre)}" <ui:param name="severity" value="warning" />
title="Cotisations" /> </ui:include>
<p:commandButton icon="pi pi-envelope" <ui:include src="/templates/components/button-icon.xhtml">
styleClass="ui-button-rounded ui-button-text ui-button-secondary" <ui:param name="icon" value="pi pi-dollar" />
action="#{membreListeBean.contacterMembre(membre)}" <ui:param name="action" value="#{membreListeBean.gererCotisations(membre)}" />
title="Contacter" /> <ui:param name="title" value="Cotisations" />
<p:commandButton icon="pi pi-ban" <ui:param name="severity" value="success" />
styleClass="ui-button-rounded ui-button-text ui-button-danger" </ui:include>
action="#{membreListeBean.suspendreMembre(membre)}" <ui:include src="/templates/components/button-icon.xhtml">
onclick="return confirm('Êtes-vous sûr de vouloir suspendre ce membre ?');" <ui:param name="icon" value="pi pi-envelope" />
title="Suspendre" <ui:param name="action" value="#{membreListeBean.contacterMembre(membre)}" />
rendered="#{membre.statut == 'ACTIF'}" /> <ui:param name="title" value="Contacter" />
<p:commandButton icon="pi pi-check" <ui:param name="severity" value="" />
styleClass="ui-button-rounded ui-button-text ui-button-success" </ui:include>
action="#{membreListeBean.reactiverMembre(membre)}" <ui:include src="/templates/components/button-icon.xhtml">
title="Réactiver" <ui:param name="icon" value="pi pi-ban" />
rendered="#{membre.statut == 'SUSPENDU'}" /> <ui:param name="action" value="#{membreListeBean.suspendreMembre(membre)}" />
<ui:param name="onclick" value="return confirm('Êtes-vous sûr de vouloir suspendre ce membre ?');" />
<ui:param name="title" value="Suspendre" />
<ui:param name="severity" value="danger" />
<ui:param name="rendered" value="#{membre.statut == 'ACTIF'}" />
</ui:include>
<ui:include src="/templates/components/button-icon.xhtml">
<ui:param name="icon" value="pi pi-check" />
<ui:param name="action" value="#{membreListeBean.reactiverMembre(membre)}" />
<ui:param name="title" value="Réactiver" />
<ui:param name="severity" value="success" />
<ui:param name="rendered" value="#{membre.statut == 'SUSPENDU'}" />
</ui:include>
</div> </div>
</p:column> </p:column>
</p:dataTable> </p:dataTable>
@@ -228,29 +250,35 @@
</span> </span>
</div> </div>
<div class="flex gap-2"> <div class="flex gap-2">
<p:commandButton value="Envoyer message" <ui:include src="/templates/components/button-info.xhtml">
icon="pi pi-envelope" <ui:param name="value" value="Envoyer message" />
styleClass="ui-button-outlined ui-button-info" <ui:param name="icon" value="pi pi-envelope" />
onclick="PF('dlgMessageGroupe').show();" <ui:param name="onclick" value="PF('dlgMessageGroupe').show();" />
disabled="#{empty membreListeBean.selectedMembres}" /> <ui:param name="outlined" value="true" />
<p:commandButton value="Rappel cotisations" <ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
icon="pi pi-bell" </ui:include>
styleClass="ui-button-outlined ui-button-warning" <ui:include src="/templates/components/button-warning.xhtml">
action="#{membreListeBean.rappelCotisationsGroupe}" <ui:param name="value" value="Rappel cotisations" />
update="@form" <ui:param name="icon" value="pi pi-bell" />
process="@form" <ui:param name="action" value="#{membreListeBean.rappelCotisationsGroupe}" />
disabled="#{empty membreListeBean.selectedMembres}" /> <ui:param name="update" value="@form" />
<p:commandButton value="Exporter sélection" <ui:param name="outlined" value="true" />
icon="pi pi-file-excel" <ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
styleClass="ui-button-outlined ui-button-success" </ui:include>
action="#{membreListeBean.exporterSelection}" <ui:include src="/templates/components/button-success.xhtml">
process="@form" <ui:param name="value" value="Exporter sélection" />
disabled="#{empty membreListeBean.selectedMembres}" /> <ui:param name="icon" value="pi pi-file-excel" />
<p:commandButton value="Modifier en lot" <ui:param name="action" value="#{membreListeBean.exporterSelection}" />
icon="pi pi-pencil" <ui:param name="outlined" value="true" />
styleClass="ui-button-outlined ui-button-secondary" <ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
onclick="PF('dlgModificationLot').show();" </ui:include>
disabled="#{empty membreListeBean.selectedMembres}" /> <ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Modifier en lot" />
<ui:param name="icon" value="pi pi-pencil" />
<ui:param name="onclick" value="PF('dlgModificationLot').show();" />
<ui:param name="outlined" value="true" />
<ui:param name="disabled" value="#{empty membreListeBean.selectedMembres}" />
</ui:include>
</div> </div>
</div> </div>
</h:form> </h:form>
@@ -320,18 +348,27 @@
</div> </div>
<div class="flex gap-2 mt-3"> <div class="flex gap-2 mt-3">
<p:commandButton value="Appliquer" icon="pi pi-check" <ui:include src="/templates/components/button-info.xhtml">
styleClass="ui-button-info" <ui:param name="value" value="Appliquer" />
action="#{membreListeBean.appliquerFiltresAvances}" <ui:param name="icon" value="pi pi-check" />
update=":formMembres:dtMembres" <ui:param name="action" value="#{membreListeBean.appliquerFiltresAvances}" />
oncomplete="PF('dlgFiltresAvances').hide();" /> <ui:param name="update" value=":formMembres:dtMembres" />
<p:commandButton value="Réinitialiser" icon="pi pi-refresh" <ui:param name="onclick" value="PF('dlgFiltresAvances').hide();" />
styleClass="ui-button-outlined ui-button-secondary" </ui:include>
action="#{membreListeBean.reinitialiserFiltres}" <ui:include src="/templates/components/button-secondary.xhtml">
update="@form :formMembres:dtMembres" /> <ui:param name="value" value="Réinitialiser" />
<p:commandButton value="Annuler" icon="pi pi-times" <ui:param name="icon" value="pi pi-refresh" />
styleClass="ui-button-outlined ui-button-danger" <ui:param name="action" value="#{membreListeBean.reinitialiserFiltres}" />
onclick="PF('dlgFiltresAvances').hide();" type="button" /> <ui:param name="update" value="@form :formMembres:dtMembres" />
<ui:param name="outlined" value="true" />
</ui:include>
<ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Annuler" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="onclick" value="PF('dlgFiltresAvances').hide();" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="ui-button-danger" />
</ui:include>
</div> </div>
</h:form> </h:form>
</p:dialog> </p:dialog>
@@ -370,14 +407,19 @@
</div> </div>
<div class="flex gap-2 mt-3"> <div class="flex gap-2 mt-3">
<p:commandButton value="Envoyer" icon="pi pi-send" <ui:include src="/templates/components/button-info.xhtml">
styleClass="ui-button-info" <ui:param name="value" value="Envoyer" />
action="#{membreListeBean.envoyerMessageGroupe}" <ui:param name="icon" value="pi pi-send" />
update="@form" <ui:param name="action" value="#{membreListeBean.envoyerMessageGroupe}" />
oncomplete="if(!args.validationFailed) PF('dlgMessageGroupe').hide();" /> <ui:param name="update" value="@form" />
<p:commandButton value="Annuler" icon="pi pi-times" <ui:param name="onclick" value="if(!args.validationFailed) PF('dlgMessageGroupe').hide();" />
styleClass="ui-button-secondary" </ui:include>
onclick="PF('dlgMessageGroupe').hide();" type="button" /> <ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Annuler" />
<ui:param name="icon" value="pi pi-times" />
<ui:param name="onclick" value="PF('dlgMessageGroupe').hide();" />
<ui:param name="outlined" value="false" />
</ui:include>
</div> </div>
</h:form> </h:form>
</p:dialog> </p:dialog>
@@ -408,13 +450,18 @@
</div> </div>
<div class="flex gap-2 mt-3"> <div class="flex gap-2 mt-3">
<p:commandButton value="Importer" icon="pi pi-upload" <ui:include src="/templates/components/button-success.xhtml">
styleClass="ui-button-success" <ui:param name="value" value="Importer" />
action="#{membreListeBean.importerMembres}" <ui:param name="icon" value="pi pi-upload" />
update="@form :formMembres" /> <ui:param name="action" value="#{membreListeBean.importerMembres}" />
<p:commandButton value="Télécharger modèle" icon="pi pi-download" <ui:param name="update" value="@form :formMembres" />
styleClass="ui-button-outlined ui-button-info" </ui:include>
action="#{membreListeBean.telechargerModele}" /> <ui:include src="/templates/components/button-info.xhtml">
<ui:param name="value" value="Télécharger modèle" />
<ui:param name="icon" value="pi pi-download" />
<ui:param name="action" value="#{membreListeBean.telechargerModele}" />
<ui:param name="outlined" value="true" />
</ui:include>
</div> </div>
</p:tab> </p:tab>
@@ -448,17 +495,22 @@
</div> </div>
<div class="flex gap-2 mt-3"> <div class="flex gap-2 mt-3">
<p:commandButton value="Exporter" icon="pi pi-download" <ui:include src="/templates/components/button-success.xhtml">
styleClass="ui-button-success" <ui:param name="value" value="Exporter" />
action="#{membreListeBean.exporterMembres}" /> <ui:param name="icon" value="pi pi-download" />
<ui:param name="action" value="#{membreListeBean.exporterMembres}" />
</ui:include>
</div> </div>
</p:tab> </p:tab>
</p:tabView> </p:tabView>
<div class="flex justify-content-end mt-3"> <div class="flex justify-content-end mt-3">
<p:commandButton value="Fermer" icon="pi pi-times" <ui:include src="/templates/components/button-secondary.xhtml">
styleClass="ui-button-secondary" <ui:param name="value" value="Fermer" />
onclick="PF('dlgImportExport').hide();" type="button" /> <ui:param name="icon" value="pi pi-times" />
<ui:param name="onclick" value="PF('dlgImportExport').hide();" />
<ui:param name="outlined" value="false" />
</ui:include>
</div> </div>
</h:form> </h:form>
</p:dialog> </p:dialog>

View File

@@ -0,0 +1,32 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton icône seule réutilisable (WOU/DRY)
Usage: <ui:include src="/templates/components/button-icon.xhtml">
<ui:param name="icon" value="pi pi-icon-name" />
<ui:param name="action" value="#{bean.method}" />
<ui:param name="update" value="componentId" />
<ui:param name="onclick" value="javascript" />
<ui:param name="severity" value="info|success|warning|danger" />
<ui:param name="rounded" value="true" />
<ui:param name="text" value="true" />
</ui:include>
-->
<ui:fragment rendered="#{empty rendered or rendered}">
<p:commandButton
icon="#{icon}"
action="#{action}"
actionListener="#{actionListener}"
update="#{update}"
onclick="#{onclick}"
disabled="#{not empty disabled and disabled}"
styleClass="#{not empty rounded and rounded ? 'ui-button-rounded' : ''} #{not empty text and text ? 'ui-button-text' : ''} #{not empty severity ? 'ui-button-' += severity : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
</ui:composition>

View File

@@ -0,0 +1,34 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton info réutilisable (WOU/DRY)
-->
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
actionListener="#{actionListener}"
update="#{update}"
onclick="#{onclick}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-info #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"
icon="#{icon}"
outcome="#{outcome}"
styleClass="ui-button-info #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
</ui:composition>

View File

@@ -0,0 +1,44 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton primaire réutilisable (WOU/DRY)
Usage: <ui:include src="/templates/components/button-primary.xhtml">
<ui:param name="value" value="Texte du bouton" />
<ui:param name="icon" value="pi pi-icon-name" />
<ui:param name="action" value="#{bean.method}" />
<ui:param name="outcome" value="/page" />
<ui:param name="update" value="componentId" />
<ui:param name="onclick" value="javascript" />
<ui:param name="disabled" value="false" />
<ui:param name="styleClass" value="" />
</ui:include>
-->
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
actionListener="#{actionListener}"
update="#{update}"
onclick="#{onclick}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-primary #{styleClass}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"
icon="#{icon}"
outcome="#{outcome}"
styleClass="ui-button-primary #{styleClass}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
</ui:composition>

View File

@@ -0,0 +1,45 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton secondaire réutilisable (WOU/DRY)
Usage: <ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="Texte du bouton" />
<ui:param name="icon" value="pi pi-icon-name" />
<ui:param name="action" value="#{bean.method}" />
<ui:param name="outcome" value="/page" />
<ui:param name="update" value="componentId" />
<ui:param name="onclick" value="javascript" />
<ui:param name="disabled" value="false" />
<ui:param name="outlined" value="true" />
<ui:param name="styleClass" value="" />
</ui:include>
-->
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
actionListener="#{actionListener}"
update="#{update}"
onclick="#{onclick}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-secondary #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"
icon="#{icon}"
outcome="#{outcome}"
styleClass="ui-button-secondary #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
</ui:composition>

View File

@@ -0,0 +1,34 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton succès réutilisable (WOU/DRY)
-->
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
actionListener="#{actionListener}"
update="#{update}"
onclick="#{onclick}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-success #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"
icon="#{icon}"
outcome="#{outcome}"
styleClass="ui-button-success #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
</ui:composition>

View File

@@ -0,0 +1,34 @@
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://xmlns.jcp.org/jsf/html"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:p="http://primefaces.org/ui">
<!--
Composant bouton warning réutilisable (WOU/DRY)
-->
<ui:fragment rendered="#{empty rendered or rendered}">
<ui:fragment rendered="#{empty outcome}">
<p:commandButton
value="#{value}"
icon="#{icon}"
action="#{action}"
actionListener="#{actionListener}"
update="#{update}"
onclick="#{onclick}"
disabled="#{not empty disabled and disabled}"
styleClass="ui-button-warning #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
<ui:fragment rendered="#{not empty outcome}">
<p:button
value="#{value}"
icon="#{icon}"
outcome="#{outcome}"
styleClass="ui-button-warning #{not empty outlined and outlined ? 'ui-button-outlined' : ''} #{styleClass}"
title="#{title}" />
</ui:fragment>
</ui:fragment>
</ui:composition>

View File

@@ -41,7 +41,10 @@
<h:form> <h:form>
<div class="newsletter-input"> <div class="newsletter-input">
<p:inputText placeholder="adresse email" /> <p:inputText placeholder="adresse email" />
<p:commandButton value="S'abonner" styleClass="ui-button-secondary "/> <ui:include src="/templates/components/button-secondary.xhtml">
<ui:param name="value" value="S'abonner" />
<ui:param name="outlined" value="false" />
</ui:include>
</div> </div>
</h:form> </h:form>
</div> </div>

View File

@@ -22,7 +22,12 @@
<div class="section-header"> <div class="section-header">
<h6>Mes tâches</h6> <h6>Mes tâches</h6>
<h:form> <h:form>
<p:commandButton type="button" icon="pi pi-plus" styleClass="ui-button-secondary ui-button-flat rounded-button" /> <ui:include src="/templates/components/button-icon.xhtml">
<ui:param name="icon" value="pi pi-plus" />
<ui:param name="rounded" value="true" />
<ui:param name="text" value="false" />
<ui:param name="styleClass" value="ui-button-secondary ui-button-flat" />
</ui:include>
</h:form> </h:form>
</div> </div>
<ul> <ul>

View File

@@ -0,0 +1,29 @@
# Configuration UnionFlow Client - Profil Développement
# Ce fichier est chargé automatiquement quand le profil 'dev' est actif
# Configuration logging pour développement
quarkus.log.category."dev.lions.unionflow".level=DEBUG
quarkus.log.category."jakarta.faces".level=INFO
quarkus.log.category."org.apache.myfaces".level=INFO
quarkus.log.category."org.primefaces".level=INFO
# Configuration MyFaces pour développement
quarkus.myfaces.project-stage=Development
quarkus.live-reload.instrumentation=true
# Configuration Keycloak pour développement
%dev.quarkus.oidc.enabled=true
%dev.quarkus.oidc.tls.verification=none
%dev.quarkus.oidc.authentication.redirect-path=/auth/callback
# %dev.quarkus.oidc.authentication.force-redirect-https=false # Not supported in this Quarkus version
%dev.quarkus.security.auth.enabled=true
# Secret Keycloak pour développement (UNIQUEMENT pour dev local)
# ⚠️ ATTENTION: Ne jamais commiter ce secret en production
# En production, utiliser la variable d'environnement KEYCLOAK_CLIENT_SECRET
%dev.quarkus.oidc.credentials.secret=${KEYCLOAK_CLIENT_SECRET:7dnWMwlabtoyp08F6FIuDxzDPE5VdUF6}
# Logging OIDC pour debug
%dev.quarkus.log.category."io.quarkus.oidc".level=DEBUG
%dev.quarkus.log.category."io.vertx.ext.auth.oidc".level=DEBUG
%dev.quarkus.log.category."io.quarkus.security".level=DEBUG

View File

@@ -0,0 +1,14 @@
# Configuration UnionFlow Client - Profil Production
# Ce fichier est chargé automatiquement quand le profil 'prod' est actif
# Configuration logging pour production
quarkus.log.console.level=WARN
# Configuration MyFaces pour production
quarkus.myfaces.project-stage=Production
quarkus.myfaces.serialize-state-in-session=true
# Configuration Keycloak pour production
%prod.quarkus.oidc.tls.verification=required
%prod.quarkus.oidc.authentication.redirect-path=/auth/callback

View File

@@ -3,7 +3,7 @@ quarkus.application.name=unionflow-client
quarkus.application.version=1.0.0 quarkus.application.version=1.0.0
# Configuration HTTP # Configuration HTTP
quarkus.http.port=8082 quarkus.http.port=8086
quarkus.http.host=0.0.0.0 quarkus.http.host=0.0.0.0
quarkus.http.root-path=/ quarkus.http.root-path=/
quarkus.http.so-reuse-port=true quarkus.http.so-reuse-port=true
@@ -28,7 +28,7 @@ quarkus.myfaces.number-of-views-in-session=50
quarkus.myfaces.number-of-sequential-views-in-session=10 quarkus.myfaces.number-of-sequential-views-in-session=10
quarkus.myfaces.serialize-state-in-session=false quarkus.myfaces.serialize-state-in-session=false
quarkus.myfaces.client-view-state-timeout=3600000 quarkus.myfaces.client-view-state-timeout=3600000
quarkus.myfaces.view-expired-exception-handler-redirect-page=/pages/public/login.xhtml quarkus.myfaces.view-expired-exception-handler-redirect-page=/
quarkus.myfaces.check-id-production-mode=false quarkus.myfaces.check-id-production-mode=false
quarkus.myfaces.strict-xhtml-links=false quarkus.myfaces.strict-xhtml-links=false
quarkus.myfaces.refresh-transient-build-on-pss=true quarkus.myfaces.refresh-transient-build-on-pss=true
@@ -36,7 +36,9 @@ quarkus.myfaces.resource-max-time-expires=604800000
quarkus.myfaces.resource-buffer-size=2048 quarkus.myfaces.resource-buffer-size=2048
# PrimeFaces Configuration # PrimeFaces Configuration
primefaces.THEME=freya-blue-light # IMPORTANT: Nous laissons PrimeFaces sans th<74>me par d<>faut et chargeons le th<74>me Freya via index.xhtml/main-template.xhtml
# pour <20>viter tout double-chargement (ex: Saga + Freya).
primefaces.THEME=none
primefaces.FONT_AWESOME=true primefaces.FONT_AWESOME=true
primefaces.CLIENT_SIDE_VALIDATION=true primefaces.CLIENT_SIDE_VALIDATION=true
primefaces.MOVE_SCRIPTS_TO_BOTTOM=true primefaces.MOVE_SCRIPTS_TO_BOTTOM=true
@@ -51,7 +53,7 @@ omnifaces.CDN_RESOURCE_HANDLER_DISABLED=true
omnifaces.COMBINED_RESOURCE_HANDLER_DISABLED=false omnifaces.COMBINED_RESOURCE_HANDLER_DISABLED=false
# Configuration Backend UnionFlow # Configuration Backend UnionFlow
unionflow.backend.url=${UNIONFLOW_BACKEND_URL:http://localhost:8080} unionflow.backend.url=${UNIONFLOW_BACKEND_URL:http://localhost:8085}
# Configuration REST Client # Configuration REST Client
quarkus.rest-client."unionflow-api".url=${unionflow.backend.url} quarkus.rest-client."unionflow-api".url=${unionflow.backend.url}
@@ -62,11 +64,46 @@ quarkus.rest-client."unionflow-api".read-timeout=30000
# Gestion des erreurs REST # Gestion des erreurs REST
quarkus.rest-client."unionflow-api".providers=dev.lions.unionflow.client.service.RestClientExceptionMapper quarkus.rest-client."unionflow-api".providers=dev.lions.unionflow.client.service.RestClientExceptionMapper
# Configuration JWT et Sécurité # Configuration Keycloak OIDC
unionflow.jwt.secret=${JWT_SECRET:union-flow-secret-key-very-long-and-secure-2024} quarkus.oidc.enabled=true
unionflow.jwt.issuer=${JWT_ISSUER:unionflow-platform} quarkus.oidc.auth-server-url=https://security.lions.dev/realms/unionflow
unionflow.jwt.expiration-time=${JWT_EXPIRATION:3600} quarkus.oidc.client-id=unionflow-client
unionflow.jwt.refresh-expiration-time=${JWT_REFRESH_EXPIRATION:86400} 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=none
# quarkus.oidc.authentication.force-redirect-https=false # Not supported in this Quarkus version
quarkus.oidc.authentication.cookie-same-site=lax
quarkus.oidc.authentication.java-script-auto-redirect=false
quarkus.oidc.discovery-enabled=true
# TEMPORAIRE: contourner un access token invalide (claim realm_access dupliqu<71>e c<>t<EFBFBD> KC)
# Pour un flux web-app, on peut s'appuyer sur l'ID Token et d<>sactiver la v<>rification de l'Access Token
# Les deux cl<63>s ci?dessous couvrent les variantes selon version de Quarkus; l'une sera ignor<6F>e si non support<72>e.
# Vérification du token activée
# ✅ CORRIGÉ: Le mapper Keycloak problématique a été supprimé (17/11/2025)
# Le scope "roles" gère maintenant correctement realm_access.roles (objet unique)
quarkus.oidc.verify-access-token=true
# Activation de la sécurité
quarkus.security.auth.enabled=true
# Chemins publics (non prot<6F>g<EFBFBD>s par OIDC) - Doit <20>tre d<>fini en premier
# La page d'accueil (/) et index.xhtml sont publics pour permettre l'affichage initial
# IMPORTANT: Les ressources JSF/PrimeFaces sont servies via /jakarta.faces.resource/* (ou /javax.faces.resource/* selon la stack)
# Elles doivent <20>tre publiques pour permettre le chargement des CSS/JS (th<74>me Freya, primeicons, primeflex, etc.)
# On inclut <20>galement /q/oidc/* pour laisser Quarkus OIDC exposer ses endpoints internes si n<>cessaire.
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
# IMPORTANT: L'ordre est crucial - les permissions publiques doivent être définies AVANT les permissions authentifiées
# Quarkus OIDC redirigera automatiquement vers Keycloak pour les chemins non publics
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
# Configuration Session # Configuration Session
unionflow.session.timeout=${SESSION_TIMEOUT:1800} unionflow.session.timeout=${SESSION_TIMEOUT:1800}
@@ -78,16 +115,3 @@ unionflow.security.password.min-length=${PASSWORD_MIN_LENGTH:8}
unionflow.security.password.require-special-chars=${PASSWORD_REQUIRE_SPECIAL:true} unionflow.security.password.require-special-chars=${PASSWORD_REQUIRE_SPECIAL:true}
unionflow.security.max-login-attempts=${MAX_LOGIN_ATTEMPTS:5} unionflow.security.max-login-attempts=${MAX_LOGIN_ATTEMPTS:5}
unionflow.security.lockout-duration=${LOCKOUT_DURATION:300} unionflow.security.lockout-duration=${LOCKOUT_DURATION:300}
# Dev mode configuration
%dev.quarkus.log.category."dev.lions.unionflow".level=DEBUG
%dev.quarkus.log.category."jakarta.faces".level=INFO
%dev.quarkus.log.category."org.apache.myfaces".level=INFO
%dev.quarkus.log.category."org.primefaces".level=INFO
%dev.quarkus.myfaces.project-stage=Development
%dev.quarkus.live-reload.instrumentation=true
# Prod mode configuration
%prod.quarkus.log.console.level=WARN
%prod.quarkus.myfaces.project-stage=Production
%prod.quarkus.myfaces.serialize-state-in-session=true