ui(adherents): afficher le detail des equipements dans un popover au clic sur le badge
AS Talange CI/CD Pipeline / Build & Run Unit Tests (push) Successful in 5m1s
AS Talange CI/CD Pipeline / Deploy to Test Environment (push) Successful in 6m20s

This commit is contained in:
2026-08-07 16:12:29 +02:00
parent 3612206e57
commit 5f372254f0
@@ -200,23 +200,47 @@
<!-- Équipements Column --> <!-- Équipements Column -->
<td class="py-3 px-4 text-center"> <td class="py-3 px-4 text-center">
<div th:with="choisis=${adherent.getLicenceActuelle() != null ? adherent.getLicenceActuelle().dotations.?[choisi == true] : null}"> <div th:with="choisis=${adherent.getLicenceActuelle() != null ? adherent.getLicenceActuelle().dotations.?[choisi == true] : null}">
<div th:if="${choisis != null and !#lists.isEmpty(choisis)}" class="flex flex-col items-center space-y-1"> <div th:if="${choisis != null and !#lists.isEmpty(choisis)}" class="relative inline-block text-left">
<span class="px-2 py-0.5 text-[9px] font-bold rounded-full border uppercase tracking-wider" <button type="button"
class="px-2.5 py-1 text-[9px] font-bold rounded-full border uppercase tracking-wider cursor-pointer hover:ring-2 hover:ring-offset-1 hover:ring-indigo-300 transition-all flex items-center space-x-1 mx-auto"
th:with="total=${#lists.size(choisis)}, th:with="total=${#lists.size(choisis)},
fournis=${#lists.size(choisis.?[fourni == true])}" fournis=${#lists.size(choisis.?[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: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 + ')')}" onclick="toggleEquipementsPopover(this, event)">
> <span th:text="${fournis == total ? '🟢 Complet (' + fournis + '/' + total + ')' : (fournis > 0 ? '🟠 Partiel (' + fournis + '/' + total + ')' : '🔴 Non fourni (0/' + total + ')')}"
th:data-total="${total}" th:data-fournis="${fournis}">
Complet (3/3) Complet (3/3)
</span> </span>
<div class="flex flex-wrap justify-center gap-1 max-w-[190px]"> <svg class="w-3 h-3 text-current opacity-70" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
<span th:each="dot : ${choisis}" </button>
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'}" <!-- Popover dropdown -->
th:title="${(dot.equipement != null ? dot.equipement.nom : '') + (dot.taille != null and !dot.taille.isEmpty() ? ' (' + dot.taille + ')' : '') + ' : ' + (dot.fourni ? 'Fourni' : 'Non fourni')}"> <div class="hidden absolute left-1/2 -translate-x-1/2 mt-2 w-64 bg-white rounded-xl shadow-xl border border-gray-200 p-3 z-50 text-left transition-all equipement-popover">
<span class="mr-0.5" th:text="${dot.fourni ? '✓' : '✗'}"></span> <div class="flex items-center justify-between pb-2 mb-2 border-b border-gray-100">
<span th:text="${dot.equipement != null ? dot.equipement.nom : 'Équipement'}">Maillot</span> <span class="text-xs font-semibold text-gray-800 flex items-center space-x-1">
<span>Détail Équipements</span>
<span class="text-[10px] font-bold text-gray-500 bg-gray-100 px-1.5 py-0.5 rounded-full" th:text="${#lists.size(choisis.?[fourni == true]) + '/' + #lists.size(choisis)}">3/3</span>
</span> </span>
<button type="button" class="text-gray-400 hover:text-gray-600 text-xs font-bold px-1" onclick="closeAllEquipementPopovers()">&times;</button>
</div>
<div class="space-y-1.5 max-h-48 overflow-y-auto pr-0.5">
<div th:each="dot : ${choisis}"
class="flex items-center justify-between p-2 rounded-lg text-xs border"
th:classappend="${dot.fourni ? 'bg-emerald-50/60 border-emerald-100 text-emerald-900' : 'bg-gray-50 border-gray-200 text-gray-700'}">
<div class="flex flex-col">
<span class="font-medium text-gray-900 leading-tight" th:text="${dot.equipement != null ? dot.equipement.nom : 'Équipement'}">Maillot</span>
<div class="text-[10px] text-gray-500 flex flex-wrap items-center gap-1 mt-0.5" th:if="${(dot.taille != null and !dot.taille.isEmpty()) or (dot.flocage != null and !dot.flocage.isEmpty()) or (dot.numero != null and !dot.numero.isEmpty())}">
<span th:if="${dot.taille != null and !dot.taille.isEmpty()}" class="font-mono bg-white/80 px-1 py-0.2 rounded border border-gray-200" th:text="'Taille: ' + ${dot.taille}">Taille: M</span>
<span th:if="${dot.flocage != null and !dot.flocage.isEmpty()}" class="italic" th:text="${dot.flocage}">Flocage</span>
<span th:if="${dot.numero != null and !dot.numero.isEmpty()}" class="font-mono font-bold" th:text="'#' + ${dot.numero}">#10</span>
</div>
</div>
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-bold flex-shrink-0"
th:classappend="${dot.fourni ? 'bg-emerald-100 text-emerald-800' : 'bg-gray-200 text-gray-600'}">
<span th:text="${dot.fourni ? '✓ Fourni' : '✗ Non fourni'}">✓ Fourni</span>
</span>
</div>
</div>
</div> </div>
</div> </div>
<div th:if="${choisis == null or #lists.isEmpty(choisis)}" class="text-xs text-gray-400 italic"> <div th:if="${choisis == null or #lists.isEmpty(choisis)}" class="text-xs text-gray-400 italic">
@@ -371,6 +395,26 @@
} }
sf.dispatchEvent(new Event('change', { bubbles: true })); sf.dispatchEvent(new Event('change', { bubbles: true }));
} }
function toggleEquipementsPopover(btn, event) {
if (event) event.stopPropagation();
const popover = btn.nextElementSibling;
const isVisible = popover && !popover.classList.contains('hidden');
closeAllEquipementPopovers();
if (popover && !isVisible) {
popover.classList.remove('hidden');
}
}
function closeAllEquipementPopovers() {
document.querySelectorAll('.equipement-popover').forEach(p => p.classList.add('hidden'));
}
document.addEventListener('click', function(event) {
if (!event.target.closest('.equipement-popover')) {
closeAllEquipementPopovers();
}
});
</script> </script>
</body> </body>
</html> </html>