ui(adherents): afficher le detail des equipements dans un popover au clic sur le badge
This commit is contained in:
@@ -200,23 +200,47 @@
|
||||
<!-- Équipements Column -->
|
||||
<td class="py-3 px-4 text-center">
|
||||
<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">
|
||||
<span class="px-2 py-0.5 text-[9px] font-bold rounded-full border uppercase tracking-wider"
|
||||
th:with="total=${#lists.size(choisis)},
|
||||
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: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 : ${choisis}"
|
||||
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>
|
||||
<div th:if="${choisis != null and !#lists.isEmpty(choisis)}" class="relative inline-block text-left">
|
||||
<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)},
|
||||
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')}"
|
||||
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)
|
||||
</span>
|
||||
<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>
|
||||
</button>
|
||||
|
||||
<!-- Popover dropdown -->
|
||||
<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">
|
||||
<div class="flex items-center justify-between pb-2 mb-2 border-b border-gray-100">
|
||||
<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>
|
||||
<button type="button" class="text-gray-400 hover:text-gray-600 text-xs font-bold px-1" onclick="closeAllEquipementPopovers()">×</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 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 }));
|
||||
}
|
||||
|
||||
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>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user