feat: add admin toggle to open/close public pre-registrations with ui messaging
This commit is contained in:
+19
-4
@@ -35,12 +35,21 @@ public class PublicInscriptionController {
|
||||
}
|
||||
|
||||
@GetMapping("/demarrer")
|
||||
public String showDemarrer() {
|
||||
public String showDemarrer(Model model) {
|
||||
Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (activeSaison == null || !activeSaison.getInscriptionsOuvertes()) {
|
||||
model.addAttribute("inscriptionsFermees", true);
|
||||
}
|
||||
return "public/demarrer";
|
||||
}
|
||||
|
||||
@PostMapping("/demarrer")
|
||||
public String processDemarrer(@RequestParam("cf-turnstile-response") String captchaResponse, RedirectAttributes redirectAttributes) {
|
||||
Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (activeSaison == null || !activeSaison.getInscriptionsOuvertes()) {
|
||||
redirectAttributes.addFlashAttribute("error", "Les inscriptions ne sont pas ouvertes pour le moment, veuillez contacter un responsable du club.");
|
||||
return "redirect:/inscription-public/demarrer";
|
||||
}
|
||||
// En vrai, captchaResponse dépend du fournisseur. Cloudflare Turnstile = cf-turnstile-response
|
||||
if (!captchaValidationService.validateCaptcha(captchaResponse)) {
|
||||
redirectAttributes.addFlashAttribute("error", "Validation CAPTCHA échouée. Veuillez réessayer.");
|
||||
@@ -56,7 +65,13 @@ public class PublicInscriptionController {
|
||||
}
|
||||
|
||||
@GetMapping("/formulaire")
|
||||
public String showFormulaire(@RequestParam("token") String tokenUuid, Model model) {
|
||||
public String showFormulaire(@RequestParam("token") String tokenUuid, Model model, RedirectAttributes redirectAttributes) {
|
||||
Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (activeSaison == null || !activeSaison.getInscriptionsOuvertes()) {
|
||||
redirectAttributes.addFlashAttribute("error", "Les inscriptions ne sont pas ouvertes pour le moment, veuillez contacter un responsable du club.");
|
||||
return "redirect:/inscription-public/demarrer";
|
||||
}
|
||||
|
||||
TokenPreInscription token = tokenRepository.findByValeurUuid(tokenUuid).orElse(null);
|
||||
if (token == null || !token.isValide()) {
|
||||
return "public/lien-expire";
|
||||
@@ -77,8 +92,8 @@ public class PublicInscriptionController {
|
||||
}
|
||||
|
||||
Saison activeSaison = saisonRepository.findByEstActiveTrue().orElse(null);
|
||||
if (activeSaison == null) {
|
||||
redirectAttributes.addFlashAttribute("error", "Les inscriptions sont actuellement fermées.");
|
||||
if (activeSaison == null || !activeSaison.getInscriptionsOuvertes()) {
|
||||
redirectAttributes.addFlashAttribute("error", "Les inscriptions ne sont pas ouvertes pour le moment, veuillez contacter un responsable du club.");
|
||||
return "redirect:/inscription-public/demarrer";
|
||||
}
|
||||
|
||||
|
||||
@@ -58,4 +58,13 @@ public class SaisonController {
|
||||
|
||||
return "redirect:/saisons";
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/toggle-inscriptions")
|
||||
public String toggleInscriptions(@PathVariable Long id) {
|
||||
Saison saison = saisonRepository.findById(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Saison introuvable : " + id));
|
||||
saison.setInscriptionsOuvertes(!saison.getInscriptionsOuvertes());
|
||||
saisonRepository.save(saison);
|
||||
return "redirect:/saisons";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,12 +30,13 @@
|
||||
<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">Nom de la Saison</th>
|
||||
<th class="py-3 px-6 font-medium text-center">Statut</th>
|
||||
<th class="py-3 px-6 font-medium text-center">Inscriptions Publiques</th>
|
||||
<th class="py-3 px-6 font-medium text-right">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-200 text-sm">
|
||||
<tr th:if="${#lists.isEmpty(saisons)}">
|
||||
<td colspan="3" class="py-8 text-center text-gray-500">Aucune saison configurée.</td>
|
||||
<td colspan="4" class="py-8 text-center text-gray-500">Aucune saison configurée.</td>
|
||||
</tr>
|
||||
<tr th:each="saison : ${saisons}" class="hover:bg-gray-50 transition-colors">
|
||||
<td class="py-4 px-6 font-medium text-gray-900" th:text="${saison.nom}">Saison 2024-2025</td>
|
||||
@@ -47,6 +48,14 @@
|
||||
Clôturée
|
||||
</span>
|
||||
</td>
|
||||
<td class="py-4 px-6 text-center">
|
||||
<form th:if="${saison.estActive}" th:action="@{/saisons/{id}/toggle-inscriptions(id=${saison.id})}" method="post">
|
||||
<button type="submit" th:class="${saison.inscriptionsOuvertes ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'} + ' px-3 py-1 rounded-full text-xs font-medium hover:opacity-80 transition-opacity'" title="Cliquez pour ouvrir/fermer">
|
||||
<span th:text="${saison.inscriptionsOuvertes ? 'Ouvertes' : 'Fermées'}"></span>
|
||||
</button>
|
||||
</form>
|
||||
<span th:unless="${saison.estActive}" class="text-gray-400 text-xs">-</span>
|
||||
</td>
|
||||
<td class="py-4 px-6 text-right flex justify-end space-x-3 items-center">
|
||||
<form th:if="${!saison.estActive}" th:action="@{/saisons/{id}/activer(id=${saison.id})}" method="post">
|
||||
<button type="submit" class="text-indigo-600 hover:text-indigo-900 font-medium bg-indigo-50 px-3 py-1 rounded-lg">Définir Active</button>
|
||||
|
||||
@@ -1,30 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>AS Talange - Pré-inscription</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
|
||||
<style> body { font-family: 'Inter', sans-serif; } </style>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 flex items-center justify-center min-h-screen">
|
||||
<div class="max-w-md w-full bg-white rounded-xl shadow-md p-8 border border-gray-100 text-center">
|
||||
<img src="/images/logo.png" alt="AS Talange" class="h-24 mx-auto mb-6 opacity-80" onerror="this.style.display='none'">
|
||||
<img src="/images/logo.png" alt="AS Talange" class="h-32 w-auto mx-auto mb-6 object-contain drop-shadow-sm"
|
||||
onerror="this.style.display='none'">
|
||||
<h1 class="text-2xl font-bold text-gray-900 mb-2">Inscription au club</h1>
|
||||
<p class="text-gray-600 mb-8">Veuillez valider le captcha pour accéder au formulaire sécurisé.</p>
|
||||
|
||||
<div th:if="${error}" class="bg-red-50 text-red-600 p-3 rounded-lg mb-6 text-sm" th:text="${error}"></div>
|
||||
<div th:if="${param.error}" class="bg-red-50 text-red-600 p-3 rounded-lg mb-6 text-sm">Les inscriptions sont actuellement fermées.</div>
|
||||
<p th:unless="${inscriptionsFermees}" class="text-gray-600 mb-8">Veuillez valider le captcha pour accéder au formulaire sécurisé.</p>
|
||||
|
||||
<form th:action="@{/inscription-public/demarrer}" method="post" class="flex flex-col items-center">
|
||||
<div th:if="${error != null and (inscriptionsFermees == null or !inscriptionsFermees)}" class="bg-red-50 text-red-600 p-3 rounded-lg mb-6 text-sm" th:text="${error}"></div>
|
||||
|
||||
<div th:if="${inscriptionsFermees}" class="bg-red-50 text-red-600 p-4 rounded-lg mb-6 text-sm font-medium">
|
||||
Les inscriptions ne sont pas ouvertes pour le moment, veuillez contacter un responsable du club.
|
||||
</div>
|
||||
|
||||
<form th:unless="${inscriptionsFermees}" th:action="@{/inscription-public/demarrer}" method="post" class="flex flex-col items-center">
|
||||
<!-- Remplacer par la vraie clé de site Cloudflare Turnstile -->
|
||||
<div class="cf-turnstile mb-6" data-sitekey="1x00000000000000000000AA"></div>
|
||||
|
||||
<button type="submit" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition-colors">
|
||||
|
||||
<button type="submit"
|
||||
class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-3 px-4 rounded-lg transition-colors">
|
||||
Accéder au formulaire
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
</html>
|
||||
@@ -9,7 +9,8 @@
|
||||
</head>
|
||||
<body class="bg-gray-50 flex items-center justify-center min-h-screen py-12">
|
||||
<div class="max-w-xl w-full bg-white rounded-xl shadow-md p-8 border border-gray-100">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6 text-center">Formulaire de pré-inscription</h2>
|
||||
<img src="/images/logo.png" alt="AS Talange" class="h-24 w-auto mx-auto mb-4 object-contain drop-shadow-sm" onerror="this.style.display='none'">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-2 text-center">Formulaire de pré-inscription</h2>
|
||||
<p class="text-sm text-gray-500 mb-8 text-center">Veuillez remplir les informations concernant le futur licencié.</p>
|
||||
|
||||
<form th:action="@{/inscription-public/formulaire}" th:object="${preInscription}" method="post" class="space-y-6">
|
||||
|
||||
Reference in New Issue
Block a user