865 lines
62 KiB
HTML
865 lines
62 KiB
HTML
<!DOCTYPE html>
|
|
<html xmlns:th="http://www.thymeleaf.org">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>Nouvel Adhérent - AS Talange</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://unpkg.com/htmx.org@1.9.11"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
body { font-family: 'Inter', sans-serif; }
|
|
.hidden-block { display: none; }
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-50 text-gray-900 flex h-screen overflow-hidden">
|
|
|
|
<!-- Sidebar -->
|
|
<div th:replace="~{fragments/sidebar :: sidebar}"></div>
|
|
|
|
<!-- Main Content -->
|
|
<main class="flex-1 flex flex-col h-screen overflow-hidden">
|
|
<!-- Header -->
|
|
<header class="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6">
|
|
<h2 class="text-lg font-semibold text-gray-800" th:text="${adherent.id == null ? 'Ajouter un adhérent' : 'Modifier l''adhérent'}">Ajouter un adhérent</h2>
|
|
</header>
|
|
|
|
<!-- Main section -->
|
|
<div class="flex-1 overflow-auto p-6">
|
|
<div class="max-w-6xl mx-auto bg-white rounded-xl shadow-sm border border-gray-100 p-8">
|
|
|
|
<form th:action="@{/adherents}" th:object="${adherent}" method="post" class="space-y-6">
|
|
<input type="hidden" th:field="*{id}" />
|
|
|
|
<div th:if="${#fields.hasErrors('global')}" class="bg-red-50 border border-red-200 text-red-600 px-4 py-3 rounded-lg text-sm mb-6">
|
|
<p th:each="err : ${#fields.errors('global')}" th:text="${err}"></p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Nom -->
|
|
<div>
|
|
<label for="nom" class="block text-sm font-medium text-gray-700 mb-1">Nom <span class="text-red-500">*</span></label>
|
|
<input type="text" id="nom" th:field="*{nom}" required
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('nom')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('nom')}" th:errors="*{nom}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
|
|
<!-- Prénom -->
|
|
<div>
|
|
<label for="prenom" class="block text-sm font-medium text-gray-700 mb-1">Prénom <span class="text-red-500">*</span></label>
|
|
<input type="text" id="prenom" th:field="*{prenom}" required
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('prenom')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('prenom')}" th:errors="*{prenom}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Date de Naissance -->
|
|
<div>
|
|
<label for="dateNaissance" class="block text-sm font-medium text-gray-700 mb-1">Date de naissance <span class="text-red-500">*</span></label>
|
|
<input type="date" id="dateNaissance" th:field="*{dateNaissance}" required
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('dateNaissance')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('dateNaissance')}" th:errors="*{dateNaissance}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
|
|
<!-- Lieu de naissance (Ville) -->
|
|
<div>
|
|
<label for="lieuNaissanceVille" class="block text-sm font-medium text-gray-700 mb-1">Ville de naissance <span class="text-red-500">*</span></label>
|
|
<input type="text" id="lieuNaissanceVille" th:field="*{lieuNaissanceVille}" required
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('lieuNaissanceVille')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('lieuNaissanceVille')}" th:errors="*{lieuNaissanceVille}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Lieu de naissance (Pays) -->
|
|
<div>
|
|
<label for="lieuNaissancePays" class="block text-sm font-medium text-gray-700 mb-1">Pays de naissance <span class="text-red-500">*</span></label>
|
|
<input type="text" id="lieuNaissancePays" th:field="*{lieuNaissancePays}" required
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('lieuNaissancePays')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('lieuNaissancePays')}" th:errors="*{lieuNaissancePays}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
|
|
<!-- Nationalité -->
|
|
<div>
|
|
<label for="nationalite" class="block text-sm font-medium text-gray-700 mb-1">Nationalité <span class="text-red-500">*</span></label>
|
|
<input type="text" id="nationalite" th:field="*{nationalite}" required
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('nationalite')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('nationalite')}" th:errors="*{nationalite}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Removed telephone -->
|
|
|
|
<!-- Représentant Légal (Dynamique) -->
|
|
<div id="representantBlock" class="hidden-block bg-blue-50 p-4 rounded-lg border border-blue-100">
|
|
<label for="representantLegal" class="block text-sm font-medium text-blue-800 mb-1">
|
|
Représentant légal <span class="text-red-500">*</span>
|
|
</label>
|
|
<p class="text-xs text-blue-600 mb-2">Obligatoire car l'adhérent a moins de 18 ans.</p>
|
|
<input type="text" id="representantLegal" th:field="*{representantLegal}"
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('representantLegal')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('representantLegal')}" th:errors="*{representantLegal}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Email -->
|
|
<div>
|
|
<label for="email" class="block text-sm font-medium text-gray-700 mb-1">Email <span class="text-red-500">*</span></label>
|
|
<input type="email" id="email" th:field="*{email}" required
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('email')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('email')}" th:errors="*{email}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
|
|
<!-- Téléphone -->
|
|
<div>
|
|
<label for="telephone" class="block text-sm font-medium text-gray-700 mb-1">Téléphone</label>
|
|
<input type="tel" id="telephone" th:field="*{telephone}"
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('telephone')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('telephone')}" th:errors="*{telephone}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
|
<!-- Sexe -->
|
|
<div>
|
|
<label for="sexe" class="block text-sm font-medium text-gray-700 mb-1">Sexe</label>
|
|
<select id="sexe" th:field="*{sexe}" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors">
|
|
<option value="MASCULIN">Masculin</option>
|
|
<option value="FEMININ">Féminin</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Type de Maillot / Poste -->
|
|
<div>
|
|
<label for="typeMaillot" class="block text-sm font-medium text-gray-700 mb-1">Poste (Type de maillot)</label>
|
|
<select id="typeMaillot" th:field="*{typeMaillot}" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors">
|
|
<option value="JOUEUR">Joueur de champ</option>
|
|
<option value="GARDIEN">Gardien de but</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
|
|
<!-- Type de demande (Read-only) -->
|
|
<div>
|
|
<label for="typeDemande" class="block text-sm font-medium text-gray-700 mb-1">Type de demande (Pré-inscription)</label>
|
|
<input type="text" id="typeDemande" th:field="*{typeDemande}" readonly
|
|
class="w-full border border-gray-200 bg-gray-50 rounded-lg px-4 py-2 text-sm text-gray-500 outline-none cursor-not-allowed">
|
|
</div>
|
|
|
|
<!-- Ancien club -->
|
|
<div>
|
|
<label for="ancienClub" class="block text-sm font-medium text-gray-700 mb-1">Ancien club</label>
|
|
<input type="text" id="ancienClub" th:field="*{ancienClub}"
|
|
class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none transition-colors"
|
|
th:classappend="${#fields.hasErrors('ancienClub')} ? 'border-red-500' : ''">
|
|
<p th:if="${#fields.hasErrors('ancienClub')}" th:errors="*{ancienClub}" class="mt-1 text-xs text-red-600"></p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Removed Adresse -->
|
|
|
|
<div class="pt-4 flex justify-end space-x-3 border-t border-gray-100">
|
|
<a th:href="@{/adherents}" class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors">Annuler</a>
|
|
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors">Enregistrer</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Licences Section (Only visible for existing adherents) -->
|
|
<div th:if="${adherent.id != null}" class="max-w-6xl mx-auto bg-white rounded-xl shadow-sm border border-gray-100 p-8 mt-6">
|
|
<div class="flex justify-between items-center mb-6">
|
|
<h3 class="text-xl font-bold text-gray-900">Licences de l'adhérent</h3>
|
|
<button th:if="${#lists.isEmpty(licences)}" onclick="openLicenceModal()" class="bg-green-600 text-white px-4 py-2 rounded-lg text-sm font-medium hover:bg-green-700 transition-colors">
|
|
+ Ajouter une Licence
|
|
</button>
|
|
</div>
|
|
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-left border-collapse min-w-[800px]">
|
|
<thead>
|
|
<tr class="bg-gray-50 text-gray-500 text-sm uppercase tracking-wider border-b border-gray-200">
|
|
<th class="py-3 px-4 font-medium">Saison</th>
|
|
<th class="py-3 px-4 font-medium">Catégorie</th>
|
|
<th class="py-3 px-4 font-medium">Demande / Type</th>
|
|
<th class="py-3 px-4 font-medium">N° Licence</th>
|
|
<th class="py-3 px-4 font-medium">État</th>
|
|
<th class="py-3 px-4 font-medium">Tarif Global</th>
|
|
<th class="py-3 px-4 font-medium">Reste à Payer</th>
|
|
<th class="py-3 px-4 font-medium text-right">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-200 text-sm">
|
|
<tr th:if="${#lists.isEmpty(licences)}">
|
|
<td colspan="8" class="py-4 px-4 text-center text-gray-500">Aucune licence enregistrée.</td>
|
|
</tr>
|
|
<th:block th:each="lic : ${licences}">
|
|
<tr class="hover:bg-gray-50 border-b border-gray-100 licence-row"
|
|
th:data-tarif-base="${lic.categorie.tarifBase}"
|
|
th:data-tarif-exterieur="${lic.categorie.tarifExterieur}"
|
|
th:data-equipements-contrib="${lic.getPrixTotal().subtract(adherent.residentTalange ? lic.categorie.tarifBase : lic.categorie.tarifExterieur)}"
|
|
th:data-total-paye="${lic.getPrixTotal().subtract(lic.getResteAPayer())}">
|
|
<td class="py-4 px-4 font-medium text-gray-900" th:text="${lic.saison.nom}">2024-2025</td>
|
|
<td class="py-4 px-4 text-gray-600">
|
|
<span th:text="${lic.categorie.nom + (lic.equipe != null ? ' (' + lic.equipe.nom + ')' : '')}">U15</span>
|
|
<span class="text-[10px] text-gray-400 block cell-tarif-categorie" th:text="${(lic.adherent != null && lic.adherent.residentTalange ? lic.categorie.tarifBase : lic.categorie.tarifExterieur) + ' € (Catégorie)'}">100.00 € (Catégorie)</span>
|
|
</td>
|
|
<td class="py-4 px-4 text-gray-600 text-xs">
|
|
<div th:text="${lic.typeDemande != null ? lic.typeDemande : '-'}">Nouvelle</div>
|
|
<div class="text-[10px] text-gray-500" th:text="${lic.typeLicence != null ? lic.typeLicence : '-'}">Libre</div>
|
|
</td>
|
|
<td class="py-4 px-4 text-gray-600 font-mono text-xs" th:text="${lic.numeroLicence != null and !lic.numeroLicence.isEmpty() ? lic.numeroLicence : '-'}">-</td>
|
|
<td class="py-4 px-4">
|
|
<span class="px-2 py-1 text-xs font-semibold rounded-full"
|
|
th:classappend="${lic.etat == 'Validée' ? 'bg-blue-100 text-blue-800' : (lic.etat == 'Payée' ? 'bg-green-100 text-green-800' : 'bg-yellow-100 text-yellow-800')}"
|
|
th:text="${lic.etat}">Brouillon</span>
|
|
</td>
|
|
<td class="py-4 px-4 text-gray-900 font-medium cell-tarif-global" th:text="${lic.getPrixTotal() + ' €'}">130.00 €</td>
|
|
<td class="py-4 px-4 font-semibold cell-reste-payer"
|
|
th:classappend="${lic.getResteAPayer() == 0 ? 'text-green-600' : 'text-red-600'}"
|
|
th:text="${lic.getResteAPayer() + ' €'}">30.00 €</td>
|
|
<td class="py-4 px-4 text-right flex justify-end space-x-2">
|
|
<button type="button"
|
|
th:data-licence-id="${lic.id}"
|
|
th:data-categorie-id="${lic.categorie.id}"
|
|
th:data-numero-licence="${lic.numeroLicence}"
|
|
th:data-etat="${lic.etat}"
|
|
th:data-type-demande="${lic.typeDemande}"
|
|
th:data-type-licence="${lic.typeLicence}"
|
|
th:data-equipe-id="${lic.equipe != null ? lic.equipe.id : ''}"
|
|
onclick="openLicenceModal(this.getAttribute('data-licence-id'), this.getAttribute('data-categorie-id'), this.getAttribute('data-numero-licence'), this.getAttribute('data-etat'), this.getAttribute('data-type-demande'), this.getAttribute('data-type-licence'), this.getAttribute('data-equipe-id'))"
|
|
class="text-blue-600 hover:text-blue-800 font-medium bg-blue-50 px-3 py-1 rounded-lg">Modifier</button>
|
|
<button th:if="${lic.getResteAPayer() > 0}"
|
|
type="button"
|
|
th:data-licence-id="${lic.id}"
|
|
th:data-reste-a-payer="${lic.getResteAPayer()}"
|
|
onclick="openPaiementModal(this.getAttribute('data-licence-id'), this.getAttribute('data-reste-a-payer'))"
|
|
class="text-green-600 hover:text-green-800 font-medium bg-green-50 px-3 py-1 rounded-lg btn-payer">Payer</button>
|
|
</td>
|
|
</tr>
|
|
<tr th:if="${!#lists.isEmpty(lic.paiements)}" class="bg-gray-50/50">
|
|
<td colspan="8" class="py-3 px-6">
|
|
<div class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2">Historique des paiements</div>
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full divide-y divide-gray-200 bg-white rounded-lg border border-gray-200 shadow-sm text-xs">
|
|
<thead>
|
|
<tr class="bg-gray-50 text-gray-500 uppercase font-medium">
|
|
<th class="py-2 px-3 text-left">Date</th>
|
|
<th class="py-2 px-3 text-left">Mode</th>
|
|
<th class="py-2 px-3 text-left">Géré par</th>
|
|
<th class="py-2 px-3 text-right font-medium">Montant</th>
|
|
<th class="py-2 px-3 text-right font-medium pr-4">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-gray-100">
|
|
<tr th:each="paiement : ${lic.paiements}" class="hover:bg-gray-50">
|
|
<td class="py-2 px-3 text-gray-600 font-medium" th:text="${#temporals.format(paiement.datePaiement, 'dd/MM/yyyy')}">01/01/2026</td>
|
|
<td class="py-2 px-3 text-gray-600">
|
|
<span class="px-2 py-0.5 rounded bg-gray-100 text-gray-700 font-mono text-[10px]" th:text="${paiement.modePaiement.nom}">Chèque</span>
|
|
</td>
|
|
<td class="py-2 px-3 text-gray-500 text-xs italic" th:text="${paiement.gestionnaire != null ? paiement.gestionnaire : '-'}">-</td>
|
|
<td class="py-2 px-3 text-right font-semibold text-green-600" th:text="${paiement.montant + ' €'}">50.00 €</td>
|
|
<td class="py-2 px-3 text-right pr-4">
|
|
<div class="flex justify-end items-center space-x-2">
|
|
<button type="button"
|
|
th:data-paiement-id="${paiement.id}"
|
|
th:data-montant="${paiement.montant}"
|
|
th:data-date="${paiement.datePaiement}"
|
|
th:data-mode-id="${paiement.modePaiement.id}"
|
|
th:data-licence-id="${lic.id}"
|
|
th:data-max-amount="${lic.getResteAPayer().add(paiement.montant)}"
|
|
onclick="openEditPaiementModal(this.getAttribute('data-paiement-id'), this.getAttribute('data-montant'), this.getAttribute('data-date'), this.getAttribute('data-mode-id'), this.getAttribute('data-licence-id'), this.getAttribute('data-max-amount'))"
|
|
class="text-blue-600 hover:text-blue-900 bg-blue-50 hover:bg-blue-100 p-1.5 rounded transition-colors inline-flex items-center"
|
|
title="Modifier">
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
|
|
</svg>
|
|
</button>
|
|
<form th:action="@{/paiements/{id}/delete(id=${paiement.id})}" method="post" class="inline m-0" onsubmit="return confirm('Êtes-vous sûr de vouloir supprimer ce paiement ?');">
|
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
|
<button type="submit" class="text-red-600 hover:text-red-900 bg-red-50 hover:bg-red-100 p-1.5 rounded transition-colors inline-flex items-center" title="Supprimer">
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"/>
|
|
</svg>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<tr class="bg-gray-50/30">
|
|
<td colspan="7" class="py-3 px-4 border-t border-gray-100">
|
|
<form th:action="@{/dotations/bulk}" method="post">
|
|
<input type="hidden" name="adherentId" th:value="${adherent.id}">
|
|
|
|
<div class="flex justify-between items-center mb-3">
|
|
<div class="text-xs text-gray-500 font-medium uppercase tracking-wider">Dotations Équipements</div>
|
|
<button th:if="${!#lists.isEmpty(lic.dotations)}" type="submit"
|
|
class="bg-blue-600 hover:bg-blue-700 text-white text-xs px-3 py-1.5 rounded-lg font-semibold shadow-sm transition-colors flex items-center space-x-1">
|
|
<svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
|
</svg>
|
|
<span>Enregistrer les dotations</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div th:if="${#lists.isEmpty(lic.dotations)}" class="text-xs text-gray-500 italic">Aucune dotation pour cette licence.</div>
|
|
|
|
<div th:if="${!#lists.isEmpty(lic.dotations)}" class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4">
|
|
<div th:each="dot : ${lic.dotations}" class="bg-white p-3 rounded-lg border border-gray-200 shadow-sm flex flex-col justify-between">
|
|
<input type="hidden" name="dotationIds" th:value="${dot.id}">
|
|
|
|
<div>
|
|
<div class="flex justify-between items-start mb-1 gap-1">
|
|
<span class="font-semibold text-xs text-gray-800 truncate" th:text="${dot.equipement.nom}">Maillot</span>
|
|
<span class="text-[9px] px-1.5 py-0.5 rounded-full font-bold flex-shrink-0"
|
|
th:classappend="${dot.licence.categorie.isEquipementObligatoire(dot.equipement.id) ? 'bg-red-50 text-red-700 border border-red-100' : 'bg-gray-50 text-gray-600 border border-gray-100'}"
|
|
th:text="${dot.licence.categorie.isEquipementObligatoire(dot.equipement.id) ? 'Obligatoire' : 'Facultatif'}">Obligatoire</span>
|
|
</div>
|
|
<div class="text-[10px] text-gray-400 mb-2 truncate" th:title="${dot.equipement.description}" th:text="${dot.equipement.description != null and !dot.equipement.description.isEmpty() ? dot.equipement.description : 'Pas de description'}">Description</div>
|
|
<!-- Special dynamic label for equipment style -->
|
|
<div class="mb-2" th:if="${dot.equipement.nom == 'Maillot' or dot.equipement.nom == 'Short' or dot.equipement.nom == 'Chaussettes'}">
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-[10px] font-semibold bg-blue-50 text-blue-700 border border-blue-100 dotation-style-label"
|
|
th:data-equipement="${dot.equipement.nom}"
|
|
th:text="${adherent.sexe == 'FEMININ' ? 'Modèle Femme' : 'Modèle Homme'} + ' - ' + ${adherent.typeMaillot == 'GARDIEN' ? 'Gardien' : 'Joueur'}">
|
|
Modèle Homme - Joueur
|
|
</span>
|
|
</div>
|
|
<div class="mb-2" th:if="${dot.equipement.nom == 'Survêtement'}">
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-[10px] font-semibold bg-indigo-50 text-indigo-700 border border-indigo-100 dotation-style-label"
|
|
th:data-equipement="${dot.equipement.nom}"
|
|
th:text="${adherent.sexe == 'FEMININ' ? 'Modèle Femme' : 'Modèle Homme'}">
|
|
Modèle Homme
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form inputs for bulk updating -->
|
|
<div class="space-y-2 pt-2 border-t border-gray-100">
|
|
<!-- Choisi checkbox for optional equipment -->
|
|
<div class="flex items-center mb-1.5 bg-blue-50/50 p-1.5 rounded border border-blue-100/50" th:if="${!dot.licence.categorie.isEquipementObligatoire(dot.equipement.id)}">
|
|
<label class="flex items-center space-x-1.5 cursor-pointer select-none">
|
|
<input type="checkbox" th:name="'choisi_' + ${dot.id}" th:checked="${dot.choisi}" class="w-3.5 h-3.5 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
|
|
<span class="text-[10px] font-bold text-blue-800 uppercase tracking-wide" th:text="'Commander (+ ' + ${dot.licence.categorie.getEquipementPrix(dot.equipement.id)} + ' €)'">Commander (+ 30 €)</span>
|
|
</label>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-1.5 mb-1.5">
|
|
<div>
|
|
<label class="block text-[9px] uppercase font-bold text-gray-400">Taille</label>
|
|
<input type="text" th:name="'taille_' + ${dot.id}" th:value="${dot.taille}" placeholder="S, M, L..."
|
|
class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div>
|
|
<label class="block text-[9px] uppercase font-bold text-gray-400">Numéro</label>
|
|
<input type="text" th:name="'numero_' + ${dot.id}" th:value="${dot.numero}" placeholder="Ex: 10"
|
|
class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-[9px] uppercase font-bold text-gray-400">Flocage</label>
|
|
<input type="text" th:name="'flocage_' + ${dot.id}" th:value="${dot.flocage}" placeholder="Nom du joueur"
|
|
class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 focus:ring-1 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div class="flex items-center pt-1.5">
|
|
<label class="flex items-center space-x-1 cursor-pointer select-none">
|
|
<input type="checkbox" th:name="'fourni_' + ${dot.id}" th:checked="${dot.fourni}" class="w-3.5 h-3.5 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
|
|
<span class="text-[11px] text-gray-700">Fourni</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
</th:block>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
</div>
|
|
</main>
|
|
|
|
<!-- Licence Modal -->
|
|
<div id="licenceModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden z-50">
|
|
<div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-xl bg-white">
|
|
<div class="mt-3 text-center">
|
|
<h3 id="licenceModalTitle" class="text-lg leading-6 font-semibold text-gray-900 mb-4">Nouvelle Licence</h3>
|
|
<form id="licenceForm" th:if="${adherent.id != null}" th:action="@{/adherents/{id}/licences(id=${adherent.id})}" method="post" class="space-y-4 text-left">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Catégorie</label>
|
|
<select id="categorieSelect" name="categorieId" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<option value="">Sélectionnez une catégorie...</option>
|
|
<option th:each="cat : ${categories}" th:value="${cat.id}"
|
|
th:data-nom="${cat.nom}"
|
|
th:data-annee-min="${cat.anneeMin}"
|
|
th:data-annee-max="${cat.anneeMax}"
|
|
th:data-tarif-base="${cat.tarifBase}"
|
|
th:data-tarif-exterieur="${cat.tarifExterieur}"
|
|
th:text="${cat.nom} + ' (Talange: ' + ${cat.tarifBase} + ' € / Ext: ' + ${cat.tarifExterieur} + ' €)'"></option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Équipe</label>
|
|
<select id="licenceEquipe" name="equipeId" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<th:block th:fragment="equipe-options">
|
|
<option value="">Aucune équipe</option>
|
|
<option th:each="team : ${equipes}" th:value="${team.id}" th:text="${team.nom}"></option>
|
|
</th:block>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Numéro de licence</label>
|
|
<input id="numeroLicenceInput" type="text" name="numeroLicence" placeholder="Ex: FFF-123456" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Type de demande</label>
|
|
<select id="typeDemandeSelect" name="typeDemande" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<option value="">Sélectionnez...</option>
|
|
<option value="Renouvellement">Renouvellement</option>
|
|
<option value="Nouvelle demande">Nouvelle demande</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Type de licence</label>
|
|
<select id="typeLicenceSelect" name="typeLicence" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<option value="">Sélectionnez...</option>
|
|
<option value="Animateur">Animateur</option>
|
|
<option value="Arbitre">Arbitre</option>
|
|
<option value="Dirigeant">Dirigeant</option>
|
|
<option value="Educateur Fédéral">Educateur Fédéral</option>
|
|
<option value="Foot loisir">Foot loisir</option>
|
|
<option value="Libre">Libre</option>
|
|
<option value="Technique">Technique</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Saison</label>
|
|
<input id="saisonInput" type="text" name="saison" value="Saison Actuelle" readonly class="w-full border border-gray-200 bg-gray-50 rounded-lg px-4 py-2 text-sm text-gray-500 outline-none cursor-not-allowed">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">État</label>
|
|
<select id="etatSelect" name="etat" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<option value="Brouillon">Brouillon</option>
|
|
<option value="Validée">Validée</option>
|
|
<option value="Payée">Payée</option>
|
|
</select>
|
|
</div>
|
|
<div class="items-center px-4 py-3 flex justify-end space-x-2">
|
|
<button type="button" onclick="closeLicenceModal()" class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">Annuler</button>
|
|
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700">Enregistrer</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Paiement Modal -->
|
|
<div id="paiementModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden z-50">
|
|
<div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-xl bg-white">
|
|
<div class="mt-3 text-center">
|
|
<h3 class="text-lg leading-6 font-semibold text-gray-900 mb-4">Enregistrer un Paiement</h3>
|
|
<form id="paiementForm" method="post" class="space-y-4 text-left">
|
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
|
<input type="hidden" name="adherentId" th:value="${adherent.id}">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Montant (€)</label>
|
|
<input type="number" step="0.01" id="paiementMontant" name="montant" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Date</label>
|
|
<input type="date" id="paiementDate" name="datePaiement" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Mode de paiement</label>
|
|
<select name="modePaiementId" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<option value="">Sélectionnez un mode...</option>
|
|
<option th:each="mode : ${modesPaiement}" th:value="${mode.id}" th:text="${mode.nom}"></option>
|
|
</select>
|
|
</div>
|
|
<div class="items-center px-4 py-3 flex justify-end space-x-2">
|
|
<button type="button" onclick="closePaiementModal()" class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">Annuler</button>
|
|
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-green-600 rounded-lg hover:bg-green-700">Payer</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Edit Paiement Modal -->
|
|
<div id="editPaiementModal" class="fixed inset-0 bg-gray-600 bg-opacity-50 overflow-y-auto h-full w-full hidden z-50">
|
|
<div class="relative top-20 mx-auto p-5 border w-96 shadow-lg rounded-xl bg-white">
|
|
<div class="mt-3 text-center">
|
|
<h3 class="text-lg leading-6 font-semibold text-gray-900 mb-4">Modifier le Paiement</h3>
|
|
<form id="editPaiementForm" method="post" class="space-y-4 text-left">
|
|
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
|
|
<input type="hidden" name="adherentId" th:value="${adherent.id}">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Montant (€)</label>
|
|
<input type="number" step="0.01" min="0.01" id="editPaiementMontant" name="montant" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Date</label>
|
|
<input type="date" id="editPaiementDate" name="datePaiement" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Mode de paiement</label>
|
|
<select id="editPaiementMode" name="modePaiementId" required class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
|
<option value="">Sélectionnez un mode...</option>
|
|
<option th:each="mode : ${modesPaiement}" th:value="${mode.id}" th:text="${mode.nom}"></option>
|
|
</select>
|
|
</div>
|
|
<div class="items-center px-4 py-3 flex justify-end space-x-2">
|
|
<button type="button" onclick="closeEditPaiementModal()" class="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50">Annuler</button>
|
|
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700">Enregistrer</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script th:inline="javascript">
|
|
function openLicenceModal(licenceId = null, categorieId = '', numeroLicence = '', etat = 'Brouillon', typeDemande = '', typeLicence = '', equipeId = '') {
|
|
document.getElementById('licenceModal').classList.remove('hidden');
|
|
const form = document.getElementById('licenceForm');
|
|
const title = document.getElementById('licenceModalTitle');
|
|
const adherentId = [[${adherent.id}]];
|
|
const catSelect = document.getElementById('categorieSelect');
|
|
const equipeSelect = document.getElementById('licenceEquipe');
|
|
|
|
// Clean up team options first
|
|
equipeSelect.innerHTML = '<option value="">Aucune équipe</option>';
|
|
|
|
if (licenceId) {
|
|
title.textContent = 'Modifier la Licence';
|
|
form.action = '/adherents/' + adherentId + '/licences/' + licenceId + '/update';
|
|
catSelect.value = categorieId;
|
|
document.getElementById('numeroLicenceInput').value = numeroLicence;
|
|
document.getElementById('etatSelect').value = etat;
|
|
document.getElementById('typeDemandeSelect').value = typeDemande;
|
|
document.getElementById('typeLicenceSelect').value = typeLicence;
|
|
|
|
// Fetch and populate teams
|
|
if (categorieId) {
|
|
fetch('/categories/equipes?categorieId=' + categorieId)
|
|
.then(response => response.text())
|
|
.then(html => {
|
|
equipeSelect.innerHTML = html;
|
|
equipeSelect.value = equipeId;
|
|
});
|
|
}
|
|
} else {
|
|
title.textContent = 'Nouvelle Licence';
|
|
form.action = '/adherents/' + adherentId + '/licences';
|
|
document.getElementById('numeroLicenceInput').value = '';
|
|
document.getElementById('etatSelect').value = 'Brouillon';
|
|
|
|
// Pré-remplissage du type de demande
|
|
const adherentTypeDemande = document.getElementById('typeDemande') ? document.getElementById('typeDemande').value : '';
|
|
const typeDemandeSelect = document.getElementById('typeDemandeSelect');
|
|
if (adherentTypeDemande === 'NOUVELLE') {
|
|
typeDemandeSelect.value = 'Nouvelle demande';
|
|
} else if (adherentTypeDemande === 'RENOUVELLEMENT') {
|
|
typeDemandeSelect.value = 'Renouvellement';
|
|
} else {
|
|
typeDemandeSelect.value = '';
|
|
}
|
|
|
|
document.getElementById('typeLicenceSelect').value = '';
|
|
|
|
// Pré-sélection de la catégorie selon l'année de naissance
|
|
const dateNaissanceStr = document.getElementById('dateNaissance').value;
|
|
let foundCat = false;
|
|
let preSelectedCatId = '';
|
|
|
|
if (dateNaissanceStr) {
|
|
const birthYear = new Date(dateNaissanceStr).getFullYear();
|
|
|
|
Array.from(catSelect.options).forEach(opt => {
|
|
const min = parseInt(opt.getAttribute('data-annee-min'));
|
|
const max = parseInt(opt.getAttribute('data-annee-max'));
|
|
if (!isNaN(min) && !isNaN(max) && birthYear >= min && birthYear <= max) {
|
|
catSelect.value = opt.value;
|
|
preSelectedCatId = opt.value;
|
|
foundCat = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (!foundCat) {
|
|
catSelect.value = '';
|
|
}
|
|
|
|
// Fetch and populate teams for the pre-selected category
|
|
if (preSelectedCatId) {
|
|
fetch('/categories/equipes?categorieId=' + preSelectedCatId)
|
|
.then(response => response.text())
|
|
.then(html => {
|
|
equipeSelect.innerHTML = html;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
function closeLicenceModal() {
|
|
document.getElementById('licenceModal').classList.add('hidden');
|
|
}
|
|
|
|
function openPaiementModal(licenceId, maxAmount) {
|
|
document.getElementById('paiementModal').classList.remove('hidden');
|
|
document.getElementById('paiementForm').action = '/licences/' + licenceId + '/paiements';
|
|
document.getElementById('paiementMontant').value = maxAmount;
|
|
document.getElementById('paiementMontant').max = maxAmount;
|
|
document.getElementById('paiementDate').valueAsDate = new Date();
|
|
}
|
|
function closePaiementModal() {
|
|
document.getElementById('paiementModal').classList.add('hidden');
|
|
}
|
|
|
|
function openEditPaiementModal(paiementId, montant, date, modePaiementId, licenceId, maxAmount) {
|
|
document.getElementById('editPaiementModal').classList.remove('hidden');
|
|
document.getElementById('editPaiementForm').action = '/paiements/' + paiementId + '/update';
|
|
document.getElementById('editPaiementMontant').value = montant;
|
|
document.getElementById('editPaiementMontant').max = maxAmount;
|
|
document.getElementById('editPaiementDate').value = date;
|
|
document.getElementById('editPaiementMode').value = modePaiementId;
|
|
}
|
|
function closeEditPaiementModal() {
|
|
document.getElementById('editPaiementModal').classList.add('hidden');
|
|
}
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
const dateInput = document.getElementById('dateNaissance');
|
|
const repBlock = document.getElementById('representantBlock');
|
|
const residentCheckbox = document.getElementById('residentTalange');
|
|
|
|
const catSelect = document.getElementById('categorieSelect');
|
|
if (catSelect) {
|
|
catSelect.addEventListener('change', function() {
|
|
const catId = this.value;
|
|
const equipeSelect = document.getElementById('licenceEquipe');
|
|
equipeSelect.innerHTML = '<option value="">Aucune équipe</option>';
|
|
if (catId) {
|
|
fetch('/categories/equipes?categorieId=' + catId)
|
|
.then(response => response.text())
|
|
.then(html => {
|
|
equipeSelect.innerHTML = html;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
function calculateAge(birthday) {
|
|
const ageDifMs = Date.now() - birthday.getTime();
|
|
const ageDate = new Date(ageDifMs);
|
|
return Math.abs(ageDate.getUTCFullYear() - 1970);
|
|
}
|
|
|
|
function updateRepresentantBlock() {
|
|
if (dateInput.value) {
|
|
const dob = new Date(dateInput.value);
|
|
const age = calculateAge(dob);
|
|
if (age < 18) {
|
|
repBlock.classList.remove('hidden-block');
|
|
} else {
|
|
repBlock.classList.add('hidden-block');
|
|
}
|
|
} else {
|
|
repBlock.classList.add('hidden-block');
|
|
}
|
|
}
|
|
|
|
function updateLicencesCategoryAndPrices() {
|
|
if (!dateInput.value) return;
|
|
const dob = new Date(dateInput.value);
|
|
const birthYear = dob.getFullYear();
|
|
const isResident = residentCheckbox ? residentCheckbox.checked : true;
|
|
|
|
const categories = [];
|
|
const catSelect = document.getElementById('categorieSelect');
|
|
if (catSelect) {
|
|
Array.from(catSelect.options).forEach(opt => {
|
|
const id = opt.value;
|
|
const nom = opt.getAttribute('data-nom');
|
|
const min = parseInt(opt.getAttribute('data-annee-min'));
|
|
const max = parseInt(opt.getAttribute('data-annee-max'));
|
|
const tarifBase = parseFloat(opt.getAttribute('data-tarif-base') || '0');
|
|
const tarifExterieur = parseFloat(opt.getAttribute('data-tarif-exterieur') || '0');
|
|
if (id) {
|
|
categories.push({ id, nom, min, max, tarifBase, tarifExterieur });
|
|
}
|
|
});
|
|
}
|
|
|
|
if (categories.length === 0) return;
|
|
|
|
const matchingCat = categories.find(c => birthYear >= c.min && birthYear <= c.max);
|
|
if (!matchingCat) return;
|
|
|
|
document.querySelectorAll('.licence-row').forEach(row => {
|
|
row.setAttribute('data-tarif-base', matchingCat.tarifBase);
|
|
row.setAttribute('data-tarif-exterieur', matchingCat.tarifExterieur);
|
|
|
|
const baseTarif = isResident ? matchingCat.tarifBase : matchingCat.tarifExterieur;
|
|
const equipContrib = parseFloat(row.getAttribute('data-equipements-contrib') || '0');
|
|
const totalPaye = parseFloat(row.getAttribute('data-total-paye') || '0');
|
|
const newTotal = baseTarif + equipContrib;
|
|
const newReste = Math.max(0, newTotal - totalPaye);
|
|
|
|
const catCell = row.querySelector('.cell-tarif-categorie');
|
|
if (catCell) {
|
|
const parentTd = catCell.parentNode;
|
|
const spanName = parentTd.querySelector('span:not(.cell-tarif-categorie)');
|
|
if (spanName) {
|
|
spanName.textContent = matchingCat.nom;
|
|
}
|
|
catCell.textContent = baseTarif.toFixed(2) + ' € (Catégorie)';
|
|
}
|
|
|
|
const globalCell = row.querySelector('.cell-tarif-global');
|
|
if (globalCell) {
|
|
globalCell.textContent = newTotal.toFixed(2) + ' €';
|
|
}
|
|
|
|
const resteCell = row.querySelector('.cell-reste-payer');
|
|
if (resteCell) {
|
|
resteCell.textContent = newReste.toFixed(2) + ' €';
|
|
if (newReste === 0) {
|
|
resteCell.classList.remove('text-red-600');
|
|
resteCell.classList.add('text-green-600');
|
|
} else {
|
|
resteCell.classList.remove('text-green-600');
|
|
resteCell.classList.add('text-red-600');
|
|
}
|
|
}
|
|
|
|
const payerBtn = row.querySelector('.btn-payer');
|
|
if (payerBtn) {
|
|
if (newReste > 0) {
|
|
payerBtn.classList.remove('hidden');
|
|
const licId = payerBtn.getAttribute('data-licence-id');
|
|
payerBtn.setAttribute('onclick', `openPaiementModal(${licId}, ${newReste})`);
|
|
} else {
|
|
payerBtn.classList.add('hidden');
|
|
}
|
|
}
|
|
|
|
const modifierBtn = row.querySelector('button[onclick^="openLicenceModal"]');
|
|
if (modifierBtn) {
|
|
modifierBtn.setAttribute('data-categorie-id', matchingCat.id);
|
|
}
|
|
});
|
|
}
|
|
|
|
dateInput.addEventListener('change', function() {
|
|
updateRepresentantBlock();
|
|
updateLicencesCategoryAndPrices();
|
|
});
|
|
|
|
// Initial check in case it's a validation error reload
|
|
updateRepresentantBlock();
|
|
// But if there's already an error on representantLegal, ensure it is shown
|
|
const hasRepError = document.querySelector('p[th\\:errors="*{representantLegal}"]');
|
|
if (hasRepError || document.getElementById('representantLegal').classList.contains('border-red-500')) {
|
|
repBlock.classList.remove('hidden-block');
|
|
}
|
|
|
|
// Recalculate price dynamically when residentTalange checkbox changes
|
|
if (residentCheckbox) {
|
|
residentCheckbox.addEventListener('change', function() {
|
|
const isResident = this.checked;
|
|
document.querySelectorAll('.licence-row').forEach(row => {
|
|
const tarifBase = parseFloat(row.getAttribute('data-tarif-base') || '0');
|
|
const tarifExterieur = parseFloat(row.getAttribute('data-tarif-exterieur') || '0');
|
|
const equipContrib = parseFloat(row.getAttribute('data-equipements-contrib') || '0');
|
|
const totalPaye = parseFloat(row.getAttribute('data-total-paye') || '0');
|
|
|
|
const baseTarif = isResident ? tarifBase : tarifExterieur;
|
|
const newTotal = baseTarif + equipContrib;
|
|
const newReste = Math.max(0, newTotal - totalPaye);
|
|
|
|
// Update Category price cell
|
|
const catCell = row.querySelector('.cell-tarif-categorie');
|
|
if (catCell) {
|
|
catCell.textContent = baseTarif.toFixed(2) + ' € (Catégorie)';
|
|
}
|
|
|
|
// Update Tarif Global cell
|
|
const globalCell = row.querySelector('.cell-tarif-global');
|
|
if (globalCell) {
|
|
globalCell.textContent = newTotal.toFixed(2) + ' €';
|
|
}
|
|
|
|
// Update Reste à Payer cell
|
|
const resteCell = row.querySelector('.cell-reste-payer');
|
|
if (resteCell) {
|
|
resteCell.textContent = newReste.toFixed(2) + ' €';
|
|
if (newReste === 0) {
|
|
resteCell.classList.remove('text-red-600');
|
|
resteCell.classList.add('text-green-600');
|
|
} else {
|
|
resteCell.classList.remove('text-green-600');
|
|
resteCell.classList.add('text-red-600');
|
|
}
|
|
}
|
|
|
|
// Update Payer button
|
|
const payerBtn = row.querySelector('.btn-payer');
|
|
if (payerBtn) {
|
|
if (newReste > 0) {
|
|
payerBtn.classList.remove('hidden');
|
|
const licId = payerBtn.getAttribute('data-licence-id');
|
|
payerBtn.setAttribute('onclick', `openPaiementModal(${licId}, ${newReste})`);
|
|
} else {
|
|
payerBtn.classList.add('hidden');
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Update equipment style labels dynamically when Sexe or Type de Maillot (Poste) changes
|
|
const sexeSelect = document.getElementById('sexe');
|
|
const typeMaillotSelect = document.getElementById('typeMaillot');
|
|
|
|
function updateEquipmentStyleLabels() {
|
|
if (!sexeSelect || !typeMaillotSelect) return;
|
|
const sexe = sexeSelect.value;
|
|
const typeMaillot = typeMaillotSelect.value;
|
|
|
|
const sexeText = (sexe === 'FEMININ') ? 'Modèle Femme' : 'Modèle Homme';
|
|
const typeText = (typeMaillot === 'GARDIEN') ? 'Gardien' : 'Joueur';
|
|
|
|
document.querySelectorAll('.dotation-style-label').forEach(label => {
|
|
const equip = label.getAttribute('data-equipement');
|
|
if (equip === 'Maillot' || equip === 'Short' || equip === 'Chaussettes') {
|
|
label.textContent = `${sexeText} - ${typeText}`;
|
|
} else if (equip === 'Survêtement') {
|
|
label.textContent = sexeText;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (sexeSelect) {
|
|
sexeSelect.addEventListener('change', updateEquipmentStyleLabels);
|
|
}
|
|
if (typeMaillotSelect) {
|
|
typeMaillotSelect.addEventListener('change', updateEquipmentStyleLabels);
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|