feat(adherents): ajouter le récapitulatif des équipements et le filtre par statut dans la liste des adhérents

This commit is contained in:
2026-08-07 14:45:43 +02:00
parent 14730e667f
commit 2bd623b719
2 changed files with 57 additions and 2 deletions
@@ -47,6 +47,7 @@ public class AdherentController {
@org.springframework.web.bind.annotation.RequestParam(required = false) String nom,
@org.springframework.web.bind.annotation.RequestParam(required = false) String prenom,
@org.springframework.web.bind.annotation.RequestParam(required = false) String categorie,
@org.springframework.web.bind.annotation.RequestParam(required = false) String equipements,
@org.springframework.web.bind.annotation.RequestParam(required = false) String licence,
@org.springframework.web.bind.annotation.RequestParam(required = false) String email,
@org.springframework.web.bind.annotation.RequestParam(required = false) String paiement,
@@ -89,6 +90,26 @@ public class AdherentController {
).collect(java.util.stream.Collectors.toList());
model.addAttribute("categorieFilter", categorie.trim());
}
if (equipements != null && !equipements.trim().isEmpty()) {
String eqFilter = equipements.trim();
adherents = adherents.stream().filter(a -> {
Licence lic = a.getLicenceActuelle();
if (lic == null || lic.getDotations() == null || lic.getDotations().isEmpty()) {
return false;
}
long total = lic.getDotations().size();
long fournis = lic.getDotations().stream().filter(d -> Boolean.TRUE.equals(d.getFourni())).count();
if ("TOUT_FOURNI".equalsIgnoreCase(eqFilter)) {
return fournis == total;
} else if ("PARTIEL".equalsIgnoreCase(eqFilter)) {
return fournis > 0 && fournis < total;
} else if ("NON_FOURNI".equalsIgnoreCase(eqFilter)) {
return fournis == 0;
}
return true;
}).collect(java.util.stream.Collectors.toList());
model.addAttribute("equipementsFilter", eqFilter);
}
if (licence != null && !licence.trim().isEmpty()) {
String l = licence.trim().toLowerCase();
adherents = adherents.stream().filter(a ->
@@ -74,7 +74,7 @@
</div>
<div class="overflow-x-auto">
<table class="w-full text-left border-collapse min-w-[1000px]">
<table class="w-full text-left border-collapse min-w-[1150px]">
<thead>
<tr class="bg-gray-50 text-gray-500 text-sm uppercase tracking-wider border-b border-gray-200">
<th class="py-3 px-6 font-medium text-left cursor-pointer hover:bg-gray-100 transition-colors group select-none" onclick="updateSort('nom')">
@@ -107,6 +107,7 @@
</span>
</div>
</th>
<th class="py-3 px-4 font-medium text-center">Équipements</th>
<th class="py-3 px-6 font-medium text-center cursor-pointer hover:bg-gray-100 transition-colors group select-none" onclick="updateSort('licence')">
<div class="flex items-center justify-center space-x-1">
<span>N° Licence</span>
@@ -147,6 +148,14 @@
<option th:each="cat : ${categories}" th:value="${cat.nom}" th:text="${cat.nom}" th:selected="${categorieFilter == cat.nom}"></option>
</select>
</td>
<td class="py-2 px-3">
<select id="filterEquipements" name="equipements" class="w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-1 focus:ring-blue-500 focus:outline-none">
<option value="">Tous</option>
<option value="TOUT_FOURNI" th:selected="${equipementsFilter == 'TOUT_FOURNI'}">Complet (Tous)</option>
<option value="PARTIEL" th:selected="${equipementsFilter == 'PARTIEL'}">Partiel</option>
<option value="NON_FOURNI" th:selected="${equipementsFilter == 'NON_FOURNI'}">Non fourni</option>
</select>
</td>
<td class="py-2 px-3">
<input type="text" id="filterLicence" name="licence" th:value="${licenceFilter}" placeholder="Filtrer N°..." class="w-full border border-gray-300 rounded px-2 py-1 text-xs focus:ring-1 focus:ring-blue-500 focus:outline-none">
</td>
@@ -174,7 +183,7 @@
</thead>
<tbody class="divide-y divide-gray-200 text-sm">
<tr th:if="${#lists.isEmpty(adherents)}">
<td colspan="8" class="py-8 text-center text-gray-500">Aucun adhérent enregistré.</td>
<td colspan="9" class="py-8 text-center text-gray-500">Aucun adhérent enregistré.</td>
</tr>
<tr th:each="adherent : ${adherents}" class="hover:bg-gray-50 transition-colors adherent-row">
<td class="py-4 px-6 font-medium text-gray-900">
@@ -188,6 +197,31 @@
<td class="py-4 px-6 font-medium text-gray-900" th:text="${adherent.prenom}">Jean</td>
<td class="py-4 px-6 text-gray-600 font-medium"
th:text="${adherent.getLicenceActuelle() != null ? adherent.getLicenceActuelle().getCategorie().getNom() + (adherent.getLicenceActuelle().getEquipe() != null ? ' (' + adherent.getLicenceActuelle().getEquipe().getNom() + ')' : '') : '-'}">-</td>
<!-- Équipements Column -->
<td class="py-3 px-4 text-center">
<div th:if="${adherent.getLicenceActuelle() != null and !#lists.isEmpty(adherent.getLicenceActuelle().dotations)}" class="flex flex-col items-center space-y-1">
<span class="px-2 py-0.5 text-[9px] font-bold rounded-full border uppercase tracking-wider"
th:with="total=${#lists.size(adherent.getLicenceActuelle().dotations)},
fournis=${#lists.size(adherent.getLicenceActuelle().dotations.?[fourni == true])}"
th:classappend="${fournis == total ? 'bg-emerald-100 text-emerald-800 border-emerald-200' : (fournis > 0 ? 'bg-amber-100 text-amber-800 border-amber-200' : 'bg-rose-100 text-rose-800 border-rose-200')}"
th:text="${fournis == total ? '🟢 Complet (' + fournis + '/' + total + ')' : (fournis > 0 ? '🟠 Partiel (' + fournis + '/' + total + ')' : '🔴 Non fourni (0/' + total + ')')}"
>
Complet (3/3)
</span>
<div class="flex flex-wrap justify-center gap-1 max-w-[190px]">
<span th:each="dot : ${adherent.getLicenceActuelle().dotations}"
class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium border"
th:classappend="${dot.fourni ? 'bg-green-50 text-green-700 border-green-200' : 'bg-gray-50 text-gray-500 border-gray-200'}"
th:title="${(dot.equipement != null ? dot.equipement.nom : '') + (dot.taille != null and !dot.taille.isEmpty() ? ' (' + dot.taille + ')' : '') + ' : ' + (dot.fourni ? 'Fourni' : 'Non fourni')}">
<span class="mr-0.5" th:text="${dot.fourni ? '✓' : '✗'}"></span>
<span th:text="${dot.equipement != null ? dot.equipement.nom : 'Équipement'}">Maillot</span>
</span>
</div>
</div>
<div th:if="${adherent.getLicenceActuelle() == null or #lists.isEmpty(adherent.getLicenceActuelle().dotations)}" class="text-xs text-gray-400 italic">
-
</div>
</td>
<td class="py-4 px-6 text-center text-gray-600 font-mono text-xs"
th:text="${adherent.getLicenceActuelle() != null and adherent.getLicenceActuelle().numeroLicence != null and !adherent.getLicenceActuelle().numeroLicence.isEmpty() ? adherent.getLicenceActuelle().numeroLicence : '-'}">-</td>
<td class="py-4 px-6 text-gray-600" th:text="${adherent.email}">jean@example.com</td>