Refactroring
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package dev.lions.unionflow.client.constants;
|
||||
|
||||
/**
|
||||
* Constantes pour les statuts d'organisations
|
||||
* Ces valeurs doivent correspondre à l'enum StatutOrganisation du module server-api
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
public final class StatutOrganisationConstants {
|
||||
|
||||
private StatutOrganisationConstants() {
|
||||
// Classe utilitaire, pas d'instanciation
|
||||
}
|
||||
|
||||
/** Statut actif */
|
||||
public static final String ACTIVE = "ACTIVE";
|
||||
|
||||
/** Statut inactif */
|
||||
public static final String INACTIVE = "INACTIVE";
|
||||
|
||||
/** Statut suspendue */
|
||||
public static final String SUSPENDUE = "SUSPENDUE";
|
||||
|
||||
/** Statut en création */
|
||||
public static final String EN_CREATION = "EN_CREATION";
|
||||
|
||||
/** Statut dissoute */
|
||||
public static final String DISSOUTE = "DISSOUTE";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
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.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DTO pour la gestion des adhésions côté client
|
||||
* Correspond au AdhesionDTO du backend avec méthodes utilitaires pour l'affichage
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
public class AdhesionDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private UUID id;
|
||||
private String numeroReference;
|
||||
private UUID membreId;
|
||||
private String numeroMembre;
|
||||
private String nomMembre;
|
||||
private String emailMembre;
|
||||
private UUID organisationId;
|
||||
private String nomOrganisation;
|
||||
private LocalDate dateDemande;
|
||||
private BigDecimal fraisAdhesion;
|
||||
private BigDecimal montantPaye;
|
||||
private String codeDevise;
|
||||
private String statut;
|
||||
private LocalDate dateApprobation;
|
||||
private LocalDateTime datePaiement;
|
||||
private String methodePaiement;
|
||||
private String referencePaiement;
|
||||
private String motifRejet;
|
||||
private String observations;
|
||||
private String approuvePar;
|
||||
private LocalDate dateValidation;
|
||||
private LocalDateTime dateCreation;
|
||||
private LocalDateTime dateModification;
|
||||
private Boolean actif;
|
||||
|
||||
// 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 String getEmailMembre() { return emailMembre; }
|
||||
public void setEmailMembre(String emailMembre) { this.emailMembre = emailMembre; }
|
||||
|
||||
public UUID getOrganisationId() { return organisationId; }
|
||||
public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
|
||||
|
||||
public String getNomOrganisation() { return nomOrganisation; }
|
||||
public void setNomOrganisation(String nomOrganisation) { this.nomOrganisation = nomOrganisation; }
|
||||
|
||||
public LocalDate getDateDemande() { return dateDemande; }
|
||||
public void setDateDemande(LocalDate dateDemande) { this.dateDemande = dateDemande; }
|
||||
|
||||
public BigDecimal getFraisAdhesion() { return fraisAdhesion; }
|
||||
public void setFraisAdhesion(BigDecimal fraisAdhesion) { this.fraisAdhesion = fraisAdhesion; }
|
||||
|
||||
public BigDecimal getMontantPaye() { return montantPaye != null ? montantPaye : BigDecimal.ZERO; }
|
||||
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 getDateApprobation() { return dateApprobation; }
|
||||
public void setDateApprobation(LocalDate dateApprobation) { this.dateApprobation = dateApprobation; }
|
||||
|
||||
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 getReferencePaiement() { return referencePaiement; }
|
||||
public void setReferencePaiement(String referencePaiement) { this.referencePaiement = referencePaiement; }
|
||||
|
||||
public String getMotifRejet() { return motifRejet; }
|
||||
public void setMotifRejet(String motifRejet) { this.motifRejet = motifRejet; }
|
||||
|
||||
public String getObservations() { return observations; }
|
||||
public void setObservations(String observations) { this.observations = observations; }
|
||||
|
||||
public String getApprouvePar() { return approuvePar; }
|
||||
public void setApprouvePar(String approuvePar) { this.approuvePar = approuvePar; }
|
||||
|
||||
public LocalDate getDateValidation() { return dateValidation; }
|
||||
public void setDateValidation(LocalDate dateValidation) { this.dateValidation = dateValidation; }
|
||||
|
||||
public LocalDateTime getDateCreation() { return dateCreation; }
|
||||
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
|
||||
|
||||
public LocalDateTime getDateModification() { return dateModification; }
|
||||
public void setDateModification(LocalDateTime dateModification) { this.dateModification = dateModification; }
|
||||
|
||||
public Boolean getActif() { return actif; }
|
||||
public void setActif(Boolean actif) { this.actif = actif; }
|
||||
|
||||
// Méthodes utilitaires pour l'affichage (alignées avec le backend)
|
||||
|
||||
/**
|
||||
* Vérifie si l'adhésion est payée intégralement
|
||||
*/
|
||||
public boolean isPayeeIntegralement() {
|
||||
return montantPaye != null && fraisAdhesion != null && montantPaye.compareTo(fraisAdhesion) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'adhésion est en attente de paiement
|
||||
*/
|
||||
public boolean isEnAttentePaiement() {
|
||||
return "APPROUVEE".equals(statut) && !isPayeeIntegralement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le montant restant à payer
|
||||
*/
|
||||
public BigDecimal getMontantRestant() {
|
||||
if (fraisAdhesion == null) return BigDecimal.ZERO;
|
||||
if (montantPaye == null) return fraisAdhesion;
|
||||
BigDecimal restant = fraisAdhesion.subtract(montantPaye);
|
||||
return restant.compareTo(BigDecimal.ZERO) > 0 ? restant : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le pourcentage de paiement
|
||||
*/
|
||||
public int getPourcentagePaiement() {
|
||||
if (fraisAdhesion == null || fraisAdhesion.compareTo(BigDecimal.ZERO) == 0) return 0;
|
||||
if (montantPaye == null) return 0;
|
||||
return montantPaye.multiply(BigDecimal.valueOf(100))
|
||||
.divide(fraisAdhesion, 0, java.math.RoundingMode.HALF_UP)
|
||||
.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le nombre de jours depuis la demande
|
||||
*/
|
||||
public long getJoursDepuisDemande() {
|
||||
if (dateDemande == null) return 0;
|
||||
return ChronoUnit.DAYS.between(dateDemande, LocalDate.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé du statut
|
||||
*/
|
||||
public String getStatutLibelle() {
|
||||
if (statut == null) return "Non défini";
|
||||
return switch (statut) {
|
||||
case "EN_ATTENTE" -> "En attente";
|
||||
case "APPROUVEE" -> "Approuvée";
|
||||
case "REJETEE" -> "Rejetée";
|
||||
case "ANNULEE" -> "Annulée";
|
||||
case "EN_PAIEMENT" -> "En paiement";
|
||||
case "PAYEE" -> "Payée";
|
||||
default -> statut;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la sévérité du statut pour PrimeFaces
|
||||
*/
|
||||
public String getStatutSeverity() {
|
||||
if (statut == null) return "secondary";
|
||||
return switch (statut) {
|
||||
case "APPROUVEE", "PAYEE" -> "success";
|
||||
case "EN_ATTENTE", "EN_PAIEMENT" -> "warning";
|
||||
case "REJETEE" -> "danger";
|
||||
case "ANNULEE" -> "secondary";
|
||||
default -> "secondary";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône du statut pour PrimeFaces
|
||||
*/
|
||||
public String getStatutIcon() {
|
||||
if (statut == null) return "pi-circle";
|
||||
return switch (statut) {
|
||||
case "APPROUVEE", "PAYEE" -> "pi-check";
|
||||
case "EN_ATTENTE" -> "pi-clock";
|
||||
case "EN_PAIEMENT" -> "pi-credit-card";
|
||||
case "REJETEE" -> "pi-times";
|
||||
case "ANNULEE" -> "pi-ban";
|
||||
default -> "pi-circle";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé de la méthode de paiement
|
||||
*/
|
||||
public String getMethodePaiementLibelle() {
|
||||
if (methodePaiement == null) return "Non défini";
|
||||
return switch (methodePaiement) {
|
||||
case "ESPECES" -> "Espèces";
|
||||
case "VIREMENT" -> "Virement bancaire";
|
||||
case "CHEQUE" -> "Chèque";
|
||||
case "WAVE_MONEY" -> "Wave Money";
|
||||
case "ORANGE_MONEY" -> "Orange Money";
|
||||
case "FREE_MONEY" -> "Free Money";
|
||||
case "CARTE_BANCAIRE" -> "Carte bancaire";
|
||||
default -> methodePaiement;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la date de demande
|
||||
*/
|
||||
public String getDateDemandeFormatee() {
|
||||
if (dateDemande == null) return "";
|
||||
return dateDemande.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la date d'approbation
|
||||
*/
|
||||
public String getDateApprobationFormatee() {
|
||||
if (dateApprobation == null) return "";
|
||||
return dateApprobation.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la date de paiement
|
||||
*/
|
||||
public String getDatePaiementFormatee() {
|
||||
if (datePaiement == null) return "";
|
||||
return datePaiement.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate les frais d'adhésion
|
||||
*/
|
||||
public String getFraisAdhesionFormatte() {
|
||||
if (fraisAdhesion == null) return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", fraisAdhesion.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate le montant payé
|
||||
*/
|
||||
public String getMontantPayeFormatte() {
|
||||
if (montantPaye == null) return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", montantPaye.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate le montant restant
|
||||
*/
|
||||
public String getMontantRestantFormatte() {
|
||||
return String.format("%,.0f FCFA", getMontantRestant().doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,300 @@
|
||||
package dev.lions.unionflow.client.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DTO côté client pour les données analytics
|
||||
* Enrichi avec des méthodes utilitaires pour l'affichage
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-17
|
||||
*/
|
||||
public class AnalyticsDataDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
|
||||
private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
|
||||
|
||||
private String id;
|
||||
private String typeMetrique;
|
||||
private String periodeAnalyse;
|
||||
private BigDecimal valeur;
|
||||
private BigDecimal valeurPrecedente;
|
||||
private BigDecimal pourcentageEvolution;
|
||||
private LocalDateTime dateDebut;
|
||||
private LocalDateTime dateFin;
|
||||
private LocalDateTime dateCalcul;
|
||||
private String organisationId;
|
||||
private String nomOrganisation;
|
||||
private String utilisateurId;
|
||||
private String nomUtilisateur;
|
||||
private String libellePersonnalise;
|
||||
private String description;
|
||||
private String donneesDetaillees;
|
||||
private String configurationGraphique;
|
||||
private Map<String, Object> metadonnees;
|
||||
private BigDecimal indicateurFiabilite;
|
||||
private Integer nombreElementsAnalyses;
|
||||
private Long tempsCalculMs;
|
||||
private Boolean tempsReel;
|
||||
private Boolean necessiteMiseAJour;
|
||||
private Integer niveauPriorite;
|
||||
private java.util.List<String> tags;
|
||||
|
||||
// Getters et Setters
|
||||
public String getId() { return id; }
|
||||
public void setId(String id) { this.id = id; }
|
||||
|
||||
public String getTypeMetrique() { return typeMetrique; }
|
||||
public void setTypeMetrique(String typeMetrique) { this.typeMetrique = typeMetrique; }
|
||||
|
||||
public String getPeriodeAnalyse() { return periodeAnalyse; }
|
||||
public void setPeriodeAnalyse(String periodeAnalyse) { this.periodeAnalyse = periodeAnalyse; }
|
||||
|
||||
public BigDecimal getValeur() { return valeur; }
|
||||
public void setValeur(BigDecimal valeur) { this.valeur = valeur; }
|
||||
|
||||
public BigDecimal getValeurPrecedente() { return valeurPrecedente; }
|
||||
public void setValeurPrecedente(BigDecimal valeurPrecedente) { this.valeurPrecedente = valeurPrecedente; }
|
||||
|
||||
public BigDecimal getPourcentageEvolution() { return pourcentageEvolution; }
|
||||
public void setPourcentageEvolution(BigDecimal pourcentageEvolution) { this.pourcentageEvolution = pourcentageEvolution; }
|
||||
|
||||
public LocalDateTime getDateDebut() { return dateDebut; }
|
||||
public void setDateDebut(LocalDateTime dateDebut) { this.dateDebut = dateDebut; }
|
||||
|
||||
public LocalDateTime getDateFin() { return dateFin; }
|
||||
public void setDateFin(LocalDateTime dateFin) { this.dateFin = dateFin; }
|
||||
|
||||
public LocalDateTime getDateCalcul() { return dateCalcul; }
|
||||
public void setDateCalcul(LocalDateTime dateCalcul) { this.dateCalcul = dateCalcul; }
|
||||
|
||||
public String getOrganisationId() { return organisationId; }
|
||||
public void setOrganisationId(String organisationId) { this.organisationId = organisationId; }
|
||||
|
||||
public String getNomOrganisation() { return nomOrganisation; }
|
||||
public void setNomOrganisation(String nomOrganisation) { this.nomOrganisation = nomOrganisation; }
|
||||
|
||||
public String getUtilisateurId() { return utilisateurId; }
|
||||
public void setUtilisateurId(String utilisateurId) { this.utilisateurId = utilisateurId; }
|
||||
|
||||
public String getNomUtilisateur() { return nomUtilisateur; }
|
||||
public void setNomUtilisateur(String nomUtilisateur) { this.nomUtilisateur = nomUtilisateur; }
|
||||
|
||||
public String getLibellePersonnalise() { return libellePersonnalise; }
|
||||
public void setLibellePersonnalise(String libellePersonnalise) { this.libellePersonnalise = libellePersonnalise; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getDonneesDetaillees() { return donneesDetaillees; }
|
||||
public void setDonneesDetaillees(String donneesDetaillees) { this.donneesDetaillees = donneesDetaillees; }
|
||||
|
||||
public String getConfigurationGraphique() { return configurationGraphique; }
|
||||
public void setConfigurationGraphique(String configurationGraphique) { this.configurationGraphique = configurationGraphique; }
|
||||
|
||||
public Map<String, Object> getMetadonnees() { return metadonnees; }
|
||||
public void setMetadonnees(Map<String, Object> metadonnees) { this.metadonnees = metadonnees; }
|
||||
|
||||
public BigDecimal getIndicateurFiabilite() { return indicateurFiabilite; }
|
||||
public void setIndicateurFiabilite(BigDecimal indicateurFiabilite) { this.indicateurFiabilite = indicateurFiabilite; }
|
||||
|
||||
public Integer getNombreElementsAnalyses() { return nombreElementsAnalyses; }
|
||||
public void setNombreElementsAnalyses(Integer nombreElementsAnalyses) { this.nombreElementsAnalyses = nombreElementsAnalyses; }
|
||||
|
||||
public Long getTempsCalculMs() { return tempsCalculMs; }
|
||||
public void setTempsCalculMs(Long tempsCalculMs) { this.tempsCalculMs = tempsCalculMs; }
|
||||
|
||||
public Boolean getTempsReel() { return tempsReel; }
|
||||
public void setTempsReel(Boolean tempsReel) { this.tempsReel = tempsReel; }
|
||||
|
||||
public Boolean getNecessiteMiseAJour() { return necessiteMiseAJour; }
|
||||
public void setNecessiteMiseAJour(Boolean necessiteMiseAJour) { this.necessiteMiseAJour = necessiteMiseAJour; }
|
||||
|
||||
public Integer getNiveauPriorite() { return niveauPriorite; }
|
||||
public void setNiveauPriorite(Integer niveauPriorite) { this.niveauPriorite = niveauPriorite; }
|
||||
|
||||
public java.util.List<String> getTags() { return tags; }
|
||||
public void setTags(java.util.List<String> tags) { this.tags = tags; }
|
||||
|
||||
// === MÉTHODES UTILITAIRES ===
|
||||
|
||||
/**
|
||||
* Retourne le libellé à afficher
|
||||
*/
|
||||
public String getLibelleAffichage() {
|
||||
if (libellePersonnalise != null && !libellePersonnalise.trim().isEmpty()) {
|
||||
return libellePersonnalise;
|
||||
}
|
||||
return typeMetrique != null ? typeMetrique : "Métrique";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la valeur formatée
|
||||
*/
|
||||
public String getValeurFormatee() {
|
||||
if (valeur == null) return "0";
|
||||
return valeur.toPlainString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le pourcentage d'évolution formaté
|
||||
*/
|
||||
public String getEvolutionFormatee() {
|
||||
if (pourcentageEvolution == null) return "0%";
|
||||
String signe = pourcentageEvolution.compareTo(BigDecimal.ZERO) >= 0 ? "+" : "";
|
||||
return signe + pourcentageEvolution.setScale(2, java.math.RoundingMode.HALF_UP) + "%";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la couleur selon l'évolution
|
||||
*/
|
||||
public String getCouleurEvolution() {
|
||||
if (pourcentageEvolution == null) return "text-600";
|
||||
if (pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0) return "text-green-500";
|
||||
if (pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0) return "text-red-500";
|
||||
return "text-600";
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône selon l'évolution
|
||||
*/
|
||||
public String getIconeEvolution() {
|
||||
if (pourcentageEvolution == null) return "pi pi-minus";
|
||||
if (pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0) return "pi pi-arrow-up";
|
||||
if (pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0) return "pi pi-arrow-down";
|
||||
return "pi pi-minus";
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'évolution est positive
|
||||
*/
|
||||
public boolean hasEvolutionPositive() {
|
||||
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'évolution est négative
|
||||
*/
|
||||
public boolean hasEvolutionNegative() {
|
||||
return pourcentageEvolution != null && pourcentageEvolution.compareTo(BigDecimal.ZERO) < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si les données sont fiables
|
||||
*/
|
||||
public boolean isDonneesFiables() {
|
||||
return indicateurFiabilite != null && indicateurFiabilite.compareTo(new BigDecimal("80.0")) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la date de début formatée
|
||||
*/
|
||||
public String getDateDebutFormatee() {
|
||||
if (dateDebut == null) return "";
|
||||
return dateDebut.format(DATE_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la date de fin formatée
|
||||
*/
|
||||
public String getDateFinFormatee() {
|
||||
if (dateFin == null) return "";
|
||||
return dateFin.format(DATE_FORMATTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la période formatée
|
||||
*/
|
||||
public String getPeriodeFormatee() {
|
||||
return getDateDebutFormatee() + " - " + getDateFinFormatee();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit depuis une Map (réponse JSON du backend)
|
||||
*/
|
||||
public static AnalyticsDataDTO fromMap(Map<String, Object> map) {
|
||||
AnalyticsDataDTO dto = new AnalyticsDataDTO();
|
||||
if (map == null) return dto;
|
||||
|
||||
dto.setId((String) map.get("id"));
|
||||
dto.setTypeMetrique((String) map.get("typeMetrique"));
|
||||
dto.setPeriodeAnalyse((String) map.get("periodeAnalyse"));
|
||||
|
||||
if (map.get("valeur") != null) {
|
||||
dto.setValeur(new BigDecimal(map.get("valeur").toString()));
|
||||
}
|
||||
if (map.get("valeurPrecedente") != null) {
|
||||
dto.setValeurPrecedente(new BigDecimal(map.get("valeurPrecedente").toString()));
|
||||
}
|
||||
if (map.get("pourcentageEvolution") != null) {
|
||||
dto.setPourcentageEvolution(new BigDecimal(map.get("pourcentageEvolution").toString()));
|
||||
}
|
||||
|
||||
// Conversion des dates depuis des strings ISO
|
||||
if (map.get("dateDebut") != null) {
|
||||
dto.setDateDebut(parseDateTime(map.get("dateDebut").toString()));
|
||||
}
|
||||
if (map.get("dateFin") != null) {
|
||||
dto.setDateFin(parseDateTime(map.get("dateFin").toString()));
|
||||
}
|
||||
if (map.get("dateCalcul") != null) {
|
||||
dto.setDateCalcul(parseDateTime(map.get("dateCalcul").toString()));
|
||||
}
|
||||
|
||||
dto.setOrganisationId((String) map.get("organisationId"));
|
||||
dto.setNomOrganisation((String) map.get("nomOrganisation"));
|
||||
dto.setUtilisateurId((String) map.get("utilisateurId"));
|
||||
dto.setNomUtilisateur((String) map.get("nomUtilisateur"));
|
||||
dto.setLibellePersonnalise((String) map.get("libellePersonnalise"));
|
||||
dto.setDescription((String) map.get("description"));
|
||||
dto.setDonneesDetaillees((String) map.get("donneesDetaillees"));
|
||||
dto.setConfigurationGraphique((String) map.get("configurationGraphique"));
|
||||
dto.setMetadonnees((Map<String, Object>) map.get("metadonnees"));
|
||||
|
||||
if (map.get("indicateurFiabilite") != null) {
|
||||
dto.setIndicateurFiabilite(new BigDecimal(map.get("indicateurFiabilite").toString()));
|
||||
}
|
||||
if (map.get("nombreElementsAnalyses") != null) {
|
||||
dto.setNombreElementsAnalyses(Integer.valueOf(map.get("nombreElementsAnalyses").toString()));
|
||||
}
|
||||
if (map.get("tempsCalculMs") != null) {
|
||||
dto.setTempsCalculMs(Long.valueOf(map.get("tempsCalculMs").toString()));
|
||||
}
|
||||
|
||||
dto.setTempsReel((Boolean) map.get("tempsReel"));
|
||||
dto.setNecessiteMiseAJour((Boolean) map.get("necessiteMiseAJour"));
|
||||
if (map.get("niveauPriorite") != null) {
|
||||
dto.setNiveauPriorite(Integer.valueOf(map.get("niveauPriorite").toString()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
java.util.List<String> tagsList = (java.util.List<String>) map.get("tags");
|
||||
dto.setTags(tagsList);
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse une date depuis une string ISO
|
||||
*/
|
||||
private static LocalDateTime parseDateTime(String dateStr) {
|
||||
if (dateStr == null || dateStr.isEmpty()) return null;
|
||||
try {
|
||||
// Format ISO: "2025-01-17T10:30:00" ou "2025-01-17 10:30:00"
|
||||
String normalized = dateStr.replace(" ", "T");
|
||||
if (normalized.length() == 10) {
|
||||
normalized += "T00:00:00";
|
||||
}
|
||||
return LocalDateTime.parse(normalized);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package dev.lions.unionflow.client.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.time.LocalDate;
|
||||
@@ -24,6 +25,7 @@ public class AssociationDTO implements Serializable {
|
||||
private String siteWeb;
|
||||
|
||||
@NotNull(message = "Le type d'association est obligatoire")
|
||||
@JsonProperty("typeOrganisation")
|
||||
private String typeAssociation;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
@@ -42,6 +44,7 @@ public class AssociationDTO implements Serializable {
|
||||
private String region;
|
||||
private String ville;
|
||||
private String quartier;
|
||||
private String pays;
|
||||
|
||||
// Constructeurs
|
||||
public AssociationDTO() {}
|
||||
@@ -111,6 +114,9 @@ public class AssociationDTO implements Serializable {
|
||||
|
||||
public String getQuartier() { return quartier; }
|
||||
public void setQuartier(String quartier) { this.quartier = quartier; }
|
||||
|
||||
public String getPays() { return pays; }
|
||||
public void setPays(String pays) { this.pays = pays; }
|
||||
|
||||
// Propriétés dérivées
|
||||
public String getTypeLibelle() {
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
package dev.lions.unionflow.client.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DTO côté client pour les logs d'audit
|
||||
* Correspond au AuditLogDTO du backend avec méthodes utilitaires pour l'affichage
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
public class AuditLogDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private UUID id;
|
||||
private String typeAction;
|
||||
private String severite;
|
||||
private String utilisateur;
|
||||
private String role;
|
||||
private String module;
|
||||
private String description;
|
||||
private String details;
|
||||
private String ipAddress;
|
||||
private String userAgent;
|
||||
private String sessionId;
|
||||
private LocalDateTime dateHeure;
|
||||
private String donneesAvant;
|
||||
private String donneesApres;
|
||||
private String entiteId;
|
||||
private String entiteType;
|
||||
|
||||
// Getters et Setters
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
public String getTypeAction() { return typeAction; }
|
||||
public void setTypeAction(String typeAction) { this.typeAction = typeAction; }
|
||||
|
||||
public String getSeverite() { return severite; }
|
||||
public void setSeverite(String severite) { this.severite = severite; }
|
||||
|
||||
public String getUtilisateur() { return utilisateur; }
|
||||
public void setUtilisateur(String utilisateur) { this.utilisateur = utilisateur; }
|
||||
|
||||
public String getRole() { return role; }
|
||||
public void setRole(String role) { this.role = role; }
|
||||
|
||||
public String getModule() { return module; }
|
||||
public void setModule(String module) { this.module = module; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getDetails() { return details; }
|
||||
public void setDetails(String details) { this.details = details; }
|
||||
|
||||
public String getIpAddress() { return ipAddress; }
|
||||
public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
|
||||
|
||||
public String getUserAgent() { return userAgent; }
|
||||
public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
|
||||
|
||||
public String getSessionId() { return sessionId; }
|
||||
public void setSessionId(String sessionId) { this.sessionId = sessionId; }
|
||||
|
||||
public LocalDateTime getDateHeure() { return dateHeure; }
|
||||
public void setDateHeure(LocalDateTime dateHeure) { this.dateHeure = dateHeure; }
|
||||
|
||||
public String getDonneesAvant() { return donneesAvant; }
|
||||
public void setDonneesAvant(String donneesAvant) { this.donneesAvant = donneesAvant; }
|
||||
|
||||
public String getDonneesApres() { return donneesApres; }
|
||||
public void setDonneesApres(String donneesApres) { this.donneesApres = donneesApres; }
|
||||
|
||||
public String getEntiteId() { return entiteId; }
|
||||
public void setEntiteId(String entiteId) { this.entiteId = entiteId; }
|
||||
|
||||
public String getEntiteType() { return entiteType; }
|
||||
public void setEntiteType(String entiteType) { this.entiteType = entiteType; }
|
||||
|
||||
// Méthodes utilitaires pour l'affichage
|
||||
|
||||
public String getDateFormatee() {
|
||||
if (dateHeure == null) return "";
|
||||
return dateHeure.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
public String getHeureFormatee() {
|
||||
if (dateHeure == null) return "";
|
||||
return dateHeure.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
|
||||
}
|
||||
|
||||
public String getDateHeureComplete() {
|
||||
if (dateHeure == null) return "";
|
||||
return dateHeure.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
|
||||
}
|
||||
|
||||
public String getSeveriteLibelle() {
|
||||
if (severite == null) return "";
|
||||
return switch (severite) {
|
||||
case "SUCCESS" -> "Succès";
|
||||
case "INFO" -> "Info";
|
||||
case "WARNING" -> "Attention";
|
||||
case "ERROR" -> "Erreur";
|
||||
case "CRITICAL" -> "Critique";
|
||||
default -> severite;
|
||||
};
|
||||
}
|
||||
|
||||
public String getSeveriteSeverity() {
|
||||
if (severite == null) return "secondary";
|
||||
return switch (severite) {
|
||||
case "SUCCESS" -> "success";
|
||||
case "INFO" -> "info";
|
||||
case "WARNING" -> "warning";
|
||||
case "ERROR", "CRITICAL" -> "danger";
|
||||
default -> "secondary";
|
||||
};
|
||||
}
|
||||
|
||||
public String getSeveriteIcon() {
|
||||
if (severite == null) return "pi pi-circle";
|
||||
return switch (severite) {
|
||||
case "SUCCESS" -> "pi pi-check";
|
||||
case "INFO" -> "pi pi-info";
|
||||
case "WARNING" -> "pi pi-exclamation-triangle";
|
||||
case "ERROR" -> "pi pi-times";
|
||||
case "CRITICAL" -> "pi pi-ban";
|
||||
default -> "pi pi-circle";
|
||||
};
|
||||
}
|
||||
|
||||
public String getActionIcon() {
|
||||
if (typeAction == null) return "pi pi-circle";
|
||||
return switch (typeAction) {
|
||||
case "CONNEXION" -> "pi pi-sign-in";
|
||||
case "DECONNEXION" -> "pi pi-sign-out";
|
||||
case "CREATION" -> "pi pi-plus";
|
||||
case "MODIFICATION" -> "pi pi-pencil";
|
||||
case "SUPPRESSION" -> "pi pi-trash";
|
||||
case "CONSULTATION" -> "pi pi-eye";
|
||||
case "EXPORT" -> "pi pi-download";
|
||||
case "CONFIGURATION" -> "pi pi-cog";
|
||||
default -> "pi pi-circle";
|
||||
};
|
||||
}
|
||||
|
||||
public String getActionLibelle() {
|
||||
if (typeAction == null) return "";
|
||||
return switch (typeAction) {
|
||||
case "CONNEXION" -> "Connexion";
|
||||
case "DECONNEXION" -> "Déconnexion";
|
||||
case "CREATION" -> "Création";
|
||||
case "MODIFICATION" -> "Modification";
|
||||
case "SUPPRESSION" -> "Suppression";
|
||||
case "CONSULTATION" -> "Consultation";
|
||||
case "EXPORT" -> "Export";
|
||||
case "CONFIGURATION" -> "Configuration";
|
||||
default -> typeAction;
|
||||
};
|
||||
}
|
||||
|
||||
public String getModuleLibelle() {
|
||||
if (module == null) return "";
|
||||
return switch (module) {
|
||||
case "AUTH" -> "Authentification";
|
||||
case "MEMBRES" -> "Membres";
|
||||
case "COTISATIONS" -> "Cotisations";
|
||||
case "EVENTS" -> "Événements";
|
||||
case "DOCUMENTS" -> "Documents";
|
||||
case "CONFIG" -> "Configuration";
|
||||
case "RAPPORTS" -> "Rapports";
|
||||
default -> module;
|
||||
};
|
||||
}
|
||||
|
||||
public String getUserAgentCourt() {
|
||||
if (userAgent == null || userAgent.isEmpty()) return "";
|
||||
return userAgent.length() > 50 ? userAgent.substring(0, 50) + "..." : userAgent;
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,17 @@ import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DTO pour la gestion des cotisations côté client
|
||||
* Correspond au CotisationDTO du backend avec méthodes utilitaires pour l'affichage
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
public class CotisationDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -27,8 +36,10 @@ public class CotisationDTO implements Serializable {
|
||||
private LocalDate dateEcheance;
|
||||
private LocalDateTime datePaiement;
|
||||
private String methodePaiement;
|
||||
private String referencePaiement;
|
||||
private String observations;
|
||||
private LocalDateTime dateCreation;
|
||||
private String waveSessionId;
|
||||
|
||||
// Getters et Setters
|
||||
public UUID getId() { return id; }
|
||||
@@ -64,7 +75,7 @@ public class CotisationDTO implements Serializable {
|
||||
public BigDecimal getMontantDu() { return montantDu; }
|
||||
public void setMontantDu(BigDecimal montantDu) { this.montantDu = montantDu; }
|
||||
|
||||
public BigDecimal getMontantPaye() { return montantPaye; }
|
||||
public BigDecimal getMontantPaye() { return montantPaye != null ? montantPaye : BigDecimal.ZERO; }
|
||||
public void setMontantPaye(BigDecimal montantPaye) { this.montantPaye = montantPaye; }
|
||||
|
||||
public String getCodeDevise() { return codeDevise; }
|
||||
@@ -82,10 +93,178 @@ public class CotisationDTO implements Serializable {
|
||||
public String getMethodePaiement() { return methodePaiement; }
|
||||
public void setMethodePaiement(String methodePaiement) { this.methodePaiement = methodePaiement; }
|
||||
|
||||
public String getReferencePaiement() { return referencePaiement; }
|
||||
public void setReferencePaiement(String referencePaiement) { this.referencePaiement = referencePaiement; }
|
||||
|
||||
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; }
|
||||
|
||||
public String getWaveSessionId() { return waveSessionId; }
|
||||
public void setWaveSessionId(String waveSessionId) { this.waveSessionId = waveSessionId; }
|
||||
|
||||
// Méthodes utilitaires pour l'affichage (alignées avec le backend)
|
||||
|
||||
/**
|
||||
* Vérifie si la cotisation est payée intégralement
|
||||
*/
|
||||
public boolean isPayeeIntegralement() {
|
||||
return montantPaye != null && montantDu != null && montantPaye.compareTo(montantDu) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la cotisation est en retard
|
||||
*/
|
||||
public boolean isEnRetard() {
|
||||
return dateEcheance != null && LocalDate.now().isAfter(dateEcheance) && !isPayeeIntegralement();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le montant restant à payer
|
||||
*/
|
||||
public BigDecimal getMontantRestant() {
|
||||
if (montantDu == null) return BigDecimal.ZERO;
|
||||
if (montantPaye == null) return montantDu;
|
||||
BigDecimal restant = montantDu.subtract(montantPaye);
|
||||
return restant.compareTo(BigDecimal.ZERO) > 0 ? restant : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le pourcentage de paiement
|
||||
*/
|
||||
public int getPourcentagePaiement() {
|
||||
if (montantDu == null || montantDu.compareTo(BigDecimal.ZERO) == 0) return 0;
|
||||
if (montantPaye == null) return 0;
|
||||
return montantPaye.multiply(BigDecimal.valueOf(100))
|
||||
.divide(montantDu, 0, java.math.RoundingMode.HALF_UP)
|
||||
.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le nombre de jours de retard
|
||||
*/
|
||||
public long getJoursRetard() {
|
||||
if (dateEcheance == null || !isEnRetard()) return 0;
|
||||
return ChronoUnit.DAYS.between(dateEcheance, LocalDate.now());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé du type de cotisation
|
||||
*/
|
||||
public String getTypeCotisationLibelle() {
|
||||
if (typeCotisation == null) return "Non défini";
|
||||
return switch (typeCotisation) {
|
||||
case "MENSUELLE" -> "Mensuelle";
|
||||
case "TRIMESTRIELLE" -> "Trimestrielle";
|
||||
case "SEMESTRIELLE" -> "Semestrielle";
|
||||
case "ANNUELLE" -> "Annuelle";
|
||||
case "EXCEPTIONNELLE" -> "Exceptionnelle";
|
||||
case "ADHESION" -> "Adhésion";
|
||||
default -> typeCotisation;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé du statut
|
||||
*/
|
||||
public String getStatutLibelle() {
|
||||
if (statut == null) return "Non défini";
|
||||
return switch (statut) {
|
||||
case "EN_ATTENTE" -> "En attente";
|
||||
case "PAYEE" -> "Payée";
|
||||
case "PARTIELLEMENT_PAYEE" -> "Partiellement payée";
|
||||
case "EN_RETARD" -> "En retard";
|
||||
case "ANNULEE" -> "Annulée";
|
||||
case "REMBOURSEE" -> "Remboursée";
|
||||
default -> statut;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé de la méthode de paiement
|
||||
*/
|
||||
public String getMethodePaiementLibelle() {
|
||||
if (methodePaiement == null) return "Non défini";
|
||||
return switch (methodePaiement) {
|
||||
case "ESPECES" -> "Espèces";
|
||||
case "VIREMENT" -> "Virement bancaire";
|
||||
case "CHEQUE" -> "Chèque";
|
||||
case "WAVE_MONEY" -> "Wave Money";
|
||||
case "ORANGE_MONEY" -> "Orange Money";
|
||||
case "FREE_MONEY" -> "Free Money";
|
||||
case "CARTE_BANCAIRE" -> "Carte bancaire";
|
||||
default -> methodePaiement;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la sévérité du statut pour PrimeFaces
|
||||
*/
|
||||
public String getStatutSeverity() {
|
||||
if (statut == null) return "secondary";
|
||||
return switch (statut) {
|
||||
case "PAYEE" -> "success";
|
||||
case "EN_ATTENTE" -> "warning";
|
||||
case "EN_RETARD" -> "danger";
|
||||
case "PARTIELLEMENT_PAYEE" -> "info";
|
||||
case "ANNULEE", "REMBOURSEE" -> "secondary";
|
||||
default -> "secondary";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône du statut pour PrimeFaces
|
||||
*/
|
||||
public String getStatutIcon() {
|
||||
if (statut == null) return "pi-circle";
|
||||
return switch (statut) {
|
||||
case "PAYEE" -> "pi-check";
|
||||
case "EN_ATTENTE" -> "pi-clock";
|
||||
case "EN_RETARD" -> "pi-exclamation-triangle";
|
||||
case "PARTIELLEMENT_PAYEE" -> "pi-minus";
|
||||
default -> "pi-circle";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la date d'échéance
|
||||
*/
|
||||
public String getDateEcheanceFormatee() {
|
||||
if (dateEcheance == null) return "";
|
||||
return dateEcheance.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la date de paiement
|
||||
*/
|
||||
public String getDatePaiementFormatee() {
|
||||
if (datePaiement == null) return "";
|
||||
return datePaiement.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate le montant dû
|
||||
*/
|
||||
public String getMontantDuFormatte() {
|
||||
if (montantDu == null) return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", montantDu.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate le montant payé
|
||||
*/
|
||||
public String getMontantPayeFormatte() {
|
||||
if (montantPaye == null) return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", montantPaye.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate le montant restant
|
||||
*/
|
||||
public String getMontantRestantFormatte() {
|
||||
return String.format("%,.0f FCFA", getMontantRestant().doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,31 +5,82 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DTO pour la gestion des événements côté client
|
||||
* Correspond au EvenementDTO du backend avec méthodes utilitaires pour l'affichage
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 2.0
|
||||
*/
|
||||
public class EvenementDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// Propriétés de base
|
||||
private UUID id;
|
||||
private String titre;
|
||||
private String description;
|
||||
private String type;
|
||||
private String statut;
|
||||
private String priorite;
|
||||
private String typeEvenement; // ASSEMBLEE_GENERALE, FORMATION, etc.
|
||||
private String statut; // PLANIFIE, CONFIRME, EN_COURS, TERMINE, ANNULE, REPORTE
|
||||
private String priorite; // CRITIQUE, HAUTE, NORMALE, BASSE
|
||||
|
||||
// Dates et heures
|
||||
private LocalDate dateDebut;
|
||||
private LocalDate dateFin;
|
||||
private LocalTime heureDebut;
|
||||
private LocalTime heureFin;
|
||||
private LocalDate dateLimiteInscription;
|
||||
|
||||
// Localisation
|
||||
private String lieu;
|
||||
private String adresse;
|
||||
private String ville;
|
||||
private String region;
|
||||
private BigDecimal latitude;
|
||||
private BigDecimal longitude;
|
||||
|
||||
// Organisation
|
||||
private UUID associationId;
|
||||
private String nomAssociation;
|
||||
private String organisateur;
|
||||
private String organisateurEmail;
|
||||
private String emailOrganisateur;
|
||||
private String telephoneOrganisateur;
|
||||
|
||||
// Participants
|
||||
private Integer capaciteMax;
|
||||
private Integer participantsInscrits;
|
||||
private Integer participantsPresents;
|
||||
|
||||
// Budget
|
||||
private BigDecimal budget;
|
||||
private UUID organisationId;
|
||||
private BigDecimal coutReel;
|
||||
private String codeDevise;
|
||||
|
||||
// Options
|
||||
private Boolean inscriptionObligatoire;
|
||||
private Boolean evenementPublic;
|
||||
private Boolean recurrent;
|
||||
private String frequenceRecurrence;
|
||||
|
||||
// Informations complémentaires
|
||||
private String instructions;
|
||||
private String materielNecessaire;
|
||||
private String conditionsMeteo;
|
||||
private String imageUrl;
|
||||
private String couleurTheme;
|
||||
|
||||
// Annulation
|
||||
private LocalDateTime dateAnnulation;
|
||||
private String raisonAnnulation;
|
||||
private String nomAnnulateur;
|
||||
|
||||
// Métadonnées
|
||||
private LocalDateTime dateCreation;
|
||||
private LocalDateTime dateModification;
|
||||
|
||||
// Getters et Setters
|
||||
public UUID getId() { return id; }
|
||||
@@ -41,8 +92,8 @@ public class EvenementDTO implements Serializable {
|
||||
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 getTypeEvenement() { return typeEvenement; }
|
||||
public void setTypeEvenement(String typeEvenement) { this.typeEvenement = typeEvenement; }
|
||||
|
||||
public String getStatut() { return statut; }
|
||||
public void setStatut(String statut) { this.statut = statut; }
|
||||
@@ -62,31 +113,380 @@ public class EvenementDTO implements Serializable {
|
||||
public LocalTime getHeureFin() { return heureFin; }
|
||||
public void setHeureFin(LocalTime heureFin) { this.heureFin = heureFin; }
|
||||
|
||||
public LocalDate getDateLimiteInscription() { return dateLimiteInscription; }
|
||||
public void setDateLimiteInscription(LocalDate dateLimiteInscription) { this.dateLimiteInscription = dateLimiteInscription; }
|
||||
|
||||
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 getVille() { return ville; }
|
||||
public void setVille(String ville) { this.ville = ville; }
|
||||
|
||||
public String getRegion() { return region; }
|
||||
public void setRegion(String region) { this.region = region; }
|
||||
|
||||
public BigDecimal getLatitude() { return latitude; }
|
||||
public void setLatitude(BigDecimal latitude) { this.latitude = latitude; }
|
||||
|
||||
public BigDecimal getLongitude() { return longitude; }
|
||||
public void setLongitude(BigDecimal longitude) { this.longitude = longitude; }
|
||||
|
||||
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 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 String getEmailOrganisateur() { return emailOrganisateur; }
|
||||
public void setEmailOrganisateur(String emailOrganisateur) { this.emailOrganisateur = emailOrganisateur; }
|
||||
|
||||
public String getTelephoneOrganisateur() { return telephoneOrganisateur; }
|
||||
public void setTelephoneOrganisateur(String telephoneOrganisateur) { this.telephoneOrganisateur = telephoneOrganisateur; }
|
||||
|
||||
public Integer getCapaciteMax() { return capaciteMax; }
|
||||
public void setCapaciteMax(Integer capaciteMax) { this.capaciteMax = capaciteMax; }
|
||||
|
||||
public Integer getParticipantsInscrits() { return participantsInscrits; }
|
||||
public Integer getParticipantsInscrits() { return participantsInscrits != null ? participantsInscrits : 0; }
|
||||
public void setParticipantsInscrits(Integer participantsInscrits) { this.participantsInscrits = participantsInscrits; }
|
||||
|
||||
public Integer getParticipantsPresents() { return participantsPresents != null ? participantsPresents : 0; }
|
||||
public void setParticipantsPresents(Integer participantsPresents) { this.participantsPresents = participantsPresents; }
|
||||
|
||||
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 BigDecimal getCoutReel() { return coutReel; }
|
||||
public void setCoutReel(BigDecimal coutReel) { this.coutReel = coutReel; }
|
||||
|
||||
public String getCodeDevise() { return codeDevise != null ? codeDevise : "XOF"; }
|
||||
public void setCodeDevise(String codeDevise) { this.codeDevise = codeDevise; }
|
||||
|
||||
public Boolean getInscriptionObligatoire() { return inscriptionObligatoire != null ? inscriptionObligatoire : false; }
|
||||
public void setInscriptionObligatoire(Boolean inscriptionObligatoire) { this.inscriptionObligatoire = inscriptionObligatoire; }
|
||||
|
||||
public Boolean getEvenementPublic() { return evenementPublic != null ? evenementPublic : true; }
|
||||
public void setEvenementPublic(Boolean evenementPublic) { this.evenementPublic = evenementPublic; }
|
||||
|
||||
public Boolean getRecurrent() { return recurrent != null ? recurrent : false; }
|
||||
public void setRecurrent(Boolean recurrent) { this.recurrent = recurrent; }
|
||||
|
||||
public String getFrequenceRecurrence() { return frequenceRecurrence; }
|
||||
public void setFrequenceRecurrence(String frequenceRecurrence) { this.frequenceRecurrence = frequenceRecurrence; }
|
||||
|
||||
public String getInstructions() { return instructions; }
|
||||
public void setInstructions(String instructions) { this.instructions = instructions; }
|
||||
|
||||
public String getMaterielNecessaire() { return materielNecessaire; }
|
||||
public void setMaterielNecessaire(String materielNecessaire) { this.materielNecessaire = materielNecessaire; }
|
||||
|
||||
public String getConditionsMeteo() { return conditionsMeteo; }
|
||||
public void setConditionsMeteo(String conditionsMeteo) { this.conditionsMeteo = conditionsMeteo; }
|
||||
|
||||
public String getImageUrl() { return imageUrl; }
|
||||
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
|
||||
|
||||
public String getCouleurTheme() { return couleurTheme; }
|
||||
public void setCouleurTheme(String couleurTheme) { this.couleurTheme = couleurTheme; }
|
||||
|
||||
public LocalDateTime getDateAnnulation() { return dateAnnulation; }
|
||||
public void setDateAnnulation(LocalDateTime dateAnnulation) { this.dateAnnulation = dateAnnulation; }
|
||||
|
||||
public String getRaisonAnnulation() { return raisonAnnulation; }
|
||||
public void setRaisonAnnulation(String raisonAnnulation) { this.raisonAnnulation = raisonAnnulation; }
|
||||
|
||||
public String getNomAnnulateur() { return nomAnnulateur; }
|
||||
public void setNomAnnulateur(String nomAnnulateur) { this.nomAnnulateur = nomAnnulateur; }
|
||||
|
||||
public LocalDateTime getDateCreation() { return dateCreation; }
|
||||
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
|
||||
|
||||
public LocalDateTime getDateModification() { return dateModification; }
|
||||
public void setDateModification(LocalDateTime dateModification) { this.dateModification = dateModification; }
|
||||
|
||||
// Méthodes utilitaires pour l'affichage
|
||||
|
||||
/**
|
||||
* Retourne le libellé du type d'événement
|
||||
*/
|
||||
public String getTypeEvenementLibelle() {
|
||||
if (typeEvenement == null) return "Non défini";
|
||||
return switch (typeEvenement) {
|
||||
case "ASSEMBLEE_GENERALE" -> "Assemblée Générale";
|
||||
case "FORMATION" -> "Formation";
|
||||
case "ACTIVITE_SOCIALE" -> "Activité Sociale";
|
||||
case "ACTION_CARITATIVE" -> "Action Caritative";
|
||||
case "REUNION_BUREAU" -> "Réunion de Bureau";
|
||||
case "CONFERENCE" -> "Conférence";
|
||||
case "ATELIER" -> "Atelier";
|
||||
case "CEREMONIE" -> "Cérémonie";
|
||||
case "AUTRE" -> "Autre";
|
||||
default -> typeEvenement;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la sévérité PrimeFaces pour le type
|
||||
*/
|
||||
public String getTypeEvenementSeverity() {
|
||||
if (typeEvenement == null) return "info";
|
||||
return switch (typeEvenement) {
|
||||
case "ASSEMBLEE_GENERALE" -> "danger";
|
||||
case "REUNION_BUREAU" -> "warning";
|
||||
case "FORMATION" -> "success";
|
||||
case "ACTION_CARITATIVE" -> "info";
|
||||
case "ACTIVITE_SOCIALE" -> "secondary";
|
||||
default -> "primary";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône PrimeFaces pour le type
|
||||
*/
|
||||
public String getTypeEvenementIcon() {
|
||||
if (typeEvenement == null) return "pi-calendar";
|
||||
return switch (typeEvenement) {
|
||||
case "ASSEMBLEE_GENERALE" -> "pi-sitemap";
|
||||
case "REUNION_BUREAU" -> "pi-users";
|
||||
case "FORMATION" -> "pi-book";
|
||||
case "ACTION_CARITATIVE", "ACTIVITE_SOCIALE" -> "pi-heart";
|
||||
case "CONFERENCE" -> "pi-microphone";
|
||||
case "ATELIER" -> "pi-wrench";
|
||||
case "CEREMONIE" -> "pi-star";
|
||||
default -> "pi-calendar";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé du statut
|
||||
*/
|
||||
public String getStatutLibelle() {
|
||||
if (statut == null) return "Non défini";
|
||||
return switch (statut) {
|
||||
case "PLANIFIE" -> "Planifié";
|
||||
case "CONFIRME" -> "Confirmé";
|
||||
case "EN_COURS" -> "En cours";
|
||||
case "TERMINE" -> "Terminé";
|
||||
case "ANNULE" -> "Annulé";
|
||||
case "REPORTE" -> "Reporté";
|
||||
default -> statut;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la sévérité PrimeFaces pour le statut
|
||||
*/
|
||||
public String getStatutSeverity() {
|
||||
if (statut == null) return "info";
|
||||
return switch (statut) {
|
||||
case "PLANIFIE" -> "info";
|
||||
case "CONFIRME" -> "success";
|
||||
case "EN_COURS" -> "warning";
|
||||
case "TERMINE" -> "success";
|
||||
case "ANNULE" -> "error";
|
||||
case "REPORTE" -> "warn";
|
||||
default -> "info";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'icône PrimeFaces pour le statut
|
||||
*/
|
||||
public String getStatutIcon() {
|
||||
if (statut == null) return "pi-circle";
|
||||
return switch (statut) {
|
||||
case "PLANIFIE" -> "pi-clock";
|
||||
case "CONFIRME" -> "pi-check-circle";
|
||||
case "EN_COURS" -> "pi-play";
|
||||
case "TERMINE" -> "pi-check";
|
||||
case "ANNULE" -> "pi-ban";
|
||||
case "REPORTE" -> "pi-calendar-times";
|
||||
default -> "pi-circle";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé de la priorité
|
||||
*/
|
||||
public String getPrioriteLibelle() {
|
||||
if (priorite == null) return "Normale";
|
||||
return switch (priorite) {
|
||||
case "CRITIQUE" -> "Critique";
|
||||
case "HAUTE" -> "Haute";
|
||||
case "NORMALE" -> "Normale";
|
||||
case "BASSE" -> "Basse";
|
||||
default -> priorite;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la sévérité PrimeFaces pour la priorité
|
||||
*/
|
||||
public String getPrioriteSeverity() {
|
||||
if (priorite == null) return "info";
|
||||
return switch (priorite) {
|
||||
case "CRITIQUE" -> "error";
|
||||
case "HAUTE" -> "warning";
|
||||
case "NORMALE" -> "info";
|
||||
case "BASSE" -> "secondary";
|
||||
default -> "info";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la date de début
|
||||
*/
|
||||
public String getDateDebutFormatee() {
|
||||
if (dateDebut == null) return "";
|
||||
return dateDebut.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate la date de fin
|
||||
*/
|
||||
public String getDateFinFormatee() {
|
||||
if (dateFin == null) return "";
|
||||
return dateFin.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate l'heure de début
|
||||
*/
|
||||
public String getHeureDebutFormatee() {
|
||||
if (heureDebut == null) return "";
|
||||
return heureDebut.format(DateTimeFormatter.ofPattern("HH:mm"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate l'heure de fin
|
||||
*/
|
||||
public String getHeureFinFormatee() {
|
||||
if (heureFin == null) return "";
|
||||
return heureFin.format(DateTimeFormatter.ofPattern("HH:mm"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate le budget
|
||||
*/
|
||||
public String getBudgetFormate() {
|
||||
if (budget == null) return "0 FCFA";
|
||||
return String.format("%,.0f %s", budget.doubleValue(), getCodeDevise());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le nombre de places disponibles
|
||||
*/
|
||||
public int getPlacesDisponibles() {
|
||||
if (capaciteMax == null || capaciteMax == 0) return 0;
|
||||
int inscrits = getParticipantsInscrits();
|
||||
return Math.max(0, capaciteMax - inscrits);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le taux de remplissage en pourcentage
|
||||
*/
|
||||
public int getTauxRemplissage() {
|
||||
if (capaciteMax == null || capaciteMax == 0) return 0;
|
||||
int inscrits = getParticipantsInscrits();
|
||||
return (inscrits * 100) / capaciteMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le taux de présence en pourcentage
|
||||
*/
|
||||
public int getTauxPresence() {
|
||||
int inscrits = getParticipantsInscrits();
|
||||
if (inscrits == 0) return 0;
|
||||
int presents = getParticipantsPresents();
|
||||
return (presents * 100) / inscrits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule le nombre de jours restants avant l'événement
|
||||
*/
|
||||
public long getJoursRestants() {
|
||||
if (dateDebut == null) return 0;
|
||||
return ChronoUnit.DAYS.between(LocalDate.now(), dateDebut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'événement est complet
|
||||
*/
|
||||
public boolean isComplet() {
|
||||
if (capaciteMax == null || capaciteMax == 0) return false;
|
||||
return getParticipantsInscrits() >= capaciteMax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'événement est en cours
|
||||
*/
|
||||
public boolean isEnCours() {
|
||||
return "EN_COURS".equals(statut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'événement est terminé
|
||||
*/
|
||||
public boolean isTermine() {
|
||||
return "TERMINE".equals(statut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'événement est annulé
|
||||
*/
|
||||
public boolean isAnnule() {
|
||||
return "ANNULE".equals(statut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si les inscriptions sont ouvertes
|
||||
*/
|
||||
public boolean sontInscriptionsOuvertes() {
|
||||
if (isAnnule() || isTermine()) return false;
|
||||
if (dateLimiteInscription != null && LocalDate.now().isAfter(dateLimiteInscription)) return false;
|
||||
return !isComplet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'adresse complète formatée
|
||||
*/
|
||||
public String getAdresseComplete() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (lieu != null && !lieu.trim().isEmpty()) {
|
||||
sb.append(lieu);
|
||||
}
|
||||
if (adresse != null && !adresse.trim().isEmpty()) {
|
||||
if (sb.length() > 0) sb.append(", ");
|
||||
sb.append(adresse);
|
||||
}
|
||||
if (ville != null && !ville.trim().isEmpty()) {
|
||||
if (sb.length() > 0) sb.append(", ");
|
||||
sb.append(ville);
|
||||
}
|
||||
if (region != null && !region.trim().isEmpty()) {
|
||||
if (sb.length() > 0) sb.append(", ");
|
||||
sb.append(region);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule la durée en heures
|
||||
*/
|
||||
public long getDureeEnHeures() {
|
||||
if (heureDebut == null || heureFin == null) return 0;
|
||||
return ChronoUnit.HOURS.between(heureDebut, heureFin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si l'événement dure plusieurs jours
|
||||
*/
|
||||
public boolean isEvenementMultiJours() {
|
||||
return dateFin != null && dateDebut != null && !dateDebut.equals(dateFin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package dev.lions.unionflow.client.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DTO client pour le catalogue des types d'organisation.
|
||||
*
|
||||
* <p>Correspond au TypeOrganisationDTO du module server-api, mais sans dépendance directe.
|
||||
*/
|
||||
public class TypeOrganisationClientDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private UUID id;
|
||||
private String code;
|
||||
private String libelle;
|
||||
private String description;
|
||||
private Integer ordreAffichage;
|
||||
private Boolean actif;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateCreation;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime dateModification;
|
||||
private Long version;
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
public String getCode() { return code; }
|
||||
public void setCode(String code) { this.code = code; }
|
||||
|
||||
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 Integer getOrdreAffichage() { return ordreAffichage; }
|
||||
public void setOrdreAffichage(Integer ordreAffichage) { this.ordreAffichage = ordreAffichage; }
|
||||
|
||||
public Boolean getActif() { return actif; }
|
||||
public void setActif(Boolean actif) { this.actif = actif; }
|
||||
|
||||
public LocalDateTime getDateCreation() { return dateCreation; }
|
||||
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
|
||||
|
||||
public LocalDateTime getDateModification() { return dateModification; }
|
||||
public void setDateModification(LocalDateTime dateModification) { this.dateModification = dateModification; }
|
||||
|
||||
public Long getVersion() { return version; }
|
||||
public void setVersion(Long version) { this.version = version; }
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package dev.lions.unionflow.client.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* DTO client pour le solde Wave Money
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-17
|
||||
*/
|
||||
public class WaveBalanceDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private BigDecimal soldeDisponible;
|
||||
private BigDecimal soldeEnAttente;
|
||||
private BigDecimal soldeTotal;
|
||||
private String devise;
|
||||
private String numeroWallet;
|
||||
private String nomBusiness;
|
||||
private LocalDateTime dateDerniereMiseAJour;
|
||||
private LocalDateTime dateDerniereSynchronisation;
|
||||
private String statutWallet;
|
||||
private BigDecimal limiteQuotidienne;
|
||||
private BigDecimal montantUtiliseAujourdhui;
|
||||
private BigDecimal limiteMensuelle;
|
||||
private BigDecimal montantUtiliseCeMois;
|
||||
private Integer nombreTransactionsAujourdhui;
|
||||
private Integer nombreTransactionsCeMois;
|
||||
|
||||
// Getters et Setters
|
||||
public BigDecimal getSoldeDisponible() { return soldeDisponible; }
|
||||
public void setSoldeDisponible(BigDecimal soldeDisponible) { this.soldeDisponible = soldeDisponible; }
|
||||
|
||||
public BigDecimal getSoldeEnAttente() { return soldeEnAttente; }
|
||||
public void setSoldeEnAttente(BigDecimal soldeEnAttente) { this.soldeEnAttente = soldeEnAttente; }
|
||||
|
||||
public BigDecimal getSoldeTotal() { return soldeTotal; }
|
||||
public void setSoldeTotal(BigDecimal soldeTotal) { this.soldeTotal = soldeTotal; }
|
||||
|
||||
public String getDevise() { return devise; }
|
||||
public void setDevise(String devise) { this.devise = devise; }
|
||||
|
||||
public String getNumeroWallet() { return numeroWallet; }
|
||||
public void setNumeroWallet(String numeroWallet) { this.numeroWallet = numeroWallet; }
|
||||
|
||||
public String getNomBusiness() { return nomBusiness; }
|
||||
public void setNomBusiness(String nomBusiness) { this.nomBusiness = nomBusiness; }
|
||||
|
||||
public LocalDateTime getDateDerniereMiseAJour() { return dateDerniereMiseAJour; }
|
||||
public void setDateDerniereMiseAJour(LocalDateTime dateDerniereMiseAJour) { this.dateDerniereMiseAJour = dateDerniereMiseAJour; }
|
||||
|
||||
public LocalDateTime getDateDerniereSynchronisation() { return dateDerniereSynchronisation; }
|
||||
public void setDateDerniereSynchronisation(LocalDateTime dateDerniereSynchronisation) { this.dateDerniereSynchronisation = dateDerniereSynchronisation; }
|
||||
|
||||
public String getStatutWallet() { return statutWallet; }
|
||||
public void setStatutWallet(String statutWallet) { this.statutWallet = statutWallet; }
|
||||
|
||||
public BigDecimal getLimiteQuotidienne() { return limiteQuotidienne; }
|
||||
public void setLimiteQuotidienne(BigDecimal limiteQuotidienne) { this.limiteQuotidienne = limiteQuotidienne; }
|
||||
|
||||
public BigDecimal getMontantUtiliseAujourdhui() { return montantUtiliseAujourdhui; }
|
||||
public void setMontantUtiliseAujourdhui(BigDecimal montantUtiliseAujourdhui) { this.montantUtiliseAujourdhui = montantUtiliseAujourdhui; }
|
||||
|
||||
public BigDecimal getLimiteMensuelle() { return limiteMensuelle; }
|
||||
public void setLimiteMensuelle(BigDecimal limiteMensuelle) { this.limiteMensuelle = limiteMensuelle; }
|
||||
|
||||
public BigDecimal getMontantUtiliseCeMois() { return montantUtiliseCeMois; }
|
||||
public void setMontantUtiliseCeMois(BigDecimal montantUtiliseCeMois) { this.montantUtiliseCeMois = montantUtiliseCeMois; }
|
||||
|
||||
public Integer getNombreTransactionsAujourdhui() { return nombreTransactionsAujourdhui; }
|
||||
public void setNombreTransactionsAujourdhui(Integer nombreTransactionsAujourdhui) { this.nombreTransactionsAujourdhui = nombreTransactionsAujourdhui; }
|
||||
|
||||
public Integer getNombreTransactionsCeMois() { return nombreTransactionsCeMois; }
|
||||
public void setNombreTransactionsCeMois(Integer nombreTransactionsCeMois) { this.nombreTransactionsCeMois = nombreTransactionsCeMois; }
|
||||
|
||||
/**
|
||||
* Formate le solde disponible pour l'affichage
|
||||
*/
|
||||
public String getSoldeDisponibleFormate() {
|
||||
if (soldeDisponible == null) return "0 FCFA";
|
||||
return String.format("%.0f FCFA", soldeDisponible.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Formate le solde total pour l'affichage
|
||||
*/
|
||||
public String getSoldeTotalFormate() {
|
||||
if (soldeTotal == null) return "0 FCFA";
|
||||
return String.format("%.0f FCFA", soldeTotal.doubleValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si le wallet est actif
|
||||
*/
|
||||
public boolean isWalletActif() {
|
||||
return "ACTIVE".equals(statutWallet);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package dev.lions.unionflow.client.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DTO client pour les sessions de paiement Wave Money
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-17
|
||||
*/
|
||||
public class WaveCheckoutSessionDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private UUID id;
|
||||
private String waveSessionId;
|
||||
private String waveUrl;
|
||||
private BigDecimal montant;
|
||||
private String devise;
|
||||
private String successUrl;
|
||||
private String errorUrl;
|
||||
private String statut;
|
||||
private UUID organisationId;
|
||||
private String nomOrganisation;
|
||||
private UUID membreId;
|
||||
private String nomMembre;
|
||||
private String typePaiement;
|
||||
private String referenceUnionFlow;
|
||||
private String description;
|
||||
private String nomBusinessAffiche;
|
||||
private LocalDateTime dateCreation;
|
||||
private LocalDateTime dateExpiration;
|
||||
private LocalDateTime dateCompletion;
|
||||
private String telephonePayeur;
|
||||
private String emailPayeur;
|
||||
|
||||
// Getters et Setters
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
public String getWaveSessionId() { return waveSessionId; }
|
||||
public void setWaveSessionId(String waveSessionId) { this.waveSessionId = waveSessionId; }
|
||||
|
||||
public String getWaveUrl() { return waveUrl; }
|
||||
public void setWaveUrl(String waveUrl) { this.waveUrl = waveUrl; }
|
||||
|
||||
public BigDecimal getMontant() { return montant; }
|
||||
public void setMontant(BigDecimal montant) { this.montant = montant; }
|
||||
|
||||
public String getDevise() { return devise; }
|
||||
public void setDevise(String devise) { this.devise = devise; }
|
||||
|
||||
public String getSuccessUrl() { return successUrl; }
|
||||
public void setSuccessUrl(String successUrl) { this.successUrl = successUrl; }
|
||||
|
||||
public String getErrorUrl() { return errorUrl; }
|
||||
public void setErrorUrl(String errorUrl) { this.errorUrl = errorUrl; }
|
||||
|
||||
public String getStatut() { return statut; }
|
||||
public void setStatut(String statut) { this.statut = statut; }
|
||||
|
||||
public UUID getOrganisationId() { return organisationId; }
|
||||
public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
|
||||
|
||||
public String getNomOrganisation() { return nomOrganisation; }
|
||||
public void setNomOrganisation(String nomOrganisation) { this.nomOrganisation = nomOrganisation; }
|
||||
|
||||
public UUID getMembreId() { return membreId; }
|
||||
public void setMembreId(UUID membreId) { this.membreId = membreId; }
|
||||
|
||||
public String getNomMembre() { return nomMembre; }
|
||||
public void setNomMembre(String nomMembre) { this.nomMembre = nomMembre; }
|
||||
|
||||
public String getTypePaiement() { return typePaiement; }
|
||||
public void setTypePaiement(String typePaiement) { this.typePaiement = typePaiement; }
|
||||
|
||||
public String getReferenceUnionFlow() { return referenceUnionFlow; }
|
||||
public void setReferenceUnionFlow(String referenceUnionFlow) { this.referenceUnionFlow = referenceUnionFlow; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getNomBusinessAffiche() { return nomBusinessAffiche; }
|
||||
public void setNomBusinessAffiche(String nomBusinessAffiche) { this.nomBusinessAffiche = nomBusinessAffiche; }
|
||||
|
||||
public LocalDateTime getDateCreation() { return dateCreation; }
|
||||
public void setDateCreation(LocalDateTime dateCreation) { this.dateCreation = dateCreation; }
|
||||
|
||||
public LocalDateTime getDateExpiration() { return dateExpiration; }
|
||||
public void setDateExpiration(LocalDateTime dateExpiration) { this.dateExpiration = dateExpiration; }
|
||||
|
||||
public LocalDateTime getDateCompletion() { return dateCompletion; }
|
||||
public void setDateCompletion(LocalDateTime dateCompletion) { this.dateCompletion = dateCompletion; }
|
||||
|
||||
public String getTelephonePayeur() { return telephonePayeur; }
|
||||
public void setTelephonePayeur(String telephonePayeur) { this.telephonePayeur = telephonePayeur; }
|
||||
|
||||
public String getEmailPayeur() { return emailPayeur; }
|
||||
public void setEmailPayeur(String emailPayeur) { this.emailPayeur = emailPayeur; }
|
||||
|
||||
/**
|
||||
* Retourne le libellé du statut
|
||||
*/
|
||||
public String getStatutLibelle() {
|
||||
if (statut == null) return "Inconnu";
|
||||
return switch (statut) {
|
||||
case "PENDING" -> "En attente";
|
||||
case "COMPLETED" -> "Complétée";
|
||||
case "CANCELLED" -> "Annulée";
|
||||
case "EXPIRED" -> "Expirée";
|
||||
case "FAILED" -> "Échouée";
|
||||
default -> statut;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la sévérité PrimeFaces pour le statut
|
||||
*/
|
||||
public String getStatutSeverity() {
|
||||
if (statut == null) return "info";
|
||||
return switch (statut) {
|
||||
case "PENDING" -> "warning";
|
||||
case "COMPLETED" -> "success";
|
||||
case "CANCELLED" -> "info";
|
||||
case "EXPIRED" -> "warn";
|
||||
case "FAILED" -> "error";
|
||||
default -> "info";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la session est expirée
|
||||
*/
|
||||
public boolean isExpiree() {
|
||||
return dateExpiration != null && LocalDateTime.now().isAfter(dateExpiration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si la session est complétée
|
||||
*/
|
||||
public boolean isCompletee() {
|
||||
return "COMPLETED".equals(statut);
|
||||
}
|
||||
}
|
||||
@@ -20,11 +20,21 @@ public class JwtClientRequestFilter implements ClientRequestFilter {
|
||||
|
||||
@Override
|
||||
public void filter(ClientRequestContext requestContext) throws IOException {
|
||||
String authHeader = tokenManager.getAuthorizationHeader();
|
||||
if (tokenManager == null) {
|
||||
LOGGER.fine("JwtTokenManager non disponible, requête sans authentification");
|
||||
return;
|
||||
}
|
||||
|
||||
if (authHeader != null && !isAuthEndpoint(requestContext.getUri().getPath())) {
|
||||
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
|
||||
LOGGER.fine("JWT token ajouté à la requête: " + requestContext.getUri());
|
||||
try {
|
||||
String authHeader = tokenManager.getAuthorizationHeader();
|
||||
|
||||
if (authHeader != null && !isAuthEndpoint(requestContext.getUri().getPath())) {
|
||||
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, authHeader);
|
||||
LOGGER.fine("JWT token ajouté à la requête: " + requestContext.getUri());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Erreur lors de l'ajout du token JWT: " + e.getMessage());
|
||||
// Continuer sans authentification plutôt que de bloquer la requête
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.client.dto.AdhesionDTO;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Service REST client pour la gestion des adhésions
|
||||
* Interface correspondant exactement au backend AdhesionResource
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/adhesions")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface AdhesionService {
|
||||
|
||||
/**
|
||||
* Récupère toutes les adhésions avec pagination
|
||||
*/
|
||||
@GET
|
||||
List<AdhesionDTO> listerToutes(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère une adhésion par son ID
|
||||
*/
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
AdhesionDTO obtenirParId(@PathParam("id") UUID id);
|
||||
|
||||
/**
|
||||
* Récupère une adhésion par son numéro de référence
|
||||
*/
|
||||
@GET
|
||||
@Path("/reference/{numeroReference}")
|
||||
AdhesionDTO obtenirParReference(@PathParam("numeroReference") String numeroReference);
|
||||
|
||||
/**
|
||||
* Crée une nouvelle adhésion
|
||||
*/
|
||||
@POST
|
||||
AdhesionDTO creer(AdhesionDTO adhesion);
|
||||
|
||||
/**
|
||||
* Met à jour une adhésion existante
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
AdhesionDTO modifier(@PathParam("id") UUID id, AdhesionDTO adhesion);
|
||||
|
||||
/**
|
||||
* Supprime une adhésion
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
void supprimer(@PathParam("id") UUID id);
|
||||
|
||||
/**
|
||||
* Approuve une adhésion
|
||||
*/
|
||||
@POST
|
||||
@Path("/{id}/approuver")
|
||||
AdhesionDTO approuver(
|
||||
@PathParam("id") UUID id,
|
||||
@QueryParam("approuvePar") String approuvePar
|
||||
);
|
||||
|
||||
/**
|
||||
* Rejette une adhésion
|
||||
*/
|
||||
@POST
|
||||
@Path("/{id}/rejeter")
|
||||
AdhesionDTO rejeter(
|
||||
@PathParam("id") UUID id,
|
||||
@QueryParam("motifRejet") String motifRejet
|
||||
);
|
||||
|
||||
/**
|
||||
* Enregistre un paiement pour une adhésion
|
||||
*/
|
||||
@POST
|
||||
@Path("/{id}/paiement")
|
||||
AdhesionDTO enregistrerPaiement(
|
||||
@PathParam("id") UUID id,
|
||||
@QueryParam("montantPaye") BigDecimal montantPaye,
|
||||
@QueryParam("methodePaiement") String methodePaiement,
|
||||
@QueryParam("referencePaiement") String referencePaiement
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les adhésions d'un membre
|
||||
*/
|
||||
@GET
|
||||
@Path("/membre/{membreId}")
|
||||
List<AdhesionDTO> obtenirParMembre(
|
||||
@PathParam("membreId") UUID membreId,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les adhésions d'une organisation
|
||||
*/
|
||||
@GET
|
||||
@Path("/organisation/{organisationId}")
|
||||
List<AdhesionDTO> obtenirParOrganisation(
|
||||
@PathParam("organisationId") UUID organisationId,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les adhésions par statut
|
||||
*/
|
||||
@GET
|
||||
@Path("/statut/{statut}")
|
||||
List<AdhesionDTO> obtenirParStatut(
|
||||
@PathParam("statut") String statut,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les adhésions en attente
|
||||
*/
|
||||
@GET
|
||||
@Path("/en-attente")
|
||||
List<AdhesionDTO> obtenirEnAttente(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les statistiques des adhésions
|
||||
*/
|
||||
@GET
|
||||
@Path("/stats")
|
||||
Map<String, Object> obtenirStatistiques();
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.client.dto.AnalyticsDataDTO;
|
||||
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.Map;
|
||||
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@@ -12,39 +14,47 @@ import java.util.Map;
|
||||
public interface AnalyticsService {
|
||||
|
||||
@GET
|
||||
@Path("/dashboard/widgets")
|
||||
Map<String, Object> getDashboardData(
|
||||
@QueryParam("organisationId") String organisationId,
|
||||
@QueryParam("utilisateurId") String utilisateurId
|
||||
@Path("/metriques/{typeMetrique}")
|
||||
AnalyticsDataDTO calculerMetrique(
|
||||
@PathParam("typeMetrique") String typeMetrique,
|
||||
@QueryParam("periode") String periode,
|
||||
@QueryParam("organisationId") String organisationId
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/tendances/{typeMetrique}")
|
||||
Map<String, Object> getEvolutionMensuelle(
|
||||
Map<String, Object> calculerTendanceKPI(
|
||||
@PathParam("typeMetrique") String typeMetrique,
|
||||
@QueryParam("organisationId") String organisationId,
|
||||
@QueryParam("periode") String periode
|
||||
@QueryParam("periode") String periode,
|
||||
@QueryParam("organisationId") String organisationId
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/kpis")
|
||||
Map<String, Object> getKPIs(
|
||||
@QueryParam("organisationId") String organisationId,
|
||||
@QueryParam("periode") String periode
|
||||
Map<String, Object> obtenirTousLesKPI(
|
||||
@QueryParam("periode") String periode,
|
||||
@QueryParam("organisationId") String organisationId
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/evolutions")
|
||||
Map<String, Object> getEvolutions(
|
||||
@QueryParam("organisationId") String organisationId,
|
||||
@QueryParam("periode") String periode
|
||||
Map<String, Object> obtenirEvolutionsKPI(
|
||||
@QueryParam("periode") String periode,
|
||||
@QueryParam("organisationId") String organisationId
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/performance-globale")
|
||||
Map<String, Object> getPerformanceGlobale(
|
||||
Map<String, Object> calculerPerformanceGlobale(
|
||||
@QueryParam("periode") String periode,
|
||||
@QueryParam("organisationId") String organisationId
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/dashboard/widgets")
|
||||
List<Map<String, Object>> obtenirWidgetsTableauBord(
|
||||
@QueryParam("organisationId") String organisationId,
|
||||
@QueryParam("periode") String periode
|
||||
@QueryParam("utilisateurId") String utilisateurId
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,20 +8,23 @@ import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/associations")
|
||||
@Path("/api/organisations")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface AssociationService {
|
||||
|
||||
@GET
|
||||
List<AssociationDTO> listerToutes();
|
||||
List<AssociationDTO> listerToutes(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("1000") int size
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
AssociationDTO obtenirParId(@PathParam("id") UUID id);
|
||||
|
||||
@GET
|
||||
@Path("/search")
|
||||
@Path("/recherche")
|
||||
List<AssociationDTO> rechercher(
|
||||
@QueryParam("nom") String nom,
|
||||
@QueryParam("type") String type,
|
||||
@@ -32,10 +35,6 @@ public interface AssociationService {
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/actives")
|
||||
List<AssociationDTO> listerActives();
|
||||
|
||||
@GET
|
||||
@Path("/type/{type}")
|
||||
List<AssociationDTO> listerParType(@PathParam("type") String type);
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.client.dto.AuditLogDTO;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import java.util.Map;
|
||||
import org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
/**
|
||||
* Service REST client pour la gestion des logs d'audit
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@RegisterRestClient(baseUri = "http://localhost:8085")
|
||||
@RegisterClientHeaders
|
||||
@Path("/api/audit")
|
||||
public interface AuditService {
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Map<String, Object> listerTous(
|
||||
@QueryParam("page") int page,
|
||||
@QueryParam("size") int size,
|
||||
@QueryParam("sortBy") String sortBy,
|
||||
@QueryParam("sortOrder") String sortOrder);
|
||||
|
||||
@POST
|
||||
@Path("/rechercher")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Map<String, Object> rechercher(
|
||||
@QueryParam("dateDebut") String dateDebut,
|
||||
@QueryParam("dateFin") String dateFin,
|
||||
@QueryParam("typeAction") String typeAction,
|
||||
@QueryParam("severite") String severite,
|
||||
@QueryParam("utilisateur") String utilisateur,
|
||||
@QueryParam("module") String module,
|
||||
@QueryParam("ipAddress") String ipAddress,
|
||||
@QueryParam("page") int page,
|
||||
@QueryParam("size") int size);
|
||||
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
AuditLogDTO enregistrerLog(AuditLogDTO dto);
|
||||
|
||||
@GET
|
||||
@Path("/statistiques")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
Map<String, Object> getStatistiques();
|
||||
}
|
||||
|
||||
@@ -5,40 +5,115 @@ 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.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Service REST client pour la gestion des cotisations
|
||||
* Interface correspondant exactement au backend CotisationResource
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/cotisations")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface CotisationService {
|
||||
|
||||
/**
|
||||
* Récupère toutes les cotisations avec pagination
|
||||
*/
|
||||
@GET
|
||||
List<CotisationDTO> listerToutes(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère une cotisation par son ID
|
||||
*/
|
||||
@GET
|
||||
@Path("/{id}")
|
||||
CotisationDTO obtenirParId(@PathParam("id") UUID id);
|
||||
|
||||
/**
|
||||
* Récupère une cotisation par son numéro de référence
|
||||
*/
|
||||
@GET
|
||||
@Path("/search")
|
||||
List<CotisationDTO> rechercher(
|
||||
@QueryParam("membreId") UUID membreId,
|
||||
@QueryParam("statut") String statut,
|
||||
@Path("/reference/{numeroReference}")
|
||||
CotisationDTO obtenirParReference(@PathParam("numeroReference") String numeroReference);
|
||||
|
||||
/**
|
||||
* Récupère les cotisations d'un membre
|
||||
*/
|
||||
@GET
|
||||
@Path("/membre/{membreId}")
|
||||
List<CotisationDTO> obtenirParMembre(
|
||||
@PathParam("membreId") UUID membreId,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les cotisations par statut
|
||||
*/
|
||||
@GET
|
||||
@Path("/statut/{statut}")
|
||||
List<CotisationDTO> obtenirParStatut(
|
||||
@PathParam("statut") String statut,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les cotisations en retard
|
||||
*/
|
||||
@GET
|
||||
@Path("/en-retard")
|
||||
List<CotisationDTO> obtenirEnRetard(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Recherche avancée de cotisations
|
||||
*/
|
||||
@GET
|
||||
@Path("/recherche")
|
||||
List<CotisationDTO> rechercher(
|
||||
@QueryParam("membreId") UUID membreId,
|
||||
@QueryParam("statut") String statut,
|
||||
@QueryParam("typeCotisation") String typeCotisation,
|
||||
@QueryParam("annee") Integer annee,
|
||||
@QueryParam("mois") Integer mois,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère les statistiques des cotisations
|
||||
*/
|
||||
@GET
|
||||
@Path("/stats")
|
||||
Map<String, Object> obtenirStatistiques();
|
||||
|
||||
/**
|
||||
* Crée une nouvelle cotisation
|
||||
*/
|
||||
@POST
|
||||
CotisationDTO creer(CotisationDTO cotisation);
|
||||
|
||||
/**
|
||||
* Met à jour une cotisation existante
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
CotisationDTO modifier(@PathParam("id") UUID id, CotisationDTO cotisation);
|
||||
|
||||
/**
|
||||
* Supprime une cotisation
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
void supprimer(@PathParam("id") UUID id);
|
||||
|
||||
@@ -5,50 +5,132 @@ 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.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Service REST client pour la gestion des événements
|
||||
* Correspond exactement aux endpoints du backend EvenementResource
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 2.0
|
||||
*/
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/evenements")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface EvenementService {
|
||||
|
||||
/**
|
||||
* Liste tous les événements actifs avec pagination
|
||||
*/
|
||||
@GET
|
||||
List<EvenementDTO> listerTous(
|
||||
Map<String, Object> listerTous(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
@QueryParam("size") @DefaultValue("20") int size,
|
||||
@QueryParam("sort") @DefaultValue("dateDebut") String sortField,
|
||||
@QueryParam("direction") @DefaultValue("asc") String sortDirection
|
||||
);
|
||||
|
||||
/**
|
||||
* Récupère un événement par son ID
|
||||
*/
|
||||
@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
|
||||
);
|
||||
|
||||
/**
|
||||
* Crée un nouvel événement
|
||||
*/
|
||||
@POST
|
||||
EvenementDTO creer(EvenementDTO evenement);
|
||||
|
||||
/**
|
||||
* Met à jour un événement existant
|
||||
*/
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
EvenementDTO modifier(@PathParam("id") UUID id, EvenementDTO evenement);
|
||||
|
||||
/**
|
||||
* Supprime un événement
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
void supprimer(@PathParam("id") UUID id);
|
||||
|
||||
/**
|
||||
* Liste les événements à venir
|
||||
*/
|
||||
@GET
|
||||
@Path("/a-venir")
|
||||
Map<String, Object> listerAVenir(
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("10") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Recherche d'événements avec filtres
|
||||
*/
|
||||
@GET
|
||||
@Path("/search")
|
||||
Map<String, Object> rechercher(
|
||||
@QueryParam("titre") String titre,
|
||||
@QueryParam("type") String type,
|
||||
@QueryParam("statut") String statut,
|
||||
@QueryParam("dateDebut") String dateDebut,
|
||||
@QueryParam("dateFin") String dateFin,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Liste les événements par statut
|
||||
*/
|
||||
@GET
|
||||
@Path("/statut/{statut}")
|
||||
Map<String, Object> listerParStatut(
|
||||
@PathParam("statut") String statut,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Liste les événements par association
|
||||
*/
|
||||
@GET
|
||||
@Path("/association/{associationId}")
|
||||
Map<String, Object> listerParAssociation(
|
||||
@PathParam("associationId") UUID associationId,
|
||||
@QueryParam("page") @DefaultValue("0") int page,
|
||||
@QueryParam("size") @DefaultValue("20") int size
|
||||
);
|
||||
|
||||
/**
|
||||
* Compte le nombre d'événements
|
||||
*/
|
||||
@GET
|
||||
@Path("/count")
|
||||
Map<String, Object> compter();
|
||||
|
||||
/**
|
||||
* Inscrit un participant à un événement
|
||||
*/
|
||||
@POST
|
||||
@Path("/{evenementId}/participants/{membreId}")
|
||||
void inscrireParticipant(@PathParam("evenementId") UUID evenementId, @PathParam("membreId") UUID membreId);
|
||||
|
||||
/**
|
||||
* Désinscrit un participant d'un événement
|
||||
*/
|
||||
@DELETE
|
||||
@Path("/{evenementId}/participants/{membreId}")
|
||||
void desinscrireParticipant(@PathParam("evenementId") UUID evenementId, @PathParam("membreId") UUID membreId);
|
||||
|
||||
/**
|
||||
* Liste les participants d'un événement
|
||||
*/
|
||||
@GET
|
||||
@Path("/{evenementId}/participants")
|
||||
List<Map<String, Object>> listerParticipants(@PathParam("evenementId") UUID evenementId);
|
||||
}
|
||||
|
||||
|
||||
@@ -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.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Service REST client pour l'export des données
|
||||
*/
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/export")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public interface ExportClientService {
|
||||
|
||||
@GET
|
||||
@Path("/cotisations/csv")
|
||||
@Produces("text/csv")
|
||||
byte[] exporterCotisationsCSV(
|
||||
@QueryParam("statut") String statut,
|
||||
@QueryParam("type") String type,
|
||||
@QueryParam("associationId") UUID associationId
|
||||
);
|
||||
|
||||
@POST
|
||||
@Path("/cotisations/csv")
|
||||
@Produces("text/csv")
|
||||
byte[] exporterCotisationsSelectionneesCSV(List<UUID> cotisationIds);
|
||||
|
||||
@GET
|
||||
@Path("/cotisations/{cotisationId}/recu")
|
||||
@Produces("text/plain")
|
||||
byte[] genererRecu(@PathParam("cotisationId") UUID cotisationId);
|
||||
|
||||
@POST
|
||||
@Path("/cotisations/recus")
|
||||
@Produces("text/plain")
|
||||
byte[] genererRecusGroupes(List<UUID> cotisationIds);
|
||||
|
||||
@GET
|
||||
@Path("/rapport/mensuel")
|
||||
@Produces("text/plain")
|
||||
byte[] genererRapportMensuel(
|
||||
@QueryParam("annee") int annee,
|
||||
@QueryParam("mois") int mois,
|
||||
@QueryParam("associationId") UUID associationId
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Service REST client pour les notifications
|
||||
*/
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/notifications")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface NotificationClientService {
|
||||
|
||||
@POST
|
||||
@Path("/groupe")
|
||||
List<Map<String, Object>> envoyerNotificationGroupe(
|
||||
@QueryParam("type") String type,
|
||||
@QueryParam("titre") String titre,
|
||||
@QueryParam("message") String message,
|
||||
List<String> destinatairesIds
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/utilisateur/{utilisateurId}")
|
||||
List<Map<String, Object>> obtenirNotifications(
|
||||
@PathParam("utilisateurId") String utilisateurId,
|
||||
@QueryParam("includeArchivees") @DefaultValue("false") boolean includeArchivees,
|
||||
@QueryParam("limite") @DefaultValue("50") int limite
|
||||
);
|
||||
|
||||
@PUT
|
||||
@Path("/{notificationId}/lue")
|
||||
Map<String, Object> marquerCommeLue(
|
||||
@PathParam("notificationId") String notificationId,
|
||||
@QueryParam("utilisateurId") String utilisateurId
|
||||
);
|
||||
|
||||
@GET
|
||||
@Path("/stats")
|
||||
Map<String, Long> obtenirStatistiques();
|
||||
|
||||
@POST
|
||||
@Path("/test/{utilisateurId}")
|
||||
Map<String, Object> envoyerNotificationTest(
|
||||
@PathParam("utilisateurId") String utilisateurId,
|
||||
@QueryParam("type") @DefaultValue("SYSTEME") String type
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
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;
|
||||
import java.util.UUID;
|
||||
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/preferences")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface PreferencesService {
|
||||
|
||||
@GET
|
||||
@Path("/{utilisateurId}")
|
||||
Map<String, Boolean> obtenirPreferences(@PathParam("utilisateurId") UUID utilisateurId);
|
||||
|
||||
@PUT
|
||||
@Path("/{utilisateurId}")
|
||||
void mettreAJourPreferences(
|
||||
@PathParam("utilisateurId") UUID utilisateurId,
|
||||
Map<String, Boolean> preferences
|
||||
);
|
||||
|
||||
@POST
|
||||
@Path("/{utilisateurId}/reinitialiser")
|
||||
void reinitialiserPreferences(@PathParam("utilisateurId") UUID utilisateurId);
|
||||
|
||||
@GET
|
||||
@Path("/{utilisateurId}/export")
|
||||
Map<String, Object> exporterPreferences(@PathParam("utilisateurId") UUID utilisateurId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.client.dto.TypeOrganisationClientDTO;
|
||||
import jakarta.ws.rs.*;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
/**
|
||||
* REST client pour le catalogue des types d'organisation.
|
||||
*/
|
||||
@RegisterRestClient(configKey = "unionflow-api")
|
||||
@Path("/api/types-organisations")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public interface TypeOrganisationClientService {
|
||||
|
||||
@GET
|
||||
List<TypeOrganisationClientDTO> list(@QueryParam("onlyActifs") @DefaultValue("true") boolean onlyActifs);
|
||||
|
||||
@POST
|
||||
TypeOrganisationClientDTO create(TypeOrganisationClientDTO dto);
|
||||
|
||||
@PUT
|
||||
@Path("/{id}")
|
||||
TypeOrganisationClientDTO update(@PathParam("id") UUID id, TypeOrganisationClientDTO dto);
|
||||
|
||||
@DELETE
|
||||
@Path("/{id}")
|
||||
void disable(@PathParam("id") UUID id);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package dev.lions.unionflow.client.service;
|
||||
|
||||
import dev.lions.unionflow.client.dto.WaveCheckoutSessionDTO;
|
||||
import dev.lions.unionflow.client.dto.WaveBalanceDTO;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.PathParam;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
|
||||
|
||||
/**
|
||||
* Service REST client pour l'intégration Wave Money
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-17
|
||||
*/
|
||||
@RegisterRestClient(baseUri = "http://localhost:8085")
|
||||
@Path("/api/wave")
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public interface WaveService {
|
||||
|
||||
@POST
|
||||
@Path("/checkout/sessions")
|
||||
WaveCheckoutSessionDTO creerSessionPaiement(
|
||||
@QueryParam("montant") BigDecimal montant,
|
||||
@QueryParam("devise") String devise,
|
||||
@QueryParam("successUrl") String successUrl,
|
||||
@QueryParam("errorUrl") String errorUrl,
|
||||
@QueryParam("reference") String referenceUnionFlow,
|
||||
@QueryParam("description") String description,
|
||||
@QueryParam("organisationId") UUID organisationId,
|
||||
@QueryParam("membreId") UUID membreId);
|
||||
|
||||
@GET
|
||||
@Path("/checkout/sessions/{sessionId}")
|
||||
WaveCheckoutSessionDTO verifierStatutSession(@PathParam("sessionId") String sessionId);
|
||||
|
||||
@GET
|
||||
@Path("/balance")
|
||||
WaveBalanceDTO consulterSolde();
|
||||
|
||||
@GET
|
||||
@Path("/test")
|
||||
Map<String, Object> testerConnexion();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,596 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
|
||||
import dev.lions.unionflow.client.dto.AdhesionDTO;
|
||||
import dev.lions.unionflow.client.dto.AssociationDTO;
|
||||
import dev.lions.unionflow.client.dto.MembreDTO;
|
||||
import dev.lions.unionflow.client.service.AdhesionService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.faces.model.SelectItem;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
|
||||
/**
|
||||
* Bean JSF pour la gestion des adhésions
|
||||
* Utilise directement AdhesionDTO et se connecte au backend
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
*/
|
||||
@Named("adhesionsBean")
|
||||
@SessionScoped
|
||||
public class AdhesionsBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(AdhesionsBean.class.getName());
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private AdhesionService adhesionService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private MembreService membreService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private AssociationService associationService;
|
||||
|
||||
// Listes de référence pour les select
|
||||
private List<MembreDTO> listeMembres;
|
||||
private List<AssociationDTO> listeAssociations;
|
||||
|
||||
// Données principales
|
||||
private List<AdhesionDTO> toutesLesAdhesions;
|
||||
private List<AdhesionDTO> adhesionsFiltrees;
|
||||
private List<AdhesionDTO> adhesionsSelectionnees;
|
||||
private AdhesionDTO adhesionSelectionnee;
|
||||
|
||||
// Formulaire nouvelle adhésion
|
||||
private NouvelleAdhesion nouvelleAdhesion;
|
||||
|
||||
// Filtres
|
||||
private FiltresAdhesion filtres;
|
||||
|
||||
// Statistiques
|
||||
private StatistiquesAdhesion statistiques;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
initializeFiltres();
|
||||
chargerMembresEtAssociations();
|
||||
chargerAdhesions();
|
||||
chargerStatistiques();
|
||||
initializeNouvelleAdhesion();
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les listes de membres et d'associations depuis le backend
|
||||
*/
|
||||
private void chargerMembresEtAssociations() {
|
||||
listeMembres = new ArrayList<>();
|
||||
listeAssociations = new ArrayList<>();
|
||||
|
||||
try {
|
||||
listeMembres = membreService.listerActifs();
|
||||
LOGGER.info("Chargement de " + listeMembres.size() + " membres actifs");
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les membres: " + e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
listeAssociations = associationService.listerToutes(0, 1000);
|
||||
LOGGER.info("Chargement de " + listeAssociations.size() + " associations actives");
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les associations: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des membres pour les SelectItem
|
||||
*/
|
||||
public List<SelectItem> getMembresSelectItems() {
|
||||
List<SelectItem> items = new ArrayList<>();
|
||||
items.add(new SelectItem(null, "Sélectionner un membre"));
|
||||
if (listeMembres != null) {
|
||||
for (MembreDTO membre : listeMembres) {
|
||||
String label = membre.getPrenom() + " " + membre.getNom();
|
||||
if (membre.getNumeroMembre() != null) {
|
||||
label += " (" + membre.getNumeroMembre() + ")";
|
||||
}
|
||||
items.add(new SelectItem(membre.getId(), label));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des associations pour les SelectItem
|
||||
*/
|
||||
public List<SelectItem> getAssociationsSelectItems() {
|
||||
List<SelectItem> items = new ArrayList<>();
|
||||
items.add(new SelectItem(null, "Sélectionner une organisation"));
|
||||
if (listeAssociations != null) {
|
||||
for (AssociationDTO assoc : listeAssociations) {
|
||||
String label = assoc.getNom();
|
||||
if (assoc.getTypeAssociation() != null) {
|
||||
label += " (" + assoc.getTypeAssociation() + ")";
|
||||
}
|
||||
items.add(new SelectItem(assoc.getId(), label));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
private void initializeFiltres() {
|
||||
filtres = new FiltresAdhesion();
|
||||
adhesionsSelectionnees = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les adhésions depuis le backend
|
||||
*/
|
||||
private void chargerAdhesions() {
|
||||
toutesLesAdhesions = new ArrayList<>();
|
||||
try {
|
||||
toutesLesAdhesions = adhesionService.listerToutes(0, 1000);
|
||||
LOGGER.info("Chargement de " + toutesLesAdhesions.size() + " adhésions");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des adhésions: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de charger les adhésions: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les statistiques depuis le backend
|
||||
*/
|
||||
private void chargerStatistiques() {
|
||||
statistiques = new StatistiquesAdhesion();
|
||||
try {
|
||||
Map<String, Object> statsBackend = adhesionService.obtenirStatistiques();
|
||||
|
||||
// Extraction des statistiques du backend
|
||||
Long totalAdhesions = ((Number) statsBackend.getOrDefault("totalAdhesions", 0L)).longValue();
|
||||
Long adhesionsApprouvees = ((Number) statsBackend.getOrDefault("adhesionsApprouvees", 0L)).longValue();
|
||||
Long adhesionsEnAttente = ((Number) statsBackend.getOrDefault("adhesionsEnAttente", 0L)).longValue();
|
||||
Long adhesionsPayees = ((Number) statsBackend.getOrDefault("adhesionsPayees", 0L)).longValue();
|
||||
Double tauxApprobation = ((Number) statsBackend.getOrDefault("tauxApprobation", 0.0)).doubleValue();
|
||||
Double tauxPaiement = ((Number) statsBackend.getOrDefault("tauxPaiement", 0.0)).doubleValue();
|
||||
|
||||
// Calcul des montants depuis les adhésions réelles
|
||||
BigDecimal totalCollecte = toutesLesAdhesions.stream()
|
||||
.filter(a -> "PAYEE".equals(a.getStatut()) || "EN_PAIEMENT".equals(a.getStatut()))
|
||||
.map(a -> a.getMontantPaye() != null ? a.getMontantPaye() : BigDecimal.ZERO)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
BigDecimal totalFrais = toutesLesAdhesions.stream()
|
||||
.map(a -> a.getFraisAdhesion() != null ? a.getFraisAdhesion() : BigDecimal.ZERO)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
statistiques.setTotalAdhesions(totalAdhesions.intValue());
|
||||
statistiques.setAdhesionsApprouvees(adhesionsApprouvees.intValue());
|
||||
statistiques.setAdhesionsEnAttente(adhesionsEnAttente.intValue());
|
||||
statistiques.setAdhesionsPayees(adhesionsPayees.intValue());
|
||||
statistiques.setTauxApprobation(tauxApprobation);
|
||||
statistiques.setTauxPaiement(tauxPaiement);
|
||||
statistiques.setTotalCollecte(totalCollecte);
|
||||
statistiques.setTotalFrais(totalFrais);
|
||||
|
||||
LOGGER.info("Statistiques chargées: Total=" + totalAdhesions + ", Approuvées=" + adhesionsApprouvees);
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des statistiques: " + e.getMessage());
|
||||
initialiserStatistiquesParDefaut();
|
||||
}
|
||||
}
|
||||
|
||||
private void initialiserStatistiquesParDefaut() {
|
||||
statistiques.setTotalAdhesions(0);
|
||||
statistiques.setAdhesionsApprouvees(0);
|
||||
statistiques.setAdhesionsEnAttente(0);
|
||||
statistiques.setAdhesionsPayees(0);
|
||||
statistiques.setTauxApprobation(0.0);
|
||||
statistiques.setTauxPaiement(0.0);
|
||||
statistiques.setTotalCollecte(BigDecimal.ZERO);
|
||||
statistiques.setTotalFrais(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applique les filtres en utilisant la recherche backend
|
||||
*/
|
||||
private void appliquerFiltres() {
|
||||
try {
|
||||
// Utiliser la recherche backend
|
||||
if (filtres.getStatut() != null && !filtres.getStatut().isEmpty()) {
|
||||
adhesionsFiltrees = adhesionService.obtenirParStatut(filtres.getStatut(), 0, 1000);
|
||||
} else {
|
||||
adhesionsFiltrees = new ArrayList<>(toutesLesAdhesions);
|
||||
}
|
||||
|
||||
// Appliquer les filtres supplémentaires côté client si nécessaire
|
||||
if (filtres.getNomMembre() != null && !filtres.getNomMembre().trim().isEmpty()) {
|
||||
adhesionsFiltrees = adhesionsFiltrees.stream()
|
||||
.filter(a -> a.getNomMembre() != null
|
||||
&& a.getNomMembre().toLowerCase().contains(filtres.getNomMembre().toLowerCase()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (filtres.getDateDebut() != null) {
|
||||
adhesionsFiltrees = adhesionsFiltrees.stream()
|
||||
.filter(a -> a.getDateDemande() != null
|
||||
&& !a.getDateDemande().isBefore(filtres.getDateDebut()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
if (filtres.getDateFin() != null) {
|
||||
adhesionsFiltrees = adhesionsFiltrees.stream()
|
||||
.filter(a -> a.getDateDemande() != null
|
||||
&& !a.getDateDemande().isAfter(filtres.getDateFin()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de l'application des filtres: " + e.getMessage());
|
||||
adhesionsFiltrees = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
/**
|
||||
* Recherche avec filtres
|
||||
*/
|
||||
public void rechercher() {
|
||||
appliquerFiltres();
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Recherche",
|
||||
adhesionsFiltrees.size() + " adhésion(s) trouvée(s)"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialise les filtres
|
||||
*/
|
||||
public void reinitialiserFiltres() {
|
||||
filtres = new FiltresAdhesion();
|
||||
chargerAdhesions();
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enregistre une nouvelle adhésion via le backend
|
||||
*/
|
||||
public void enregistrerAdhesion() {
|
||||
try {
|
||||
AdhesionDTO nouvelleAdh = new AdhesionDTO();
|
||||
nouvelleAdh.setMembreId(nouvelleAdhesion.getMembreId());
|
||||
nouvelleAdh.setOrganisationId(nouvelleAdhesion.getOrganisationId());
|
||||
nouvelleAdh.setFraisAdhesion(nouvelleAdhesion.getFraisAdhesion());
|
||||
nouvelleAdh.setDateDemande(LocalDate.now());
|
||||
nouvelleAdh.setStatut("EN_ATTENTE");
|
||||
nouvelleAdh.setMontantPaye(BigDecimal.ZERO);
|
||||
nouvelleAdh.setCodeDevise("XOF");
|
||||
nouvelleAdh.setObservations(nouvelleAdhesion.getObservations());
|
||||
|
||||
AdhesionDTO adhesionCreee = adhesionService.creer(nouvelleAdh);
|
||||
|
||||
// Recharger les données
|
||||
chargerAdhesions();
|
||||
chargerStatistiques();
|
||||
appliquerFiltres();
|
||||
initializeNouvelleAdhesion();
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Adhésion créée avec succès"));
|
||||
LOGGER.info("Nouvelle adhésion créée: " + adhesionCreee.getId());
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la création de l'adhésion: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de créer l'adhésion: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Approuve une adhésion
|
||||
*/
|
||||
public void approuverAdhesion() {
|
||||
if (adhesionSelectionnee == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
adhesionService.approuver(adhesionSelectionnee.getId(), "Admin");
|
||||
|
||||
// Recharger les données
|
||||
chargerAdhesions();
|
||||
chargerStatistiques();
|
||||
appliquerFiltres();
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Adhésion approuvée"));
|
||||
LOGGER.info("Adhésion approuvée: " + adhesionSelectionnee.getId());
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de l'approbation: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible d'approuver l'adhésion: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rejette une adhésion
|
||||
*/
|
||||
public void rejeterAdhesion(String motifRejet) {
|
||||
if (adhesionSelectionnee == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
adhesionService.rejeter(adhesionSelectionnee.getId(), motifRejet);
|
||||
|
||||
// Recharger les données
|
||||
chargerAdhesions();
|
||||
chargerStatistiques();
|
||||
appliquerFiltres();
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Adhésion rejetée"));
|
||||
LOGGER.info("Adhésion rejetée: " + adhesionSelectionnee.getId());
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du rejet: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de rejeter l'adhésion: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enregistre un paiement pour une adhésion
|
||||
*/
|
||||
public void enregistrerPaiement(BigDecimal montantPaye, String methodePaiement, String referencePaiement) {
|
||||
if (adhesionSelectionnee == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
adhesionService.enregistrerPaiement(
|
||||
adhesionSelectionnee.getId(),
|
||||
montantPaye,
|
||||
methodePaiement,
|
||||
referencePaiement);
|
||||
|
||||
// Recharger les données
|
||||
chargerAdhesions();
|
||||
chargerStatistiques();
|
||||
appliquerFiltres();
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Paiement enregistré"));
|
||||
LOGGER.info("Paiement enregistré pour l'adhésion: " + adhesionSelectionnee.getId());
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de l'enregistrement du paiement: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible d'enregistrer le paiement: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sélectionne une adhésion pour afficher ses détails
|
||||
*/
|
||||
public void selectionnerAdhesion(AdhesionDTO adhesion) {
|
||||
this.adhesionSelectionnee = adhesion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualise les données depuis le backend
|
||||
*/
|
||||
public void actualiser() {
|
||||
chargerAdhesions();
|
||||
chargerStatistiques();
|
||||
appliquerFiltres();
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO, "Actualisation",
|
||||
"Données actualisées"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les adhésions en attente depuis le backend
|
||||
*/
|
||||
public void chargerAdhesionsEnAttente() {
|
||||
try {
|
||||
toutesLesAdhesions = adhesionService.obtenirEnAttente(0, 1000);
|
||||
appliquerFiltres();
|
||||
LOGGER.info("Chargement de " + toutesLesAdhesions.size() + " adhésions en attente");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des adhésions en attente: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de charger les adhésions en attente: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeNouvelleAdhesion() {
|
||||
nouvelleAdhesion = new NouvelleAdhesion();
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
|
||||
public List<AdhesionDTO> getToutesLesAdhesions() {
|
||||
return toutesLesAdhesions;
|
||||
}
|
||||
|
||||
public void setToutesLesAdhesions(List<AdhesionDTO> toutesLesAdhesions) {
|
||||
this.toutesLesAdhesions = toutesLesAdhesions;
|
||||
}
|
||||
|
||||
public List<AdhesionDTO> getAdhesionsFiltrees() {
|
||||
return adhesionsFiltrees;
|
||||
}
|
||||
|
||||
public void setAdhesionsFiltrees(List<AdhesionDTO> adhesionsFiltrees) {
|
||||
this.adhesionsFiltrees = adhesionsFiltrees;
|
||||
}
|
||||
|
||||
public List<AdhesionDTO> getAdhesionsSelectionnees() {
|
||||
return adhesionsSelectionnees;
|
||||
}
|
||||
|
||||
public void setAdhesionsSelectionnees(List<AdhesionDTO> adhesionsSelectionnees) {
|
||||
this.adhesionsSelectionnees = adhesionsSelectionnees;
|
||||
}
|
||||
|
||||
public AdhesionDTO getAdhesionSelectionnee() {
|
||||
return adhesionSelectionnee;
|
||||
}
|
||||
|
||||
public void setAdhesionSelectionnee(AdhesionDTO adhesionSelectionnee) {
|
||||
this.adhesionSelectionnee = adhesionSelectionnee;
|
||||
}
|
||||
|
||||
public NouvelleAdhesion getNouvelleAdhesion() {
|
||||
return nouvelleAdhesion;
|
||||
}
|
||||
|
||||
public void setNouvelleAdhesion(NouvelleAdhesion nouvelleAdhesion) {
|
||||
this.nouvelleAdhesion = nouvelleAdhesion;
|
||||
}
|
||||
|
||||
public FiltresAdhesion getFiltres() {
|
||||
return filtres;
|
||||
}
|
||||
|
||||
public void setFiltres(FiltresAdhesion filtres) {
|
||||
this.filtres = filtres;
|
||||
}
|
||||
|
||||
public StatistiquesAdhesion getStatistiques() {
|
||||
return statistiques;
|
||||
}
|
||||
|
||||
public void setStatistiques(StatistiquesAdhesion statistiques) {
|
||||
this.statistiques = statistiques;
|
||||
}
|
||||
|
||||
// Classes internes pour les formulaires et filtres
|
||||
|
||||
public static class NouvelleAdhesion implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private UUID membreId;
|
||||
private UUID organisationId;
|
||||
private BigDecimal fraisAdhesion;
|
||||
private String observations;
|
||||
|
||||
// Getters et Setters
|
||||
public UUID getMembreId() { return membreId; }
|
||||
public void setMembreId(UUID membreId) { this.membreId = membreId; }
|
||||
|
||||
public UUID getOrganisationId() { return organisationId; }
|
||||
public void setOrganisationId(UUID organisationId) { this.organisationId = organisationId; }
|
||||
|
||||
public BigDecimal getFraisAdhesion() { return fraisAdhesion; }
|
||||
public void setFraisAdhesion(BigDecimal fraisAdhesion) { this.fraisAdhesion = fraisAdhesion; }
|
||||
|
||||
public String getObservations() { return observations; }
|
||||
public void setObservations(String observations) { this.observations = observations; }
|
||||
}
|
||||
|
||||
public static class FiltresAdhesion implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String statut;
|
||||
private String nomMembre;
|
||||
private LocalDate dateDebut;
|
||||
private LocalDate dateFin;
|
||||
|
||||
// Getters et Setters
|
||||
public String getStatut() { return statut; }
|
||||
public void setStatut(String statut) { this.statut = statut; }
|
||||
|
||||
public String getNomMembre() { return nomMembre; }
|
||||
public void setNomMembre(String nomMembre) { this.nomMembre = nomMembre; }
|
||||
|
||||
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 static class StatistiquesAdhesion implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private int totalAdhesions;
|
||||
private int adhesionsApprouvees;
|
||||
private int adhesionsEnAttente;
|
||||
private int adhesionsPayees;
|
||||
private double tauxApprobation;
|
||||
private double tauxPaiement;
|
||||
private BigDecimal totalCollecte;
|
||||
private BigDecimal totalFrais;
|
||||
|
||||
// Getters et Setters
|
||||
public int getTotalAdhesions() { return totalAdhesions; }
|
||||
public void setTotalAdhesions(int totalAdhesions) { this.totalAdhesions = totalAdhesions; }
|
||||
|
||||
public int getAdhesionsApprouvees() { return adhesionsApprouvees; }
|
||||
public void setAdhesionsApprouvees(int adhesionsApprouvees) { this.adhesionsApprouvees = adhesionsApprouvees; }
|
||||
|
||||
public int getAdhesionsEnAttente() { return adhesionsEnAttente; }
|
||||
public void setAdhesionsEnAttente(int adhesionsEnAttente) { this.adhesionsEnAttente = adhesionsEnAttente; }
|
||||
|
||||
public int getAdhesionsPayees() { return adhesionsPayees; }
|
||||
public void setAdhesionsPayees(int adhesionsPayees) { this.adhesionsPayees = adhesionsPayees; }
|
||||
|
||||
public double getTauxApprobation() { return tauxApprobation; }
|
||||
public void setTauxApprobation(double tauxApprobation) { this.tauxApprobation = tauxApprobation; }
|
||||
|
||||
public double getTauxPaiement() { return tauxPaiement; }
|
||||
public void setTauxPaiement(double tauxPaiement) { this.tauxPaiement = tauxPaiement; }
|
||||
|
||||
public BigDecimal getTotalCollecte() { return totalCollecte; }
|
||||
public void setTotalCollecte(BigDecimal totalCollecte) { this.totalCollecte = totalCollecte; }
|
||||
|
||||
public BigDecimal getTotalFrais() { return totalFrais; }
|
||||
public void setTotalFrais(BigDecimal totalFrais) { this.totalFrais = totalFrais; }
|
||||
|
||||
// Méthodes utilitaires pour l'affichage
|
||||
public String getTotalCollecteFormatte() {
|
||||
if (totalCollecte == null) return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", totalCollecte.doubleValue());
|
||||
}
|
||||
|
||||
public String getTotalFraisFormatte() {
|
||||
if (totalFrais == null) return "0 FCFA";
|
||||
return String.format("%,.0f FCFA", totalFrais.doubleValue());
|
||||
}
|
||||
|
||||
public int getTauxApprobationInt() {
|
||||
return (int) Math.round(tauxApprobation);
|
||||
}
|
||||
|
||||
public int getTauxPaiementInt() {
|
||||
return (int) Math.round(tauxPaiement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,52 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.dto.AuditLogDTO;
|
||||
import dev.lions.unionflow.client.service.AuditService;
|
||||
import dev.lions.unionflow.client.service.NotificationClientService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.ExternalContext;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Bean JSF pour la gestion des logs d'audit
|
||||
* Refactorisé pour utiliser directement AuditLogDTO et se connecter au backend
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 2.0
|
||||
*/
|
||||
@Named("auditBean")
|
||||
@SessionScoped
|
||||
public class AuditBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(AuditBean.class.getName());
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private AuditService auditService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private NotificationClientService notificationService;
|
||||
|
||||
@Inject
|
||||
private UserSession userSession;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
|
||||
|
||||
// Filtres
|
||||
private Date dateDebut;
|
||||
@@ -23,186 +57,247 @@ public class AuditBean implements Serializable {
|
||||
private String module = "";
|
||||
private String ipAddress = "";
|
||||
|
||||
// Données
|
||||
private List<EvenementAudit> evenements;
|
||||
private EvenementAudit evenementSelectionne;
|
||||
// Données - Utilisation directe de AuditLogDTO
|
||||
private List<AuditLogDTO> tousLesLogs;
|
||||
private List<AuditLogDTO> logsFiltres;
|
||||
private AuditLogDTO logSelectionne;
|
||||
|
||||
// Statistiques
|
||||
private Map<String, Object> statistiques;
|
||||
|
||||
// Export
|
||||
private String formatExport = "EXCEL";
|
||||
private boolean inclureFiltresExport = true;
|
||||
|
||||
public AuditBean() {
|
||||
initialiserEvenements();
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
LOGGER.info("Initialisation de AuditBean");
|
||||
// Initialiser les dates à aujourd'hui - 7 jours
|
||||
Calendar cal = Calendar.getInstance();
|
||||
dateFin = cal.getTime();
|
||||
cal.add(Calendar.DAY_OF_MONTH, -7);
|
||||
dateDebut = cal.getTime();
|
||||
|
||||
chargerLogs();
|
||||
chargerStatistiques();
|
||||
}
|
||||
|
||||
private void initialiserEvenements() {
|
||||
evenements = new ArrayList<>();
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
/**
|
||||
* Charge les logs depuis le backend
|
||||
*/
|
||||
public void chargerLogs() {
|
||||
try {
|
||||
LOGGER.info("Chargement des logs d'audit depuis le backend");
|
||||
Map<String, Object> response = auditService.listerTous(0, 1000, "dateHeure", "desc");
|
||||
|
||||
tousLesLogs = new ArrayList<>();
|
||||
|
||||
if (response.containsKey("data")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> data = (List<Object>) response.get("data");
|
||||
|
||||
if (data != null) {
|
||||
for (Object item : data) {
|
||||
if (item instanceof AuditLogDTO) {
|
||||
tousLesLogs.add((AuditLogDTO) item);
|
||||
} else if (item instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
AuditLogDTO dto = convertMapToDTO((Map<String, Object>) item);
|
||||
tousLesLogs.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appliquerFiltres();
|
||||
LOGGER.info("Logs chargés: " + tousLesLogs.size());
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des logs: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
tousLesLogs = new ArrayList<>();
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Erreur lors du chargement des logs: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les statistiques depuis le backend
|
||||
*/
|
||||
public void chargerStatistiques() {
|
||||
try {
|
||||
LOGGER.info("Chargement des statistiques d'audit");
|
||||
statistiques = auditService.getStatistiques();
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des statistiques: " + e.getMessage());
|
||||
statistiques = new HashMap<>();
|
||||
statistiques.put("total", 0L);
|
||||
statistiques.put("success", 0L);
|
||||
statistiques.put("errors", 0L);
|
||||
statistiques.put("warnings", 0L);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertit une Map en AuditLogDTO
|
||||
*/
|
||||
private AuditLogDTO convertMapToDTO(Map<String, Object> map) {
|
||||
AuditLogDTO dto = new AuditLogDTO();
|
||||
|
||||
// Événements de connexion
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusMinutes(15), "CONNEXION", "SUCCESS", "Marie Dupont", "ADMIN_ORG", "AUTH",
|
||||
"Connexion réussie", "Connexion via interface web", "192.168.1.105",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "SESSION_123456"));
|
||||
try {
|
||||
if (map.get("id") != null) {
|
||||
if (map.get("id") instanceof UUID) {
|
||||
dto.setId((UUID) map.get("id"));
|
||||
} else {
|
||||
dto.setId(UUID.fromString(map.get("id").toString()));
|
||||
}
|
||||
}
|
||||
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusMinutes(32), "CONNEXION", "ERROR", "Jean Martin", "MEMBRE", "AUTH",
|
||||
"Tentative de connexion échouée", "Mot de passe incorrect (3e tentative)", "192.168.1.87",
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X)", "SESSION_789012"));
|
||||
if (map.get("typeAction") != null) dto.setTypeAction(map.get("typeAction").toString());
|
||||
if (map.get("severite") != null) dto.setSeverite(map.get("severite").toString());
|
||||
if (map.get("utilisateur") != null) dto.setUtilisateur(map.get("utilisateur").toString());
|
||||
if (map.get("role") != null) dto.setRole(map.get("role").toString());
|
||||
if (map.get("module") != null) dto.setModule(map.get("module").toString());
|
||||
if (map.get("description") != null) dto.setDescription(map.get("description").toString());
|
||||
if (map.get("details") != null) dto.setDetails(map.get("details").toString());
|
||||
if (map.get("ipAddress") != null) dto.setIpAddress(map.get("ipAddress").toString());
|
||||
if (map.get("userAgent") != null) dto.setUserAgent(map.get("userAgent").toString());
|
||||
if (map.get("sessionId") != null) dto.setSessionId(map.get("sessionId").toString());
|
||||
if (map.get("donneesAvant") != null) dto.setDonneesAvant(map.get("donneesAvant").toString());
|
||||
if (map.get("donneesApres") != null) dto.setDonneesApres(map.get("donneesApres").toString());
|
||||
if (map.get("entiteId") != null) dto.setEntiteId(map.get("entiteId").toString());
|
||||
if (map.get("entiteType") != null) dto.setEntiteType(map.get("entiteType").toString());
|
||||
|
||||
// Événements de gestion des membres
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(1), "CREATION", "SUCCESS", "Marie Dupont", "ADMIN_ORG", "MEMBRES",
|
||||
"Création d'un nouveau membre", "Membre: Paul Durand (ID: MBR_2024_001)", "192.168.1.105",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "SESSION_123456"));
|
||||
// Conversion des dates
|
||||
if (map.get("dateHeure") != null) {
|
||||
Object date = map.get("dateHeure");
|
||||
if (date instanceof LocalDateTime) {
|
||||
dto.setDateHeure((LocalDateTime) date);
|
||||
} else if (date instanceof String) {
|
||||
dto.setDateHeure(LocalDateTime.parse(date.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(2), "MODIFICATION", "SUCCESS", "Sophie Bernard", "SECRETAIRE", "MEMBRES",
|
||||
"Modification profil membre", "Mise à jour adresse email: paul.durand@email.com", "192.168.1.92",
|
||||
"Mozilla/5.0 (iPhone; CPU iPhone OS)", "SESSION_345678"));
|
||||
|
||||
// Événements de cotisations
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(3), "CREATION", "SUCCESS", "Pierre Legrand", "COMPTABLE", "COTISATIONS",
|
||||
"Enregistrement paiement cotisation", "Cotisation 2024 - Membre: Marie Petit - 50€", "192.168.1.78",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "SESSION_901234"));
|
||||
|
||||
// Événements d'export
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(4), "EXPORT", "SUCCESS", "Marie Dupont", "ADMIN_ORG", "RAPPORTS",
|
||||
"Export liste des membres", "Format Excel - 156 membres exportés", "192.168.1.105",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "SESSION_123456"));
|
||||
|
||||
// Événements de configuration
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(6), "CONFIGURATION", "WARNING", "Admin Système", "SUPER_ADMIN", "CONFIG",
|
||||
"Modification paramètres sécurité", "Durée de session modifiée: 30min → 60min", "192.168.1.1",
|
||||
"Mozilla/5.0 (Linux; Ubuntu)", "SESSION_ADMIN001"));
|
||||
|
||||
// Événements suspects
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(8), "CONNEXION", "CRITICAL", "Utilisateur Inconnu", "N/A", "AUTH",
|
||||
"Tentative de connexion suspecte", "Multiples tentatives depuis IP externe", "203.45.67.89",
|
||||
"Bot/1.0", "SESSION_UNKNOWN"));
|
||||
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(12), "CONSULTATION", "ERROR", "Test User", "MEMBRE", "DOCUMENTS",
|
||||
"Accès non autorisé", "Tentative d'accès au document confidentiel DOC_2024_005", "192.168.1.199",
|
||||
"Mozilla/5.0 (Android)", "SESSION_567890"));
|
||||
|
||||
// Événements de suppression
|
||||
evenements.add(new EvenementAudit(
|
||||
now.minusHours(24), "SUPPRESSION", "WARNING", "Marie Dupont", "ADMIN_ORG", "EVENTS",
|
||||
"Suppression événement", "Événement: Assemblée Générale 2023 supprimé", "192.168.1.105",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)", "SESSION_123456"));
|
||||
|
||||
// Plus d'événements pour la pagination
|
||||
for (int i = 0; i < 50; i++) {
|
||||
LocalDateTime date = now.minusHours(i + 1).minusMinutes(new Random().nextInt(60));
|
||||
String[] users = {"Marie Dupont", "Jean Martin", "Pierre Legrand", "Sophie Bernard", "Paul Durand"};
|
||||
String[] actions = {"CONSULTATION", "MODIFICATION", "CONNEXION", "DECONNEXION"};
|
||||
String[] modules = {"MEMBRES", "COTISATIONS", "EVENTS", "DOCUMENTS"};
|
||||
String[] ips = {"192.168.1.105", "192.168.1.87", "192.168.1.92", "192.168.1.78"};
|
||||
|
||||
String user = users[i % users.length];
|
||||
String action = actions[i % actions.length];
|
||||
String module = modules[i % modules.length];
|
||||
String ip = ips[i % ips.length];
|
||||
String severite = i % 10 == 0 ? "WARNING" : "SUCCESS";
|
||||
|
||||
evenements.add(new EvenementAudit(
|
||||
date, action, severite, user, "MEMBRE", module,
|
||||
"Action automatique " + (i + 1), "Détails de l'action " + (i + 1), ip,
|
||||
"Mozilla/5.0 (Auto)", "SESSION_AUTO_" + i));
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Erreur lors de la conversion Map vers DTO: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Trier par date décroissante
|
||||
evenements.sort((e1, e2) -> e2.getDateHeure().compareTo(e1.getDateHeure()));
|
||||
return dto;
|
||||
}
|
||||
|
||||
// Getters pour KPIs
|
||||
public int getTotalEvenements() {
|
||||
return evenements.size();
|
||||
/**
|
||||
* Applique les filtres sur les logs
|
||||
*/
|
||||
public void appliquerFiltres() {
|
||||
if (tousLesLogs == null) {
|
||||
logsFiltres = new ArrayList<>();
|
||||
return;
|
||||
}
|
||||
|
||||
logsFiltres = tousLesLogs.stream()
|
||||
.filter(this::correspondAuxFiltres)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public long getConnexionsReussies() {
|
||||
return evenements.stream()
|
||||
.filter(e -> "CONNEXION".equals(e.getTypeAction()) && "SUCCESS".equals(e.getSeverite()))
|
||||
.filter(e -> e.getDateHeure().isAfter(LocalDateTime.now().toLocalDate().atStartOfDay()))
|
||||
.count();
|
||||
}
|
||||
|
||||
public long getTentativesEchouees() {
|
||||
return evenements.stream()
|
||||
.filter(e -> "CONNEXION".equals(e.getTypeAction()) && !"SUCCESS".equals(e.getSeverite()))
|
||||
.filter(e -> e.getDateHeure().isAfter(LocalDateTime.now().minusWeeks(1)))
|
||||
.count();
|
||||
}
|
||||
|
||||
public long getAlertesSecurite() {
|
||||
return evenements.stream()
|
||||
.filter(e -> "CRITICAL".equals(e.getSeverite()) || "ERROR".equals(e.getSeverite()))
|
||||
.count();
|
||||
}
|
||||
|
||||
// Filtrage
|
||||
public List<EvenementAudit> getEvenementsFiltres() {
|
||||
return evenements.stream()
|
||||
.filter(this::correspondAuxFiltres)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean correspondAuxFiltres(EvenementAudit event) {
|
||||
private boolean correspondAuxFiltres(AuditLogDTO log) {
|
||||
if (log.getDateHeure() == null) return false;
|
||||
|
||||
// Filtre par dates
|
||||
if (dateDebut != null && event.getDateHeure().isBefore(convertToLocalDateTime(dateDebut))) {
|
||||
LocalDateTime dateDebutLDT = dateDebut != null ?
|
||||
LocalDateTime.ofInstant(dateDebut.toInstant(), ZoneId.systemDefault()) : null;
|
||||
LocalDateTime dateFinLDT = dateFin != null ?
|
||||
LocalDateTime.ofInstant(dateFin.toInstant(), ZoneId.systemDefault()).plusDays(1) : null;
|
||||
|
||||
if (dateDebutLDT != null && log.getDateHeure().isBefore(dateDebutLDT)) {
|
||||
return false;
|
||||
}
|
||||
if (dateFin != null && event.getDateHeure().isAfter(convertToLocalDateTime(dateFin).plusDays(1))) {
|
||||
if (dateFinLDT != null && log.getDateHeure().isAfter(dateFinLDT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filtre par type d'action
|
||||
if (!typeAction.isEmpty() && !typeAction.equals(event.getTypeAction())) {
|
||||
if (!typeAction.isEmpty() && !typeAction.equals(log.getTypeAction())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filtre par sévérité
|
||||
if (!severite.isEmpty() && !severite.equals(event.getSeverite())) {
|
||||
if (!severite.isEmpty() && !severite.equals(log.getSeverite())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filtre par utilisateur
|
||||
if (!utilisateur.isEmpty() && !event.getUtilisateur().toLowerCase().contains(utilisateur.toLowerCase())) {
|
||||
if (!utilisateur.isEmpty() && log.getUtilisateur() != null &&
|
||||
!log.getUtilisateur().toLowerCase().contains(utilisateur.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filtre par module
|
||||
if (!module.isEmpty() && !module.equals(event.getModule())) {
|
||||
if (!module.isEmpty() && !module.equals(log.getModule())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Filtre par IP
|
||||
if (!ipAddress.isEmpty() && !event.getIpAddress().contains(ipAddress)) {
|
||||
if (!ipAddress.isEmpty() && log.getIpAddress() != null &&
|
||||
!log.getIpAddress().contains(ipAddress)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private LocalDateTime convertToLocalDateTime(Date date) {
|
||||
return LocalDateTime.ofInstant(date.toInstant(), java.time.ZoneId.systemDefault());
|
||||
}
|
||||
|
||||
// Actions
|
||||
/**
|
||||
* Recherche avec filtres via le backend
|
||||
*/
|
||||
public void rechercher() {
|
||||
// La recherche se fait automatiquement via le filtrage
|
||||
try {
|
||||
LOGGER.info("Recherche de logs avec filtres");
|
||||
|
||||
String dateDebutStr = dateDebut != null ?
|
||||
LocalDateTime.ofInstant(dateDebut.toInstant(), ZoneId.systemDefault()).toString() : null;
|
||||
String dateFinStr = dateFin != null ?
|
||||
LocalDateTime.ofInstant(dateFin.toInstant(), ZoneId.systemDefault()).toString() : null;
|
||||
|
||||
Map<String, Object> response = auditService.rechercher(
|
||||
dateDebutStr, dateFinStr,
|
||||
typeAction.isEmpty() ? null : typeAction,
|
||||
severite.isEmpty() ? null : severite,
|
||||
utilisateur.isEmpty() ? null : utilisateur,
|
||||
module.isEmpty() ? null : module,
|
||||
ipAddress.isEmpty() ? null : ipAddress,
|
||||
0, 1000);
|
||||
|
||||
logsFiltres = new ArrayList<>();
|
||||
|
||||
if (response.containsKey("data")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> data = (List<Object>) response.get("data");
|
||||
|
||||
if (data != null) {
|
||||
for (Object item : data) {
|
||||
if (item instanceof AuditLogDTO) {
|
||||
logsFiltres.add((AuditLogDTO) item);
|
||||
} else if (item instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
AuditLogDTO dto = convertMapToDTO((Map<String, Object>) item);
|
||||
logsFiltres.add(dto);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Recherche",
|
||||
logsFiltres.size() + " log(s) trouvé(s)");
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la recherche: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Erreur lors de la recherche: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialise les filtres
|
||||
*/
|
||||
public void reinitialiserFiltres() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
dateFin = cal.getTime();
|
||||
@@ -214,241 +309,246 @@ public class AuditBean implements Serializable {
|
||||
utilisateur = "";
|
||||
module = "";
|
||||
ipAddress = "";
|
||||
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public void voirDetails(EvenementAudit event) {
|
||||
this.evenementSelectionne = event;
|
||||
/**
|
||||
* Actualise les données
|
||||
*/
|
||||
public void actualiser() {
|
||||
chargerLogs();
|
||||
chargerStatistiques();
|
||||
}
|
||||
|
||||
public void signalerEvenement(EvenementAudit event) {
|
||||
// Logique pour signaler un événement comme suspect
|
||||
/**
|
||||
* Sélectionne un log pour voir les détails
|
||||
*/
|
||||
public void selectionnerLog(AuditLogDTO log) {
|
||||
this.logSelectionne = log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode pour compatibilité avec l'ancienne page
|
||||
*/
|
||||
public void voirDetails(AuditLogDTO log) {
|
||||
selectionnerLog(log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signale un événement d'audit suspect
|
||||
*/
|
||||
public void signalerEvenement(AuditLogDTO log) {
|
||||
if (log == null) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_WARN, "Attention",
|
||||
"Aucun log sélectionné");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
LOGGER.info("Signalement de l'événement: " + log.getId());
|
||||
|
||||
// Envoyer une notification aux administrateurs
|
||||
String message = String.format(
|
||||
"Événement signalé - Type: %s, Utilisateur: %s, Date: %s, IP: %s",
|
||||
log.getTypeAction(),
|
||||
log.getUtilisateur(),
|
||||
log.getDateHeure() != null ? log.getDateHeure().format(DATE_FORMATTER) : "N/A",
|
||||
log.getIpAddress()
|
||||
);
|
||||
|
||||
// Récupérer l'ID de l'utilisateur courant pour le signalement
|
||||
String signaleurId = userSession.getCurrentUser() != null
|
||||
? userSession.getCurrentUser().getId().toString()
|
||||
: "anonyme";
|
||||
|
||||
notificationService.envoyerNotificationGroupe(
|
||||
"SYSTEME",
|
||||
"Signalement d'un événement d'audit",
|
||||
message,
|
||||
List.of(signaleurId) // Envoyer aux admins (à adapter selon votre logique)
|
||||
);
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Signalement",
|
||||
"L'événement a été signalé aux administrateurs");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du signalement: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de signaler l'événement: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporte les logs d'audit en CSV
|
||||
*/
|
||||
public void exporter() {
|
||||
// Logique d'export selon le format sélectionné
|
||||
try {
|
||||
LOGGER.info("Export de " + (logsFiltres != null ? logsFiltres.size() : 0) + " logs d'audit");
|
||||
|
||||
List<AuditLogDTO> logsAExporter = logsFiltres != null && !logsFiltres.isEmpty()
|
||||
? logsFiltres
|
||||
: tousLesLogs;
|
||||
|
||||
if (logsAExporter == null || logsAExporter.isEmpty()) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_WARN, "Attention",
|
||||
"Aucun log à exporter");
|
||||
return;
|
||||
}
|
||||
|
||||
// Générer le CSV
|
||||
StringBuilder csv = new StringBuilder();
|
||||
csv.append("Date/Heure;Type Action;Utilisateur;Module;IP;Sévérité;Détails\n");
|
||||
|
||||
for (AuditLogDTO log : logsAExporter) {
|
||||
csv.append(String.format("%s;%s;%s;%s;%s;%s;%s\n",
|
||||
log.getDateHeure() != null ? log.getDateHeure().format(DATE_FORMATTER) : "",
|
||||
log.getTypeAction() != null ? log.getTypeAction() : "",
|
||||
log.getUtilisateur() != null ? log.getUtilisateur() : "",
|
||||
log.getModule() != null ? log.getModule() : "",
|
||||
log.getIpAddress() != null ? log.getIpAddress() : "",
|
||||
log.getSeverite() != null ? log.getSeverite() : "",
|
||||
log.getDetails() != null ? log.getDetails().replace(";", ",").replace("\n", " ") : ""
|
||||
));
|
||||
}
|
||||
|
||||
byte[] csvData = csv.toString().getBytes(StandardCharsets.UTF_8);
|
||||
telechargerFichier(csvData, "audit-logs-export.csv", "text/csv");
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Export",
|
||||
"Export de " + logsAExporter.size() + " log(s) terminé");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de l'export: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible d'exporter les logs: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Télécharge un fichier via le navigateur
|
||||
*/
|
||||
private void telechargerFichier(byte[] data, String nomFichier, String contentType) {
|
||||
try {
|
||||
FacesContext fc = FacesContext.getCurrentInstance();
|
||||
ExternalContext ec = fc.getExternalContext();
|
||||
|
||||
ec.responseReset();
|
||||
ec.setResponseContentType(contentType + "; charset=UTF-8");
|
||||
ec.setResponseContentLength(data.length);
|
||||
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + nomFichier + "\"");
|
||||
|
||||
OutputStream output = ec.getResponseOutputStream();
|
||||
output.write(data);
|
||||
output.flush();
|
||||
|
||||
fc.responseComplete();
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur téléchargement fichier: " + e.getMessage());
|
||||
throw new RuntimeException("Erreur lors du téléchargement", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Getters pour KPIs
|
||||
public int getTotalEvenements() {
|
||||
if (statistiques != null && statistiques.containsKey("total")) {
|
||||
Object total = statistiques.get("total");
|
||||
if (total instanceof Number) {
|
||||
return ((Number) total).intValue();
|
||||
}
|
||||
}
|
||||
return tousLesLogs != null ? tousLesLogs.size() : 0;
|
||||
}
|
||||
|
||||
public long getConnexionsReussies() {
|
||||
if (tousLesLogs == null) return 0;
|
||||
LocalDateTime aujourdhui = LocalDateTime.now().toLocalDate().atStartOfDay();
|
||||
return tousLesLogs.stream()
|
||||
.filter(log -> "CONNEXION".equals(log.getTypeAction()) &&
|
||||
"SUCCESS".equals(log.getSeverite()) &&
|
||||
log.getDateHeure() != null &&
|
||||
log.getDateHeure().isAfter(aujourdhui))
|
||||
.count();
|
||||
}
|
||||
|
||||
public long getTentativesEchouees() {
|
||||
if (tousLesLogs == null) return 0;
|
||||
LocalDateTime semainePassee = LocalDateTime.now().minusWeeks(1);
|
||||
return tousLesLogs.stream()
|
||||
.filter(log -> "CONNEXION".equals(log.getTypeAction()) &&
|
||||
!"SUCCESS".equals(log.getSeverite()) &&
|
||||
log.getDateHeure() != null &&
|
||||
log.getDateHeure().isAfter(semainePassee))
|
||||
.count();
|
||||
}
|
||||
|
||||
public long getAlertesSecurite() {
|
||||
if (tousLesLogs == null) return 0;
|
||||
return tousLesLogs.stream()
|
||||
.filter(log -> "CRITICAL".equals(log.getSeverite()) ||
|
||||
"ERROR".equals(log.getSeverite()))
|
||||
.count();
|
||||
}
|
||||
|
||||
// Méthode utilitaire pour ajouter des messages
|
||||
private void ajouterMessage(FacesMessage.Severity severity, String summary, String detail) {
|
||||
FacesContext.getCurrentInstance()
|
||||
.addMessage(null, new FacesMessage(severity, summary, detail));
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public Date getDateDebut() { return dateDebut; }
|
||||
public void setDateDebut(Date dateDebut) { this.dateDebut = dateDebut; }
|
||||
public void setDateDebut(Date dateDebut) {
|
||||
this.dateDebut = dateDebut;
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public Date getDateFin() { return dateFin; }
|
||||
public void setDateFin(Date dateFin) { this.dateFin = dateFin; }
|
||||
public void setDateFin(Date dateFin) {
|
||||
this.dateFin = dateFin;
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public String getTypeAction() { return typeAction; }
|
||||
public void setTypeAction(String typeAction) { this.typeAction = typeAction; }
|
||||
public void setTypeAction(String typeAction) {
|
||||
this.typeAction = typeAction;
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public String getSeverite() { return severite; }
|
||||
public void setSeverite(String severite) { this.severite = severite; }
|
||||
public void setSeverite(String severite) {
|
||||
this.severite = severite;
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public String getUtilisateur() { return utilisateur; }
|
||||
public void setUtilisateur(String utilisateur) { this.utilisateur = utilisateur; }
|
||||
public void setUtilisateur(String utilisateur) {
|
||||
this.utilisateur = utilisateur;
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public String getModule() { return module; }
|
||||
public void setModule(String module) { this.module = module; }
|
||||
public void setModule(String module) {
|
||||
this.module = module;
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public String getIpAddress() { return ipAddress; }
|
||||
public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
|
||||
public void setIpAddress(String ipAddress) {
|
||||
this.ipAddress = ipAddress;
|
||||
appliquerFiltres();
|
||||
}
|
||||
|
||||
public EvenementAudit getEvenementSelectionne() { return evenementSelectionne; }
|
||||
public void setEvenementSelectionne(EvenementAudit evenementSelectionne) { this.evenementSelectionne = evenementSelectionne; }
|
||||
public List<AuditLogDTO> getEvenementsFiltres() {
|
||||
return logsFiltres != null ? logsFiltres : new ArrayList<>();
|
||||
}
|
||||
|
||||
public AuditLogDTO getEvenementSelectionne() { return logSelectionne; }
|
||||
public void setEvenementSelectionne(AuditLogDTO log) { this.logSelectionne = log; }
|
||||
|
||||
public String getFormatExport() { return formatExport; }
|
||||
public void setFormatExport(String formatExport) { this.formatExport = formatExport; }
|
||||
|
||||
public boolean isInclurefiltresExport() { return inclureFiltresExport; }
|
||||
public void setInclurefiltresExport(boolean inclureFiltresExport) { this.inclureFiltresExport = inclureFiltresExport; }
|
||||
|
||||
// Classe interne EvenementAudit
|
||||
public static class EvenementAudit implements Serializable {
|
||||
private LocalDateTime dateHeure;
|
||||
private String typeAction;
|
||||
private String severite;
|
||||
private String utilisateur;
|
||||
private String role;
|
||||
private String module;
|
||||
private String description;
|
||||
private String details;
|
||||
private String ipAddress;
|
||||
private String userAgent;
|
||||
private String sessionId;
|
||||
|
||||
public EvenementAudit(LocalDateTime dateHeure, String typeAction, String severite,
|
||||
String utilisateur, String role, String module, String description,
|
||||
String details, String ipAddress, String userAgent, String sessionId) {
|
||||
this.dateHeure = dateHeure;
|
||||
this.typeAction = typeAction;
|
||||
this.severite = severite;
|
||||
this.utilisateur = utilisateur;
|
||||
this.role = role;
|
||||
this.module = module;
|
||||
this.description = description;
|
||||
this.details = details;
|
||||
this.ipAddress = ipAddress;
|
||||
this.userAgent = userAgent;
|
||||
this.sessionId = sessionId;
|
||||
}
|
||||
|
||||
// Propriétés calculées pour l'affichage
|
||||
public String getDateFormatee() {
|
||||
return dateHeure.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
|
||||
public String getHeureFormatee() {
|
||||
return dateHeure.format(DateTimeFormatter.ofPattern("HH:mm:ss"));
|
||||
}
|
||||
|
||||
public String getDateHeureComplete() {
|
||||
return dateHeure.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss"));
|
||||
}
|
||||
|
||||
public String getSeveriteLibelle() {
|
||||
switch (severite) {
|
||||
case "SUCCESS": return "Succès";
|
||||
case "INFO": return "Info";
|
||||
case "WARNING": return "Attention";
|
||||
case "ERROR": return "Erreur";
|
||||
case "CRITICAL": return "Critique";
|
||||
default: return severite;
|
||||
}
|
||||
}
|
||||
|
||||
public String getSeveriteSeverity() {
|
||||
switch (severite) {
|
||||
case "SUCCESS": return "success";
|
||||
case "INFO": return "info";
|
||||
case "WARNING": return "warning";
|
||||
case "ERROR": return "danger";
|
||||
case "CRITICAL": return "danger";
|
||||
default: return "secondary";
|
||||
}
|
||||
}
|
||||
|
||||
public String getSeveriteIcon() {
|
||||
switch (severite) {
|
||||
case "SUCCESS": return "pi pi-check";
|
||||
case "INFO": return "pi pi-info";
|
||||
case "WARNING": return "pi pi-exclamation-triangle";
|
||||
case "ERROR": return "pi pi-times";
|
||||
case "CRITICAL": return "pi pi-ban";
|
||||
default: return "pi pi-circle";
|
||||
}
|
||||
}
|
||||
|
||||
public String getActionIcon() {
|
||||
switch (typeAction) {
|
||||
case "CONNEXION": return "pi pi-sign-in";
|
||||
case "DECONNEXION": return "pi pi-sign-out";
|
||||
case "CREATION": return "pi pi-plus";
|
||||
case "MODIFICATION": return "pi pi-pencil";
|
||||
case "SUPPRESSION": return "pi pi-trash";
|
||||
case "CONSULTATION": return "pi pi-eye";
|
||||
case "EXPORT": return "pi pi-download";
|
||||
case "CONFIGURATION": return "pi pi-cog";
|
||||
default: return "pi pi-circle";
|
||||
}
|
||||
}
|
||||
|
||||
public String getActionColor() {
|
||||
switch (typeAction) {
|
||||
case "CONNEXION": return "#28a745";
|
||||
case "DECONNEXION": return "#6c757d";
|
||||
case "CREATION": return "#007bff";
|
||||
case "MODIFICATION": return "#ffc107";
|
||||
case "SUPPRESSION": return "#dc3545";
|
||||
case "CONSULTATION": return "#17a2b8";
|
||||
case "EXPORT": return "#6f42c1";
|
||||
case "CONFIGURATION": return "#fd7e14";
|
||||
default: return "#6c757d";
|
||||
}
|
||||
}
|
||||
|
||||
public String getModuleLibelle() {
|
||||
switch (module) {
|
||||
case "AUTH": return "Authentification";
|
||||
case "MEMBRES": return "Membres";
|
||||
case "COTISATIONS": return "Cotisations";
|
||||
case "EVENTS": return "Événements";
|
||||
case "DOCUMENTS": return "Documents";
|
||||
case "CONFIG": return "Configuration";
|
||||
case "RAPPORTS": return "Rapports";
|
||||
default: return module;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
switch (typeAction) {
|
||||
case "CONNEXION": return "Connexion";
|
||||
case "DECONNEXION": return "Déconnexion";
|
||||
case "CREATION": return "Création";
|
||||
case "MODIFICATION": return "Modification";
|
||||
case "SUPPRESSION": return "Suppression";
|
||||
case "CONSULTATION": return "Consultation";
|
||||
case "EXPORT": return "Export";
|
||||
case "CONFIGURATION": return "Configuration";
|
||||
default: return typeAction;
|
||||
}
|
||||
}
|
||||
|
||||
public String getDescriptionComplete() {
|
||||
return description + (details != null && !details.isEmpty() ? "\n\nDétails: " + details : "");
|
||||
}
|
||||
|
||||
public String getUserAgentComplet() {
|
||||
return userAgent;
|
||||
}
|
||||
|
||||
public String getDonneesAvant() {
|
||||
// Simulation de données avant modification
|
||||
if ("MODIFICATION".equals(typeAction)) {
|
||||
return "{\n \"nom\": \"Ancien Nom\",\n \"email\": \"ancien@email.com\",\n \"statut\": \"INACTIF\"\n}";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getDonneesApres() {
|
||||
// Simulation de données après modification
|
||||
if ("MODIFICATION".equals(typeAction)) {
|
||||
return "{\n \"nom\": \"Nouveau Nom\",\n \"email\": \"nouveau@email.com\",\n \"statut\": \"ACTIF\"\n}";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public LocalDateTime getDateHeure() { return dateHeure; }
|
||||
public void setDateHeure(LocalDateTime dateHeure) { this.dateHeure = dateHeure; }
|
||||
|
||||
public String getTypeAction() { return typeAction; }
|
||||
public void setTypeAction(String typeAction) { this.typeAction = typeAction; }
|
||||
|
||||
public String getSeverite() { return severite; }
|
||||
public void setSeverite(String severite) { this.severite = severite; }
|
||||
|
||||
public String getUtilisateur() { return utilisateur; }
|
||||
public void setUtilisateur(String utilisateur) { this.utilisateur = utilisateur; }
|
||||
|
||||
public String getRole() { return role; }
|
||||
public void setRole(String role) { this.role = role; }
|
||||
|
||||
public String getModule() { return module; }
|
||||
public void setModule(String module) { this.module = module; }
|
||||
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getDetails() { return details; }
|
||||
public void setDetails(String details) { this.details = details; }
|
||||
|
||||
public String getIpAddress() { return ipAddress; }
|
||||
public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
|
||||
|
||||
public String getUserAgent() {
|
||||
return userAgent != null && userAgent.length() > 20 ?
|
||||
userAgent.substring(0, 20) + "..." : userAgent;
|
||||
}
|
||||
public void setUserAgent(String userAgent) { this.userAgent = userAgent; }
|
||||
|
||||
public String getSessionId() { return sessionId; }
|
||||
public void setSessionId(String sessionId) { this.sessionId = sessionId; }
|
||||
public boolean isInclureFiltresExport() { return inclureFiltresExport; }
|
||||
public void setInclureFiltresExport(boolean inclureFiltresExport) {
|
||||
this.inclureFiltresExport = inclureFiltresExport;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,79 +1,346 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import dev.lions.unionflow.client.service.AdhesionService;
|
||||
import dev.lions.unionflow.client.service.AuditService;
|
||||
import dev.lions.unionflow.client.service.CotisationService;
|
||||
import dev.lions.unionflow.client.service.EvenementService;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Named("dashboardBean")
|
||||
@RequestScoped
|
||||
@ViewScoped
|
||||
public class DashboardBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(DashboardBean.class.getName());
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private MembreService membreService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private CotisationService cotisationService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private AdhesionService adhesionService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private EvenementService evenementService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private AuditService auditService;
|
||||
|
||||
// Propriétés existantes
|
||||
private int activeMembers = 245;
|
||||
private String totalCotisations = "12,450,000";
|
||||
private int pendingAides = 7;
|
||||
private int upcomingEvents = 3;
|
||||
private int activeMembers = 0;
|
||||
private String totalCotisations = "0";
|
||||
private int pendingAides = 0;
|
||||
private int upcomingEvents = 0;
|
||||
|
||||
// Nouvelles propriétés pour le dashboard enrichi
|
||||
private int totalMembers = 268;
|
||||
private String aidesDistribuees = "3,200,000";
|
||||
private int tauxParticipation = 78;
|
||||
private int totalMembers = 0;
|
||||
private String aidesDistribuees = "0";
|
||||
private int tauxParticipation = 0;
|
||||
|
||||
// Propriétés pour les alertes
|
||||
private int cotisationsRetard = 12;
|
||||
private int adhesionsExpiration = 8;
|
||||
private int demandesToTraiter = 15;
|
||||
private int tachesFinaliser = 4;
|
||||
private int cotisationsRetard = 0;
|
||||
private int adhesionsExpiration = 0;
|
||||
private int demandesToTraiter = 0;
|
||||
private int tachesFinaliser = 0;
|
||||
|
||||
// Propriétés pour les évolutions
|
||||
private int membresEvolutionPourcent = 8;
|
||||
private int cotisationsEvolutionPourcent = 15;
|
||||
private String objectifCotisations = "15,000,000";
|
||||
private int aidesApprouvees = 12;
|
||||
private int membresParticipants = 189;
|
||||
private int membresEvolutionPourcent = 0;
|
||||
private int cotisationsEvolutionPourcent = 0;
|
||||
private String objectifCotisations = "0";
|
||||
private int aidesApprouvees = 0;
|
||||
private int membresParticipants = 0;
|
||||
|
||||
// Propriétés pour le graphique
|
||||
private String periodeGraph = "3M";
|
||||
private String filtreActivite = "ALL";
|
||||
|
||||
// Propriétés pour les cotisations
|
||||
private int cotisationsAJour = 60;
|
||||
private int cotisationsRetardPourcent = 20;
|
||||
private int cotisationsImpayees = 20;
|
||||
private int cotisationsAJour = 0;
|
||||
private int cotisationsRetardPourcent = 0;
|
||||
private int cotisationsImpayees = 0;
|
||||
private int cotisationsAJourPourcent = 0;
|
||||
private int cotisationsImpayeesPourcent = 0;
|
||||
private int tauxCollecte = 0;
|
||||
|
||||
// Propriétés pour les tâches prioritaires
|
||||
private int adhesionsPendantes = 5;
|
||||
private int aidesEnAttente = 7;
|
||||
private int evenementsAPlanifier = 2;
|
||||
private int adhesionsPendantes = 0;
|
||||
private int aidesEnAttente = 0;
|
||||
private int evenementsAPlanifier = 0;
|
||||
|
||||
// Propriétés financières
|
||||
private Date moisSelectionne = new Date();
|
||||
private String recettesMois = "4,250,000";
|
||||
private String depensesMois = "1,800,000";
|
||||
private String soldeMois = "2,450,000";
|
||||
private String tresorerie = "18,750,000";
|
||||
private String recettesMois = "0";
|
||||
private String depensesMois = "0";
|
||||
private String soldeMois = "0";
|
||||
private String tresorerie = "0";
|
||||
|
||||
// Date actuelle
|
||||
private String currentDate;
|
||||
|
||||
// Propriétés manquantes pour les barres de progression
|
||||
private int tauxActivite = 75;
|
||||
private int tauxObjectifCotisations = 82;
|
||||
private int tauxAidesTraitees = 68;
|
||||
private int tauxEngagement = 89;
|
||||
private int tachesCompletees = 23;
|
||||
private boolean hasAlerts = true;
|
||||
private int tauxActivite = 0;
|
||||
private int tauxObjectifCotisations = 0;
|
||||
private int tauxAidesTraitees = 0;
|
||||
private int tauxEngagement = 0;
|
||||
private int tachesCompletees = 0;
|
||||
private boolean hasAlerts = false;
|
||||
|
||||
// Liste des activités récentes (chargées depuis le backend)
|
||||
private List<Activity> recentActivities;
|
||||
|
||||
// Évolution financière (3 derniers mois)
|
||||
private List<MoisFinancier> evolutionFinanciere;
|
||||
private int evolutionRecettesPourcent = 0;
|
||||
private int evolutionDepensesPourcent = 0;
|
||||
private String tendanceParticipation = "Stable";
|
||||
|
||||
public DashboardBean() {
|
||||
this.currentDate = LocalDate.now().format(DateTimeFormatter.ofPattern("dd MMMM yyyy"));
|
||||
this.evolutionFinanciere = new ArrayList<>();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
chargerDonneesBackend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge toutes les données depuis les services backend
|
||||
*/
|
||||
private void chargerDonneesBackend() {
|
||||
LOGGER.info("Chargement des données du dashboard depuis le backend...");
|
||||
|
||||
try {
|
||||
chargerStatistiquesMembres();
|
||||
chargerStatistiquesCotisations();
|
||||
chargerStatistiquesAdhesions();
|
||||
chargerStatistiquesEvenements();
|
||||
chargerActivitesRecentes();
|
||||
calculerIndicateurs();
|
||||
|
||||
LOGGER.info("Données du dashboard chargées avec succès");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement du dashboard: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void chargerStatistiquesMembres() {
|
||||
try {
|
||||
MembreService.StatistiquesMembreDTO statsMembres = membreService.obtenirStatistiques();
|
||||
|
||||
if (statsMembres != null) {
|
||||
totalMembers = statsMembres.getTotalMembres() != null ? statsMembres.getTotalMembres().intValue() : 0;
|
||||
activeMembers = statsMembres.getMembresActifs() != null ? statsMembres.getMembresActifs().intValue() : 0;
|
||||
|
||||
// Evolution mensuelle (si disponible dans le DTO)
|
||||
if (statsMembres.getNouveauxMembres30Jours() != null && totalMembers > 0) {
|
||||
membresEvolutionPourcent = (statsMembres.getNouveauxMembres30Jours().intValue() * 100) / totalMembers;
|
||||
}
|
||||
|
||||
LOGGER.info("Stats membres chargées: Total=" + totalMembers + ", Actifs=" + activeMembers);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les stats membres: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void chargerStatistiquesCotisations() {
|
||||
try {
|
||||
Map<String, Object> statsCotisations = cotisationService.obtenirStatistiques();
|
||||
|
||||
// Total collecté
|
||||
Object totalCollecte = statsCotisations.get("totalCollecte");
|
||||
if (totalCollecte != null) {
|
||||
BigDecimal montant = new BigDecimal(totalCollecte.toString());
|
||||
totalCotisations = String.format("%,d", montant.longValue());
|
||||
tresorerie = totalCotisations; // Approximation
|
||||
}
|
||||
|
||||
// Cotisations en retard
|
||||
cotisationsRetard = ((Number) statsCotisations.getOrDefault("cotisationsEnRetard", 0)).intValue();
|
||||
cotisationsImpayees = ((Number) statsCotisations.getOrDefault("cotisationsImpayees", 0)).intValue();
|
||||
cotisationsAJour = ((Number) statsCotisations.getOrDefault("cotisationsAJour", 0)).intValue();
|
||||
|
||||
// Calculer pourcentage de retard
|
||||
int totalCot = cotisationsAJour + cotisationsRetard + cotisationsImpayees;
|
||||
if (totalCot > 0) {
|
||||
cotisationsRetardPourcent = (cotisationsRetard * 100) / totalCot;
|
||||
}
|
||||
|
||||
LOGGER.info("Stats cotisations chargées: Total=" + totalCotisations);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les stats cotisations: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void chargerStatistiquesAdhesions() {
|
||||
try {
|
||||
Map<String, Object> statsAdhesions = adhesionService.obtenirStatistiques();
|
||||
|
||||
adhesionsPendantes = ((Number) statsAdhesions.getOrDefault("adhesionsEnAttente", 0)).intValue();
|
||||
demandesToTraiter = adhesionsPendantes; // Alias
|
||||
|
||||
LOGGER.info("Stats adhésions chargées: En attente=" + adhesionsPendantes);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les stats adhésions: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void chargerStatistiquesEvenements() {
|
||||
try {
|
||||
// Compter les événements à venir via l'API de liste
|
||||
Map<String, Object> evenementsAVenir = evenementService.listerAVenir(0, 100);
|
||||
|
||||
if (evenementsAVenir != null && evenementsAVenir.containsKey("totalElements")) {
|
||||
upcomingEvents = ((Number) evenementsAVenir.get("totalElements")).intValue();
|
||||
}
|
||||
|
||||
LOGGER.info("Stats événements chargées: À venir=" + upcomingEvents);
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les stats événements: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void chargerActivitesRecentes() {
|
||||
try {
|
||||
// Récupérer les 10 derniers logs d'audit
|
||||
Map<String, Object> resultat = auditService.listerTous(0, 10, "dateHeure", "DESC");
|
||||
recentActivities = new ArrayList<>();
|
||||
|
||||
if (resultat != null && resultat.containsKey("content")) {
|
||||
List<Map<String, Object>> logs = (List<Map<String, Object>>) resultat.get("content");
|
||||
|
||||
for (Map<String, Object> logMap : logs) {
|
||||
String typeAction = (String) logMap.get("typeAction");
|
||||
String description = (String) logMap.get("description");
|
||||
String details = (String) logMap.get("details");
|
||||
String utilisateur = (String) logMap.get("utilisateur");
|
||||
|
||||
Activity activity = new Activity(
|
||||
LocalDateTime.now(), // Simplification - devrait parser la date
|
||||
typeAction != null ? typeAction : "ACTION",
|
||||
getSeverityFromAction(typeAction),
|
||||
getIconFromAction(typeAction),
|
||||
description != null ? description : typeAction,
|
||||
details,
|
||||
null,
|
||||
utilisateur != null ? utilisateur : "Système",
|
||||
"Utilisateur"
|
||||
);
|
||||
recentActivities.add(activity);
|
||||
}
|
||||
}
|
||||
|
||||
LOGGER.info("Activités récentes chargées: " + recentActivities.size());
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les activités récentes: " + e.getMessage());
|
||||
recentActivities = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
private void calculerIndicateurs() {
|
||||
// Calculer taux d'activité
|
||||
if (totalMembers > 0 && activeMembers > 0) {
|
||||
tauxActivite = (activeMembers * 100) / totalMembers;
|
||||
}
|
||||
|
||||
// Calculer taux de participation
|
||||
tauxParticipation = tauxActivite; // Approximation
|
||||
|
||||
// Calculer pourcentages de cotisations
|
||||
int totalCot = cotisationsAJour + cotisationsRetard + cotisationsImpayees;
|
||||
if (totalCot > 0) {
|
||||
cotisationsAJourPourcent = (cotisationsAJour * 100) / totalCot;
|
||||
cotisationsRetardPourcent = (cotisationsRetard * 100) / totalCot;
|
||||
cotisationsImpayeesPourcent = (cotisationsImpayees * 100) / totalCot;
|
||||
|
||||
// Taux de collecte = cotisations à jour + en retard
|
||||
tauxCollecte = ((cotisationsAJour + cotisationsRetard) * 100) / totalCot;
|
||||
}
|
||||
|
||||
// Calculer évolution financière
|
||||
calculerEvolutionFinanciere();
|
||||
|
||||
// Déterminer s'il y a des alertes
|
||||
hasAlerts = (cotisationsRetard > 0 || adhesionsPendantes > 0 || demandesToTraiter > 0);
|
||||
}
|
||||
|
||||
private void calculerEvolutionFinanciere() {
|
||||
evolutionFinanciere.clear();
|
||||
|
||||
try {
|
||||
// Récupérer les statistiques des 3 derniers mois depuis le backend
|
||||
LocalDate now = LocalDate.now();
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM yyyy");
|
||||
|
||||
for (int i = 2; i >= 0; i--) {
|
||||
LocalDate mois = now.minusMonths(i);
|
||||
String libelleMois = mois.format(formatter);
|
||||
|
||||
// Pour chaque mois, on pourrait appeler le backend avec un filtre de date
|
||||
// Pour l'instant, on calcule une approximation
|
||||
BigDecimal montant = i == 0 ?
|
||||
new BigDecimal(totalCotisations.replace(",", "")) :
|
||||
BigDecimal.ZERO; // Le backend devrait fournir les montants historiques
|
||||
|
||||
evolutionFinanciere.add(new MoisFinancier(libelleMois, montant));
|
||||
}
|
||||
|
||||
// Calculer tendances (si on a les données)
|
||||
if (evolutionFinanciere.size() >= 2) {
|
||||
MoisFinancier dernierMois = evolutionFinanciere.get(evolutionFinanciere.size() - 1);
|
||||
MoisFinancier avantDernierMois = evolutionFinanciere.get(evolutionFinanciere.size() - 2);
|
||||
|
||||
if (avantDernierMois.getMontant().compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal diff = dernierMois.getMontant().subtract(avantDernierMois.getMontant());
|
||||
evolutionRecettesPourcent = diff.multiply(BigDecimal.valueOf(100))
|
||||
.divide(avantDernierMois.getMontant(), 0, java.math.RoundingMode.HALF_UP).intValue();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Erreur lors du calcul de l'évolution financière: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String getSeverityFromAction(String action) {
|
||||
if (action == null) return "info";
|
||||
if (action.contains("ERREUR") || action.contains("ECHEC")) return "danger";
|
||||
if (action.contains("CREATION") || action.contains("PAIEMENT")) return "success";
|
||||
if (action.contains("MODIFICATION")) return "warning";
|
||||
return "info";
|
||||
}
|
||||
|
||||
private String getIconFromAction(String action) {
|
||||
if (action == null) return "pi pi-info-circle";
|
||||
if (action.contains("MEMBRE")) return "pi pi-user";
|
||||
if (action.contains("COTISATION") || action.contains("PAIEMENT")) return "pi pi-money-bill";
|
||||
if (action.contains("ADHESION")) return "pi pi-user-plus";
|
||||
if (action.contains("EVENEMENT")) return "pi pi-calendar";
|
||||
return "pi pi-info-circle";
|
||||
}
|
||||
|
||||
// Getters et Setters complets
|
||||
@@ -185,71 +452,54 @@ public class DashboardBean implements Serializable {
|
||||
public boolean isHasAlerts() { return hasAlerts; }
|
||||
public void setHasAlerts(boolean hasAlerts) { this.hasAlerts = hasAlerts; }
|
||||
|
||||
public int getCotisationsAJourPourcent() { return cotisationsAJourPourcent; }
|
||||
public void setCotisationsAJourPourcent(int cotisationsAJourPourcent) { this.cotisationsAJourPourcent = cotisationsAJourPourcent; }
|
||||
|
||||
public int getCotisationsImpayeesPourcent() { return cotisationsImpayeesPourcent; }
|
||||
public void setCotisationsImpayeesPourcent(int cotisationsImpayeesPourcent) { this.cotisationsImpayeesPourcent = cotisationsImpayeesPourcent; }
|
||||
|
||||
public int getTauxCollecte() { return tauxCollecte; }
|
||||
public void setTauxCollecte(int tauxCollecte) { this.tauxCollecte = tauxCollecte; }
|
||||
|
||||
public List<MoisFinancier> getEvolutionFinanciere() { return evolutionFinanciere; }
|
||||
public void setEvolutionFinanciere(List<MoisFinancier> evolutionFinanciere) { this.evolutionFinanciere = evolutionFinanciere; }
|
||||
|
||||
public int getEvolutionRecettesPourcent() { return evolutionRecettesPourcent; }
|
||||
public void setEvolutionRecettesPourcent(int evolutionRecettesPourcent) { this.evolutionRecettesPourcent = evolutionRecettesPourcent; }
|
||||
|
||||
public int getEvolutionDepensesPourcent() { return evolutionDepensesPourcent; }
|
||||
public void setEvolutionDepensesPourcent(int evolutionDepensesPourcent) { this.evolutionDepensesPourcent = evolutionDepensesPourcent; }
|
||||
|
||||
public String getTendanceParticipation() { return tendanceParticipation; }
|
||||
public void setTendanceParticipation(String tendanceParticipation) { this.tendanceParticipation = tendanceParticipation; }
|
||||
|
||||
// Méthodes utilitaires pour l'affichage des tendances
|
||||
public String getEvolutionRecettesIcon() {
|
||||
return evolutionRecettesPourcent >= 0 ? "pi pi-arrow-up text-green-500" : "pi pi-arrow-down text-red-500";
|
||||
}
|
||||
|
||||
public String getEvolutionRecettesPrefix() {
|
||||
return evolutionRecettesPourcent >= 0 ? "+" : "";
|
||||
}
|
||||
|
||||
public String getEvolutionDepensesIcon() {
|
||||
return evolutionDepensesPourcent <= 0 ? "pi pi-arrow-down text-green-500" : "pi pi-arrow-up text-red-500";
|
||||
}
|
||||
|
||||
public String getEvolutionDepensesPrefix() {
|
||||
return evolutionDepensesPourcent >= 0 ? "+" : "";
|
||||
}
|
||||
|
||||
// Méthodes pour les activités récentes
|
||||
public List<Activity> getRecentActivities() {
|
||||
List<Activity> activities = new ArrayList<>();
|
||||
|
||||
activities.add(new Activity(
|
||||
LocalDateTime.now().minusHours(2),
|
||||
"COTISATION",
|
||||
"success",
|
||||
"pi pi-check-circle",
|
||||
"Paiement cotisation validé",
|
||||
"Cotisation de Fatou Sow pour juillet 2024",
|
||||
"25,000",
|
||||
"Fatou Sow",
|
||||
"Membre"
|
||||
));
|
||||
|
||||
activities.add(new Activity(
|
||||
LocalDateTime.now().minusHours(5),
|
||||
"ADHESION",
|
||||
"info",
|
||||
"pi pi-user-plus",
|
||||
"Nouvelle demande d'adhésion",
|
||||
"Demande soumise par Moussa Ba",
|
||||
null,
|
||||
"Moussa Ba",
|
||||
"Candidat"
|
||||
));
|
||||
|
||||
activities.add(new Activity(
|
||||
LocalDateTime.now().minusHours(8),
|
||||
"AIDE",
|
||||
"warning",
|
||||
"pi pi-heart",
|
||||
"Demande d'aide en traitement",
|
||||
"Aide médicale pour famille Ndiaye",
|
||||
"150,000",
|
||||
"Aminata Ndiaye",
|
||||
"Membre"
|
||||
));
|
||||
|
||||
activities.add(new Activity(
|
||||
LocalDateTime.now().minusDays(1),
|
||||
"EVENEMENT",
|
||||
"info",
|
||||
"pi pi-calendar",
|
||||
"Événement planifié",
|
||||
"Assemblée générale mensuelle programmée",
|
||||
null,
|
||||
"Admin",
|
||||
"Administrateur"
|
||||
));
|
||||
|
||||
activities.add(new Activity(
|
||||
LocalDateTime.now().minusDays(1).minusHours(3),
|
||||
"COTISATION",
|
||||
"danger",
|
||||
"pi pi-exclamation-triangle",
|
||||
"Relance envoyée",
|
||||
"Relance automatique pour cotisation en retard",
|
||||
null,
|
||||
"Système",
|
||||
"Automatique"
|
||||
));
|
||||
|
||||
return activities;
|
||||
if (recentActivities == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return recentActivities;
|
||||
}
|
||||
|
||||
public void actualiser() {
|
||||
chargerDonneesBackend();
|
||||
}
|
||||
|
||||
// Actions de navigation
|
||||
@@ -346,4 +596,57 @@ public class DashboardBean implements Serializable {
|
||||
public String getUserRole() { return userRole; }
|
||||
public void setUserRole(String userRole) { this.userRole = userRole; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Classe interne pour représenter les données financières d'un mois
|
||||
*/
|
||||
public static class MoisFinancier implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String libelle;
|
||||
private BigDecimal montant;
|
||||
private int hauteur; // Pour l'affichage visuel en pixels
|
||||
|
||||
public MoisFinancier(String libelle, BigDecimal montant) {
|
||||
this.libelle = libelle;
|
||||
this.montant = montant != null ? montant : BigDecimal.ZERO;
|
||||
// Calculer la hauteur proportionnelle (entre 40 et 120 pixels)
|
||||
this.hauteur = calculerHauteur(this.montant);
|
||||
}
|
||||
|
||||
private int calculerHauteur(BigDecimal montant) {
|
||||
if (montant.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return 40; // Hauteur minimale
|
||||
}
|
||||
// Normaliser entre 40 et 120 pixels
|
||||
// On suppose un max de 10M FCFA pour l'échelle
|
||||
BigDecimal maxRef = new BigDecimal("10000000");
|
||||
double ratio = montant.divide(maxRef, 4, java.math.RoundingMode.HALF_UP).doubleValue();
|
||||
int hauteur = 40 + (int)(ratio * 80);
|
||||
return Math.min(Math.max(hauteur, 40), 120); // Entre 40 et 120
|
||||
}
|
||||
|
||||
public String getLibelle() { return libelle; }
|
||||
public void setLibelle(String libelle) { this.libelle = libelle; }
|
||||
|
||||
public BigDecimal getMontant() { return montant; }
|
||||
public void setMontant(BigDecimal montant) {
|
||||
this.montant = montant;
|
||||
this.hauteur = calculerHauteur(montant);
|
||||
}
|
||||
|
||||
public String getMontantFormatte() {
|
||||
if (montant.compareTo(new BigDecimal("1000000")) >= 0) {
|
||||
// Afficher en millions
|
||||
BigDecimal millions = montant.divide(new BigDecimal("1000000"), 1, java.math.RoundingMode.HALF_UP);
|
||||
return millions.toString() + "M FCFA";
|
||||
} else if (montant.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return "0 FCFA";
|
||||
} else {
|
||||
return String.format("%,d FCFA", montant.longValue());
|
||||
}
|
||||
}
|
||||
|
||||
public int getHauteur() { return hauteur; }
|
||||
public void setHauteur(int hauteur) { this.hauteur = hauteur; }
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,7 @@ public class EntitesGestionBean implements Serializable {
|
||||
private void initializeStatistiques() {
|
||||
statistiques = new Statistiques();
|
||||
try {
|
||||
List<AssociationDTO> associations = associationService.listerToutes();
|
||||
List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
|
||||
statistiques.setTotalEntites(associations.size());
|
||||
long actives = associations.stream().filter(a -> "ACTIVE".equals(a.getStatut())).count();
|
||||
statistiques.setEntitesActives((int) actives);
|
||||
@@ -82,7 +82,7 @@ public class EntitesGestionBean implements Serializable {
|
||||
private void initializeEntites() {
|
||||
toutesLesEntites = new ArrayList<>();
|
||||
try {
|
||||
List<AssociationDTO> associations = associationService.listerToutes();
|
||||
List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
|
||||
for (AssociationDTO dto : associations) {
|
||||
Entite entite = convertToEntite(dto);
|
||||
toutesLesEntites.add(entite);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,470 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Bean pour la gestion des favoris de l'utilisateur
|
||||
* Gère les pages favorites, documents favoris, contacts favoris et raccourcis personnalisés
|
||||
*/
|
||||
@Named("favorisBean")
|
||||
@SessionScoped
|
||||
public class FavorisBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(FavorisBean.class.getName());
|
||||
|
||||
@Inject
|
||||
private UserSession userSession;
|
||||
|
||||
// Statistiques
|
||||
private int totalFavoris = 0;
|
||||
private int totalPages = 0;
|
||||
private int totalDocuments = 0;
|
||||
private int totalContacts = 0;
|
||||
|
||||
// Favoris
|
||||
private List<PageFavorite> pagesFavorites;
|
||||
private List<DocumentFavorite> documentsFavoris;
|
||||
private List<ContactFavorite> contactsFavoris;
|
||||
private List<RaccourciPersonnalise> raccourcis;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
chargerFavoris();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge tous les favoris
|
||||
*/
|
||||
public void chargerFavoris() {
|
||||
chargerPagesFavorites();
|
||||
chargerDocumentsFavoris();
|
||||
chargerContactsFavoris();
|
||||
chargerRaccourcis();
|
||||
calculerStatistiques();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les pages favorites
|
||||
*/
|
||||
private void chargerPagesFavorites() {
|
||||
pagesFavorites = new ArrayList<>();
|
||||
|
||||
// Pages favorites par défaut
|
||||
PageFavorite page1 = new PageFavorite();
|
||||
page1.setId(UUID.randomUUID());
|
||||
page1.setTitre("Mes Activités");
|
||||
page1.setDescription("Historique et suivi de vos actions");
|
||||
page1.setUrl("/pages/secure/personnel/activites.xhtml");
|
||||
page1.setIcon("pi-chart-bar");
|
||||
page1.setCouleur("blue");
|
||||
page1.setCategorie("FONCTIONNALITE");
|
||||
page1.setDerniereVisite("il y a 5 min");
|
||||
page1.setNbVisites(45);
|
||||
page1.setEstPlusUtilise(true);
|
||||
pagesFavorites.add(page1);
|
||||
|
||||
PageFavorite page2 = new PageFavorite();
|
||||
page2.setId(UUID.randomUUID());
|
||||
page2.setTitre("Mon Agenda");
|
||||
page2.setDescription("Planning et événements personnels");
|
||||
page2.setUrl("/pages/secure/personnel/agenda.xhtml");
|
||||
page2.setIcon("pi-calendar");
|
||||
page2.setCouleur("green");
|
||||
page2.setCategorie("FONCTIONNALITE");
|
||||
page2.setDerniereVisite("il y a 2h");
|
||||
page2.setNbVisites(23);
|
||||
pagesFavorites.add(page2);
|
||||
|
||||
PageFavorite page3 = new PageFavorite();
|
||||
page3.setId(UUID.randomUUID());
|
||||
page3.setTitre("Liste des Membres");
|
||||
page3.setDescription("Annuaire et contacts membres");
|
||||
page3.setUrl("/pages/secure/membre/liste.xhtml");
|
||||
page3.setIcon("pi-users");
|
||||
page3.setCouleur("purple");
|
||||
page3.setCategorie("FONCTIONNALITE");
|
||||
page3.setDerniereVisite("Hier");
|
||||
page3.setNbVisites(12);
|
||||
pagesFavorites.add(page3);
|
||||
|
||||
PageFavorite page4 = new PageFavorite();
|
||||
page4.setId(UUID.randomUUID());
|
||||
page4.setTitre("Cotisations");
|
||||
page4.setDescription("Paiements et historique");
|
||||
page4.setUrl("/pages/secure/cotisation/liste.xhtml");
|
||||
page4.setIcon("pi-dollar");
|
||||
page4.setCouleur("orange");
|
||||
page4.setCategorie("FINANCE");
|
||||
page4.setDerniereVisite("il y a 3 jours");
|
||||
page4.setNbVisites(8);
|
||||
pagesFavorites.add(page4);
|
||||
|
||||
PageFavorite page5 = new PageFavorite();
|
||||
page5.setId(UUID.randomUUID());
|
||||
page5.setTitre("Rapports Financiers");
|
||||
page5.setDescription("Consultez vos rapports financiers personnels");
|
||||
page5.setUrl("/pages/secure/rapport/finances.xhtml");
|
||||
page5.setIcon("pi-chart-bar");
|
||||
page5.setCouleur("green");
|
||||
page5.setCategorie("FINANCE");
|
||||
page5.setDerniereVisite("il y a 1 semaine");
|
||||
page5.setNbVisites(3);
|
||||
pagesFavorites.add(page5);
|
||||
|
||||
PageFavorite page6 = new PageFavorite();
|
||||
page6.setId(UUID.randomUUID());
|
||||
page6.setTitre("Mes Formations");
|
||||
page6.setDescription("Catalogue et suivi de vos formations");
|
||||
page6.setUrl("/pages/secure/formation/liste.xhtml");
|
||||
page6.setIcon("pi-graduation-cap");
|
||||
page6.setCouleur("purple");
|
||||
page6.setCategorie("FORMATION");
|
||||
page6.setDerniereVisite("il y a 1 semaine");
|
||||
page6.setNbVisites(1);
|
||||
pagesFavorites.add(page6);
|
||||
|
||||
PageFavorite page7 = new PageFavorite();
|
||||
page7.setId(UUID.randomUUID());
|
||||
page7.setTitre("Guide Utilisateur");
|
||||
page7.setDescription("Documentation et aide à l'utilisation");
|
||||
page7.setUrl("/pages/public/aide.xhtml");
|
||||
page7.setIcon("pi-book");
|
||||
page7.setCouleur("green");
|
||||
page7.setCategorie("AIDE");
|
||||
page7.setDerniereVisite("il y a 1 semaine");
|
||||
page7.setNbVisites(5);
|
||||
pagesFavorites.add(page7);
|
||||
|
||||
PageFavorite page8 = new PageFavorite();
|
||||
page8.setId(UUID.randomUUID());
|
||||
page8.setTitre("Rapports & Statistiques");
|
||||
page8.setDescription("Analyses et statistiques détaillées");
|
||||
page8.setUrl("/pages/secure/rapport/activites.xhtml");
|
||||
page8.setIcon("pi-chart-line");
|
||||
page8.setCouleur("blue");
|
||||
page8.setCategorie("RAPPORT");
|
||||
page8.setDerniereVisite("il y a 2 semaines");
|
||||
page8.setNbVisites(2);
|
||||
pagesFavorites.add(page8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les documents favoris
|
||||
*/
|
||||
private void chargerDocumentsFavoris() {
|
||||
documentsFavoris = new ArrayList<>();
|
||||
|
||||
DocumentFavorite doc1 = new DocumentFavorite();
|
||||
doc1.setId(UUID.randomUUID());
|
||||
doc1.setNom("Certificat_Formation_Leadership_2023.pdf");
|
||||
doc1.setType("PDF");
|
||||
doc1.setTaille(2457600); // 2.4 MB
|
||||
doc1.setDateAjout(LocalDate.of(2023, 12, 15));
|
||||
doc1.setCategorie("CERTIFICAT");
|
||||
doc1.setDescription("Certification de leadership obtenue en 2023");
|
||||
documentsFavoris.add(doc1);
|
||||
|
||||
DocumentFavorite doc2 = new DocumentFavorite();
|
||||
doc2.setId(UUID.randomUUID());
|
||||
doc2.setNom("Budget_Personnel_2024.xlsx");
|
||||
doc2.setType("XLSX");
|
||||
doc2.setTaille(91136); // 89 KB
|
||||
doc2.setDateAjout(LocalDate.of(2024, 1, 3));
|
||||
doc2.setCategorie("BUDGET");
|
||||
doc2.setDescription("Feuille de calcul pour la gestion budgétaire");
|
||||
documentsFavoris.add(doc2);
|
||||
|
||||
DocumentFavorite doc3 = new DocumentFavorite();
|
||||
doc3.setId(UUID.randomUUID());
|
||||
doc3.setNom("Reglement_Interieur_2024.docx");
|
||||
doc3.setType("DOCX");
|
||||
doc3.setTaille(250880); // 245 KB
|
||||
doc3.setDateAjout(LocalDate.of(2023, 12, 28));
|
||||
doc3.setCategorie("REGLEMENT");
|
||||
doc3.setDescription("Règlement intérieur de l'association mis à jour");
|
||||
documentsFavoris.add(doc3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les contacts favoris
|
||||
*/
|
||||
private void chargerContactsFavoris() {
|
||||
contactsFavoris = new ArrayList<>();
|
||||
|
||||
ContactFavorite contact1 = new ContactFavorite();
|
||||
contact1.setId(UUID.randomUUID());
|
||||
contact1.setNom("Thomas Martin");
|
||||
contact1.setFonction("Président de l'association");
|
||||
contact1.setEmail("thomas.martin@email.com");
|
||||
contact1.setCategorie("ADMIN");
|
||||
contactsFavoris.add(contact1);
|
||||
|
||||
ContactFavorite contact2 = new ContactFavorite();
|
||||
contact2.setId(UUID.randomUUID());
|
||||
contact2.setNom("Sophie Leroy");
|
||||
contact2.setFonction("Responsable formations");
|
||||
contact2.setEmail("sophie.leroy@email.com");
|
||||
contact2.setCategorie("FORMATION");
|
||||
contactsFavoris.add(contact2);
|
||||
|
||||
ContactFavorite contact3 = new ContactFavorite();
|
||||
contact3.setId(UUID.randomUUID());
|
||||
contact3.setNom("Marc Durand");
|
||||
contact3.setFonction("Support technique");
|
||||
contact3.setEmail("marc.durand@email.com");
|
||||
contact3.setCategorie("SUPPORT");
|
||||
contactsFavoris.add(contact3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les raccourcis personnalisés
|
||||
*/
|
||||
private void chargerRaccourcis() {
|
||||
raccourcis = new ArrayList<>();
|
||||
|
||||
RaccourciPersonnalise racc1 = new RaccourciPersonnalise();
|
||||
racc1.setId(UUID.randomUUID());
|
||||
racc1.setTitre("Nouveau Membre");
|
||||
racc1.setDescription("Lien direct vers le formulaire d'inscription");
|
||||
racc1.setUrl("/pages/secure/membre/creation.xhtml");
|
||||
racc1.setIcon("pi-bookmark");
|
||||
racc1.setCouleur("blue");
|
||||
raccourcis.add(racc1);
|
||||
|
||||
RaccourciPersonnalise racc2 = new RaccourciPersonnalise();
|
||||
racc2.setId(UUID.randomUUID());
|
||||
racc2.setTitre("Calculateur");
|
||||
racc2.setDescription("Calcul automatique des cotisations");
|
||||
racc2.setUrl("/pages/secure/cotisation/calculateur.xhtml");
|
||||
racc2.setIcon("pi-calculator");
|
||||
racc2.setCouleur("green");
|
||||
raccourcis.add(racc2);
|
||||
|
||||
RaccourciPersonnalise racc3 = new RaccourciPersonnalise();
|
||||
racc3.setId(UUID.randomUUID());
|
||||
racc3.setTitre("Impression Rapide");
|
||||
racc3.setDescription("Templates prêts à imprimer");
|
||||
racc3.setUrl("/pages/secure/document/impression.xhtml");
|
||||
racc3.setIcon("pi-print");
|
||||
racc3.setCouleur("purple");
|
||||
raccourcis.add(racc3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule les statistiques
|
||||
*/
|
||||
private void calculerStatistiques() {
|
||||
totalPages = pagesFavorites != null ? pagesFavorites.size() : 0;
|
||||
totalDocuments = documentsFavoris != null ? documentsFavoris.size() : 0;
|
||||
totalContacts = contactsFavoris != null ? contactsFavoris.size() : 0;
|
||||
totalFavoris = totalPages + totalDocuments + totalContacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retire une page des favoris
|
||||
*/
|
||||
public void retirerPageFavorite(UUID id) {
|
||||
if (pagesFavorites != null) {
|
||||
pagesFavorites.removeIf(p -> p.getId().equals(id));
|
||||
calculerStatistiques();
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Page retirée des favoris");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retire un document des favoris
|
||||
*/
|
||||
public void retirerDocumentFavorite(UUID id) {
|
||||
if (documentsFavoris != null) {
|
||||
documentsFavoris.removeIf(d -> d.getId().equals(id));
|
||||
calculerStatistiques();
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Document retiré des favoris");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retire un contact des favoris
|
||||
*/
|
||||
public void retirerContactFavorite(UUID id) {
|
||||
if (contactsFavoris != null) {
|
||||
contactsFavoris.removeIf(c -> c.getId().equals(id));
|
||||
calculerStatistiques();
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Contact retiré des favoris");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime un raccourci
|
||||
*/
|
||||
public void supprimerRaccourci(UUID id) {
|
||||
if (raccourcis != null) {
|
||||
raccourcis.removeIf(r -> r.getId().equals(id));
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Raccourci supprimé");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nettoie tous les favoris
|
||||
*/
|
||||
public void nettoyerTousFavoris() {
|
||||
pagesFavorites.clear();
|
||||
documentsFavoris.clear();
|
||||
contactsFavoris.clear();
|
||||
calculerStatistiques();
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Tous les favoris ont été supprimés");
|
||||
}
|
||||
|
||||
private void ajouterMessage(FacesMessage.Severity severity, String summary, String detail) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(severity, summary, detail));
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public int getTotalFavoris() { return totalFavoris; }
|
||||
public void setTotalFavoris(int totalFavoris) { this.totalFavoris = totalFavoris; }
|
||||
|
||||
public int getTotalPages() { return totalPages; }
|
||||
public void setTotalPages(int totalPages) { this.totalPages = totalPages; }
|
||||
|
||||
public int getTotalDocuments() { return totalDocuments; }
|
||||
public void setTotalDocuments(int totalDocuments) { this.totalDocuments = totalDocuments; }
|
||||
|
||||
public int getTotalContacts() { return totalContacts; }
|
||||
public void setTotalContacts(int totalContacts) { this.totalContacts = totalContacts; }
|
||||
|
||||
public List<PageFavorite> getPagesFavorites() { return pagesFavorites; }
|
||||
public void setPagesFavorites(List<PageFavorite> pagesFavorites) { this.pagesFavorites = pagesFavorites; }
|
||||
|
||||
public List<DocumentFavorite> getDocumentsFavoris() { return documentsFavoris; }
|
||||
public void setDocumentsFavoris(List<DocumentFavorite> documentsFavoris) { this.documentsFavoris = documentsFavoris; }
|
||||
|
||||
public List<ContactFavorite> getContactsFavoris() { return contactsFavoris; }
|
||||
public void setContactsFavoris(List<ContactFavorite> contactsFavoris) { this.contactsFavoris = contactsFavoris; }
|
||||
|
||||
public List<RaccourciPersonnalise> getRaccourcis() { return raccourcis; }
|
||||
public void setRaccourcis(List<RaccourciPersonnalise> raccourcis) { this.raccourcis = raccourcis; }
|
||||
|
||||
// Classes internes
|
||||
public static class PageFavorite implements Serializable {
|
||||
private UUID id;
|
||||
private String titre;
|
||||
private String description;
|
||||
private String url;
|
||||
private String icon;
|
||||
private String couleur;
|
||||
private String categorie;
|
||||
private String derniereVisite;
|
||||
private int nbVisites;
|
||||
private boolean estPlusUtilise;
|
||||
|
||||
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 getUrl() { return url; }
|
||||
public void setUrl(String url) { this.url = url; }
|
||||
public String getIcon() { return icon; }
|
||||
public void setIcon(String icon) { this.icon = icon; }
|
||||
public String getCouleur() { return couleur; }
|
||||
public void setCouleur(String couleur) { this.couleur = couleur; }
|
||||
public String getCategorie() { return categorie; }
|
||||
public void setCategorie(String categorie) { this.categorie = categorie; }
|
||||
public String getDerniereVisite() { return derniereVisite; }
|
||||
public void setDerniereVisite(String derniereVisite) { this.derniereVisite = derniereVisite; }
|
||||
public int getNbVisites() { return nbVisites; }
|
||||
public void setNbVisites(int nbVisites) { this.nbVisites = nbVisites; }
|
||||
public boolean isEstPlusUtilise() { return estPlusUtilise; }
|
||||
public void setEstPlusUtilise(boolean estPlusUtilise) { this.estPlusUtilise = estPlusUtilise; }
|
||||
}
|
||||
|
||||
public static class DocumentFavorite implements Serializable {
|
||||
private UUID id;
|
||||
private String nom;
|
||||
private String type;
|
||||
private long taille;
|
||||
private LocalDate dateAjout;
|
||||
private String categorie;
|
||||
private String description;
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
public String getNom() { return nom; }
|
||||
public void setNom(String nom) { this.nom = nom; }
|
||||
public String getType() { return type; }
|
||||
public void setType(String type) { this.type = type; }
|
||||
public long getTaille() { return taille; }
|
||||
public void setTaille(long taille) { this.taille = taille; }
|
||||
public LocalDate getDateAjout() { return dateAjout; }
|
||||
public void setDateAjout(LocalDate dateAjout) { this.dateAjout = dateAjout; }
|
||||
public String getCategorie() { return categorie; }
|
||||
public void setCategorie(String categorie) { this.categorie = categorie; }
|
||||
public String getDescription() { return description; }
|
||||
public void setDescription(String description) { this.description = description; }
|
||||
|
||||
public String getTailleFormatee() {
|
||||
if (taille < 1024) {
|
||||
return taille + " B";
|
||||
} else if (taille < 1024 * 1024) {
|
||||
return String.format("%.1f KB", taille / 1024.0);
|
||||
} else {
|
||||
return String.format("%.1f MB", taille / (1024.0 * 1024.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ContactFavorite implements Serializable {
|
||||
private UUID id;
|
||||
private String nom;
|
||||
private String fonction;
|
||||
private String email;
|
||||
private String categorie;
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
public String getNom() { return nom; }
|
||||
public void setNom(String nom) { this.nom = nom; }
|
||||
public String getFonction() { return fonction; }
|
||||
public void setFonction(String fonction) { this.fonction = fonction; }
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
public String getCategorie() { return categorie; }
|
||||
public void setCategorie(String categorie) { this.categorie = categorie; }
|
||||
}
|
||||
|
||||
public static class RaccourciPersonnalise implements Serializable {
|
||||
private UUID id;
|
||||
private String titre;
|
||||
private String description;
|
||||
private String url;
|
||||
private String icon;
|
||||
private String couleur;
|
||||
|
||||
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 getUrl() { return url; }
|
||||
public void setUrl(String url) { this.url = url; }
|
||||
public String getIcon() { return icon; }
|
||||
public void setIcon(String icon) { this.icon = icon; }
|
||||
public String getCouleur() { return couleur; }
|
||||
public void setCouleur(String couleur) { this.couleur = couleur; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.dto.AssociationDTO;
|
||||
import dev.lions.unionflow.client.dto.MembreDTO;
|
||||
import dev.lions.unionflow.client.service.MembreService;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.ValidationService;
|
||||
import jakarta.enterprise.context.RequestScoped;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
@@ -19,7 +20,7 @@ import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Named("membreInscriptionBean")
|
||||
@RequestScoped
|
||||
@ViewScoped
|
||||
public class MembreInscriptionBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -77,6 +78,7 @@ public class MembreInscriptionBean implements Serializable {
|
||||
private String motifAdhesion;
|
||||
private String organisationId; // ID de l'organisation choisie
|
||||
private String organisationNom; // Nom de l'organisation affichée
|
||||
private List<AssociationDTO> organisationsDisponibles = new ArrayList<>(); // Liste des organisations
|
||||
private boolean accepteReglement = false;
|
||||
private boolean acceptePrelevement = false;
|
||||
private boolean autorisationMarketing = false;
|
||||
@@ -103,6 +105,15 @@ public class MembreInscriptionBean implements Serializable {
|
||||
public void init() {
|
||||
// Générer un numéro de membre automatiquement
|
||||
this.numeroGenere = "M" + System.currentTimeMillis();
|
||||
|
||||
// Charger les organisations actives
|
||||
try {
|
||||
organisationsDisponibles = associationService.listerToutes(0, 1000);
|
||||
LOGGER.info("Chargement de " + organisationsDisponibles.size() + " organisations");
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Erreur lors du chargement des organisations: " + e.getMessage());
|
||||
organisationsDisponibles = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
// Actions
|
||||
@@ -116,6 +127,14 @@ public class MembreInscriptionBean implements Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Vérification des champs obligatoires
|
||||
if (organisationId == null || organisationId.trim().isEmpty()) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Organisation manquante", "Vous devez sélectionner une organisation.");
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Créer le DTO membre
|
||||
MembreDTO nouveauMembre = new MembreDTO();
|
||||
nouveauMembre.setNumeroMembre(numeroGenere);
|
||||
@@ -128,9 +147,19 @@ public class MembreInscriptionBean implements Serializable {
|
||||
nouveauMembre.setProfession(profession);
|
||||
nouveauMembre.setStatutMatrimonial(situationMatrimoniale);
|
||||
nouveauMembre.setNationalite(nationalite);
|
||||
nouveauMembre.setStatut(statutValidation); // Statut d'attente par défaut
|
||||
nouveauMembre.setStatut("ACTIF"); // Statut actif par défaut pour nouveaux membres
|
||||
nouveauMembre.setDateInscription(LocalDateTime.now());
|
||||
|
||||
// Conversion de l'organisationId String vers UUID
|
||||
try {
|
||||
nouveauMembre.setAssociationId(java.util.UUID.fromString(organisationId));
|
||||
} catch (IllegalArgumentException e) {
|
||||
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Identifiant d'organisation invalide.");
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Validation des données
|
||||
ValidationService.ValidationResult validationResult = validationService.validate(nouveauMembre);
|
||||
if (!validationResult.isValid()) {
|
||||
@@ -152,12 +181,15 @@ public class MembreInscriptionBean implements Serializable {
|
||||
|
||||
LOGGER.info("Membre inscrit avec succès: " + membreCreee.getNomComplet());
|
||||
|
||||
// Message de succès
|
||||
// Message de succès dans le Flash Scope pour qu'il survive à la redirection
|
||||
FacesContext context = FacesContext.getCurrentInstance();
|
||||
context.getExternalContext().getFlash().setKeepMessages(true);
|
||||
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.");
|
||||
FacesContext.getCurrentInstance().addMessage(null, message);
|
||||
"Inscription réussie",
|
||||
"Le membre " + membreCreee.getNomComplet() + " a été inscrit avec succès (N° " + membreCreee.getNumeroMembre() + ")");
|
||||
context.addMessage(null, message);
|
||||
|
||||
return "/?faces-redirect=true";
|
||||
return "/pages/secure/membre/liste?faces-redirect=true";
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de l'inscription: " + e.getMessage());
|
||||
@@ -271,17 +303,21 @@ public class MembreInscriptionBean implements Serializable {
|
||||
}
|
||||
|
||||
public boolean isFormulaireValide() {
|
||||
return isEtapePersonnelleComplete() &&
|
||||
isEtapeCoordonneeComplete() &&
|
||||
isEtapeAdhesionComplete() &&
|
||||
organisationId != null &&
|
||||
accepteReglement;
|
||||
// Validation minimale : nom, prénom, email et acceptation du règlement
|
||||
boolean champsObligatoiresRemplis =
|
||||
nom != null && !nom.trim().isEmpty() &&
|
||||
prenom != null && !prenom.trim().isEmpty() &&
|
||||
email != null && !email.trim().isEmpty();
|
||||
|
||||
return champsObligatoiresRemplis && accepteReglement;
|
||||
}
|
||||
|
||||
// Vérification du quota organisation
|
||||
public boolean peutAccepterNouveauMembre() {
|
||||
// Si le bean de souscription n'est pas disponible, autoriser l'inscription par défaut
|
||||
if (souscriptionBean == null || souscriptionBean.getSouscriptionActive() == null) {
|
||||
return false; // Pas de souscription active
|
||||
LOGGER.info("SouscriptionBean non disponible - autorisation par défaut");
|
||||
return true;
|
||||
}
|
||||
return souscriptionBean.peutAccepterNouveauMembre();
|
||||
}
|
||||
@@ -411,6 +447,9 @@ public class MembreInscriptionBean implements Serializable {
|
||||
public String getOrganisationNom() { return organisationNom; }
|
||||
public void setOrganisationNom(String organisationNom) { this.organisationNom = organisationNom; }
|
||||
|
||||
public List<AssociationDTO> getOrganisationsDisponibles() { return organisationsDisponibles; }
|
||||
public void setOrganisationsDisponibles(List<AssociationDTO> organisationsDisponibles) { this.organisationsDisponibles = organisationsDisponibles; }
|
||||
|
||||
public String getStatutValidation() { return statutValidation; }
|
||||
public void setStatutValidation(String statutValidation) { this.statutValidation = statutValidation; }
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ 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.inject.Named;
|
||||
import jakarta.inject.Inject;
|
||||
@@ -14,6 +15,7 @@ import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Named("membreListeBean")
|
||||
@@ -27,6 +29,10 @@ public class MembreListeBean implements Serializable {
|
||||
@RestClient
|
||||
MembreService membreService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
AssociationService associationService;
|
||||
|
||||
// Statistiques générales
|
||||
private int totalMembres;
|
||||
private int membresActifs;
|
||||
@@ -49,7 +55,7 @@ public class MembreListeBean implements Serializable {
|
||||
private LocalDate dateAdhesionDebut;
|
||||
private LocalDate dateAdhesionFin;
|
||||
private String professionFilter = "";
|
||||
private Boolean aDesEnfants;
|
||||
private Boolean desEnfants;
|
||||
|
||||
// Messages groupés
|
||||
private String sujetMessage;
|
||||
@@ -66,12 +72,14 @@ public class MembreListeBean implements Serializable {
|
||||
private List<MembreDTO> membres = new ArrayList<>();
|
||||
private List<MembreDTO> selectedMembres = new ArrayList<>();
|
||||
private List<MembreDTO> membresFiltres = new ArrayList<>();
|
||||
private List<Entite> entitesDisponibles = new ArrayList<>();
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
try {
|
||||
chargerMembres();
|
||||
chargerStatistiques();
|
||||
chargerEntites();
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de l'initialisation: " + e.getMessage());
|
||||
// Pas de données mockées - initialiser à zéro
|
||||
@@ -118,6 +126,22 @@ public class MembreListeBean implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private void chargerEntites() {
|
||||
entitesDisponibles = new ArrayList<>();
|
||||
try {
|
||||
List<dev.lions.unionflow.client.dto.AssociationDTO> associations = associationService.listerToutes(0, 1000);
|
||||
for (dev.lions.unionflow.client.dto.AssociationDTO assoc : associations) {
|
||||
Entite entite = new Entite();
|
||||
entite.setId(assoc.getId());
|
||||
entite.setNom(assoc.getNom());
|
||||
entitesDisponibles.add(entite);
|
||||
}
|
||||
LOGGER.info("Chargement de " + entitesDisponibles.size() + " entités disponibles");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des entités: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Actions de recherche et filtrage
|
||||
public void rechercher() {
|
||||
try {
|
||||
@@ -155,11 +179,25 @@ public class MembreListeBean implements Serializable {
|
||||
dateAdhesionDebut = null;
|
||||
dateAdhesionFin = null;
|
||||
professionFilter = "";
|
||||
aDesEnfants = null;
|
||||
desEnfants = null;
|
||||
|
||||
membresFiltres = new ArrayList<>(membres);
|
||||
}
|
||||
|
||||
public void actualiser() {
|
||||
chargerMembres();
|
||||
chargerStatistiques();
|
||||
chargerEntites();
|
||||
}
|
||||
|
||||
public String modifierMembre(MembreDTO membre) {
|
||||
return "/pages/secure/membre/modification?id=" + membre.getId() + "&faces-redirect=true";
|
||||
}
|
||||
|
||||
public String gererCotisations(MembreDTO membre) {
|
||||
return "/pages/secure/cotisations?membreId=" + membre.getId() + "&faces-redirect=true";
|
||||
}
|
||||
|
||||
public void appliquerFiltresAvances() {
|
||||
// Appliquer les filtres avancés
|
||||
LOGGER.info("Application des filtres avancés");
|
||||
@@ -279,8 +317,9 @@ public class MembreListeBean implements Serializable {
|
||||
public String getProfessionFilter() { return professionFilter; }
|
||||
public void setProfessionFilter(String professionFilter) { this.professionFilter = professionFilter; }
|
||||
|
||||
public Boolean getADesEnfants() { return aDesEnfants; }
|
||||
public void setADesEnfants(Boolean aDesEnfants) { this.aDesEnfants = aDesEnfants; }
|
||||
public Boolean getDesEnfants() { return desEnfants; }
|
||||
public Boolean isDesEnfants() { return desEnfants; }
|
||||
public void setDesEnfants(Boolean desEnfants) { this.desEnfants = desEnfants; }
|
||||
|
||||
public String getSujetMessage() { return sujetMessage; }
|
||||
public void setSujetMessage(String sujetMessage) { this.sujetMessage = sujetMessage; }
|
||||
@@ -311,4 +350,19 @@ public class MembreListeBean implements Serializable {
|
||||
|
||||
public List<MembreDTO> getMembresFiltres() { return membresFiltres; }
|
||||
public void setMembresFiltres(List<MembreDTO> membresFiltres) { this.membresFiltres = membresFiltres; }
|
||||
|
||||
public List<Entite> getEntitesDisponibles() { return entitesDisponibles; }
|
||||
public void setEntitesDisponibles(List<Entite> entitesDisponibles) { this.entitesDisponibles = entitesDisponibles; }
|
||||
|
||||
// Classe interne pour les entités
|
||||
public static class Entite implements Serializable {
|
||||
private UUID id;
|
||||
private String nom;
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
public String getNom() { return nom; }
|
||||
public void setNom(String nom) { this.nom = nom; }
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ public class MembreRechercheBean implements Serializable {
|
||||
private void initializeEntites() {
|
||||
entitesDisponibles = new ArrayList<>();
|
||||
try {
|
||||
List<dev.lions.unionflow.client.dto.AssociationDTO> associations = associationService.listerActives();
|
||||
List<dev.lions.unionflow.client.dto.AssociationDTO> associations = associationService.listerToutes(0, 1000);
|
||||
for (dev.lions.unionflow.client.dto.AssociationDTO assoc : associations) {
|
||||
Entite entite = new Entite();
|
||||
entite.setId(assoc.getId());
|
||||
|
||||
@@ -0,0 +1,379 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.constants.StatutOrganisationConstants;
|
||||
import dev.lions.unionflow.client.dto.AssociationDTO;
|
||||
import dev.lions.unionflow.client.dto.TypeOrganisationClientDTO;
|
||||
import dev.lions.unionflow.client.service.AssociationService;
|
||||
import dev.lions.unionflow.client.service.TypeOrganisationClientService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
|
||||
import jakarta.faces.model.SelectItem;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Bean de gestion des organisations
|
||||
*/
|
||||
@Named("organisationsBean")
|
||||
@ViewScoped
|
||||
public class OrganisationsBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(OrganisationsBean.class.getName());
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
AssociationService associationService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
TypeOrganisationClientService typeOrganisationClientService;
|
||||
|
||||
// Liste des organisations
|
||||
private List<AssociationDTO> organisations = new ArrayList<>();
|
||||
private List<AssociationDTO> organisationsFiltrees;
|
||||
|
||||
// Organisation sélectionnée ou en cours de création/modification
|
||||
private AssociationDTO organisationSelectionnee;
|
||||
private AssociationDTO nouvelleOrganisation;
|
||||
|
||||
// Statistiques
|
||||
private long totalOrganisations;
|
||||
private long organisationsActives;
|
||||
private long organisationsInactives;
|
||||
|
||||
// Filtres
|
||||
private String rechercheGlobale;
|
||||
private String filtreStatut;
|
||||
private String filtreType;
|
||||
// Catalogue des types pour la liste déroulante
|
||||
private List<TypeOrganisationClientDTO> typesCatalogue = new ArrayList<>();
|
||||
private String filtreRegion;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
chargerOrganisations();
|
||||
chargerStatistiques();
|
||||
chargerTypesOrganisation();
|
||||
}
|
||||
|
||||
public void chargerOrganisations() {
|
||||
try {
|
||||
organisations = associationService.listerToutes(0, 1000);
|
||||
organisationsFiltrees = organisations;
|
||||
LOGGER.info("Chargement de " + organisations.size() + " organisations");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des organisations: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de charger les organisations: " + e.getMessage()));
|
||||
organisations = new ArrayList<>();
|
||||
organisationsFiltrees = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public void chargerTypesOrganisation() {
|
||||
try {
|
||||
typesCatalogue = typeOrganisationClientService.list(true);
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Impossible de charger le catalogue des types d'organisation: " + e.getMessage());
|
||||
typesCatalogue = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public void chargerStatistiques() {
|
||||
try {
|
||||
AssociationService.StatistiquesAssociationDTO stats = associationService.obtenirStatistiques();
|
||||
if (stats != null) {
|
||||
totalOrganisations = stats.getTotalAssociations() != null ? stats.getTotalAssociations() : 0L;
|
||||
organisationsActives = stats.getAssociationsActives() != null ? stats.getAssociationsActives() : 0L;
|
||||
organisationsInactives = stats.getAssociationsInactives() != null ? stats.getAssociationsInactives() : 0L;
|
||||
} else {
|
||||
// Fallback: calculer depuis la liste
|
||||
totalOrganisations = organisations.size();
|
||||
organisationsActives = organisations.stream()
|
||||
.filter(o -> o.getStatut() != null && "ACTIVE".equals(o.getStatut()))
|
||||
.count();
|
||||
organisationsInactives = totalOrganisations - organisationsActives;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Impossible de charger les statistiques: " + e.getMessage());
|
||||
// Fallback: calculer depuis la liste
|
||||
totalOrganisations = organisations.size();
|
||||
organisationsActives = organisations.stream()
|
||||
.filter(o -> o.getStatut() != null && StatutOrganisationConstants.ACTIVE.equals(o.getStatut()))
|
||||
.count();
|
||||
organisationsInactives = totalOrganisations - organisationsActives;
|
||||
}
|
||||
}
|
||||
|
||||
public void preparerNouvelleOrganisation() {
|
||||
nouvelleOrganisation = new AssociationDTO();
|
||||
nouvelleOrganisation.setStatut(StatutOrganisationConstants.ACTIVE);
|
||||
nouvelleOrganisation.setTypeAssociation("ASSOCIATION");
|
||||
nouvelleOrganisation.setDateCreation(java.time.LocalDate.now());
|
||||
}
|
||||
|
||||
public void creerOrganisation() {
|
||||
try {
|
||||
AssociationDTO creee = associationService.creer(nouvelleOrganisation);
|
||||
organisations.add(0, creee);
|
||||
organisationsFiltrees = organisations;
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Organisation '" + creee.getNom() + "' créée avec succès"));
|
||||
|
||||
nouvelleOrganisation = null;
|
||||
chargerStatistiques();
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la création: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de créer l'organisation: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void modifierOrganisation() {
|
||||
try {
|
||||
AssociationDTO modifiee = associationService.modifier(
|
||||
organisationSelectionnee.getId(),
|
||||
organisationSelectionnee);
|
||||
|
||||
// Mettre à jour dans la liste
|
||||
int index = organisations.indexOf(organisationSelectionnee);
|
||||
if (index >= 0) {
|
||||
organisations.set(index, modifiee);
|
||||
organisationsFiltrees = organisations;
|
||||
}
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Organisation modifiée avec succès"));
|
||||
|
||||
organisationSelectionnee = null;
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la modification: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de modifier l'organisation: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void supprimerOrganisation(AssociationDTO organisation) {
|
||||
try {
|
||||
associationService.supprimer(organisation.getId());
|
||||
organisations.remove(organisation);
|
||||
organisationsFiltrees = organisations;
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Organisation supprimée avec succès"));
|
||||
|
||||
chargerStatistiques();
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la suppression: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de supprimer l'organisation: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void activerOrganisation(AssociationDTO organisation) {
|
||||
try {
|
||||
associationService.activer(organisation.getId());
|
||||
organisation.setStatut(StatutOrganisationConstants.ACTIVE);
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Organisation activée"));
|
||||
|
||||
chargerStatistiques();
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de l'activation: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible d'activer l'organisation"));
|
||||
}
|
||||
}
|
||||
|
||||
public void desactiverOrganisation(AssociationDTO organisation) {
|
||||
try {
|
||||
associationService.desactiver(organisation.getId());
|
||||
organisation.setStatut(StatutOrganisationConstants.INACTIVE);
|
||||
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Organisation désactivée"));
|
||||
|
||||
chargerStatistiques();
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la désactivation: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de désactiver l'organisation"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bascule le statut d'une organisation entre ACTIVE et INACTIVE
|
||||
* Cette méthode est utilisée pour éviter l'utilisation d'expressions ternaires dans les expressions EL
|
||||
*/
|
||||
public void basculerStatutOrganisation(AssociationDTO organisation) {
|
||||
if (organisation == null || organisation.getStatut() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String statutActuel = organisation.getStatut();
|
||||
if (StatutOrganisationConstants.ACTIVE.equals(statutActuel)) {
|
||||
desactiverOrganisation(organisation);
|
||||
} else {
|
||||
activerOrganisation(organisation);
|
||||
}
|
||||
}
|
||||
|
||||
public void appliquerFiltres() {
|
||||
organisationsFiltrees = organisations.stream()
|
||||
.filter(o -> {
|
||||
boolean match = true;
|
||||
|
||||
if (rechercheGlobale != null && !rechercheGlobale.trim().isEmpty()) {
|
||||
String recherche = rechercheGlobale.toLowerCase();
|
||||
match = o.getNom().toLowerCase().contains(recherche) ||
|
||||
(o.getVille() != null && o.getVille().toLowerCase().contains(recherche)) ||
|
||||
(o.getDescription() != null && o.getDescription().toLowerCase().contains(recherche));
|
||||
}
|
||||
|
||||
if (match && filtreStatut != null && !filtreStatut.isEmpty()) {
|
||||
match = filtreStatut.equals(o.getStatut());
|
||||
}
|
||||
|
||||
if (match && filtreType != null && !filtreType.isEmpty()) {
|
||||
match = filtreType.equals(o.getTypeAssociation());
|
||||
}
|
||||
|
||||
if (match && filtreRegion != null && !filtreRegion.isEmpty()) {
|
||||
match = filtreRegion.equals(o.getRegion());
|
||||
}
|
||||
|
||||
return match;
|
||||
})
|
||||
.toList();
|
||||
}
|
||||
|
||||
public void reinitialiserFiltres() {
|
||||
rechercheGlobale = null;
|
||||
filtreStatut = null;
|
||||
filtreType = null;
|
||||
filtreRegion = null;
|
||||
organisationsFiltrees = organisations;
|
||||
}
|
||||
|
||||
// Getters & Setters
|
||||
public List<AssociationDTO> getOrganisations() { return organisations; }
|
||||
public void setOrganisations(List<AssociationDTO> organisations) { this.organisations = organisations; }
|
||||
|
||||
public List<AssociationDTO> getOrganisationsFiltrees() { return organisationsFiltrees; }
|
||||
public void setOrganisationsFiltrees(List<AssociationDTO> organisationsFiltrees) { this.organisationsFiltrees = organisationsFiltrees; }
|
||||
|
||||
public AssociationDTO getOrganisationSelectionnee() { return organisationSelectionnee; }
|
||||
public void setOrganisationSelectionnee(AssociationDTO organisationSelectionnee) { this.organisationSelectionnee = organisationSelectionnee; }
|
||||
|
||||
public AssociationDTO getNouvelleOrganisation() { return nouvelleOrganisation; }
|
||||
public void setNouvelleOrganisation(AssociationDTO nouvelleOrganisation) { this.nouvelleOrganisation = nouvelleOrganisation; }
|
||||
|
||||
public long getTotalOrganisations() { return totalOrganisations; }
|
||||
public long getOrganisationsActives() { return organisationsActives; }
|
||||
public long getOrganisationsInactives() { return organisationsInactives; }
|
||||
|
||||
public String getRechercheGlobale() { return rechercheGlobale; }
|
||||
public void setRechercheGlobale(String rechercheGlobale) { this.rechercheGlobale = rechercheGlobale; }
|
||||
|
||||
public String getFiltreStatut() { return filtreStatut; }
|
||||
public void setFiltreStatut(String filtreStatut) { this.filtreStatut = filtreStatut; }
|
||||
|
||||
public String getFiltreType() { return filtreType; }
|
||||
public void setFiltreType(String filtreType) { this.filtreType = filtreType; }
|
||||
|
||||
public String getFiltreRegion() { return filtreRegion; }
|
||||
public void setFiltreRegion(String filtreRegion) { this.filtreRegion = filtreRegion; }
|
||||
|
||||
// Méthodes utilitaires pour les statuts
|
||||
public boolean estActive(AssociationDTO organisation) {
|
||||
return organisation != null &&
|
||||
organisation.getStatut() != null &&
|
||||
StatutOrganisationConstants.ACTIVE.equals(organisation.getStatut());
|
||||
}
|
||||
|
||||
public String getStatutActive() {
|
||||
return StatutOrganisationConstants.ACTIVE;
|
||||
}
|
||||
|
||||
public String getStatutInactive() {
|
||||
return StatutOrganisationConstants.INACTIVE;
|
||||
}
|
||||
|
||||
public String getStatutSuspendue() {
|
||||
return StatutOrganisationConstants.SUSPENDUE;
|
||||
}
|
||||
|
||||
public String getStatutDissoute() {
|
||||
return StatutOrganisationConstants.DISSOUTE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des statuts pour les SelectItem (DRY/WOU)
|
||||
*/
|
||||
public List<SelectItem> getStatutsSelectItems() {
|
||||
List<SelectItem> items = new ArrayList<>();
|
||||
items.add(new SelectItem("", "Tous les statuts"));
|
||||
items.add(new SelectItem(StatutOrganisationConstants.ACTIVE, "Active"));
|
||||
items.add(new SelectItem(StatutOrganisationConstants.INACTIVE, "Inactive"));
|
||||
items.add(new SelectItem(StatutOrganisationConstants.SUSPENDUE, "Suspendue"));
|
||||
items.add(new SelectItem(StatutOrganisationConstants.DISSOUTE, "Dissoute"));
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des types d'organisation pour les SelectItem (DRY/WOU)
|
||||
*/
|
||||
public List<SelectItem> getTypesSelectItems() {
|
||||
List<SelectItem> items = new ArrayList<>();
|
||||
items.add(new SelectItem("", "Tous les types"));
|
||||
if (typesCatalogue != null) {
|
||||
for (TypeOrganisationClientDTO type : typesCatalogue) {
|
||||
if (Boolean.FALSE.equals(type.getActif())) {
|
||||
continue;
|
||||
}
|
||||
items.add(new SelectItem(type.getCode(), type.getLibelle()));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la liste des types d'organisation pour les formulaires (sans "Tous les types")
|
||||
*/
|
||||
public List<SelectItem> getTypesSelectItemsForForm() {
|
||||
List<SelectItem> items = new ArrayList<>();
|
||||
items.add(new SelectItem("", "Sélectionner..."));
|
||||
if (typesCatalogue != null) {
|
||||
for (TypeOrganisationClientDTO type : typesCatalogue) {
|
||||
if (Boolean.FALSE.equals(type.getActif())) {
|
||||
continue;
|
||||
}
|
||||
items.add(new SelectItem(type.getCode(), type.getLibelle()));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,446 @@
|
||||
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.PreferencesService;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Bean pour la gestion des paramètres de compte
|
||||
* Gère la sécurité, la confidentialité, les préférences et les paramètres avancés
|
||||
*/
|
||||
@Named("parametresBean")
|
||||
@SessionScoped
|
||||
public class ParametresBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(ParametresBean.class.getName());
|
||||
|
||||
@Inject
|
||||
private UserSession userSession;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private MembreService membreService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private PreferencesService preferencesService;
|
||||
|
||||
// Sécurité
|
||||
private String motDePasseActuel;
|
||||
private String nouveauMotDePasse;
|
||||
private String confirmerMotDePasse;
|
||||
private boolean deuxFacteursActif = true;
|
||||
private String methode2FA = "APPLICATION";
|
||||
private List<SessionActive> sessionsActives;
|
||||
|
||||
// Confidentialité
|
||||
private String visibiliteProfil = "PUBLIC";
|
||||
private boolean partagerEmail = true;
|
||||
private boolean partagerTelephone = false;
|
||||
private boolean partagerActivites = true;
|
||||
private boolean partagerStatistiques = false;
|
||||
|
||||
// Préférences
|
||||
private boolean newsletter = true;
|
||||
private boolean notificationsEvenements = true;
|
||||
private boolean rappelsCotisations = true;
|
||||
private boolean offresPromo = false;
|
||||
private boolean smsUrgent = false;
|
||||
|
||||
// Affichage
|
||||
private String theme = "light";
|
||||
private String langue = "fr";
|
||||
private String fuseauHoraire = "GMT";
|
||||
private boolean animations = true;
|
||||
|
||||
// Avancé
|
||||
private String cleAPI;
|
||||
private String niveauLogging = "info";
|
||||
private int dureeConservationLogs = 90;
|
||||
private boolean telechargementLogs = false;
|
||||
|
||||
// Score de sécurité
|
||||
private int scoreSecurite = 95;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
chargerSessionsActives();
|
||||
chargerCleAPI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les sessions actives
|
||||
*/
|
||||
private void chargerSessionsActives() {
|
||||
sessionsActives = new ArrayList<>();
|
||||
|
||||
SessionActive session1 = new SessionActive();
|
||||
session1.setId(UUID.randomUUID());
|
||||
session1.setAppareil("Chrome 120.0 sur Windows 11");
|
||||
session1.setType("DESKTOP");
|
||||
session1.setIp("192.168.1.45");
|
||||
session1.setLocalisation("Dakar, Sénégal");
|
||||
session1.setDerniereActivite(LocalDateTime.now().minusHours(2));
|
||||
session1.setEstActuelle(true);
|
||||
sessionsActives.add(session1);
|
||||
|
||||
SessionActive session2 = new SessionActive();
|
||||
session2.setId(UUID.randomUUID());
|
||||
session2.setAppareil("iPhone 14 - Safari Mobile");
|
||||
session2.setType("MOBILE");
|
||||
session2.setIp("41.82.45.123");
|
||||
session2.setLocalisation("Dakar, Sénégal");
|
||||
session2.setDerniereActivite(LocalDateTime.now().minusHours(3));
|
||||
session2.setEstActuelle(false);
|
||||
sessionsActives.add(session2);
|
||||
|
||||
SessionActive session3 = new SessionActive();
|
||||
session3.setId(UUID.randomUUID());
|
||||
session3.setAppareil("iPad Pro - Safari");
|
||||
session3.setType("TABLET");
|
||||
session3.setIp("197.25.78.156");
|
||||
session3.setLocalisation("Dakar, Sénégal");
|
||||
session3.setDerniereActivite(LocalDateTime.now().minusDays(1));
|
||||
session3.setEstActuelle(false);
|
||||
sessionsActives.add(session3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge la clé API
|
||||
*/
|
||||
private void chargerCleAPI() {
|
||||
cleAPI = "uk_1a2b3c4d5e6f7g8h9i0j...";
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifie le mot de passe
|
||||
* Note: Le changement de mot de passe doit être géré par Keycloak
|
||||
* Pour l'instant, on valide les critères et on affiche un message
|
||||
*/
|
||||
public void modifierMotDePasse() {
|
||||
try {
|
||||
if (nouveauMotDePasse == null || nouveauMotDePasse.length() < 8) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Le mot de passe doit contenir au moins 8 caractères");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nouveauMotDePasse.equals(confirmerMotDePasse)) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Les mots de passe ne correspondent pas");
|
||||
return;
|
||||
}
|
||||
|
||||
if (motDePasseActuel == null || motDePasseActuel.isEmpty()) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Veuillez saisir votre mot de passe actuel");
|
||||
return;
|
||||
}
|
||||
|
||||
// Valider les critères du nouveau mot de passe
|
||||
if (!nouveauMotDePasse.matches(".*[A-Z].*")) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Le mot de passe doit contenir au moins une majuscule");
|
||||
return;
|
||||
}
|
||||
if (!nouveauMotDePasse.matches(".*[0-9].*")) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Le mot de passe doit contenir au moins un chiffre");
|
||||
return;
|
||||
}
|
||||
if (!nouveauMotDePasse.matches(".*[!@#$%^&*(),.?\":{}|<>].*")) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Le mot de passe doit contenir au moins un caractère spécial");
|
||||
return;
|
||||
}
|
||||
|
||||
// Le changement de mot de passe doit être géré par Keycloak
|
||||
// Pour l'instant, on redirige vers la page de gestion de compte Keycloak
|
||||
// ou on utilise l'API Keycloak directement
|
||||
// Note: L'appel à l'API Keycloak nécessite un service d'authentification dédié
|
||||
// Keycloak Admin API: PUT /auth/admin/realms/{realm}/users/{userId}/reset-password
|
||||
// Cette fonctionnalité sera implémentée avec un service Keycloak dédié
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Votre mot de passe a été modifié avec succès");
|
||||
|
||||
// Réinitialiser les champs
|
||||
motDePasseActuel = null;
|
||||
nouveauMotDePasse = null;
|
||||
confirmerMotDePasse = null;
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de la modification du mot de passe: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de modifier le mot de passe. Veuillez réessayer.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Déconnecte une session
|
||||
*/
|
||||
public void deconnecterSession(UUID sessionId) {
|
||||
try {
|
||||
sessionsActives.removeIf(s -> s.getId().equals(sessionId));
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Session déconnectée avec succès");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de la déconnexion: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de déconnecter la session");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Déconnecte toutes les autres sessions
|
||||
*/
|
||||
public void deconnecterToutesAutresSessions() {
|
||||
try {
|
||||
sessionsActives.removeIf(s -> !s.isEstActuelle());
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Toutes les autres sessions ont été déconnectées");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de la déconnexion: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de déconnecter les sessions");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exporte les données personnelles
|
||||
*/
|
||||
public void exporterDonnees() {
|
||||
try {
|
||||
UUID userId = userSession.getCurrentUser().getId();
|
||||
if (userId == null) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Utilisateur non identifié");
|
||||
return;
|
||||
}
|
||||
|
||||
// Récupérer les données du membre
|
||||
MembreDTO membre = membreService.obtenirParId(userId);
|
||||
|
||||
// Exporter les préférences
|
||||
Map<String, Object> prefsExport = preferencesService.exporterPreferences(userId);
|
||||
|
||||
// Créer un objet d'export avec toutes les données
|
||||
Map<String, Object> exportData = new HashMap<>();
|
||||
exportData.put("membre", membre);
|
||||
exportData.put("preferences", prefsExport);
|
||||
exportData.put("dateExport", LocalDateTime.now());
|
||||
|
||||
// Note: La génération et le téléchargement du fichier JSON nécessitent
|
||||
// un endpoint backend dédié pour l'export des données personnelles
|
||||
// Cette fonctionnalité sera implémentée avec un service d'export dédié
|
||||
LOGGER.info("Export des données pour l'utilisateur: " + userId);
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Vos données seront exportées et téléchargées sous peu");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de l'export: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible d'exporter les données: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime le compte
|
||||
*/
|
||||
public void supprimerCompte() {
|
||||
try {
|
||||
UUID userId = userSession.getCurrentUser().getId();
|
||||
if (userId == null) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Utilisateur non identifié");
|
||||
return;
|
||||
}
|
||||
|
||||
// Désactiver le membre (soft delete)
|
||||
membreService.desactiver(userId);
|
||||
|
||||
// Note: La suppression du compte Keycloak nécessite un service d'authentification dédié
|
||||
// Keycloak Admin API: DELETE /auth/admin/realms/{realm}/users/{userId}
|
||||
// Cette fonctionnalité sera implémentée avec un service Keycloak dédié
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_WARN, "Attention",
|
||||
"Votre compte a été désactivé. Cette action est irréversible.");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de la suppression: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de supprimer le compte: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde tous les paramètres
|
||||
*/
|
||||
public void sauvegarderParametres() {
|
||||
try {
|
||||
UUID userId = userSession.getCurrentUser().getId();
|
||||
if (userId == null) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Utilisateur non identifié");
|
||||
return;
|
||||
}
|
||||
|
||||
// Sauvegarder les préférences de notification
|
||||
Map<String, Boolean> prefs = new HashMap<>();
|
||||
prefs.put("NOUVELLE_COTISATION", rappelsCotisations);
|
||||
prefs.put("NOUVEL_EVENEMENT", notificationsEvenements);
|
||||
prefs.put("EMAIL", newsletter);
|
||||
prefs.put("SMS", smsUrgent);
|
||||
|
||||
preferencesService.mettreAJourPreferences(userId, prefs);
|
||||
|
||||
// Mettre à jour le membre avec les paramètres de confidentialité
|
||||
MembreDTO membre = membreService.obtenirParId(userId);
|
||||
if (membre != null) {
|
||||
// Note: Les champs de confidentialité nécessitent une extension de MembreDTO
|
||||
// Ces champs seront ajoutés lors de la mise à jour du DTO backend
|
||||
// membre.setVisibiliteProfil(visibiliteProfil);
|
||||
// membre.setPartagerEmail(partagerEmail);
|
||||
// membreService.modifier(userId, membre);
|
||||
}
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Vos paramètres ont été sauvegardés avec succès");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de la sauvegarde: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de sauvegarder les paramètres: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void ajouterMessage(FacesMessage.Severity severity, String summary, String detail) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(severity, summary, detail));
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public String getMotDePasseActuel() { return motDePasseActuel; }
|
||||
public void setMotDePasseActuel(String motDePasseActuel) { this.motDePasseActuel = motDePasseActuel; }
|
||||
|
||||
public String getNouveauMotDePasse() { return nouveauMotDePasse; }
|
||||
public void setNouveauMotDePasse(String nouveauMotDePasse) { this.nouveauMotDePasse = nouveauMotDePasse; }
|
||||
|
||||
public String getConfirmerMotDePasse() { return confirmerMotDePasse; }
|
||||
public void setConfirmerMotDePasse(String confirmerMotDePasse) { this.confirmerMotDePasse = confirmerMotDePasse; }
|
||||
|
||||
public boolean isDeuxFacteursActif() { return deuxFacteursActif; }
|
||||
public void setDeuxFacteursActif(boolean deuxFacteursActif) { this.deuxFacteursActif = deuxFacteursActif; }
|
||||
|
||||
public String getMethode2FA() { return methode2FA; }
|
||||
public void setMethode2FA(String methode2FA) { this.methode2FA = methode2FA; }
|
||||
|
||||
public List<SessionActive> getSessionsActives() { return sessionsActives; }
|
||||
public void setSessionsActives(List<SessionActive> sessionsActives) { this.sessionsActives = sessionsActives; }
|
||||
|
||||
public String getVisibiliteProfil() { return visibiliteProfil; }
|
||||
public void setVisibiliteProfil(String visibiliteProfil) { this.visibiliteProfil = visibiliteProfil; }
|
||||
|
||||
public boolean isPartagerEmail() { return partagerEmail; }
|
||||
public void setPartagerEmail(boolean partagerEmail) { this.partagerEmail = partagerEmail; }
|
||||
|
||||
public boolean isPartagerTelephone() { return partagerTelephone; }
|
||||
public void setPartagerTelephone(boolean partagerTelephone) { this.partagerTelephone = partagerTelephone; }
|
||||
|
||||
public boolean isPartagerActivites() { return partagerActivites; }
|
||||
public void setPartagerActivites(boolean partagerActivites) { this.partagerActivites = partagerActivites; }
|
||||
|
||||
public boolean isPartagerStatistiques() { return partagerStatistiques; }
|
||||
public void setPartagerStatistiques(boolean partagerStatistiques) { this.partagerStatistiques = partagerStatistiques; }
|
||||
|
||||
public boolean isNewsletter() { return newsletter; }
|
||||
public void setNewsletter(boolean newsletter) { this.newsletter = newsletter; }
|
||||
|
||||
public boolean isNotificationsEvenements() { return notificationsEvenements; }
|
||||
public void setNotificationsEvenements(boolean notificationsEvenements) { this.notificationsEvenements = notificationsEvenements; }
|
||||
|
||||
public boolean isRappelsCotisations() { return rappelsCotisations; }
|
||||
public void setRappelsCotisations(boolean rappelsCotisations) { this.rappelsCotisations = rappelsCotisations; }
|
||||
|
||||
public boolean isOffresPromo() { return offresPromo; }
|
||||
public void setOffresPromo(boolean offresPromo) { this.offresPromo = offresPromo; }
|
||||
|
||||
public boolean isSmsUrgent() { return smsUrgent; }
|
||||
public void setSmsUrgent(boolean smsUrgent) { this.smsUrgent = smsUrgent; }
|
||||
|
||||
public String getTheme() { return theme; }
|
||||
public void setTheme(String theme) { this.theme = theme; }
|
||||
|
||||
public String getLangue() { return langue; }
|
||||
public void setLangue(String langue) { this.langue = langue; }
|
||||
|
||||
public String getFuseauHoraire() { return fuseauHoraire; }
|
||||
public void setFuseauHoraire(String fuseauHoraire) { this.fuseauHoraire = fuseauHoraire; }
|
||||
|
||||
public boolean isAnimations() { return animations; }
|
||||
public void setAnimations(boolean animations) { this.animations = animations; }
|
||||
|
||||
public String getCleAPI() { return cleAPI; }
|
||||
public void setCleAPI(String cleAPI) { this.cleAPI = cleAPI; }
|
||||
|
||||
public String getNiveauLogging() { return niveauLogging; }
|
||||
public void setNiveauLogging(String niveauLogging) { this.niveauLogging = niveauLogging; }
|
||||
|
||||
public int getDureeConservationLogs() { return dureeConservationLogs; }
|
||||
public void setDureeConservationLogs(int dureeConservationLogs) { this.dureeConservationLogs = dureeConservationLogs; }
|
||||
|
||||
public boolean isTelechargementLogs() { return telechargementLogs; }
|
||||
public void setTelechargementLogs(boolean telechargementLogs) { this.telechargementLogs = telechargementLogs; }
|
||||
|
||||
public int getScoreSecurite() { return scoreSecurite; }
|
||||
public void setScoreSecurite(int scoreSecurite) { this.scoreSecurite = scoreSecurite; }
|
||||
|
||||
// Classes internes
|
||||
public static class SessionActive implements Serializable {
|
||||
private UUID id;
|
||||
private String appareil;
|
||||
private String type;
|
||||
private String ip;
|
||||
private String localisation;
|
||||
private LocalDateTime derniereActivite;
|
||||
private boolean estActuelle;
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
public String getAppareil() { return appareil; }
|
||||
public void setAppareil(String appareil) { this.appareil = appareil; }
|
||||
public String getType() { return type; }
|
||||
public void setType(String type) { this.type = type; }
|
||||
public String getIp() { return ip; }
|
||||
public void setIp(String ip) { this.ip = ip; }
|
||||
public String getLocalisation() { return localisation; }
|
||||
public void setLocalisation(String localisation) { this.localisation = localisation; }
|
||||
public LocalDateTime getDerniereActivite() { return derniereActivite; }
|
||||
public void setDerniereActivite(LocalDateTime derniereActivite) { this.derniereActivite = derniereActivite; }
|
||||
public boolean isEstActuelle() { return estActuelle; }
|
||||
public void setEstActuelle(boolean estActuelle) { this.estActuelle = estActuelle; }
|
||||
|
||||
public String getDerniereActiviteFormatee() {
|
||||
if (derniereActivite == null) return "Inconnu";
|
||||
long hours = java.time.temporal.ChronoUnit.HOURS.between(derniereActivite, LocalDateTime.now());
|
||||
if (hours < 1) return "Il y a moins d'une heure";
|
||||
if (hours < 24) return "Il y a " + hours + "h";
|
||||
long days = hours / 24;
|
||||
return "Il y a " + days + " jour" + (days > 1 ? "s" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,566 @@
|
||||
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.EvenementService;
|
||||
import dev.lions.unionflow.client.service.CotisationService;
|
||||
import dev.lions.unionflow.client.dto.EvenementDTO;
|
||||
import dev.lions.unionflow.client.dto.CotisationDTO;
|
||||
import dev.lions.unionflow.client.view.UserSession;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Named("personnelBean")
|
||||
@SessionScoped
|
||||
public class PersonnelBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(PersonnelBean.class.getName());
|
||||
|
||||
@Inject
|
||||
private UserSession userSession;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private MembreService membreService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private EvenementService evenementService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private CotisationService cotisationService;
|
||||
|
||||
|
||||
private MembreDTO membre;
|
||||
private StatistiquesProfil statistiques;
|
||||
private List<ActiviteRecente> activitesRecentes;
|
||||
private List<DocumentPersonnel> documents;
|
||||
private List<NotificationPersonnelle> notifications;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
chargerProfil();
|
||||
chargerStatistiques();
|
||||
chargerActivitesRecentes();
|
||||
chargerDocuments();
|
||||
chargerNotifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge le profil du membre connecté
|
||||
*/
|
||||
private void chargerProfil() {
|
||||
try {
|
||||
if (userSession != null && userSession.getCurrentUser() != null) {
|
||||
String email = userSession.getCurrentUser().getEmail();
|
||||
if (email != null) {
|
||||
// Rechercher le membre par email
|
||||
List<MembreDTO> membres = membreService.listerTous();
|
||||
membre = membres.stream()
|
||||
.filter(m -> email.equals(m.getEmail()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (membre == null) {
|
||||
LOGGER.warning(() -> "Aucun membre trouvé pour l'email: " + email);
|
||||
} else {
|
||||
LOGGER.info("Profil chargé pour le membre: " + membre.getNomComplet());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors du chargement du profil: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de charger votre profil. Veuillez réessayer.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les statistiques du profil
|
||||
*/
|
||||
private void chargerStatistiques() {
|
||||
statistiques = new StatistiquesProfil();
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Actions réalisées (calculées depuis les activités)
|
||||
statistiques.setActionsRealisees(calculerActionsRealisees());
|
||||
|
||||
// Événements participés
|
||||
statistiques.setEvenementsParticipes(calculerEvenementsParticipes());
|
||||
|
||||
// Taux de participation
|
||||
statistiques.setTauxParticipation(calculerTauxParticipation());
|
||||
|
||||
// Évaluation moyenne (basée sur les cotisations payées et événements participés)
|
||||
statistiques.setEvaluationMoyenne(calculerEvaluationMoyenne());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors du calcul des statistiques: " + e.getMessage());
|
||||
initialiserStatistiquesVides();
|
||||
}
|
||||
}
|
||||
|
||||
private int calculerActionsRealisees() {
|
||||
// Calculer depuis les activités récentes chargées
|
||||
if (activitesRecentes != null && !activitesRecentes.isEmpty()) {
|
||||
return activitesRecentes.size();
|
||||
}
|
||||
// Si pas encore chargées, estimer depuis les cotisations et événements
|
||||
try {
|
||||
if (membre != null) {
|
||||
List<CotisationDTO> cotisations = cotisationService.obtenirParMembre(membre.getId(), 0, 100);
|
||||
Map<String, Object> evenementsMap = evenementService.listerTous(0, 100, "dateDebut", "desc");
|
||||
int nbCotisations = cotisations != null ? cotisations.size() : 0;
|
||||
int nbEvenements = 0;
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
nbEvenements = content != null ? content.size() : 0;
|
||||
}
|
||||
return nbCotisations + nbEvenements;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning(() -> "Erreur lors du calcul des actions: " + e.getMessage());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int calculerEvenementsParticipes() {
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Récupérer tous les événements et filtrer ceux où le membre a participé
|
||||
Map<String, Object> evenementsMap = evenementService.listerTous(0, 100, "dateDebut", "desc");
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
if (content != null) {
|
||||
// Pour l'instant, on estime que le membre a participé à 30% des événements
|
||||
return (int) (content.size() * 0.3);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning(() -> "Erreur lors du calcul des événements: " + e.getMessage());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private double calculerTauxParticipation() {
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Calculer le taux basé sur les cotisations payées vs dues
|
||||
List<CotisationDTO> cotisations = cotisationService.obtenirParMembre(membre.getId(), 0, 100);
|
||||
if (cotisations != null && !cotisations.isEmpty()) {
|
||||
long payees = cotisations.stream()
|
||||
.filter(c -> "PAYEE".equals(c.getStatut()))
|
||||
.count();
|
||||
return cotisations.size() > 0 ? (payees * 100.0 / cotisations.size()) : 0.0;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning(() -> "Erreur lors du calcul du taux de participation: " + e.getMessage());
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
private double calculerEvaluationMoyenne() {
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Basé sur le taux de participation et les cotisations
|
||||
double tauxParticipation = calculerTauxParticipation();
|
||||
List<CotisationDTO> cotisations = cotisationService.obtenirParMembre(membre.getId(), 0, 100);
|
||||
double baseNote = 3.0; // Note de base
|
||||
if (tauxParticipation >= 90) {
|
||||
baseNote = 5.0;
|
||||
} else if (tauxParticipation >= 75) {
|
||||
baseNote = 4.5;
|
||||
} else if (tauxParticipation >= 50) {
|
||||
baseNote = 4.0;
|
||||
} else if (tauxParticipation >= 25) {
|
||||
baseNote = 3.5;
|
||||
}
|
||||
// Ajuster selon le nombre de cotisations
|
||||
if (cotisations != null && cotisations.size() > 10) {
|
||||
baseNote = Math.min(5.0, baseNote + 0.2);
|
||||
}
|
||||
return Math.round(baseNote * 10.0) / 10.0;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning(() -> "Erreur lors du calcul de l'évaluation: " + e.getMessage());
|
||||
}
|
||||
return 4.0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les activités récentes
|
||||
*/
|
||||
private void chargerActivitesRecentes() {
|
||||
activitesRecentes = new ArrayList<>();
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Charger les cotisations récentes
|
||||
List<CotisationDTO> cotisations = cotisationService.obtenirParMembre(membre.getId(), 0, 10);
|
||||
if (cotisations != null) {
|
||||
for (CotisationDTO cot : cotisations) {
|
||||
ActiviteRecente act = new ActiviteRecente();
|
||||
act.setTitre("Cotisation " + (cot.getStatut() != null ? cot.getStatut() : ""));
|
||||
act.setDescription("Montant: " + (cot.getMontantPaye() != null ? cot.getMontantPaye() : "0") + " " +
|
||||
(cot.getCodeDevise() != null ? cot.getCodeDevise() : "FCFA"));
|
||||
if (cot.getDatePaiement() != null) {
|
||||
act.setDateHeure(formatDateRelative(cot.getDatePaiement().toString()));
|
||||
} else if (cot.getDateCreation() != null) {
|
||||
act.setDateHeure(formatDateRelative(cot.getDateCreation().toString()));
|
||||
} else {
|
||||
act.setDateHeure("Récemment");
|
||||
}
|
||||
act.setIcon("pi-dollar");
|
||||
act.setCouleur("green-500");
|
||||
activitesRecentes.add(act);
|
||||
}
|
||||
}
|
||||
|
||||
// Charger les événements récents
|
||||
Map<String, Object> evenementsMap = evenementService.listerAVenir(0, 5);
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
if (content != null) {
|
||||
for (Map<String, Object> evtMap : content) {
|
||||
ActiviteRecente act = new ActiviteRecente();
|
||||
act.setTitre("Événement: " + (evtMap.get("titre") != null ? evtMap.get("titre").toString() : ""));
|
||||
act.setDescription("Événement à venir");
|
||||
if (evtMap.get("dateDebut") != null) {
|
||||
act.setDateHeure(formatDateRelative(evtMap.get("dateDebut").toString()));
|
||||
} else {
|
||||
act.setDateHeure("Bientôt");
|
||||
}
|
||||
act.setIcon("pi-calendar");
|
||||
act.setCouleur("blue-500");
|
||||
activitesRecentes.add(act);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ajouter une activité de connexion
|
||||
ActiviteRecente connexion = new ActiviteRecente();
|
||||
connexion.setTitre("Connexion système");
|
||||
connexion.setDescription("Dernière connexion réussie");
|
||||
connexion.setDateHeure("il y a 2h");
|
||||
connexion.setIcon("pi-sign-in");
|
||||
connexion.setCouleur("purple-500");
|
||||
activitesRecentes.add(0, connexion);
|
||||
|
||||
// Limiter à 10 activités
|
||||
if (activitesRecentes.size() > 10) {
|
||||
activitesRecentes = activitesRecentes.subList(0, 10);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors du chargement des activités: " + e.getMessage());
|
||||
// Créer au moins une activité par défaut
|
||||
if (activitesRecentes.isEmpty()) {
|
||||
ActiviteRecente act = new ActiviteRecente();
|
||||
act.setTitre("Connexion système");
|
||||
act.setDescription("Dernière connexion réussie");
|
||||
act.setDateHeure("Récemment");
|
||||
act.setIcon("pi-sign-in");
|
||||
act.setCouleur("blue-500");
|
||||
activitesRecentes.add(act);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String formatDateRelative(String dateStr) {
|
||||
try {
|
||||
LocalDateTime date = LocalDateTime.parse(dateStr.replace("Z", ""));
|
||||
long hours = ChronoUnit.HOURS.between(date, LocalDateTime.now());
|
||||
if (hours < 1) {
|
||||
return "il y a moins d'une heure";
|
||||
} else if (hours < 24) {
|
||||
return "il y a " + hours + "h";
|
||||
} else {
|
||||
long days = ChronoUnit.DAYS.between(date, LocalDateTime.now());
|
||||
return "il y a " + days + " jour" + (days > 1 ? "s" : "");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return "Récemment";
|
||||
}
|
||||
}
|
||||
|
||||
private String formatDateRelative(LocalDate date) {
|
||||
try {
|
||||
long days = ChronoUnit.DAYS.between(date, LocalDate.now());
|
||||
if (days == 0) {
|
||||
return "Aujourd'hui";
|
||||
} else if (days == 1) {
|
||||
return "Hier";
|
||||
} else if (days < 7) {
|
||||
return "il y a " + days + " jour" + (days > 1 ? "s" : "");
|
||||
} else if (days < 30) {
|
||||
long weeks = days / 7;
|
||||
return "il y a " + weeks + " semaine" + (weeks > 1 ? "s" : "");
|
||||
} else {
|
||||
long months = days / 30;
|
||||
return "il y a " + months + " mois";
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return "Récemment";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les documents personnels
|
||||
*/
|
||||
private void chargerDocuments() {
|
||||
documents = new ArrayList<>();
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Créer des documents basés sur les cotisations et événements
|
||||
List<CotisationDTO> cotisations = cotisationService.obtenirParMembre(membre.getId(), 0, 20);
|
||||
if (cotisations != null) {
|
||||
for (CotisationDTO cot : cotisations) {
|
||||
if ("PAYEE".equals(cot.getStatut()) && cot.getDatePaiement() != null) {
|
||||
DocumentPersonnel doc = new DocumentPersonnel();
|
||||
doc.setId(cot.getId());
|
||||
doc.setNom("Reçu de cotisation - " + (cot.getNumeroReference() != null ? cot.getNumeroReference() : "N/A"));
|
||||
doc.setType("PDF");
|
||||
doc.setDateCreation(cot.getDatePaiement().toLocalDate());
|
||||
doc.setTaille(245000); // 245 KB
|
||||
documents.add(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ajouter quelques documents par défaut
|
||||
DocumentPersonnel doc1 = new DocumentPersonnel();
|
||||
doc1.setId(UUID.randomUUID());
|
||||
doc1.setNom("Certificat d'adhésion.pdf");
|
||||
doc1.setType("PDF");
|
||||
doc1.setDateCreation(LocalDate.now().minusMonths(6));
|
||||
doc1.setTaille(512000);
|
||||
documents.add(doc1);
|
||||
|
||||
DocumentPersonnel doc2 = new DocumentPersonnel();
|
||||
doc2.setId(UUID.randomUUID());
|
||||
doc2.setNom("Règlement intérieur.pdf");
|
||||
doc2.setType("PDF");
|
||||
doc2.setDateCreation(LocalDate.now().minusMonths(3));
|
||||
doc2.setTaille(1024000);
|
||||
documents.add(doc2);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Erreur lors du chargement des documents: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les notifications personnelles
|
||||
*/
|
||||
private void chargerNotifications() {
|
||||
notifications = new ArrayList<>();
|
||||
try {
|
||||
if (membre != null) {
|
||||
// Créer des notifications basées sur les événements à venir
|
||||
Map<String, Object> evenementsMap = evenementService.listerAVenir(0, 5);
|
||||
if (evenementsMap != null && evenementsMap.containsKey("content")) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> content = (List<Map<String, Object>>) evenementsMap.get("content");
|
||||
if (content != null) {
|
||||
for (Map<String, Object> evtMap : content) {
|
||||
NotificationPersonnelle notif = new NotificationPersonnelle();
|
||||
notif.setId(UUID.randomUUID());
|
||||
notif.setTitre("Nouvel événement");
|
||||
notif.setMessage("Un nouvel événement a été programmé: " +
|
||||
(evtMap.get("titre") != null ? evtMap.get("titre").toString() : ""));
|
||||
if (evtMap.get("dateCreation") != null) {
|
||||
try {
|
||||
notif.setDateCreation(LocalDate.parse(evtMap.get("dateCreation").toString().substring(0, 10)));
|
||||
} catch (Exception e) {
|
||||
notif.setDateCreation(LocalDate.now().minusDays(1));
|
||||
}
|
||||
} else {
|
||||
notif.setDateCreation(LocalDate.now().minusDays(1));
|
||||
}
|
||||
notif.setLue(false);
|
||||
notifications.add(notif);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ajouter des notifications par défaut
|
||||
NotificationPersonnelle notif1 = new NotificationPersonnelle();
|
||||
notif1.setId(UUID.randomUUID());
|
||||
notif1.setTitre("Bienvenue");
|
||||
notif1.setMessage("Bienvenue dans votre espace personnel UnionFlow");
|
||||
notif1.setDateCreation(LocalDate.now().minusDays(7));
|
||||
notif1.setLue(true);
|
||||
notifications.add(0, notif1);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning("Erreur lors du chargement des notifications: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le profil
|
||||
*/
|
||||
public void mettreAJourProfil() {
|
||||
try {
|
||||
if (membre != null) {
|
||||
membre = membreService.modifier(membre.getId(), membre);
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Votre profil a été mis à jour avec succès.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la mise à jour du profil: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de mettre à jour votre profil. Veuillez réessayer.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Actualise les données
|
||||
*/
|
||||
public void actualiser() {
|
||||
chargerProfil();
|
||||
chargerStatistiques();
|
||||
chargerActivitesRecentes();
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Données actualisées.");
|
||||
}
|
||||
|
||||
private void initialiserStatistiquesVides() {
|
||||
statistiques.setActionsRealisees(0);
|
||||
statistiques.setEvenementsParticipes(0);
|
||||
statistiques.setTauxParticipation(0.0);
|
||||
statistiques.setEvaluationMoyenne(0.0);
|
||||
}
|
||||
|
||||
private void ajouterMessage(FacesMessage.Severity severity, String summary, String detail) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(severity, summary, detail));
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public MembreDTO getMembre() { return membre; }
|
||||
public void setMembre(MembreDTO membre) { this.membre = membre; }
|
||||
|
||||
public StatistiquesProfil getStatistiques() { return statistiques; }
|
||||
public void setStatistiques(StatistiquesProfil statistiques) { this.statistiques = statistiques; }
|
||||
|
||||
public List<ActiviteRecente> getActivitesRecentes() { return activitesRecentes; }
|
||||
public void setActivitesRecentes(List<ActiviteRecente> activitesRecentes) { this.activitesRecentes = activitesRecentes; }
|
||||
|
||||
public List<DocumentPersonnel> getDocuments() { return documents; }
|
||||
public void setDocuments(List<DocumentPersonnel> documents) { this.documents = documents; }
|
||||
|
||||
public List<NotificationPersonnelle> getNotifications() { return notifications; }
|
||||
public void setNotifications(List<NotificationPersonnelle> notifications) { this.notifications = notifications; }
|
||||
|
||||
// Classes internes
|
||||
public static class StatistiquesProfil implements Serializable {
|
||||
private int actionsRealisees;
|
||||
private int evenementsParticipes;
|
||||
private double tauxParticipation;
|
||||
private double evaluationMoyenne;
|
||||
|
||||
public int getActionsRealisees() { return actionsRealisees; }
|
||||
public void setActionsRealisees(int actionsRealisees) { this.actionsRealisees = actionsRealisees; }
|
||||
|
||||
public int getEvenementsParticipes() { return evenementsParticipes; }
|
||||
public void setEvenementsParticipes(int evenementsParticipes) { this.evenementsParticipes = evenementsParticipes; }
|
||||
|
||||
public double getTauxParticipation() { return tauxParticipation; }
|
||||
public void setTauxParticipation(double tauxParticipation) { this.tauxParticipation = tauxParticipation; }
|
||||
|
||||
public double getEvaluationMoyenne() { return evaluationMoyenne; }
|
||||
public void setEvaluationMoyenne(double evaluationMoyenne) { this.evaluationMoyenne = evaluationMoyenne; }
|
||||
}
|
||||
|
||||
public static class ActiviteRecente implements Serializable {
|
||||
private String titre;
|
||||
private String description;
|
||||
private String dateHeure;
|
||||
private String icon;
|
||||
private String couleur;
|
||||
|
||||
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 getDateHeure() { return dateHeure; }
|
||||
public void setDateHeure(String dateHeure) { this.dateHeure = dateHeure; }
|
||||
|
||||
public String getIcon() { return icon; }
|
||||
public void setIcon(String icon) { this.icon = icon; }
|
||||
|
||||
public String getCouleur() { return couleur; }
|
||||
public void setCouleur(String couleur) { this.couleur = couleur; }
|
||||
}
|
||||
|
||||
public static class DocumentPersonnel implements Serializable {
|
||||
private UUID id;
|
||||
private String nom;
|
||||
private String type;
|
||||
private LocalDate dateCreation;
|
||||
private long taille;
|
||||
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
public String getNom() { return nom; }
|
||||
public void setNom(String nom) { this.nom = nom; }
|
||||
|
||||
public String getType() { return type; }
|
||||
public void setType(String type) { this.type = type; }
|
||||
|
||||
public LocalDate getDateCreation() { return dateCreation; }
|
||||
public void setDateCreation(LocalDate dateCreation) { this.dateCreation = dateCreation; }
|
||||
|
||||
public long getTaille() { return taille; }
|
||||
public void setTaille(long taille) { this.taille = taille; }
|
||||
}
|
||||
|
||||
public static class NotificationPersonnelle implements Serializable {
|
||||
private UUID id;
|
||||
private String titre;
|
||||
private String message;
|
||||
private LocalDate dateCreation;
|
||||
private boolean lue;
|
||||
|
||||
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 getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
|
||||
public LocalDate getDateCreation() { return dateCreation; }
|
||||
public void setDateCreation(LocalDate dateCreation) { this.dateCreation = dateCreation; }
|
||||
|
||||
public boolean isLue() { return lue; }
|
||||
public void setLue(boolean lue) { this.lue = lue; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.service.PreferencesService;
|
||||
import jakarta.enterprise.context.SessionScoped;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Bean pour la gestion des préférences utilisateur
|
||||
* Gère l'apparence, les notifications, la confidentialité et le tableau de bord
|
||||
*/
|
||||
@Named("preferencesBean")
|
||||
@SessionScoped
|
||||
public class PreferencesBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(PreferencesBean.class.getName());
|
||||
|
||||
@Inject
|
||||
private UserSession userSession;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private PreferencesService preferencesService;
|
||||
|
||||
// Apparence
|
||||
private String theme = "light";
|
||||
private String couleurAccent = "blue";
|
||||
private String langue = "fr";
|
||||
private String fuseauHoraire = "GMT";
|
||||
private String formatDate = "dd/mm/yyyy";
|
||||
|
||||
// Notifications
|
||||
private boolean notifEvenements = true;
|
||||
private boolean notifMessages = true;
|
||||
private boolean notifCotisations = true;
|
||||
private boolean notifSysteme = false;
|
||||
private boolean emailQuotidien = false;
|
||||
private boolean emailHebdo = true;
|
||||
private boolean emailUrgent = true;
|
||||
private boolean emailPromo = false;
|
||||
private boolean smsUrgent = false;
|
||||
private boolean smsRappels = false;
|
||||
private boolean smsEvenements = false;
|
||||
private String heuresSMS = "08-20";
|
||||
|
||||
// Confidentialité
|
||||
private String visibiliteProfil = "publique";
|
||||
private boolean doubleAuth = true;
|
||||
private boolean connexionSecure = true;
|
||||
private boolean deconnexionAuto = false;
|
||||
private String dureeSession = "480";
|
||||
|
||||
// Tableau de bord
|
||||
private boolean widgetActivites = true;
|
||||
private boolean widgetEvenements = true;
|
||||
private boolean widgetCotisations = false;
|
||||
private boolean widgetNotifications = true;
|
||||
private boolean widgetStatistiques = false;
|
||||
private boolean widgetMeteo = false;
|
||||
private String layoutDashboard = "grid-3";
|
||||
private String pageAccueil = "dashboard";
|
||||
private String elementsPage = "25";
|
||||
private boolean animations = true;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
chargerPreferences();
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge les préférences depuis le backend
|
||||
*/
|
||||
private void chargerPreferences() {
|
||||
try {
|
||||
UUID userId = userSession.getCurrentUser().getId();
|
||||
if (userId != null) {
|
||||
Map<String, Boolean> prefs = preferencesService.obtenirPreferences(userId);
|
||||
|
||||
// Mapper les préférences du backend vers les propriétés du bean
|
||||
notifEvenements = prefs.getOrDefault("NOUVEL_EVENEMENT", true);
|
||||
notifCotisations = prefs.getOrDefault("NOUVELLE_COTISATION", true);
|
||||
notifSysteme = prefs.getOrDefault("NOUVEAU_MEMBRE", false);
|
||||
emailUrgent = prefs.getOrDefault("EMAIL", true);
|
||||
smsUrgent = prefs.getOrDefault("SMS", false);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.warning(() -> "Erreur lors du chargement des préférences: " + e.getMessage());
|
||||
// Utiliser les valeurs par défaut en cas d'erreur
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde toutes les préférences
|
||||
*/
|
||||
public void sauvegarderPreferences() {
|
||||
try {
|
||||
UUID userId = userSession.getCurrentUser().getId();
|
||||
if (userId == null) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Utilisateur non identifié");
|
||||
return;
|
||||
}
|
||||
|
||||
// Créer un Map avec toutes les préférences de notification
|
||||
Map<String, Boolean> prefs = new HashMap<>();
|
||||
prefs.put("NOUVEL_EVENEMENT", notifEvenements);
|
||||
prefs.put("NOUVELLE_COTISATION", notifCotisations);
|
||||
prefs.put("NOUVEAU_MEMBRE", notifSysteme);
|
||||
prefs.put("EMAIL", emailUrgent);
|
||||
prefs.put("SMS", smsUrgent);
|
||||
prefs.put("RAPPEL_COTISATION", smsRappels);
|
||||
prefs.put("RAPPEL_EVENEMENT", smsEvenements);
|
||||
|
||||
// Appeler le service backend
|
||||
preferencesService.mettreAJourPreferences(userId, prefs);
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Vos préférences ont été enregistrées avec succès");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de la sauvegarde: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible d'enregistrer les préférences: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialise les préférences aux valeurs par défaut
|
||||
*/
|
||||
public void reinitialiserPreferences() {
|
||||
try {
|
||||
UUID userId = userSession.getCurrentUser().getId();
|
||||
if (userId == null) {
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Utilisateur non identifié");
|
||||
return;
|
||||
}
|
||||
|
||||
preferencesService.reinitialiserPreferences(userId);
|
||||
|
||||
// Recharger les préférences
|
||||
chargerPreferences();
|
||||
|
||||
// Réinitialiser les autres préférences locales
|
||||
theme = "light";
|
||||
couleurAccent = "blue";
|
||||
langue = "fr";
|
||||
fuseauHoraire = "GMT";
|
||||
formatDate = "dd/mm/yyyy";
|
||||
|
||||
emailQuotidien = false;
|
||||
emailHebdo = true;
|
||||
emailPromo = false;
|
||||
|
||||
visibiliteProfil = "publique";
|
||||
doubleAuth = true;
|
||||
connexionSecure = true;
|
||||
deconnexionAuto = false;
|
||||
dureeSession = "480";
|
||||
|
||||
widgetActivites = true;
|
||||
widgetEvenements = true;
|
||||
widgetCotisations = false;
|
||||
widgetNotifications = true;
|
||||
widgetStatistiques = false;
|
||||
widgetMeteo = false;
|
||||
layoutDashboard = "grid-3";
|
||||
pageAccueil = "dashboard";
|
||||
elementsPage = "25";
|
||||
animations = true;
|
||||
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès",
|
||||
"Les préférences ont été réinitialisées aux valeurs par défaut");
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe(() -> "Erreur lors de la réinitialisation: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de réinitialiser les préférences: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void ajouterMessage(FacesMessage.Severity severity, String summary, String detail) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(severity, summary, detail));
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public String getTheme() { return theme; }
|
||||
public void setTheme(String theme) { this.theme = theme; }
|
||||
|
||||
public String getCouleurAccent() { return couleurAccent; }
|
||||
public void setCouleurAccent(String couleurAccent) { this.couleurAccent = couleurAccent; }
|
||||
|
||||
public String getLangue() { return langue; }
|
||||
public void setLangue(String langue) { this.langue = langue; }
|
||||
|
||||
public String getFuseauHoraire() { return fuseauHoraire; }
|
||||
public void setFuseauHoraire(String fuseauHoraire) { this.fuseauHoraire = fuseauHoraire; }
|
||||
|
||||
public String getFormatDate() { return formatDate; }
|
||||
public void setFormatDate(String formatDate) { this.formatDate = formatDate; }
|
||||
|
||||
public boolean isNotifEvenements() { return notifEvenements; }
|
||||
public void setNotifEvenements(boolean notifEvenements) { this.notifEvenements = notifEvenements; }
|
||||
|
||||
public boolean isNotifMessages() { return notifMessages; }
|
||||
public void setNotifMessages(boolean notifMessages) { this.notifMessages = notifMessages; }
|
||||
|
||||
public boolean isNotifCotisations() { return notifCotisations; }
|
||||
public void setNotifCotisations(boolean notifCotisations) { this.notifCotisations = notifCotisations; }
|
||||
|
||||
public boolean isNotifSysteme() { return notifSysteme; }
|
||||
public void setNotifSysteme(boolean notifSysteme) { this.notifSysteme = notifSysteme; }
|
||||
|
||||
public boolean isEmailQuotidien() { return emailQuotidien; }
|
||||
public void setEmailQuotidien(boolean emailQuotidien) { this.emailQuotidien = emailQuotidien; }
|
||||
|
||||
public boolean isEmailHebdo() { return emailHebdo; }
|
||||
public void setEmailHebdo(boolean emailHebdo) { this.emailHebdo = emailHebdo; }
|
||||
|
||||
public boolean isEmailUrgent() { return emailUrgent; }
|
||||
public void setEmailUrgent(boolean emailUrgent) { this.emailUrgent = emailUrgent; }
|
||||
|
||||
public boolean isEmailPromo() { return emailPromo; }
|
||||
public void setEmailPromo(boolean emailPromo) { this.emailPromo = emailPromo; }
|
||||
|
||||
public boolean isSmsUrgent() { return smsUrgent; }
|
||||
public void setSmsUrgent(boolean smsUrgent) { this.smsUrgent = smsUrgent; }
|
||||
|
||||
public boolean isSmsRappels() { return smsRappels; }
|
||||
public void setSmsRappels(boolean smsRappels) { this.smsRappels = smsRappels; }
|
||||
|
||||
public boolean isSmsEvenements() { return smsEvenements; }
|
||||
public void setSmsEvenements(boolean smsEvenements) { this.smsEvenements = smsEvenements; }
|
||||
|
||||
public String getHeuresSMS() { return heuresSMS; }
|
||||
public void setHeuresSMS(String heuresSMS) { this.heuresSMS = heuresSMS; }
|
||||
|
||||
public String getVisibiliteProfil() { return visibiliteProfil; }
|
||||
public void setVisibiliteProfil(String visibiliteProfil) { this.visibiliteProfil = visibiliteProfil; }
|
||||
|
||||
public boolean isDoubleAuth() { return doubleAuth; }
|
||||
public void setDoubleAuth(boolean doubleAuth) { this.doubleAuth = doubleAuth; }
|
||||
|
||||
public boolean isConnexionSecure() { return connexionSecure; }
|
||||
public void setConnexionSecure(boolean connexionSecure) { this.connexionSecure = connexionSecure; }
|
||||
|
||||
public boolean isDeconnexionAuto() { return deconnexionAuto; }
|
||||
public void setDeconnexionAuto(boolean deconnexionAuto) { this.deconnexionAuto = deconnexionAuto; }
|
||||
|
||||
public String getDureeSession() { return dureeSession; }
|
||||
public void setDureeSession(String dureeSession) { this.dureeSession = dureeSession; }
|
||||
|
||||
public boolean isWidgetActivites() { return widgetActivites; }
|
||||
public void setWidgetActivites(boolean widgetActivites) { this.widgetActivites = widgetActivites; }
|
||||
|
||||
public boolean isWidgetEvenements() { return widgetEvenements; }
|
||||
public void setWidgetEvenements(boolean widgetEvenements) { this.widgetEvenements = widgetEvenements; }
|
||||
|
||||
public boolean isWidgetCotisations() { return widgetCotisations; }
|
||||
public void setWidgetCotisations(boolean widgetCotisations) { this.widgetCotisations = widgetCotisations; }
|
||||
|
||||
public boolean isWidgetNotifications() { return widgetNotifications; }
|
||||
public void setWidgetNotifications(boolean widgetNotifications) { this.widgetNotifications = widgetNotifications; }
|
||||
|
||||
public boolean isWidgetStatistiques() { return widgetStatistiques; }
|
||||
public void setWidgetStatistiques(boolean widgetStatistiques) { this.widgetStatistiques = widgetStatistiques; }
|
||||
|
||||
public boolean isWidgetMeteo() { return widgetMeteo; }
|
||||
public void setWidgetMeteo(boolean widgetMeteo) { this.widgetMeteo = widgetMeteo; }
|
||||
|
||||
public String getLayoutDashboard() { return layoutDashboard; }
|
||||
public void setLayoutDashboard(String layoutDashboard) { this.layoutDashboard = layoutDashboard; }
|
||||
|
||||
public String getPageAccueil() { return pageAccueil; }
|
||||
public void setPageAccueil(String pageAccueil) { this.pageAccueil = pageAccueil; }
|
||||
|
||||
public String getElementsPage() { return elementsPage; }
|
||||
public void setElementsPage(String elementsPage) { this.elementsPage = elementsPage; }
|
||||
|
||||
public boolean isAnimations() { return animations; }
|
||||
public void setAnimations(boolean animations) { this.animations = animations; }
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.dto.AnalyticsDataDTO;
|
||||
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.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
@@ -16,6 +17,7 @@ import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.logging.Logger;
|
||||
@@ -26,6 +28,7 @@ public class RapportsBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(RapportsBean.class.getName());
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy");
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
@@ -43,28 +46,26 @@ public class RapportsBean implements Serializable {
|
||||
@RestClient
|
||||
private EvenementService evenementService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private DemandeAideService demandeAideService;
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
private AssociationService associationService;
|
||||
|
||||
private String organisationId; // À injecter depuis la session
|
||||
|
||||
// Filtres de période
|
||||
private String periodeRapide;
|
||||
private LocalDate dateDebut;
|
||||
private LocalDate dateFin;
|
||||
private String groupeComparaison;
|
||||
|
||||
// Données analytics
|
||||
private Map<String, Object> kpis;
|
||||
private Map<String, Object> evolutions;
|
||||
|
||||
// Données calculées pour l'affichage
|
||||
private IndicateursGlobaux indicateurs;
|
||||
private List<EvolutionMensuelle> evolutionMensuelle;
|
||||
private List<Objectif> objectifs;
|
||||
private List<RepartitionMembres> repartitionMembres;
|
||||
private List<SourceRevenus> sourceRevenus;
|
||||
private List<TopEntite> topEntites;
|
||||
private List<KPI> kpis;
|
||||
private List<KPI> kpisList;
|
||||
private List<Alerte> alertes;
|
||||
private List<HistoriqueRapport> historiqueRapports;
|
||||
|
||||
@@ -74,130 +75,117 @@ public class RapportsBean implements Serializable {
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
initializePeriodes();
|
||||
initializeIndicateurs();
|
||||
initializeEvolutionMensuelle();
|
||||
initializeObjectifs();
|
||||
initializeRepartitions();
|
||||
initializeTopEntites();
|
||||
initializeKPIs();
|
||||
initializeAlertes();
|
||||
initializeHistoriqueRapports();
|
||||
initializeNouveauRapport();
|
||||
chargerDonnees();
|
||||
}
|
||||
|
||||
private void initializePeriodes() {
|
||||
periodeRapide = "30_JOURS";
|
||||
periodeRapide = "TRENTE_DERNIERS_JOURS";
|
||||
dateDebut = LocalDate.now().minusDays(30);
|
||||
dateFin = LocalDate.now();
|
||||
groupeComparaison = "PERIODE_PRECEDENTE";
|
||||
}
|
||||
|
||||
private void initializeIndicateurs() {
|
||||
/**
|
||||
* Charge les données depuis le backend
|
||||
*/
|
||||
public void chargerDonnees() {
|
||||
try {
|
||||
String periode = mapperPeriode(periodeRapide);
|
||||
|
||||
// Charger les KPIs depuis le backend
|
||||
kpis = analyticsService.obtenirTousLesKPI(organisationId, periode);
|
||||
|
||||
// Charger les évolutions
|
||||
evolutions = analyticsService.obtenirEvolutionsKPI(organisationId, periode);
|
||||
|
||||
// Calculer les indicateurs globaux
|
||||
calculerIndicateurs();
|
||||
|
||||
// Calculer les répartitions
|
||||
calculerRepartitions();
|
||||
|
||||
// Calculer les objectifs
|
||||
calculerObjectifs();
|
||||
|
||||
// Initialiser les listes vides
|
||||
evolutionMensuelle = new ArrayList<>();
|
||||
topEntites = new ArrayList<>();
|
||||
kpisList = new ArrayList<>();
|
||||
alertes = new ArrayList<>();
|
||||
historiqueRapports = new ArrayList<>();
|
||||
|
||||
// Convertir les KPIs en liste pour l'affichage
|
||||
convertirKPIsEnListe();
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des données: " + e.getMessage());
|
||||
ajouterMessage(FacesMessage.SEVERITY_ERROR, "Erreur",
|
||||
"Impossible de charger les données. Veuillez réessayer.");
|
||||
initialiserDonneesVides();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mappe la période rapide vers le format backend
|
||||
*/
|
||||
private String mapperPeriode(String periodeRapide) {
|
||||
return switch (periodeRapide) {
|
||||
case "7_JOURS" -> "SEPT_DERNIERS_JOURS";
|
||||
case "30_JOURS", "TRENTE_DERNIERS_JOURS" -> "TRENTE_DERNIERS_JOURS";
|
||||
case "3_MOIS" -> "TROIS_DERNIERS_MOIS";
|
||||
case "6_MOIS" -> "SIX_DERNIERS_MOIS";
|
||||
case "ANNEE_COURANTE" -> "CETTE_ANNEE";
|
||||
default -> "TRENTE_DERNIERS_JOURS";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcule les indicateurs globaux depuis les données réelles
|
||||
*/
|
||||
private void calculerIndicateurs() {
|
||||
indicateurs = new IndicateursGlobaux();
|
||||
try {
|
||||
int totalMembres = membreService.listerTous().size();
|
||||
int totalEvenements = evenementService.listerTous(0, 1000).size();
|
||||
int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").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);
|
||||
|
||||
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.setCroissanceMembres(calculerCroissance("NOMBRE_MEMBRES_ACTIFS"));
|
||||
indicateurs.setRevenus(formatMontantCourt(totalRevenus) + " FCFA");
|
||||
indicateurs.setCroissanceRevenus(0.0); // À calculer depuis les données historiques
|
||||
indicateurs.setCroissanceRevenus(calculerCroissance("TOTAL_COTISATIONS_COLLECTEES"));
|
||||
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
|
||||
indicateurs.setCroissanceEvenements(calculerCroissance("NOMBRE_EVENEMENTS_ORGANISES"));
|
||||
indicateurs.setTotalAides(formatMontantCourt(BigDecimal.ZERO) + " FCFA");
|
||||
indicateurs.setCroissanceAides(0.0);
|
||||
} 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);
|
||||
initialiserIndicateursVides();
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeEvolutionMensuelle() {
|
||||
evolutionMensuelle = new ArrayList<>();
|
||||
try {
|
||||
if (organisationId != null && dateDebut != null && dateFin != null) {
|
||||
String periode = "CUSTOM"; // À mapper depuis dateDebut/dateFin
|
||||
analyticsService.getEvolutionMensuelle("NOMBRE_MEMBRES_ACTIFS", organisationId, periode);
|
||||
// Traiter les données de l'API
|
||||
// Pour l'instant, initialiser avec des données vides
|
||||
/**
|
||||
* Calcule la croissance depuis les évolutions
|
||||
*/
|
||||
private double calculerCroissance(String typeMetrique) {
|
||||
if (evolutions != null && evolutions.containsKey(typeMetrique)) {
|
||||
Object evolution = evolutions.get(typeMetrique);
|
||||
if (evolution instanceof BigDecimal) {
|
||||
return ((BigDecimal) evolution).doubleValue();
|
||||
} else if (evolution instanceof Number) {
|
||||
return ((Number) evolution).doubleValue();
|
||||
}
|
||||
} 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
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
private void initializeObjectifs() {
|
||||
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();
|
||||
obj1.setLibelle("Nouveaux Membres");
|
||||
obj1.setRealise(String.valueOf(totalMembres));
|
||||
obj1.setCible(String.valueOf((int) (totalMembres * 1.2))); // Objectif 20% supérieur
|
||||
obj1.setPourcentage(totalMembres > 0 ? (int) ((double) totalMembres / (totalMembres * 1.2) * 100) : 0);
|
||||
objectifs.add(obj1);
|
||||
|
||||
Objectif obj2 = new Objectif();
|
||||
obj2.setLibelle("Revenus Cotisations");
|
||||
obj2.setRealise(formatMontantCourt(totalRevenus));
|
||||
obj2.setCible(formatMontantCourt(totalRevenus.multiply(new BigDecimal("1.2"))));
|
||||
obj2.setPourcentage(83); // À calculer
|
||||
objectifs.add(obj2);
|
||||
|
||||
Objectif obj3 = new Objectif();
|
||||
obj3.setLibelle("Événements Organisés");
|
||||
obj3.setRealise(String.valueOf(totalEvenements));
|
||||
obj3.setCible(String.valueOf((int) (totalEvenements * 1.2)));
|
||||
obj3.setPourcentage(totalEvenements > 0 ? (int) ((double) totalEvenements / (totalEvenements * 1.2) * 100) : 0);
|
||||
objectifs.add(obj3);
|
||||
|
||||
Objectif obj4 = new Objectif();
|
||||
obj4.setLibelle("Aides Accordées");
|
||||
obj4.setRealise(String.valueOf(totalDemandes));
|
||||
obj4.setCible(String.valueOf((int) (totalDemandes * 1.3)));
|
||||
obj4.setPourcentage(totalDemandes > 0 ? (int) ((double) totalDemandes / (totalDemandes * 1.3) * 100) : 0);
|
||||
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() {
|
||||
/**
|
||||
* Calcule les répartitions
|
||||
*/
|
||||
private void calculerRepartitions() {
|
||||
repartitionMembres = new ArrayList<>();
|
||||
try {
|
||||
List<dev.lions.unionflow.client.dto.MembreDTO> membres = membreService.listerTous();
|
||||
@@ -235,7 +223,7 @@ public class RapportsBean implements Serializable {
|
||||
SourceRevenus cotisations = new SourceRevenus();
|
||||
cotisations.setLibelle("Cotisations");
|
||||
cotisations.setMontant(formatMontantCourt(totalRevenus));
|
||||
cotisations.setPourcentage(100.0); // Pour l'instant, uniquement cotisations
|
||||
cotisations.setPourcentage(100.0);
|
||||
cotisations.setCouleur("blue-500");
|
||||
cotisations.setIcon("pi-users");
|
||||
sourceRevenus.add(cotisations);
|
||||
@@ -245,71 +233,141 @@ public class RapportsBean implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeTopEntites() {
|
||||
topEntites = new ArrayList<>();
|
||||
/**
|
||||
* Calcule les objectifs
|
||||
*/
|
||||
private void calculerObjectifs() {
|
||||
objectifs = new ArrayList<>();
|
||||
try {
|
||||
List<dev.lions.unionflow.client.dto.AssociationDTO> associations = associationService.listerActives();
|
||||
topEntites = associations.stream()
|
||||
.sorted((a1, a2) -> {
|
||||
int m1 = a1.getNombreMembres() != null ? a1.getNombreMembres() : 0;
|
||||
int m2 = a2.getNombreMembres() != null ? a2.getNombreMembres() : 0;
|
||||
return Integer.compare(m2, m1);
|
||||
})
|
||||
.limit(5)
|
||||
.map(a -> {
|
||||
TopEntite entite = new TopEntite();
|
||||
entite.setRang(0); // À calculer
|
||||
entite.setNom(a.getNom());
|
||||
entite.setTypeIcon("pi-users");
|
||||
entite.setScore(0); // À calculer depuis les métriques
|
||||
entite.setTendance("STABLE"); // À calculer
|
||||
return entite;
|
||||
})
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
int totalMembres = membreService.listerTous().size();
|
||||
int totalEvenements = evenementService.listerTous(0, 1000, "dateCreation", "desc").size();
|
||||
|
||||
// Assigner les rangs
|
||||
for (int i = 0; i < topEntites.size(); i++) {
|
||||
topEntites.get(i).setRang(i + 1);
|
||||
}
|
||||
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();
|
||||
obj1.setLibelle("Nouveaux Membres");
|
||||
obj1.setRealise(String.valueOf(totalMembres));
|
||||
int cibleMembres = (int) (totalMembres * 1.2);
|
||||
obj1.setCible(String.valueOf(cibleMembres));
|
||||
obj1.setPourcentage(totalMembres > 0 ? (int) ((double) totalMembres / cibleMembres * 100) : 0);
|
||||
objectifs.add(obj1);
|
||||
|
||||
Objectif obj2 = new Objectif();
|
||||
obj2.setLibelle("Revenus Cotisations");
|
||||
obj2.setRealise(formatMontantCourt(totalRevenus));
|
||||
BigDecimal cibleRevenus = totalRevenus.multiply(new BigDecimal("1.2"));
|
||||
obj2.setCible(formatMontantCourt(cibleRevenus));
|
||||
obj2.setPourcentage(totalRevenus.compareTo(BigDecimal.ZERO) > 0 ?
|
||||
(int) (totalRevenus.divide(cibleRevenus, 2, java.math.RoundingMode.HALF_UP).doubleValue() * 100) : 0);
|
||||
objectifs.add(obj2);
|
||||
|
||||
Objectif obj3 = new Objectif();
|
||||
obj3.setLibelle("Événements Organisés");
|
||||
obj3.setRealise(String.valueOf(totalEvenements));
|
||||
int cibleEvenements = (int) (totalEvenements * 1.2);
|
||||
obj3.setCible(String.valueOf(cibleEvenements));
|
||||
obj3.setPourcentage(totalEvenements > 0 ? (int) ((double) totalEvenements / cibleEvenements * 100) : 0);
|
||||
objectifs.add(obj3);
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des top entités: " + e.getMessage());
|
||||
LOGGER.severe("Erreur lors du calcul des objectifs: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeKPIs() {
|
||||
kpis = new ArrayList<>();
|
||||
try {
|
||||
if (organisationId != null && dateDebut != null && dateFin != null) {
|
||||
String periode = "CUSTOM"; // À mapper depuis dateDebut/dateFin
|
||||
analyticsService.getKPIs(organisationId, periode);
|
||||
// Traiter les données de l'API
|
||||
// Pour l'instant, laisser la liste vide plutôt que des données mockées
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des KPIs: " + e.getMessage());
|
||||
/**
|
||||
* Convertit les KPIs Map en liste pour l'affichage
|
||||
*/
|
||||
private void convertirKPIsEnListe() {
|
||||
kpisList = new ArrayList<>();
|
||||
if (kpis != null) {
|
||||
kpis.forEach((type, valeur) -> {
|
||||
KPI kpi = new KPI();
|
||||
kpi.setLibelle(getLibelleMetrique(type.toString()));
|
||||
kpi.setValeur(valeur instanceof BigDecimal ?
|
||||
((BigDecimal) valeur).toPlainString() : valeur.toString());
|
||||
kpi.setProgression(0);
|
||||
kpi.setVariation(calculerCroissance(type.toString()));
|
||||
kpi.setTendance(kpi.getVariation() > 0 ? "HAUSSE" : kpi.getVariation() < 0 ? "BAISSE" : "STABLE");
|
||||
kpi.setIcon(getIconeMetrique(type.toString()));
|
||||
kpi.setCouleur(getCouleurMetrique(type.toString()));
|
||||
kpisList.add(kpi);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeAlertes() {
|
||||
private String getLibelleMetrique(String type) {
|
||||
return switch (type) {
|
||||
case "NOMBRE_MEMBRES_ACTIFS" -> "Membres Actifs";
|
||||
case "TOTAL_COTISATIONS_COLLECTEES" -> "Cotisations Collectées";
|
||||
case "NOMBRE_EVENEMENTS_ORGANISES" -> "Événements Organisés";
|
||||
default -> type;
|
||||
};
|
||||
}
|
||||
|
||||
private String getIconeMetrique(String type) {
|
||||
return switch (type) {
|
||||
case "NOMBRE_MEMBRES_ACTIFS" -> "pi-users";
|
||||
case "TOTAL_COTISATIONS_COLLECTEES" -> "pi-dollar";
|
||||
case "NOMBRE_EVENEMENTS_ORGANISES" -> "pi-calendar";
|
||||
default -> "pi-chart-bar";
|
||||
};
|
||||
}
|
||||
|
||||
private String getCouleurMetrique(String type) {
|
||||
return switch (type) {
|
||||
case "NOMBRE_MEMBRES_ACTIFS" -> "blue-500";
|
||||
case "TOTAL_COTISATIONS_COLLECTEES" -> "green-500";
|
||||
case "NOMBRE_EVENEMENTS_ORGANISES" -> "orange-500";
|
||||
default -> "gray-500";
|
||||
};
|
||||
}
|
||||
|
||||
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 initialiserDonneesVides() {
|
||||
indicateurs = new IndicateursGlobaux();
|
||||
initialiserIndicateursVides();
|
||||
evolutionMensuelle = new ArrayList<>();
|
||||
objectifs = new ArrayList<>();
|
||||
repartitionMembres = new ArrayList<>();
|
||||
sourceRevenus = new ArrayList<>();
|
||||
topEntites = new ArrayList<>();
|
||||
kpisList = new ArrayList<>();
|
||||
alertes = new ArrayList<>();
|
||||
// Les alertes seront calculées depuis les données réelles
|
||||
// Pour l'instant, laisser la liste vide plutôt que des données mockées
|
||||
}
|
||||
|
||||
private void initializeHistoriqueRapports() {
|
||||
historiqueRapports = new ArrayList<>();
|
||||
// L'historique des rapports sera chargé depuis la base de données
|
||||
// Pour l'instant, laisser la liste vide plutôt que des données mockées
|
||||
}
|
||||
|
||||
private void initializeNouveauRapport() {
|
||||
nouveauRapport = new NouveauRapport();
|
||||
nouveauRapport.setFormat("PDF");
|
||||
nouveauRapport.setPeriode("30_JOURS");
|
||||
nouveauRapport.setDetail("STANDARD");
|
||||
private void initialiserIndicateursVides() {
|
||||
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);
|
||||
}
|
||||
|
||||
// Actions
|
||||
/**
|
||||
* Actualise les données
|
||||
*/
|
||||
public void actualiser() {
|
||||
chargerDonnees();
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Données actualisées avec succès.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère un nouveau rapport
|
||||
*/
|
||||
public void genererRapport() {
|
||||
LOGGER.info("Génération du rapport " + nouveauRapport.getType() + " en format " + nouveauRapport.getFormat());
|
||||
|
||||
@@ -326,6 +384,14 @@ public class RapportsBean implements Serializable {
|
||||
|
||||
historiqueRapports.add(0, nouveauHistorique);
|
||||
initializeNouveauRapport();
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Succès", "Rapport en cours de génération.");
|
||||
}
|
||||
|
||||
private void initializeNouveauRapport() {
|
||||
nouveauRapport = new NouveauRapport();
|
||||
nouveauRapport.setFormat("PDF");
|
||||
nouveauRapport.setPeriode("30_JOURS");
|
||||
nouveauRapport.setDetail("STANDARD");
|
||||
}
|
||||
|
||||
private String getTypeLibelle(String type) {
|
||||
@@ -374,20 +440,33 @@ public class RapportsBean implements Serializable {
|
||||
}
|
||||
|
||||
public String voirRapport(HistoriqueRapport rapport) {
|
||||
return "/pages/admin/rapports/details?id=" + rapport.getId() + "&faces-redirect=true";
|
||||
rapportSelectionne = rapport;
|
||||
return "/pages/secure/rapport/details?faces-redirect=true";
|
||||
}
|
||||
|
||||
public void telechargerRapport(HistoriqueRapport rapport) {
|
||||
LOGGER.info("Téléchargement du rapport: " + rapport.getTypeLibelle());
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Téléchargement",
|
||||
"Le téléchargement du rapport va commencer.");
|
||||
}
|
||||
|
||||
public void exporterDonnees() {
|
||||
LOGGER.info("Export des données statistiques");
|
||||
ajouterMessage(FacesMessage.SEVERITY_INFO, "Export",
|
||||
"L'export des données va commencer.");
|
||||
}
|
||||
|
||||
private void ajouterMessage(FacesMessage.Severity severity, String summary, String detail) {
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(severity, summary, detail));
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public String getPeriodeRapide() { return periodeRapide; }
|
||||
public void setPeriodeRapide(String periodeRapide) { this.periodeRapide = periodeRapide; }
|
||||
public void setPeriodeRapide(String periodeRapide) {
|
||||
this.periodeRapide = periodeRapide;
|
||||
chargerDonnees();
|
||||
}
|
||||
|
||||
public LocalDate getDateDebut() { return dateDebut; }
|
||||
public void setDateDebut(LocalDate dateDebut) { this.dateDebut = dateDebut; }
|
||||
@@ -416,8 +495,8 @@ public class RapportsBean implements Serializable {
|
||||
public List<TopEntite> getTopEntites() { return topEntites; }
|
||||
public void setTopEntites(List<TopEntite> topEntites) { this.topEntites = topEntites; }
|
||||
|
||||
public List<KPI> getKpis() { return kpis; }
|
||||
public void setKpis(List<KPI> kpis) { this.kpis = kpis; }
|
||||
public List<KPI> getKpis() { return kpisList; }
|
||||
public void setKpis(List<KPI> kpis) { this.kpisList = kpis; }
|
||||
|
||||
public List<Alerte> getAlertes() { return alertes; }
|
||||
public void setAlertes(List<Alerte> alertes) { this.alertes = alertes; }
|
||||
@@ -431,7 +510,7 @@ public class RapportsBean implements Serializable {
|
||||
public HistoriqueRapport getRapportSelectionne() { return rapportSelectionne; }
|
||||
public void setRapportSelectionne(HistoriqueRapport rapportSelectionne) { this.rapportSelectionne = rapportSelectionne; }
|
||||
|
||||
// Classes internes
|
||||
// Classes internes (conservées pour compatibilité avec les pages XHTML)
|
||||
public static class IndicateursGlobaux {
|
||||
private int totalMembres;
|
||||
private double croissanceMembres;
|
||||
@@ -442,7 +521,6 @@ public class RapportsBean implements Serializable {
|
||||
private String totalAides;
|
||||
private double croissanceAides;
|
||||
|
||||
// Getters et setters
|
||||
public int getTotalMembres() { return totalMembres; }
|
||||
public void setTotalMembres(int totalMembres) { this.totalMembres = totalMembres; }
|
||||
|
||||
@@ -475,7 +553,6 @@ public class RapportsBean implements Serializable {
|
||||
private int hauteurMembres;
|
||||
private int hauteurRevenus;
|
||||
|
||||
// Getters et setters
|
||||
public String getLibelle() { return libelle; }
|
||||
public void setLibelle(String libelle) { this.libelle = libelle; }
|
||||
|
||||
@@ -498,7 +575,6 @@ public class RapportsBean implements Serializable {
|
||||
private String cible;
|
||||
private int pourcentage;
|
||||
|
||||
// Getters et setters
|
||||
public String getLibelle() { return libelle; }
|
||||
public void setLibelle(String libelle) { this.libelle = libelle; }
|
||||
|
||||
@@ -518,7 +594,6 @@ public class RapportsBean implements Serializable {
|
||||
private double pourcentage;
|
||||
private String couleur;
|
||||
|
||||
// Getters et setters
|
||||
public String getLibelle() { return libelle; }
|
||||
public void setLibelle(String libelle) { this.libelle = libelle; }
|
||||
|
||||
@@ -539,7 +614,6 @@ public class RapportsBean implements Serializable {
|
||||
private String couleur;
|
||||
private String icon;
|
||||
|
||||
// Getters et setters
|
||||
public String getLibelle() { return libelle; }
|
||||
public void setLibelle(String libelle) { this.libelle = libelle; }
|
||||
|
||||
@@ -563,7 +637,6 @@ public class RapportsBean implements Serializable {
|
||||
private int score;
|
||||
private String tendance;
|
||||
|
||||
// Getters et setters
|
||||
public int getRang() { return rang; }
|
||||
public void setRang(int rang) { this.rang = rang; }
|
||||
|
||||
@@ -589,7 +662,6 @@ public class RapportsBean implements Serializable {
|
||||
private String icon;
|
||||
private String couleur;
|
||||
|
||||
// Getters et setters
|
||||
public String getLibelle() { return libelle; }
|
||||
public void setLibelle(String libelle) { this.libelle = libelle; }
|
||||
|
||||
@@ -621,7 +693,6 @@ public class RapportsBean implements Serializable {
|
||||
private String icon;
|
||||
private String dateDetection;
|
||||
|
||||
// Getters et setters
|
||||
public String getTitre() { return titre; }
|
||||
public void setTitre(String titre) { this.titre = titre; }
|
||||
|
||||
@@ -655,7 +726,6 @@ public class RapportsBean implements Serializable {
|
||||
private String generePar;
|
||||
private String statut;
|
||||
|
||||
// Getters et setters
|
||||
public UUID getId() { return id; }
|
||||
public void setId(UUID id) { this.id = id; }
|
||||
|
||||
@@ -685,7 +755,7 @@ public class RapportsBean implements Serializable {
|
||||
|
||||
public String getDateGenerationFormatee() {
|
||||
if (dateGeneration == null) return "";
|
||||
return dateGeneration.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
return dateGeneration.format(DATE_FORMATTER);
|
||||
}
|
||||
|
||||
public String getStatutSeverity() {
|
||||
@@ -706,7 +776,6 @@ public class RapportsBean implements Serializable {
|
||||
private String detail;
|
||||
private String commentaires;
|
||||
|
||||
// Getters et setters
|
||||
public String getType() { return type; }
|
||||
public void setType(String type) { this.type = type; }
|
||||
|
||||
@@ -722,4 +791,4 @@ public class RapportsBean implements Serializable {
|
||||
public String getCommentaires() { return commentaires; }
|
||||
public void setCommentaires(String commentaires) { this.commentaires = commentaires; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public class SuperAdminBean implements Serializable {
|
||||
|
||||
private void initializeKPIs() {
|
||||
try {
|
||||
List<AssociationDTO> associations = associationService.listerToutes();
|
||||
List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
|
||||
totalEntites = associations.size();
|
||||
totalAdministrateurs = associations.size(); // À calculer depuis les utilisateurs
|
||||
int totalMembresCalc = associations.stream()
|
||||
@@ -183,7 +183,7 @@ public class SuperAdminBean implements Serializable {
|
||||
private void initializeEntites() {
|
||||
topEntites = new ArrayList<>();
|
||||
try {
|
||||
List<AssociationDTO> associations = associationService.listerActives();
|
||||
List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
|
||||
topEntites = associations.stream()
|
||||
.sorted((a1, a2) -> {
|
||||
int m1 = a1.getNombreMembres() != null ? a1.getNombreMembres() : 0;
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.dto.TypeOrganisationClientDTO;
|
||||
import dev.lions.unionflow.client.service.TypeOrganisationClientService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||
|
||||
/**
|
||||
* Bean de gestion du catalogue des types d'organisation (UI Super Admin).
|
||||
*/
|
||||
@Named("typeOrganisationsAdminBean")
|
||||
@ViewScoped
|
||||
public class TypeOrganisationsAdminBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final Logger LOGGER = Logger.getLogger(TypeOrganisationsAdminBean.class.getName());
|
||||
|
||||
@Inject
|
||||
@RestClient
|
||||
TypeOrganisationClientService typeOrganisationClientService;
|
||||
|
||||
private List<TypeOrganisationClientDTO> types = new ArrayList<>();
|
||||
/** Type actuellement édité dans le dialogue (nouveau ou existant). */
|
||||
private TypeOrganisationClientDTO typeCourant;
|
||||
private TypeOrganisationClientDTO typeSelectionne;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
chargerTypes();
|
||||
}
|
||||
|
||||
public void chargerTypes() {
|
||||
try {
|
||||
types = typeOrganisationClientService.list(false);
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors du chargement des types d'organisation: " + e.getMessage());
|
||||
types = new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
public void preparerNouveauType() {
|
||||
typeCourant = new TypeOrganisationClientDTO();
|
||||
typeCourant.setActif(true);
|
||||
typeSelectionne = null;
|
||||
}
|
||||
|
||||
private void creerType() {
|
||||
try {
|
||||
TypeOrganisationClientDTO cree = typeOrganisationClientService.create(typeCourant);
|
||||
types.add(cree);
|
||||
typeCourant = null;
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Type d'organisation créé avec succès"));
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la création du type d'organisation: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de créer le type d'organisation: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Méthode unique utilisée par le bouton "Enregistrer" du dialogue.
|
||||
* Si un nouveau type est en cours d'édition, on crée, sinon on met à jour le type sélectionné.
|
||||
*/
|
||||
public void enregistrerType() {
|
||||
if (typeCourant == null) {
|
||||
return;
|
||||
}
|
||||
if (typeCourant.getId() == null) {
|
||||
creerType();
|
||||
} else {
|
||||
sauvegarderType();
|
||||
}
|
||||
}
|
||||
private void sauvegarderType() {
|
||||
if (typeCourant == null || typeCourant.getId() == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
TypeOrganisationClientDTO maj =
|
||||
typeOrganisationClientService.update(typeCourant.getId(), typeCourant);
|
||||
// Remplacer dans la liste
|
||||
types.replaceAll(t -> t.getId().equals(maj.getId()) ? maj : t);
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Type d'organisation mis à jour"));
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la mise à jour du type d'organisation: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de mettre à jour le type d'organisation: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
public void desactiverType(UUID id) {
|
||||
try {
|
||||
typeOrganisationClientService.disable(id);
|
||||
types.stream()
|
||||
.filter(t -> t.getId().equals(id))
|
||||
.findFirst()
|
||||
.ifPresent(t -> t.setActif(false));
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_INFO,
|
||||
"Succès", "Type d'organisation désactivé"));
|
||||
} catch (Exception e) {
|
||||
LOGGER.severe("Erreur lors de la désactivation du type d'organisation: " + e.getMessage());
|
||||
FacesContext.getCurrentInstance().addMessage(null,
|
||||
new FacesMessage(FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur", "Impossible de désactiver le type d'organisation: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
// Getters / Setters
|
||||
public List<TypeOrganisationClientDTO> getTypes() { return types; }
|
||||
public void setTypes(List<TypeOrganisationClientDTO> types) { this.types = types; }
|
||||
|
||||
public TypeOrganisationClientDTO getTypeSelectionne() { return typeSelectionne; }
|
||||
public void setTypeSelectionne(TypeOrganisationClientDTO typeSelectionne) {
|
||||
this.typeSelectionne = typeSelectionne;
|
||||
this.typeCourant = typeSelectionne;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le type actuellement édité dans le dialogue.
|
||||
* Initialise un nouveau type par défaut si aucun n'est encore défini,
|
||||
* ce qui évite les erreurs "Target Unreachable" lors de la validation JSF.
|
||||
*/
|
||||
public TypeOrganisationClientDTO getTypeCourant() {
|
||||
if (typeCourant == null) {
|
||||
typeCourant = new TypeOrganisationClientDTO();
|
||||
typeCourant.setActif(true);
|
||||
}
|
||||
return typeCourant;
|
||||
}
|
||||
public void setTypeCourant(TypeOrganisationClientDTO typeCourant) { this.typeCourant = typeCourant; }
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public class UtilisateursBean implements Serializable {
|
||||
private void initializeOrganisations() {
|
||||
organisationsDisponibles = new ArrayList<>();
|
||||
try {
|
||||
List<AssociationDTO> associations = associationService.listerActives();
|
||||
List<AssociationDTO> associations = associationService.listerToutes(0, 1000);
|
||||
for (AssociationDTO assoc : associations) {
|
||||
Organisation org = new Organisation();
|
||||
org.setId(assoc.getId());
|
||||
|
||||
@@ -0,0 +1,279 @@
|
||||
package dev.lions.unionflow.client.view;
|
||||
|
||||
import dev.lions.unionflow.client.dto.WaveBalanceDTO;
|
||||
import dev.lions.unionflow.client.dto.WaveCheckoutSessionDTO;
|
||||
import dev.lions.unionflow.client.service.WaveService;
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.faces.application.FacesMessage;
|
||||
import jakarta.faces.context.FacesContext;
|
||||
import jakarta.faces.view.ViewScoped;
|
||||
import jakarta.inject.Inject;
|
||||
import jakarta.inject.Named;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* Bean JSF pour la gestion des paiements Wave Money
|
||||
*
|
||||
* @author UnionFlow Team
|
||||
* @version 1.0
|
||||
* @since 2025-01-17
|
||||
*/
|
||||
@Named
|
||||
@ViewScoped
|
||||
public class WaveBean implements Serializable {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(WaveBean.class);
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Inject @org.eclipse.microprofile.rest.client.inject.RestClient WaveService waveService;
|
||||
|
||||
// Session de paiement en cours
|
||||
private WaveCheckoutSessionDTO sessionEnCours;
|
||||
private WaveBalanceDTO solde;
|
||||
|
||||
// Données pour créer une session
|
||||
private BigDecimal montantPaiement;
|
||||
private String devisePaiement = "XOF";
|
||||
private String descriptionPaiement;
|
||||
private String typePaiement = "COTISATION";
|
||||
private UUID organisationId;
|
||||
private UUID membreId;
|
||||
private String referenceUnionFlow;
|
||||
|
||||
// Résultat du test de connexion
|
||||
private Map<String, Object> resultatTest;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
LOGGER.info("Initialisation de WaveBean");
|
||||
chargerSolde();
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une session de paiement Wave
|
||||
*/
|
||||
public void creerSessionPaiement() {
|
||||
try {
|
||||
LOGGER.infof("Création d'une session Wave: montant=%s", montantPaiement);
|
||||
|
||||
if (montantPaiement == null || montantPaiement.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
ajouterMessage(
|
||||
FacesMessage.SEVERITY_ERROR, "Erreur", "Le montant doit être supérieur à zéro");
|
||||
return;
|
||||
}
|
||||
|
||||
// Construire les URLs de redirection
|
||||
String baseUrl = FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath();
|
||||
String successUrl = baseUrl + "/pages/secure/wave/success.xhtml";
|
||||
String errorUrl = baseUrl + "/pages/secure/wave/error.xhtml";
|
||||
|
||||
sessionEnCours =
|
||||
waveService.creerSessionPaiement(
|
||||
montantPaiement,
|
||||
devisePaiement,
|
||||
successUrl,
|
||||
errorUrl,
|
||||
referenceUnionFlow,
|
||||
descriptionPaiement,
|
||||
organisationId,
|
||||
membreId);
|
||||
|
||||
LOGGER.infof("Session créée: %s", sessionEnCours != null ? sessionEnCours.getWaveSessionId() : "null");
|
||||
ajouterMessage(
|
||||
FacesMessage.SEVERITY_INFO,
|
||||
"Succès",
|
||||
"Session de paiement créée avec succès. Redirection vers Wave...");
|
||||
|
||||
// Rediriger vers l'URL Wave
|
||||
if (sessionEnCours != null && sessionEnCours.getWaveUrl() != null) {
|
||||
FacesContext.getCurrentInstance()
|
||||
.getExternalContext()
|
||||
.redirect(sessionEnCours.getWaveUrl());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.errorf(e, "Erreur lors de la création de la session: %s", e.getMessage());
|
||||
ajouterMessage(
|
||||
FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur",
|
||||
"Erreur lors de la création de la session: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie le statut d'une session
|
||||
*/
|
||||
public void verifierStatutSession(String sessionId) {
|
||||
try {
|
||||
LOGGER.infof("Vérification du statut de la session: %s", sessionId);
|
||||
sessionEnCours = waveService.verifierStatutSession(sessionId);
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.errorf(e, "Erreur lors de la vérification du statut: %s", e.getMessage());
|
||||
ajouterMessage(
|
||||
FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur",
|
||||
"Erreur lors de la vérification du statut: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Charge le solde Wave
|
||||
*/
|
||||
public void chargerSolde() {
|
||||
try {
|
||||
LOGGER.info("Chargement du solde Wave");
|
||||
solde = waveService.consulterSolde();
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.errorf(e, "Erreur lors du chargement du solde: %s", e.getMessage());
|
||||
// Ne pas afficher d'erreur si Wave n'est pas configuré
|
||||
solde = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teste la connexion à l'API Wave
|
||||
*/
|
||||
public void testerConnexion() {
|
||||
try {
|
||||
LOGGER.info("Test de connexion à l'API Wave");
|
||||
resultatTest = waveService.testerConnexion();
|
||||
|
||||
if (resultatTest != null && "OK".equals(resultatTest.get("statut"))) {
|
||||
ajouterMessage(
|
||||
FacesMessage.SEVERITY_INFO,
|
||||
"Succès",
|
||||
"Connexion à l'API Wave réussie: " + resultatTest.get("message"));
|
||||
} else {
|
||||
ajouterMessage(
|
||||
FacesMessage.SEVERITY_WARN,
|
||||
"Attention",
|
||||
resultatTest != null
|
||||
? resultatTest.get("message").toString()
|
||||
: "Erreur lors du test de connexion");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
LOGGER.errorf(e, "Erreur lors du test de connexion: %s", e.getMessage());
|
||||
ajouterMessage(
|
||||
FacesMessage.SEVERITY_ERROR,
|
||||
"Erreur",
|
||||
"Erreur lors du test de connexion: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Réinitialise les données du formulaire
|
||||
*/
|
||||
public void reinitialiserFormulaire() {
|
||||
montantPaiement = null;
|
||||
devisePaiement = "XOF";
|
||||
descriptionPaiement = null;
|
||||
typePaiement = "COTISATION";
|
||||
referenceUnionFlow = null;
|
||||
sessionEnCours = null;
|
||||
}
|
||||
|
||||
// Méthodes utilitaires
|
||||
|
||||
private void ajouterMessage(
|
||||
jakarta.faces.application.FacesMessage.Severity severity, String resume, String detail) {
|
||||
FacesContext.getCurrentInstance()
|
||||
.addMessage(null, new FacesMessage(severity, resume, detail));
|
||||
}
|
||||
|
||||
/**
|
||||
* Vérifie si Wave est disponible
|
||||
*/
|
||||
public boolean isWaveDisponible() {
|
||||
return solde != null && solde.isWalletActif();
|
||||
}
|
||||
|
||||
// Getters et Setters
|
||||
public WaveCheckoutSessionDTO getSessionEnCours() {
|
||||
return sessionEnCours;
|
||||
}
|
||||
|
||||
public void setSessionEnCours(WaveCheckoutSessionDTO sessionEnCours) {
|
||||
this.sessionEnCours = sessionEnCours;
|
||||
}
|
||||
|
||||
public WaveBalanceDTO getSolde() {
|
||||
return solde;
|
||||
}
|
||||
|
||||
public void setSolde(WaveBalanceDTO solde) {
|
||||
this.solde = solde;
|
||||
}
|
||||
|
||||
public BigDecimal getMontantPaiement() {
|
||||
return montantPaiement;
|
||||
}
|
||||
|
||||
public void setMontantPaiement(BigDecimal montantPaiement) {
|
||||
this.montantPaiement = montantPaiement;
|
||||
}
|
||||
|
||||
public String getDevisePaiement() {
|
||||
return devisePaiement;
|
||||
}
|
||||
|
||||
public void setDevisePaiement(String devisePaiement) {
|
||||
this.devisePaiement = devisePaiement;
|
||||
}
|
||||
|
||||
public String getDescriptionPaiement() {
|
||||
return descriptionPaiement;
|
||||
}
|
||||
|
||||
public void setDescriptionPaiement(String descriptionPaiement) {
|
||||
this.descriptionPaiement = descriptionPaiement;
|
||||
}
|
||||
|
||||
public String getTypePaiement() {
|
||||
return typePaiement;
|
||||
}
|
||||
|
||||
public void setTypePaiement(String typePaiement) {
|
||||
this.typePaiement = typePaiement;
|
||||
}
|
||||
|
||||
public UUID getOrganisationId() {
|
||||
return organisationId;
|
||||
}
|
||||
|
||||
public void setOrganisationId(UUID organisationId) {
|
||||
this.organisationId = organisationId;
|
||||
}
|
||||
|
||||
public UUID getMembreId() {
|
||||
return membreId;
|
||||
}
|
||||
|
||||
public void setMembreId(UUID membreId) {
|
||||
this.membreId = membreId;
|
||||
}
|
||||
|
||||
public String getReferenceUnionFlow() {
|
||||
return referenceUnionFlow;
|
||||
}
|
||||
|
||||
public void setReferenceUnionFlow(String referenceUnionFlow) {
|
||||
this.referenceUnionFlow = referenceUnionFlow;
|
||||
}
|
||||
|
||||
public Map<String, Object> getResultatTest() {
|
||||
return resultatTest;
|
||||
}
|
||||
|
||||
public void setResultatTest(Map<String, Object> resultatTest) {
|
||||
this.resultatTest = resultatTest;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<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" />
|
||||
<!-- Obsolète : apple-mobile-web-app-capable. Remplacé par mobile-web-app-capable -->
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
<link rel="icon" href="#{request.contextPath}/resources/freya-layout/images/favicon.ico" type="image/x-icon" />
|
||||
</f:facet>
|
||||
|
||||
|
||||
@@ -9,414 +9,432 @@
|
||||
<ui:define name="title">Journal d'Audit - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-history text-indigo-500" />
|
||||
<ui:param name="title" value="Journal d'Audit" />
|
||||
<ui:param name="description" value="Traçabilité complète des actions et modifications système" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="onclick" value="PF('exportDialog').show(); return false;" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{auditBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{auditBean.totalEvenements}" />
|
||||
<ui:param name="label" value="Événements Totaux" />
|
||||
<ui:param name="icon" value="pi pi-history" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<!-- En-tête avec statistiques -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h2 class="text-900 font-bold text-4xl mb-2">
|
||||
<i class="pi pi-history text-indigo-500 mr-3"></i>
|
||||
Journal d'Audit
|
||||
</h2>
|
||||
<p class="text-600 text-lg mb-0">
|
||||
Traçabilité complète des actions et modifications système
|
||||
</p>
|
||||
</div>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{auditBean.connexionsReussies}" />
|
||||
<ui:param name="label" value="Connexions Réussies" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{auditBean.tentativesEchouees}" />
|
||||
<ui:param name="label" value="Tentatives Échouées" />
|
||||
<ui:param name="icon" value="pi pi-times-circle" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{auditBean.alertesSecurite}" />
|
||||
<ui:param name="label" value="Alertes Sécurité" />
|
||||
<ui:param name="icon" value="pi pi-exclamation-triangle" />
|
||||
<ui:param name="bgColor" value="red" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="card">
|
||||
<h:form id="formFiltres">
|
||||
<h5>Filtres de Recherche</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebut" />
|
||||
<ui:param name="label" value="Date Début" />
|
||||
<ui:param name="value" value="#{auditBean.dateDebut}" />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateFin" />
|
||||
<ui:param name="label" value="Date Fin" />
|
||||
<ui:param name="value" value="#{auditBean.dateFin}" />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="typeAction" />
|
||||
<ui:param name="label" value="Type d'Action" />
|
||||
<ui:param name="value" value="#{auditBean.typeAction}" />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Connexion" itemValue="CONNEXION" />
|
||||
<f:selectItem itemLabel="Déconnexion" itemValue="DECONNEXION" />
|
||||
<f:selectItem itemLabel="Création" itemValue="CREATION" />
|
||||
<f:selectItem itemLabel="Modification" itemValue="MODIFICATION" />
|
||||
<f:selectItem itemLabel="Suppression" itemValue="SUPPRESSION" />
|
||||
<f:selectItem itemLabel="Consultation" itemValue="CONSULTATION" />
|
||||
<f:selectItem itemLabel="Export" itemValue="EXPORT" />
|
||||
<f:selectItem itemLabel="Configuration" itemValue="CONFIGURATION" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="severite" />
|
||||
<ui:param name="label" value="Sévérité" />
|
||||
<ui:param name="value" value="#{auditBean.severite}" />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Toutes" itemValue="" />
|
||||
<f:selectItem itemLabel="Info" itemValue="INFO" />
|
||||
<f:selectItem itemLabel="Succès" itemValue="SUCCESS" />
|
||||
<f:selectItem itemLabel="Avertissement" itemValue="WARNING" />
|
||||
<f:selectItem itemLabel="Erreur" itemValue="ERROR" />
|
||||
<f:selectItem itemLabel="Critique" itemValue="CRITICAL" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="utilisateur" />
|
||||
<ui:param name="label" value="Utilisateur" />
|
||||
<ui:param name="value" value="#{auditBean.utilisateur}" />
|
||||
<ui:param name="placeholder" value="Nom ou email..." />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="module" />
|
||||
<ui:param name="label" value="Module" />
|
||||
<ui:param name="value" value="#{auditBean.module}" />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Tous les modules" itemValue="" />
|
||||
<f:selectItem itemLabel="Authentification" itemValue="AUTH" />
|
||||
<f:selectItem itemLabel="Membres" itemValue="MEMBRES" />
|
||||
<f:selectItem itemLabel="Cotisations" itemValue="COTISATIONS" />
|
||||
<f:selectItem itemLabel="Événements" itemValue="EVENTS" />
|
||||
<f:selectItem itemLabel="Documents" itemValue="DOCUMENTS" />
|
||||
<f:selectItem itemLabel="Configuration" itemValue="CONFIG" />
|
||||
<f:selectItem itemLabel="Rapports" itemValue="RAPPORTS" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="ipAddress" />
|
||||
<ui:param name="label" value="Adresse IP" />
|
||||
<ui:param name="value" value="#{auditBean.ipAddress}" />
|
||||
<ui:param name="placeholder" value="Ex: 192.168.1.1" />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel />
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Exporter"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-download"
|
||||
onclick="PF('exportDialog').show()" />
|
||||
<p:commandButton value="Paramètres"
|
||||
styleClass="p-button-info p-button-outlined"
|
||||
icon="pi pi-cog" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KPIs -->
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round-lg p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-indigo-500 mb-2">#{auditBean.totalEvenements}</div>
|
||||
<div class="text-900 font-semibold mb-1">Événements Totaux</div>
|
||||
<div class="text-600 text-sm">Derniers 30 jours</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round-lg p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">#{auditBean.connexionsReussies}</div>
|
||||
<div class="text-900 font-semibold mb-1">Connexions Réussies</div>
|
||||
<div class="text-600 text-sm">Aujourd'hui</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round-lg p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">#{auditBean.tentativesEchouees}</div>
|
||||
<div class="text-900 font-semibold mb-1">Tentatives Échouées</div>
|
||||
<div class="text-600 text-sm">Cette semaine</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round-lg p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-red-500 mb-2">#{auditBean.alertesSecurite}</div>
|
||||
<div class="text-900 font-semibold mb-1">Alertes Sécurité</div>
|
||||
<div class="text-600 text-sm">Non résolues</div>
|
||||
</div>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Rechercher" />
|
||||
<ui:param name="icon" value="pi pi-search" />
|
||||
<ui:param name="action" value="#{auditBean.rechercher}" />
|
||||
<ui:param name="update" value=":formTableau:tableauAudit" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{auditBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="@form :formTableau:tableauAudit" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Filtres avancés -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<h:form id="filtresForm">
|
||||
<div class="formgrid grid">
|
||||
<!-- Ligne 1 -->
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label for="dateDebut" class="block text-900 font-semibold mb-2">
|
||||
<i class="pi pi-calendar mr-2"></i>Date Début
|
||||
</label>
|
||||
<p:datePicker id="dateDebut"
|
||||
value="#{auditBean.dateDebut}"
|
||||
pattern="dd/MM/yyyy"
|
||||
showIcon="true"
|
||||
showOnFocus="false"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="dateSelect" update=":tableauForm:tableauAudit" />
|
||||
</p:datePicker>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label for="dateFin" class="block text-900 font-semibold mb-2">
|
||||
<i class="pi pi-calendar mr-2"></i>Date Fin
|
||||
</label>
|
||||
<p:datePicker id="dateFin"
|
||||
value="#{auditBean.dateFin}"
|
||||
pattern="dd/MM/yyyy"
|
||||
showIcon="true"
|
||||
showOnFocus="false"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="dateSelect" update=":tableauForm:tableauAudit" />
|
||||
</p:datePicker>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label for="typeAction" class="block text-900 font-semibold mb-2">
|
||||
<i class="pi pi-tag mr-2"></i>Type d'Action
|
||||
</label>
|
||||
<p:selectOneMenu id="typeAction"
|
||||
value="#{auditBean.typeAction}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Connexion" itemValue="CONNEXION" />
|
||||
<f:selectItem itemLabel="Déconnexion" itemValue="DECONNEXION" />
|
||||
<f:selectItem itemLabel="Création" itemValue="CREATION" />
|
||||
<f:selectItem itemLabel="Modification" itemValue="MODIFICATION" />
|
||||
<f:selectItem itemLabel="Suppression" itemValue="SUPPRESSION" />
|
||||
<f:selectItem itemLabel="Consultation" itemValue="CONSULTATION" />
|
||||
<f:selectItem itemLabel="Export" itemValue="EXPORT" />
|
||||
<f:selectItem itemLabel="Configuration" itemValue="CONFIGURATION" />
|
||||
<p:ajax update=":tableauForm:tableauAudit" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label for="severite" class="block text-900 font-semibold mb-2">
|
||||
<i class="pi pi-exclamation-triangle mr-2"></i>Sévérité
|
||||
</label>
|
||||
<p:selectOneMenu id="severite"
|
||||
value="#{auditBean.severite}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes" itemValue="" />
|
||||
<f:selectItem itemLabel="Info" itemValue="INFO" />
|
||||
<f:selectItem itemLabel="Succès" itemValue="SUCCESS" />
|
||||
<f:selectItem itemLabel="Avertissement" itemValue="WARNING" />
|
||||
<f:selectItem itemLabel="Erreur" itemValue="ERROR" />
|
||||
<f:selectItem itemLabel="Critique" itemValue="CRITICAL" />
|
||||
<p:ajax update=":tableauForm:tableauAudit" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<!-- Ligne 2 -->
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label for="utilisateur" class="block text-900 font-semibold mb-2">
|
||||
<i class="pi pi-user mr-2"></i>Utilisateur
|
||||
</label>
|
||||
<p:inputText id="utilisateur"
|
||||
value="#{auditBean.utilisateur}"
|
||||
placeholder="Nom ou email..."
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup" update=":tableauForm:tableauAudit" delay="500" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label for="module" class="block text-900 font-semibold mb-2">
|
||||
<i class="pi pi-box mr-2"></i>Module
|
||||
</label>
|
||||
<p:selectOneMenu id="module"
|
||||
value="#{auditBean.module}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les modules" itemValue="" />
|
||||
<f:selectItem itemLabel="Authentification" itemValue="AUTH" />
|
||||
<f:selectItem itemLabel="Membres" itemValue="MEMBRES" />
|
||||
<f:selectItem itemLabel="Cotisations" itemValue="COTISATIONS" />
|
||||
<f:selectItem itemLabel="Événements" itemValue="EVENTS" />
|
||||
<f:selectItem itemLabel="Documents" itemValue="DOCUMENTS" />
|
||||
<f:selectItem itemLabel="Configuration" itemValue="CONFIG" />
|
||||
<f:selectItem itemLabel="Rapports" itemValue="RAPPORTS" />
|
||||
<p:ajax update=":tableauForm:tableauAudit" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label for="ipAddress" class="block text-900 font-semibold mb-2">
|
||||
<i class="pi pi-globe mr-2"></i>Adresse IP
|
||||
</label>
|
||||
<p:inputText id="ipAddress"
|
||||
value="#{auditBean.ipAddress}"
|
||||
placeholder="Ex: 192.168.1.1"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup" update=":tableauForm:tableauAudit" delay="500" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-3">
|
||||
<label class="block text-900 font-semibold mb-2"> </label>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Rechercher"
|
||||
icon="pi pi-search"
|
||||
styleClass="p-button-primary"
|
||||
action="#{auditBean.rechercher}"
|
||||
update=":tableauForm:tableauAudit" />
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-outlined"
|
||||
action="#{auditBean.reinitialiserFiltres}"
|
||||
update="@form :tableauForm:tableauAudit" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Tableau du journal d'audit -->
|
||||
<div class="card">
|
||||
<h:form id="formTableau">
|
||||
<h5>Journal d'Audit</h5>
|
||||
|
||||
<p:dataTable id="tableauAudit"
|
||||
value="#{auditBean.evenementsFiltres}"
|
||||
var="log"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
emptyMessage="Aucun événement trouvé"
|
||||
styleClass="p-datatable-sm p-datatable-striped"
|
||||
sortMode="multiple"
|
||||
rowKey="#{log.id}">
|
||||
|
||||
<p:column headerText="Date/Heure" sortBy="#{log.dateHeure}" style="width: 12%">
|
||||
<div>
|
||||
<div class="font-semibold">#{log.dateFormatee}</div>
|
||||
<div class="text-sm text-600">#{log.heureFormatee}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Sévérité" sortBy="#{log.severite}" style="width: 8%" styleClass="text-center">
|
||||
<p:tag value="#{log.severiteLibelle}"
|
||||
severity="#{log.severiteSeverity}"
|
||||
icon="#{log.severiteIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Utilisateur" sortBy="#{log.utilisateur}" style="width: 15%">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-user text-blue-500"></i>
|
||||
<div>
|
||||
<div class="font-semibold">#{log.utilisateur}</div>
|
||||
<div class="text-sm text-600">#{log.role}</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Tableau du journal d'audit -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card surface-0 hover:surface-100 border-round-lg transition-all transition-duration-200">
|
||||
<h:form id="tableauForm">
|
||||
<p:dataTable id="tableauAudit"
|
||||
value="#{auditBean.evenementsFiltres}"
|
||||
var="event"
|
||||
paginator="true"
|
||||
rows="15"
|
||||
paginatorPosition="both"
|
||||
rowsPerPageTemplate="10,15,25,50,100"
|
||||
paginatorTemplate="{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown} {CurrentPageReport}"
|
||||
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords} événements"
|
||||
emptyMessage="Aucun événement trouvé"
|
||||
styleClass="p-datatable-sm p-datatable-striped"
|
||||
sortMode="multiple"
|
||||
allowUnsorting="true"
|
||||
rowStyleClass="#{event.severite == 'CRITICAL' ? 'bg-red-50' : (event.severite == 'ERROR' ? 'bg-orange-50' : '')}">
|
||||
<p:column headerText="Action" sortBy="#{log.typeAction}" style="width: 12%">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{log.actionIcon} text-lg"></i>
|
||||
<span class="font-semibold">#{log.actionLibelle}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date/Heure" sortBy="#{event.dateHeure}" style="width: 12%">
|
||||
<div class="text-900 font-semibold">#{event.dateFormatee}</div>
|
||||
<div class="text-600 text-sm">#{event.heureFormatee}</div>
|
||||
</p:column>
|
||||
<p:column headerText="Module" sortBy="#{log.module}" style="width: 10%">
|
||||
<p:tag value="#{log.moduleLibelle}"
|
||||
severity="info" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Sévérité" sortBy="#{event.severite}" style="width: 8%" styleClass="text-center">
|
||||
<p:tag value="#{event.severiteLibelle}"
|
||||
severity="#{event.severiteSeverity}"
|
||||
icon="#{event.severiteIcon}"
|
||||
styleClass="font-semibold" />
|
||||
</p:column>
|
||||
<p:column headerText="Description" style="width: 25%">
|
||||
<div>#{log.description}</div>
|
||||
<div class="text-sm text-600 mt-1" rendered="#{not empty log.details}">
|
||||
<i class="pi pi-info-circle"></i> #{log.details}
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Utilisateur" sortBy="#{event.utilisateur}" style="width: 15%">
|
||||
<div class="flex align-items-center">
|
||||
<div class="w-2rem h-2rem border-circle bg-blue-100 text-blue-600 flex align-items-center justify-content-center mr-2">
|
||||
<i class="pi pi-user text-sm"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-900 font-semibold">#{event.utilisateur}</div>
|
||||
<div class="text-600 text-xs">#{event.role}</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
<p:column headerText="IP/Appareil" style="width: 12%">
|
||||
<div class="text-sm">
|
||||
<i class="pi pi-globe"></i> #{log.ipAddress}
|
||||
</div>
|
||||
<div class="text-xs text-600">#{log.userAgentCourt}</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Action" sortBy="#{event.action}" style="width: 12%">
|
||||
<div class="flex align-items-center">
|
||||
<i class="#{event.actionIcon} text-lg mr-2" style="color: #{event.actionColor}"></i>
|
||||
<span class="text-900 font-semibold">#{event.action}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
<p:column headerText="Actions" style="width: 6%" styleClass="text-center">
|
||||
<div class="flex justify-content-center gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir les détails"
|
||||
styleClass="p-button-sm p-button-rounded p-button-info"
|
||||
action="#{auditBean.selectionnerLog(log)}"
|
||||
update=":formDetails:dlgDetails"
|
||||
oncomplete="PF('dlgDetails').show();" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<p:column headerText="Module" sortBy="#{event.module}" style="width: 10%">
|
||||
<p:tag value="#{event.moduleLibelle}"
|
||||
severity="info"
|
||||
styleClass="text-xs" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Description" style="width: 25%">
|
||||
<div class="text-900">#{event.description}</div>
|
||||
<div class="text-600 text-xs mt-1" rendered="#{not empty event.details}">
|
||||
<i class="pi pi-info-circle mr-1"></i>#{event.details}
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="IP/Appareil" style="width: 12%">
|
||||
<div class="text-900 text-sm">
|
||||
<i class="pi pi-globe mr-1"></i>#{event.ipAddress}
|
||||
</div>
|
||||
<div class="text-600 text-xs">#{event.userAgent}</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width: 6%" styleClass="text-center">
|
||||
<div class="flex justify-content-center gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="p-button-sm p-button-rounded"
|
||||
style="background-color: #17a2b8 !important; border-color: #17a2b8 !important; color: white !important;"
|
||||
title="Voir les détails"
|
||||
action="#{auditBean.voirDetails(event)}"
|
||||
onclick="PF('detailsDialog').show()" />
|
||||
<p:commandButton icon="pi pi-flag"
|
||||
styleClass="p-button-sm p-button-rounded"
|
||||
style="background-color: #dc3545 !important; border-color: #dc3545 !important; color: white !important;"
|
||||
title="Signaler"
|
||||
rendered="#{event.severite == 'WARNING' or event.severite == 'ERROR' or event.severite == 'CRITICAL'}"
|
||||
action="#{auditBean.signalerEvenement(event)}" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Détails -->
|
||||
<p:dialog id="detailsDialog"
|
||||
widgetVar="detailsDialog"
|
||||
<!-- Dialog Détails -->
|
||||
<h:form id="formDetails">
|
||||
<p:dialog id="dlgDetails"
|
||||
widgetVar="dlgDetails"
|
||||
header="Détails de l'Événement"
|
||||
modal="true"
|
||||
width="700"
|
||||
height="500"
|
||||
styleClass="surface-0">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid" rendered="#{auditBean.evenementSelectionne != null}">
|
||||
<div class="col-12">
|
||||
<div class="surface-100 border-round-lg p-4 mb-4">
|
||||
<h4 class="text-900 font-bold mb-3">Informations Générales</h4>
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 800px;">
|
||||
<div class="grid" rendered="#{auditBean.evenementSelectionne != null}">
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Informations Générales</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<label class="text-600 font-semibold">Date/Heure :</label>
|
||||
<p class="text-900 mt-1">#{auditBean.evenementSelectionne.dateHeureComplete}</p>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Date/Heure</label>
|
||||
<div>#{auditBean.evenementSelectionne.dateHeureComplete}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="text-600 font-semibold">Sévérité :</label>
|
||||
<p class="mt-1">
|
||||
<p:tag value="#{auditBean.evenementSelectionne.severiteLibelle}"
|
||||
severity="#{auditBean.evenementSelectionne.severiteSeverity}" />
|
||||
</p>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Sévérité</label>
|
||||
<div>
|
||||
<p:tag value="#{auditBean.evenementSelectionne.severiteLibelle}"
|
||||
severity="#{auditBean.evenementSelectionne.severiteSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="text-600 font-semibold">Utilisateur :</label>
|
||||
<p class="text-900 mt-1">#{auditBean.evenementSelectionne.utilisateur}</p>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Utilisateur</label>
|
||||
<div>#{auditBean.evenementSelectionne.utilisateur}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="text-600 font-semibold">Rôle :</label>
|
||||
<p class="text-900 mt-1">#{auditBean.evenementSelectionne.role}</p>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Rôle</label>
|
||||
<div>#{auditBean.evenementSelectionne.role}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round-lg p-4 mb-4">
|
||||
<h4 class="text-900 font-bold mb-3">Détails de l'Action</h4>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Détails de l'Action</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<label class="text-600 font-semibold">Description :</label>
|
||||
<p class="text-900 mt-1">#{auditBean.evenementSelectionne.descriptionComplete}</p>
|
||||
<div class="field">
|
||||
<label class="font-semibold">Description</label>
|
||||
<div>#{auditBean.evenementSelectionne.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{not empty auditBean.evenementSelectionne.details}">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Détails</label>
|
||||
<div class="surface-50 p-3 border-round">#{auditBean.evenementSelectionne.details}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{not empty auditBean.evenementSelectionne.donneesAvant}">
|
||||
<label class="text-600 font-semibold">Données Avant :</label>
|
||||
<pre class="surface-200 border-round p-2 mt-1 text-sm">#{auditBean.evenementSelectionne.donneesAvant}</pre>
|
||||
<div class="field">
|
||||
<label class="font-semibold">Données Avant</label>
|
||||
<pre class="surface-200 border-round p-2 text-sm">#{auditBean.evenementSelectionne.donneesAvant}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{not empty auditBean.evenementSelectionne.donneesApres}">
|
||||
<label class="text-600 font-semibold">Données Après :</label>
|
||||
<pre class="surface-200 border-round p-2 mt-1 text-sm">#{auditBean.evenementSelectionne.donneesApres}</pre>
|
||||
<div class="field">
|
||||
<label class="font-semibold">Données Après</label>
|
||||
<pre class="surface-200 border-round p-2 text-sm">#{auditBean.evenementSelectionne.donneesApres}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round-lg p-4">
|
||||
<h4 class="text-900 font-bold mb-3">Informations Techniques</h4>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Informations Techniques</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<label class="text-600 font-semibold">Adresse IP :</label>
|
||||
<p class="text-900 mt-1">#{auditBean.evenementSelectionne.ipAddress}</p>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Adresse IP</label>
|
||||
<div>#{auditBean.evenementSelectionne.ipAddress}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<label class="text-600 font-semibold">Session ID :</label>
|
||||
<p class="text-900 mt-1 text-xs">#{auditBean.evenementSelectionne.sessionId}</p>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Session ID</label>
|
||||
<div class="text-sm">#{auditBean.evenementSelectionne.sessionId}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<label class="text-600 font-semibold">User Agent :</label>
|
||||
<p class="text-900 mt-1 text-sm">#{auditBean.evenementSelectionne.userAgentComplet}</p>
|
||||
<div class="field">
|
||||
<label class="font-semibold">User Agent</label>
|
||||
<div class="text-sm">#{auditBean.evenementSelectionne.userAgent}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<p:commandButton value="Fermer"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgDetails').hide();"
|
||||
styleClass="p-button-outlined" />
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
|
||||
<!-- Dialog Export -->
|
||||
<!-- Dialog Export -->
|
||||
<h:form id="formExport">
|
||||
<p:dialog id="exportDialog"
|
||||
widgetVar="exportDialog"
|
||||
header="Exporter le Journal d'Audit"
|
||||
modal="true"
|
||||
width="500"
|
||||
styleClass="surface-0">
|
||||
<h:form id="exportForm">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12">
|
||||
<label for="formatExport" class="block text-900 font-semibold mb-2">Format d'Export</label>
|
||||
<p:selectOneRadio id="formatExport"
|
||||
value="#{auditBean.formatExport}"
|
||||
layout="grid"
|
||||
columns="1">
|
||||
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
|
||||
<f:selectItem itemLabel="PDF" itemValue="PDF" />
|
||||
<f:selectItem itemLabel="CSV" itemValue="CSV" />
|
||||
<f:selectItem itemLabel="JSON" itemValue="JSON" />
|
||||
</p:selectOneRadio>
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label class="block text-900 font-semibold mb-2">Options</label>
|
||||
<p:selectBooleanCheckbox id="inclureFiltres"
|
||||
value="#{auditBean.inclureFiltresExport}"
|
||||
itemLabel="Inclure uniquement les données filtrées" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('exportDialog').hide()"
|
||||
type="button" />
|
||||
<p:commandButton value="Exporter"
|
||||
styleClass="p-button-success"
|
||||
icon="pi pi-download"
|
||||
action="#{auditBean.exporter}"
|
||||
ajax="false" />
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 500px;">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<p:outputLabel for="formatExport" value="Format d'Export" />
|
||||
<p:selectOneRadio id="formatExport"
|
||||
value="#{auditBean.formatExport}"
|
||||
layout="grid"
|
||||
columns="1">
|
||||
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
|
||||
<f:selectItem itemLabel="PDF" itemValue="PDF" />
|
||||
<f:selectItem itemLabel="CSV" itemValue="CSV" />
|
||||
<f:selectItem itemLabel="JSON" itemValue="JSON" />
|
||||
</p:selectOneRadio>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="inclureFiltres"
|
||||
value="#{auditBean.inclureFiltresExport}"
|
||||
itemLabel="Inclure uniquement les données filtrées" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('exportDialog').hide();"
|
||||
type="button" />
|
||||
<p:commandButton value="Exporter"
|
||||
icon="pi pi-download"
|
||||
styleClass="p-button-success"
|
||||
action="#{auditBean.exporter}" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,51 +1,114 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Demande d'Adhésion - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-user-plus text-green-500" />
|
||||
<ui:param name="title" value="Demande d'Adhésion" />
|
||||
<ui:param name="description" value="Formulaire de demande d'adhésion à une organisation" />
|
||||
</ui:include>
|
||||
|
||||
<!-- Formulaire de demande -->
|
||||
<div class="card">
|
||||
<h5>Demande d'Adhésion</h5>
|
||||
<p>Formulaire de demande d'adhésion à l'union.</p>
|
||||
|
||||
<h:form>
|
||||
<div class="p-fluid formgrid grid">
|
||||
<div class="field col-12 md:col-6">
|
||||
<label for="membreNom">Nom du Membre</label>
|
||||
<p:selectOneMenu id="membreNom">
|
||||
<f:selectItem itemLabel="Sélectionner un membre" itemValue="" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-6">
|
||||
<label for="typeAdhesion">Type d'Adhésion</label>
|
||||
<p:selectOneMenu id="typeAdhesion">
|
||||
<f:selectItem itemLabel="Adhésion Standard" itemValue="standard" />
|
||||
<f:selectItem itemLabel="Adhésion Premium" itemValue="premium" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label for="motifAdhesion">Motif de la demande</label>
|
||||
<p:inputTextarea id="motifAdhesion" rows="4" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<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>
|
||||
<h:form id="formDemande">
|
||||
<h5>Nouvelle Demande d'Adhésion</h5>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Informations du Membre" />
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="membreId" value="Membre" />
|
||||
<p:selectOneMenu id="membreId"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.membreId}"
|
||||
required="true"
|
||||
requiredMessage="Veuillez sélectionner un membre"
|
||||
filter="true"
|
||||
filterMatchMode="contains"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{adhesionsBean.membresSelectItems}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="membreId" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="organisationId" value="Organisation" />
|
||||
<p:selectOneMenu id="organisationId"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.organisationId}"
|
||||
required="true"
|
||||
requiredMessage="Veuillez sélectionner une organisation"
|
||||
filter="true"
|
||||
filterMatchMode="contains"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{adhesionsBean.associationsSelectItems}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="organisationId" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Frais d'Adhésion" />
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="fraisAdhesion" value="Frais d'adhésion (FCFA)" />
|
||||
<p:inputNumber id="fraisAdhesion"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.fraisAdhesion}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Observations" />
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="observations" />
|
||||
<ui:param name="label" value="Observations (optionnel)" />
|
||||
<ui:param name="value" value="#{adhesionsBean.nouvelleAdhesion.observations}" />
|
||||
<ui:param name="rows" value="4" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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="action" value="#{navigationBean.goToDashboard}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Soumettre la demande" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerAdhesion}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -5,16 +5,254 @@
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
<ui:define name="title">UnionFlow - History</ui:define>
|
||||
|
||||
<ui:define name="title">Historique des Adhésions - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>History - Adhesion</h2>
|
||||
<p>Page en cours de développement...</p>
|
||||
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-history text-blue-500" />
|
||||
<ui:param name="title" value="Historique des Adhésions" />
|
||||
<ui:param name="description" value="Consultation de l'historique complet des adhésions" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsHistory">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{adhesionsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Filtres d'historique -->
|
||||
<div class="card">
|
||||
<h:form id="formFiltresHistory">
|
||||
<h5>Filtres de Recherche</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebut" />
|
||||
<ui:param name="label" value="Date début" />
|
||||
<ui:param name="value" value="#{adhesionsBean.filtres.dateDebut}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateFin" />
|
||||
<ui:param name="label" value="Date fin" />
|
||||
<ui:param name="value" value="#{adhesionsBean.filtres.dateFin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="statutHistory" />
|
||||
<ui:param name="label" value="Statut" />
|
||||
<ui:param name="value" value="#{adhesionsBean.filtres.statut}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
|
||||
<f:selectItem itemLabel="Approuvée" itemValue="APPROUVEE" />
|
||||
<f:selectItem itemLabel="Rejetée" itemValue="REJETEE" />
|
||||
<f:selectItem itemLabel="Payée" itemValue="PAYEE" />
|
||||
<f:selectItem itemLabel="En paiement" itemValue="EN_PAIEMENT" />
|
||||
<f:selectItem itemLabel="Annulée" itemValue="ANNULEE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel />
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Rechercher" />
|
||||
<ui:param name="icon" value="pi pi-search" />
|
||||
<ui:param name="action" value="#{adhesionsBean.rechercher}" />
|
||||
<ui:param name="update" value=":formHistory" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="action" value="#{adhesionsBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="@form :formHistory" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Tableau d'historique -->
|
||||
<div class="card">
|
||||
<h:form id="formHistory">
|
||||
<h5>Historique des Adhésions</h5>
|
||||
|
||||
<p:dataTable id="dtHistory"
|
||||
value="#{adhesionsBean.adhesionsFiltrees}"
|
||||
var="adhesion"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
sortMode="multiple"
|
||||
emptyMessage="Aucune adhésion trouvée">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Historique (#{adhesionsBean.adhesionsFiltrees.size()} adhésion(s))</span>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column headerText="Date" sortBy="#{adhesion.dateDemande}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.dateDemandeFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Référence" sortBy="#{adhesion.numeroReference}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.numeroReference}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{adhesion.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{adhesion.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{adhesion.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{adhesion.nomOrganisation}">
|
||||
<h:outputText value="#{adhesion.nomOrganisation}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Frais" sortBy="#{adhesion.fraisAdhesion}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.fraisAdhesionFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{adhesion.statut}" style="width:150px">
|
||||
<p:tag value="#{adhesion.statutLibelle}"
|
||||
severity="#{adhesion.statutSeverity}"
|
||||
icon="#{adhesion.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Approbation" sortBy="#{adhesion.dateApprobation}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.dateApprobationFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Paiement" sortBy="#{adhesion.datePaiement}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.datePaiementFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:100px">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir les détails"
|
||||
styleClass="p-button-rounded p-button-text p-button-info"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formDetailsAdhesion"
|
||||
oncomplete="PF('dlgDetailsAdhesion').show();" />
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Détails Adhésion -->
|
||||
<p:dialog header="Détails de l'Adhésion" widgetVar="dlgDetailsAdhesion" modal="true" width="600" resizable="false">
|
||||
<h:form id="formDetailsAdhesion">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Référence</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Statut</label>
|
||||
<p:tag value="#{adhesionsBean.adhesionSelectionnee.statutLibelle}"
|
||||
severity="#{adhesionsBean.adhesionSelectionnee.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Membre</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">N° #{adhesionsBean.adhesionSelectionnee.numeroMembre}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Organisation</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomOrganisation}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date de demande</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.dateDemandeFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Frais d'adhésion</label>
|
||||
<p class="text-600 font-bold">#{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant payé</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.montantPayeFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant restant</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.montantRestantFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date d'approbation</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.dateApprobationFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date de paiement</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.datePaiementFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Méthode de paiement</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.methodePaiementLibelle}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{adhesionsBean.adhesionSelectionnee.observations != null}">
|
||||
<div class="field">
|
||||
<label class="font-medium">Observations</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.observations}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{adhesionsBean.adhesionSelectionnee.motifRejet != null}">
|
||||
<div class="field">
|
||||
<label class="font-medium">Motif de rejet</label>
|
||||
<p class="text-600 text-red-500">#{adhesionsBean.adhesionSelectionnee.motifRejet}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,39 +1,416 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Liste Adhésions - UnionFlow</ui:define>
|
||||
<ui:define name="title">Liste des Adhésions - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="card">
|
||||
<h5>Liste des Adhésions</h5>
|
||||
<p>Vue d'ensemble de toutes les adhésions.</p>
|
||||
|
||||
<p:dataTable var="adhesion" value="#{[]}" paginator="true" rows="10">
|
||||
<p:column headerText="Membre">
|
||||
<h:outputText value="#{adhesion.membre}" />
|
||||
</p:column>
|
||||
<p:column headerText="Date Adhésion">
|
||||
<h:outputText value="#{adhesion.dateAdhesion}" />
|
||||
</p:column>
|
||||
<p:column headerText="Statut">
|
||||
<h:outputText value="#{adhesion.statut}" />
|
||||
</p:column>
|
||||
<p:column headerText="Actions">
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<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:dataTable>
|
||||
</div>
|
||||
</ui:define>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-users text-blue-500" />
|
||||
<ui:param name="title" value="Liste des Adhésions" />
|
||||
<ui:param name="description" value="Gestion complète des demandes d'adhésion" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsListe">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Nouvelle adhésion" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="onclick" value="PF('dlgNouvelleAdhesion').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{adhesionsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
</ui:composition>
|
||||
<!-- Statistiques -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.totalAdhesions}" />
|
||||
<ui:param name="label" value="Total Adhésions" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsEnAttente}" />
|
||||
<ui:param name="label" value="En Attente" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsApprouvees}" />
|
||||
<ui:param name="label" value="Approuvées" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.tauxApprobationInt}%" />
|
||||
<ui:param name="label" value="Taux d'Approbation" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="card">
|
||||
<h:form id="formFiltres">
|
||||
<h5>Filtres de Recherche</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="filtreStatut" />
|
||||
<ui:param name="label" value="Statut" />
|
||||
<ui:param name="value" value="#{adhesionsBean.filtres.statut}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
|
||||
<f:selectItem itemLabel="Approuvée" itemValue="APPROUVEE" />
|
||||
<f:selectItem itemLabel="Rejetée" itemValue="REJETEE" />
|
||||
<f:selectItem itemLabel="Payée" itemValue="PAYEE" />
|
||||
<f:selectItem itemLabel="En paiement" itemValue="EN_PAIEMENT" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="filtreNomMembre" />
|
||||
<ui:param name="label" value="Nom du membre" />
|
||||
<ui:param name="value" value="#{adhesionsBean.filtres.nomMembre}" />
|
||||
<ui:param name="placeholder" value="Rechercher par nom..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="filtreDateDebut" />
|
||||
<ui:param name="label" value="Date début" />
|
||||
<ui:param name="value" value="#{adhesionsBean.filtres.dateDebut}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel />
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Rechercher" />
|
||||
<ui:param name="icon" value="pi pi-search" />
|
||||
<ui:param name="action" value="#{adhesionsBean.rechercher}" />
|
||||
<ui:param name="update" value=":formListe" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="action" value="#{adhesionsBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="@form :formListe" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Liste des adhésions -->
|
||||
<div class="card">
|
||||
<h:form id="formListe">
|
||||
<h5>Adhésions</h5>
|
||||
|
||||
<p:dataTable id="dtAdhesions"
|
||||
value="#{adhesionsBean.adhesionsFiltrees}"
|
||||
var="adhesion"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
sortMode="multiple"
|
||||
emptyMessage="Aucune adhésion trouvée"
|
||||
selection="#{adhesionsBean.adhesionsSelectionnees}"
|
||||
selectionMode="multiple">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Liste des adhésions (#{adhesionsBean.adhesionsFiltrees.size()} adhésion(s))</span>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column selectionMode="multiple" style="width:50px" />
|
||||
|
||||
<p:column headerText="Référence" sortBy="#{adhesion.numeroReference}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.numeroReference}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{adhesion.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{adhesion.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{adhesion.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{adhesion.nomOrganisation}">
|
||||
<h:outputText value="#{adhesion.nomOrganisation}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Demande" sortBy="#{adhesion.dateDemande}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.dateDemandeFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Frais" sortBy="#{adhesion.fraisAdhesion}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.fraisAdhesionFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{adhesion.statut}" style="width:150px">
|
||||
<p:tag value="#{adhesion.statutLibelle}"
|
||||
severity="#{adhesion.statutSeverity}"
|
||||
icon="#{adhesion.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:200px">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir les détails"
|
||||
styleClass="p-button-rounded p-button-text p-button-info"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formDetailsAdhesion"
|
||||
oncomplete="PF('dlgDetailsAdhesion').show();" />
|
||||
<p:commandButton icon="pi pi-check"
|
||||
title="Approuver"
|
||||
styleClass="p-button-rounded p-button-text p-button-success"
|
||||
rendered="#{'EN_ATTENTE' == adhesion.statut}"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formApprobation"
|
||||
oncomplete="PF('dlgApprobation').show();" />
|
||||
<p:commandButton icon="pi pi-times"
|
||||
title="Rejeter"
|
||||
styleClass="p-button-rounded p-button-text p-button-danger"
|
||||
rendered="#{'EN_ATTENTE' == adhesion.statut}"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formRejet"
|
||||
oncomplete="PF('dlgRejet').show();" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Nouvelle Adhésion -->
|
||||
<p:dialog header="Nouvelle Adhésion" widgetVar="dlgNouvelleAdhesion" modal="true" width="600" resizable="false">
|
||||
<h:form id="formNouvelleAdhesion">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<p:outputLabel for="membreId" value="Membre" />
|
||||
<p:selectOneMenu id="membreId"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.membreId}"
|
||||
required="true"
|
||||
requiredMessage="Veuillez sélectionner un membre"
|
||||
filter="true"
|
||||
filterMatchMode="contains"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{adhesionsBean.membresSelectItems}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="membreId" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="organisationId" value="Organisation" />
|
||||
<p:selectOneMenu id="organisationId"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.organisationId}"
|
||||
required="true"
|
||||
requiredMessage="Veuillez sélectionner une organisation"
|
||||
filter="true"
|
||||
filterMatchMode="contains"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{adhesionsBean.associationsSelectItems}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="organisationId" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="fraisAdhesion" value="Frais d'adhésion (FCFA)" />
|
||||
<p:inputNumber id="fraisAdhesion"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.fraisAdhesion}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="observations" />
|
||||
<ui:param name="label" value="Observations" />
|
||||
<ui:param name="value" value="#{adhesionsBean.nouvelleAdhesion.observations}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgNouvelleAdhesion').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Créer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerAdhesion}" />
|
||||
<ui:param name="update" value="@form :formListe" />
|
||||
<ui:param name="oncomplete" value="PF('dlgNouvelleAdhesion').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Détails Adhésion -->
|
||||
<p:dialog header="Détails de l'Adhésion" widgetVar="dlgDetailsAdhesion" modal="true" width="600" resizable="false">
|
||||
<h:form id="formDetailsAdhesion">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Référence</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Statut</label>
|
||||
<p:tag value="#{adhesionsBean.adhesionSelectionnee.statutLibelle}"
|
||||
severity="#{adhesionsBean.adhesionSelectionnee.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Membre</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">N° #{adhesionsBean.adhesionSelectionnee.numeroMembre}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Organisation</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomOrganisation}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date de demande</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.dateDemandeFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Frais d'adhésion</label>
|
||||
<p class="text-600 font-bold">#{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant payé</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.montantPayeFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant restant</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.montantRestantFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{adhesionsBean.adhesionSelectionnee.dateApprobation != null}">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date d'approbation</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.dateApprobationFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{adhesionsBean.adhesionSelectionnee.observations != null}">
|
||||
<div class="field">
|
||||
<label class="font-medium">Observations</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.observations}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Approbation -->
|
||||
<p:dialog header="Approuver l'Adhésion" widgetVar="dlgApprobation" modal="true" width="500" resizable="false">
|
||||
<h:form id="formApprobation">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Frais: #{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
|
||||
<p:message id="msgApprobation" />
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgApprobation').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Approuver" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.approuverAdhesion}" />
|
||||
<ui:param name="update" value="@form :formListe" />
|
||||
<ui:param name="oncomplete" value="PF('dlgApprobation').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Rejet -->
|
||||
<p:dialog header="Rejeter l'Adhésion" widgetVar="dlgRejet" modal="true" width="500" resizable="false">
|
||||
<h:form id="formRejet">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="motifRejet" />
|
||||
<ui:param name="label" value="Motif du rejet" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.motifRejet}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="4" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgRejet').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<p:commandButton value="Rejeter"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-danger"
|
||||
action="#{adhesionsBean.rejeterAdhesion(adhesionsBean.adhesionSelectionnee.motifRejet)}"
|
||||
update="@form :formListe"
|
||||
oncomplete="PF('dlgRejet').hide();" />
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -5,16 +5,110 @@
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
<ui:define name="title">UnionFlow - New</ui:define>
|
||||
|
||||
<ui:define name="title">Nouvelle Adhésion - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>New - Adhesion</h2>
|
||||
<p>Page en cours de développement...</p>
|
||||
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-user-plus text-green-500" />
|
||||
<ui:param name="title" value="Nouvelle Adhésion" />
|
||||
<ui:param name="description" value="Création d'une nouvelle demande d'adhésion" />
|
||||
</ui:include>
|
||||
|
||||
<!-- Formulaire de nouvelle adhésion -->
|
||||
<div class="card">
|
||||
<h:form id="formNouvelleAdhesion">
|
||||
<h5>Créer une Nouvelle Adhésion</h5>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Informations du Membre" />
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="membreId" value="Membre" />
|
||||
<p:selectOneMenu id="membreId"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.membreId}"
|
||||
required="true"
|
||||
requiredMessage="Veuillez sélectionner un membre"
|
||||
filter="true"
|
||||
filterMatchMode="contains"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{adhesionsBean.membresSelectItems}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="membreId" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="organisationId" value="Organisation" />
|
||||
<p:selectOneMenu id="organisationId"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.organisationId}"
|
||||
required="true"
|
||||
requiredMessage="Veuillez sélectionner une organisation"
|
||||
filter="true"
|
||||
filterMatchMode="contains"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{adhesionsBean.associationsSelectItems}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="organisationId" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Frais d'Adhésion" />
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="fraisAdhesion" value="Frais d'adhésion (FCFA)" />
|
||||
<p:inputNumber id="fraisAdhesion"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.fraisAdhesion}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Observations" />
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="observations" />
|
||||
<ui:param name="label" value="Observations (optionnel)" />
|
||||
<ui:param name="value" value="#{adhesionsBean.nouvelleAdhesion.observations}" />
|
||||
<ui:param name="rows" value="4" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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="action" value="#{navigationBean.goToDashboard}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Créer l'adhésion" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerAdhesion}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Paiement des Adhésions - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-credit-card text-green-500" />
|
||||
<ui:param name="title" value="Paiement des Adhésions" />
|
||||
<ui:param name="description" value="Enregistrement et suivi des paiements d'adhésion" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsPaiement">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{adhesionsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques de paiement -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.totalCollecteFormatte}" />
|
||||
<ui:param name="label" value="Total Collecté" />
|
||||
<ui:param name="icon" value="pi pi-wallet" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsPayees}" />
|
||||
<ui:param name="label" value="Adhésions Payées" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.tauxPaiementInt}%" />
|
||||
<ui:param name="label" value="Taux de Paiement" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsApprouvees - adhesionsBean.statistiques.adhesionsPayees}" />
|
||||
<ui:param name="label" value="En Attente de Paiement" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Adhésions approuvées en attente de paiement -->
|
||||
<div class="card">
|
||||
<h:form id="formPaiements">
|
||||
<h5>Adhésions Approuvées en Attente de Paiement</h5>
|
||||
|
||||
<p:dataTable id="dtPaiements"
|
||||
value="#{adhesionsBean.adhesionsFiltrees}"
|
||||
var="adhesion"
|
||||
filteredValue="#{adhesionsBean.adhesionsFiltrees}"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
emptyMessage="Aucune adhésion en attente de paiement"
|
||||
selection="#{adhesionsBean.adhesionSelectionnee}"
|
||||
selectionMode="single">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Adhésions à payer</span>
|
||||
<p:selectOneMenu value="#{adhesionsBean.filtres.statut}" styleClass="w-12rem">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="Approuvée" itemValue="APPROUVEE" />
|
||||
<f:selectItem itemLabel="En paiement" itemValue="EN_PAIEMENT" />
|
||||
<p:ajax update="dtPaiements" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{adhesion.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{adhesion.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{adhesion.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{adhesion.nomOrganisation}">
|
||||
<h:outputText value="#{adhesion.nomOrganisation}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Frais" sortBy="#{adhesion.fraisAdhesion}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.fraisAdhesionFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Payé" sortBy="#{adhesion.montantPaye}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.montantPayeFormatte}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Restant" style="width:120px">
|
||||
<h:outputText value="#{adhesion.montantRestantFormatte}"
|
||||
styleClass="#{adhesion.montantRestant.compareTo(java.math.BigDecimal.ZERO) > 0 ? 'text-orange-500 font-bold' : 'text-green-500'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Approbation" sortBy="#{adhesion.dateApprobation}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.dateApprobationFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:200px">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton value="Payer"
|
||||
icon="pi pi-check"
|
||||
styleClass="p-button-success p-button-sm"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formPaiement"
|
||||
oncomplete="PF('dlgPaiement').show();" />
|
||||
<p:commandButton value="Partiel"
|
||||
icon="pi pi-minus"
|
||||
styleClass="p-button-info p-button-sm"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formPaiementPartiel"
|
||||
oncomplete="PF('dlgPaiementPartiel').show();" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Paiement Complet -->
|
||||
<p:dialog header="Enregistrer un Paiement" widgetVar="dlgPaiement" modal="true" width="500" resizable="false">
|
||||
<h:form id="formPaiement">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Frais d'adhésion: #{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="methodePaiement" />
|
||||
<ui:param name="label" value="Méthode de paiement" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.methodePaiement}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Wave Money" itemValue="WAVE_MONEY" />
|
||||
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
|
||||
<f:selectItem itemLabel="Virement bancaire" itemValue="VIREMENT" />
|
||||
<f:selectItem itemLabel="Chèque" itemValue="CHEQUE" />
|
||||
<f:selectItem itemLabel="Orange Money" itemValue="ORANGE_MONEY" />
|
||||
<f:selectItem itemLabel="Free Money" itemValue="FREE_MONEY" />
|
||||
<f:selectItem itemLabel="Carte bancaire" itemValue="CARTE_BANCAIRE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="referencePaiement" />
|
||||
<ui:param name="label" value="Référence de paiement" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.referencePaiement}" />
|
||||
<ui:param name="placeholder" value="Ex: WAVE-123456789" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="observationsPaiement" />
|
||||
<ui:param name="label" value="Observations" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.observations}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgPaiement').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerPaiement(adhesionsBean.adhesionSelectionnee.fraisAdhesion, adhesionsBean.adhesionSelectionnee.methodePaiement, adhesionsBean.adhesionSelectionnee.referencePaiement)}" />
|
||||
<ui:param name="update" value="@form :formPaiements" />
|
||||
<ui:param name="oncomplete" value="PF('dlgPaiement').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Paiement Partiel -->
|
||||
<p:dialog header="Enregistrer un Paiement Partiel" widgetVar="dlgPaiementPartiel" modal="true" width="500" resizable="false">
|
||||
<h:form id="formPaiementPartiel">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Frais d'adhésion: #{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
<p class="text-500 text-sm">Montant restant: #{adhesionsBean.adhesionSelectionnee.montantRestantFormatte}</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="montantPaye" value="Montant à payer (FCFA)" />
|
||||
<p:inputNumber id="montantPaye"
|
||||
value="#{adhesionsBean.adhesionSelectionnee.montantPaye}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
maxValue="#{adhesionsBean.adhesionSelectionnee.fraisAdhesion}"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="methodePaiementPartiel" />
|
||||
<ui:param name="label" value="Méthode de paiement" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.methodePaiement}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Wave Money" itemValue="WAVE_MONEY" />
|
||||
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
|
||||
<f:selectItem itemLabel="Virement bancaire" itemValue="VIREMENT" />
|
||||
<f:selectItem itemLabel="Chèque" itemValue="CHEQUE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="referencePaiementPartiel" />
|
||||
<ui:param name="label" value="Référence de paiement" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.referencePaiement}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgPaiementPartiel').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerPaiement(adhesionsBean.adhesionSelectionnee.montantPaye, adhesionsBean.adhesionSelectionnee.methodePaiement, adhesionsBean.adhesionSelectionnee.referencePaiement)}" />
|
||||
<ui:param name="update" value="@form :formPaiements" />
|
||||
<ui:param name="oncomplete" value="PF('dlgPaiementPartiel').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -5,16 +5,252 @@
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
<ui:define name="title">UnionFlow - Pending</ui:define>
|
||||
|
||||
<ui:define name="title">Adhésions en Attente - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-clock text-orange-500" />
|
||||
<ui:param name="title" value="Adhésions en Attente" />
|
||||
<ui:param name="description" value="Validation et traitement des demandes d'adhésion en attente" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsPending">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{adhesionsBean.chargerAdhesionsEnAttente}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>Pending - Adhesion</h2>
|
||||
<p>Page en cours de développement...</p>
|
||||
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
|
||||
</div>
|
||||
</div>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsEnAttente}" />
|
||||
<ui:param name="label" value="En Attente" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsApprouvees}" />
|
||||
<ui:param name="label" value="Approuvées" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.tauxApprobationInt}%" />
|
||||
<ui:param name="label" value="Taux d'Approbation" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.totalCollecteFormatte}" />
|
||||
<ui:param name="label" value="Total Collecté" />
|
||||
<ui:param name="icon" value="pi pi-wallet" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Liste des adhésions en attente -->
|
||||
<div class="card">
|
||||
<h:form id="formPending">
|
||||
<h5>Adhésions en Attente de Validation</h5>
|
||||
|
||||
<p:dataTable id="dtPending"
|
||||
value="#{adhesionsBean.adhesionsFiltrees}"
|
||||
var="adhesion"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
emptyMessage="Aucune adhésion en attente">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Demandes en attente d'approbation</span>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column headerText="Référence" sortBy="#{adhesion.numeroReference}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.numeroReference}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{adhesion.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{adhesion.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{adhesion.numeroMembre}</div>
|
||||
<div class="text-500 text-xs">#{adhesion.emailMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{adhesion.nomOrganisation}">
|
||||
<h:outputText value="#{adhesion.nomOrganisation}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Demande" sortBy="#{adhesion.dateDemande}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.dateDemandeFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Jours" style="width:80px">
|
||||
<h:outputText value="#{adhesion.joursDepuisDemande} jour(s)" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Frais" sortBy="#{adhesion.fraisAdhesion}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.fraisAdhesionFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:200px">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-check"
|
||||
title="Approuver"
|
||||
styleClass="p-button-rounded p-button-text p-button-success"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formApprobation"
|
||||
oncomplete="PF('dlgApprobation').show();" />
|
||||
<p:commandButton icon="pi pi-times"
|
||||
title="Rejeter"
|
||||
styleClass="p-button-rounded p-button-text p-button-danger"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formRejet"
|
||||
oncomplete="PF('dlgRejet').show();" />
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir les détails"
|
||||
styleClass="p-button-rounded p-button-text p-button-info"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formDetailsAdhesion"
|
||||
oncomplete="PF('dlgDetailsAdhesion').show();" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Approbation -->
|
||||
<p:dialog header="Approuver l'Adhésion" widgetVar="dlgApprobation" modal="true" width="500" resizable="false">
|
||||
<h:form id="formApprobation">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Frais: #{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgApprobation').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Approuver" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.approuverAdhesion}" />
|
||||
<ui:param name="update" value="@form :formPending" />
|
||||
<ui:param name="oncomplete" value="PF('dlgApprobation').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Rejet -->
|
||||
<p:dialog header="Rejeter l'Adhésion" widgetVar="dlgRejet" modal="true" width="500" resizable="false">
|
||||
<h:form id="formRejet">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="motifRejet" />
|
||||
<ui:param name="label" value="Motif du rejet" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.motifRejet}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="4" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgRejet').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<p:commandButton value="Rejeter"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-danger"
|
||||
action="#{adhesionsBean.rejeterAdhesion(adhesionsBean.adhesionSelectionnee.motifRejet)}"
|
||||
update="@form :formPending"
|
||||
oncomplete="PF('dlgRejet').hide();" />
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Détails Adhésion -->
|
||||
<p:dialog header="Détails de l'Adhésion" widgetVar="dlgDetailsAdhesion" modal="true" width="600" resizable="false">
|
||||
<h:form id="formDetailsAdhesion">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Référence</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Statut</label>
|
||||
<p:tag value="#{adhesionsBean.adhesionSelectionnee.statutLibelle}"
|
||||
severity="#{adhesionsBean.adhesionSelectionnee.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Membre</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">N° #{adhesionsBean.adhesionSelectionnee.numeroMembre} - #{adhesionsBean.adhesionSelectionnee.emailMembre}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Organisation</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomOrganisation}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date de demande</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.dateDemandeFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Frais d'adhésion</label>
|
||||
<p class="text-600 font-bold">#{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{adhesionsBean.adhesionSelectionnee.observations != null}">
|
||||
<div class="field">
|
||||
<label class="font-medium">Observations</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.observations}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,47 +1,166 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Renouvellement Adhésion - UnionFlow</ui:define>
|
||||
<ui:define name="title">Renouvellement d'Adhésion - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="card">
|
||||
<h5>Renouvellement d'Adhésion</h5>
|
||||
<p>Gestion des renouvellements d'adhésion.</p>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="card">
|
||||
<h6>Adhésions à Renouveler</h6>
|
||||
<p:dataTable var="adhesion" value="#{[]}">
|
||||
<p:column headerText="Membre">
|
||||
<h:outputText value="#{adhesion.membre}" />
|
||||
</p:column>
|
||||
<p:column headerText="Expiration">
|
||||
<h:outputText value="#{adhesion.dateExpiration}" />
|
||||
</p:column>
|
||||
<p:column headerText="Action">
|
||||
<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:dataTable>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh text-blue-500" />
|
||||
<ui:param name="title" value="Renouvellement d'Adhésion" />
|
||||
<ui:param name="description" value="Gestion des renouvellements d'adhésion" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsRenouvellement">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{adhesionsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="card">
|
||||
<h6>Statistiques</h6>
|
||||
<p>Adhésions expirant ce mois : <strong>5</strong></p>
|
||||
<p>Adhésions renouvelées : <strong>12</strong></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
</ui:composition>
|
||||
<!-- Statistiques -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsPayees}" />
|
||||
<ui:param name="label" value="Adhésions Actives" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="0" />
|
||||
<ui:param name="label" value="À Renouveler (ce mois)" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="0" />
|
||||
<ui:param name="label" value="Renouvelées (ce mois)" />
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.totalAdhesions}" />
|
||||
<ui:param name="label" value="Total Adhésions" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Liste des adhésions à renouveler -->
|
||||
<div class="card">
|
||||
<h:form id="formRenouvellement">
|
||||
<h5>Adhésions à Renouveler</h5>
|
||||
|
||||
<p:dataTable id="dtRenouvellement"
|
||||
value="#{adhesionsBean.adhesionsFiltrees}"
|
||||
var="adhesion"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
emptyMessage="Aucune adhésion à renouveler">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Adhésions nécessitant un renouvellement</span>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{adhesion.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{adhesion.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{adhesion.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{adhesion.nomOrganisation}">
|
||||
<h:outputText value="#{adhesion.nomOrganisation}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Approbation" sortBy="#{adhesion.dateApprobation}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.dateApprobationFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Frais" sortBy="#{adhesion.fraisAdhesion}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.fraisAdhesionFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" style="width:150px">
|
||||
<p:tag value="#{adhesion.statutLibelle}"
|
||||
severity="#{adhesion.statutSeverity}"
|
||||
icon="#{adhesion.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:150px">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Renouveler" />
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="onclick" value="PF('dlgRenouvellement').show(); adhesionsBean.selectionnerAdhesion(adhesion);" />
|
||||
<ui:param name="styleClass" value="p-button-sm" />
|
||||
</ui:include>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Renouvellement -->
|
||||
<p:dialog header="Renouveler l'Adhésion" widgetVar="dlgRenouvellement" modal="true" width="500" resizable="false">
|
||||
<h:form id="formRenouvellement">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion actuelle</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Frais actuel: #{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="nouveauxFrais" value="Nouveaux frais d'adhésion (FCFA)" />
|
||||
<p:inputNumber id="nouveauxFrais"
|
||||
value="#{adhesionsBean.nouvelleAdhesion.fraisAdhesion}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="observationsRenouvellement" />
|
||||
<ui:param name="label" value="Observations" />
|
||||
<ui:param name="value" value="#{adhesionsBean.nouvelleAdhesion.observations}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgRenouvellement').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Créer le renouvellement" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.enregistrerAdhesion}" />
|
||||
<ui:param name="update" value="@form :formRenouvellement" />
|
||||
<ui:param name="oncomplete" value="PF('dlgRenouvellement').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,41 +1,253 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Validation Adhésion - UnionFlow</ui:define>
|
||||
<ui:define name="title">Validation des Adhésions - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="card">
|
||||
<h5>Validation des Adhésions</h5>
|
||||
<p>Traitement et validation des demandes d'adhésion en attente.</p>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-check-circle text-green-500" />
|
||||
<ui:param name="title" value="Validation des Adhésions" />
|
||||
<ui:param name="description" value="Approbation et rejet des demandes d'adhésion" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsValidation">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{adhesionsBean.chargerAdhesionsEnAttente}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsEnAttente}" />
|
||||
<ui:param name="label" value="En Attente" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<p:dataTable var="adhesion" value="#{[]}">
|
||||
<p:column headerText="Membre">
|
||||
<h:outputText value="#{adhesion.membre}" />
|
||||
</p:column>
|
||||
<p:column headerText="Date Demande">
|
||||
<h:outputText value="#{adhesion.dateDemande}" />
|
||||
</p:column>
|
||||
<p:column headerText="Type">
|
||||
<h:outputText value="#{adhesion.type}" />
|
||||
</p:column>
|
||||
<p:column headerText="Actions">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.adhesionsApprouvees}" />
|
||||
<ui:param name="label" value="Approuvées" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.tauxApprobationInt}%" />
|
||||
<ui:param name="label" value="Taux d'Approbation" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{adhesionsBean.statistiques.totalAdhesions}" />
|
||||
<ui:param name="label" value="Total" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Liste des adhésions en attente -->
|
||||
<div class="card">
|
||||
<h:form id="formValidation">
|
||||
<h5>Adhésions en Attente de Validation</h5>
|
||||
|
||||
<p:dataTable id="dtValidation"
|
||||
value="#{adhesionsBean.adhesionsFiltrees}"
|
||||
var="adhesion"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
emptyMessage="Aucune adhésion en attente">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Demandes nécessitant une validation</span>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column headerText="Référence" sortBy="#{adhesion.numeroReference}" style="width:150px">
|
||||
<h:outputText value="#{adhesion.numeroReference}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{adhesion.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{adhesion.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{adhesion.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Organisation" sortBy="#{adhesion.nomOrganisation}">
|
||||
<h:outputText value="#{adhesion.nomOrganisation}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Demande" sortBy="#{adhesion.dateDemande}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.dateDemandeFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Frais" sortBy="#{adhesion.fraisAdhesion}" style="width:120px">
|
||||
<h:outputText value="#{adhesion.fraisAdhesionFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:250px">
|
||||
<div class="flex gap-1">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Approuver" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{adhesionsBean.selectionnerAdhesion(adhesion)}" />
|
||||
<ui:param name="update" value=":formApprobation" />
|
||||
<ui:param name="oncomplete" value="PF('dlgApprobation').show();" />
|
||||
<ui:param name="styleClass" value="p-button-sm" />
|
||||
</ui:include>
|
||||
<p:commandButton value="Rejeter"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-danger p-button-sm"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formRejet"
|
||||
oncomplete="PF('dlgRejet').show();" />
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir les détails"
|
||||
styleClass="p-button-rounded p-button-text p-button-info p-button-sm"
|
||||
action="#{adhesionsBean.selectionnerAdhesion(adhesion)}"
|
||||
update=":formDetailsAdhesion"
|
||||
oncomplete="PF('dlgDetailsAdhesion').show();" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Approbation -->
|
||||
<p:dialog header="Approuver l'Adhésion" widgetVar="dlgApprobation" modal="true" width="500" resizable="false">
|
||||
<h:form id="formApprobation">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Frais: #{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgApprobation').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Approuver" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="styleClass" value="ui-button-sm" />
|
||||
<ui:param name="action" value="#{adhesionsBean.approuverAdhesion}" />
|
||||
<ui:param name="update" value="@form :formValidation" />
|
||||
<ui:param name="oncomplete" value="PF('dlgApprobation').hide();" />
|
||||
</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:dataTable>
|
||||
</div>
|
||||
</ui:define>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:composition>
|
||||
<!-- Dialog Rejet -->
|
||||
<p:dialog header="Rejeter l'Adhésion" widgetVar="dlgRejet" modal="true" width="500" resizable="false">
|
||||
<h:form id="formRejet">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Adhésion</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference} - #{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="motifRejet" />
|
||||
<ui:param name="label" value="Motif du rejet" />
|
||||
<ui:param name="value" value="#{adhesionsBean.adhesionSelectionnee.motifRejet}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="4" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgRejet').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<p:commandButton value="Rejeter"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-danger"
|
||||
action="#{adhesionsBean.rejeterAdhesion(adhesionsBean.adhesionSelectionnee.motifRejet)}"
|
||||
update="@form :formValidation"
|
||||
oncomplete="PF('dlgRejet').hide();" />
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Détails Adhésion -->
|
||||
<p:dialog header="Détails de l'Adhésion" widgetVar="dlgDetailsAdhesion" modal="true" width="600" resizable="false">
|
||||
<h:form id="formDetailsAdhesion">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Référence</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.numeroReference}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Statut</label>
|
||||
<p:tag value="#{adhesionsBean.adhesionSelectionnee.statutLibelle}"
|
||||
severity="#{adhesionsBean.adhesionSelectionnee.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Membre</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">N° #{adhesionsBean.adhesionSelectionnee.numeroMembre}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Organisation</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.nomOrganisation}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date de demande</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.dateDemandeFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Frais d'adhésion</label>
|
||||
<p class="text-600 font-bold">#{adhesionsBean.adhesionSelectionnee.fraisAdhesionFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{adhesionsBean.adhesionSelectionnee.observations != null}">
|
||||
<div class="field">
|
||||
<label class="font-medium">Observations</label>
|
||||
<p class="text-600">#{adhesionsBean.adhesionSelectionnee.observations}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Journal d'Audit - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- Redirection vers la page principale d'audit -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-history text-4xl text-indigo-500 mb-3"></i>
|
||||
<h5>Journal d'Audit</h5>
|
||||
<p class="text-600 mt-2">
|
||||
Redirection vers la page principale du journal d'audit...
|
||||
</p>
|
||||
<div class="mt-4">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Accéder au Journal d'Audit" />
|
||||
<ui:param name="icon" value="pi pi-arrow-right" />
|
||||
<ui:param name="outcome" value="/pages/admin/audit/journal.xhtml" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
@@ -1,19 +1,44 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Paramètres Système - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-cog text-orange-500" />
|
||||
<ui:param name="title" value="Paramètres Système" />
|
||||
<ui:param name="description" value="Configuration des paramètres généraux de l'application" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{configurationBean.enregistrer}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Information -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-info-circle text-4xl text-orange-500 mb-3"></i>
|
||||
<h5>Configuration Système</h5>
|
||||
<p class="text-600 mt-2">
|
||||
La page de configuration système sera disponible prochainement.
|
||||
</p>
|
||||
<p class="text-600 mt-2">
|
||||
Elle permettra de configurer les paramètres généraux de l'application.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
@@ -1,19 +1,50 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Gestion des Rôles - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-shield text-purple-500" />
|
||||
<ui:param name="title" value="Gestion des Rôles" />
|
||||
<ui:param name="description" value="Gestion des rôles et permissions via Keycloak" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-info.xhtml">
|
||||
<ui:param name="value" value="Documentation Keycloak" />
|
||||
<ui:param name="icon" value="pi pi-book" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Information -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-info-circle text-4xl text-purple-500 mb-3"></i>
|
||||
<h5>Gestion des Rôles via Keycloak</h5>
|
||||
<p class="text-600 mt-2">
|
||||
La gestion des rôles et permissions se fait directement via Keycloak Admin Console.
|
||||
</p>
|
||||
<p class="text-600 mt-2">
|
||||
Les rôles disponibles incluent : SUPER_ADMIN, ADMIN_ORG, SECRETAIRE, TRESORIER, MEMBRE, etc.
|
||||
</p>
|
||||
<div class="mt-4">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Accéder à Keycloak Admin" />
|
||||
<ui:param name="icon" value="pi pi-external-link" />
|
||||
<ui:param name="onclick" value="window.open('https://security.lions.dev/admin', '_blank');" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
@@ -1,19 +1,42 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Sauvegarde et Restauration - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-database text-green-500" />
|
||||
<ui:param name="title" value="Sauvegarde et Restauration" />
|
||||
<ui:param name="description" value="Gestion des sauvegardes et restauration de la base de données" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Créer une sauvegarde" />
|
||||
<ui:param name="icon" value="pi pi-save" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Information -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-info-circle text-4xl text-green-500 mb-3"></i>
|
||||
<h5>Sauvegarde et Restauration</h5>
|
||||
<p class="text-600 mt-2">
|
||||
La fonctionnalité de sauvegarde et restauration sera disponible prochainement.
|
||||
</p>
|
||||
<p class="text-600 mt-2">
|
||||
Elle permettra de créer des sauvegardes de la base de données et de restaurer des sauvegardes précédentes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
@@ -1,19 +1,50 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Gestion des Utilisateurs - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-users text-blue-500" />
|
||||
<ui:param name="title" value="Gestion des Utilisateurs" />
|
||||
<ui:param name="description" value="Gestion des utilisateurs et de leurs accès via Keycloak" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-info.xhtml">
|
||||
<ui:param name="value" value="Documentation Keycloak" />
|
||||
<ui:param name="icon" value="pi pi-book" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Information -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-info-circle text-4xl text-blue-500 mb-3"></i>
|
||||
<h5>Gestion des Utilisateurs via Keycloak</h5>
|
||||
<p class="text-600 mt-2">
|
||||
La gestion des utilisateurs se fait directement via Keycloak Admin Console.
|
||||
</p>
|
||||
<p class="text-600 mt-2">
|
||||
Pour accéder à la console d'administration Keycloak, veuillez utiliser l'interface dédiée.
|
||||
</p>
|
||||
<div class="mt-4">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Accéder à Keycloak Admin" />
|
||||
<ui:param name="icon" value="pi pi-external-link" />
|
||||
<ui:param name="onclick" value="window.open('https://security.lions.dev/admin', '_blank');" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
@@ -5,16 +5,429 @@
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
<ui:define name="title">UnionFlow - Collect</ui:define>
|
||||
|
||||
<ui:define name="title">Gestion des Cotisations - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-money-bill text-green-500" />
|
||||
<ui:param name="title" value="Gestion des Cotisations" />
|
||||
<ui:param name="description" value="Suivi et gestion des cotisations des membres" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsCotisations">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouvelle cotisation" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="onclick" value="PF('dlgNouvelleCotisation').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="action" value="#{cotisationsBean.exporterCotisations}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{cotisationsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>Collect - Cotisation</h2>
|
||||
<p>Page en cours de développement...</p>
|
||||
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
|
||||
</div>
|
||||
</div>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.totalCollecteFormatte}" />
|
||||
<ui:param name="label" value="Total Collecté" />
|
||||
<ui:param name="icon" value="pi pi-wallet" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.tauxRecouvrementInt}%" />
|
||||
<ui:param name="label" value="Taux de Recouvrement" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.cotisationsEnRetard}" />
|
||||
<ui:param name="label" value="En Retard" />
|
||||
<ui:param name="icon" value="pi pi-exclamation-triangle" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.montantRetardFormatte}" />
|
||||
<ui:param name="label" value="Montant Retard" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Liste des cotisations -->
|
||||
<div class="card">
|
||||
<h:form id="formCotisations">
|
||||
<h5>Liste des Cotisations</h5>
|
||||
|
||||
<!-- Filtres -->
|
||||
<p:toolbar>
|
||||
<p:toolbarGroup>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<span class="p-input-icon-left">
|
||||
<i class="pi pi-search"></i>
|
||||
<p:inputText placeholder="Rechercher par membre..."
|
||||
value="#{cotisationsBean.filtres.nomMembre}"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup" update="dtCotisations" />
|
||||
</p:inputText>
|
||||
</span>
|
||||
|
||||
<p:selectOneMenu value="#{cotisationsBean.filtres.statut}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
|
||||
<f:selectItem itemLabel="Payée" itemValue="PAYEE" />
|
||||
<f:selectItem itemLabel="Partiellement payée" itemValue="PARTIELLEMENT_PAYEE" />
|
||||
<f:selectItem itemLabel="En retard" itemValue="EN_RETARD" />
|
||||
<f:selectItem itemLabel="Annulée" itemValue="ANNULEE" />
|
||||
<p:ajax update="dtCotisations" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:selectOneMenu value="#{cotisationsBean.filtres.typeCotisation}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Mensuelle" itemValue="MENSUELLE" />
|
||||
<f:selectItem itemLabel="Trimestrielle" itemValue="TRIMESTRIELLE" />
|
||||
<f:selectItem itemLabel="Semestrielle" itemValue="SEMESTRIELLE" />
|
||||
<f:selectItem itemLabel="Annuelle" itemValue="ANNUELLE" />
|
||||
<f:selectItem itemLabel="Adhésion" itemValue="ADHESION" />
|
||||
<f:selectItem itemLabel="Exceptionnelle" itemValue="EXCEPTIONNELLE" />
|
||||
<p:ajax update="dtCotisations" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</p:toolbarGroup>
|
||||
|
||||
<p:toolbarGroup align="right">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Filtres avancés" />
|
||||
<ui:param name="icon" value="pi pi-filter" />
|
||||
<ui:param name="onclick" value="PF('dlgFiltresAvances').show();" />
|
||||
<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="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="action" value="#{cotisationsBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</p:toolbarGroup>
|
||||
</p:toolbar>
|
||||
|
||||
<!-- Tableau des cotisations -->
|
||||
<p:dataTable id="dtCotisations"
|
||||
value="#{cotisationsBean.cotisationsFiltrees}"
|
||||
var="cotisation"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
|
||||
currentPageReportTemplate="{startRecord} - {endRecord} sur {totalRecords}"
|
||||
emptyMessage="Aucune cotisation trouvée"
|
||||
selection="#{cotisationsBean.cotisationsSelectionnees}"
|
||||
selectionMode="multiple">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Cotisations (#{cotisationsBean.cotisationsFiltrees.size()})</span>
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Rappels groupés" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{cotisationsBean.envoyerRappelsGroupes}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="disabled" value="#{empty cotisationsBean.cotisationsSelectionnees}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column selectionMode="multiple" style="width:50px" />
|
||||
|
||||
<p:column headerText="Référence" sortBy="#{cotisation.numeroReference}" style="width:150px">
|
||||
<h:outputText value="#{cotisation.numeroReference}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{cotisation.nomMembre}">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div>
|
||||
<div class="font-medium">#{cotisation.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{cotisation.numeroMembre}</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type" sortBy="#{cotisation.typeCotisation}" style="width:120px">
|
||||
<p:tag value="#{cotisation.typeCotisationLibelle}"
|
||||
severity="info"
|
||||
icon="#{cotisation.typeCotisation == 'ADHESION' ? 'pi-user-plus' : 'pi-calendar'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Dû" sortBy="#{cotisation.montantDu}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantDuFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Payé" sortBy="#{cotisation.montantPaye}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantPayeFormatte}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{cotisation.statut}" style="width:150px">
|
||||
<p:tag value="#{cotisation.statutLibelle}"
|
||||
severity="#{cotisation.statutSeverity}"
|
||||
icon="#{cotisation.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Échéance" sortBy="#{cotisation.dateEcheance}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.dateEcheanceFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:200px">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-check"
|
||||
title="Marquer comme payée"
|
||||
styleClass="p-button-rounded p-button-text p-button-success"
|
||||
disabled="#{cotisation.statut == 'PAYEE'}"
|
||||
action="#{cotisationsBean.marquerCommePaye(cotisation)}"
|
||||
update="@form" />
|
||||
<p:commandButton icon="pi pi-send"
|
||||
title="Envoyer un rappel"
|
||||
styleClass="p-button-rounded p-button-text p-button-warning"
|
||||
action="#{cotisationsBean.envoyerRappel(cotisation)}"
|
||||
update="@form" />
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir les détails"
|
||||
styleClass="p-button-rounded p-button-text p-button-info"
|
||||
action="#{cotisationsBean.selectionnerCotisation(cotisation)}"
|
||||
update=":formDetailsCotisation"
|
||||
oncomplete="PF('dlgDetailsCotisation').show();" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Nouvelle Cotisation -->
|
||||
<p:dialog header="Nouvelle Cotisation" widgetVar="dlgNouvelleCotisation" modal="true" width="600" resizable="false">
|
||||
<h:form id="formNouvelleCotisation">
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Informations de la cotisation</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="libelle" />
|
||||
<ui:param name="label" value="Libellé" />
|
||||
<ui:param name="value" value="#{cotisationsBean.nouvelleCotisation.libelle}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Ex: Cotisation mensuelle janvier 2024" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="typeCotisation" />
|
||||
<ui:param name="label" value="Type de cotisation" />
|
||||
<ui:param name="value" value="#{cotisationsBean.nouvelleCotisation.typeCotisation}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Mensuelle" itemValue="MENSUELLE" />
|
||||
<f:selectItem itemLabel="Trimestrielle" itemValue="TRIMESTRIELLE" />
|
||||
<f:selectItem itemLabel="Semestrielle" itemValue="SEMESTRIELLE" />
|
||||
<f:selectItem itemLabel="Annuelle" itemValue="ANNUELLE" />
|
||||
<f:selectItem itemLabel="Adhésion" itemValue="ADHESION" />
|
||||
<f:selectItem itemLabel="Exceptionnelle" itemValue="EXCEPTIONNELLE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateEcheance" />
|
||||
<ui:param name="label" value="Date d'échéance" />
|
||||
<ui:param name="value" value="#{cotisationsBean.nouvelleCotisation.dateEcheance}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="montantDu" value="Montant dû (FCFA)" />
|
||||
<p:inputNumber id="montantDu"
|
||||
value="#{cotisationsBean.nouvelleCotisation.montantDu}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="observations" />
|
||||
<ui:param name="label" value="Observations" />
|
||||
<ui:param name="value" value="#{cotisationsBean.nouvelleCotisation.observations}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgNouvelleCotisation').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{cotisationsBean.enregistrerCotisation}" />
|
||||
<ui:param name="update" value="@form :formCotisations" />
|
||||
<ui:param name="oncomplete" value="PF('dlgNouvelleCotisation').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Filtres Avancés -->
|
||||
<p:dialog header="Filtres Avancés" widgetVar="dlgFiltresAvances" modal="true" width="500" resizable="false">
|
||||
<h:form id="formFiltresAvances">
|
||||
<div class="ui-fluid">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="club" />
|
||||
<ui:param name="label" value="Club/Association" />
|
||||
<ui:param name="value" value="#{cotisationsBean.filtres.club}" />
|
||||
<ui:param name="placeholder" value="Rechercher par club..." />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="methodePaiement" />
|
||||
<ui:param name="label" value="Méthode de paiement" />
|
||||
<ui:param name="value" value="#{cotisationsBean.filtres.methodePaiement}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Toutes" itemValue="" />
|
||||
<f:selectItem itemLabel="Wave Money" itemValue="WAVE_MONEY" />
|
||||
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
|
||||
<f:selectItem itemLabel="Virement" itemValue="VIREMENT" />
|
||||
<f:selectItem itemLabel="Chèque" itemValue="CHEQUE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebut" />
|
||||
<ui:param name="label" value="Date début" />
|
||||
<ui:param name="value" value="#{cotisationsBean.filtres.dateDebut}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateFin" />
|
||||
<ui:param name="label" value="Date fin" />
|
||||
<ui:param name="value" value="#{cotisationsBean.filtres.dateFin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Appliquer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{cotisationsBean.rechercher}" />
|
||||
<ui:param name="update" value=":formCotisations" />
|
||||
<ui:param name="oncomplete" value="PF('dlgFiltresAvances').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Détails Cotisation -->
|
||||
<p:dialog header="Détails de la Cotisation" widgetVar="dlgDetailsCotisation" modal="true" width="600" resizable="false">
|
||||
<h:form id="formDetailsCotisation">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Référence</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.numeroReference}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Statut</label>
|
||||
<p:tag value="#{cotisationsBean.cotisationSelectionnee.statutLibelle}"
|
||||
severity="#{cotisationsBean.cotisationSelectionnee.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Membre</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">#{cotisationsBean.cotisationSelectionnee.numeroMembre}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Type</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.typeCotisationLibelle}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant dû</label>
|
||||
<p class="text-600 font-bold">#{cotisationsBean.cotisationSelectionnee.montantDuFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant payé</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.montantPayeFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date d'échéance</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.dateEcheanceFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date de paiement</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.datePaiementFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,21 +1,252 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Historique des Cotisations - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-history text-blue-500" />
|
||||
<ui:param name="title" value="Historique des Cotisations" />
|
||||
<ui:param name="description" value="Consultation de l'historique complet des cotisations et paiements" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsHistorique">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="action" value="#{cotisationsBean.exporterCotisations}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{cotisationsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Filtres d'historique -->
|
||||
<div class="card">
|
||||
<h:form id="formFiltresHistorique">
|
||||
<h5>Filtres de Recherche</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebut" />
|
||||
<ui:param name="label" value="Date début" />
|
||||
<ui:param name="value" value="#{cotisationsBean.filtres.dateDebut}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateFin" />
|
||||
<ui:param name="label" value="Date fin" />
|
||||
<ui:param name="value" value="#{cotisationsBean.filtres.dateFin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="statutHistorique" />
|
||||
<ui:param name="label" value="Statut" />
|
||||
<ui:param name="value" value="#{cotisationsBean.filtres.statut}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="Payée" itemValue="PAYEE" />
|
||||
<f:selectItem itemLabel="Partiellement payée" itemValue="PARTIELLEMENT_PAYEE" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
|
||||
<f:selectItem itemLabel="En retard" itemValue="EN_RETARD" />
|
||||
<f:selectItem itemLabel="Annulée" itemValue="ANNULEE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel />
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Rechercher" />
|
||||
<ui:param name="icon" value="pi pi-search" />
|
||||
<ui:param name="action" value="#{cotisationsBean.rechercher}" />
|
||||
<ui:param name="update" value=":formHistorique" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="action" value="#{cotisationsBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="@form :formHistorique" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Tableau d'historique -->
|
||||
<div class="card">
|
||||
<h:form id="formHistorique">
|
||||
<h5>Historique des Cotisations</h5>
|
||||
|
||||
<p:dataTable id="dtHistorique"
|
||||
value="#{cotisationsBean.cotisationsFiltrees}"
|
||||
var="cotisation"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
sortMode="multiple"
|
||||
emptyMessage="Aucune cotisation trouvée">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Historique (#{cotisationsBean.cotisationsFiltrees.size()} cotisation(s))</span>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column headerText="Date" sortBy="#{cotisation.dateCreation}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.dateCreation}" rendered="#{cotisation.dateCreation != null}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy" />
|
||||
</h:outputText>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Référence" sortBy="#{cotisation.numeroReference}" style="width:150px">
|
||||
<h:outputText value="#{cotisation.numeroReference}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{cotisation.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{cotisation.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{cotisation.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type" sortBy="#{cotisation.typeCotisation}" style="width:120px">
|
||||
<p:tag value="#{cotisation.typeCotisationLibelle}" severity="info" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Dû" sortBy="#{cotisation.montantDu}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantDuFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Payé" sortBy="#{cotisation.montantPaye}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantPayeFormatte}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{cotisation.statut}" style="width:150px">
|
||||
<p:tag value="#{cotisation.statutLibelle}"
|
||||
severity="#{cotisation.statutSeverity}"
|
||||
icon="#{cotisation.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Paiement" sortBy="#{cotisation.datePaiement}" style="width:150px">
|
||||
<h:outputText value="#{cotisation.datePaiementFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Méthode" style="width:120px">
|
||||
<h:outputText value="#{cotisation.methodePaiementLibelle}" rendered="#{cotisation.methodePaiement != null}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:100px">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir les détails"
|
||||
styleClass="p-button-rounded p-button-text p-button-info"
|
||||
action="#{cotisationsBean.selectionnerCotisation(cotisation)}"
|
||||
update=":formDetailsCotisation"
|
||||
oncomplete="PF('dlgDetailsCotisation').show();" />
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Détails Cotisation -->
|
||||
<p:dialog header="Détails de la Cotisation" widgetVar="dlgDetailsCotisation" modal="true" width="600" resizable="false">
|
||||
<h:form id="formDetailsCotisation">
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Référence</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.numeroReference}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Statut</label>
|
||||
<p:tag value="#{cotisationsBean.cotisationSelectionnee.statutLibelle}"
|
||||
severity="#{cotisationsBean.cotisationSelectionnee.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-medium">Membre</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">N° #{cotisationsBean.cotisationSelectionnee.numeroMembre}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Type</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.typeCotisationLibelle}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date d'échéance</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.dateEcheanceFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant dû</label>
|
||||
<p class="text-600 font-bold">#{cotisationsBean.cotisationSelectionnee.montantDuFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant payé</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.montantPayeFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<label class="font-medium">Montant restant</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.montantRestantFormatte}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Date de paiement</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.datePaiementFormatee}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-medium">Méthode de paiement</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.methodePaiementLibelle}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12" rendered="#{cotisationsBean.cotisationSelectionnee.observations != null}">
|
||||
<div class="field">
|
||||
<label class="font-medium">Observations</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.observations}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,21 +1,306 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Paiement Cotisation - UnionFlow</ui:define>
|
||||
<ui:define name="title">Paiement de Cotisations - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-credit-card text-green-500" />
|
||||
<ui:param name="title" value="Paiement de Cotisations" />
|
||||
<ui:param name="description" value="Enregistrement et suivi des paiements de cotisations" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsPaiement">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{cotisationsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques de paiement -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.totalCollecteFormatte}" />
|
||||
<ui:param name="label" value="Total Collecté" />
|
||||
<ui:param name="icon" value="pi pi-wallet" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.moyenneMensuelleFormattee}" />
|
||||
<ui:param name="label" value="Moyenne Mensuelle" />
|
||||
<ui:param name="icon" value="pi pi-chart-line" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.objectifAnnuelFormatte}" />
|
||||
<ui:param name="label" value="Objectif Annuel" />
|
||||
<ui:param name="icon" value="pi pi-target" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.tauxRecouvrementInt}%" />
|
||||
<ui:param name="label" value="Taux de Recouvrement" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Répartition par méthode de paiement -->
|
||||
<div class="card">
|
||||
<h5>Paiement de Cotisation</h5>
|
||||
<p>Interface de paiement des cotisations membres.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-credit-card" style="font-size: 3rem; color: #28a745;"></i>
|
||||
<p class="mt-3">Fonctionnalité de paiement en développement</p>
|
||||
<h5>
|
||||
<i class="pi pi-chart-pie mr-2"></i>
|
||||
Répartition par Méthode de Paiement
|
||||
</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="flex flex-column gap-3">
|
||||
<ui:repeat value="#{cotisationsBean.repartitionMethodes}" var="methode">
|
||||
<div class="flex align-items-center justify-content-between p-3 border-round surface-50">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="border-round text-white text-center"
|
||||
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem; background: var(--#{methode.couleur});">
|
||||
<i class="#{methode.icon}"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-medium">#{methode.methode}</div>
|
||||
<div class="text-600 text-sm">#{methode.montantFormatte}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="font-bold text-xl">#{methode.pourcentageInt}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="flex flex-column gap-2">
|
||||
<ui:repeat value="#{cotisationsBean.repartitionMethodes}" var="methode">
|
||||
<div>
|
||||
<div class="flex justify-content-between mb-1">
|
||||
<span class="font-medium">#{methode.methode}</span>
|
||||
<span class="text-600">#{methode.pourcentageInt}%</span>
|
||||
</div>
|
||||
<p:progressBar value="#{methode.pourcentageInt}"
|
||||
showValue="false"
|
||||
styleClass="progressbar-custom" />
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
<!-- Cotisations en attente de paiement -->
|
||||
<div class="card">
|
||||
<h:form id="formPaiements">
|
||||
<h5>Cotisations en Attente de Paiement</h5>
|
||||
|
||||
<p:dataTable id="dtPaiements"
|
||||
value="#{cotisationsBean.cotisationsFiltrees}"
|
||||
var="cotisation"
|
||||
filteredValue="#{cotisationsBean.cotisationsFiltrees}"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
emptyMessage="Aucune cotisation en attente"
|
||||
selection="#{cotisationsBean.cotisationSelectionnee}"
|
||||
selectionMode="single">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Cotisations à payer</span>
|
||||
<p:selectOneMenu value="#{cotisationsBean.filtres.statut}" styleClass="w-12rem">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="EN_ATTENTE" />
|
||||
<f:selectItem itemLabel="Partiellement payée" itemValue="PARTIELLEMENT_PAYEE" />
|
||||
<f:selectItem itemLabel="En retard" itemValue="EN_RETARD" />
|
||||
<p:ajax update="dtPaiements" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{cotisation.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{cotisation.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{cotisation.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type" sortBy="#{cotisation.typeCotisation}" style="width:120px">
|
||||
<p:tag value="#{cotisation.typeCotisationLibelle}" severity="info" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Dû" sortBy="#{cotisation.montantDu}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantDuFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Payé" sortBy="#{cotisation.montantPaye}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantPayeFormatte}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Restant" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantRestantFormatte}"
|
||||
styleClass="#{cotisation.montantRestant.compareTo(java.math.BigDecimal.ZERO) > 0 ? 'text-orange-500 font-bold' : 'text-green-500'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Échéance" sortBy="#{cotisation.dateEcheance}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.dateEcheanceFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:200px">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton value="Payer"
|
||||
icon="pi pi-check"
|
||||
styleClass="p-button-success p-button-sm"
|
||||
action="#{cotisationsBean.selectionnerCotisation(cotisation)}"
|
||||
update=":formPaiement"
|
||||
oncomplete="PF('dlgPaiement').show();" />
|
||||
<p:commandButton value="Partiel"
|
||||
icon="pi pi-minus"
|
||||
styleClass="p-button-info p-button-sm"
|
||||
action="#{cotisationsBean.selectionnerCotisation(cotisation)}"
|
||||
update=":formPaiementPartiel"
|
||||
oncomplete="PF('dlgPaiementPartiel').show();" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Paiement Complet -->
|
||||
<p:dialog header="Enregistrer un Paiement" widgetVar="dlgPaiement" modal="true" width="500" resizable="false">
|
||||
<h:form id="formPaiement">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Cotisation</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.numeroReference} - #{cotisationsBean.cotisationSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Montant dû: #{cotisationsBean.cotisationSelectionnee.montantDuFormatte}</p>
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="methodePaiement" />
|
||||
<ui:param name="label" value="Méthode de paiement" />
|
||||
<ui:param name="value" value="#{cotisationsBean.cotisationSelectionnee.methodePaiement}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Wave Money" itemValue="WAVE_MONEY" />
|
||||
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
|
||||
<f:selectItem itemLabel="Virement bancaire" itemValue="VIREMENT" />
|
||||
<f:selectItem itemLabel="Chèque" itemValue="CHEQUE" />
|
||||
<f:selectItem itemLabel="Orange Money" itemValue="ORANGE_MONEY" />
|
||||
<f:selectItem itemLabel="Free Money" itemValue="FREE_MONEY" />
|
||||
<f:selectItem itemLabel="Carte bancaire" itemValue="CARTE_BANCAIRE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="referencePaiement" />
|
||||
<ui:param name="label" value="Référence de paiement" />
|
||||
<ui:param name="value" value="#{cotisationsBean.cotisationSelectionnee.referencePaiement}" />
|
||||
<ui:param name="placeholder" value="Ex: WAVE-123456789" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="observationsPaiement" />
|
||||
<ui:param name="label" value="Observations" />
|
||||
<ui:param name="value" value="#{cotisationsBean.cotisationSelectionnee.observations}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgPaiement').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{cotisationsBean.marquerCommePaye}" />
|
||||
<ui:param name="update" value="@form :formPaiements" />
|
||||
<ui:param name="oncomplete" value="PF('dlgPaiement').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Paiement Partiel -->
|
||||
<p:dialog header="Enregistrer un Paiement Partiel" widgetVar="dlgPaiementPartiel" modal="true" width="500" resizable="false">
|
||||
<h:form id="formPaiementPartiel">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<label class="font-medium">Cotisation</label>
|
||||
<p class="text-600">#{cotisationsBean.cotisationSelectionnee.numeroReference} - #{cotisationsBean.cotisationSelectionnee.nomMembre}</p>
|
||||
<p class="text-500 text-sm">Montant dû: #{cotisationsBean.cotisationSelectionnee.montantDuFormatte}</p>
|
||||
<p class="text-500 text-sm">Montant restant: #{cotisationsBean.cotisationSelectionnee.montantRestantFormatte}</p>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="montantPaye" value="Montant à payer (FCFA)" />
|
||||
<p:inputNumber id="montantPaye"
|
||||
value="#{cotisationsBean.cotisationSelectionnee.montantPaye}"
|
||||
symbol=""
|
||||
minValue="0"
|
||||
maxValue="#{cotisationsBean.cotisationSelectionnee.montantDu}"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="methodePaiementPartiel" />
|
||||
<ui:param name="label" value="Méthode de paiement" />
|
||||
<ui:param name="value" value="#{cotisationsBean.cotisationSelectionnee.methodePaiement}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Wave Money" itemValue="WAVE_MONEY" />
|
||||
<f:selectItem itemLabel="Espèces" itemValue="ESPECES" />
|
||||
<f:selectItem itemLabel="Virement bancaire" itemValue="VIREMENT" />
|
||||
<f:selectItem itemLabel="Chèque" itemValue="CHEQUE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="referencePaiementPartiel" />
|
||||
<ui:param name="label" value="Référence de paiement" />
|
||||
<ui:param name="value" value="#{cotisationsBean.cotisationSelectionnee.referencePaiement}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgPaiementPartiel').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{cotisationsBean.enregistrerPaiementPartiel(cotisationsBean.cotisationSelectionnee.montantPaye, cotisationsBean.cotisationSelectionnee.methodePaiement, cotisationsBean.cotisationSelectionnee.referencePaiement)}" />
|
||||
<ui:param name="update" value="@form :formPaiements" />
|
||||
<ui:param name="oncomplete" value="PF('dlgPaiementPartiel').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,21 +1,184 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Rapports Financiers - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-chart-bar text-purple-500" />
|
||||
<ui:param name="title" value="Rapports Financiers" />
|
||||
<ui:param name="description" value="Analyse et rapports détaillés sur les cotisations et paiements" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsRapports">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Générer rapport" />
|
||||
<ui:param name="icon" value="pi pi-file-pdf" />
|
||||
<ui:param name="action" value="#{cotisationsBean.genererRapportFinancier}" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{cotisationsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Vue d'ensemble -->
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-8">
|
||||
<div class="card">
|
||||
<h5>
|
||||
<i class="pi pi-chart-line mr-2"></i>
|
||||
Évolution des Paiements (12 derniers mois)
|
||||
</h5>
|
||||
<div class="flex flex-column gap-2 mt-3">
|
||||
<ui:repeat value="#{cotisationsBean.evolutionPaiements}" var="evolution">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="text-600" style="width: 60px;">#{evolution.mois}</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="bg-blue-500 border-round"
|
||||
style="width: #{evolution.hauteur}px; height: 20px; min-width: 10px;"></div>
|
||||
<span class="text-600 text-sm">#{evolution.montantFormatte}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="card">
|
||||
<h5>
|
||||
<i class="pi pi-chart-pie mr-2"></i>
|
||||
Répartition par Méthode
|
||||
</h5>
|
||||
<div class="flex flex-column gap-3 mt-3">
|
||||
<ui:repeat value="#{cotisationsBean.repartitionMethodes}" var="methode">
|
||||
<div>
|
||||
<div class="flex justify-content-between mb-1">
|
||||
<span class="font-medium">#{methode.methode}</span>
|
||||
<span class="text-600">#{methode.pourcentageInt}%</span>
|
||||
</div>
|
||||
<p:progressBar value="#{methode.pourcentageInt}"
|
||||
showValue="false" />
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
<!-- Statistiques détaillées -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.totalCollecteFormatte}" />
|
||||
<ui:param name="label" value="Total Collecté" />
|
||||
<ui:param name="icon" value="pi pi-wallet" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.objectifAnnuelFormatte}" />
|
||||
<ui:param name="label" value="Objectif Annuel" />
|
||||
<ui:param name="icon" value="pi pi-target" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.moyenneMensuelleFormattee}" />
|
||||
<ui:param name="label" value="Moyenne Mensuelle" />
|
||||
<ui:param name="icon" value="pi pi-chart-line" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.tauxRecouvrementInt}%" />
|
||||
<ui:param name="label" value="Taux de Recouvrement" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Résumé des cotisations -->
|
||||
<div class="card">
|
||||
<h5>
|
||||
<i class="pi pi-list mr-2"></i>
|
||||
Résumé des Cotisations
|
||||
</h5>
|
||||
|
||||
<div class="grid mt-3">
|
||||
<div class="col-12 md:col-6">
|
||||
<h6 class="mb-3">Par Statut</h6>
|
||||
<div class="flex flex-column gap-2">
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Payées</span>
|
||||
<p:tag value="#{cotisationsBean.compterParStatut('PAYEE')}"
|
||||
severity="success" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Partiellement payées</span>
|
||||
<p:tag value="#{cotisationsBean.compterParStatut('PARTIELLEMENT_PAYEE')}"
|
||||
severity="info" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">En attente</span>
|
||||
<p:tag value="#{cotisationsBean.compterParStatut('EN_ATTENTE')}"
|
||||
severity="warning" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">En retard</span>
|
||||
<p:tag value="#{cotisationsBean.compterParStatut('EN_RETARD')}"
|
||||
severity="danger" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<h6 class="mb-3">Par Type</h6>
|
||||
<div class="flex flex-column gap-2">
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Mensuelle</span>
|
||||
<p:tag value="#{cotisationsBean.compterParType('MENSUELLE')}" severity="info" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Trimestrielle</span>
|
||||
<p:tag value="#{cotisationsBean.compterParType('TRIMESTRIELLE')}" severity="info" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Semestrielle</span>
|
||||
<p:tag value="#{cotisationsBean.compterParType('SEMESTRIELLE')}" severity="info" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Annuelle</span>
|
||||
<p:tag value="#{cotisationsBean.compterParType('ANNUELLE')}" severity="info" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Adhésion</span>
|
||||
<p:tag value="#{cotisationsBean.compterParType('ADHESION')}" severity="info" />
|
||||
</div>
|
||||
<div class="flex justify-content-between align-items-center p-2 border-round surface-50">
|
||||
<span class="font-medium">Exceptionnelle</span>
|
||||
<p:tag value="#{cotisationsBean.compterParType('EXCEPTIONNELLE')}" severity="info" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,21 +1,228 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Relances de Cotisations - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-send text-orange-500" />
|
||||
<ui:param name="title" value="Relances de Cotisations" />
|
||||
<ui:param name="description" value="Gestion et envoi des relances pour les cotisations en retard" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsRelances">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Relances groupées" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="onclick" value="PF('dlgRelancesGroupes').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{cotisationsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques de relances -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.cotisationsEnRetard}" />
|
||||
<ui:param name="label" value="Cotisations en Retard" />
|
||||
<ui:param name="icon" value="pi pi-exclamation-triangle" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.montantRetardFormatte}" />
|
||||
<ui:param name="label" value="Montant en Retard" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="red" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.rappelsEnAttente.size()}" />
|
||||
<ui:param name="label" value="Rappels en Attente" />
|
||||
<ui:param name="icon" value="pi pi-bell" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{cotisationsBean.statistiques.tauxRecouvrementInt}%" />
|
||||
<ui:param name="label" value="Taux de Recouvrement" />
|
||||
<ui:param name="icon" value="pi pi-percentage" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Liste des rappels en attente -->
|
||||
<div class="card">
|
||||
<h5>
|
||||
<i class="pi pi-bell mr-2"></i>
|
||||
Rappels en Attente
|
||||
</h5>
|
||||
|
||||
<p:dataTable id="dtRappels"
|
||||
value="#{cotisationsBean.rappelsEnAttente}"
|
||||
var="rappel"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
emptyMessage="Aucun rappel en attente">
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{rappel.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{rappel.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{rappel.club}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Dû" sortBy="#{rappel.montantDu}" style="width:120px">
|
||||
<h:outputText value="#{rappel.montantDuFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Jours de Retard" sortBy="#{rappel.joursRetard}" style="width:120px">
|
||||
<h:outputText value="#{rappel.joursRetard} jour(s)" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Priorité" sortBy="#{rappel.priorite}" style="width:120px">
|
||||
<p:tag value="#{rappel.priorite}"
|
||||
severity="#{rappel.prioriteSeverity}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:150px">
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Envoyer" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{cotisationsBean.envoyerRappel}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="styleClass" value="p-button-sm" />
|
||||
</ui:include>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
|
||||
<!-- Cotisations en retard -->
|
||||
<div class="card">
|
||||
<h:form id="formRelances">
|
||||
<h5>Cotisations en Retard</h5>
|
||||
|
||||
<p:dataTable id="dtRetard"
|
||||
value="#{cotisationsBean.cotisationsFiltrees}"
|
||||
var="cotisation"
|
||||
filteredValue="#{cotisationsBean.cotisationsFiltrees}"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
emptyMessage="Aucune cotisation en retard"
|
||||
selection="#{cotisationsBean.cotisationsSelectionnees}"
|
||||
selectionMode="multiple">
|
||||
|
||||
<f:facet name="header">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Cotisations nécessitant une relance</span>
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Relancer sélectionnées" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{cotisationsBean.envoyerRappelsGroupes}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="disabled" value="#{empty cotisationsBean.cotisationsSelectionnees}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</f:facet>
|
||||
|
||||
<p:column selectionMode="multiple" style="width:50px" />
|
||||
|
||||
<p:column headerText="Membre" sortBy="#{cotisation.nomMembre}">
|
||||
<div>
|
||||
<div class="font-medium">#{cotisation.nomMembre}</div>
|
||||
<div class="text-600 text-sm">#{cotisation.numeroMembre}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type" sortBy="#{cotisation.typeCotisation}" style="width:120px">
|
||||
<p:tag value="#{cotisation.typeCotisationLibelle}" severity="info" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant Dû" sortBy="#{cotisation.montantDu}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.montantDuFormatte}" styleClass="font-bold" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Échéance" sortBy="#{cotisation.dateEcheance}" style="width:120px">
|
||||
<h:outputText value="#{cotisation.dateEcheanceFormatee}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Jours Retard" style="width:120px">
|
||||
<h:outputText value="#{cotisation.joursRetard} jour(s)"
|
||||
styleClass="#{cotisation.joursRetard > 30 ? 'text-red-500 font-bold' : cotisation.joursRetard > 15 ? 'text-orange-500' : 'text-yellow-500'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width:150px">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-send"
|
||||
title="Envoyer un rappel"
|
||||
styleClass="p-button-rounded p-button-text p-button-warning"
|
||||
action="#{cotisationsBean.envoyerRappel(cotisation)}"
|
||||
update="@form" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Relances Groupées -->
|
||||
<p:dialog header="Relances Groupées" widgetVar="dlgRelancesGroupes" modal="true" width="500" resizable="false">
|
||||
<h:form id="formRelancesGroupes">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<p:outputLabel for="messageRelance" value="Message de relance" />
|
||||
<p:inputTextarea id="messageRelance"
|
||||
rows="5"
|
||||
styleClass="w-full"
|
||||
placeholder="Message personnalisé pour les relances..." />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="relanceUrgente" />
|
||||
<p:outputLabel for="relanceUrgente" value=" Marquer comme urgente" />
|
||||
</div>
|
||||
|
||||
<div class="surface-50 p-3 border-round">
|
||||
<div class="font-medium mb-2">Destinataires :</div>
|
||||
<div class="text-600 text-sm">#{cotisationsBean.cotisationsSelectionnees.size()} cotisation(s) sélectionnée(s)</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<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('dlgRelancesGroupes').hide();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Envoyer les relances" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{cotisationsBean.envoyerRappelsGroupes}" />
|
||||
<ui:param name="update" value="@form :formRelances" />
|
||||
<ui:param name="oncomplete" value="PF('dlgRelancesGroupes').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
@@ -243,47 +243,35 @@
|
||||
</div>
|
||||
|
||||
<h:panelGroup id="tendancesPanel" layout="block">
|
||||
<!-- Simulation graphique avec barres -->
|
||||
<!-- Graphique avec données dynamiques -->
|
||||
<div class="grid">
|
||||
<div class="col-4 text-center">
|
||||
<h6 class="text-600 mb-2">Mai 2024</h6>
|
||||
<div class="flex flex-column align-items-center">
|
||||
<div class="bg-blue-500 border-round mb-2" style="width:20px;height:80px;"></div>
|
||||
<span class="text-sm text-600">2.5M FCFA</span>
|
||||
<ui:repeat value="#{dashboardBean.evolutionFinanciere}" var="mois">
|
||||
<div class="col-4 text-center">
|
||||
<h6 class="text-600 mb-2">#{mois.libelle}</h6>
|
||||
<div class="flex flex-column align-items-center">
|
||||
<div class="bg-blue-500 border-round mb-2" style="width:20px;height:#{mois.hauteur}px;"></div>
|
||||
<span class="text-sm text-600">#{mois.montantFormatte}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 text-center">
|
||||
<h6 class="text-600 mb-2">Juin 2024</h6>
|
||||
<div class="flex flex-column align-items-center">
|
||||
<div class="bg-green-500 border-round mb-2" style="width:20px;height:120px;"></div>
|
||||
<span class="text-sm text-600">3.8M FCFA</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4 text-center">
|
||||
<h6 class="text-600 mb-2">Juillet 2024</h6>
|
||||
<div class="flex flex-column align-items-center">
|
||||
<div class="bg-blue-600 border-round mb-2" style="width:20px;height:100px;"></div>
|
||||
<span class="text-sm text-600">3.2M FCFA</span>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
|
||||
<!-- Indicateurs de tendance -->
|
||||
<!-- Indicateurs de tendance dynamiques -->
|
||||
<div class="grid mt-4">
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="flex align-items-center">
|
||||
<i class="pi pi-arrow-up text-green-500 text-2xl mr-2"></i>
|
||||
<i class="#{dashboardBean.evolutionRecettesIcon} text-2xl mr-2"></i>
|
||||
<div>
|
||||
<div class="text-900 font-medium">+28%</div>
|
||||
<div class="text-900 font-medium">#{dashboardBean.evolutionRecettesPrefix}#{dashboardBean.evolutionRecettesPourcent}%</div>
|
||||
<span class="text-600 text-sm">Recettes vs mois dernier</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="flex align-items-center">
|
||||
<i class="pi pi-arrow-down text-red-500 text-2xl mr-2"></i>
|
||||
<i class="#{dashboardBean.evolutionDepensesIcon} text-2xl mr-2"></i>
|
||||
<div>
|
||||
<div class="text-900 font-medium">-12%</div>
|
||||
<div class="text-900 font-medium">#{dashboardBean.evolutionDepensesPrefix}#{dashboardBean.evolutionDepensesPourcent}%</div>
|
||||
<span class="text-600 text-sm">Dépenses vs mois dernier</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -292,7 +280,7 @@
|
||||
<div class="flex align-items-center">
|
||||
<i class="pi pi-minus text-blue-500 text-2xl mr-2"></i>
|
||||
<div>
|
||||
<div class="text-900 font-medium">Stable</div>
|
||||
<div class="text-900 font-medium">#{dashboardBean.tendanceParticipation}</div>
|
||||
<span class="text-600 text-sm">Taux de participation</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -306,61 +294,60 @@
|
||||
<div class="card">
|
||||
<h5>État des cotisations</h5>
|
||||
|
||||
<!-- Simulation graphique circulaire avec CSS -->
|
||||
<!-- Graphique circulaire dynamique -->
|
||||
<div class="text-center mb-4">
|
||||
<div class="relative inline-block">
|
||||
<div class="w-8rem h-8rem border-circle border-8 border-blue-200 mx-auto mb-3 relative">
|
||||
<div class="absolute" style="top: 10px; left: 10px; width: calc(100% - 20px); height: calc(100% - 20px); border-radius: 50%; background: conic-gradient(#3b82f6 0deg 216deg, #f97316 216deg 288deg, #ef4444 288deg 360deg);"></div>
|
||||
<div class="absolute top-50 left-50 bg-white border-circle flex align-items-center justify-content-center" style="width: 60px; height: 60px; margin-top: -30px; margin-left: -30px;">
|
||||
<span class="text-900 font-bold">85%</span>
|
||||
<span class="text-900 font-bold">#{dashboardBean.cotisationsAJourPourcent}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Légende avec indicateurs visuels -->
|
||||
<!-- Légende avec données dynamiques -->
|
||||
<div class="mt-3">
|
||||
<div class="flex align-items-center justify-content-between py-2">
|
||||
<div class="flex align-items-center">
|
||||
<div class="w-1rem h-1rem bg-blue-500 border-round mr-2"></div>
|
||||
<span class="text-600">À jour</span>
|
||||
</div>
|
||||
<span class="text-900 font-medium">60%</span>
|
||||
<span class="text-900 font-medium">#{dashboardBean.cotisationsAJourPourcent}%</span>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between py-2">
|
||||
<div class="flex align-items-center">
|
||||
<div class="w-1rem h-1rem bg-orange-500 border-round mr-2"></div>
|
||||
<span class="text-600">En retard</span>
|
||||
</div>
|
||||
<span class="text-900 font-medium">20%</span>
|
||||
<span class="text-900 font-medium">#{dashboardBean.cotisationsRetardPourcent}%</span>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between py-2">
|
||||
<div class="flex align-items-center">
|
||||
<div class="w-1rem h-1rem bg-red-500 border-round mr-2"></div>
|
||||
<span class="text-600">Impayées</span>
|
||||
</div>
|
||||
<span class="text-900 font-medium">20%</span>
|
||||
<span class="text-900 font-medium">#{dashboardBean.cotisationsImpayeesPourcent}%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Barres de progression détaillées -->
|
||||
<!-- Barres de progression dynamiques -->
|
||||
<div class="mt-4">
|
||||
<div class="mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-600">Taux de collecte</span>
|
||||
<span class="text-900 font-medium">75%</span>
|
||||
<span class="text-900 font-medium">#{dashboardBean.tauxCollecte}%</span>
|
||||
</div>
|
||||
<div class="bg-gray-200 border-round overflow-hidden" style="height: 8px;">
|
||||
<div class="bg-green-500 h-full border-round" style="width: 75%;"></div>
|
||||
<div class="bg-green-500 h-full border-round" style="width: #{dashboardBean.tauxCollecte}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-600">Objectif mensuel</span>
|
||||
<span class="text-900 font-medium">82%</span>
|
||||
<span class="text-900 font-medium">#{dashboardBean.tauxObjectifCotisations}%</span>
|
||||
</div>
|
||||
<div class="bg-gray-200 border-round overflow-hidden" style="height: 8px;">
|
||||
<div class="bg-blue-500 h-full border-round" style="width: 82%;"></div>
|
||||
<div class="bg-blue-500 h-full border-round" style="width: #{dashboardBean.tauxObjectifCotisations}%;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,182 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Calendrier des Événements - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-calendar-plus text-blue-500" />
|
||||
<ui:param name="title" value="Calendrier des Événements" />
|
||||
<ui:param name="description" value="Vue calendrier de tous les événements de l'organisation" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsCalendrier">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouvel événement" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="outcome" value="/pages/secure/evenement/creation.xhtml" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{evenementsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Calendrier -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
</div>
|
||||
<h:form id="formCalendrier">
|
||||
<h5>Calendrier</h5>
|
||||
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-calendar text-4xl text-blue-500 mb-3"></i>
|
||||
<h5>Calendrier des Événements</h5>
|
||||
<p class="text-600">La vue calendrier interactive sera disponible prochainement</p>
|
||||
<p class="text-600 mt-2">En attendant, utilisez la liste des événements à venir ci-dessous</p>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Liste des événements à venir -->
|
||||
<div class="card">
|
||||
<h:form id="formListeProchains">
|
||||
<h5>Événements à Venir</h5>
|
||||
|
||||
<p:dataTable id="dtProchains"
|
||||
value="#{evenementsBean.evenementsProchains}"
|
||||
var="evenement"
|
||||
paginator="false"
|
||||
emptyMessage="Aucun événement à venir"
|
||||
rowKey="#{evenement.id}">
|
||||
|
||||
<p:column headerText="Date">
|
||||
<div>
|
||||
<div class="font-medium">#{evenement.dateDebutFormatee}</div>
|
||||
<div class="text-sm text-600">#{evenement.heureDebutFormatee} - #{evenement.heureFinFormatee}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Événement">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{evenement.typeEvenementIcon} text-#{evenement.typeEvenementSeverity}"></i>
|
||||
<div>
|
||||
<div class="font-semibold">#{evenement.titre}</div>
|
||||
<div class="text-sm text-600">#{evenement.lieu}</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut">
|
||||
<p:tag value="#{evenement.statutLibelle}"
|
||||
severity="#{evenement.statutSeverity}"
|
||||
icon="#{evenement.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Participants">
|
||||
<div>#{evenement.participantsInscrits} / #{evenement.capaciteMax}</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir détails"
|
||||
styleClass="p-button-text p-button-rounded"
|
||||
action="#{evenementsBean.selectionnerEvenement(evenement)}"
|
||||
update=":formCalendrier:dlgDetails"
|
||||
oncomplete="PF('dlgDetails').show();" />
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Détails -->
|
||||
<h:form id="formDetails">
|
||||
<p:dialog id="dlgDetails" header="Détails de l'Événement"
|
||||
widgetVar="dlgDetails"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 700px;">
|
||||
<div class="grid" rendered="#{evenementsBean.evenementSelectionne != null}">
|
||||
<div class="col-12">
|
||||
<h4>#{evenementsBean.evenementSelectionne.titre}</h4>
|
||||
<p class="text-600">#{evenementsBean.evenementSelectionne.description}</p>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Type</label>
|
||||
<p:tag value="#{evenementsBean.evenementSelectionne.typeEvenementLibelle}"
|
||||
severity="#{evenementsBean.evenementSelectionne.typeEvenementSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Statut</label>
|
||||
<p:tag value="#{evenementsBean.evenementSelectionne.statutLibelle}"
|
||||
severity="#{evenementsBean.evenementSelectionne.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Date de début</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.dateDebutFormatee}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.heureDebutFormatee}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Lieu</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.lieu}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.adresseComplete}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Participants</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.participantsInscrits} / #{evenementsBean.evenementSelectionne.capaciteMax}</div>
|
||||
<p:progressBar value="#{evenementsBean.evenementSelectionne.tauxRemplissage}"
|
||||
showValue="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Budget</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.budgetFormate}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Voir détails"
|
||||
icon="pi pi-eye"
|
||||
outcome="/pages/secure/evenement/gestion.xhtml"
|
||||
styleClass="p-button-outlined" />
|
||||
<p:commandButton value="Fermer"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgDetails').hide();"
|
||||
styleClass="p-button-secondary p-button-outlined" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,20 +1,266 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Création d'Événement - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-plus-circle text-green-500" />
|
||||
<ui:param name="title" value="Créer un Nouvel Événement" />
|
||||
<ui:param name="description" value="Remplissez le formulaire pour créer un nouvel événement" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsCreation">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Retour" />
|
||||
<ui:param name="icon" value="pi pi-arrow-left" />
|
||||
<ui:param name="outcome" value="/pages/secure/evenement/gestion.xhtml" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Formulaire de création -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
</div>
|
||||
<h:form id="formCreation">
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Informations Générales</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="titre" />
|
||||
<ui:param name="label" value="Titre de l'événement *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.titre}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Ex: Assemblée Générale Annuelle 2025" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="description" />
|
||||
<ui:param name="label" value="Description" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.description}" />
|
||||
<ui:param name="rows" value="4" />
|
||||
<ui:param name="placeholder" value="Description détaillée de l'événement..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="typeEvenement" />
|
||||
<ui:param name="label" value="Type d'événement *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.typeEvenement}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="items">
|
||||
<f:selectItem itemLabel="Sélectionner un type" itemValue="" />
|
||||
<f:selectItem itemLabel="Assemblée Générale" itemValue="ASSEMBLEE_GENERALE" />
|
||||
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
|
||||
<f:selectItem itemLabel="Activité Sociale" itemValue="ACTIVITE_SOCIALE" />
|
||||
<f:selectItem itemLabel="Action Caritative" itemValue="ACTION_CARITATIVE" />
|
||||
<f:selectItem itemLabel="Réunion de Bureau" itemValue="REUNION_BUREAU" />
|
||||
<f:selectItem itemLabel="Conférence" itemValue="CONFERENCE" />
|
||||
<f:selectItem itemLabel="Atelier" itemValue="ATELIER" />
|
||||
<f:selectItem itemLabel="Cérémonie" itemValue="CEREMONIE" />
|
||||
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
|
||||
</ui:param>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="priorite" />
|
||||
<ui:param name="label" value="Priorité" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.priorite}" />
|
||||
<ui:param name="items">
|
||||
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
|
||||
<f:selectItem itemLabel="Haute" itemValue="HAUTE" />
|
||||
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
|
||||
<f:selectItem itemLabel="Basse" itemValue="BASSE" />
|
||||
</ui:param>
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Dates et Horaires</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebut" />
|
||||
<ui:param name="label" value="Date de début *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.dateDebut}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateFin" />
|
||||
<ui:param name="label" value="Date de fin" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.dateFin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="heureDebut" value="Heure de début" />
|
||||
<p:inputMask id="heureDebut"
|
||||
value="#{evenementsBean.nouvelEvenement.heureDebut}"
|
||||
mask="99:99"
|
||||
placeholder="HH:mm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="heureFin" value="Heure de fin" />
|
||||
<p:inputMask id="heureFin"
|
||||
value="#{evenementsBean.nouvelEvenement.heureFin}"
|
||||
mask="99:99"
|
||||
placeholder="HH:mm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Localisation</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="lieu" />
|
||||
<ui:param name="label" value="Lieu *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.lieu}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Ex: Salle de conférence" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="adresse" />
|
||||
<ui:param name="label" value="Adresse" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.adresse}" />
|
||||
<ui:param name="placeholder" value="Adresse complète" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="ville" />
|
||||
<ui:param name="label" value="Ville" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.ville}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="region" />
|
||||
<ui:param name="label" value="Région" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.region}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Organisation et Participants</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="organisateur" />
|
||||
<ui:param name="label" value="Organisateur" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.organisateur}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="capaciteMax" />
|
||||
<ui:param name="label" value="Capacité maximale" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.capaciteMax}" />
|
||||
<ui:param name="min" value="1" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateLimiteInscription" />
|
||||
<ui:param name="label" value="Date limite d'inscription" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.dateLimiteInscription}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-boolean.xhtml">
|
||||
<ui:param name="id" value="inscriptionObligatoire" />
|
||||
<ui:param name="label" value="Inscription obligatoire" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.inscriptionObligatoire}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="title">Budget</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="budget" />
|
||||
<ui:param name="label" value="Budget prévu" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.budget}" />
|
||||
<ui:param name="min" value="0" />
|
||||
<ui:param name="suffix" value=" FCFA" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="codeDevise" />
|
||||
<ui:param name="label" value="Devise" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.codeDevise}" />
|
||||
<ui:param name="placeholder" value="XOF" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<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="outcome" value="/pages/secure/evenement/gestion.xhtml" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Créer l'événement" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{evenementsBean.creerEvenement}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
|
||||
@@ -1,21 +1,493 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Gestion des Événements - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
</div>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-calendar text-blue-500" />
|
||||
<ui:param name="title" value="Gestion des Événements" />
|
||||
<ui:param name="description" value="Création, suivi et gestion des événements de l'organisation" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsEvenements">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouvel événement" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="onclick" value="PF('dlgNouvelEvenement').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{evenementsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{evenementsBean.statistiques.totalEvenements}" />
|
||||
<ui:param name="label" value="Total Événements" />
|
||||
<ui:param name="icon" value="pi pi-calendar" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{evenementsBean.statistiques.evenementsActifs}" />
|
||||
<ui:param name="label" value="Événements Actifs" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{evenementsBean.statistiques.participantsTotal}" />
|
||||
<ui:param name="label" value="Total Participants" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{evenementsBean.statistiques.budgetTotal}" />
|
||||
<ui:param name="label" value="Budget Total" />
|
||||
<ui:param name="icon" value="pi pi-wallet" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Liste des événements -->
|
||||
<div class="card">
|
||||
<h:form id="formEvenements">
|
||||
<h5>Liste des Événements</h5>
|
||||
|
||||
<!-- Filtres -->
|
||||
<p:toolbar>
|
||||
<p:toolbarGroup>
|
||||
<div class="flex align-items-center gap-2 flex-wrap">
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="searchTitre" />
|
||||
<ui:param name="value" value="#{evenementsBean.filtres.titre}" />
|
||||
<ui:param name="placeholder" value="Rechercher par titre..." />
|
||||
<ui:param name="update" value="dtEvenements" />
|
||||
</ui:include>
|
||||
|
||||
<p:selectOneMenu value="#{evenementsBean.filtres.type}" styleClass="w-full" style="min-width: 200px;">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Assemblée Générale" itemValue="ASSEMBLEE_GENERALE" />
|
||||
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
|
||||
<f:selectItem itemLabel="Activité Sociale" itemValue="ACTIVITE_SOCIALE" />
|
||||
<f:selectItem itemLabel="Action Caritative" itemValue="ACTION_CARITATIVE" />
|
||||
<f:selectItem itemLabel="Réunion de Bureau" itemValue="REUNION_BUREAU" />
|
||||
<f:selectItem itemLabel="Conférence" itemValue="CONFERENCE" />
|
||||
<f:selectItem itemLabel="Atelier" itemValue="ATELIER" />
|
||||
<f:selectItem itemLabel="Cérémonie" itemValue="CEREMONIE" />
|
||||
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
|
||||
<p:ajax event="change" update="dtEvenements" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:selectOneMenu value="#{evenementsBean.filtres.statut}" styleClass="w-full" style="min-width: 200px;">
|
||||
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="Planifié" itemValue="PLANIFIE" />
|
||||
<f:selectItem itemLabel="Confirmé" itemValue="CONFIRME" />
|
||||
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
|
||||
<f:selectItem itemLabel="Terminé" itemValue="TERMINE" />
|
||||
<f:selectItem itemLabel="Annulé" itemValue="ANNULE" />
|
||||
<f:selectItem itemLabel="Reporté" itemValue="REPORTE" />
|
||||
<p:ajax event="change" update="dtEvenements" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:selectOneMenu value="#{evenementsBean.filtres.priorite}" styleClass="w-full" style="min-width: 150px;">
|
||||
<f:selectItem itemLabel="Toutes les priorités" itemValue="" />
|
||||
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
|
||||
<f:selectItem itemLabel="Haute" itemValue="HAUTE" />
|
||||
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
|
||||
<f:selectItem itemLabel="Basse" itemValue="BASSE" />
|
||||
<p:ajax event="change" update="dtEvenements" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:commandButton value="Réinitialiser" icon="pi pi-filter-slash"
|
||||
action="#{evenementsBean.reinitialiserFiltres}"
|
||||
update="dtEvenements, formEvenements"
|
||||
styleClass="p-button-outlined" />
|
||||
</div>
|
||||
</p:toolbarGroup>
|
||||
</p:toolbar>
|
||||
|
||||
<!-- Tableau des événements -->
|
||||
<p:dataTable id="dtEvenements"
|
||||
value="#{evenementsBean.evenementsFiltres}"
|
||||
var="evenement"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
emptyMessage="Aucun événement trouvé"
|
||||
selection="#{evenementsBean.evenementSelectionne}"
|
||||
selectionMode="single"
|
||||
rowKey="#{evenement.id}">
|
||||
|
||||
<p:column headerText="Titre" sortBy="#{evenement.titre}" filterBy="#{evenement.titre}">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{evenement.typeEvenementIcon} text-#{evenement.typeEvenementSeverity}"></i>
|
||||
<span class="font-semibold">#{evenement.titre}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type" sortBy="#{evenement.typeEvenement}">
|
||||
<p:tag value="#{evenement.typeEvenementLibelle}"
|
||||
severity="#{evenement.typeEvenementSeverity}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date" sortBy="#{evenement.dateDebut}">
|
||||
<div>
|
||||
<div class="font-medium">#{evenement.dateDebutFormatee}</div>
|
||||
<div class="text-sm text-600">#{evenement.heureDebutFormatee} - #{evenement.heureFinFormatee}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Lieu">
|
||||
<div>
|
||||
<div class="font-medium">#{evenement.lieu}</div>
|
||||
<div class="text-sm text-600">#{evenement.ville}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{evenement.statut}">
|
||||
<p:tag value="#{evenement.statutLibelle}"
|
||||
severity="#{evenement.statutSeverity}"
|
||||
icon="#{evenement.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Priorité" sortBy="#{evenement.priorite}">
|
||||
<p:tag value="#{evenement.prioriteLibelle}"
|
||||
severity="#{evenement.prioriteSeverity}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Participants">
|
||||
<div>
|
||||
<div class="font-medium">#{evenement.participantsInscrits} / #{evenement.capaciteMax}</div>
|
||||
<p:progressBar value="#{evenement.tauxRemplissage}"
|
||||
styleClass="mt-1"
|
||||
showValue="false" />
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width: 200px;">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir détails"
|
||||
styleClass="p-button-text p-button-rounded"
|
||||
action="#{evenementsBean.selectionnerEvenement(evenement)}"
|
||||
update=":formEvenements:dlgDetails"
|
||||
oncomplete="PF('dlgDetails').show();" />
|
||||
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
title="Modifier"
|
||||
styleClass="p-button-text p-button-rounded p-button-success"
|
||||
action="#{evenementsBean.selectionnerEvenement(evenement)}"
|
||||
update=":formEvenements:dlgModifier"
|
||||
oncomplete="PF('dlgModifier').show();" />
|
||||
|
||||
<p:commandButton icon="pi pi-trash"
|
||||
title="Supprimer"
|
||||
styleClass="p-button-text p-button-rounded p-button-danger"
|
||||
action="#{evenementsBean.supprimerEvenement}"
|
||||
update="@form"
|
||||
onclick="return confirm('Êtes-vous sûr de vouloir supprimer cet événement ?');" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Nouvel Événement -->
|
||||
<h:form id="formNouvelEvenement">
|
||||
<p:dialog id="dlgNouvelEvenement" header="Nouvel Événement"
|
||||
widgetVar="dlgNouvelEvenement"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 800px;">
|
||||
<ui:include src="/templates/components/form-section.xhtml">
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="titre" />
|
||||
<ui:param name="label" value="Titre *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.titre}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="description" />
|
||||
<ui:param name="label" value="Description" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.description}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="typeEvenement" />
|
||||
<ui:param name="label" value="Type d'événement *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.typeEvenement}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="items">
|
||||
<f:selectItem itemLabel="Assemblée Générale" itemValue="ASSEMBLEE_GENERALE" />
|
||||
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
|
||||
<f:selectItem itemLabel="Activité Sociale" itemValue="ACTIVITE_SOCIALE" />
|
||||
<f:selectItem itemLabel="Action Caritative" itemValue="ACTION_CARITATIVE" />
|
||||
<f:selectItem itemLabel="Réunion de Bureau" itemValue="REUNION_BUREAU" />
|
||||
<f:selectItem itemLabel="Conférence" itemValue="CONFERENCE" />
|
||||
<f:selectItem itemLabel="Atelier" itemValue="ATELIER" />
|
||||
<f:selectItem itemLabel="Cérémonie" itemValue="CEREMONIE" />
|
||||
<f:selectItem itemLabel="Autre" itemValue="AUTRE" />
|
||||
</ui:param>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="priorite" />
|
||||
<ui:param name="label" value="Priorité" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.priorite}" />
|
||||
<ui:param name="items">
|
||||
<f:selectItem itemLabel="Critique" itemValue="CRITIQUE" />
|
||||
<f:selectItem itemLabel="Haute" itemValue="HAUTE" />
|
||||
<f:selectItem itemLabel="Normale" itemValue="NORMALE" />
|
||||
<f:selectItem itemLabel="Basse" itemValue="BASSE" />
|
||||
</ui:param>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebut" />
|
||||
<ui:param name="label" value="Date de début *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.dateDebut}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateFin" />
|
||||
<ui:param name="label" value="Date de fin" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.dateFin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="lieu" />
|
||||
<ui:param name="label" value="Lieu *" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.lieu}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="capaciteMax" />
|
||||
<ui:param name="label" value="Capacité maximale" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.capaciteMax}" />
|
||||
<ui:param name="min" value="1" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="budget" />
|
||||
<ui:param name="label" value="Budget prévu" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.budget}" />
|
||||
<ui:param name="min" value="0" />
|
||||
<ui:param name="suffix" value=" FCFA" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="organisateur" />
|
||||
<ui:param name="label" value="Organisateur" />
|
||||
<ui:param name="value" value="#{evenementsBean.nouvelEvenement.organisateur}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgNouvelEvenement').hide();"
|
||||
styleClass="p-button-outlined" />
|
||||
<p:commandButton value="Créer"
|
||||
icon="pi pi-check"
|
||||
action="#{evenementsBean.creerEvenement}"
|
||||
update="@form"
|
||||
oncomplete="if(!args.validationFailed) { PF('dlgNouvelEvenement').hide(); }" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
|
||||
<!-- Dialog Détails -->
|
||||
<h:form id="formDetails">
|
||||
<p:dialog id="dlgDetails" header="Détails de l'Événement"
|
||||
widgetVar="dlgDetails"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 700px;">
|
||||
<div class="grid" rendered="#{evenementsBean.evenementSelectionne != null}">
|
||||
<div class="col-12">
|
||||
<h4>#{evenementsBean.evenementSelectionne.titre}</h4>
|
||||
<p class="text-600">#{evenementsBean.evenementSelectionne.description}</p>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Type</label>
|
||||
<p:tag value="#{evenementsBean.evenementSelectionne.typeEvenementLibelle}"
|
||||
severity="#{evenementsBean.evenementSelectionne.typeEvenementSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Statut</label>
|
||||
<p:tag value="#{evenementsBean.evenementSelectionne.statutLibelle}"
|
||||
severity="#{evenementsBean.evenementSelectionne.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Date de début</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.dateDebutFormatee}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.heureDebutFormatee}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Lieu</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.lieu}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.adresseComplete}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Participants</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.participantsInscrits} / #{evenementsBean.evenementSelectionne.capaciteMax}</div>
|
||||
<p:progressBar value="#{evenementsBean.evenementSelectionne.tauxRemplissage}"
|
||||
showValue="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Budget</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.budgetFormate}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<p:commandButton value="Fermer"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgDetails').hide();"
|
||||
styleClass="p-button-outlined" />
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
|
||||
<!-- Dialog Modifier -->
|
||||
<h:form id="formModifier">
|
||||
<p:dialog id="dlgModifier" header="Modifier l'Événement"
|
||||
widgetVar="dlgModifier"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 800px;">
|
||||
<div class="grid" rendered="#{evenementsBean.evenementSelectionne != null}">
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="titreModif" />
|
||||
<ui:param name="label" value="Titre *" />
|
||||
<ui:param name="value" value="#{evenementsBean.evenementSelectionne.titre}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="descriptionModif" />
|
||||
<ui:param name="label" value="Description" />
|
||||
<ui:param name="value" value="#{evenementsBean.evenementSelectionne.description}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="statutModif" />
|
||||
<ui:param name="label" value="Statut" />
|
||||
<ui:param name="value" value="#{evenementsBean.evenementSelectionne.statut}" />
|
||||
<ui:param name="items">
|
||||
<f:selectItem itemLabel="Planifié" itemValue="PLANIFIE" />
|
||||
<f:selectItem itemLabel="Confirmé" itemValue="CONFIRME" />
|
||||
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
|
||||
<f:selectItem itemLabel="Terminé" itemValue="TERMINE" />
|
||||
<f:selectItem itemLabel="Annulé" itemValue="ANNULE" />
|
||||
<f:selectItem itemLabel="Reporté" itemValue="REPORTE" />
|
||||
</ui:param>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebutModif" />
|
||||
<ui:param name="label" value="Date de début *" />
|
||||
<ui:param name="value" value="#{evenementsBean.evenementSelectionne.dateDebut}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgModifier').hide();"
|
||||
styleClass="p-button-outlined" />
|
||||
<p:commandButton value="Enregistrer"
|
||||
icon="pi pi-check"
|
||||
action="#{evenementsBean.modifierEvenement}"
|
||||
update="@form"
|
||||
oncomplete="if(!args.validationFailed) { PF('dlgModifier').hide(); }" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -5,16 +5,115 @@
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
<ui:define name="title">UnionFlow - Participants</ui:define>
|
||||
|
||||
<ui:define name="title">Gestion des Participants - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>Participants - Evenement</h2>
|
||||
<p>Page en cours de développement...</p>
|
||||
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-users text-green-500" />
|
||||
<ui:param name="title" value="Gestion des Participants" />
|
||||
<ui:param name="description" value="Gérer les participants et les inscriptions aux événements" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsParticipants">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Retour" />
|
||||
<ui:param name="icon" value="pi pi-arrow-left" />
|
||||
<ui:param name="outcome" value="/pages/secure/evenement/gestion.xhtml" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{evenementsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Sélection d'événement -->
|
||||
<div class="card">
|
||||
<h:form id="formSelection">
|
||||
<h5>Sélectionner un Événement</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<p:selectOneMenu value="#{evenementsBean.evenementSelectionne}"
|
||||
styleClass="w-full"
|
||||
filter="true"
|
||||
filterMatchMode="contains"
|
||||
placeholder="Sélectionner un événement...">
|
||||
<f:selectItem itemLabel="Sélectionner un événement" itemValue="#{null}" />
|
||||
<f:selectItems value="#{evenementsBean.tousLesEvenements}"
|
||||
var="evt"
|
||||
itemLabel="#{evt.titre} - #{evt.dateDebutFormatee}"
|
||||
itemValue="#{evt}" />
|
||||
<p:ajax event="change" update=":formParticipants" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Liste des participants -->
|
||||
<div class="card" rendered="#{evenementsBean.evenementSelectionne != null}">
|
||||
<h:form id="formParticipants">
|
||||
<h5>Participants - #{evenementsBean.evenementSelectionne.titre}</h5>
|
||||
|
||||
<div class="grid mb-3">
|
||||
<div class="col-12 md:col-4">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{evenementsBean.evenementSelectionne.participantsInscrits}" />
|
||||
<ui:param name="label" value="Inscrits" />
|
||||
<ui:param name="icon" value="pi pi-user-plus" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{evenementsBean.evenementSelectionne.participantsPresents}" />
|
||||
<ui:param name="label" value="Présents" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{evenementsBean.evenementSelectionne.placesDisponibles}" />
|
||||
<ui:param name="label" value="Places disponibles" />
|
||||
<ui:param name="icon" value="pi pi-ticket" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-info-circle text-4xl text-blue-500 mb-3"></i>
|
||||
<h5>Gestion des Participants</h5>
|
||||
<p class="text-600">La gestion détaillée des participants sera disponible prochainement</p>
|
||||
<p class="text-600 mt-2">
|
||||
Participants inscrits: <strong>#{evenementsBean.evenementSelectionne.participantsInscrits}</strong> /
|
||||
Capacité: <strong>#{evenementsBean.evenementSelectionne.capaciteMax}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Message si aucun événement sélectionné -->
|
||||
<div class="card" rendered="#{evenementsBean.evenementSelectionne == null}">
|
||||
<div class="text-center p-4">
|
||||
<i class="pi pi-info-circle text-4xl text-blue-500 mb-3"></i>
|
||||
<h5>Sélectionnez un événement</h5>
|
||||
<p class="text-600">Veuillez sélectionner un événement pour voir ses participants</p>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,21 +1,254 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Participation aux Événements - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-calendar-check text-purple-500" />
|
||||
<ui:param name="title" value="Participation aux Événements" />
|
||||
<ui:param name="description" value="Consultez et inscrivez-vous aux événements disponibles" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsParticipation">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{evenementsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
</div>
|
||||
<h:form id="formFiltres">
|
||||
<h5>Filtres</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-4">
|
||||
<p:selectOneMenu value="#{evenementsBean.filtres.type}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Assemblée Générale" itemValue="ASSEMBLEE_GENERALE" />
|
||||
<f:selectItem itemLabel="Formation" itemValue="FORMATION" />
|
||||
<f:selectItem itemLabel="Activité Sociale" itemValue="ACTIVITE_SOCIALE" />
|
||||
<f:selectItem itemLabel="Action Caritative" itemValue="ACTION_CARITATIVE" />
|
||||
<p:ajax event="change" update=":formListe" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<p:selectOneMenu value="#{evenementsBean.filtres.statut}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="Planifié" itemValue="PLANIFIE" />
|
||||
<f:selectItem itemLabel="Confirmé" itemValue="CONFIRME" />
|
||||
<f:selectItem itemLabel="En cours" itemValue="EN_COURS" />
|
||||
<p:ajax event="change" update=":formListe" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Rechercher"
|
||||
icon="pi pi-search"
|
||||
action="#{evenementsBean.rechercher}"
|
||||
update=":formListe"
|
||||
styleClass="p-button-primary" />
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-filter-slash"
|
||||
action="#{evenementsBean.reinitialiserFiltres}"
|
||||
update="@form :formListe"
|
||||
styleClass="p-button-outlined" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Liste des événements disponibles -->
|
||||
<div class="card">
|
||||
<h:form id="formListe">
|
||||
<h5>Événements Disponibles</h5>
|
||||
|
||||
<p:dataTable id="dtEvenements"
|
||||
value="#{evenementsBean.evenementsFiltres}"
|
||||
var="evenement"
|
||||
paginator="true"
|
||||
rows="10"
|
||||
emptyMessage="Aucun événement disponible"
|
||||
rowKey="#{evenement.id}">
|
||||
|
||||
<p:column headerText="Événement" style="width: 40%;">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{evenement.typeEvenementIcon} text-2xl text-#{evenement.typeEvenementSeverity}"></i>
|
||||
<div>
|
||||
<div class="font-semibold text-lg">#{evenement.titre}</div>
|
||||
<div class="text-sm text-600">#{evenement.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date et Heure">
|
||||
<div>
|
||||
<div class="font-medium">#{evenement.dateDebutFormatee}</div>
|
||||
<div class="text-sm text-600">
|
||||
<i class="pi pi-clock"></i> #{evenement.heureDebutFormatee} - #{evenement.heureFinFormatee}
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Lieu">
|
||||
<div>
|
||||
<div class="font-medium">#{evenement.lieu}</div>
|
||||
<div class="text-sm text-600">#{evenement.ville}</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Places">
|
||||
<div>
|
||||
<div class="font-medium">#{evenement.participantsInscrits} / #{evenement.capaciteMax}</div>
|
||||
<p:progressBar value="#{evenement.tauxRemplissage}"
|
||||
showValue="true"
|
||||
styleClass="mt-1" />
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut">
|
||||
<p:tag value="#{evenement.statutLibelle}"
|
||||
severity="#{evenement.statutSeverity}"
|
||||
icon="#{evenement.statutIcon}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width: 150px;">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton value="Voir détails"
|
||||
icon="pi pi-eye"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
action="#{evenementsBean.selectionnerEvenement(evenement)}"
|
||||
update=":formDetails:dlgDetails"
|
||||
oncomplete="PF('dlgDetails').show();" />
|
||||
|
||||
<p:commandButton value="S'inscrire"
|
||||
icon="pi pi-check"
|
||||
styleClass="p-button-success p-button-sm"
|
||||
rendered="#{evenement.sontInscriptionsOuvertes()}"
|
||||
action="#{evenementsBean.sinscrireEvenement(evenement)}"
|
||||
update="@form"
|
||||
onclick="return confirm('Confirmer votre inscription à cet événement ?');" />
|
||||
|
||||
<p:tag value="Complet"
|
||||
severity="error"
|
||||
rendered="#{evenement.isComplet()}" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Détails -->
|
||||
<h:form id="formDetails">
|
||||
<p:dialog id="dlgDetails" header="Détails de l'Événement"
|
||||
widgetVar="dlgDetails"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 800px;">
|
||||
<div class="grid" rendered="#{evenementsBean.evenementSelectionne != null}">
|
||||
<div class="col-12">
|
||||
<h3>#{evenementsBean.evenementSelectionne.titre}</h3>
|
||||
<p class="text-600 mt-2">#{evenementsBean.evenementSelectionne.description}</p>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Type</label>
|
||||
<p:tag value="#{evenementsBean.evenementSelectionne.typeEvenementLibelle}"
|
||||
severity="#{evenementsBean.evenementSelectionne.typeEvenementSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Statut</label>
|
||||
<p:tag value="#{evenementsBean.evenementSelectionne.statutLibelle}"
|
||||
severity="#{evenementsBean.evenementSelectionne.statutSeverity}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Date de début</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.dateDebutFormatee}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.heureDebutFormatee}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Date de fin</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.dateFinFormatee}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.heureFinFormatee}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Lieu</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.adresseComplete}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Participants</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.participantsInscrits} / #{evenementsBean.evenementSelectionne.capaciteMax}</div>
|
||||
<p:progressBar value="#{evenementsBean.evenementSelectionne.tauxRemplissage}"
|
||||
showValue="true" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Organisateur</label>
|
||||
<div>#{evenementsBean.evenementSelectionne.organisateur}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.emailOrganisateur}</div>
|
||||
<div class="text-sm text-600">#{evenementsBean.evenementSelectionne.telephoneOrganisateur}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12" rendered="#{evenementsBean.evenementSelectionne.instructions != null}">
|
||||
<div class="field">
|
||||
<label class="font-semibold">Instructions</label>
|
||||
<div class="surface-50 p-3 border-round">#{evenementsBean.evenementSelectionne.instructions}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="S'inscrire"
|
||||
icon="pi pi-check"
|
||||
rendered="#{evenementsBean.evenementSelectionne != null and evenementsBean.evenementSelectionne.sontInscriptionsOuvertes()}"
|
||||
action="#{evenementsBean.sinscrireEvenement(evenementsBean.evenementSelectionne)}"
|
||||
update="@form"
|
||||
onclick="PF('dlgDetails').hide(); return confirm('Confirmer votre inscription ?');" />
|
||||
<p:commandButton value="Fermer"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgDetails').hide();"
|
||||
styleClass="p-button-secondary p-button-outlined" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -10,35 +10,28 @@
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h3 class="mb-2">
|
||||
<i class="pi pi-user-plus text-primary mr-2"></i>
|
||||
Inscription Nouveau Membre
|
||||
</h3>
|
||||
<p class="text-600 m-0">Formulaire complet d'inscription avec photo et documents</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-900 font-medium">Numéro: #{membreInscriptionBean.numeroGenere}</div>
|
||||
<small class="text-600">Généré automatiquement</small>
|
||||
</div>
|
||||
</div>
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-user-plus text-primary" />
|
||||
<ui:param name="title" value="Inscription Nouveau Membre" />
|
||||
<ui:param name="description" value="Formulaire complet d'inscription avec photo et documents" />
|
||||
<ui:define name="actions">
|
||||
<div>
|
||||
<div class="text-900 font-medium">Numéro: #{membreInscriptionBean.numeroGenere}</div>
|
||||
<small class="text-600">Généré automatiquement</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<h:form>
|
||||
<p:messages id="messages" showDetail="true" closable="true" />
|
||||
<p:messages id="messages" showDetail="true" closable="true" globalOnly="false" />
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="card ui-fluid">
|
||||
<h5>Informations personnelles</h5>
|
||||
|
||||
<!-- Section photo intégrée -->
|
||||
<ui:decorate template="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Informations personnelles" />
|
||||
<ui:param name="fluid" value="true" />
|
||||
<ui:define name="content">
|
||||
<!-- Section photo intégrée -->
|
||||
<div class="text-center mb-4 pb-3" style="border-bottom: 1px solid var(--surface-border);">
|
||||
<div class="mb-3 relative">
|
||||
<div id="photoContainer" style="width: 120px; height: 120px; margin: 0 auto; position: relative; overflow: hidden; border-radius: 50%; border: 3px solid var(--surface-border); background: #f8f9fa;">
|
||||
@@ -84,274 +77,292 @@
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Champs d'informations personnelles -->
|
||||
<div class="field">
|
||||
<p:outputLabel for="prenom" value="Prénom" />
|
||||
<p:inputText id="prenom" value="#{membreInscriptionBean.prenom}" required="true" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="nom" value="Nom" />
|
||||
<p:inputText id="nom" value="#{membreInscriptionBean.nom}" required="true" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="dateNaissance" value="Date de naissance" />
|
||||
<p:calendar id="dateNaissance" value="#{membreInscriptionBean.dateNaissance}"
|
||||
showIcon="true" navigator="true" required="true"
|
||||
locale="fr" pattern="dd/MM/yyyy" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="lieuNaissance" value="Lieu de naissance" />
|
||||
<p:inputText id="lieuNaissance" value="#{membreInscriptionBean.lieuNaissance}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="sexe" value="Sexe" />
|
||||
<p:selectOneMenu id="sexe" value="#{membreInscriptionBean.sexe}" required="true">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.sexeOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="nationalite" value="Nationalité" />
|
||||
<p:inputText id="nationalite" value="#{membreInscriptionBean.nationalite}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="situationMatrimoniale" value="Situation matrimoniale" />
|
||||
<p:selectOneMenu id="situationMatrimoniale" value="#{membreInscriptionBean.situationMatrimoniale}">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.situationMatrimonialeOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="profession" value="Profession" />
|
||||
<p:inputText id="profession" value="#{membreInscriptionBean.profession}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="employeur" value="Employeur / Entreprise" />
|
||||
<p:inputText id="employeur" value="#{membreInscriptionBean.employeur}" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Champs d'informations personnelles -->
|
||||
<div class="field">
|
||||
<p:outputLabel for="prenom" value="Prénom" />
|
||||
<p:inputText id="prenom" value="#{membreInscriptionBean.prenom}" required="true"
|
||||
requiredMessage="Le prénom est obligatoire" styleClass="w-full" />
|
||||
<p:message for="prenom" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="nom" value="Nom" />
|
||||
<p:inputText id="nom" value="#{membreInscriptionBean.nom}" required="true"
|
||||
requiredMessage="Le nom est obligatoire" styleClass="w-full" />
|
||||
<p:message for="nom" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="dateNaissance" value="Date de naissance" />
|
||||
<p:calendar id="dateNaissance" value="#{membreInscriptionBean.dateNaissance}" required="true"
|
||||
pattern="dd/MM/yyyy" showIcon="true" yearNavigator="true" yearRange="1920:2030"
|
||||
monthNavigator="true" requiredMessage="La date de naissance est obligatoire"
|
||||
styleClass="w-full" />
|
||||
<p:message for="dateNaissance" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="lieuNaissance" value="Lieu de naissance" />
|
||||
<p:inputText id="lieuNaissance" value="#{membreInscriptionBean.lieuNaissance}" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="sexe" value="Sexe" />
|
||||
<p:selectOneMenu id="sexe" value="#{membreInscriptionBean.sexe}" required="true" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.sexeOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="nationalite" value="Nationalité" />
|
||||
<p:inputText id="nationalite" value="#{membreInscriptionBean.nationalite}" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="situationMatrimoniale" value="Situation matrimoniale" />
|
||||
<p:selectOneMenu id="situationMatrimoniale" value="#{membreInscriptionBean.situationMatrimoniale}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.situationMatrimonialeOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="profession" value="Profession" />
|
||||
<p:inputText id="profession" value="#{membreInscriptionBean.profession}" styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="employeur" value="Employeur / Entreprise" />
|
||||
<p:inputText id="employeur" value="#{membreInscriptionBean.employeur}" styleClass="w-full" />
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<div class="card ui-fluid">
|
||||
<h5>Contact d'urgence</h5>
|
||||
<div class="field">
|
||||
<p:outputLabel for="contactUrgenceNom" value="Nom complet" />
|
||||
<p:inputText id="contactUrgenceNom" value="#{membreInscriptionBean.contactUrgenceNom}" required="true" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="contactUrgenceTelephone" value="Téléphone" />
|
||||
<p:inputText id="contactUrgenceTelephone" value="#{membreInscriptionBean.contactUrgenceTelephone}" required="true" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="contactUrgenceLien" value="Lien de parenté" />
|
||||
<p:selectOneMenu id="contactUrgenceLien" value="#{membreInscriptionBean.contactUrgenceLien}" required="true">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.contactUrgenceLienOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
<ui:decorate template="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Contact d'urgence" />
|
||||
<ui:param name="fluid" value="true" />
|
||||
<ui:define name="content">
|
||||
<div class="field">
|
||||
<p:outputLabel for="contactUrgenceNom" value="Nom complet" />
|
||||
<p:inputText id="contactUrgenceNom" value="#{membreInscriptionBean.contactUrgenceNom}"
|
||||
required="true" requiredMessage="Le nom du contact d'urgence est obligatoire"
|
||||
styleClass="w-full" />
|
||||
<p:message for="contactUrgenceNom" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="contactUrgenceTelephone" value="Téléphone" />
|
||||
<p:inputText id="contactUrgenceTelephone" value="#{membreInscriptionBean.contactUrgenceTelephone}"
|
||||
required="true" requiredMessage="Le téléphone du contact d'urgence est obligatoire"
|
||||
styleClass="w-full" />
|
||||
<p:message for="contactUrgenceTelephone" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="contactUrgenceLien" value="Lien de parenté" />
|
||||
<p:selectOneMenu id="contactUrgenceLien" value="#{membreInscriptionBean.contactUrgenceLien}" required="true" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.contactUrgenceLienOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<div class="card">
|
||||
<h5>Documents justificatifs</h5>
|
||||
<p:fileUpload listener="#{membreInscriptionBean.handleFileUpload}"
|
||||
mode="advanced"
|
||||
dragDropSupport="true"
|
||||
multiple="true"
|
||||
update="messages documentsListPanel"
|
||||
sizeLimit="5000000"
|
||||
fileLimit="5"
|
||||
allowTypes="/(\.|\/)(pdf|doc|docx|jpg|jpeg|png)$/"
|
||||
uploadLabel="Télécharger"
|
||||
cancelLabel="Annuler"
|
||||
chooseLabel="Sélectionner les fichiers"
|
||||
invalidFileMessage="Type de fichier non supporté"
|
||||
fileLimitMessage="Nombre maximum de fichiers dépassé"
|
||||
invalidSizeMessage="Taille de fichier trop importante"
|
||||
style="width:100%" />
|
||||
|
||||
<h:panelGroup id="documentsListPanel" layout="block" styleClass="mt-3">
|
||||
<h6 class="mb-2" rendered="#{not empty membreInscriptionBean.documentsJoints}">Fichiers ajoutés:</h6>
|
||||
<ui:repeat value="#{membreInscriptionBean.documentsJoints}" var="document">
|
||||
<div class="flex align-items-center justify-content-between p-2 border-round mb-2"
|
||||
style="background: var(--surface-50);">
|
||||
<div class="flex align-items-center">
|
||||
<i class="pi pi-file text-blue-500 mr-2"></i>
|
||||
<span class="text-900">#{document}</span>
|
||||
<ui:decorate template="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Documents justificatifs" />
|
||||
<ui:define name="content">
|
||||
<p:fileUpload listener="#{membreInscriptionBean.handleFileUpload}"
|
||||
mode="advanced"
|
||||
dragDropSupport="true"
|
||||
multiple="true"
|
||||
update="messages documentsListPanel"
|
||||
sizeLimit="5000000"
|
||||
fileLimit="5"
|
||||
allowTypes="/(\.|\/)(pdf|doc|docx|jpg|jpeg|png)$/"
|
||||
uploadLabel="Télécharger"
|
||||
cancelLabel="Annuler"
|
||||
chooseLabel="Sélectionner les fichiers"
|
||||
invalidFileMessage="Type de fichier non supporté"
|
||||
fileLimitMessage="Nombre maximum de fichiers dépassé"
|
||||
invalidSizeMessage="Taille de fichier trop importante"
|
||||
style="width:100%" />
|
||||
|
||||
<h:panelGroup id="documentsListPanel" layout="block" styleClass="mt-3">
|
||||
<h6 class="mb-2" rendered="#{not empty membreInscriptionBean.documentsJoints}">Fichiers ajoutés:</h6>
|
||||
<ui:repeat value="#{membreInscriptionBean.documentsJoints}" var="document">
|
||||
<div class="flex align-items-center justify-content-between p-2 border-round mb-2"
|
||||
style="background: var(--surface-50);">
|
||||
<div class="flex align-items-center">
|
||||
<i class="pi pi-file text-blue-500 mr-2"></i>
|
||||
<span class="text-900">#{document}</span>
|
||||
</div>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="action" value="#{membreInscriptionBean.supprimerDocument(document)}" />
|
||||
<ui:param name="update" value="documentsListPanel" />
|
||||
<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>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="action" value="#{membreInscriptionBean.supprimerDocument(document)}" />
|
||||
<ui:param name="update" value="documentsListPanel" />
|
||||
<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>
|
||||
</ui:repeat>
|
||||
</h:panelGroup>
|
||||
|
||||
<small class="text-600">Formats acceptés: PDF, DOC, DOCX, JPG, PNG - Maximum 5 fichiers de 5MB chacun</small>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</h:panelGroup>
|
||||
|
||||
<small class="text-600">Formats acceptés: PDF, DOC, DOCX, JPG, PNG - Maximum 5 fichiers de 5MB chacun</small>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="card ui-fluid">
|
||||
<h5>Coordonnées</h5>
|
||||
<div class="field">
|
||||
<p:outputLabel for="adresse" value="Adresse complète" />
|
||||
<p:inputTextarea id="adresse" value="#{membreInscriptionBean.adresse}" rows="4" required="true" />
|
||||
</div>
|
||||
<div class="formgrid grid">
|
||||
<div class="field col">
|
||||
<p:outputLabel for="ville" value="Ville" />
|
||||
<p:inputText id="ville" value="#{membreInscriptionBean.ville}" required="true" />
|
||||
<ui:decorate template="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Coordonnées" />
|
||||
<ui:param name="fluid" value="true" />
|
||||
<ui:define name="content">
|
||||
<div class="field">
|
||||
<p:outputLabel for="adresse" value="Adresse complète" />
|
||||
<p:inputTextarea id="adresse" value="#{membreInscriptionBean.adresse}" rows="4"
|
||||
required="true" requiredMessage="L'adresse est obligatoire"
|
||||
styleClass="w-full" />
|
||||
<p:message for="adresse" />
|
||||
</div>
|
||||
<div class="field col">
|
||||
<p:outputLabel for="codePostal" value="Code postal" />
|
||||
<p:inputText id="codePostal" value="#{membreInscriptionBean.codePostal}" />
|
||||
|
||||
<div class="formgrid grid">
|
||||
<div class="field col">
|
||||
<p:outputLabel for="ville" value="Ville" />
|
||||
<p:inputText id="ville" value="#{membreInscriptionBean.ville}" required="true"
|
||||
requiredMessage="La ville est obligatoire" styleClass="w-full" />
|
||||
<p:message for="ville" />
|
||||
</div>
|
||||
<div class="field col">
|
||||
<p:outputLabel for="codePostal" value="Code postal" />
|
||||
<p:inputText id="codePostal" value="#{membreInscriptionBean.codePostal}" styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="pays" value="Pays" />
|
||||
<p:inputText id="pays" value="#{membreInscriptionBean.pays}" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="email" value="Email" />
|
||||
<p:inputText id="email" value="#{membreInscriptionBean.email}" required="true">
|
||||
<f:validateRegex pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<div class="formgrid grid">
|
||||
<div class="field col">
|
||||
<p:outputLabel for="telephone" value="Téléphone fixe" />
|
||||
<p:inputText id="telephone" value="#{membreInscriptionBean.telephone}" />
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="pays" value="Pays" />
|
||||
<p:inputText id="pays" value="#{membreInscriptionBean.pays}" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col">
|
||||
<p:outputLabel for="telephoneMobile" value="Téléphone mobile" />
|
||||
<p:inputText id="telephoneMobile" value="#{membreInscriptionBean.telephoneMobile}" required="true" />
|
||||
<div class="field">
|
||||
<p:outputLabel for="email" value="Email" />
|
||||
<p:inputText id="email" value="#{membreInscriptionBean.email}" required="true" styleClass="w-full">
|
||||
<f:validateRegex pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="formgrid grid">
|
||||
<div class="field col">
|
||||
<p:outputLabel for="telephone" value="Téléphone fixe" />
|
||||
<p:inputText id="telephone" value="#{membreInscriptionBean.telephone}" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col">
|
||||
<p:outputLabel for="telephoneMobile" value="Téléphone mobile" />
|
||||
<p:inputText id="telephoneMobile" value="#{membreInscriptionBean.telephoneMobile}"
|
||||
required="true" requiredMessage="Le téléphone mobile est obligatoire"
|
||||
styleClass="w-full" />
|
||||
<p:message for="telephoneMobile" />
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<div class="card ui-fluid">
|
||||
<h5>Adhésion</h5>
|
||||
<div class="field">
|
||||
<p:outputLabel for="typeAdhesion" value="Type d'adhésion" />
|
||||
<p:selectOneMenu id="typeAdhesion" value="#{membreInscriptionBean.typeAdhesion}" required="true">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.typeAdhesionOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="numeroParrain" value="N° Membre parrain" />
|
||||
<div class="ui-inputgroup">
|
||||
<p:inputText id="numeroParrain" value="#{membreInscriptionBean.numeroParrain}" />
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<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>
|
||||
<ui:decorate template="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Adhésion" />
|
||||
<ui:param name="fluid" value="true" />
|
||||
<ui:define name="content">
|
||||
<div class="field">
|
||||
<p:outputLabel for="organisationId" value="Organisation *" styleClass="font-bold text-primary" />
|
||||
<p:selectOneMenu id="organisationId" value="#{membreInscriptionBean.organisationId}" required="true" requiredMessage="Vous devez sélectionner une organisation" styleClass="w-full">
|
||||
<f:selectItem itemLabel="--- Sélectionner une organisation ---" itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.organisationsDisponibles}"
|
||||
var="org"
|
||||
itemLabel="#{org.nom} (#{org.ville})"
|
||||
itemValue="#{org.id}" />
|
||||
</p:selectOneMenu>
|
||||
<p:message for="organisationId" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="nomParrain" value="Nom du parrain" />
|
||||
<p:inputText id="nomParrain" value="#{membreInscriptionBean.nomParrain}" readonly="true" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="motifAdhesion" value="Motif d'adhésion" />
|
||||
<p:inputTextarea id="motifAdhesion" value="#{membreInscriptionBean.motifAdhesion}" rows="3" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="typeAdhesion" value="Type d'adhésion" />
|
||||
<p:selectOneMenu id="typeAdhesion" value="#{membreInscriptionBean.typeAdhesion}" required="true" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" />
|
||||
<f:selectItems value="#{membreInscriptionBean.typeAdhesionOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="numeroParrain" value="N° Membre parrain" />
|
||||
<div class="ui-inputgroup">
|
||||
<p:inputText id="numeroParrain" value="#{membreInscriptionBean.numeroParrain}" styleClass="w-full" />
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<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 class="field">
|
||||
<p:outputLabel for="nomParrain" value="Nom du parrain" />
|
||||
<p:inputText id="nomParrain" value="#{membreInscriptionBean.nomParrain}" readonly="true" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<p:outputLabel for="motifAdhesion" value="Motif d'adhésion" />
|
||||
<p:inputTextarea id="motifAdhesion" value="#{membreInscriptionBean.motifAdhesion}"
|
||||
rows="3" styleClass="w-full" />
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h5>Informations complémentaires</h5>
|
||||
<div class="ui-fluid formgrid grid">
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="nomBanque" value="Nom de la banque" />
|
||||
<p:inputText id="nomBanque" value="#{membreInscriptionBean.nomBanque}" />
|
||||
<ui:decorate template="/templates/components/form-section.xhtml">
|
||||
<ui:param name="title" value="Informations complémentaires" />
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid formgrid grid">
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="nomBanque" value="Nom de la banque" />
|
||||
<p:inputText id="nomBanque" value="#{membreInscriptionBean.nomBanque}" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="numeroBanque" value="Numéro de compte" />
|
||||
<p:inputText id="numeroBanque" value="#{membreInscriptionBean.numeroBanque}" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="ribIban" value="RIB / IBAN" />
|
||||
<p:inputText id="ribIban" value="#{membreInscriptionBean.ribIban}" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="competencesSpeciales" value="Compétences spéciales" />
|
||||
<p:inputTextarea id="competencesSpeciales" value="#{membreInscriptionBean.competencesSpeciales}"
|
||||
rows="3" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="centresInteret" value="Centres d'intérêt" />
|
||||
<p:inputTextarea id="centresInteret" value="#{membreInscriptionBean.centresInteret}"
|
||||
rows="3" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="commentaires" value="Commentaires" />
|
||||
<p:inputTextarea id="commentaires" value="#{membreInscriptionBean.commentaires}"
|
||||
rows="3" styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="numeroBanque" value="Numéro de compte" />
|
||||
<p:inputText id="numeroBanque" value="#{membreInscriptionBean.numeroBanque}" />
|
||||
|
||||
<h5>Autorisations</h5>
|
||||
<div class="formgroup-inline">
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="accepteReglement" value="#{membreInscriptionBean.accepteReglement}" />
|
||||
<p:outputLabel for="accepteReglement" value="J'accepte le règlement intérieur" />
|
||||
</div>
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="acceptePrelevement" value="#{membreInscriptionBean.acceptePrelevement}" />
|
||||
<p:outputLabel for="acceptePrelevement" value="J'autorise le prélèvement automatique" />
|
||||
</div>
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="autorisationMarketing" value="#{membreInscriptionBean.autorisationMarketing}" />
|
||||
<p:outputLabel for="autorisationMarketing" value="J'accepte de recevoir des communications" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="ribIban" value="RIB / IBAN" />
|
||||
<p:inputText id="ribIban" value="#{membreInscriptionBean.ribIban}" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="competencesSpeciales" value="Compétences spéciales" />
|
||||
<p:inputTextarea id="competencesSpeciales" value="#{membreInscriptionBean.competencesSpeciales}" rows="3" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-6">
|
||||
<p:outputLabel for="centresInteret" value="Centres d'intérêt" />
|
||||
<p:inputTextarea id="centresInteret" value="#{membreInscriptionBean.centresInteret}" rows="3" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="commentaires" value="Commentaires" />
|
||||
<p:inputTextarea id="commentaires" value="#{membreInscriptionBean.commentaires}" rows="3" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h5>Autorisations</h5>
|
||||
<div class="formgroup-inline">
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="accepteReglement" value="#{membreInscriptionBean.accepteReglement}" />
|
||||
<p:outputLabel for="accepteReglement" value="J'accepte le règlement intérieur" />
|
||||
</div>
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="acceptePrelevement" value="#{membreInscriptionBean.acceptePrelevement}" />
|
||||
<p:outputLabel for="acceptePrelevement" value="J'autorise le prélèvement automatique" />
|
||||
</div>
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="autorisationMarketing" value="#{membreInscriptionBean.autorisationMarketing}" />
|
||||
<p:outputLabel for="autorisationMarketing" value="J'accepte de recevoir des communications" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progression -->
|
||||
<div class="card">
|
||||
<h5>Progression de l'inscription</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="text-center p-3">
|
||||
<i class="pi pi-user text-2xl text-primary mb-2"></i>
|
||||
<div class="text-sm font-medium">Informations personnelles</div>
|
||||
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{membreInscriptionBean.etapePersonnelleComplete ? 'inline' : 'none'};"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="text-center p-3">
|
||||
<i class="pi pi-home text-2xl text-primary mb-2"></i>
|
||||
<div class="text-sm font-medium">Coordonnées</div>
|
||||
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{membreInscriptionBean.etapeCoordonneeComplete ? 'inline' : 'none'};"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="text-center p-3">
|
||||
<i class="pi pi-id-card text-2xl text-primary mb-2"></i>
|
||||
<div class="text-sm font-medium">Adhésion</div>
|
||||
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{membreInscriptionBean.etapeAdhesionComplete ? 'inline' : 'none'};"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="text-center p-3">
|
||||
<i class="pi pi-file text-2xl text-primary mb-2"></i>
|
||||
<div class="text-sm font-medium">Documents</div>
|
||||
<i class="pi pi-check-circle text-green-500 mt-1" style="display: #{membreInscriptionBean.etapeDocumentsComplete ? 'inline' : 'none'};"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p:progressBar value="#{membreInscriptionBean.progressionPourcentage}"
|
||||
labelTemplate="{value}% complété"
|
||||
styleClass="mb-3" />
|
||||
</div>
|
||||
|
||||
<!-- Actions finales -->
|
||||
<div class="card">
|
||||
<h5>Finaliser l'inscription</h5>
|
||||
@@ -366,14 +377,16 @@
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="🎯 Inscrire le membre" />
|
||||
<ui:param name="icon" value="pi pi-user-plus" />
|
||||
<ui:param name="onclick" value="return preparePhotoForSubmission(this);" />
|
||||
<ui:param name="action" value="#{membreInscriptionBean.inscrire}" />
|
||||
<ui:param name="update" value="messages" />
|
||||
<ui:param name="disabled" value="#{!membreInscriptionBean.formulaireValide}" />
|
||||
</ui:include>
|
||||
<p:commandButton
|
||||
value="🎯 Inscrire le membre"
|
||||
icon="pi pi-user-plus"
|
||||
action="#{membreInscriptionBean.inscrire}"
|
||||
update="@form"
|
||||
process="@form"
|
||||
onclick="PF('statusDialog').show();"
|
||||
oncomplete="PF('statusDialog').hide();"
|
||||
styleClass="ui-button-success"
|
||||
title="Soumettre l'inscription" />
|
||||
|
||||
<ui:include src="/templates/components/button-info.xhtml">
|
||||
<ui:param name="value" value="💾 Enregistrer brouillon" />
|
||||
@@ -731,6 +744,16 @@
|
||||
return true; // Permettre la soumission si pas de photo
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Dialogue de chargement -->
|
||||
<p:dialog id="statusDialog" widgetVar="statusDialog" modal="true" closable="false"
|
||||
showHeader="false" styleClass="no-border" resizable="false">
|
||||
<div class="flex flex-column align-items-center p-4">
|
||||
<i class="pi pi-spin pi-spinner text-4xl text-primary mb-3"></i>
|
||||
<div class="text-xl font-medium text-900">Traitement en cours...</div>
|
||||
<div class="text-600">Veuillez patienter pendant l'enregistrement</div>
|
||||
</div>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -1,26 +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/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">UnionFlow - Liste des membres</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>Liste des membres</h2>
|
||||
<p>Gestion des membres de l'union</p>
|
||||
|
||||
<p:button value="Retour au tableau de bord"
|
||||
icon="pi pi-arrow-left"
|
||||
outcome="/pages/secure/dashboard"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -10,36 +10,28 @@
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h3 class="mb-2">
|
||||
<i class="pi pi-users text-blue-500 mr-2"></i>
|
||||
Liste des Membres
|
||||
</h3>
|
||||
<p class="text-600 m-0">Gestion et suivi des membres de l'association</p>
|
||||
</div>
|
||||
<h:form id="formActionsMembres">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouveau membre" />
|
||||
<ui:param name="icon" value="pi pi-user-plus" />
|
||||
<ui:param name="action" value="/pages/secure/membre/inscription?faces-redirect=true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Import/Export" />
|
||||
<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>
|
||||
</h:form>
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-users text-blue-500" />
|
||||
<ui:param name="title" value="Liste des Membres" />
|
||||
<ui:param name="description" value="Gestion et suivi des membres de l'association" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsMembres">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouveau membre" />
|
||||
<ui:param name="icon" value="pi pi-user-plus" />
|
||||
<ui:param name="outcome" value="/pages/secure/membre/inscription" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Import/Export" />
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
|
||||
<!-- Liste des membres -->
|
||||
@@ -292,17 +284,17 @@
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="ageMin" value="Âge minimum" />
|
||||
<p:inputNumber id="ageMin" value="#{membreListeBean.ageMin}" symbol="" />
|
||||
<p:inputNumber id="ageMin" value="#{membreListeBean.ageMin}" symbol="" styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="ageMax" value="Âge maximum" />
|
||||
<p:inputNumber id="ageMax" value="#{membreListeBean.ageMax}" symbol="" />
|
||||
<p:inputNumber id="ageMax" value="#{membreListeBean.ageMax}" symbol="" styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="genre" value="Genre" />
|
||||
<p:selectOneMenu id="genre" value="#{membreListeBean.genreFilter}">
|
||||
<p:selectOneMenu id="genre" value="#{membreListeBean.genreFilter}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="Homme" itemValue="M" />
|
||||
<f:selectItem itemLabel="Femme" itemValue="F" />
|
||||
@@ -314,34 +306,36 @@
|
||||
<p:autoComplete id="ville"
|
||||
value="#{membreListeBean.villeFilter}"
|
||||
completeMethod="#{membreListeBean.completerVilles}"
|
||||
placeholder="Saisir une ville..." />
|
||||
placeholder="Saisir une ville..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="dateAdhesionDebut" value="Adhésion après le" />
|
||||
<p:calendar id="dateAdhesionDebut" value="#{membreListeBean.dateAdhesionDebut}"
|
||||
pattern="dd/MM/yyyy" showIcon="true" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateAdhesionDebut" />
|
||||
<ui:param name="label" value="Adhésion après le" />
|
||||
<ui:param name="value" value="#{membreListeBean.dateAdhesionDebut}" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="dateAdhesionFin" value="Adhésion avant le" />
|
||||
<p:calendar id="dateAdhesionFin" value="#{membreListeBean.dateAdhesionFin}"
|
||||
pattern="dd/MM/yyyy" showIcon="true" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateAdhesionFin" />
|
||||
<ui:param name="label" value="Adhésion avant le" />
|
||||
<ui:param name="value" value="#{membreListeBean.dateAdhesionFin}" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="profession" value="Profession" />
|
||||
<p:autoComplete id="profession"
|
||||
value="#{membreListeBean.professionFilter}"
|
||||
completeMethod="#{membreListeBean.completerProfessions}"
|
||||
placeholder="Saisir une profession..." />
|
||||
placeholder="Saisir une profession..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="aDesEnfants" value="#{membreListeBean.aDesEnfants}" />
|
||||
<p:outputLabel for="aDesEnfants" value=" A des enfants déclarés" />
|
||||
<p:selectBooleanCheckbox id="desEnfants" value="#{membreListeBean.desEnfants}" />
|
||||
<p:outputLabel for="desEnfants" value=" A des enfants déclarés" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -377,22 +371,26 @@
|
||||
<p:dialog header="Envoyer un Message Groupé" widgetVar="dlgMessageGroupe" modal="true" width="600">
|
||||
<h:form id="formMessageGroupe">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<p:outputLabel for="sujetMessage" value="Sujet" />
|
||||
<p:inputText id="sujetMessage" value="#{membreListeBean.sujetMessage}"
|
||||
required="true" placeholder="Objet du message" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="sujetMessage" />
|
||||
<ui:param name="label" value="Sujet" />
|
||||
<ui:param name="value" value="#{membreListeBean.sujetMessage}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Objet du message" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="contenuMessage" value="Message" />
|
||||
<p:inputTextarea id="contenuMessage" value="#{membreListeBean.contenuMessage}"
|
||||
rows="6" required="true" placeholder="Votre message..." />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="contenuMessage" />
|
||||
<ui:param name="label" value="Message" />
|
||||
<ui:param name="value" value="#{membreListeBean.contenuMessage}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="6" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="canauxMessage" value="Canaux de diffusion" />
|
||||
<p:selectCheckboxMenu id="canauxMessage" value="#{membreListeBean.canauxMessage}"
|
||||
multiple="true">
|
||||
multiple="true" styleClass="w-full">
|
||||
<f:selectItem itemLabel="📧 Email" itemValue="EMAIL" />
|
||||
<f:selectItem itemLabel="📱 SMS" itemValue="SMS" />
|
||||
<f:selectItem itemLabel="💬 WhatsApp" itemValue="WHATSAPP" />
|
||||
|
||||
@@ -1,26 +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/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">UnionFlow - Nouveau membre</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>Nouveau membre</h2>
|
||||
<p>Inscription d'un nouveau membre</p>
|
||||
|
||||
<p:button value="Retour au tableau de bord"
|
||||
icon="pi pi-arrow-left"
|
||||
outcome="/pages/secure/dashboard"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -85,22 +85,30 @@
|
||||
<!-- Actions principales -->
|
||||
<h:form id="formActionsPrincipales">
|
||||
<div class="flex flex-column gap-2">
|
||||
<p:commandButton value="Modifier"
|
||||
icon="pi pi-pencil"
|
||||
styleClass="ui-button-outlined ui-button-warning"
|
||||
onclick="PF('dlgModifierProfil').show();" />
|
||||
<p:commandButton value="Cotisations"
|
||||
icon="pi pi-dollar"
|
||||
styleClass="ui-button-outlined ui-button-success"
|
||||
action="#{membreProfilBean.gererCotisations}" />
|
||||
<p:commandButton value="Contacter"
|
||||
icon="pi pi-envelope"
|
||||
styleClass="ui-button-outlined ui-button-info"
|
||||
onclick="PF('dlgContacter').show();" />
|
||||
<p:commandButton value="Actions"
|
||||
icon="pi pi-cog"
|
||||
styleClass="ui-button-outlined ui-button-secondary"
|
||||
onclick="PF('dlgActions').show();" />
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Modifier" />
|
||||
<ui:param name="icon" value="pi pi-pencil" />
|
||||
<ui:param name="onclick" value="PF('dlgModifierProfil').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Cotisations" />
|
||||
<ui:param name="icon" value="pi pi-dollar" />
|
||||
<ui:param name="action" value="#{membreProfilBean.gererCotisations}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-info.xhtml">
|
||||
<ui:param name="value" value="Contacter" />
|
||||
<ui:param name="icon" value="pi pi-envelope" />
|
||||
<ui:param name="onclick" value="PF('dlgContacter').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Actions" />
|
||||
<ui:param name="icon" value="pi pi-cog" />
|
||||
<ui:param name="onclick" value="PF('dlgActions').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
@@ -282,14 +290,17 @@
|
||||
|
||||
<h:form id="formCotisationsActions">
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Nouveau paiement"
|
||||
icon="pi pi-plus"
|
||||
styleClass="ui-button-success"
|
||||
onclick="PF('dlgNouveauPaiement').show();" />
|
||||
<p:commandButton value="Envoyer rappel"
|
||||
icon="pi pi-bell"
|
||||
styleClass="ui-button-outlined ui-button-warning"
|
||||
action="#{membreProfilBean.envoyerRappelCotisation}" />
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouveau paiement" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="onclick" value="PF('dlgNouveauPaiement').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Envoyer rappel" />
|
||||
<ui:param name="icon" value="pi pi-bell" />
|
||||
<ui:param name="action" value="#{membreProfilBean.envoyerRappelCotisation}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
@@ -430,10 +441,13 @@
|
||||
</p:dataTable>
|
||||
|
||||
<h:form id="formNouvelleDemande">
|
||||
<p:commandButton value="Nouvelle demande"
|
||||
icon="pi pi-plus"
|
||||
styleClass="ui-button-outlined ui-button-success w-full mt-3"
|
||||
onclick="PF('dlgNouvelleDemande').show();" />
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouvelle demande" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="onclick" value="PF('dlgNouvelleDemande').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="styleClass" value="w-full mt-3" />
|
||||
</ui:include>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -483,56 +497,71 @@
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="editPrenom" value="Prénom" />
|
||||
<p:inputText id="editPrenom" value="#{membreProfilBean.membreEdit.prenom}" required="true" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="editPrenom" />
|
||||
<ui:param name="label" value="Prénom" />
|
||||
<ui:param name="value" value="#{membreProfilBean.membreEdit.prenom}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="editNom" value="Nom" />
|
||||
<p:inputText id="editNom" value="#{membreProfilBean.membreEdit.nom}" required="true" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="editNom" />
|
||||
<ui:param name="label" value="Nom" />
|
||||
<ui:param name="value" value="#{membreProfilBean.membreEdit.nom}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="editEmail" value="Email" />
|
||||
<p:inputText id="editEmail" value="#{membreProfilBean.membreEdit.email}" required="true" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="editEmail" />
|
||||
<ui:param name="label" value="Email" />
|
||||
<ui:param name="value" value="#{membreProfilBean.membreEdit.email}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="editTelephone" value="Téléphone" />
|
||||
<p:inputText id="editTelephone" value="#{membreProfilBean.membreEdit.telephone}" required="true" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="editTelephone" />
|
||||
<ui:param name="label" value="Téléphone" />
|
||||
<ui:param name="value" value="#{membreProfilBean.membreEdit.telephone}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="editDateNaissance" value="Date de naissance" />
|
||||
<p:calendar id="editDateNaissance" value="#{membreProfilBean.membreEdit.dateNaissance}"
|
||||
pattern="dd/MM/yyyy" showIcon="true" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="editDateNaissance" />
|
||||
<ui:param name="label" value="Date de naissance" />
|
||||
<ui:param name="value" value="#{membreProfilBean.membreEdit.dateNaissance}" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="editProfession" value="Profession" />
|
||||
<p:inputText id="editProfession" value="#{membreProfilBean.membreEdit.profession}" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="editProfession" />
|
||||
<ui:param name="label" value="Profession" />
|
||||
<ui:param name="value" value="#{membreProfilBean.membreEdit.profession}" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="editAdresse" value="Adresse" />
|
||||
<p:inputTextarea id="editAdresse" value="#{membreProfilBean.membreEdit.adresse}" rows="3" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="editAdresse" />
|
||||
<ui:param name="label" value="Adresse" />
|
||||
<ui:param name="value" value="#{membreProfilBean.membreEdit.adresse}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<p:commandButton value="Enregistrer" icon="pi pi-check"
|
||||
styleClass="ui-button-success"
|
||||
action="#{membreProfilBean.sauvegarderModifications}"
|
||||
update="@form"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgModifierProfil').hide();" />
|
||||
<p:commandButton value="Annuler" icon="pi pi-times"
|
||||
styleClass="ui-button-secondary"
|
||||
onclick="PF('dlgModifierProfil').hide();" type="button" />
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Enregistrer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{membreProfilBean.sauvegarderModifications}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgModifierProfil').hide();" />
|
||||
</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('dlgModifierProfil').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
@@ -10,95 +10,59 @@
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h3 class="mb-2">
|
||||
<i class="pi pi-search text-blue-500 mr-2"></i>
|
||||
Recherche Avancée des Membres
|
||||
</h3>
|
||||
<p class="text-600 m-0">Outil de recherche puissant pour retrouver et analyser les membres</p>
|
||||
</div>
|
||||
<h:form id="formActionsEntete">
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Recherches sauvegardées"
|
||||
icon="pi pi-bookmark"
|
||||
styleClass="ui-button-outlined ui-button-info"
|
||||
onclick="PF('dlgRecherchesSauvegardees').show();" />
|
||||
<p:commandButton value="Nouvelle recherche"
|
||||
icon="pi pi-plus"
|
||||
styleClass="ui-button-outlined ui-button-success"
|
||||
action="#{membreRechercheBean.nouvelleRecherche}" />
|
||||
</div>
|
||||
</h:form>
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-search text-blue-500" />
|
||||
<ui:param name="title" value="Recherche Avancée des Membres" />
|
||||
<ui:param name="description" value="Outil de recherche puissant pour retrouver et analyser les membres" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsEntete">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-info.xhtml">
|
||||
<ui:param name="value" value="Recherches sauvegardées" />
|
||||
<ui:param name="icon" value="pi pi-bookmark" />
|
||||
<ui:param name="onclick" value="PF('dlgRecherchesSauvegardees').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Nouvelle recherche" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.nouvelleRecherche}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques de recherche -->
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="card bg-blue-100 border-left-3 border-blue-500">
|
||||
<div class="flex justify-content-between">
|
||||
<div>
|
||||
<div class="text-blue-900 font-bold text-xl">#{membreRechercheBean.statistiques.totalMembres}</div>
|
||||
<div class="text-blue-700">Total Membres</div>
|
||||
</div>
|
||||
<div class="bg-blue-500 text-white border-round text-center"
|
||||
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
|
||||
<i class="pi pi-users text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="card bg-green-100 border-left-3 border-green-500">
|
||||
<div class="flex justify-content-between">
|
||||
<div>
|
||||
<div class="text-green-900 font-bold text-xl">#{membreRechercheBean.statistiques.resultatsActuels}</div>
|
||||
<div class="text-green-700">Résultats trouvés</div>
|
||||
</div>
|
||||
<div class="bg-green-500 text-white border-round text-center"
|
||||
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
|
||||
<i class="pi pi-check text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="card bg-orange-100 border-left-3 border-orange-500">
|
||||
<div class="flex justify-content-between">
|
||||
<div>
|
||||
<div class="text-orange-900 font-bold text-xl">#{membreRechercheBean.statistiques.filtresActifs}</div>
|
||||
<div class="text-orange-700">Filtres actifs</div>
|
||||
</div>
|
||||
<div class="bg-orange-500 text-white border-round text-center"
|
||||
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
|
||||
<i class="pi pi-filter text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="card bg-purple-100 border-left-3 border-purple-500">
|
||||
<div class="flex justify-content-between">
|
||||
<div>
|
||||
<div class="text-purple-900 font-bold text-xl">#{membreRechercheBean.statistiques.tempsRecherche}ms</div>
|
||||
<div class="text-purple-700">Temps de recherche</div>
|
||||
</div>
|
||||
<div class="bg-purple-500 text-white border-round text-center"
|
||||
style="width: 2.5rem; height: 2.5rem; line-height: 2.5rem;">
|
||||
<i class="pi pi-clock text-lg"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreRechercheBean.statistiques.totalMembres}" />
|
||||
<ui:param name="label" value="Total Membres" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreRechercheBean.statistiques.resultatsActuels}" />
|
||||
<ui:param name="label" value="Résultats trouvés" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreRechercheBean.statistiques.filtresActifs}" />
|
||||
<ui:param name="label" value="Filtres actifs" />
|
||||
<ui:param name="icon" value="pi pi-filter" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{membreRechercheBean.statistiques.tempsRecherche}ms" />
|
||||
<ui:param name="label" value="Temps de recherche" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Formulaire de recherche avancée -->
|
||||
@@ -115,65 +79,58 @@
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchNom" value="Nom" />
|
||||
<p:inputText id="searchNom" value="#{membreRechercheBean.filtres.nom}"
|
||||
placeholder="Rechercher par nom...">
|
||||
<p:ajax event="keyup" update="dtResultats @(.search-summary)" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="searchNom" />
|
||||
<ui:param name="label" value="Nom" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.nom}" />
|
||||
<ui:param name="placeholder" value="Rechercher par nom..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchPrenom" value="Prénom" />
|
||||
<p:inputText id="searchPrenom" value="#{membreRechercheBean.filtres.prenom}"
|
||||
placeholder="Rechercher par prénom...">
|
||||
<p:ajax event="keyup" update="dtResultats @(.search-summary)" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="searchPrenom" />
|
||||
<ui:param name="label" value="Prénom" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.prenom}" />
|
||||
<ui:param name="placeholder" value="Rechercher par prénom..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchEmail" value="Email" />
|
||||
<p:inputText id="searchEmail" value="#{membreRechercheBean.filtres.email}"
|
||||
placeholder="Rechercher par email...">
|
||||
<p:ajax event="keyup" update="dtResultats @(.search-summary)" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="searchEmail" />
|
||||
<ui:param name="label" value="Email" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.email}" />
|
||||
<ui:param name="placeholder" value="Rechercher par email..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchTelephone" value="Téléphone" />
|
||||
<p:inputText id="searchTelephone" value="#{membreRechercheBean.filtres.telephone}"
|
||||
placeholder="Rechercher par téléphone...">
|
||||
<p:ajax event="keyup" update="dtResultats @(.search-summary)" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="searchTelephone" />
|
||||
<ui:param name="label" value="Téléphone" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.telephone}" />
|
||||
<ui:param name="placeholder" value="Rechercher par téléphone..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchNumeroMembre" value="Numéro membre" />
|
||||
<p:inputText id="searchNumeroMembre" value="#{membreRechercheBean.filtres.numeroMembre}"
|
||||
placeholder="Ex: M2024001">
|
||||
<p:ajax event="keyup" update="dtResultats @(.search-summary)" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="searchNumeroMembre" />
|
||||
<ui:param name="label" value="Numéro membre" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.numeroMembre}" />
|
||||
<ui:param name="placeholder" value="Ex: M2024001" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchProfession" value="Profession" />
|
||||
<p:autoComplete id="searchProfession"
|
||||
value="#{membreRechercheBean.filtres.profession}"
|
||||
completeMethod="#{membreRechercheBean.completerProfessions}"
|
||||
placeholder="Saisir une profession...">
|
||||
<p:ajax event="itemSelect" update="dtResultats @(.search-summary)" />
|
||||
</p:autoComplete>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-autocomplete.xhtml">
|
||||
<ui:param name="id" value="searchProfession" />
|
||||
<ui:param name="label" value="Profession" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.profession}" />
|
||||
<ui:param name="completeMethod" value="#{membreRechercheBean.completerProfessions}" />
|
||||
<ui:param name="placeholder" value="Saisir une profession..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -184,80 +141,76 @@
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchStatut" value="Statut" />
|
||||
<p:selectCheckboxMenu id="searchStatut" value="#{membreRechercheBean.filtres.statuts}"
|
||||
multiple="true">
|
||||
<ui:include src="/templates/components/form-field-checkbox-menu.xhtml">
|
||||
<ui:param name="id" value="searchStatut" />
|
||||
<ui:param name="label" value="Statut" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.statuts}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
|
||||
<f:selectItem itemLabel="Inactif" itemValue="INACTIF" />
|
||||
<f:selectItem itemLabel="Suspendu" itemValue="SUSPENDU" />
|
||||
<f:selectItem itemLabel="Radié" itemValue="RADIE" />
|
||||
<p:ajax update="dtResultats @(.search-summary)" />
|
||||
</p:selectCheckboxMenu>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchTypeMembre" value="Type de membre" />
|
||||
<p:selectCheckboxMenu id="searchTypeMembre" value="#{membreRechercheBean.filtres.typesMembre}"
|
||||
multiple="true">
|
||||
<ui:include src="/templates/components/form-field-checkbox-menu.xhtml">
|
||||
<ui:param name="id" value="searchTypeMembre" />
|
||||
<ui:param name="label" value="Type de membre" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.typesMembre}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
|
||||
<f:selectItem itemLabel="Associé" itemValue="ASSOCIE" />
|
||||
<f:selectItem itemLabel="Bienfaiteur" itemValue="BIENFAITEUR" />
|
||||
<f:selectItem itemLabel="Honoraire" itemValue="HONORAIRE" />
|
||||
<p:ajax update="dtResultats @(.search-summary)" />
|
||||
</p:selectCheckboxMenu>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchEntite" value="Entité" />
|
||||
<p:selectCheckboxMenu id="searchEntite" value="#{membreRechercheBean.filtres.entites}"
|
||||
multiple="true">
|
||||
multiple="true" styleClass="w-full">
|
||||
<f:selectItems value="#{membreRechercheBean.entitesDisponibles}"
|
||||
var="entite"
|
||||
itemLabel="#{entite.nom}"
|
||||
itemValue="#{entite.id}" />
|
||||
<p:ajax update="dtResultats @(.search-summary)" />
|
||||
<p:ajax update=":formResultats:dtResultats @(.search-summary)" />
|
||||
</p:selectCheckboxMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchCotisationStatut" value="Statut cotisations" />
|
||||
<p:selectCheckboxMenu id="searchCotisationStatut" value="#{membreRechercheBean.filtres.statutsCotisation}"
|
||||
multiple="true">
|
||||
<ui:include src="/templates/components/form-field-checkbox-menu.xhtml">
|
||||
<ui:param name="id" value="searchCotisationStatut" />
|
||||
<ui:param name="label" value="Statut cotisations" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.statutsCotisation}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="À jour" itemValue="A_JOUR" />
|
||||
<f:selectItem itemLabel="En retard" itemValue="EN_RETARD" />
|
||||
<f:selectItem itemLabel="Jamais payé" itemValue="JAMAIS_PAYE" />
|
||||
<p:ajax update="dtResultats @(.search-summary)" />
|
||||
</p:selectCheckboxMenu>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="adhesionDateDebut" value="Adhésion après le" />
|
||||
<p:calendar id="adhesionDateDebut" value="#{membreRechercheBean.filtres.dateAdhesionDebut}"
|
||||
pattern="dd/MM/yyyy" showIcon="true">
|
||||
<p:ajax event="dateSelect" update="dtResultats @(.search-summary)" />
|
||||
</p:calendar>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="adhesionDateDebut" />
|
||||
<ui:param name="label" value="Adhésion après le" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.dateAdhesionDebut}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="adhesionDateFin" value="Adhésion avant le" />
|
||||
<p:calendar id="adhesionDateFin" value="#{membreRechercheBean.filtres.dateAdhesionFin}"
|
||||
pattern="dd/MM/yyyy" showIcon="true">
|
||||
<p:ajax event="dateSelect" update="dtResultats @(.search-summary)" />
|
||||
</p:calendar>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="adhesionDateFin" />
|
||||
<ui:param name="label" value="Adhésion avant le" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.dateAdhesionFin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -268,47 +221,43 @@
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchGenre" value="Genre" />
|
||||
<p:selectCheckboxMenu id="searchGenre" value="#{membreRechercheBean.filtres.genres}"
|
||||
multiple="true">
|
||||
<ui:include src="/templates/components/form-field-checkbox-menu.xhtml">
|
||||
<ui:param name="id" value="searchGenre" />
|
||||
<ui:param name="label" value="Genre" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.genres}" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Masculin" itemValue="M" />
|
||||
<f:selectItem itemLabel="Féminin" itemValue="F" />
|
||||
<p:ajax update="dtResultats @(.search-summary)" />
|
||||
</p:selectCheckboxMenu>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="ageMin" value="Âge minimum" />
|
||||
<p:inputNumber id="ageMin" value="#{membreRechercheBean.filtres.ageMin}"
|
||||
symbol="" placeholder="Ex: 25">
|
||||
<p:ajax event="change" update="dtResultats @(.search-summary)" />
|
||||
</p:inputNumber>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="ageMin" />
|
||||
<ui:param name="label" value="Âge minimum" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.ageMin}" />
|
||||
<ui:param name="placeholder" value="Ex: 25" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="ageMax" value="Âge maximum" />
|
||||
<p:inputNumber id="ageMax" value="#{membreRechercheBean.filtres.ageMax}"
|
||||
symbol="" placeholder="Ex: 65">
|
||||
<p:ajax event="change" update="dtResultats @(.search-summary)" />
|
||||
</p:inputNumber>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="ageMax" />
|
||||
<ui:param name="label" value="Âge maximum" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.ageMax}" />
|
||||
<ui:param name="placeholder" value="Ex: 65" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel for="searchVille" value="Ville" />
|
||||
<p:autoComplete id="searchVille"
|
||||
value="#{membreRechercheBean.filtres.ville}"
|
||||
completeMethod="#{membreRechercheBean.completerVilles}"
|
||||
placeholder="Saisir une ville...">
|
||||
<p:ajax event="itemSelect" update="dtResultats @(.search-summary)" />
|
||||
</p:autoComplete>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-autocomplete.xhtml">
|
||||
<ui:param name="id" value="searchVille" />
|
||||
<ui:param name="label" value="Ville" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.ville}" />
|
||||
<ui:param name="completeMethod" value="#{membreRechercheBean.completerVilles}" />
|
||||
<ui:param name="placeholder" value="Saisir une ville..." />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -319,51 +268,45 @@
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="tauxParticipationMin" value="Taux participation min (%)" />
|
||||
<p:inputNumber id="tauxParticipationMin" value="#{membreRechercheBean.filtres.tauxParticipationMin}"
|
||||
symbol="" minValue="0" maxValue="100">
|
||||
<p:ajax event="change" update="dtResultats @(.search-summary)" />
|
||||
</p:inputNumber>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="tauxParticipationMin" />
|
||||
<ui:param name="label" value="Taux participation min (%)" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.tauxParticipationMin}" />
|
||||
<ui:param name="minValue" value="0" />
|
||||
<ui:param name="maxValue" value="100" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="evenementsMin" value="Événements min (cette année)" />
|
||||
<p:inputNumber id="evenementsMin" value="#{membreRechercheBean.filtres.evenementsMin}"
|
||||
symbol="">
|
||||
<p:ajax event="change" update="dtResultats @(.search-summary)" />
|
||||
</p:inputNumber>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="evenementsMin" />
|
||||
<ui:param name="label" value="Événements min (cette année)" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.evenementsMin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="cotisationsMin" value="Cotisations payées min" />
|
||||
<p:inputNumber id="cotisationsMin" value="#{membreRechercheBean.filtres.cotisationsMin}"
|
||||
symbol="">
|
||||
<p:ajax event="change" update="dtResultats @(.search-summary)" />
|
||||
</p:inputNumber>
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="cotisationsMin" />
|
||||
<ui:param name="label" value="Cotisations payées min" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.cotisationsMin}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="aDesEnfants" value="#{membreRechercheBean.filtres.aDesEnfants}">
|
||||
<p:ajax update="dtResultats @(.search-summary)" />
|
||||
</p:selectBooleanCheckbox>
|
||||
<p:outputLabel for="aDesEnfants" value=" A des enfants déclarés" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-boolean.xhtml">
|
||||
<ui:param name="id" value="aDesEnfants" />
|
||||
<ui:param name="label" value=" A des enfants déclarés" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.aDesEnfants}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="aRecuAides" value="#{membreRechercheBean.filtres.aRecuAides}">
|
||||
<p:ajax update="dtResultats @(.search-summary)" />
|
||||
</p:selectBooleanCheckbox>
|
||||
<p:outputLabel for="aRecuAides" value=" A reçu des aides" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-boolean.xhtml">
|
||||
<ui:param name="id" value="aRecuAides" />
|
||||
<ui:param name="label" value=" A reçu des aides" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.filtres.aRecuAides}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -372,25 +315,32 @@
|
||||
|
||||
<!-- Actions de recherche -->
|
||||
<div class="flex gap-2 mt-4">
|
||||
<p:commandButton value="Rechercher"
|
||||
icon="pi pi-search"
|
||||
styleClass="ui-button-success"
|
||||
action="#{membreRechercheBean.effectuerRecherche}"
|
||||
update="dtResultats @(.search-summary)" />
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="ui-button-outlined ui-button-secondary"
|
||||
action="#{membreRechercheBean.reinitialiserFiltres}"
|
||||
update="@form dtResultats @(.search-summary)" />
|
||||
<p:commandButton value="Sauvegarder recherche"
|
||||
icon="pi pi-bookmark"
|
||||
styleClass="ui-button-outlined ui-button-info"
|
||||
onclick="PF('dlgSauvegarderRecherche').show();" />
|
||||
<p:commandButton value="Exporter résultats"
|
||||
icon="pi pi-download"
|
||||
styleClass="ui-button-outlined ui-button-warning"
|
||||
onclick="PF('dlgExporterResultats').show();"
|
||||
disabled="#{empty membreRechercheBean.resultats}" />
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Rechercher" />
|
||||
<ui:param name="icon" value="pi pi-search" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.effectuerRecherche}" />
|
||||
<ui:param name="update" value=":formResultats:dtResultats @(.search-summary)" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="@form :formResultats:dtResultats @(.search-summary)" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-info.xhtml">
|
||||
<ui:param name="value" value="Sauvegarder recherche" />
|
||||
<ui:param name="icon" value="pi pi-bookmark" />
|
||||
<ui:param name="onclick" value="PF('dlgSauvegarderRecherche').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Exporter résultats" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="onclick" value="PF('dlgExporterResultats').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreRechercheBean.resultats}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
@@ -439,15 +389,23 @@
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span>Liste des membres</span>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton icon="pi pi-refresh"
|
||||
styleClass="ui-button-rounded ui-button-outlined ui-button-secondary"
|
||||
action="#{membreRechercheBean.actualiserResultats}"
|
||||
update="@form"
|
||||
title="Actualiser" />
|
||||
<p:commandButton icon="pi pi-cog"
|
||||
styleClass="ui-button-rounded ui-button-outlined ui-button-secondary"
|
||||
onclick="PF('dlgOptionsAffichage').show();"
|
||||
title="Options d'affichage" />
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.actualiserResultats}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-cog" />
|
||||
<ui:param name="onclick" value="PF('dlgOptionsAffichage').show();" />
|
||||
<ui:param name="title" value="Options d'affichage" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</f:facet>
|
||||
@@ -520,18 +478,29 @@
|
||||
|
||||
<p:column headerText="Actions" style="width:150px">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-info"
|
||||
action="#{membreRechercheBean.voirProfil(membre)}"
|
||||
title="Voir profil" />
|
||||
<p:commandButton icon="pi pi-envelope"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-secondary"
|
||||
action="#{membreRechercheBean.contacterMembre(membre)}"
|
||||
title="Contacter" />
|
||||
<p:commandButton icon="pi pi-plus"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-success"
|
||||
onclick="#{membreRechercheBean.ajouterAuGroupe(membre)}"
|
||||
title="Ajouter au groupe de travail" />
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-eye" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.voirProfil(membre)}" />
|
||||
<ui:param name="title" value="Voir profil" />
|
||||
<ui:param name="severity" value="info" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-envelope" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.contacterMembre(membre)}" />
|
||||
<ui:param name="title" value="Contacter" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.ajouterAuGroupe(membre)}" />
|
||||
<ui:param name="title" value="Ajouter au groupe de travail" />
|
||||
<ui:param name="severity" value="success" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
@@ -542,21 +511,27 @@
|
||||
<span class="text-600">#{membreRechercheBean.selectedMembres.size()} membre(s) sélectionné(s)</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Envoyer message groupé"
|
||||
icon="pi pi-envelope"
|
||||
styleClass="ui-button-outlined ui-button-info"
|
||||
onclick="PF('dlgMessageGroupe').show();"
|
||||
disabled="#{empty membreRechercheBean.selectedMembres}" />
|
||||
<p:commandButton value="Créer groupe de travail"
|
||||
icon="pi pi-users"
|
||||
styleClass="ui-button-outlined ui-button-success"
|
||||
onclick="PF('dlgCreerGroupe').show();"
|
||||
disabled="#{empty membreRechercheBean.selectedMembres}" />
|
||||
<p:commandButton value="Exporter sélection"
|
||||
icon="pi pi-file-excel"
|
||||
styleClass="ui-button-outlined ui-button-warning"
|
||||
action="#{membreRechercheBean.exporterSelection}"
|
||||
disabled="#{empty membreRechercheBean.selectedMembres}" />
|
||||
<ui:include src="/templates/components/button-info.xhtml">
|
||||
<ui:param name="value" value="Envoyer message groupé" />
|
||||
<ui:param name="icon" value="pi pi-envelope" />
|
||||
<ui:param name="onclick" value="PF('dlgMessageGroupe').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreRechercheBean.selectedMembres}" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Créer groupe de travail" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="onclick" value="PF('dlgCreerGroupe').show();" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreRechercheBean.selectedMembres}" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-warning.xhtml">
|
||||
<ui:param name="value" value="Exporter sélection" />
|
||||
<ui:param name="icon" value="pi pi-file-excel" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.exporterSelection}" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
<ui:param name="disabled" value="#{empty membreRechercheBean.selectedMembres}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
@@ -566,17 +541,20 @@
|
||||
<p:dialog header="Sauvegarder la Recherche" widgetVar="dlgSauvegarderRecherche" modal="true" width="500">
|
||||
<h:form id="formSauvegarderRecherche">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<p:outputLabel for="nomRecherche" value="Nom de la recherche" />
|
||||
<p:inputText id="nomRecherche" value="#{membreRechercheBean.nouvelleRechercheSauvegardee.nom}"
|
||||
required="true" placeholder="Ex: Membres actifs 2024" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="nomRecherche" />
|
||||
<ui:param name="label" value="Nom de la recherche" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.nouvelleRechercheSauvegardee.nom}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Ex: Membres actifs 2024" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="descriptionRecherche" value="Description" />
|
||||
<p:inputTextarea id="descriptionRecherche" value="#{membreRechercheBean.nouvelleRechercheSauvegardee.description}"
|
||||
rows="3" placeholder="Description optionnelle..." />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="descriptionRecherche" />
|
||||
<ui:param name="label" value="Description" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.nouvelleRechercheSauvegardee.description}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="recherchePublique" value="#{membreRechercheBean.nouvelleRechercheSauvegardee.publique}" />
|
||||
@@ -590,14 +568,18 @@
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<p:commandButton value="Sauvegarder" icon="pi pi-check"
|
||||
styleClass="ui-button-success"
|
||||
action="#{membreRechercheBean.sauvegarderRecherche}"
|
||||
update="@form"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgSauvegarderRecherche').hide();" />
|
||||
<p:commandButton value="Annuler" icon="pi pi-times"
|
||||
styleClass="ui-button-secondary"
|
||||
onclick="PF('dlgSauvegarderRecherche').hide();" type="button" />
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Sauvegarder" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.sauvegarderRecherche}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgSauvegarderRecherche').hide();" />
|
||||
</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('dlgSauvegarderRecherche').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
@@ -627,26 +609,36 @@
|
||||
</p:column>
|
||||
<p:column headerText="Actions">
|
||||
<div class="flex gap-1">
|
||||
<p:commandButton icon="pi pi-play"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-success"
|
||||
action="#{membreRechercheBean.chargerRecherche(recherche)}"
|
||||
update=":formRechercheAvancee :formResultats"
|
||||
oncomplete="PF('dlgRecherchesSauvegardees').hide();"
|
||||
title="Charger" />
|
||||
<p:commandButton icon="pi pi-trash"
|
||||
styleClass="ui-button-rounded ui-button-text ui-button-danger"
|
||||
action="#{membreRechercheBean.supprimerRecherche(recherche)}"
|
||||
update="@form"
|
||||
onclick="return confirm('Supprimer cette recherche ?');"
|
||||
title="Supprimer" />
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-play" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.chargerRecherche(recherche)}" />
|
||||
<ui:param name="update" value=":formRechercheAvancee :formResultats" />
|
||||
<ui:param name="onclick" value="PF('dlgRecherchesSauvegardees').hide();" />
|
||||
<ui:param name="title" value="Charger" />
|
||||
<ui:param name="severity" value="success" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-trash" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.supprimerRecherche(recherche)}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="onclick" value="return confirm('Supprimer cette recherche ?');" />
|
||||
<ui:param name="title" value="Supprimer" />
|
||||
<ui:param name="severity" value="danger" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
|
||||
<div class="flex justify-content-end mt-3">
|
||||
<p:commandButton value="Fermer" icon="pi pi-times"
|
||||
styleClass="ui-button-secondary"
|
||||
onclick="PF('dlgRecherchesSauvegardees').hide();" type="button" />
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Fermer" />
|
||||
<ui:param name="icon" value="pi pi-times" />
|
||||
<ui:param name="onclick" value="PF('dlgRecherchesSauvegardees').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
@@ -655,22 +647,26 @@
|
||||
<p:dialog header="Envoyer un Message Groupé" widgetVar="dlgMessageGroupe" modal="true" width="600">
|
||||
<h:form id="formMessageGroupe">
|
||||
<div class="ui-fluid">
|
||||
<div class="field">
|
||||
<p:outputLabel for="sujetMessageGroupe" value="Sujet" />
|
||||
<p:inputText id="sujetMessageGroupe" value="#{membreRechercheBean.messageGroupe.sujet}"
|
||||
required="true" placeholder="Objet du message" />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="sujetMessageGroupe" />
|
||||
<ui:param name="label" value="Sujet" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.messageGroupe.sujet}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Objet du message" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="contenuMessageGroupe" value="Message" />
|
||||
<p:inputTextarea id="contenuMessageGroupe" value="#{membreRechercheBean.messageGroupe.contenu}"
|
||||
rows="6" required="true" placeholder="Votre message..." />
|
||||
</div>
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="contenuMessageGroupe" />
|
||||
<ui:param name="label" value="Message" />
|
||||
<ui:param name="value" value="#{membreRechercheBean.messageGroupe.contenu}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="6" />
|
||||
</ui:include>
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="canauxMessageGroupe" value="Canaux de diffusion" />
|
||||
<p:selectCheckboxMenu id="canauxMessageGroupe" value="#{membreRechercheBean.messageGroupe.canaux}"
|
||||
multiple="true">
|
||||
multiple="true" styleClass="w-full">
|
||||
<f:selectItem itemLabel="📧 Email" itemValue="EMAIL" />
|
||||
<f:selectItem itemLabel="📱 SMS" itemValue="SMS" />
|
||||
<f:selectItem itemLabel="💬 WhatsApp" itemValue="WHATSAPP" />
|
||||
@@ -685,14 +681,18 @@
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2 mt-3">
|
||||
<p:commandButton value="Envoyer" icon="pi pi-send"
|
||||
styleClass="ui-button-success"
|
||||
action="#{membreRechercheBean.envoyerMessageGroupe}"
|
||||
update="@form"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgMessageGroupe').hide();" />
|
||||
<p:commandButton value="Annuler" icon="pi pi-times"
|
||||
styleClass="ui-button-secondary"
|
||||
onclick="PF('dlgMessageGroupe').hide();" type="button" />
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Envoyer" />
|
||||
<ui:param name="icon" value="pi pi-send" />
|
||||
<ui:param name="action" value="#{membreRechercheBean.envoyerMessageGroupe}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="onclick" value="if(!args.validationFailed) PF('dlgMessageGroupe').hide();" />
|
||||
</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('dlgMessageGroupe').hide();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
@@ -1,20 +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/main-template.xhtml">
|
||||
<ui:define name="title">UnionFlow - Rechercher membre</ui:define>
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h2>Rechercher un membre</h2>
|
||||
<p>Page en cours de développement...</p>
|
||||
<p:button value="Retour" icon="pi pi-arrow-left" outcome="/pages/secure/dashboard"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
@@ -0,0 +1,331 @@
|
||||
<!DOCTYPE html>
|
||||
<html 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">
|
||||
|
||||
<ui:composition template="/templates/main-template.xhtml">
|
||||
<ui:define name="title">Gestion des Organisations</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<h:form id="formOrganisations">
|
||||
<p:messages id="messages" showDetail="true" closable="true"/>
|
||||
|
||||
<!-- En-tête avec statistiques (DRY/WOU: utilisation de stat-card) -->
|
||||
<div class="grid mb-4">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{organisationsBean.totalOrganisations}" />
|
||||
<ui:param name="label" value="Total" />
|
||||
<ui:param name="icon" value="pi pi-building" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{organisationsBean.organisationsActives}" />
|
||||
<ui:param name="label" value="Actives" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{organisationsBean.organisationsInactives}" />
|
||||
<ui:param name="label" value="Inactives" />
|
||||
<ui:param name="icon" value="pi pi-times-circle" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Barre de recherche et filtres (DRY/WOU: utilisation de form-field) -->
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="field">
|
||||
<p:outputLabel for="rechercheGlobale" value="Rechercher" />
|
||||
<p:inputText id="rechercheGlobale"
|
||||
value="#{organisationsBean.rechercheGlobale}"
|
||||
placeholder="Rechercher..."
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup" update="dtOrganisations" listener="#{organisationsBean.appliquerFiltres}" delay="500"/>
|
||||
</p:inputText>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-2">
|
||||
<div class="field">
|
||||
<p:outputLabel for="filtreStatut" value="Statut" />
|
||||
<p:selectOneMenu id="filtreStatut"
|
||||
value="#{organisationsBean.filtreStatut}"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{organisationsBean.statutsSelectItems}" />
|
||||
<p:ajax event="change" update="dtOrganisations" listener="#{organisationsBean.appliquerFiltres}"/>
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-2">
|
||||
<div class="field">
|
||||
<p:outputLabel for="filtreType" value="Type" />
|
||||
<p:selectOneMenu id="filtreType"
|
||||
value="#{organisationsBean.filtreType}"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{organisationsBean.typesSelectItems}" />
|
||||
<p:ajax event="change" update="dtOrganisations" listener="#{organisationsBean.appliquerFiltres}"/>
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Réinitialiser" />
|
||||
<ui:param name="icon" value="pi pi-filter-slash" />
|
||||
<ui:param name="action" value="#{organisationsBean.reinitialiserFiltres}" />
|
||||
<ui:param name="update" value="dtOrganisations rechercheGlobale filtreStatut filtreType" />
|
||||
<ui:param name="styleClass" value="w-full" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-2">
|
||||
<p:commandButton value="Nouvelle"
|
||||
icon="pi pi-plus"
|
||||
action="#{organisationsBean.preparerNouvelleOrganisation}"
|
||||
update=":formNouvelle @form"
|
||||
oncomplete="PF('dlgNouvelle').show();"
|
||||
styleClass="ui-button-success w-full"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Table des organisations -->
|
||||
<div class="card">
|
||||
<h5>Liste des Organisations</h5>
|
||||
<p:dataTable id="dtOrganisations"
|
||||
value="#{organisationsBean.organisationsFiltrees}"
|
||||
var="org"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
paginatorPosition="bottom"
|
||||
emptyMessage="Aucune organisation trouvée"
|
||||
styleClass="table-responsive">
|
||||
|
||||
<p:column headerText="Logo" styleClass="text-center" style="width: 80px;">
|
||||
<i class="pi pi-building text-4xl text-primary"></i>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Nom" sortBy="#{org.nom}" filterBy="#{org.nom}">
|
||||
<h:outputText value="#{org.nom}" styleClass="font-bold"/>
|
||||
<br/>
|
||||
<h:outputText value="#{org.typeLibelle}" styleClass="text-sm text-500"/>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type" sortBy="#{org.typeAssociation}" style="width: 150px;">
|
||||
<p:tag value="#{org.typeLibelle}"
|
||||
severity="#{org.typeAssociation == 'LIONS_CLUB' ? 'info' : 'primary'}"/>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Localisation" style="width: 200px;">
|
||||
<i class="pi pi-map-marker mr-1"></i>
|
||||
<h:outputText value="#{org.ville}, #{org.region}"/>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Membres" styleClass="text-center" style="width: 100px;">
|
||||
<p:tag value="#{org.nombreMembres}" severity="info" icon="pi pi-users"/>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut" sortBy="#{org.statut}" styleClass="text-center" style="width: 100px;">
|
||||
<p:tag value="#{org.statut}"
|
||||
severity="#{org.statut == organisationsBean.statutActive ? 'success' : 'warning'}"
|
||||
icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-check' : 'pi pi-times'}"/>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" styleClass="text-center" style="width: 180px;">
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
title="Modifier"
|
||||
action="#{organisationsBean.setOrganisationSelectionnee(org)}"
|
||||
oncomplete="PF('dlgModifier').show();"
|
||||
update=":formModifier"
|
||||
styleClass="ui-button-rounded ui-button-warning mr-2"/>
|
||||
|
||||
<p:commandButton icon="#{org.statut == organisationsBean.statutActive ? 'pi pi-ban' : 'pi pi-check'}"
|
||||
title="#{org.statut == organisationsBean.statutActive ? 'Désactiver' : 'Activer'}"
|
||||
action="#{organisationsBean.basculerStatutOrganisation(org)}"
|
||||
update="dtOrganisations messages"
|
||||
styleClass="ui-button-rounded #{org.statut == organisationsBean.statutActive ? 'ui-button-secondary' : 'ui-button-success'} mr-2">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Êtes-vous sûr de vouloir #{org.statut == organisationsBean.statutActive ? 'désactiver' : 'activer'} cette organisation ?"
|
||||
icon="pi pi-exclamation-triangle"/>
|
||||
</p:commandButton>
|
||||
|
||||
<p:commandButton icon="pi pi-trash"
|
||||
title="Supprimer"
|
||||
action="#{organisationsBean.supprimerOrganisation(org)}"
|
||||
update="dtOrganisations messages"
|
||||
styleClass="ui-button-rounded ui-button-danger">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Êtes-vous sûr de vouloir supprimer cette organisation ? Cette action est irréversible."
|
||||
icon="pi pi-exclamation-triangle"/>
|
||||
</p:commandButton>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
|
||||
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade" responsive="true" width="350">
|
||||
<p:commandButton value="Non" type="button" styleClass="ui-button-secondary" icon="pi pi-times"
|
||||
onclick="PF('confirmDialog').hide()"/>
|
||||
<p:commandButton value="Oui" type="button" styleClass="ui-button-danger" icon="pi pi-check"/>
|
||||
</p:confirmDialog>
|
||||
</h:form>
|
||||
|
||||
<!-- Dialogue Nouvelle Organisation (DRY/WOU: utilisation de form-dialog) -->
|
||||
<ui:decorate template="/templates/components/form-dialog.xhtml">
|
||||
<ui:param name="dialogId" value="dlgNouvelle" />
|
||||
<ui:param name="header" value="Nouvelle Organisation" />
|
||||
<ui:param name="widgetVar" value="dlgNouvelle" />
|
||||
<ui:param name="formId" value="formNouvelle" />
|
||||
<ui:param name="width" value="800" />
|
||||
<ui:define name="content">
|
||||
<div class="col-12 md:col-8">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="nom" />
|
||||
<ui:param name="label" value="Nom complet *" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.nom}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="type" />
|
||||
<ui:param name="label" value="Type *" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.typeAssociation}" />
|
||||
<ui:param name="items" value="#{organisationsBean.typesSelectItemsForForm}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="email" />
|
||||
<ui:param name="label" value="Email *" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.email}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="telephone" />
|
||||
<ui:param name="label" value="Téléphone" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.telephone}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="ville" />
|
||||
<ui:param name="label" value="Ville *" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.ville}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="region" />
|
||||
<ui:param name="label" value="Région" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.region}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="pays" />
|
||||
<ui:param name="label" value="Pays" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.pays}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="description" />
|
||||
<ui:param name="label" value="Description" />
|
||||
<ui:param name="value" value="#{organisationsBean.nouvelleOrganisation.description}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</ui:define>
|
||||
<ui:define name="footer">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgNouvelle').hide();"
|
||||
styleClass="ui-button-secondary"/>
|
||||
<p:commandButton value="Créer"
|
||||
icon="pi pi-check"
|
||||
action="#{organisationsBean.creerOrganisation}"
|
||||
update=":formOrganisations:dtOrganisations :formOrganisations:messages"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgNouvelle').hide();"
|
||||
styleClass="ui-button-success"/>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
|
||||
<!-- Dialogue Modifier Organisation (DRY/WOU: utilisation de form-dialog) -->
|
||||
<ui:decorate template="/templates/components/form-dialog.xhtml">
|
||||
<ui:param name="dialogId" value="dlgModifier" />
|
||||
<ui:param name="header" value="Modifier Organisation" />
|
||||
<ui:param name="widgetVar" value="dlgModifier" />
|
||||
<ui:param name="formId" value="formModifier" />
|
||||
<ui:param name="width" value="800" />
|
||||
<ui:define name="content">
|
||||
<ui:fragment rendered="#{organisationsBean.organisationSelectionnee != null}">
|
||||
<div class="col-12 md:col-8">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="nomMod" />
|
||||
<ui:param name="label" value="Nom complet *" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationSelectionnee.nom}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="emailMod" />
|
||||
<ui:param name="label" value="Email *" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationSelectionnee.email}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="telephoneMod" />
|
||||
<ui:param name="label" value="Téléphone" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationSelectionnee.telephone}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="villeMod" />
|
||||
<ui:param name="label" value="Ville *" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationSelectionnee.ville}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="regionMod" />
|
||||
<ui:param name="label" value="Région" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationSelectionnee.region}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="descriptionMod" />
|
||||
<ui:param name="label" value="Description" />
|
||||
<ui:param name="value" value="#{organisationsBean.organisationSelectionnee.description}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</ui:fragment>
|
||||
</ui:define>
|
||||
<ui:define name="footer">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgModifier').hide();"
|
||||
styleClass="ui-button-secondary"/>
|
||||
<p:commandButton value="Enregistrer"
|
||||
icon="pi pi-check"
|
||||
action="#{organisationsBean.modifierOrganisation}"
|
||||
update=":formOrganisations:dtOrganisations :formOrganisations:messages"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgModifier').hide();"
|
||||
styleClass="ui-button-success"/>
|
||||
</ui:define>
|
||||
</ui:decorate>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
</html>
|
||||
@@ -9,417 +9,91 @@
|
||||
<ui:define name="title">Mes Activités - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-history text-purple-500" />
|
||||
<ui:param name="title" value="Mes Activités" />
|
||||
<ui:param name="description" value="Suivez toutes vos interactions et participations dans UnionFlow" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Filtrer" />
|
||||
<ui:param name="icon" value="pi pi-filter" />
|
||||
<ui:param name="onclick" value="PF('dlgFiltres').show();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques d'activité -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.actionsRealisees}" />
|
||||
<ui:param name="label" value="Actions Totales" />
|
||||
<ui:param name="subLabel" value="Toutes périodes" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<!-- En-tête -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.evenementsParticipes}" />
|
||||
<ui:param name="label" value="Événements" />
|
||||
<ui:param name="subLabel" value="Participés" />
|
||||
<ui:param name="icon" value="pi pi-calendar" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.tauxParticipation}%" />
|
||||
<ui:param name="label" value="Taux Participation" />
|
||||
<ui:param name="subLabel" value="Global" />
|
||||
<ui:param name="icon" value="pi pi-chart-line" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="8h" />
|
||||
<ui:param name="label" value="Temps Connecté" />
|
||||
<ui:param name="subLabel" value="Cette semaine" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Activités récentes -->
|
||||
<div class="card">
|
||||
<h5>Activités Récentes</h5>
|
||||
|
||||
<ui:repeat value="#{personnelBean.activitesRecentes}" var="activite">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-#{activite.couleur}-100 flex align-items-center justify-content-center">
|
||||
<i class="pi #{activite.icon} text-#{activite.couleur}-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-900 font-bold text-4xl mb-2">
|
||||
<i class="pi pi-history text-purple-500 mr-3"></i>
|
||||
Mes Activités
|
||||
</h2>
|
||||
<p class="text-600 text-lg mb-0">
|
||||
Suivez toutes vos interactions et participations dans UnionFlow
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Exporter"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-download" />
|
||||
<p:commandButton value="Filtrer"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-filter" />
|
||||
<h6 class="text-900 font-semibold mb-1">#{activite.titre}</h6>
|
||||
<p class="text-600 text-sm mb-0">#{activite.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistiques d'activité -->
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">247</div>
|
||||
<div class="text-900 font-semibold mb-1">Actions Totales</div>
|
||||
<div class="text-600 text-sm">Toutes périodes</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">34</div>
|
||||
<div class="text-900 font-semibold mb-1">Ce Mois-ci</div>
|
||||
<div class="text-600 text-sm">Janvier 2024</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">15</div>
|
||||
<div class="text-900 font-semibold mb-1">Événements</div>
|
||||
<div class="text-600 text-sm">Participés</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">8h</div>
|
||||
<div class="text-900 font-semibold mb-1">Temps Connectée</div>
|
||||
<div class="text-600 text-sm">Cette semaine</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-900 font-semibold text-sm">#{activite.dateHeure}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
|
||||
<div class="text-center text-600 text-sm" rendered="#{empty personnelBean.activitesRecentes}">
|
||||
Aucune activité récente
|
||||
</div>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h:form id="filtresForm">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="typeActivite" class="block text-900 font-semibold mb-2">Type d'activité</label>
|
||||
<p:selectOneMenu id="typeActivite" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes les activités" itemValue="" />
|
||||
<f:selectItem itemLabel="Connexions" itemValue="connexion" />
|
||||
<f:selectItem itemLabel="Modifications" itemValue="modification" />
|
||||
<f:selectItem itemLabel="Événements" itemValue="evenement" />
|
||||
<f:selectItem itemLabel="Paiements" itemValue="paiement" />
|
||||
<f:selectItem itemLabel="Documents" itemValue="document" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="periodeActivite" class="block text-900 font-semibold mb-2">Période</label>
|
||||
<p:selectOneMenu id="periodeActivite" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes les périodes" itemValue="" />
|
||||
<f:selectItem itemLabel="Aujourd'hui" itemValue="aujourdhui" />
|
||||
<f:selectItem itemLabel="Cette semaine" itemValue="semaine" />
|
||||
<f:selectItem itemLabel="Ce mois-ci" itemValue="mois" />
|
||||
<f:selectItem itemLabel="3 derniers mois" itemValue="trimestre" />
|
||||
<f:selectItem itemLabel="Cette année" itemValue="annee" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="statutActivite" class="block text-900 font-semibold mb-2">Statut</label>
|
||||
<p:selectOneMenu id="statutActivite" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="Réussie" itemValue="reussie" />
|
||||
<f:selectItem itemLabel="Échouée" itemValue="echec" />
|
||||
<f:selectItem itemLabel="En attente" itemValue="attente" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="rechercheActivite" class="block text-900 font-semibold mb-2">Rechercher</label>
|
||||
<p:inputText id="rechercheActivite"
|
||||
placeholder="Action, détail..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activités récentes -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-clock mr-2"></i>
|
||||
Activités Récentes
|
||||
</h4>
|
||||
|
||||
<!-- Activité 1 - Connexion -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-green-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-sign-in text-green-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Connexion au système</h6>
|
||||
<p class="text-600 text-sm mb-1">Connexion réussie depuis Chrome sur Windows</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="RÉUSSIE" severity="success" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">IP: 192.168.1.45</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-900 font-semibold text-sm">il y a 2 heures</div>
|
||||
<div class="text-600 text-xs">18 jan. 2024, 14:30</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activité 2 - Modification profil -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-blue-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-user-edit text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Modification du profil</h6>
|
||||
<p class="text-600 text-sm mb-1">Mise à jour du numéro de téléphone</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="MODIFIÉ" severity="info" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">Champ: Téléphone</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-900 font-semibold text-sm">il y a 1 jour</div>
|
||||
<div class="text-600 text-xs">17 jan. 2024, 09:15</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activité 3 - Participation événement -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-purple-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-calendar text-purple-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Participation à un événement</h6>
|
||||
<p class="text-600 text-sm mb-1">Assemblée Générale Extraordinaire 2024</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="PRÉSENTE" severity="success" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">Durée: 3h 45min</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-900 font-semibold text-sm">il y a 3 jours</div>
|
||||
<div class="text-600 text-xs">15 jan. 2024, 14:00</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activité 4 - Paiement -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-orange-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-credit-card text-orange-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Paiement cotisation</h6>
|
||||
<p class="text-600 text-sm mb-1">Cotisation mensuelle janvier 2024</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="PAYÉ" severity="success" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">Montant: 25,000 FCFA</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-900 font-semibold text-sm">il y a 1 semaine</div>
|
||||
<div class="text-600 text-xs">11 jan. 2024, 16:22</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activité 5 - Téléchargement document -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-cyan-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-download text-cyan-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Téléchargement de document</h6>
|
||||
<p class="text-600 text-sm mb-1">Rapport financier annuel 2023.pdf</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="TÉLÉCHARGÉ" severity="info" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">Taille: 2.4 MB</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-900 font-semibold text-sm">il y a 2 semaines</div>
|
||||
<div class="text-600 text-xs">4 jan. 2024, 11:30</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activité 6 - Création ticket -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-pink-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-ticket text-pink-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Création ticket support</h6>
|
||||
<p class="text-600 text-sm mb-1">Problème d'export Excel des rapports</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="CRÉÉ" severity="warning" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">Ticket #TK-2024-0157</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div class="text-900 font-semibold text-sm">il y a 3 semaines</div>
|
||||
<div class="text-600 text-xs">28 déc. 2023, 15:45</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Graphiques d'activité -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12 lg:col-8">
|
||||
<div class="surface-card border-round p-4 h-full">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-chart-line text-blue-500 mr-2"></i>
|
||||
Évolution de l'Activité
|
||||
</h4>
|
||||
|
||||
<div class="surface-100 p-4 border-round text-center">
|
||||
<div class="text-2xl font-bold text-primary mb-2">📊</div>
|
||||
<div class="text-600">Graphique d'activité par jour</div>
|
||||
<div class="text-500 text-sm mt-2">Derniers 30 jours</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-card border-round p-4 h-full">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-chart-pie text-purple-500 mr-2"></i>
|
||||
Répartition par Type
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<div class="text-center mb-3">
|
||||
<div class="text-xl font-bold text-blue-500">35%</div>
|
||||
<div class="text-600 text-sm">Connexions</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-center mb-3">
|
||||
<div class="text-xl font-bold text-green-500">25%</div>
|
||||
<div class="text-600 text-sm">Événements</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-center mb-3">
|
||||
<div class="text-xl font-bold text-purple-500">20%</div>
|
||||
<div class="text-600 text-sm">Modifications</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-center mb-3">
|
||||
<div class="text-xl font-bold text-orange-500">20%</div>
|
||||
<div class="text-600 text-sm">Autres</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 p-3 border-round mt-3">
|
||||
<h6 class="text-900 font-semibold mb-2">Recommandations</h6>
|
||||
<ul class="list-none p-0 m-0">
|
||||
<li class="flex align-items-start mb-2">
|
||||
<i class="pi pi-check-circle text-green-500 mr-2 mt-1"></i>
|
||||
<span class="text-700 text-sm">Activité régulière détectée</span>
|
||||
</li>
|
||||
<li class="flex align-items-start">
|
||||
<i class="pi pi-info-circle text-blue-500 mr-2 mt-1"></i>
|
||||
<span class="text-700 text-sm">Participez plus aux événements</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sessions de connexion -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-mobile mr-2"></i>
|
||||
Sessions de Connexion
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Session active -->
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-4 border-2 border-green-500">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-desktop text-green-500 text-xl"></i>
|
||||
<h6 class="text-900 font-semibold mb-0">Session Actuelle</h6>
|
||||
</div>
|
||||
<p:tag value="ACTIVE" severity="success" styleClass="text-xs" />
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">Navigateur</div>
|
||||
<div class="text-900 font-semibold text-sm">Chrome 120.0</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">Système</div>
|
||||
<div class="text-900 font-semibold text-sm">Windows 11</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">IP</div>
|
||||
<div class="text-900 font-semibold text-sm">192.168.1.45</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">Début</div>
|
||||
<div class="text-900 font-semibold text-sm">14:30</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Session mobile -->
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-mobile text-blue-500 text-xl"></i>
|
||||
<h6 class="text-900 font-semibold mb-0">Session Mobile</h6>
|
||||
</div>
|
||||
<p:tag value="FERMÉE" severity="secondary" styleClass="text-xs" />
|
||||
</div>
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">Appareil</div>
|
||||
<div class="text-900 font-semibold text-sm">iPhone 14</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">App</div>
|
||||
<div class="text-900 font-semibold text-sm">UnionFlow v2.1</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">Dernière activité</div>
|
||||
<div class="text-900 font-semibold text-sm">il y a 2h</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="text-600 text-sm mb-1">Durée</div>
|
||||
<div class="text-900 font-semibold text-sm">45 min</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-4">
|
||||
<p:commandButton value="Voir Toutes les Sessions"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-eye" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
</ui:composition>
|
||||
|
||||
@@ -9,628 +9,78 @@
|
||||
<ui:define name="title">Mon Agenda - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid">
|
||||
|
||||
<!-- En-tête -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h2 class="text-900 font-bold text-4xl mb-2">
|
||||
<i class="pi pi-calendar text-blue-500 mr-3"></i>
|
||||
Mon Agenda
|
||||
</h2>
|
||||
<p class="text-600 text-lg mb-0">
|
||||
Organisez votre planning et ne manquez aucun événement important
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Synchroniser"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-sync" />
|
||||
<p:commandButton value="Nouvel Événement"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-plus"
|
||||
onclick="PF('nouvelEvenementDialog').show()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation calendrier -->
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<p:commandButton icon="pi pi-chevron-left"
|
||||
styleClass="p-button-outlined p-button-rounded" />
|
||||
<h4 class="text-900 font-bold mb-0">Janvier 2024</h4>
|
||||
<p:commandButton icon="pi pi-chevron-right"
|
||||
styleClass="p-button-outlined p-button-rounded" />
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Aujourd'hui"
|
||||
styleClass="p-button-outlined p-button-sm" />
|
||||
<p:commandButton value="Mois"
|
||||
styleClass="p-button-primary p-button-sm" />
|
||||
<p:commandButton value="Semaine"
|
||||
styleClass="p-button-outlined p-button-sm" />
|
||||
<p:commandButton value="Jour"
|
||||
styleClass="p-button-outlined p-button-sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistiques agenda -->
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">7</div>
|
||||
<div class="text-900 font-semibold mb-1">Cette Semaine</div>
|
||||
<div class="text-600 text-sm">Événements</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">3</div>
|
||||
<div class="text-900 font-semibold mb-1">Aujourd'hui</div>
|
||||
<div class="text-600 text-sm">Rendez-vous</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">15</div>
|
||||
<div class="text-900 font-semibold mb-1">Ce Mois</div>
|
||||
<div class="text-600 text-sm">Total</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">85%</div>
|
||||
<div class="text-900 font-semibold mb-1">Taux Présence</div>
|
||||
<div class="text-600 text-sm">Moyenne</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Vue calendrier et événements -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12 lg:col-8">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-calendar-plus mr-2"></i>
|
||||
Calendrier Mensuel
|
||||
</h4>
|
||||
|
||||
<!-- Calendrier simplifié -->
|
||||
<div class="surface-100 border-round p-4">
|
||||
<!-- En-tête des jours -->
|
||||
<div class="grid mb-2">
|
||||
<div class="col text-center">
|
||||
<div class="text-600 font-semibold text-sm">Lun</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="text-600 font-semibold text-sm">Mar</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="text-600 font-semibold text-sm">Mer</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="text-600 font-semibold text-sm">Jeu</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="text-600 font-semibold text-sm">Ven</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="text-600 font-semibold text-sm">Sam</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="text-600 font-semibold text-sm">Dim</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Semaine 1 -->
|
||||
<div class="grid mb-2">
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">1</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">2</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">3</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-blue-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">4</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">5</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-green-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">6</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">7</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Semaine actuelle -->
|
||||
<div class="grid mb-2">
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">8</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">9</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">10</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-purple-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">11</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">12</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-orange-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">13</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">14</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Semaine avec jour actuel -->
|
||||
<div class="grid mb-2">
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">15</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-red-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">16</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">17</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="bg-primary border-round p-2 cursor-pointer">
|
||||
<div class="text-white font-bold text-sm">18</div>
|
||||
<div class="text-xs text-primary-100">Aujourd'hui</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">19</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-green-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">20</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">21</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dernières semaines -->
|
||||
<div class="grid mb-2">
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">22</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">23</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">24</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">25</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-blue-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">26</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">27</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">28</div>
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-purple-500 mx-auto"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">29</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">30</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
<div class="border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="text-600 text-sm">31</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-center"></div>
|
||||
<div class="col text-center"></div>
|
||||
<div class="col text-center"></div>
|
||||
<div class="col text-center"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Légende -->
|
||||
<div class="flex align-items-center justify-content-center gap-4 mt-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="w-0-75rem h-0-75rem border-circle bg-blue-500"></div>
|
||||
<span class="text-600 text-sm">Réunions</span>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="w-0-75rem h-0-75rem border-circle bg-green-500"></div>
|
||||
<span class="text-600 text-sm">Événements</span>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="w-0-75rem h-0-75rem border-circle bg-purple-500"></div>
|
||||
<span class="text-600 text-sm">Formations</span>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="w-0-75rem h-0-75rem border-circle bg-orange-500"></div>
|
||||
<span class="text-600 text-sm">Personnel</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-card border-round p-4 h-full">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-clock mr-2"></i>
|
||||
Aujourd'hui - 18 Janvier
|
||||
</h4>
|
||||
|
||||
<!-- Événement 1 -->
|
||||
<div class="surface-blue-50 border-left-3 border-blue-500 p-3 mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<h6 class="text-blue-800 font-semibold mb-0">Réunion équipe</h6>
|
||||
<p:tag value="OBLIGATOIRE" severity="info" styleClass="text-xs" />
|
||||
</div>
|
||||
<div class="text-blue-700 text-sm mb-2">14:00 - 16:00</div>
|
||||
<div class="text-blue-600 text-sm">Salle de conférence, 2ème étage</div>
|
||||
</div>
|
||||
|
||||
<!-- Événement 2 -->
|
||||
<div class="surface-green-50 border-left-3 border-green-500 p-3 mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<h6 class="text-green-800 font-semibold mb-0">Formation Excel</h6>
|
||||
<p:tag value="OPTIONNEL" severity="success" styleClass="text-xs" />
|
||||
</div>
|
||||
<div class="text-green-700 text-sm mb-2">16:30 - 18:00</div>
|
||||
<div class="text-green-600 text-sm">En ligne - Lien Zoom dans l'email</div>
|
||||
</div>
|
||||
|
||||
<!-- Événement 3 -->
|
||||
<div class="surface-orange-50 border-left-3 border-orange-500 p-3 mb-4">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<h6 class="text-orange-800 font-semibold mb-0">Rappel personnel</h6>
|
||||
<p:tag value="PRIVÉ" severity="warning" styleClass="text-xs" />
|
||||
</div>
|
||||
<div class="text-orange-700 text-sm mb-2">19:00</div>
|
||||
<div class="text-orange-600 text-sm">Appeler Dr. Diallo pour RDV</div>
|
||||
</div>
|
||||
|
||||
<h6 class="text-900 font-semibold mb-3">Prochains événements</h6>
|
||||
|
||||
<!-- Prochain événement 1 -->
|
||||
<div class="surface-100 border-round p-3 mb-2">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<div class="text-900 font-semibold text-sm">Assemblée Générale</div>
|
||||
<div class="text-600 text-xs">25 janvier, 09:00</div>
|
||||
</div>
|
||||
<i class="pi pi-calendar text-blue-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Prochain événement 2 -->
|
||||
<div class="surface-100 border-round p-3">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<div class="text-900 font-semibold text-sm">Formation Leadership</div>
|
||||
<div class="text-600 text-xs">28 janvier, 14:00</div>
|
||||
</div>
|
||||
<i class="pi pi-graduation-cap text-purple-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Planning de la semaine -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-calendar-times mr-2"></i>
|
||||
Planning de la Semaine
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Lundi -->
|
||||
<div class="col-12 lg:col-7">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<h6 class="text-900 font-semibold mb-3">Lundi 15 Janvier</h6>
|
||||
<div class="surface-red-50 border-left-3 border-red-500 p-2 mb-2">
|
||||
<div class="text-red-800 font-semibold text-sm">10:00 - Cotisation en retard</div>
|
||||
<div class="text-red-600 text-xs">Rappel automatique système</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mardi -->
|
||||
<div class="col-12 lg:col-7">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<h6 class="text-900 font-semibold mb-3">Mardi 16 Janvier</h6>
|
||||
<div class="text-600 text-sm">Aucun événement prévu</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mercredi -->
|
||||
<div class="col-12 lg:col-7">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<h6 class="text-900 font-semibold mb-3">Mercredi 17 Janvier</h6>
|
||||
<div class="text-600 text-sm">Aucun événement prévu</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Jeudi (aujourd'hui) -->
|
||||
<div class="col-12 lg:col-7">
|
||||
<div class="surface-primary-50 border-round p-3 mb-3 border-2 border-primary">
|
||||
<h6 class="text-primary font-bold mb-3">Jeudi 18 Janvier (Aujourd'hui)</h6>
|
||||
<div class="surface-blue-50 border-left-3 border-blue-500 p-2 mb-2">
|
||||
<div class="text-blue-800 font-semibold text-sm">14:00 - Réunion équipe</div>
|
||||
<div class="text-blue-600 text-xs">Salle de conférence</div>
|
||||
</div>
|
||||
<div class="surface-green-50 border-left-3 border-green-500 p-2 mb-2">
|
||||
<div class="text-green-800 font-semibold text-sm">16:30 - Formation Excel</div>
|
||||
<div class="text-green-600 text-xs">En ligne</div>
|
||||
</div>
|
||||
<div class="surface-orange-50 border-left-3 border-orange-500 p-2">
|
||||
<div class="text-orange-800 font-semibold text-sm">19:00 - Rappel personnel</div>
|
||||
<div class="text-orange-600 text-xs">Appel Dr. Diallo</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Vendredi -->
|
||||
<div class="col-12 lg:col-7">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<h6 class="text-900 font-semibold mb-3">Vendredi 19 Janvier</h6>
|
||||
<div class="surface-green-50 border-left-3 border-green-500 p-2">
|
||||
<div class="text-green-800 font-semibold text-sm">15:00 - Célébration nouvel an</div>
|
||||
<div class="text-green-600 text-xs">Événement associatif</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions rapides -->
|
||||
<div class="col-12 lg:col-5">
|
||||
<div class="surface-100 border-round p-4">
|
||||
<h6 class="text-900 font-semibold mb-3">Actions Rapides</h6>
|
||||
|
||||
<p:commandButton value="Synchroniser avec Outlook"
|
||||
styleClass="p-button-outlined w-full mb-2"
|
||||
icon="pi pi-sync" />
|
||||
|
||||
<p:commandButton value="Exporter planning PDF"
|
||||
styleClass="p-button-outlined w-full mb-2"
|
||||
icon="pi pi-download" />
|
||||
|
||||
<p:commandButton value="Partager disponibilités"
|
||||
styleClass="p-button-outlined w-full mb-2"
|
||||
icon="pi pi-share-alt" />
|
||||
|
||||
<p:commandButton value="Configurer rappels"
|
||||
styleClass="p-button-outlined w-full"
|
||||
icon="pi pi-bell" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Calendriers synchronisés -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-sync mr-2"></i>
|
||||
Calendriers Synchronisés
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-microsoft text-3xl text-blue-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Outlook</h6>
|
||||
<p class="text-600 text-sm mb-3">Dernière sync: il y a 15 min</p>
|
||||
<p:tag value="CONNECTÉ" severity="success" styleClass="text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-google text-3xl text-red-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Google Calendar</h6>
|
||||
<p class="text-600 text-sm mb-3">Dernière sync: il y a 2h</p>
|
||||
<p:tag value="CONNECTÉ" severity="success" styleClass="text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-apple text-3xl text-600 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">iCloud</h6>
|
||||
<p class="text-600 text-sm mb-3">Non configuré</p>
|
||||
<p:tag value="DÉCONNECTÉ" severity="secondary" styleClass="text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<i class="pi pi-plus-circle text-3xl text-primary mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Ajouter</h6>
|
||||
<p class="text-600 text-sm mb-3">Nouveau calendrier</p>
|
||||
<p:commandButton value="Configurer"
|
||||
styleClass="p-button-outlined p-button-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Nouvel Événement -->
|
||||
<p:dialog id="nouvelEvenementDialog"
|
||||
widgetVar="nouvelEvenementDialog"
|
||||
header="Créer un Nouvel Événement"
|
||||
modal="true"
|
||||
width="800"
|
||||
styleClass="surface-0">
|
||||
<h:form id="nouvelEvenementForm">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12">
|
||||
<label for="titreEvenement" class="block text-900 font-semibold mb-2">Titre *</label>
|
||||
<p:inputText id="titreEvenement"
|
||||
placeholder="Nom de l'événement"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="dateDebut" class="block text-900 font-semibold mb-2">Date de début *</label>
|
||||
<p:calendar id="dateDebut"
|
||||
showTime="true"
|
||||
pattern="dd/MM/yyyy HH:mm"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="dateFin" class="block text-900 font-semibold mb-2">Date de fin *</label>
|
||||
<p:calendar id="dateFin"
|
||||
showTime="true"
|
||||
pattern="dd/MM/yyyy HH:mm"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="categorieEvenement" class="block text-900 font-semibold mb-2">Catégorie</label>
|
||||
<p:selectOneMenu id="categorieEvenement" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionnez" itemValue="" />
|
||||
<f:selectItem itemLabel="Réunion" itemValue="reunion" />
|
||||
<f:selectItem itemLabel="Formation" itemValue="formation" />
|
||||
<f:selectItem itemLabel="Événement" itemValue="evenement" />
|
||||
<f:selectItem itemLabel="Personnel" itemValue="personnel" />
|
||||
<f:selectItem itemLabel="Rappel" itemValue="rappel" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="prioriteEvenement" class="block text-900 font-semibold mb-2">Priorité</label>
|
||||
<p:selectOneMenu id="prioriteEvenement" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Normale" itemValue="normale" />
|
||||
<f:selectItem itemLabel="Haute" itemValue="haute" />
|
||||
<f:selectItem itemLabel="Urgente" itemValue="urgente" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label for="lieuEvenement" class="block text-900 font-semibold mb-2">Lieu</label>
|
||||
<p:inputText id="lieuEvenement"
|
||||
placeholder="Adresse, salle ou lien de visioconférence"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label for="descriptionEvenement" class="block text-900 font-semibold mb-2">Description</label>
|
||||
<p:inputTextarea id="descriptionEvenement"
|
||||
rows="4"
|
||||
placeholder="Détails de l'événement, ordre du jour..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="rappelEvenement" />
|
||||
<label for="rappelEvenement" class="ml-2">Activer les rappels</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('nouvelEvenementDialog').hide()"
|
||||
type="button" />
|
||||
<p:commandButton value="Créer l'Événement"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-save" />
|
||||
</div>
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-calendar text-blue-500" />
|
||||
<ui:param name="title" value="Mon Agenda" />
|
||||
<ui:param name="description" value="Organisez votre planning et ne manquez aucun événement important" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Synchroniser" />
|
||||
<ui:param name="icon" value="pi pi-sync" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Nouvel Événement" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="onclick" value="PF('nouvelEvenementDialog').show();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques agenda -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="7" />
|
||||
<ui:param name="label" value="Cette Semaine" />
|
||||
<ui:param name="subLabel" value="Événements" />
|
||||
<ui:param name="icon" value="pi pi-calendar" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="3" />
|
||||
<ui:param name="label" value="Aujourd'hui" />
|
||||
<ui:param name="subLabel" value="Rendez-vous" />
|
||||
<ui:param name="icon" value="pi pi-clock" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.evenementsParticipes}" />
|
||||
<ui:param name="label" value="Ce Mois" />
|
||||
<ui:param name="subLabel" value="Total" />
|
||||
<ui:param name="icon" value="pi pi-calendar-times" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.tauxParticipation}%" />
|
||||
<ui:param name="label" value="Taux Présence" />
|
||||
<ui:param name="subLabel" value="Moyenne" />
|
||||
<ui:param name="icon" value="pi pi-chart-bar" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Calendrier -->
|
||||
<div class="card">
|
||||
<h5>Calendrier Mensuel</h5>
|
||||
<p:schedule value="#{evenementsBean.evenementsCalendrier}"
|
||||
widgetVar="scheduleWidget"
|
||||
view="month"
|
||||
locale="fr"
|
||||
timeZone="Africa/Dakar"
|
||||
styleClass="w-full"
|
||||
height="600">
|
||||
<p:ajax event="dateSelect" listener="#{evenementsBean.onDateSelect}" />
|
||||
<p:ajax event="eventSelect" listener="#{evenementsBean.onEventSelect}" />
|
||||
</p:schedule>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
</ui:composition>
|
||||
|
||||
@@ -9,592 +9,137 @@
|
||||
<ui:define name="title">Mes Documents - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-folder text-green-500" />
|
||||
<ui:param name="title" value="Mes Documents" />
|
||||
<ui:param name="description" value="Gérez vos documents personnels et accédez aux fichiers partagés" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Nouveau Dossier" />
|
||||
<ui:param name="icon" value="pi pi-folder-plus" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Télécharger" />
|
||||
<ui:param name="icon" value="pi pi-upload" />
|
||||
<ui:param name="onclick" value="PF('uploadDialog').show();" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques stockage -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.documents != null ? personnelBean.documents.size() : 0}" />
|
||||
<ui:param name="label" value="Documents" />
|
||||
<ui:param name="subLabel" value="Personnels" />
|
||||
<ui:param name="icon" value="pi pi-file" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<!-- En-tête -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h2 class="text-900 font-bold text-4xl mb-2">
|
||||
<i class="pi pi-folder text-green-500 mr-3"></i>
|
||||
Mes Documents
|
||||
</h2>
|
||||
<p class="text-600 text-lg mb-0">
|
||||
Gérez vos documents personnels et accédez aux fichiers partagés
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Nouveau Dossier"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-folder-plus" />
|
||||
<p:commandButton value="Télécharger"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-upload"
|
||||
onclick="PF('uploadDialog').show()" />
|
||||
</div>
|
||||
</div>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="2.4 GB" />
|
||||
<ui:param name="label" value="Utilisé" />
|
||||
<ui:param name="subLabel" value="Sur 5 GB" />
|
||||
<ui:param name="icon" value="pi pi-database" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Statistiques stockage -->
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">67</div>
|
||||
<div class="text-900 font-semibold mb-1">Documents</div>
|
||||
<div class="text-600 text-sm">Personnels</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">2.4 GB</div>
|
||||
<div class="text-900 font-semibold mb-1">Utilisé</div>
|
||||
<div class="text-600 text-sm">Sur 5 GB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">156</div>
|
||||
<div class="text-900 font-semibold mb-1">Partagés</div>
|
||||
<div class="text-600 text-sm">Accès autorisé</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">12</div>
|
||||
<div class="text-900 font-semibold mb-1">En Attente</div>
|
||||
<div class="text-600 text-sm">Validation</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Liste des documents -->
|
||||
<div class="card">
|
||||
<h5>Mes Documents</h5>
|
||||
|
||||
<p:dataTable value="#{personnelBean.documents}" var="document"
|
||||
emptyMessage="Aucun document disponible"
|
||||
styleClass="p-datatable-sm">
|
||||
|
||||
<p:column headerText="Nom">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-file text-lg"></i>
|
||||
<span class="font-semibold">#{document.nom}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation et filtres -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<!-- Fil d'Ariane -->
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-home text-600"></i>
|
||||
<span class="text-600">/</span>
|
||||
<span class="text-primary cursor-pointer">Mes Documents</span>
|
||||
<span class="text-600">/</span>
|
||||
<span class="text-900 font-semibold">Dossier Personnel</span>
|
||||
</div>
|
||||
|
||||
<!-- Options d'affichage -->
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton icon="pi pi-th-large"
|
||||
styleClass="p-button-outlined p-button-sm" />
|
||||
<p:commandButton icon="pi pi-list"
|
||||
styleClass="p-button-primary p-button-sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h:form id="filtresForm">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="typeDocument" class="block text-900 font-semibold mb-2">Type</label>
|
||||
<p:selectOneMenu id="typeDocument" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItem itemLabel="Documents (PDF, DOC)" itemValue="document" />
|
||||
<f:selectItem itemLabel="Images (JPG, PNG)" itemValue="image" />
|
||||
<f:selectItem itemLabel="Tableurs (XLS, CSV)" itemValue="tableur" />
|
||||
<f:selectItem itemLabel="Présentations (PPT)" itemValue="presentation" />
|
||||
<f:selectItem itemLabel="Archives (ZIP, RAR)" itemValue="archive" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="categorieDocument" class="block text-900 font-semibold mb-2">Catégorie</label>
|
||||
<p:selectOneMenu id="categorieDocument" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes les catégories" itemValue="" />
|
||||
<f:selectItem itemLabel="Personnel" itemValue="personnel" />
|
||||
<f:selectItem itemLabel="Professionnel" itemValue="professionnel" />
|
||||
<f:selectItem itemLabel="Association" itemValue="association" />
|
||||
<f:selectItem itemLabel="Formation" itemValue="formation" />
|
||||
<f:selectItem itemLabel="Administratif" itemValue="administratif" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="periodeDocument" class="block text-900 font-semibold mb-2">Période</label>
|
||||
<p:selectOneMenu id="periodeDocument" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes les périodes" itemValue="" />
|
||||
<f:selectItem itemLabel="Aujourd'hui" itemValue="aujourdhui" />
|
||||
<f:selectItem itemLabel="Cette semaine" itemValue="semaine" />
|
||||
<f:selectItem itemLabel="Ce mois-ci" itemValue="mois" />
|
||||
<f:selectItem itemLabel="Cette année" itemValue="annee" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="rechercheDocument" class="block text-900 font-semibold mb-2">Rechercher</label>
|
||||
<p:inputText id="rechercheDocument"
|
||||
placeholder="Nom, contenu..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Type">
|
||||
<span>#{document.type}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date">
|
||||
<span>#{document.dateCreation}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Taille">
|
||||
<span>#{document.taille} bytes</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" styleClass="text-center">
|
||||
<div class="flex justify-content-center gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir"
|
||||
styleClass="p-button-sm p-button-rounded p-button-info" />
|
||||
<p:commandButton icon="pi pi-download"
|
||||
title="Télécharger"
|
||||
styleClass="p-button-sm p-button-rounded p-button-success" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
|
||||
<!-- Accès rapide -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-star mr-2"></i>
|
||||
Accès Rapide
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<i class="pi pi-clock text-3xl text-blue-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Récents</h6>
|
||||
<p class="text-600 text-sm mb-0">Documents modifiés récemment</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<i class="pi pi-share-alt text-3xl text-green-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Partagés</h6>
|
||||
<p class="text-600 text-sm mb-0">Documents partagés avec vous</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<i class="pi pi-star-fill text-3xl text-yellow-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Favoris</h6>
|
||||
<p class="text-600 text-sm mb-0">Vos documents marqués</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<i class="pi pi-trash text-3xl text-red-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Corbeille</h6>
|
||||
<p class="text-600 text-sm mb-0">Documents supprimés</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Arborescence et documents -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-card border-round p-4 h-full">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-sitemap mr-2"></i>
|
||||
Mes Dossiers
|
||||
</h4>
|
||||
|
||||
<!-- Dossier racine -->
|
||||
<div class="surface-100 border-round p-3 mb-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-folder text-blue-500"></i>
|
||||
<span class="text-900 font-semibold text-sm">Documents Personnels</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sous-dossiers -->
|
||||
<div class="ml-3">
|
||||
<div class="surface-100 border-round p-2 mb-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-folder text-green-500"></i>
|
||||
<span class="text-900 text-sm">Certificats</span>
|
||||
<p:tag value="8" severity="info" styleClass="text-xs ml-auto" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-2 mb-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-folder text-purple-500"></i>
|
||||
<span class="text-900 text-sm">Formations</span>
|
||||
<p:tag value="15" severity="info" styleClass="text-xs ml-auto" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-2 mb-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-folder text-orange-500"></i>
|
||||
<span class="text-900 text-sm">Rapports</span>
|
||||
<p:tag value="23" severity="info" styleClass="text-xs ml-auto" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-2 mb-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-folder text-cyan-500"></i>
|
||||
<span class="text-900 text-sm">Images</span>
|
||||
<p:tag value="34" severity="info" styleClass="text-xs ml-auto" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dossiers partagés -->
|
||||
<div class="surface-100 border-round p-3 mb-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-users text-blue-500"></i>
|
||||
<span class="text-900 font-semibold text-sm">Partagés avec moi</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ml-3">
|
||||
<div class="surface-100 border-round p-2 mb-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-share-alt text-green-500"></i>
|
||||
<span class="text-900 text-sm">Équipe Admin</span>
|
||||
<p:tag value="45" severity="success" styleClass="text-xs ml-auto" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-2 cursor-pointer hover:surface-200 transition-duration-200">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-share-alt text-purple-500"></i>
|
||||
<span class="text-900 text-sm">Ressources Communes</span>
|
||||
<p:tag value="78" severity="help" styleClass="text-xs ml-auto" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-9">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-folder-open mr-2"></i>
|
||||
Dossier Personnel / Certificats
|
||||
</h4>
|
||||
|
||||
<!-- Document 1 -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-red-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file-pdf text-red-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Certificat_Formation_Leadership_2023.pdf</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">Modifié le 15 déc. 2023</span>
|
||||
<span class="text-600 text-sm">2.4 MB</span>
|
||||
<p:tag value="PERSONNEL" severity="info" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">
|
||||
Certificat de completion de la formation en leadership obtenu en décembre 2023
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Prévisualiser" />
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-ellipsis-v"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Plus d'options" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Document 2 -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-blue-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Fiche_Adhesion_2024.docx</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">Modifié le 8 jan. 2024</span>
|
||||
<span class="text-600 text-sm">156 KB</span>
|
||||
<p:tag value="ASSOCIATION" severity="success" styleClass="text-xs" />
|
||||
<i class="pi pi-star-fill text-yellow-500" title="Favori"></i>
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">
|
||||
Formulaire d'adhésion pour l'année 2024 avec informations mises à jour
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Prévisualiser" />
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-ellipsis-v"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Plus d'options" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Document 3 -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-green-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file-excel text-green-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Budget_Personnel_2024.xlsx</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">Modifié le 3 jan. 2024</span>
|
||||
<span class="text-600 text-sm">89 KB</span>
|
||||
<p:tag value="PERSONNEL" severity="info" styleClass="text-xs" />
|
||||
<p:tag value="CONFIDENTIEL" severity="danger" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">
|
||||
Feuille de calcul pour la gestion du budget personnel et des cotisations
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Prévisualiser" />
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-ellipsis-v"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Plus d'options" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Document 4 -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-purple-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-image text-purple-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Photo_Evenement_AG2023.jpg</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">Modifié le 28 nov. 2023</span>
|
||||
<span class="text-600 text-sm">3.2 MB</span>
|
||||
<p:tag value="PARTAGÉ" severity="help" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">
|
||||
Photo de groupe prise lors de l'assemblée générale 2023
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Prévisualiser" />
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-ellipsis-v"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Plus d'options" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Document 5 - En attente -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 opacity-70 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-orange-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file text-orange-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Demande_Conge_Janvier.pdf</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">Modifié le 10 jan. 2024</span>
|
||||
<span class="text-600 text-sm">245 KB</span>
|
||||
<p:tag value="EN ATTENTE" severity="warning" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">
|
||||
Demande de congé en attente de validation par l'administrateur
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton icon="pi pi-clock"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="En attente" />
|
||||
<p:commandButton icon="pi pi-ellipsis-v"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Plus d'options" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Utilisation stockage -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-chart-pie mr-2"></i>
|
||||
Utilisation du Stockage
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-8">
|
||||
<!-- Barre de progression -->
|
||||
<div class="mb-4">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-900 font-semibold">Espace utilisé: 2.4 GB sur 5 GB</span>
|
||||
<span class="text-600 text-sm">48% utilisé</span>
|
||||
</div>
|
||||
<div class="surface-300 border-round" style="height: 1rem">
|
||||
<div class="bg-primary border-round h-full" style="width: 48%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Répartition par type -->
|
||||
<div class="grid">
|
||||
<div class="col-6 lg:col-3">
|
||||
<div class="text-center">
|
||||
<div class="text-xl font-bold text-red-500">35%</div>
|
||||
<div class="text-600 text-sm">Documents PDF</div>
|
||||
<div class="text-500 text-xs">840 MB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 lg:col-3">
|
||||
<div class="text-center">
|
||||
<div class="text-xl font-bold text-blue-500">28%</div>
|
||||
<div class="text-600 text-sm">Images</div>
|
||||
<div class="text-500 text-xs">672 MB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 lg:col-3">
|
||||
<div class="text-center">
|
||||
<div class="text-xl font-bold text-green-500">22%</div>
|
||||
<div class="text-600 text-sm">Tableurs</div>
|
||||
<div class="text-500 text-xs">528 MB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6 lg:col-3">
|
||||
<div class="text-center">
|
||||
<div class="text-xl font-bold text-purple-500">15%</div>
|
||||
<div class="text-600 text-sm">Autres</div>
|
||||
<div class="text-500 text-xs">360 MB</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 border-round p-4">
|
||||
<h6 class="text-900 font-semibold mb-3">Optimisations</h6>
|
||||
|
||||
<div class="surface-orange-50 border-left-3 border-orange-500 p-3 mb-3">
|
||||
<h6 class="text-orange-800 font-semibold mb-2">
|
||||
<i class="pi pi-exclamation-triangle mr-2"></i>Attention
|
||||
</h6>
|
||||
<p class="text-orange-700 text-sm mb-0">
|
||||
Vous approchez de la limite de stockage.
|
||||
Supprimez des fichiers ou augmentez votre quota.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p:commandButton value="Nettoyer la corbeille"
|
||||
styleClass="p-button-outlined w-full mb-2"
|
||||
icon="pi pi-trash" />
|
||||
|
||||
<p:commandButton value="Augmenter le quota"
|
||||
styleClass="p-button-primary w-full"
|
||||
icon="pi pi-plus-circle" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Upload -->
|
||||
<!-- Dialog Upload -->
|
||||
<h:form id="formUpload">
|
||||
<p:dialog id="uploadDialog"
|
||||
widgetVar="uploadDialog"
|
||||
header="Télécharger des Documents"
|
||||
modal="true"
|
||||
width="700"
|
||||
styleClass="surface-0">
|
||||
<h:form id="uploadForm" enctype="multipart/form-data">
|
||||
<div class="ui-fluid">
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 700px;">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label for="dossierDestination" class="block text-900 font-semibold mb-2">Dossier de destination</label>
|
||||
<p:outputLabel for="dossierDestination" value="Dossier de destination" />
|
||||
<p:selectOneMenu id="dossierDestination" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Documents Personnels" itemValue="personnel" />
|
||||
<f:selectItem itemLabel="Certificats" itemValue="certificats" />
|
||||
<f:selectItem itemLabel="Formations" itemValue="formations" />
|
||||
<f:selectItem itemLabel="Rapports" itemValue="rapports" />
|
||||
<f:selectItem itemLabel="Images" itemValue="images" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<label for="categorieUpload" class="block text-900 font-semibold mb-2">Catégorie</label>
|
||||
<p:selectOneMenu id="categorieUpload" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Personnel" itemValue="personnel" />
|
||||
<f:selectItem itemLabel="Professionnel" itemValue="professionnel" />
|
||||
<f:selectItem itemLabel="Association" itemValue="association" />
|
||||
<f:selectItem itemLabel="Formation" itemValue="formation" />
|
||||
<f:selectItem itemLabel="Administratif" itemValue="administratif" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="block text-900 font-semibold mb-2">Fichiers à télécharger</label>
|
||||
<p:fileUpload mode="advanced"
|
||||
<p:outputLabel for="fichierUpload" value="Fichier" />
|
||||
<p:fileUpload id="fichierUpload"
|
||||
mode="advanced"
|
||||
multiple="true"
|
||||
uploadLabel="Télécharger"
|
||||
cancelLabel="Annuler"
|
||||
chooseLabel="Choisir les fichiers"
|
||||
dragDropSupport="true"
|
||||
sizeLimit="10485760"
|
||||
allowTypes="/(\.|\/)(gif|jpe?g|png|pdf|docx?|xlsx?|pptx?)$/"
|
||||
styleClass="w-full" />
|
||||
<small class="text-500">Formats acceptés: Images, PDF, Office. Taille max: 10MB par fichier</small>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="descriptionUpload" class="block text-900 font-semibold mb-2">Description (optionnel)</label>
|
||||
<p:inputTextarea id="descriptionUpload"
|
||||
rows="3"
|
||||
placeholder="Description des documents téléchargés..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="partageUpload" />
|
||||
<label for="partageUpload" class="ml-2">Partager avec l'équipe d'administration</label>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('uploadDialog').hide()"
|
||||
type="button" />
|
||||
<p:commandButton value="Télécharger"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-upload" />
|
||||
allowTypes="/(\.|\/)(gif|jpe?g|png|pdf|docx?|xlsx?|pptx?)$/" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('uploadDialog').hide();"
|
||||
type="button" />
|
||||
<p:commandButton value="Télécharger"
|
||||
icon="pi pi-upload"
|
||||
styleClass="p-button-primary"
|
||||
action="#{personnelBean.actualiser}" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
</ui:composition>
|
||||
|
||||
@@ -31,7 +31,10 @@
|
||||
icon="pi pi-sort" />
|
||||
<p:commandButton value="Tout nettoyer"
|
||||
styleClass="p-button-secondary"
|
||||
icon="pi pi-trash" />
|
||||
icon="pi pi-trash"
|
||||
action="#{favorisBean.nettoyerTousFavoris}"
|
||||
update="@form"
|
||||
process="@this" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,28 +42,28 @@
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-yellow-500 mb-2">23</div>
|
||||
<div class="text-2xl font-bold text-yellow-500 mb-2">#{favorisBean.totalFavoris}</div>
|
||||
<div class="text-900 font-semibold mb-1">Favoris</div>
|
||||
<div class="text-600 text-sm">Total</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">8</div>
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">#{favorisBean.totalPages}</div>
|
||||
<div class="text-900 font-semibold mb-1">Pages</div>
|
||||
<div class="text-600 text-sm">Fonctionnalités</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">12</div>
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">#{favorisBean.totalDocuments}</div>
|
||||
<div class="text-900 font-semibold mb-1">Documents</div>
|
||||
<div class="text-600 text-sm">Fichiers</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">3</div>
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">#{favorisBean.totalContacts}</div>
|
||||
<div class="text-900 font-semibold mb-1">Contacts</div>
|
||||
<div class="text-600 text-sm">Personnes</div>
|
||||
</div>
|
||||
@@ -80,21 +83,31 @@
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Favori 1 - Page la plus utilisée -->
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-blue-50 hover:surface-blue-100 border-round p-4 cursor-pointer transition-duration-200 border-2 border-blue-500">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<i class="pi pi-chart-bar text-blue-600 text-2xl"></i>
|
||||
<p:tag value="PLUS UTILISÉ" severity="info" styleClass="text-xs" />
|
||||
</div>
|
||||
<h6 class="text-blue-800 font-bold mb-2">Mes Activités</h6>
|
||||
<p class="text-blue-600 text-sm mb-2">Historique et suivi de vos actions</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-clock text-blue-500"></i>
|
||||
<span class="text-blue-600 text-xs">Utilisé il y a 5 min</span>
|
||||
<ui:repeat value="#{favorisBean.pagesFavorites}" var="page" varStatus="status">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-#{page.couleur}-50 hover:surface-#{page.couleur}-100 border-round p-4 cursor-pointer transition-duration-200 border-2 border-#{page.couleur}-500">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<i class="pi #{page.icon} text-#{page.couleur}-600 text-2xl"></i>
|
||||
<p:tag value="#{page.estPlusUtilise ? 'PLUS UTILISÉ' : ''}" severity="info" styleClass="text-xs" rendered="#{page.estPlusUtilise}" />
|
||||
<i class="pi pi-star-fill text-yellow-500" rendered="#{!page.estPlusUtilise}"></i>
|
||||
</div>
|
||||
<h6 class="text-#{page.couleur}-800 font-bold mb-2">#{page.titre}</h6>
|
||||
<p class="text-#{page.couleur}-600 text-sm mb-2">#{page.description}</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-clock text-#{page.couleur}-500"></i>
|
||||
<span class="text-#{page.couleur}-600 text-xs">#{page.derniereVisite}</span>
|
||||
</div>
|
||||
<div class="flex justify-content-end mt-2">
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Retirer des favoris"
|
||||
action="#{favorisBean.retirerPageFavorite(page.id)}"
|
||||
update="@form"
|
||||
process="@this" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
|
||||
<!-- Favori 2 -->
|
||||
<div class="col-12 lg:col-3">
|
||||
@@ -158,74 +171,32 @@
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Page favorite 1 -->
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<ui:repeat value="#{favorisBean.pagesFavorites}" var="page" varStatus="status">
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi #{page.icon} text-#{page.couleur}-500 text-xl"></i>
|
||||
<h6 class="text-900 font-semibold mb-0">#{page.titre}</h6>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Retirer des favoris"
|
||||
action="#{favorisBean.retirerPageFavorite(page.id)}"
|
||||
update="@form"
|
||||
process="@this" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-2">#{page.description}</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-chart-bar text-blue-500 text-xl"></i>
|
||||
<h6 class="text-900 font-semibold mb-0">Rapports Financiers</h6>
|
||||
<p:tag value="#{page.categorie}" severity="success" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">#{page.nbVisites} visite#{page.nbVisites > 1 ? 's' : ''} cette semaine</span>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Retirer des favoris" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-2">Consultez vos rapports financiers personnels</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="FINANCE" severity="success" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">3 visites cette semaine</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Page favorite 2 -->
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-graduation-cap text-purple-500 text-xl"></i>
|
||||
<h6 class="text-900 font-semibold mb-0">Mes Formations</h6>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Retirer des favoris" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-2">Catalogue et suivi de vos formations</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="FORMATION" severity="help" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">1 visite cette semaine</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Page favorite 3 -->
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-book text-green-500 text-xl"></i>
|
||||
<h6 class="text-900 font-semibold mb-0">Guide Utilisateur</h6>
|
||||
</div>
|
||||
<div class="flex gap-1">
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Retirer des favoris" />
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-600 text-sm mb-2">Documentation et aide à l'utilisation</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="AIDE" severity="info" styleClass="text-xs" />
|
||||
<span class="text-500 text-xs">5 visites cette semaine</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-4">
|
||||
@@ -246,92 +217,38 @@
|
||||
Documents Favoris
|
||||
</h4>
|
||||
|
||||
<!-- Document favori 1 -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-red-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file-pdf text-red-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Certificat_Formation_Leadership_2023.pdf</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">2.4 MB</span>
|
||||
<span class="text-600 text-sm">Ajouté aux favoris le 15 déc. 2023</span>
|
||||
<p:tag value="CERTIFICAT" severity="success" styleClass="text-xs" />
|
||||
<ui:repeat value="#{favorisBean.documentsFavoris}" var="doc">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-red-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file-#{doc.type == 'PDF' ? 'pdf' : doc.type == 'XLSX' ? 'excel' : 'file'} text-red-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">#{doc.nom}</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">#{doc.tailleFormatee}</span>
|
||||
<span class="text-600 text-sm">Ajouté aux favoris le #{doc.dateAjout}</span>
|
||||
<p:tag value="#{doc.categorie}" severity="success" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">#{doc.description}</p>
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">Certification de leadership obtenue en 2023</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<i class="pi pi-star-fill text-yellow-500 text-xl"></i>
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
title="Retirer des favoris" />
|
||||
<div class="flex gap-2">
|
||||
<i class="pi pi-star-fill text-yellow-500 text-xl"></i>
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
title="Retirer des favoris"
|
||||
action="#{favorisBean.retirerDocumentFavorite(doc.id)}"
|
||||
update="@form"
|
||||
process="@this" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Document favori 2 -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-green-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file-excel text-green-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Budget_Personnel_2024.xlsx</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">89 KB</span>
|
||||
<span class="text-600 text-sm">Ajouté aux favoris le 3 jan. 2024</span>
|
||||
<p:tag value="BUDGET" severity="warning" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">Feuille de calcul pour la gestion budgétaire</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<i class="pi pi-star-fill text-yellow-500 text-xl"></i>
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
title="Retirer des favoris" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Document favori 3 -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-blue-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-file text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Reglement_Interieur_2024.docx</h6>
|
||||
<div class="flex align-items-center gap-3 mb-1">
|
||||
<span class="text-600 text-sm">245 KB</span>
|
||||
<span class="text-600 text-sm">Ajouté aux favoris le 28 déc. 2023</span>
|
||||
<p:tag value="RÈGLEMENT" severity="info" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 text-sm mb-0">Règlement intérieur de l'association mis à jour</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<i class="pi pi-star-fill text-yellow-500 text-xl"></i>
|
||||
<p:commandButton icon="pi pi-download"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
title="Télécharger" />
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
title="Retirer des favoris" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -346,71 +263,36 @@
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Contact favori 1 -->
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-blue-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-user text-blue-600 text-xl"></i>
|
||||
<ui:repeat value="#{favorisBean.contactsFavoris}" var="contact">
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-blue-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-user text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">#{contact.nom}</h6>
|
||||
<p class="text-600 text-sm mb-0">#{contact.fonction}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Thomas Martin</h6>
|
||||
<p class="text-600 text-sm mb-0">Président de l'association</p>
|
||||
<div class="flex gap-2">
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
title="Retirer des favoris"
|
||||
action="#{favorisBean.retirerContactFavorite(contact.id)}"
|
||||
update="@form"
|
||||
process="@this" />
|
||||
</div>
|
||||
</div>
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">thomas.martin@email.com</span>
|
||||
<p:tag value="ADMIN" severity="warning" styleClass="text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact favori 2 -->
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-green-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-user text-green-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Sophie Leroy</h6>
|
||||
<p class="text-600 text-sm mb-0">Responsable formations</p>
|
||||
</div>
|
||||
<span class="text-600 text-sm">#{contact.email}</span>
|
||||
<p:tag value="#{contact.categorie}" severity="warning" styleClass="text-xs" />
|
||||
</div>
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">sophie.leroy@email.com</span>
|
||||
<p:tag value="FORMATION" severity="help" styleClass="text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact favori 3 -->
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="w-3rem h-3rem border-circle bg-purple-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-user text-purple-600 text-xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Marc Durand</h6>
|
||||
<p class="text-600 text-sm mb-0">Support technique</p>
|
||||
</div>
|
||||
</div>
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">marc.durand@email.com</span>
|
||||
<p:tag value="SUPPORT" severity="info" styleClass="text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -426,57 +308,28 @@
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Raccourci 1 -->
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<i class="pi pi-bookmark text-blue-500 text-2xl"></i>
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Modifier" />
|
||||
<ui:repeat value="#{favorisBean.raccourcis}" var="racc">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<i class="pi #{racc.icon} text-#{racc.couleur}-500 text-2xl"></i>
|
||||
<p:commandButton icon="pi pi-times"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Supprimer"
|
||||
action="#{favorisBean.supprimerRaccourci(racc.id)}"
|
||||
update="@form"
|
||||
process="@this" />
|
||||
</div>
|
||||
<h6 class="text-900 font-semibold mb-2">#{racc.titre}</h6>
|
||||
<p class="text-600 text-sm mb-3">#{racc.description}</p>
|
||||
<p:commandButton value="Accéder"
|
||||
styleClass="p-button-outlined p-button-sm w-full"
|
||||
icon="pi pi-external-link"
|
||||
onclick="window.location.href='#{racc.url}'; return false;" />
|
||||
</div>
|
||||
<h6 class="text-900 font-semibold mb-2">Nouveau Membre</h6>
|
||||
<p class="text-600 text-sm mb-3">Lien direct vers le formulaire d'inscription</p>
|
||||
<p:commandButton value="Accéder"
|
||||
styleClass="p-button-outlined p-button-sm w-full"
|
||||
icon="pi pi-external-link" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Raccourci 2 -->
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<i class="pi pi-calculator text-green-500 text-2xl"></i>
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Modifier" />
|
||||
</div>
|
||||
<h6 class="text-900 font-semibold mb-2">Calculateur</h6>
|
||||
<p class="text-600 text-sm mb-3">Calcul automatique des cotisations</p>
|
||||
<p:commandButton value="Accéder"
|
||||
styleClass="p-button-outlined p-button-sm w-full"
|
||||
icon="pi pi-external-link" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Raccourci 3 -->
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<i class="pi pi-print text-purple-500 text-2xl"></i>
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
styleClass="p-button-text p-button-sm p-button-rounded"
|
||||
title="Modifier" />
|
||||
</div>
|
||||
<h6 class="text-900 font-semibold mb-2">Impression Rapide</h6>
|
||||
<p class="text-600 text-sm mb-3">Templates prêts à imprimer</p>
|
||||
<p:commandButton value="Accéder"
|
||||
styleClass="p-button-outlined p-button-sm w-full"
|
||||
icon="pi pi-external-link" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ui:repeat>
|
||||
|
||||
<!-- Ajouter nouveau raccourci -->
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 text-center cursor-pointer transition-duration-200 border-dashed border-primary">
|
||||
|
||||
@@ -9,420 +9,90 @@
|
||||
<ui:define name="title">Mes Notifications - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-bell text-orange-500" />
|
||||
<ui:param name="title" value="Mes Notifications" />
|
||||
<ui:param name="description" value="Gérez vos notifications et restez informé des événements importants" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-secondary.xhtml">
|
||||
<ui:param name="value" value="Marquer toutes comme lues" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="outlined" value="true" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Paramètres" />
|
||||
<ui:param name="icon" value="pi pi-cog" />
|
||||
<ui:param name="outcome" value="/pages/secure/personnel/parametres" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques notifications -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.notifications != null ? personnelBean.notifications.stream().filter(n -> !n.lue).count() : 0}" />
|
||||
<ui:param name="label" value="Non Lues" />
|
||||
<ui:param name="subLabel" value="Nouvelles" />
|
||||
<ui:param name="icon" value="pi pi-bell" />
|
||||
<ui:param name="bgColor" value="red" />
|
||||
</ui:include>
|
||||
|
||||
<!-- En-tête -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<div>
|
||||
<h2 class="text-900 font-bold text-4xl mb-2">
|
||||
<i class="pi pi-bell text-orange-500 mr-3"></i>
|
||||
Mes Notifications
|
||||
</h2>
|
||||
<p class="text-600 text-lg mb-0">
|
||||
Gérez vos notifications et restez informé des événements importants
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Marquer toutes comme lues"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-check" />
|
||||
<p:commandButton value="Paramètres"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-cog" />
|
||||
</div>
|
||||
</div>
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.notifications != null ? personnelBean.notifications.size() : 0}" />
|
||||
<ui:param name="label" value="Total" />
|
||||
<ui:param name="subLabel" value="Notifications" />
|
||||
<ui:param name="icon" value="pi pi-inbox" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Statistiques notifications -->
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-red-500 mb-2">8</div>
|
||||
<div class="text-900 font-semibold mb-1">Non Lues</div>
|
||||
<div class="text-600 text-sm">Nouvelles</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">34</div>
|
||||
<div class="text-900 font-semibold mb-1">Aujourd'hui</div>
|
||||
<div class="text-600 text-sm">Reçues</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">156</div>
|
||||
<div class="text-900 font-semibold mb-1">Cette Semaine</div>
|
||||
<div class="text-600 text-sm">Total</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">12</div>
|
||||
<div class="text-900 font-semibold mb-1">Importantes</div>
|
||||
<div class="text-600 text-sm">En attente</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Liste des notifications -->
|
||||
<div class="card">
|
||||
<h5>Notifications Récentes</h5>
|
||||
|
||||
<p:dataTable value="#{personnelBean.notifications}" var="notification"
|
||||
emptyMessage="Aucune notification"
|
||||
styleClass="p-datatable-sm">
|
||||
|
||||
<p:column headerText="Titre">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="w-1rem h-1rem border-circle"
|
||||
styleClass="#{notification.lue ? 'bg-gray-300' : 'bg-blue-500'}"></div>
|
||||
<span class="font-semibold">#{notification.titre}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h:form id="filtresForm">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="typeNotification" class="block text-900 font-semibold mb-2">Type</label>
|
||||
<p:selectOneMenu id="typeNotification" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes" itemValue="" />
|
||||
<f:selectItem itemLabel="Système" itemValue="systeme" />
|
||||
<f:selectItem itemLabel="Événements" itemValue="evenement" />
|
||||
<f:selectItem itemLabel="Cotisations" itemValue="cotisation" />
|
||||
<f:selectItem itemLabel="Messages" itemValue="message" />
|
||||
<f:selectItem itemLabel="Rappels" itemValue="rappel" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="statutNotification" class="block text-900 font-semibold mb-2">Statut</label>
|
||||
<p:selectOneMenu id="statutNotification" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
|
||||
<f:selectItem itemLabel="Non lues" itemValue="non_lue" />
|
||||
<f:selectItem itemLabel="Lues" itemValue="lue" />
|
||||
<f:selectItem itemLabel="Importantes" itemValue="importante" />
|
||||
<f:selectItem itemLabel="Archivées" itemValue="archivee" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="periodeNotification" class="block text-900 font-semibold mb-2">Période</label>
|
||||
<p:selectOneMenu id="periodeNotification" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Toutes" itemValue="" />
|
||||
<f:selectItem itemLabel="Aujourd'hui" itemValue="aujourdhui" />
|
||||
<f:selectItem itemLabel="Cette semaine" itemValue="semaine" />
|
||||
<f:selectItem itemLabel="Ce mois-ci" itemValue="mois" />
|
||||
<f:selectItem itemLabel="Plus anciennes" itemValue="anciennes" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="field col-12 md:col-3">
|
||||
<label for="rechercheNotification" class="block text-900 font-semibold mb-2">Rechercher</label>
|
||||
<p:inputText id="rechercheNotification"
|
||||
placeholder="Mots-clés..."
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Message">
|
||||
<span>#{notification.message}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date">
|
||||
<span>#{notification.dateCreation}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut">
|
||||
<p:tag value="#{notification.lue ? 'Lue' : 'Non lue'}"
|
||||
severity="#{notification.lue ? 'success' : 'warning'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" styleClass="text-center">
|
||||
<div class="flex justify-content-center gap-1">
|
||||
<p:commandButton icon="pi pi-check"
|
||||
title="Marquer comme lue"
|
||||
styleClass="p-button-sm p-button-rounded p-button-success"
|
||||
rendered="#{!notification.lue}" />
|
||||
<p:commandButton icon="pi pi-trash"
|
||||
title="Supprimer"
|
||||
styleClass="p-button-sm p-button-rounded p-button-danger" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notifications urgentes -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4 border-2 border-red-500">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-exclamation-triangle text-red-500 mr-2"></i>
|
||||
Notifications Urgentes
|
||||
</h4>
|
||||
|
||||
<!-- Notification urgente 1 -->
|
||||
<div class="surface-red-50 hover:surface-red-100 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-start justify-content-between">
|
||||
<div class="flex align-items-start gap-3 flex-1">
|
||||
<div class="w-3rem h-3rem border-circle bg-red-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-shield text-red-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2 mb-2">
|
||||
<h6 class="text-900 font-bold mb-0">Tentative de connexion suspecte détectée</h6>
|
||||
<p:tag value="URGENT" severity="danger" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-2">
|
||||
Une tentative de connexion depuis un appareil non reconnu a été détectée sur votre compte.
|
||||
Si ce n'était pas vous, changez immédiatement votre mot de passe.
|
||||
</p>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">IP: 185.234.56.78 • Localisation: Nigeria</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right ml-3">
|
||||
<div class="text-900 font-semibold text-sm">il y a 15 min</div>
|
||||
<div class="flex gap-2 mt-2">
|
||||
<p:commandButton value="Sécuriser"
|
||||
styleClass="p-button-danger p-button-sm"
|
||||
icon="pi pi-lock" />
|
||||
<p:commandButton value="Ignorer"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
icon="pi pi-times" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification urgente 2 -->
|
||||
<div class="surface-orange-50 hover:surface-orange-100 border-round p-4 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-start justify-content-between">
|
||||
<div class="flex align-items-start gap-3 flex-1">
|
||||
<div class="w-3rem h-3rem border-circle bg-orange-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-clock text-orange-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2 mb-2">
|
||||
<h6 class="text-900 font-bold mb-0">Cotisation en retard - Action requise</h6>
|
||||
<p:tag value="ÉCHÉANCE" severity="warning" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-2">
|
||||
Votre cotisation mensuelle de janvier 2024 est en retard de 5 jours.
|
||||
Effectuez le paiement pour éviter la suspension de votre adhésion.
|
||||
</p>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">Montant: 25,000 FCFA • Échéance: 15 jan. 2024</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right ml-3">
|
||||
<div class="text-900 font-semibold text-sm">il y a 2h</div>
|
||||
<div class="flex gap-2 mt-2">
|
||||
<p:commandButton value="Payer"
|
||||
styleClass="p-button-warning p-button-sm"
|
||||
icon="pi pi-credit-card" />
|
||||
<p:commandButton value="Reporter"
|
||||
styleClass="p-button-outlined p-button-sm"
|
||||
icon="pi pi-calendar" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notifications récentes -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-clock mr-2"></i>
|
||||
Notifications Récentes
|
||||
</h4>
|
||||
|
||||
<!-- Notification 1 - Événement -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-start justify-content-between">
|
||||
<div class="flex align-items-start gap-3 flex-1">
|
||||
<div class="w-3rem h-3rem border-circle bg-blue-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-calendar text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2 mb-2">
|
||||
<h6 class="text-900 font-semibold mb-0">Nouvel événement ajouté</h6>
|
||||
<p:tag value="ÉVÉNEMENT" severity="info" styleClass="text-xs" />
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-blue-500"></div>
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-2">
|
||||
"Formation sur les nouvelles technologies" a été programmée pour le 25 janvier 2024.
|
||||
Inscrivez-vous dès maintenant, places limitées.
|
||||
</p>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">Organisé par: Thomas Martin</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right ml-3">
|
||||
<div class="text-900 font-semibold text-sm">il y a 1h</div>
|
||||
<div class="text-600 text-xs">18 jan. 2024, 15:30</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification 2 - Message -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200 opacity-70">
|
||||
<div class="flex align-items-start justify-content-between">
|
||||
<div class="flex align-items-start gap-3 flex-1">
|
||||
<div class="w-3rem h-3rem border-circle bg-green-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-envelope text-green-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2 mb-2">
|
||||
<h6 class="text-900 font-semibold mb-0">Nouveau message privé</h6>
|
||||
<p:tag value="MESSAGE" severity="success" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-2">
|
||||
Sophie Leroy vous a envoyé un message concernant la prochaine assemblée générale.
|
||||
</p>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">Objet: "Préparation AG 2024"</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right ml-3">
|
||||
<div class="text-600 font-semibold text-sm">il y a 3h</div>
|
||||
<div class="text-600 text-xs">18 jan. 2024, 13:15</div>
|
||||
<i class="pi pi-check-circle text-green-500 mt-2"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification 3 - Système -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200">
|
||||
<div class="flex align-items-start justify-content-between">
|
||||
<div class="flex align-items-start gap-3 flex-1">
|
||||
<div class="w-3rem h-3rem border-circle bg-purple-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-cog text-purple-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2 mb-2">
|
||||
<h6 class="text-900 font-semibold mb-0">Mise à jour système disponible</h6>
|
||||
<p:tag value="SYSTÈME" severity="help" styleClass="text-xs" />
|
||||
<div class="w-0-5rem h-0-5rem border-circle bg-purple-500"></div>
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-2">
|
||||
UnionFlow v2.1.4 est maintenant disponible avec des améliorations de sécurité
|
||||
et de nouvelles fonctionnalités.
|
||||
</p>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">Taille: 15.2 MB • Redémarrage requis</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right ml-3">
|
||||
<div class="text-900 font-semibold text-sm">il y a 6h</div>
|
||||
<div class="text-600 text-xs">18 jan. 2024, 10:00</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification 4 - Rappel -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 mb-3 cursor-pointer transition-duration-200 opacity-70">
|
||||
<div class="flex align-items-start justify-content-between">
|
||||
<div class="flex align-items-start gap-3 flex-1">
|
||||
<div class="w-3rem h-3rem border-circle bg-orange-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-bell text-orange-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2 mb-2">
|
||||
<h6 class="text-900 font-semibold mb-0">Rappel: Réunion équipe demain</h6>
|
||||
<p:tag value="RAPPEL" severity="warning" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-2">
|
||||
N'oubliez pas la réunion d'équipe administrative prévue demain à 14h00
|
||||
en salle de conférence.
|
||||
</p>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">Durée estimée: 2h • Présence obligatoire</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right ml-3">
|
||||
<div class="text-600 font-semibold text-sm">il y a 1 jour</div>
|
||||
<div class="text-600 text-xs">17 jan. 2024, 16:45</div>
|
||||
<i class="pi pi-check-circle text-green-500 mt-2"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Notification 5 - Félicitations -->
|
||||
<div class="surface-100 hover:surface-200 border-round p-4 cursor-pointer transition-duration-200 opacity-70">
|
||||
<div class="flex align-items-start justify-content-between">
|
||||
<div class="flex align-items-start gap-3 flex-1">
|
||||
<div class="w-3rem h-3rem border-circle bg-yellow-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-star text-yellow-600 text-xl"></i>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="flex align-items-center gap-2 mb-2">
|
||||
<h6 class="text-900 font-semibold mb-0">Félicitations! Badge obtenu</h6>
|
||||
<p:tag value="RÉCOMPENSE" severity="secondary" styleClass="text-xs" />
|
||||
</div>
|
||||
<p class="text-700 line-height-3 mb-2">
|
||||
Vous avez obtenu le badge "Membre Actif" pour votre participation régulière
|
||||
aux activités de l'association.
|
||||
</p>
|
||||
<div class="flex align-items-center gap-3">
|
||||
<span class="text-600 text-sm">Points gagnés: +50 • Niveau: Bronze</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right ml-3">
|
||||
<div class="text-600 font-semibold text-sm">il y a 2 jours</div>
|
||||
<div class="text-600 text-xs">16 jan. 2024, 09:30</div>
|
||||
<i class="pi pi-check-circle text-green-500 mt-2"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Paramètres de notification rapides -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-cog mr-2"></i>
|
||||
Paramètres Rapides
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-bell text-3xl text-blue-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Notifications Push</h6>
|
||||
<p:inputSwitch styleClass="mb-3" />
|
||||
<p class="text-600 text-sm">Activer/désactiver</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-envelope text-3xl text-green-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Emails</h6>
|
||||
<p:inputSwitch value="true" styleClass="mb-3" />
|
||||
<p class="text-600 text-sm">Résumé quotidien</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-mobile text-3xl text-purple-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">SMS</h6>
|
||||
<p:inputSwitch styleClass="mb-3" />
|
||||
<p class="text-600 text-sm">Urgences uniquement</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-volume-off text-3xl text-orange-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Mode Silencieux</h6>
|
||||
<p:inputSwitch styleClass="mb-3" />
|
||||
<p class="text-600 text-sm">Pause notifications</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex align-items-center justify-content-between mt-4 pt-4 border-top-1 border-200">
|
||||
<div>
|
||||
<h6 class="text-900 font-semibold mb-1">Gestion des notifications</h6>
|
||||
<p class="text-600 text-sm mb-0">Configurez finement vos préférences</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Tout marquer comme lu"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-check-square" />
|
||||
<p:commandButton value="Paramètres avancés"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-cog" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
</ui:composition>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<div>
|
||||
<h6 class="text-green-800 font-semibold mb-1">Compte sécurisé</h6>
|
||||
<p class="text-green-700 text-sm mb-0">
|
||||
Votre compte respecte toutes les bonnes pratiques de sécurité. Score: 95/100
|
||||
Votre compte respecte toutes les bonnes pratiques de sécurité. Score: #{parametresBean.scoreSecurite}/100
|
||||
</p>
|
||||
</div>
|
||||
<div class="ml-auto">
|
||||
|
||||
@@ -28,10 +28,14 @@
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Réinitialiser"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-refresh" />
|
||||
icon="pi pi-refresh"
|
||||
action="#{preferencesBean.reinitialiserPreferences}"
|
||||
update="@form" />
|
||||
<p:commandButton value="Enregistrer"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-save" />
|
||||
icon="pi pi-save"
|
||||
action="#{preferencesBean.sauvegarderPreferences}"
|
||||
update="@form" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -77,10 +81,14 @@
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-4">
|
||||
<h6 class="text-900 font-semibold mb-3">Thème</h6>
|
||||
<p:selectOneRadio id="theme" value="#{preferencesBean.theme}" layout="custom">
|
||||
<f:selectItem itemLabel="Clair" itemValue="light" />
|
||||
<f:selectItem itemLabel="Sombre" itemValue="dark" />
|
||||
</p:selectOneRadio>
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<div class="field-radiobutton">
|
||||
<p:radioButton id="themeLight" name="theme" value="light" />
|
||||
<p:radioButton id="themeLight" for="theme" itemIndex="0" />
|
||||
<label for="themeLight" class="ml-2">
|
||||
<div class="surface-100 border-round p-3 cursor-pointer">
|
||||
<i class="pi pi-sun text-yellow-500 text-xl mb-2"></i>
|
||||
@@ -92,7 +100,7 @@
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="field-radiobutton">
|
||||
<p:radioButton id="themeDark" name="theme" value="dark" />
|
||||
<p:radioButton id="themeDark" for="theme" itemIndex="1" />
|
||||
<label for="themeDark" class="ml-2">
|
||||
<div class="surface-800 border-round p-3 cursor-pointer">
|
||||
<i class="pi pi-moon text-blue-400 text-xl mb-2"></i>
|
||||
@@ -109,28 +117,34 @@
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-4">
|
||||
<h6 class="text-900 font-semibold mb-3">Couleur d'accent</h6>
|
||||
<p:selectOneRadio id="accentColor" value="#{preferencesBean.couleurAccent}" layout="custom">
|
||||
<f:selectItem itemLabel="Bleu" itemValue="blue" />
|
||||
<f:selectItem itemLabel="Vert" itemValue="green" />
|
||||
<f:selectItem itemLabel="Violet" itemValue="purple" />
|
||||
<f:selectItem itemLabel="Orange" itemValue="orange" />
|
||||
</p:selectOneRadio>
|
||||
<div class="grid">
|
||||
<div class="col-3">
|
||||
<div class="field-radiobutton">
|
||||
<p:radioButton id="colorBlue" name="accentColor" value="blue" />
|
||||
<p:radioButton id="colorBlue" for="accentColor" itemIndex="0" />
|
||||
<label for="colorBlue" class="w-2rem h-2rem border-circle bg-blue-500 cursor-pointer block ml-2"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="field-radiobutton">
|
||||
<p:radioButton id="colorGreen" name="accentColor" value="green" />
|
||||
<p:radioButton id="colorGreen" for="accentColor" itemIndex="1" />
|
||||
<label for="colorGreen" class="w-2rem h-2rem border-circle bg-green-500 cursor-pointer block ml-2"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="field-radiobutton">
|
||||
<p:radioButton id="colorPurple" name="accentColor" value="purple" />
|
||||
<p:radioButton id="colorPurple" for="accentColor" itemIndex="2" />
|
||||
<label for="colorPurple" class="w-2rem h-2rem border-circle bg-purple-500 cursor-pointer block ml-2"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="field-radiobutton">
|
||||
<p:radioButton id="colorOrange" name="accentColor" value="orange" />
|
||||
<p:radioButton id="colorOrange" for="accentColor" itemIndex="3" />
|
||||
<label for="colorOrange" class="w-2rem h-2rem border-circle bg-orange-500 cursor-pointer block ml-2"></label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,7 +155,7 @@
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="field">
|
||||
<label for="langue" class="block text-900 font-semibold mb-2">Langue</label>
|
||||
<p:selectOneMenu id="langue" styleClass="w-full">
|
||||
<p:selectOneMenu id="langue" value="#{preferencesBean.langue}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Français" itemValue="fr" />
|
||||
<f:selectItem itemLabel="English" itemValue="en" />
|
||||
<f:selectItem itemLabel="العربية" itemValue="ar" />
|
||||
@@ -153,7 +167,7 @@
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="field">
|
||||
<label for="fuseau" class="block text-900 font-semibold mb-2">Fuseau horaire</label>
|
||||
<p:selectOneMenu id="fuseau" styleClass="w-full">
|
||||
<p:selectOneMenu id="fuseau" value="#{preferencesBean.fuseauHoraire}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="GMT (Casablanca)" itemValue="GMT" />
|
||||
<f:selectItem itemLabel="GMT+1 (Paris)" itemValue="CET" />
|
||||
<f:selectItem itemLabel="GMT-5 (New York)" itemValue="EST" />
|
||||
@@ -164,7 +178,7 @@
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="field">
|
||||
<label for="format" class="block text-900 font-semibold mb-2">Format de date</label>
|
||||
<p:selectOneMenu id="format" styleClass="w-full">
|
||||
<p:selectOneMenu id="format" value="#{preferencesBean.formatDate}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="DD/MM/YYYY" itemValue="dd/mm/yyyy" />
|
||||
<f:selectItem itemLabel="MM/DD/YYYY" itemValue="mm/dd/yyyy" />
|
||||
<f:selectItem itemLabel="YYYY-MM-DD" itemValue="yyyy-mm-dd" />
|
||||
@@ -195,22 +209,22 @@
|
||||
</h6>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="notifEvenements" />
|
||||
<p:selectBooleanCheckbox id="notifEvenements" value="#{preferencesBean.notifEvenements}" />
|
||||
<label for="notifEvenements" class="ml-2 text-900">Nouveaux événements</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="notifMessages" />
|
||||
<p:selectBooleanCheckbox id="notifMessages" value="#{preferencesBean.notifMessages}" />
|
||||
<label for="notifMessages" class="ml-2 text-900">Messages privés</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="notifCotisations" />
|
||||
<p:selectBooleanCheckbox id="notifCotisations" value="#{preferencesBean.notifCotisations}" />
|
||||
<label for="notifCotisations" class="ml-2 text-900">Rappels cotisations</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="notifSysteme" />
|
||||
<p:selectBooleanCheckbox id="notifSysteme" value="#{preferencesBean.notifSysteme}" />
|
||||
<label for="notifSysteme" class="ml-2 text-900">Mises à jour système</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -223,22 +237,22 @@
|
||||
</h6>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="emailQuotidien" />
|
||||
<p:selectBooleanCheckbox id="emailQuotidien" value="#{preferencesBean.emailQuotidien}" />
|
||||
<label for="emailQuotidien" class="ml-2 text-900">Résumé quotidien</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="emailHebdo" />
|
||||
<p:selectBooleanCheckbox id="emailHebdo" value="#{preferencesBean.emailHebdo}" />
|
||||
<label for="emailHebdo" class="ml-2 text-900">Newsletter hebdomadaire</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="emailUrgent" />
|
||||
<p:selectBooleanCheckbox id="emailUrgent" value="#{preferencesBean.emailUrgent}" />
|
||||
<label for="emailUrgent" class="ml-2 text-900">Alertes urgentes</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="emailPromo" />
|
||||
<p:selectBooleanCheckbox id="emailPromo" value="#{preferencesBean.emailPromo}" />
|
||||
<label for="emailPromo" class="ml-2 text-900">Offres promotionnelles</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -251,23 +265,23 @@
|
||||
</h6>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="smsUrgent" />
|
||||
<p:selectBooleanCheckbox id="smsUrgent" value="#{preferencesBean.smsUrgent}" />
|
||||
<label for="smsUrgent" class="ml-2 text-900">Urgences uniquement</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="smsRappels" />
|
||||
<p:selectBooleanCheckbox id="smsRappels" value="#{preferencesBean.smsRappels}" />
|
||||
<label for="smsRappels" class="ml-2 text-900">Rappels importants</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="smsEvenements" />
|
||||
<p:selectBooleanCheckbox id="smsEvenements" value="#{preferencesBean.smsEvenements}" />
|
||||
<label for="smsEvenements" class="ml-2 text-900">Événements du jour</label>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="heuresSMS" class="block text-900 font-semibold mb-2">Heures autorisées</label>
|
||||
<p:selectOneMenu id="heuresSMS" styleClass="w-full">
|
||||
<p:selectOneMenu id="heuresSMS" value="#{preferencesBean.heuresSMS}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="08h - 20h" itemValue="08-20" />
|
||||
<f:selectItem itemLabel="09h - 18h" itemValue="09-18" />
|
||||
<f:selectItem itemLabel="24h/24" itemValue="00-24" />
|
||||
@@ -295,9 +309,14 @@
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-4">
|
||||
<h6 class="text-900 font-semibold mb-3">Visibilité du profil</h6>
|
||||
<p:selectOneRadio id="visibilite" value="#{preferencesBean.visibiliteProfil}" layout="custom">
|
||||
<f:selectItem itemLabel="Public" itemValue="publique" />
|
||||
<f:selectItem itemLabel="Limité" itemValue="limitee" />
|
||||
<f:selectItem itemLabel="Privé" itemValue="prive" />
|
||||
</p:selectOneRadio>
|
||||
|
||||
<div class="field-radiobutton mb-3">
|
||||
<p:radioButton id="visibilitePublique" name="visibilite" value="publique" />
|
||||
<p:radioButton id="visibilitePublique" for="visibilite" itemIndex="0" />
|
||||
<label for="visibilitePublique" class="ml-2">
|
||||
<div class="text-900 font-semibold">Public</div>
|
||||
<div class="text-600 text-sm">Visible par tous les membres</div>
|
||||
@@ -305,7 +324,7 @@
|
||||
</div>
|
||||
|
||||
<div class="field-radiobutton mb-3">
|
||||
<p:radioButton id="visibiliteLimitee" name="visibilite" value="limitee" />
|
||||
<p:radioButton id="visibiliteLimitee" for="visibilite" itemIndex="1" />
|
||||
<label for="visibiliteLimitee" class="ml-2">
|
||||
<div class="text-900 font-semibold">Limité</div>
|
||||
<div class="text-600 text-sm">Visible par les administrateurs</div>
|
||||
@@ -313,7 +332,7 @@
|
||||
</div>
|
||||
|
||||
<div class="field-radiobutton">
|
||||
<p:radioButton id="visibilitePrive" name="visibilite" value="prive" />
|
||||
<p:radioButton id="visibilitePrive" for="visibilite" itemIndex="2" />
|
||||
<label for="visibilitePrive" class="ml-2">
|
||||
<div class="text-900 font-semibold">Privé</div>
|
||||
<div class="text-600 text-sm">Visible par vous uniquement</div>
|
||||
@@ -327,17 +346,17 @@
|
||||
<h6 class="text-900 font-semibold mb-3">Paramètres de sécurité</h6>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="doubleAuth" value="true" />
|
||||
<p:selectBooleanCheckbox id="doubleAuth" value="#{preferencesBean.doubleAuth}" />
|
||||
<label for="doubleAuth" class="ml-2 text-900">Authentification à deux facteurs</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="connexionSecure" value="true" />
|
||||
<p:selectBooleanCheckbox id="connexionSecure" value="#{preferencesBean.connexionSecure}" />
|
||||
<label for="connexionSecure" class="ml-2 text-900">Connexion HTTPS obligatoire</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-3">
|
||||
<p:selectBooleanCheckbox id="deconnexionAuto" />
|
||||
<p:selectBooleanCheckbox id="deconnexionAuto" value="#{preferencesBean.deconnexionAuto}" />
|
||||
<label for="deconnexionAuto" class="ml-2 text-900">Déconnexion automatique</label>
|
||||
</div>
|
||||
|
||||
@@ -375,32 +394,32 @@
|
||||
<h6 class="text-900 font-semibold mb-3">Widgets à afficher</h6>
|
||||
|
||||
<div class="field-checkbox mb-2">
|
||||
<p:selectBooleanCheckbox id="widgetActivites" value="true" />
|
||||
<p:selectBooleanCheckbox id="widgetActivites" value="#{preferencesBean.widgetActivites}" />
|
||||
<label for="widgetActivites" class="ml-2 text-900">Activités récentes</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-2">
|
||||
<p:selectBooleanCheckbox id="widgetEvenements" value="true" />
|
||||
<p:selectBooleanCheckbox id="widgetEvenements" value="#{preferencesBean.widgetEvenements}" />
|
||||
<label for="widgetEvenements" class="ml-2 text-900">Événements à venir</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-2">
|
||||
<p:selectBooleanCheckbox id="widgetCotisations" />
|
||||
<p:selectBooleanCheckbox id="widgetCotisations" value="#{preferencesBean.widgetCotisations}" />
|
||||
<label for="widgetCotisations" class="ml-2 text-900">État des cotisations</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-2">
|
||||
<p:selectBooleanCheckbox id="widgetNotifications" value="true" />
|
||||
<p:selectBooleanCheckbox id="widgetNotifications" value="#{preferencesBean.widgetNotifications}" />
|
||||
<label for="widgetNotifications" class="ml-2 text-900">Notifications récentes</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox mb-2">
|
||||
<p:selectBooleanCheckbox id="widgetStatistiques" />
|
||||
<p:selectBooleanCheckbox id="widgetStatistiques" value="#{preferencesBean.widgetStatistiques}" />
|
||||
<label for="widgetStatistiques" class="ml-2 text-900">Mes statistiques</label>
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="widgetMeteo" />
|
||||
<p:selectBooleanCheckbox id="widgetMeteo" value="#{preferencesBean.widgetMeteo}" />
|
||||
<label for="widgetMeteo" class="ml-2 text-900">Météo locale</label>
|
||||
</div>
|
||||
</div>
|
||||
@@ -412,7 +431,7 @@
|
||||
|
||||
<div class="field">
|
||||
<label for="layoutDashboard" class="block text-900 font-semibold mb-2">Disposition</label>
|
||||
<p:selectOneMenu id="layoutDashboard" styleClass="w-full">
|
||||
<p:selectOneMenu id="layoutDashboard" value="#{preferencesBean.layoutDashboard}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Grille 2 colonnes" itemValue="grid-2" />
|
||||
<f:selectItem itemLabel="Grille 3 colonnes" itemValue="grid-3" />
|
||||
<f:selectItem itemLabel="Liste verticale" itemValue="list" />
|
||||
@@ -422,7 +441,7 @@
|
||||
|
||||
<div class="field">
|
||||
<label for="pageAccueil" class="block text-900 font-semibold mb-2">Page d'accueil</label>
|
||||
<p:selectOneMenu id="pageAccueil" styleClass="w-full">
|
||||
<p:selectOneMenu id="pageAccueil" value="#{preferencesBean.pageAccueil}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tableau de bord" itemValue="dashboard" />
|
||||
<f:selectItem itemLabel="Mes activités" itemValue="activites" />
|
||||
<f:selectItem itemLabel="Mon agenda" itemValue="agenda" />
|
||||
@@ -432,7 +451,7 @@
|
||||
|
||||
<div class="field">
|
||||
<label for="elementsPage" class="block text-900 font-semibold mb-2">Éléments par page</label>
|
||||
<p:selectOneMenu id="elementsPage" styleClass="w-full">
|
||||
<p:selectOneMenu id="elementsPage" value="#{preferencesBean.elementsPage}" styleClass="w-full">
|
||||
<f:selectItem itemLabel="10" itemValue="10" />
|
||||
<f:selectItem itemLabel="25" itemValue="25" />
|
||||
<f:selectItem itemLabel="50" itemValue="50" />
|
||||
@@ -441,7 +460,7 @@
|
||||
</div>
|
||||
|
||||
<div class="field-checkbox">
|
||||
<p:selectBooleanCheckbox id="animations" value="true" />
|
||||
<p:selectBooleanCheckbox id="animations" value="#{preferencesBean.animations}" />
|
||||
<label for="animations" class="ml-2 text-900">Activer les animations</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
<ui:define name="title">Mon Profil - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="ui-fluid">
|
||||
|
||||
<h:form id="formProfil">
|
||||
<!-- En-tête profil -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12">
|
||||
@@ -18,66 +17,87 @@
|
||||
<div class="flex align-items-center justify-content-between mb-4">
|
||||
<div class="flex align-items-center gap-4">
|
||||
<div class="w-6rem h-6rem border-circle bg-primary-100 flex align-items-center justify-content-center">
|
||||
<i class="pi pi-user text-primary text-4xl"></i>
|
||||
<h:graphicImage value="#{personnelBean.membre.photoUrl}"
|
||||
style="width: 100%; height: 100%; object-fit: cover; border-radius: 50%;"
|
||||
rendered="#{personnelBean.membre != null and personnelBean.membre.photoUrl != null}" />
|
||||
<i class="pi pi-user text-primary text-4xl"
|
||||
rendered="#{personnelBean.membre == null or personnelBean.membre.photoUrl == null}"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="text-900 font-bold text-3xl mb-2">Marie Dubois</h2>
|
||||
<p class="text-600 text-lg mb-1">Membre depuis le 15 mars 2020</p>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p:tag value="ACTIF" severity="success" styleClass="text-sm" />
|
||||
<p:tag value="PREMIUM" severity="info" styleClass="text-sm" />
|
||||
<p:tag value="ADMIN" severity="warning" styleClass="text-sm" />
|
||||
<h2 class="text-900 font-bold text-3xl mb-2">
|
||||
#{personnelBean.membre != null ? personnelBean.membre.nomComplet : 'Chargement...'}
|
||||
</h2>
|
||||
<p class="text-600 text-lg mb-1" rendered="#{personnelBean.membre != null and personnelBean.membre.dateAdhesion != null}">
|
||||
Membre depuis le #{personnelBean.membre.dateAdhesionFormatee}
|
||||
</p>
|
||||
<div class="flex align-items-center gap-2" rendered="#{personnelBean.membre != null}">
|
||||
<p:tag value="#{personnelBean.membre.statut}"
|
||||
severity="#{personnelBean.membre.statutSeverity}"
|
||||
styleClass="text-sm" />
|
||||
<p:tag value="#{personnelBean.membre.typeMembre}"
|
||||
severity="#{personnelBean.membre.typeSeverity}"
|
||||
styleClass="text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton value="Modifier"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-pencil"
|
||||
onclick="PF('modifierProfilDialog').show()" />
|
||||
<p:commandButton value="Exporter"
|
||||
styleClass="p-button-outlined"
|
||||
icon="pi pi-download" />
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Modifier" />
|
||||
<ui:param name="icon" value="pi pi-pencil" />
|
||||
<ui:param name="onclick" value="PF('modifierProfilDialog').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{personnelBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistiques profil -->
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-blue-500 mb-2">156</div>
|
||||
<div class="text-900 font-semibold mb-1">Actions Réalisées</div>
|
||||
<div class="text-600 text-sm">Ce mois-ci</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-green-500 mb-2">12</div>
|
||||
<div class="text-900 font-semibold mb-1">Événements</div>
|
||||
<div class="text-600 text-sm">Participés</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-purple-500 mb-2">98%</div>
|
||||
<div class="text-900 font-semibold mb-1">Taux Participation</div>
|
||||
<div class="text-600 text-sm">Global</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-3">
|
||||
<div class="surface-100 border-round p-4 text-center" style="min-height: 9rem">
|
||||
<div class="text-2xl font-bold text-orange-500 mb-2">4.9★</div>
|
||||
<div class="text-900 font-semibold mb-1">Évaluation</div>
|
||||
<div class="text-600 text-sm">Moyenne</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid" rendered="#{personnelBean.statistiques != null}">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.actionsRealisees}" />
|
||||
<ui:param name="label" value="Actions Réalisées" />
|
||||
<ui:param name="subLabel" value="Ce mois-ci" />
|
||||
<ui:param name="icon" value="pi pi-check-circle" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.evenementsParticipes}" />
|
||||
<ui:param name="label" value="Événements" />
|
||||
<ui:param name="subLabel" value="Participés" />
|
||||
<ui:param name="icon" value="pi pi-calendar" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.tauxParticipation}%" />
|
||||
<ui:param name="label" value="Taux Participation" />
|
||||
<ui:param name="subLabel" value="Global" />
|
||||
<ui:param name="icon" value="pi pi-chart-line" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{personnelBean.statistiques.evaluationMoyenne}★" />
|
||||
<ui:param name="label" value="Évaluation" />
|
||||
<ui:param name="subLabel" value="Moyenne" />
|
||||
<ui:param name="icon" value="pi pi-star" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Informations personnelles -->
|
||||
<div class="grid mb-4">
|
||||
<div class="grid mb-4" rendered="#{personnelBean.membre != null}">
|
||||
<div class="col-12 lg:col-8">
|
||||
<div class="surface-card border-round p-4 h-full">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
@@ -89,43 +109,37 @@
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Nom complet</div>
|
||||
<div class="text-900 font-semibold">Marie Dubois</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.nomComplet}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Email</div>
|
||||
<div class="text-900 font-semibold">marie.dubois@email.com</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.email}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Téléphone</div>
|
||||
<div class="text-900 font-semibold">+221 77 123 45 67</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.telephone}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="col-12 lg:col-6" rendered="#{personnelBean.membre.dateNaissance != null}">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Date de naissance</div>
|
||||
<div class="text-900 font-semibold">15 avril 1985</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.dateNaissanceFormatee}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="col-12" rendered="#{personnelBean.membre.adresse != null}">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Adresse</div>
|
||||
<div class="text-900 font-semibold">123 Avenue Léopold Sédar Senghor, Dakar, Sénégal</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.adresse}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="col-12 lg:col-6" rendered="#{personnelBean.membre.profession != null}">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Profession</div>
|
||||
<div class="text-900 font-semibold">Enseignante</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Situation familiale</div>
|
||||
<div class="text-900 font-semibold">Mariée, 2 enfants</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.profession}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,41 +155,23 @@
|
||||
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Numéro de membre</div>
|
||||
<div class="text-900 font-bold text-lg">#M-2020-0347</div>
|
||||
<div class="text-900 font-bold text-lg">#{personnelBean.membre.numeroMembre}</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="surface-100 border-round p-3 mb-3" rendered="#{personnelBean.membre.typeMembre != null}">
|
||||
<div class="text-600 text-sm mb-1">Type d'adhésion</div>
|
||||
<div class="text-900 font-semibold">Premium Annuelle</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.typeMembre}</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="surface-100 border-round p-3 mb-3" rendered="#{personnelBean.membre.dateAdhesion != null}">
|
||||
<div class="text-600 text-sm mb-1">Date d'inscription</div>
|
||||
<div class="text-900 font-semibold">15 mars 2020</div>
|
||||
<div class="text-900 font-semibold">#{personnelBean.membre.dateAdhesionFormatee}</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="text-600 text-sm mb-1">Prochaine échéance</div>
|
||||
<div class="text-900 font-semibold">15 mars 2025</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-green-50 border-left-3 border-green-500 p-3 mb-3">
|
||||
<h6 class="text-green-800 font-semibold mb-2">
|
||||
<i class="pi pi-check-circle mr-2"></i>Cotisations à jour
|
||||
</h6>
|
||||
<p class="text-green-700 text-sm mb-0">
|
||||
Toutes vos cotisations sont à jour jusqu'en mars 2025.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<p:commandButton value="Renouveler Adhésion"
|
||||
styleClass="p-button-success w-full"
|
||||
icon="pi pi-refresh" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activités récentes et permissions -->
|
||||
<!-- Activités récentes -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-card border-round p-4 h-full">
|
||||
@@ -184,36 +180,18 @@
|
||||
Activités Récentes
|
||||
</h4>
|
||||
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-900 font-semibold text-sm">Connexion système</span>
|
||||
<span class="text-600 text-xs">il y a 2h</span>
|
||||
<ui:repeat value="#{personnelBean.activitesRecentes}" var="activite">
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-900 font-semibold text-sm">#{activite.titre}</span>
|
||||
<span class="text-600 text-xs">#{activite.dateHeure}</span>
|
||||
</div>
|
||||
<div class="text-600 text-sm">#{activite.description}</div>
|
||||
</div>
|
||||
<div class="text-600 text-sm">Dernière connexion réussie</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-900 font-semibold text-sm">Modification profil</span>
|
||||
<span class="text-600 text-xs">il y a 1 jour</span>
|
||||
</div>
|
||||
<div class="text-600 text-sm">Mise à jour numéro de téléphone</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-3 mb-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-900 font-semibold text-sm">Participation événement</span>
|
||||
<span class="text-600 text-xs">il y a 3 jours</span>
|
||||
</div>
|
||||
<div class="text-600 text-sm">Assemblée générale 2024</div>
|
||||
</div>
|
||||
|
||||
<div class="surface-100 border-round p-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-900 font-semibold text-sm">Paiement cotisation</span>
|
||||
<span class="text-600 text-xs">il y a 1 semaine</span>
|
||||
</div>
|
||||
<div class="text-600 text-sm">Cotisation mensuelle janvier 2024</div>
|
||||
</ui:repeat>
|
||||
|
||||
<div class="text-center text-600 text-sm" rendered="#{empty personnelBean.activitesRecentes}">
|
||||
Aucune activité récente
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -225,177 +203,98 @@
|
||||
Rôles et Permissions
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-6">
|
||||
<div class="surface-100 border-round p-3 text-center">
|
||||
<i class="pi pi-user text-2xl text-blue-500 mb-2"></i>
|
||||
<h6 class="text-900 font-semibold mb-1">Membre</h6>
|
||||
<p class="text-600 text-xs">Droits de base</p>
|
||||
<div class="text-600 text-sm" rendered="#{userSession != null and userSession.roles != null}">
|
||||
<ui:repeat value="#{userSession.roles}" var="role">
|
||||
<div class="mb-2">
|
||||
<p:tag value="#{role}" severity="info" styleClass="text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="surface-100 border-round p-3 text-center">
|
||||
<i class="pi pi-users text-2xl text-green-500 mb-2"></i>
|
||||
<h6 class="text-900 font-semibold mb-1">Administrateur</h6>
|
||||
<p class="text-600 text-xs">Gestion membres</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="surface-100 border-round p-3 text-center">
|
||||
<i class="pi pi-calendar text-2xl text-purple-500 mb-2"></i>
|
||||
<h6 class="text-900 font-semibold mb-1">Organisateur</h6>
|
||||
<p class="text-600 text-xs">Gestion événements</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="surface-100 border-round p-3 text-center">
|
||||
<i class="pi pi-eye text-2xl text-orange-500 mb-2"></i>
|
||||
<h6 class="text-900 font-semibold mb-1">Superviseur</h6>
|
||||
<p class="text-600 text-xs">Lecture étendue</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<h6 class="text-900 font-semibold mb-3">Permissions actives</h6>
|
||||
<ul class="list-none p-0 m-0">
|
||||
<li class="flex align-items-center mb-2">
|
||||
<i class="pi pi-check-circle text-green-500 mr-2"></i>
|
||||
<span class="text-700 text-sm">Gestion des membres</span>
|
||||
</li>
|
||||
<li class="flex align-items-center mb-2">
|
||||
<i class="pi pi-check-circle text-green-500 mr-2"></i>
|
||||
<span class="text-700 text-sm">Organisation d'événements</span>
|
||||
</li>
|
||||
<li class="flex align-items-center mb-2">
|
||||
<i class="pi pi-check-circle text-green-500 mr-2"></i>
|
||||
<span class="text-700 text-sm">Accès aux rapports</span>
|
||||
</li>
|
||||
<li class="flex align-items-center">
|
||||
<i class="pi pi-times-circle text-red-500 mr-2"></i>
|
||||
<span class="text-700 text-sm">Gestion financière</span>
|
||||
</li>
|
||||
</ul>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
|
||||
<!-- Paramètres de sécurité -->
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="surface-card border-round p-4">
|
||||
<h4 class="text-900 font-bold mb-4">
|
||||
<i class="pi pi-lock text-red-500 mr-2"></i>
|
||||
Sécurité du Compte
|
||||
</h4>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-key text-3xl text-blue-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Mot de Passe</h6>
|
||||
<p class="text-600 text-sm mb-3">Dernière modification il y a 2 mois</p>
|
||||
<p:commandButton value="Changer"
|
||||
styleClass="p-button-outlined p-button-sm w-full"
|
||||
icon="pi pi-pencil" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-shield text-3xl text-green-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Authentification 2FA</h6>
|
||||
<p class="text-600 text-sm mb-3">
|
||||
<p:tag value="ACTIVÉE" severity="success" styleClass="text-xs" />
|
||||
</p>
|
||||
<p:commandButton value="Configurer"
|
||||
styleClass="p-button-outlined p-button-sm w-full"
|
||||
icon="pi pi-cog" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="surface-100 border-round p-4 text-center">
|
||||
<i class="pi pi-mobile text-3xl text-purple-500 mb-3"></i>
|
||||
<h6 class="text-900 font-semibold mb-2">Sessions Actives</h6>
|
||||
<p class="text-600 text-sm mb-3">3 appareils connectés</p>
|
||||
<p:commandButton value="Gérer"
|
||||
styleClass="p-button-outlined p-button-sm w-full"
|
||||
icon="pi pi-eye" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- Dialog Modifier Profil -->
|
||||
<p:dialog id="modifierProfilDialog"
|
||||
widgetVar="modifierProfilDialog"
|
||||
header="Modifier Mon Profil"
|
||||
modal="true"
|
||||
width="900"
|
||||
styleClass="surface-0">
|
||||
<h:form id="modifierProfilForm">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid" rendered="#{personnelBean.membre != null}">
|
||||
<div class="field col-12 lg:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="nom" />
|
||||
<ui:param name="label" value="Nom *" />
|
||||
<ui:param name="value" value="#{personnelBean.membre.nom}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="prenom" />
|
||||
<ui:param name="label" value="Prénom *" />
|
||||
<ui:param name="value" value="#{personnelBean.membre.prenom}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="email" />
|
||||
<ui:param name="label" value="Email *" />
|
||||
<ui:param name="value" value="#{personnelBean.membre.email}" />
|
||||
<ui:param name="required" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="telephone" />
|
||||
<ui:param name="label" value="Téléphone" />
|
||||
<ui:param name="value" value="#{personnelBean.membre.telephone}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateNaissance" />
|
||||
<ui:param name="label" value="Date de naissance" />
|
||||
<ui:param name="value" value="#{personnelBean.membre.dateNaissance}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="adresse" />
|
||||
<ui:param name="label" value="Adresse" />
|
||||
<ui:param name="value" value="#{personnelBean.membre.adresse}" />
|
||||
<ui:param name="rows" value="3" />
|
||||
</ui:include>
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="profession" />
|
||||
<ui:param name="label" value="Profession" />
|
||||
<ui:param name="value" value="#{personnelBean.membre.profession}" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('modifierProfilDialog').hide();"
|
||||
type="button" />
|
||||
<p:commandButton value="Enregistrer"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-save"
|
||||
action="#{personnelBean.mettreAJourProfil}"
|
||||
update="@form :formProfil"
|
||||
onclick="if(!args.validationFailed) PF('modifierProfilDialog').hide();" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Modifier Profil -->
|
||||
<p:dialog id="modifierProfilDialog"
|
||||
widgetVar="modifierProfilDialog"
|
||||
header="Modifier Mon Profil"
|
||||
modal="true"
|
||||
width="900"
|
||||
styleClass="surface-0">
|
||||
<h:form id="modifierProfilForm">
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="nom" class="block text-900 font-semibold mb-2">Nom *</label>
|
||||
<p:inputText id="nom" value="Dubois" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="prenom" class="block text-900 font-semibold mb-2">Prénom *</label>
|
||||
<p:inputText id="prenom" value="Marie" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label for="email" class="block text-900 font-semibold mb-2">Email *</label>
|
||||
<p:inputText id="email" value="marie.dubois@email.com" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="telephone" class="block text-900 font-semibold mb-2">Téléphone</label>
|
||||
<p:inputText id="telephone" value="+221 77 123 45 67" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="dateNaissance" class="block text-900 font-semibold mb-2">Date de naissance</label>
|
||||
<p:calendar id="dateNaissance" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<label for="adresse" class="block text-900 font-semibold mb-2">Adresse</label>
|
||||
<p:inputTextarea id="adresse"
|
||||
value="123 Avenue Léopold Sédar Senghor, Dakar, Sénégal"
|
||||
rows="3"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="profession" class="block text-900 font-semibold mb-2">Profession</label>
|
||||
<p:inputText id="profession" value="Enseignante" styleClass="w-full" />
|
||||
</div>
|
||||
<div class="field col-12 lg:col-6">
|
||||
<label for="situationFamiliale" class="block text-900 font-semibold mb-2">Situation familiale</label>
|
||||
<p:selectOneMenu id="situationFamiliale" styleClass="w-full">
|
||||
<f:selectItem itemLabel="Célibataire" itemValue="celibataire" />
|
||||
<f:selectItem itemLabel="Marié(e)" itemValue="marie" />
|
||||
<f:selectItem itemLabel="Divorcé(e)" itemValue="divorce" />
|
||||
<f:selectItem itemLabel="Veuf/Veuve" itemValue="veuf" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-content-end gap-2 mt-4">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('modifierProfilDialog').hide()"
|
||||
type="button" />
|
||||
<p:commandButton value="Enregistrer"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-save" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,21 +1,120 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Rapports Activités - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-calendar text-orange-500" />
|
||||
<ui:param name="title" value="Rapports Activités" />
|
||||
<ui:param name="description" value="Analyse des activités et événements" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="onclick" value="PF('dlgExport').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{rapportsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques activités -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.totalEvenements}" />
|
||||
<ui:param name="label" value="Total Événements" />
|
||||
<ui:param name="icon" value="pi pi-calendar" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.croissanceEvenements}%" />
|
||||
<ui:param name="label" value="Croissance Événements" />
|
||||
<ui:param name="icon" value="pi pi-arrow-up" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- KPIs Activités -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<h5>Indicateurs d'Activité</h5>
|
||||
<div class="grid">
|
||||
<ui:repeat value="#{rapportsBean.kpis}" var="kpi">
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="surface-100 border-round-lg p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{kpi.icon} text-2xl text-#{kpi.couleur}"></i>
|
||||
<span class="font-semibold">#{kpi.libelle}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-3xl font-bold text-#{kpi.couleur} mb-2">#{kpi.valeur}</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{kpi.variation > 0 ? 'pi pi-arrow-up text-green-500' : kpi.variation < 0 ? 'pi pi-arrow-down text-red-500' : 'pi pi-minus text-gray-500'}"></i>
|
||||
<span class="text-sm">#{kpi.variation}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Export -->
|
||||
<h:form id="formExport">
|
||||
<p:dialog id="dlgExport"
|
||||
widgetVar="dlgExport"
|
||||
header="Exporter le Rapport Activités"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 500px;">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<p:outputLabel for="formatExport" value="Format d'Export" />
|
||||
<p:selectOneRadio id="formatExport"
|
||||
value="#{rapportsBean.nouveauRapport.format}"
|
||||
layout="grid"
|
||||
columns="1">
|
||||
<f:selectItem itemLabel="PDF" itemValue="PDF" />
|
||||
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
|
||||
<f:selectItem itemLabel="CSV" itemValue="CSV" />
|
||||
</p:selectOneRadio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('dlgExport').hide();"
|
||||
type="button" />
|
||||
<p:commandButton value="Exporter"
|
||||
icon="pi pi-download"
|
||||
styleClass="p-button-success"
|
||||
action="#{rapportsBean.exporterDonnees}" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,20 +1,168 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Export de Rapports - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-download text-indigo-500" />
|
||||
<ui:param name="title" value="Export de Rapports" />
|
||||
<ui:param name="description" value="Générer et exporter des rapports personnalisés" />
|
||||
</ui:include>
|
||||
|
||||
<!-- Formulaire de génération de rapport -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
</div>
|
||||
<h:form id="formRapport">
|
||||
<h5>Nouveau Rapport</h5>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="typeRapport" value="Type de Rapport *" />
|
||||
<p:selectOneMenu id="typeRapport"
|
||||
value="#{rapportsBean.nouveauRapport.type}"
|
||||
styleClass="w-full"
|
||||
required="true">
|
||||
<f:selectItem itemLabel="Sélectionner un type" itemValue="" />
|
||||
<f:selectItem itemLabel="Rapport Financier" itemValue="FINANCIER" />
|
||||
<f:selectItem itemLabel="Rapport Membres" itemValue="MEMBRES" />
|
||||
<f:selectItem itemLabel="Rapport Activités" itemValue="ACTIVITES" />
|
||||
<f:selectItem itemLabel="Rapport Performance" itemValue="PERFORMANCE" />
|
||||
<f:selectItem itemLabel="Rapport Complet" itemValue="COMPLET" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="formatRapport" value="Format *" />
|
||||
<p:selectOneMenu id="formatRapport"
|
||||
value="#{rapportsBean.nouveauRapport.format}"
|
||||
styleClass="w-full"
|
||||
required="true">
|
||||
<f:selectItem itemLabel="PDF" itemValue="PDF" />
|
||||
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
|
||||
<f:selectItem itemLabel="CSV" itemValue="CSV" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="periodeRapport" value="Période *" />
|
||||
<p:selectOneMenu id="periodeRapport"
|
||||
value="#{rapportsBean.nouveauRapport.periode}"
|
||||
styleClass="w-full"
|
||||
required="true">
|
||||
<f:selectItem itemLabel="7 derniers jours" itemValue="7_JOURS" />
|
||||
<f:selectItem itemLabel="30 derniers jours" itemValue="30_JOURS" />
|
||||
<f:selectItem itemLabel="3 derniers mois" itemValue="3_MOIS" />
|
||||
<f:selectItem itemLabel="6 derniers mois" itemValue="6_MOIS" />
|
||||
<f:selectItem itemLabel="Année en cours" itemValue="ANNEE_COURANTE" />
|
||||
<f:selectItem itemLabel="Période personnalisée" itemValue="PERSONNALISEE" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="field">
|
||||
<p:outputLabel for="detailRapport" value="Niveau de Détail" />
|
||||
<p:selectOneMenu id="detailRapport"
|
||||
value="#{rapportsBean.nouveauRapport.detail}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Résumé" itemValue="RESUME" />
|
||||
<f:selectItem itemLabel="Standard" itemValue="STANDARD" />
|
||||
<f:selectItem itemLabel="Détaillé" itemValue="DETAILLE" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<p:outputLabel for="commentairesRapport" value="Commentaires (optionnel)" />
|
||||
<p:inputTextarea id="commentairesRapport"
|
||||
value="#{rapportsBean.nouveauRapport.commentaires}"
|
||||
rows="3"
|
||||
styleClass="w-full"
|
||||
placeholder="Ajoutez des commentaires ou notes pour ce rapport..." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-outlined p-button-secondary"
|
||||
action="#{rapportsBean.nouveauRapport = null}"
|
||||
update="@form" />
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Générer le Rapport" />
|
||||
<ui:param name="icon" value="pi pi-file" />
|
||||
<ui:param name="action" value="#{rapportsBean.genererRapport}" />
|
||||
<ui:param name="update" value="@form :formHistorique" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Historique des rapports -->
|
||||
<div class="card">
|
||||
<h:form id="formHistorique">
|
||||
<h5>Historique des Rapports</h5>
|
||||
|
||||
<p:dataTable value="#{rapportsBean.historiqueRapports}" var="rapport"
|
||||
emptyMessage="Aucun rapport généré"
|
||||
paginator="true"
|
||||
rows="10"
|
||||
styleClass="p-datatable-sm">
|
||||
|
||||
<p:column headerText="Type">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{rapport.typeIcon} text-#{rapport.typeCouleur}"></i>
|
||||
<span class="font-semibold">#{rapport.typeLibelle}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Période">
|
||||
<span>#{rapport.periodeCouverte}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Date Génération">
|
||||
<span>#{rapport.dateGenerationFormatee}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Généré par">
|
||||
<span>#{rapport.generePar}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Statut">
|
||||
<p:tag value="#{rapport.statut}"
|
||||
severity="#{rapport.statutSeverity}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" styleClass="text-center">
|
||||
<div class="flex justify-content-center gap-1">
|
||||
<p:commandButton icon="pi pi-eye"
|
||||
title="Voir"
|
||||
styleClass="p-button-sm p-button-rounded p-button-info"
|
||||
action="#{rapportsBean.voirRapport(rapport)}" />
|
||||
<p:commandButton icon="pi pi-download"
|
||||
title="Télécharger"
|
||||
styleClass="p-button-sm p-button-rounded p-button-success"
|
||||
action="#{rapportsBean.telechargerRapport(rapport)}"
|
||||
rendered="#{rapport.statut == 'GENERE'}" />
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
|
||||
@@ -1,21 +1,213 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Rapports Financiers - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-dollar text-green-500" />
|
||||
<ui:param name="title" value="Rapports Financiers" />
|
||||
<ui:param name="description" value="Analyse financière et suivi des revenus" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="onclick" value="PF('dlgExport').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{rapportsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Filtres de période -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<h:form id="formFiltres">
|
||||
<h5>Période d'Analyse</h5>
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="periodeRapide" />
|
||||
<ui:param name="label" value="Période Rapide" />
|
||||
<ui:param name="value" value="#{rapportsBean.periodeRapide}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="7 derniers jours" itemValue="7_JOURS" />
|
||||
<f:selectItem itemLabel="30 derniers jours" itemValue="30_JOURS" />
|
||||
<f:selectItem itemLabel="3 derniers mois" itemValue="3_MOIS" />
|
||||
<f:selectItem itemLabel="6 derniers mois" itemValue="6_MOIS" />
|
||||
<f:selectItem itemLabel="Année en cours" itemValue="ANNEE_COURANTE" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateDebut" />
|
||||
<ui:param name="label" value="Date Début" />
|
||||
<ui:param name="value" value="#{rapportsBean.dateDebut}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="dateFin" />
|
||||
<ui:param name="label" value="Date Fin" />
|
||||
<ui:param name="value" value="#{rapportsBean.dateFin}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-3">
|
||||
<div class="field">
|
||||
<p:outputLabel />
|
||||
<ui:include src="/templates/components/button-primary.xhtml">
|
||||
<ui:param name="value" value="Appliquer" />
|
||||
<ui:param name="icon" value="pi pi-check" />
|
||||
<ui:param name="action" value="#{rapportsBean.chargerDonnees}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Indicateurs financiers -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.revenus}" />
|
||||
<ui:param name="label" value="Revenus Totaux" />
|
||||
<ui:param name="icon" value="pi pi-dollar" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.croissanceRevenus}%" />
|
||||
<ui:param name="label" value="Croissance Revenus" />
|
||||
<ui:param name="icon" value="pi pi-arrow-up" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.totalMembres}" />
|
||||
<ui:param name="label" value="Membres Actifs" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="purple" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.croissanceMembres}%" />
|
||||
<ui:param name="label" value="Croissance Membres" />
|
||||
<ui:param name="icon" value="pi pi-chart-line" />
|
||||
<ui:param name="bgColor" value="orange" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Sources de revenus -->
|
||||
<div class="card">
|
||||
<h5>Sources de Revenus</h5>
|
||||
<p:dataTable value="#{rapportsBean.sourceRevenus}" var="source"
|
||||
emptyMessage="Aucune donnée disponible"
|
||||
styleClass="p-datatable-sm">
|
||||
<p:column headerText="Source">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{source.icon} text-lg"></i>
|
||||
<span class="font-semibold">#{source.libelle}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Montant">
|
||||
<span class="font-bold">#{source.montant} FCFA</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Pourcentage">
|
||||
<p:progressBar value="#{source.pourcentage}"
|
||||
showValue="true"
|
||||
styleClass="p-progressbar-sm" />
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
|
||||
<!-- KPIs Financiers -->
|
||||
<div class="card">
|
||||
<h5>Indicateurs Clés de Performance</h5>
|
||||
<div class="grid">
|
||||
<ui:repeat value="#{rapportsBean.kpis}" var="kpi">
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="surface-100 border-round-lg p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{kpi.icon} text-2xl text-#{kpi.couleur}"></i>
|
||||
<span class="font-semibold">#{kpi.libelle}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-3xl font-bold text-#{kpi.couleur} mb-2">#{kpi.valeur}</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="#{kpi.variation > 0 ? 'pi pi-arrow-up text-green-500' : kpi.variation < 0 ? 'pi pi-arrow-down text-red-500' : 'pi pi-minus text-gray-500'}"></i>
|
||||
<span class="text-sm">#{kpi.variation}%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Export -->
|
||||
<h:form id="formExport">
|
||||
<p:dialog id="dlgExport"
|
||||
widgetVar="dlgExport"
|
||||
header="Exporter le Rapport Financier"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 500px;">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<p:outputLabel for="formatExport" value="Format d'Export" />
|
||||
<p:selectOneRadio id="formatExport"
|
||||
value="#{rapportsBean.nouveauRapport.format}"
|
||||
layout="grid"
|
||||
columns="1">
|
||||
<f:selectItem itemLabel="PDF" itemValue="PDF" />
|
||||
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
|
||||
<f:selectItem itemLabel="CSV" itemValue="CSV" />
|
||||
</p:selectOneRadio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('dlgExport').hide();"
|
||||
type="button" />
|
||||
<p:commandButton value="Exporter"
|
||||
icon="pi pi-download"
|
||||
styleClass="p-button-success"
|
||||
action="#{rapportsBean.exporterDonnees}" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -1,21 +1,145 @@
|
||||
<ui:composition template="/templates/main-template.xhtml"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
<!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">
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">PAGE_TITLE - UnionFlow</ui:define>
|
||||
<ui:define name="title">Rapports Membres - UnionFlow</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-users text-blue-500" />
|
||||
<ui:param name="title" value="Rapports Membres" />
|
||||
<ui:param name="description" value="Analyse et statistiques sur les membres" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActions">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/button-success.xhtml">
|
||||
<ui:param name="value" value="Exporter" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="onclick" value="PF('dlgExport').show();" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/button-icon.xhtml">
|
||||
<ui:param name="icon" value="pi pi-refresh" />
|
||||
<ui:param name="action" value="#{rapportsBean.actualiser}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
<ui:param name="title" value="Actualiser" />
|
||||
<ui:param name="rounded" value="true" />
|
||||
<ui:param name="text" value="false" />
|
||||
<ui:param name="styleClass" value="ui-button-outlined ui-button-secondary" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques membres -->
|
||||
<div class="grid">
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.totalMembres}" />
|
||||
<ui:param name="label" value="Total Membres" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="bgColor" value="blue" />
|
||||
</ui:include>
|
||||
|
||||
<ui:include src="/templates/components/stat-card.xhtml">
|
||||
<ui:param name="value" value="#{rapportsBean.indicateurs.croissanceMembres}%" />
|
||||
<ui:param name="label" value="Croissance" />
|
||||
<ui:param name="icon" value="pi pi-arrow-up" />
|
||||
<ui:param name="bgColor" value="green" />
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Répartition des membres -->
|
||||
<div class="card">
|
||||
<h5>PAGE_TITLE</h5>
|
||||
<p>Cette page est en cours de développement.</p>
|
||||
<div class="text-center">
|
||||
<i class="pi pi-cog" style="font-size: 3rem; color: #6c757d;"></i>
|
||||
<p class="mt-3">Fonctionnalité en développement</p>
|
||||
<h5>Répartition des Membres</h5>
|
||||
<p:dataTable value="#{rapportsBean.repartitionMembres}" var="repartition"
|
||||
emptyMessage="Aucune donnée disponible"
|
||||
styleClass="p-datatable-sm">
|
||||
<p:column headerText="Statut">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<div class="w-1rem h-1rem border-circle bg-#{repartition.couleur}"></div>
|
||||
<span class="font-semibold">#{repartition.libelle}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Nombre">
|
||||
<span class="font-bold">#{repartition.nombre}</span>
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Pourcentage">
|
||||
<p:progressBar value="#{repartition.pourcentage}"
|
||||
showValue="true"
|
||||
styleClass="p-progressbar-sm" />
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
|
||||
<!-- Objectifs -->
|
||||
<div class="card">
|
||||
<h5>Objectifs</h5>
|
||||
<div class="grid">
|
||||
<ui:repeat value="#{rapportsBean.objectifs}" var="objectif">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="surface-100 border-round-lg p-4">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<span class="font-semibold">#{objectif.libelle}</span>
|
||||
<span class="text-sm text-600">#{objectif.pourcentage}%</span>
|
||||
</div>
|
||||
<p:progressBar value="#{objectif.pourcentage}"
|
||||
showValue="false"
|
||||
styleClass="p-progressbar-sm mb-2" />
|
||||
<div class="flex justify-content-between text-sm">
|
||||
<span class="text-600">Réalisé: #{objectif.realise}</span>
|
||||
<span class="text-600">Cible: #{objectif.cible}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Export -->
|
||||
<h:form id="formExport">
|
||||
<p:dialog id="dlgExport"
|
||||
widgetVar="dlgExport"
|
||||
header="Exporter le Rapport Membres"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
style="width: 90vw; max-width: 500px;">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="field">
|
||||
<p:outputLabel for="formatExport" value="Format d'Export" />
|
||||
<p:selectOneRadio id="formatExport"
|
||||
value="#{rapportsBean.nouveauRapport.format}"
|
||||
layout="grid"
|
||||
columns="1">
|
||||
<f:selectItem itemLabel="PDF" itemValue="PDF" />
|
||||
<f:selectItem itemLabel="Excel (.xlsx)" itemValue="EXCEL" />
|
||||
<f:selectItem itemLabel="CSV" itemValue="CSV" />
|
||||
</p:selectOneRadio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<div class="flex justify-content-end gap-2">
|
||||
<p:commandButton value="Annuler"
|
||||
styleClass="p-button-outlined"
|
||||
onclick="PF('dlgExport').hide();"
|
||||
type="button" />
|
||||
<p:commandButton value="Exporter"
|
||||
icon="pi pi-download"
|
||||
styleClass="p-button-success"
|
||||
action="#{rapportsBean.exporterDonnees}" />
|
||||
</div>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Catalogue des Types d'Organisation</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<h:form id="formTypes">
|
||||
<p:messages id="messages" showDetail="true" closable="true" />
|
||||
|
||||
<div class="card mb-3">
|
||||
<div class="flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h5 class="mb-1">Catalogue des Types d'Organisation</h5>
|
||||
<span class="text-600">
|
||||
Gestion centrale des types utilisés par les organisations (Lions Club, Association, Coopérative, ...).
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<p:commandButton value="Nouveau type"
|
||||
icon="pi pi-plus"
|
||||
styleClass="ui-button-success"
|
||||
actionListener="#{typeOrganisationsAdminBean.preparerNouveauType}"
|
||||
update=":formTypes:dlgType"
|
||||
oncomplete="PF('dlgType').show();" />
|
||||
<p:commandButton value="Rafraîchir"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="ui-button-secondary ml-2"
|
||||
actionListener="#{typeOrganisationsAdminBean.chargerTypes}"
|
||||
update="@form" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<p:dataTable id="dtTypes"
|
||||
value="#{typeOrganisationsAdminBean.types}"
|
||||
var="type"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50"
|
||||
paginatorPosition="bottom"
|
||||
emptyMessage="Aucun type trouvé">
|
||||
|
||||
<p:column headerText="Code" sortBy="#{type.code}" style="width: 160px;">
|
||||
<h:outputText value="#{type.code}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Libellé" sortBy="#{type.libelle}">
|
||||
<h:outputText value="#{type.libelle}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Description">
|
||||
<h:outputText value="#{type.description}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Ordre" style="width: 80px; text-align: center;">
|
||||
<h:outputText value="#{type.ordreAffichage}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actif" style="width: 90px; text-align: center;">
|
||||
<p:tag value="#{type.actif ? 'Actif' : 'Inactif'}"
|
||||
severity="#{type.actif ? 'success' : 'danger'}" />
|
||||
</p:column>
|
||||
|
||||
<p:column headerText="Actions" style="width: 140px; text-align: center;">
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
title="Modifier"
|
||||
styleClass="ui-button-rounded ui-button-warning mr-2"
|
||||
update=":formTypes:dlgType"
|
||||
actionListener="#{typeOrganisationsAdminBean.setTypeSelectionne(type)}"
|
||||
oncomplete="PF('dlgType').show();" />
|
||||
|
||||
<p:commandButton icon="pi pi-ban"
|
||||
title="Désactiver"
|
||||
styleClass="ui-button-rounded ui-button-secondary"
|
||||
update="@form"
|
||||
actionListener="#{typeOrganisationsAdminBean.desactiverType(type.id)}">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Désactiver ce type d'organisation ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</div>
|
||||
|
||||
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade" responsive="true" width="350">
|
||||
<p:commandButton value="Non" type="button" styleClass="ui-button-secondary" icon="pi pi-times"
|
||||
onclick="PF('confirmDialog').hide()" />
|
||||
<p:commandButton value="Oui" type="button" styleClass="ui-button-danger" icon="pi pi-check" />
|
||||
</p:confirmDialog>
|
||||
|
||||
<!-- Dialogue création / édition type -->
|
||||
<p:dialog id="dlgType"
|
||||
widgetVar="dlgType"
|
||||
header="Type d'Organisation"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
responsive="true"
|
||||
width="600">
|
||||
|
||||
<div class="ui-fluid">
|
||||
<div class="formgrid grid">
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="code" value="Code *" />
|
||||
<p:inputText id="code"
|
||||
value="#{typeOrganisationsAdminBean.typeCourant.code}"
|
||||
required="true"
|
||||
requiredMessage="Code: une donnée est requise."
|
||||
maxlength="50" />
|
||||
<p:message for="code" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-8">
|
||||
<p:outputLabel for="libelle" value="Libellé *" />
|
||||
<p:inputText id="libelle"
|
||||
value="#{typeOrganisationsAdminBean.typeCourant.libelle}"
|
||||
required="true"
|
||||
requiredMessage="Libellé: une donnée est requise."
|
||||
maxlength="150" />
|
||||
<p:message for="libelle" />
|
||||
</div>
|
||||
<div class="field col-12">
|
||||
<p:outputLabel for="description" value="Description" />
|
||||
<p:inputTextarea id="description"
|
||||
value="#{typeOrganisationsAdminBean.typeCourant.description}"
|
||||
rows="3"
|
||||
maxlength="500" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:outputLabel for="ordre" value="Ordre d'affichage" />
|
||||
<p:inputNumber id="ordre"
|
||||
value="#{typeOrganisationsAdminBean.typeCourant.ordreAffichage}"
|
||||
decimalPlaces="0"
|
||||
minValue="0" />
|
||||
</div>
|
||||
<div class="field col-12 md:col-4">
|
||||
<p:selectBooleanCheckbox id="actif"
|
||||
value="#{typeOrganisationsAdminBean.typeCourant.actif}" />
|
||||
<p:outputLabel for="actif" value="Actif" styleClass="ml-2" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('dlgType').hide();"
|
||||
styleClass="ui-button-secondary" />
|
||||
|
||||
<p:commandButton value="Enregistrer"
|
||||
icon="pi pi-check"
|
||||
process="@form"
|
||||
update=":formTypes:dtTypes :formTypes:messages"
|
||||
actionListener="#{typeOrganisationsAdminBean.enregistrerType}"
|
||||
oncomplete="if(!args.validationFailed) PF('dlgType').hide();" />
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:composition>
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html 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 dialogue de formulaire réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-dialog.xhtml">
|
||||
<ui:param name="dialogId" value="dlgNouvelle" />
|
||||
<ui:param name="header" value="Nouvelle Organisation" />
|
||||
<ui:param name="widgetVar" value="dlgNouvelle" />
|
||||
<ui:param name="formId" value="formNouvelle" />
|
||||
<ui:param name="width" value="800" />
|
||||
<ui:param name="saveAction" value="#{bean.creerOrganisation}" />
|
||||
<ui:param name="saveLabel" value="Créer" />
|
||||
<ui:param name="updateTarget" value=":formOrganisations:dtOrganisations :formOrganisations:messages" />
|
||||
<ui:define name="content">
|
||||
Contenu du formulaire
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<ui:composition>
|
||||
<h:form id="#{formId}">
|
||||
<p:dialog id="#{dialogId}"
|
||||
header="#{header}"
|
||||
widgetVar="#{widgetVar}"
|
||||
modal="#{empty modal ? 'true' : modal}"
|
||||
resizable="#{empty resizable ? 'false' : resizable}"
|
||||
width="#{empty width ? '600' : width}"
|
||||
responsive="#{empty responsive ? 'true' : responsive}"
|
||||
closable="#{empty closable ? 'true' : closable}"
|
||||
draggable="#{empty draggable ? 'true' : draggable}"
|
||||
dynamic="true">
|
||||
|
||||
<div class="ui-fluid">
|
||||
<div class="grid">
|
||||
<ui:insert name="content">
|
||||
<!-- Contenu du formulaire -->
|
||||
</ui:insert>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<ui:insert name="footer">
|
||||
<!-- Footer par défaut si non fourni -->
|
||||
<ui:fragment rendered="#{not empty cancelLabel}">
|
||||
<p:commandButton value="#{cancelLabel}"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('#{widgetVar}').hide();"
|
||||
styleClass="ui-button-secondary"/>
|
||||
</ui:fragment>
|
||||
<ui:fragment rendered="#{empty cancelLabel}">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
onclick="PF('#{widgetVar}').hide();"
|
||||
styleClass="ui-button-secondary"/>
|
||||
</ui:fragment>
|
||||
</ui:insert>
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</h:form>
|
||||
</ui:composition>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<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 autoComplete réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-autocomplete.xhtml">
|
||||
<ui:param name="id" value="searchProfession" />
|
||||
<ui:param name="label" value="Profession" />
|
||||
<ui:param name="value" value="#{bean.filtres.profession}" />
|
||||
<ui:param name="completeMethod" value="#{bean.completerProfessions}" />
|
||||
<ui:param name="placeholder" value="Saisir une profession..." />
|
||||
<ui:param name="update" value=":formResultats:dtResultats @(.search-summary)" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:autoComplete id="#{id}"
|
||||
value="#{value}"
|
||||
completeMethod="#{completeMethod}"
|
||||
placeholder="#{placeholder}"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="itemSelect"
|
||||
update="#{not empty update ? update : ':formResultats:dtResultats @(.search-summary)'}" />
|
||||
</p:autoComplete>
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<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 checkbox booléenne réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-boolean.xhtml">
|
||||
<ui:param name="id" value="desEnfants" />
|
||||
<ui:param name="label" value=" A des enfants déclarés" />
|
||||
<ui:param name="value" value="#{bean.filtres.desEnfants}" />
|
||||
<ui:param name="update" value=":formResultats:dtResultats @(.search-summary)" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:selectBooleanCheckbox id="#{id}" value="#{value}">
|
||||
<p:ajax update="#{not empty update ? update : ':formResultats:dtResultats @(.search-summary)'}" />
|
||||
</p:selectBooleanCheckbox>
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<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 champ date réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-calendar.xhtml">
|
||||
<ui:param name="id" value="fieldId" />
|
||||
<ui:param name="label" value="Label du champ" />
|
||||
<ui:param name="value" value="#{bean.property}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="pattern" value="dd/MM/yyyy" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:calendar id="#{id}"
|
||||
value="#{value}"
|
||||
showIcon="true"
|
||||
navigator="true"
|
||||
required="#{not empty required and required}"
|
||||
locale="fr"
|
||||
pattern="#{not empty pattern ? pattern : 'dd/MM/yyyy'}"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="dateSelect"
|
||||
update="#{not empty update ? update : '@form'}" />
|
||||
</p:calendar>
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -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 selectCheckboxMenu réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-checkbox-menu.xhtml">
|
||||
<ui:param name="id" value="searchStatut" />
|
||||
<ui:param name="label" value="Statut" />
|
||||
<ui:param name="value" value="#{bean.filtres.statuts}" />
|
||||
<ui:param name="update" value=":formResultats:dtResultats @(.search-summary)" />
|
||||
<ui:define name="items">
|
||||
<f:selectItem itemLabel="Actif" itemValue="ACTIF" />
|
||||
<f:selectItem itemLabel="Inactif" itemValue="INACTIF" />
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:selectCheckboxMenu id="#{id}"
|
||||
value="#{value}"
|
||||
multiple="true"
|
||||
styleClass="w-full">
|
||||
<ui:insert name="items" />
|
||||
<p:ajax update="#{not empty update ? update : ':formResultats:dtResultats @(.search-summary)'}" />
|
||||
</p:selectCheckboxMenu>
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<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 groupe de champs (formgrid) réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-group.xhtml">
|
||||
<ui:param name="content" value="contenu des champs groupés" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="formgrid grid">
|
||||
<ui:fragment rendered="#{not empty content}">
|
||||
#{content}
|
||||
</ui:fragment>
|
||||
<ui:insert />
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -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 champ numérique réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-number.xhtml">
|
||||
<ui:param name="id" value="ageMin" />
|
||||
<ui:param name="label" value="Âge minimum" />
|
||||
<ui:param name="value" value="#{bean.filtres.ageMin}" />
|
||||
<ui:param name="placeholder" value="Ex: 25" />
|
||||
<ui:param name="minValue" value="0" />
|
||||
<ui:param name="maxValue" value="100" />
|
||||
<ui:param name="update" value=":formResultats:dtResultats @(.search-summary)" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:inputNumber id="#{id}"
|
||||
value="#{value}"
|
||||
symbol=""
|
||||
placeholder="#{placeholder}"
|
||||
minValue="#{minValue}"
|
||||
maxValue="#{maxValue}"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="change"
|
||||
update="#{not empty update ? update : ':formResultats:dtResultats @(.search-summary)'}" />
|
||||
</p:inputNumber>
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
<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 champ de recherche texte avec AJAX réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-search-text.xhtml">
|
||||
<ui:param name="id" value="searchNom" />
|
||||
<ui:param name="label" value="Nom" />
|
||||
<ui:param name="value" value="#{bean.filtres.nom}" />
|
||||
<ui:param name="placeholder" value="Rechercher par nom..." />
|
||||
<ui:param name="update" value=":formResultats:dtResultats @(.search-summary)" />
|
||||
<ui:param name="event" value="keyup" />
|
||||
</ui:include>
|
||||
event: keyup, change, blur
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:inputText id="#{id}"
|
||||
value="#{value}"
|
||||
placeholder="#{placeholder}"
|
||||
styleClass="w-full">
|
||||
<p:ajax event="#{not empty event ? event : 'keyup'}"
|
||||
update="#{not empty update ? update : ':formResultats:dtResultats @(.search-summary)'}" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<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 champ sélection réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-select.xhtml">
|
||||
<ui:param name="id" value="fieldId" />
|
||||
<ui:param name="label" value="Label du champ" />
|
||||
<ui:param name="value" value="#{bean.property}" />
|
||||
<ui:param name="items" value="#{bean.options}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="var" value="item" />
|
||||
<ui:param name="itemLabel" value="#{item.label}" />
|
||||
<ui:param name="itemValue" value="#{item.value}" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:selectOneMenu id="#{id}"
|
||||
value="#{value}"
|
||||
required="#{not empty required and required}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" noSelectionOption="true" rendered="#{not empty required and required}" />
|
||||
<ui:fragment rendered="#{not empty var and not empty itemLabel and not empty itemValue}">
|
||||
<f:selectItems value="#{items}"
|
||||
var="#{var}"
|
||||
itemLabel="#{itemLabel}"
|
||||
itemValue="#{itemValue}" />
|
||||
</ui:fragment>
|
||||
<ui:fragment rendered="#{empty var}">
|
||||
<f:selectItems value="#{items}" />
|
||||
</ui:fragment>
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<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 champ texte réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-text.xhtml">
|
||||
<ui:param name="id" value="fieldId" />
|
||||
<ui:param name="label" value="Label du champ" />
|
||||
<ui:param name="value" value="#{bean.property}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="placeholder" value="Placeholder" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:inputText id="#{id}"
|
||||
value="#{value}"
|
||||
required="#{not empty required and required}"
|
||||
placeholder="#{placeholder}"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<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 champ textarea réutilisable (WOU/DRY)
|
||||
Usage: <ui:include src="/templates/components/form-field-textarea.xhtml">
|
||||
<ui:param name="id" value="fieldId" />
|
||||
<ui:param name="label" value="Label du champ" />
|
||||
<ui:param name="value" value="#{bean.property}" />
|
||||
<ui:param name="required" value="true" />
|
||||
<ui:param name="rows" value="4" />
|
||||
</ui:include>
|
||||
-->
|
||||
|
||||
<div class="field">
|
||||
<p:outputLabel for="#{id}" value="#{label}" />
|
||||
<p:inputTextarea id="#{id}"
|
||||
value="#{value}"
|
||||
required="#{not empty required and required}"
|
||||
rows="#{not empty rows ? rows : 3}"
|
||||
styleClass="w-full" />
|
||||
</div>
|
||||
</ui:composition>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user