feat: gestion des utilisateurs, rôles et équipes
- Ajout de la section de gestion des utilisateurs avec rôles (Admin, Trésorerie, Agent de Saisie). - Restriction des accès par rôle (Admin a tout, Trésorerie a adhérents/paiements, Agent de saisie a adhérents/planning). - Flux de modification obligatoire de mot de passe temporaire au premier login (par défaut AsTalange123). - Intégration de la configuration des équipes du club.
This commit is contained in:
@@ -174,7 +174,7 @@
|
||||
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}">U15</span>
|
||||
<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 font-mono text-xs" th:text="${lic.numeroLicence != null and !lic.numeroLicence.isEmpty() ? lic.numeroLicence : '-'}">-</td>
|
||||
@@ -193,7 +193,8 @@
|
||||
th:data-categorie-id="${lic.categorie.id}"
|
||||
th:data-numero-licence="${lic.numeroLicence}"
|
||||
th:data-etat="${lic.etat}"
|
||||
onclick="openLicenceModal(this.getAttribute('data-licence-id'), this.getAttribute('data-categorie-id'), this.getAttribute('data-numero-licence'), this.getAttribute('data-etat'))"
|
||||
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-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"
|
||||
@@ -330,6 +331,15 @@
|
||||
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">
|
||||
@@ -388,18 +398,33 @@
|
||||
</div>
|
||||
|
||||
<script th:inline="javascript">
|
||||
function openLicenceModal(licenceId = null, categorieId = '', numeroLicence = '', etat = 'Brouillon') {
|
||||
function openLicenceModal(licenceId = null, categorieId = '', numeroLicence = '', etat = 'Brouillon', 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';
|
||||
document.getElementById('categorieSelect').value = categorieId;
|
||||
catSelect.value = categorieId;
|
||||
document.getElementById('numeroLicenceInput').value = numeroLicence;
|
||||
document.getElementById('etatSelect').value = etat;
|
||||
|
||||
// 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';
|
||||
@@ -408,8 +433,8 @@
|
||||
|
||||
// Pré-sélection de la catégorie selon l'année de naissance
|
||||
const dateNaissanceStr = document.getElementById('dateNaissance').value;
|
||||
const catSelect = document.getElementById('categorieSelect');
|
||||
let foundCat = false;
|
||||
let preSelectedCatId = '';
|
||||
|
||||
if (dateNaissanceStr) {
|
||||
const birthYear = new Date(dateNaissanceStr).getFullYear();
|
||||
@@ -419,6 +444,7 @@
|
||||
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;
|
||||
}
|
||||
});
|
||||
@@ -427,6 +453,15 @@
|
||||
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() {
|
||||
@@ -448,6 +483,22 @@
|
||||
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);
|
||||
|
||||
@@ -107,7 +107,8 @@
|
||||
</div>
|
||||
</td>
|
||||
<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() : '-'}">-</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>
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user