From 6d0dd660f29a82b7533f94d666b8d22ac8bc0016 Mon Sep 17 00:00:00 2001 From: dahoud Date: Wed, 10 Dec 2025 00:21:36 +0000 Subject: [PATCH] Update client submodule to latest commit (removed lions-user-manager dependency) --- .../service/MembreImportMultipartForm.java | 29 ++ .../client/view/MembreExportBean.java | 322 ++++++++++++++++++ .../client/view/MembreImportBean.java | 213 ++++++++++++ .../pages/secure/membre/export.xhtml | 310 +++++++++++++++++ .../pages/secure/membre/import.xhtml | 243 +++++++++++++ .../templates/components/cards/kpi-card.xhtml | 150 ++++++++ .../components/forms/detail-field-row.xhtml | 26 ++ .../templates/components/profile-photo.xhtml | 41 +++ 8 files changed, 1334 insertions(+) create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/service/MembreImportMultipartForm.java create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreExportBean.java create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreImportBean.java create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/export.xhtml create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/import.xhtml create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/cards/kpi-card.xhtml create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/forms/detail-field-row.xhtml create mode 100644 unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/profile-photo.xhtml diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/service/MembreImportMultipartForm.java b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/service/MembreImportMultipartForm.java new file mode 100644 index 0000000..a5bab24 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/service/MembreImportMultipartForm.java @@ -0,0 +1,29 @@ +package dev.lions.unionflow.client.service; + +import jakarta.ws.rs.FormParam; +import jakarta.ws.rs.core.MediaType; +import org.eclipse.microprofile.rest.client.annotation.RegisterProvider; +import org.jboss.resteasy.reactive.PartType; +import java.util.UUID; + +public class MembreImportMultipartForm { + @FormParam("file") + @PartType(MediaType.APPLICATION_OCTET_STREAM) + public byte[] file; + + @FormParam("fileName") + public String fileName; + + @FormParam("organisationId") + public UUID organisationId; + + @FormParam("typeMembreDefaut") + public String typeMembreDefaut; + + @FormParam("mettreAJourExistants") + public boolean mettreAJourExistants; + + @FormParam("ignorerErreurs") + public boolean ignorerErreurs; +} + diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreExportBean.java b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreExportBean.java new file mode 100644 index 0000000..675f894 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreExportBean.java @@ -0,0 +1,322 @@ +package dev.lions.unionflow.client.view; + +import dev.lions.unionflow.client.service.MembreService; +import dev.lions.unionflow.client.service.AssociationService; +import dev.lions.unionflow.server.api.dto.organisation.OrganisationDTO; +import dev.lions.unionflow.client.dto.AssociationDTO; +import lombok.Getter; +import lombok.Setter; +import jakarta.faces.view.ViewScoped; +import jakarta.inject.Named; +import jakarta.inject.Inject; +import jakarta.annotation.PostConstruct; +import jakarta.faces.context.FacesContext; +import jakarta.faces.application.FacesMessage; +import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import java.io.IOException; +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.logging.Logger; + +@Named("membreExportBean") +@ViewScoped +@Getter +@Setter +public class MembreExportBean implements Serializable { + + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(MembreExportBean.class.getName()); + + @Inject + @RestClient + MembreService membreService; + + @Inject + @RestClient + AssociationService associationService; + + // Configuration de l'export + private String formatExport = "EXCEL"; + private String scopeExport = "TOUS"; + private List colonnesExport = new ArrayList<>(); + + // Filtres + private String statutFilter = ""; + private String typeFilter = ""; + private UUID organisationId; + private LocalDate dateAdhesionDebut; + private LocalDate dateAdhesionFin; + + // Options d'export + private boolean inclureHeaders = true; + private boolean formaterDates = true; + private boolean inclureStatistiques = false; + private boolean chiffrerDonnees = false; + private String motDePasseExport = ""; + + // Organisations disponibles + private List organisationsDisponibles = new ArrayList<>(); + + // Statistiques + private int totalMembres = 0; + private int membresActifs = 0; + private int membresInactifs = 0; + private int nombreMembresAExporter = 0; + + // Historique des exports + private List historiqueExports = new ArrayList<>(); + + @PostConstruct + public void init() { + chargerOrganisations(); + chargerStatistiques(); + initialiserColonnesExport(); + } + + private void chargerOrganisations() { + organisationsDisponibles = new ArrayList<>(); + try { + List associations = associationService.listerToutes(0, 1000); + for (AssociationDTO assoc : associations) { + OrganisationDTO org = new OrganisationDTO(); + org.setId(assoc.getId()); + org.setNom(assoc.getNom()); + org.setVille(assoc.getVille()); + organisationsDisponibles.add(org); + } + LOGGER.info("Chargement de " + organisationsDisponibles.size() + " organisations disponibles"); + } catch (Exception e) { + LOGGER.severe("Erreur lors du chargement des organisations: " + e.getMessage()); + } + } + + private void chargerStatistiques() { + try { + MembreService.StatistiquesMembreDTO stats = membreService.obtenirStatistiques(); + if (stats != null) { + totalMembres = stats.getTotalMembres() != null ? stats.getTotalMembres().intValue() : 0; + membresActifs = stats.getMembresActifs() != null ? stats.getMembresActifs().intValue() : 0; + membresInactifs = stats.getMembresInactifs() != null ? stats.getMembresInactifs().intValue() : 0; + } + actualiserCompteur(); + } catch (Exception e) { + LOGGER.severe("Erreur lors du chargement des statistiques: " + e.getMessage()); + } + } + + private void initialiserColonnesExport() { + colonnesExport = new ArrayList<>(); + colonnesExport.add("PERSO"); + colonnesExport.add("CONTACT"); + colonnesExport.add("ADHESION"); + } + + public void actualiserCompteur() { + actualiserCompteur(null); + } + + public void actualiserCompteur(jakarta.faces.event.AjaxBehaviorEvent event) { + try { + // Appel au backend pour obtenir le comptage exact selon les filtres + String statut = null; + if ("ACTIFS".equals(scopeExport)) { + statut = "ACTIF"; + } else if ("INACTIFS".equals(scopeExport)) { + statut = "INACTIF"; + } else if (statutFilter != null && !statutFilter.isEmpty()) { + statut = statutFilter; + } + + String dateAdhesionDebutStr = dateAdhesionDebut != null ? dateAdhesionDebut.toString() : null; + String dateAdhesionFinStr = dateAdhesionFin != null ? dateAdhesionFin.toString() : null; + + Long count = membreService.compterMembresPourExport( + organisationId, + statut, + typeFilter != null && !typeFilter.isEmpty() ? typeFilter : null, + dateAdhesionDebutStr, + dateAdhesionFinStr + ); + + nombreMembresAExporter = count != null ? count.intValue() : 0; + + LOGGER.info("Comptage des membres pour export: " + nombreMembresAExporter); + + } catch (Exception e) { + LOGGER.severe("Erreur lors de l'actualisation du compteur: " + e.getMessage()); + // Fallback sur estimation basée sur les statistiques + if ("TOUS".equals(scopeExport)) { + nombreMembresAExporter = totalMembres; + } else if ("ACTIFS".equals(scopeExport)) { + nombreMembresAExporter = membresActifs; + } else if ("INACTIFS".equals(scopeExport)) { + nombreMembresAExporter = membresInactifs; + } else { + nombreMembresAExporter = 0; + } + } + } + + public void exporterMembres() { + if (colonnesExport == null || colonnesExport.isEmpty()) { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", + "Veuillez sélectionner au moins une catégorie de colonnes à exporter")); + return; + } + + if (nombreMembresAExporter == 0) { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", + "Aucun membre ne correspond aux critères sélectionnés")); + return; + } + + try { + LOGGER.info("Export des membres: format=" + formatExport + ", nombre=" + nombreMembresAExporter); + + String dateAdhesionDebutStr = dateAdhesionDebut != null ? dateAdhesionDebut.toString() : null; + String dateAdhesionFinStr = dateAdhesionFin != null ? dateAdhesionFin.toString() : null; + + // Générer un mot de passe aléatoire si le chiffrement est demandé + String motDePasse = null; + if (chiffrerDonnees) { + if (motDePasseExport != null && !motDePasseExport.trim().isEmpty()) { + motDePasse = motDePasseExport; + } else { + // Générer un mot de passe aléatoire de 12 caractères + motDePasse = genererMotDePasseAleatoire(); + } + } + + byte[] exportData = membreService.exporterExcel( + formatExport, + organisationId, + statutFilter, + typeFilter, + dateAdhesionDebutStr, + dateAdhesionFinStr, + colonnesExport, + inclureHeaders, + formaterDates, + inclureStatistiques && "EXCEL".equals(formatExport), // Statistiques uniquement pour Excel + motDePasse + ); + + FacesContext facesContext = FacesContext.getCurrentInstance(); + HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); + + response.reset(); + String contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; + String extension = "xlsx"; + + if ("CSV".equals(formatExport)) { + contentType = "text/csv"; + extension = "csv"; + } + + response.setContentType(contentType); + response.setHeader("Content-Disposition", "attachment; filename=\"membres_export_" + + LocalDate.now() + "." + extension + "\""); + response.setContentLength(exportData.length); + + response.getOutputStream().write(exportData); + response.getOutputStream().flush(); + facesContext.responseComplete(); + + // Ajouter à l'historique + ExportHistorique historique = new ExportHistorique(); + historique.setDate(LocalDateTime.now()); + historique.setFormat(formatExport); + historique.setNombreMembres(nombreMembresAExporter); + historique.setTaille(formatTaille(exportData.length)); + historiqueExports.add(0, historique); // Ajouter au début + + // Afficher le mot de passe si le chiffrement était demandé + if (chiffrerDonnees && motDePasse != null) { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_INFO, "Fichier protégé", + "Le fichier a été protégé par un mot de passe. " + + "Mot de passe: " + motDePasse + + " (Note: Le fichier est protégé contre la modification, mais peut toujours être ouvert)")); + } + + LOGGER.info("Export généré et téléchargé: " + exportData.length + " bytes"); + } catch (IOException e) { + LOGGER.severe("Erreur lors du téléchargement de l'export: " + e.getMessage()); + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", + "Impossible de télécharger l'export: " + e.getMessage())); + } catch (Exception e) { + LOGGER.severe("Erreur lors de l'export: " + e.getMessage()); + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", + "Impossible d'exporter les membres: " + e.getMessage())); + } + } + + private String formatTaille(long bytes) { + if (bytes < 1024) { + return bytes + " B"; + } else if (bytes < 1024 * 1024) { + return String.format("%.2f KB", bytes / 1024.0); + } else { + return String.format("%.2f MB", bytes / (1024.0 * 1024.0)); + } + } + + public void telechargerExport(ExportHistorique export) { + // L'historique est stocké localement dans la session, pas de téléchargement depuis le serveur + LOGGER.info("Export historique consulté: " + export.getDate() + " - " + export.getFormat()); + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_INFO, "Information", + "L'export du " + export.getDate().format(java.time.format.DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")) + + " n'est plus disponible. Veuillez générer un nouvel export.")); + } + + private String genererMotDePasseAleatoire() { + String caracteres = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%&*"; + java.util.Random random = new java.util.Random(); + StringBuilder motDePasse = new StringBuilder(12); + for (int i = 0; i < 12; i++) { + motDePasse.append(caracteres.charAt(random.nextInt(caracteres.length()))); + } + return motDePasse.toString(); + } + + public void reinitialiser() { + formatExport = "EXCEL"; + scopeExport = "TOUS"; + colonnesExport = new ArrayList<>(); + colonnesExport.add("PERSO"); + colonnesExport.add("CONTACT"); + colonnesExport.add("ADHESION"); + statutFilter = ""; + typeFilter = ""; + organisationId = null; + dateAdhesionDebut = null; + dateAdhesionFin = null; + inclureHeaders = true; + formaterDates = true; + inclureStatistiques = false; + chiffrerDonnees = false; + motDePasseExport = ""; + actualiserCompteur(); + } + + // Classe interne pour l'historique des exports + @Getter + @Setter + public static class ExportHistorique implements Serializable { + private LocalDateTime date; + private String format; + private int nombreMembres; + private String taille; + } +} + diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreImportBean.java b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreImportBean.java new file mode 100644 index 0000000..80785e5 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/java/dev/lions/unionflow/client/view/MembreImportBean.java @@ -0,0 +1,213 @@ +package dev.lions.unionflow.client.view; + +import dev.lions.unionflow.client.service.MembreService; +import dev.lions.unionflow.client.service.MembreImportMultipartForm; +import dev.lions.unionflow.client.service.AssociationService; +import dev.lions.unionflow.server.api.dto.organisation.OrganisationDTO; +import dev.lions.unionflow.client.dto.AssociationDTO; +import lombok.Getter; +import lombok.Setter; +import jakarta.faces.view.ViewScoped; +import jakarta.inject.Named; +import jakarta.inject.Inject; +import jakarta.annotation.PostConstruct; +import jakarta.faces.context.FacesContext; +import jakarta.faces.application.FacesMessage; +import jakarta.servlet.http.HttpServletResponse; +import org.eclipse.microprofile.rest.client.inject.RestClient; +import org.primefaces.event.FileUploadEvent; +import org.primefaces.model.file.UploadedFile; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.logging.Logger; + +@Named("membreImportBean") +@ViewScoped +@Getter +@Setter +public class MembreImportBean implements Serializable { + + private static final long serialVersionUID = 1L; + private static final Logger LOGGER = Logger.getLogger(MembreImportBean.class.getName()); + + @Inject + @RestClient + MembreService membreService; + + @Inject + @RestClient + AssociationService associationService; + + // Fichier à importer + private UploadedFile fichierImport; + + // Options d'import + private boolean mettreAJourExistants = false; + private boolean ignorerErreurs = false; + private UUID organisationId; + private String typeMembreDefaut = ""; + + // Organisations disponibles + private List organisationsDisponibles = new ArrayList<>(); + + // Résultat de l'import + private ResultatImport resultatImport; + + @PostConstruct + public void init() { + chargerOrganisations(); + } + + private void chargerOrganisations() { + organisationsDisponibles = new ArrayList<>(); + try { + List associations = associationService.listerToutes(0, 1000); + for (AssociationDTO assoc : associations) { + OrganisationDTO org = new OrganisationDTO(); + org.setId(assoc.getId()); + org.setNom(assoc.getNom()); + org.setVille(assoc.getVille()); + organisationsDisponibles.add(org); + } + LOGGER.info("Chargement de " + organisationsDisponibles.size() + " organisations disponibles"); + } catch (Exception e) { + LOGGER.severe("Erreur lors du chargement des organisations: " + e.getMessage()); + } + } + + /** + * Gère l'upload du fichier (appelé par PrimeFaces FileUpload) + */ + public void handleFileUpload(FileUploadEvent event) { + fichierImport = event.getFile(); + LOGGER.info("Fichier sélectionné: " + (fichierImport != null ? fichierImport.getFileName() : "null")); + } + + /** + * Lance l'import des membres + */ + public void importerMembres() { + if (fichierImport == null || fichierImport.getFileName() == null || fichierImport.getFileName().isEmpty()) { + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_WARN, "Attention", + "Veuillez sélectionner un fichier à importer")); + return; + } + + try { + LOGGER.info("Import du fichier: " + fichierImport.getFileName()); + + byte[] fileContent = fichierImport.getContent(); + String fileName = fichierImport.getFileName(); + + // Créer le formulaire multipart + MembreImportMultipartForm form = new MembreImportMultipartForm(); + form.file = fileContent; + form.fileName = fileName; + form.organisationId = organisationId; + form.typeMembreDefaut = typeMembreDefaut != null && !typeMembreDefaut.isEmpty() ? typeMembreDefaut : "ACTIF"; + form.mettreAJourExistants = mettreAJourExistants; + form.ignorerErreurs = ignorerErreurs; + + // Appeler le service REST + MembreService.ResultatImportDTO result = membreService.importerDonnees(form); + + // Convertir le résultat + resultatImport = new ResultatImport(); + resultatImport.setTotalTraite(result.getTotalLignes() != null ? result.getTotalLignes() : 0); + resultatImport.setReussis(result.getLignesTraitees() != null ? result.getLignesTraitees() : 0); + resultatImport.setEchecs(result.getLignesErreur() != null ? result.getLignesErreur() : 0); + resultatImport.setIgnores(0); + + // Convertir les erreurs + List erreursList = new ArrayList<>(); + if (result.getErreurs() != null) { + for (int i = 0; i < result.getErreurs().size(); i++) { + ErreurImport erreur = new ErreurImport(); + erreur.setLigne(i + 1); + erreur.setMessage(result.getErreurs().get(i)); + erreursList.add(erreur); + } + } + resultatImport.setErreurs(erreursList); + + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", + "Import terminé: " + resultatImport.getReussis() + " membres importés avec succès" + + (resultatImport.getEchecs() > 0 ? ", " + resultatImport.getEchecs() + " erreurs" : ""))); + + // Réinitialiser le fichier + fichierImport = null; + + } catch (Exception e) { + LOGGER.severe("Erreur lors de l'import: " + e.getMessage()); + LOGGER.log(java.util.logging.Level.SEVERE, "Détails de l'erreur d'import", e); + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", + "Impossible d'importer le fichier: " + e.getMessage())); + } + } + + public void telechargerModele() { + try { + LOGGER.info("Téléchargement du modèle d'import"); + + byte[] modele = membreService.telechargerModeleImport(); + + FacesContext facesContext = FacesContext.getCurrentInstance(); + HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); + + response.reset(); + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment; filename=\"modele_import_membres.xlsx\""); + response.setContentLength(modele.length); + + response.getOutputStream().write(modele); + response.getOutputStream().flush(); + facesContext.responseComplete(); + + LOGGER.info("Modèle d'import téléchargé"); + } catch (IOException e) { + LOGGER.severe("Erreur lors du téléchargement du modèle: " + e.getMessage()); + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", + "Impossible de télécharger le modèle: " + e.getMessage())); + } catch (Exception e) { + LOGGER.severe("Erreur lors du téléchargement du modèle: " + e.getMessage()); + FacesContext.getCurrentInstance().addMessage(null, + new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", + "Impossible de télécharger le modèle: " + e.getMessage())); + } + } + + public void reinitialiser() { + fichierImport = null; + mettreAJourExistants = false; + ignorerErreurs = false; + organisationId = null; + typeMembreDefaut = ""; + resultatImport = null; + } + + // Classe interne pour le résultat de l'import + @Getter + @Setter + public static class ResultatImport implements Serializable { + private int totalTraite; + private int reussis; + private int echecs; + private int ignores; + private List erreurs = new ArrayList<>(); + } + + @Getter + @Setter + public static class ErreurImport implements Serializable { + private int ligne; + private String message; + } +} + diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/export.xhtml b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/export.xhtml new file mode 100644 index 0000000..1d29dc9 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/export.xhtml @@ -0,0 +1,310 @@ + + + + + Export des Membres - UnionFlow + + + + + + + + + +
+ + + + + + +
+
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ +
Configuration de l'export
+ +
+
+
+ + + + + +
+
+ +
+
+ + + + + + + + +
+
+
+ + + + +
+ + + + + + + + + + + Sélectionnez au moins une catégorie de colonnes +
+
+
+ + + + +
+
+
+ + + + + + + + + +
+
+ +
+
+ + + + + + + + + +
+
+ +
+
+ + + + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + + + +
+
+
+
+
+ + + + + +
+
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + + Le fichier sera protégé par un mot de passe (généré automatiquement ou personnalisé ci-dessous) +
+
+ +
+
+ + + Si vide, un mot de passe aléatoire sera généré et affiché après l'export +
+
+
+
+
+ + +
+
+
+
Nombre de membres à exporter :
+
#{membreExportBean.nombreMembresAExporter} membre(s) correspond(ent) aux critères sélectionnés
+
+ + + + + + + + +
+
+ + +
+ + + + + + + + + + + + + + +
+
+
+ + +
+
Historique des exports
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+ diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/import.xhtml b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/import.xhtml new file mode 100644 index 0000000..8812613 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/pages/secure/membre/import.xhtml @@ -0,0 +1,243 @@ + + + + + Import en Masse des Membres - UnionFlow + + + + + + + + + +
+ + + + + + +
+
+
+
+ + +
+
+ +
+
Instructions d'import
+

+ Téléchargez le modèle Excel, remplissez-le avec les données des membres, puis importez-le ici. +

+
+
+
Format du fichier :
+
    +
  • Format Excel (.xlsx) ou CSV (.csv)
  • +
  • Maximum 1000 lignes par import
  • +
  • Taille maximale : 10 MB
  • +
+
+
+
Colonnes requises :
+
    +
  • Nom, Prénom (obligatoires)
  • +
  • Email, Téléphone (obligatoires)
  • +
  • Date de naissance, Adresse
  • +
  • Profession, Type membre
  • +
+
+
+
+
+
+ + +
+ +
Fichier à importer
+ +
+
+
+ + + Formats acceptés : .xlsx, .xls, .csv - Maximum 10 MB +
+
+ +
+
+ +
+ + + + + + + + +
+
+
+
+ + + + +
+
+
+ + + Si coché, les membres existants (même email) seront mis à jour +
+
+ +
+
+ + + Continuer l'import même si certaines lignes contiennent des erreurs +
+
+ +
+
+ + + + + +
+
+ +
+
+ + + + + + + + +
+
+
+
+
+ + +
+ + + +
+
+ + + + + + + +
+ +
+ + + + + + + +
+ +
+ + + + + + + +
+ +
+ + + + + + + +
+
+ +
+
Détails des erreurs :
+
+ +
+ Ligne #{erreur.ligne}: + #{erreur.message} +
+
+
+
+
+
+
+ + +
+ + + + + + + + + + + + + + +
+
+
+
+ +
+ diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/cards/kpi-card.xhtml b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/cards/kpi-card.xhtml new file mode 100644 index 0000000..0a97208 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/cards/kpi-card.xhtml @@ -0,0 +1,150 @@ + + + + + + + + + + +
+
+
+ +
+ #{title} +
+ +
+
+ + +
#{value}
+ + + + + +
+
+ #{statusLabel} + #{statusValue} +
+
+ Aucun utilisateur actif +
+
+ + + + + +
+ + +#{growthValue} + #{growthLabel} +
+
+ #{noDataLabel} +
+
+ + +
+ + +#{growthValue}% + #{growthLabel} +
+
+ #{noDataLabel} +
+
+
+
+
+ + + +
+
+
+ +
+ diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/forms/detail-field-row.xhtml b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/forms/detail-field-row.xhtml new file mode 100644 index 0000000..3687332 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/forms/detail-field-row.xhtml @@ -0,0 +1,26 @@ + + + + +
+ #{label}: +
+ #{value} + #{suffix} +
+
+
+ diff --git a/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/profile-photo.xhtml b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/profile-photo.xhtml new file mode 100644 index 0000000..ea75695 --- /dev/null +++ b/unionflow-client-quarkus-primefaces-freya/src/main/resources/META-INF/resources/templates/components/profile-photo.xhtml @@ -0,0 +1,41 @@ + + + + + + + +
+ +
+ #{initiales} +
+
+
+ + + +
+