package dev.lions.unionflow.client.view; import dev.lions.unionflow.client.service.MembreService; import dev.lions.unionflow.server.api.dto.membre.response.MembreResponse; import dev.lions.unionflow.server.api.dto.membre.response.MembreSummaryResponse; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.inject.Named; import java.io.Serializable; import java.util.Collections; import java.util.List; import java.util.UUID; import org.eclipse.microprofile.rest.client.inject.RestClient; import org.jboss.logging.Logger; /** * Bean picker pour la sélection du Compliance Officer (Sprint 14 — Instr. BCEAO 001-03-2025). * *

Réutilise {@link MembreService} existant — DRY strict, aucun nouveau REST client. * *

Usage XHTML : *

 * <p:autoComplete value="#{model.complianceOfficerId}"
 *                completeMethod="#{complianceOfficerPickerBean.suggest}"
 *                var="m" itemLabel="#{complianceOfficerPickerBean.label(m)}"
 *                itemValue="#{m.id}" forceSelection="true" />
 * 
* * @since 2026-04-25 (Sprint 14) */ @Named("complianceOfficerPickerBean") @ApplicationScoped public class ComplianceOfficerPickerBean implements Serializable { private static final long serialVersionUID = 1L; private static final Logger LOG = Logger.getLogger(ComplianceOfficerPickerBean.class); @Inject @RestClient MembreService membreService; /** * Suggère des membres correspondant à la requête (utilisé par {@code p:autoComplete.completeMethod}). * Recherche via nom OU prénom. */ public List suggest(String query) { if (query == null || query.isBlank()) return Collections.emptyList(); try { // Recherche larges : nom OU prénom contenant la query List byNom = membreService.rechercher( query, null, null, null, null, null, 0, 10); List byPrenom = membreService.rechercher( null, query, null, null, null, null, 0, 10); java.util.LinkedHashMap uniques = new java.util.LinkedHashMap<>(); for (MembreResponse m : byNom) uniques.putIfAbsent(m.getId(), toSummary(m)); for (MembreResponse m : byPrenom) uniques.putIfAbsent(m.getId(), toSummary(m)); return new java.util.ArrayList<>(uniques.values()); } catch (Exception e) { LOG.warnf("Suggest membres failed for query='%s' : %s", query, e.getMessage()); return Collections.emptyList(); } } /** Label de présentation : "Prénom NOM (numéro)". */ public String label(MembreSummaryResponse m) { if (m == null) return ""; StringBuilder sb = new StringBuilder(); if (m.getPrenom() != null) sb.append(m.getPrenom()); if (m.getNom() != null) { if (sb.length() > 0) sb.append(' '); sb.append(m.getNom().toUpperCase()); } if (m.getNumeroMembre() != null && !m.getNumeroMembre().isBlank()) { sb.append(" (").append(m.getNumeroMembre()).append(')'); } return sb.length() == 0 ? "(membre " + m.getId() + ")" : sb.toString(); } /** Résolution UUID → membre pour affichage initial du form en mode édition. */ public MembreSummaryResponse resoudre(UUID id) { if (id == null) return null; try { MembreResponse m = membreService.obtenirParId(id); return toSummary(m); } catch (Exception e) { LOG.warnf("Résolution membre id=%s échouée : %s", id, e.getMessage()); return null; } } // ── Mapping interne ──────────────────────────────────────────────────── private MembreSummaryResponse toSummary(MembreResponse m) { if (m == null) return null; MembreSummaryResponse s = new MembreSummaryResponse(); s.setId(m.getId()); s.setNom(m.getNom()); s.setPrenom(m.getPrenom()); s.setEmail(m.getEmail()); s.setTelephone(m.getTelephone()); s.setNumeroMembre(m.getNumeroMembre()); s.setStatutCompte(m.getStatutCompte()); return s; } }