feat: add new fields in pre-registration and sync with adherent and dotations

This commit is contained in:
2026-07-05 12:47:46 +02:00
parent 6dd45deb8c
commit 5ee9be467b
7 changed files with 159 additions and 4 deletions
@@ -50,6 +50,18 @@ public class Adherent {
@Column(name = "ancienne_categorie", length = 50) @Column(name = "ancienne_categorie", length = 50)
private String ancienneCategorie; private String ancienneCategorie;
@Column(name = "raison_changement_club")
private String raisonChangementClub;
@Column(name = "comment_connu_club")
private String commentConnuClub;
@Column(name = "taille_vetement", length = 50)
private String tailleVetement;
@Column(length = 50)
private String pointure;
private boolean residentTalange = true; private boolean residentTalange = true;
@Column(nullable = false, length = 10) @Column(nullable = false, length = 10)
@@ -105,6 +117,18 @@ public class Adherent {
public String getAncienneCategorie() { return ancienneCategorie; } public String getAncienneCategorie() { return ancienneCategorie; }
public void setAncienneCategorie(String ancienneCategorie) { this.ancienneCategorie = ancienneCategorie; } public void setAncienneCategorie(String ancienneCategorie) { this.ancienneCategorie = ancienneCategorie; }
public String getRaisonChangementClub() { return raisonChangementClub; }
public void setRaisonChangementClub(String raisonChangementClub) { this.raisonChangementClub = raisonChangementClub; }
public String getCommentConnuClub() { return commentConnuClub; }
public void setCommentConnuClub(String commentConnuClub) { this.commentConnuClub = commentConnuClub; }
public String getTailleVetement() { return tailleVetement; }
public void setTailleVetement(String tailleVetement) { this.tailleVetement = tailleVetement; }
public String getPointure() { return pointure; }
public void setPointure(String pointure) { this.pointure = pointure; }
public boolean isResidentTalange() { return residentTalange; } public boolean isResidentTalange() { return residentTalange; }
public void setResidentTalange(boolean residentTalange) { this.residentTalange = residentTalange; } public void setResidentTalange(boolean residentTalange) { this.residentTalange = residentTalange; }
@@ -64,6 +64,18 @@ public class PreInscription {
@Column(name = "ancienne_categorie", length = 50) @Column(name = "ancienne_categorie", length = 50)
private String ancienneCategorie = "NA"; private String ancienneCategorie = "NA";
@Column(name = "raison_changement_club")
private String raisonChangementClub;
@Column(name = "comment_connu_club")
private String commentConnuClub;
@Column(name = "taille_vetement", length = 50)
private String tailleVetement;
@Column(length = 50)
private String pointure;
// Getters and Setters // Getters and Setters
public Long getId() { return id; } public Long getId() { return id; }
public void setId(Long id) { this.id = id; } public void setId(Long id) { this.id = id; }
@@ -118,4 +130,16 @@ public class PreInscription {
public String getAncienneCategorie() { return ancienneCategorie; } public String getAncienneCategorie() { return ancienneCategorie; }
public void setAncienneCategorie(String ancienneCategorie) { this.ancienneCategorie = ancienneCategorie; } public void setAncienneCategorie(String ancienneCategorie) { this.ancienneCategorie = ancienneCategorie; }
public String getRaisonChangementClub() { return raisonChangementClub; }
public void setRaisonChangementClub(String raisonChangementClub) { this.raisonChangementClub = raisonChangementClub; }
public String getCommentConnuClub() { return commentConnuClub; }
public void setCommentConnuClub(String commentConnuClub) { this.commentConnuClub = commentConnuClub; }
public String getTailleVetement() { return tailleVetement; }
public void setTailleVetement(String tailleVetement) { this.tailleVetement = tailleVetement; }
public String getPointure() { return pointure; }
public void setPointure(String pointure) { this.pointure = pointure; }
} }
@@ -48,6 +48,10 @@ public class PreInscriptionService {
adherent.setAncienClub(pre.getAncienClub()); adherent.setAncienClub(pre.getAncienClub());
adherent.setAncienneCategorie(pre.getAncienneCategorie()); adherent.setAncienneCategorie(pre.getAncienneCategorie());
adherent.setSexe(pre.getSexe()); adherent.setSexe(pre.getSexe());
adherent.setRaisonChangementClub(pre.getRaisonChangementClub());
adherent.setCommentConnuClub(pre.getCommentConnuClub());
adherent.setTailleVetement(pre.getTailleVetement());
adherent.setPointure(pre.getPointure());
// Par défaut // Par défaut
adherent.setTypeMaillot("JOUEUR"); adherent.setTypeMaillot("JOUEUR");
adherent.setResidentTalange(false); adherent.setResidentTalange(false);
@@ -0,0 +1,9 @@
ALTER TABLE pre_inscription ADD COLUMN raison_changement_club VARCHAR(255);
ALTER TABLE pre_inscription ADD COLUMN comment_connu_club VARCHAR(255);
ALTER TABLE pre_inscription ADD COLUMN taille_vetement VARCHAR(50);
ALTER TABLE pre_inscription ADD COLUMN pointure VARCHAR(50);
ALTER TABLE adherent ADD COLUMN raison_changement_club VARCHAR(255);
ALTER TABLE adherent ADD COLUMN comment_connu_club VARCHAR(255);
ALTER TABLE adherent ADD COLUMN taille_vetement VARCHAR(50);
ALTER TABLE adherent ADD COLUMN pointure VARCHAR(50);
@@ -7,7 +7,9 @@ import com.astalange.core.repository.PreInscriptionRepository;
import com.astalange.core.repository.TokenPreInscriptionRepository; import com.astalange.core.repository.TokenPreInscriptionRepository;
import com.astalange.core.repository.SaisonRepository; import com.astalange.core.repository.SaisonRepository;
import com.astalange.core.repository.CategorieRepository; import com.astalange.core.repository.CategorieRepository;
import com.astalange.core.repository.EquipementRepository;
import com.astalange.core.entity.Categorie; import com.astalange.core.entity.Categorie;
import com.astalange.core.entity.Equipement;
import com.astalange.core.service.CaptchaValidationService; import com.astalange.core.service.CaptchaValidationService;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.Model; import org.springframework.ui.Model;
@@ -20,6 +22,8 @@ import java.time.LocalDate;
import java.util.UUID; import java.util.UUID;
import java.util.List; import java.util.List;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Set;
import java.util.TreeSet;
@Controller @Controller
@RequestMapping("/inscription-public") @RequestMapping("/inscription-public")
@@ -30,17 +34,20 @@ public class PublicInscriptionController {
private final PreInscriptionRepository preInscriptionRepository; private final PreInscriptionRepository preInscriptionRepository;
private final SaisonRepository saisonRepository; private final SaisonRepository saisonRepository;
private final CategorieRepository categorieRepository; private final CategorieRepository categorieRepository;
private final EquipementRepository equipementRepository;
public PublicInscriptionController(CaptchaValidationService captchaValidationService, public PublicInscriptionController(CaptchaValidationService captchaValidationService,
TokenPreInscriptionRepository tokenRepository, TokenPreInscriptionRepository tokenRepository,
PreInscriptionRepository preInscriptionRepository, PreInscriptionRepository preInscriptionRepository,
SaisonRepository saisonRepository, SaisonRepository saisonRepository,
CategorieRepository categorieRepository) { CategorieRepository categorieRepository,
EquipementRepository equipementRepository) {
this.captchaValidationService = captchaValidationService; this.captchaValidationService = captchaValidationService;
this.tokenRepository = tokenRepository; this.tokenRepository = tokenRepository;
this.preInscriptionRepository = preInscriptionRepository; this.preInscriptionRepository = preInscriptionRepository;
this.saisonRepository = saisonRepository; this.saisonRepository = saisonRepository;
this.categorieRepository = categorieRepository; this.categorieRepository = categorieRepository;
this.equipementRepository = equipementRepository;
} }
@Value("${captcha.sitekey:1x00000000000000000000AA}") @Value("${captcha.sitekey:1x00000000000000000000AA}")
@@ -97,6 +104,34 @@ public class PublicInscriptionController {
model.addAttribute("preInscription", new PreInscription()); model.addAttribute("preInscription", new PreInscription());
model.addAttribute("tokenUuid", tokenUuid); model.addAttribute("tokenUuid", tokenUuid);
// Fetch tailles and pointures
List<Equipement> equipements = equipementRepository.findAll();
Set<String> tailles = new TreeSet<>();
Set<String> pointures = new TreeSet<>();
for (Equipement eq : equipements) {
if (activeSaison.equals(eq.getSaison()) && eq.getTaillesDisponibles() != null && !eq.getTaillesDisponibles().trim().isEmpty()) {
String[] parts = eq.getTaillesDisponibles().split(",");
for (String p : parts) {
String val = p.trim();
if (!val.isEmpty()) {
try {
int num = Integer.parseInt(val);
if (num >= 25 && num <= 50) {
pointures.add(val);
} else {
tailles.add(val);
}
} catch (NumberFormatException e) {
tailles.add(val);
}
}
}
}
}
model.addAttribute("taillesDisponibles", tailles);
model.addAttribute("pointuresDisponibles", pointures);
return "public/formulaire"; return "public/formulaire";
} }
@@ -187,6 +187,30 @@
<option value="Senior">Senior</option> <option value="Senior">Senior</option>
</select> </select>
</div> </div>
<div>
<label for="raisonChangementClub" class="block text-sm font-medium text-gray-700 mb-1">Raison du changement</label>
<input type="text" id="raisonChangementClub" th:field="*{raisonChangementClub}"
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">
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
<div>
<label for="tailleVetement" class="block text-sm font-medium text-gray-700 mb-1">Taille équipement</label>
<input type="text" id="tailleVetement" th:field="*{tailleVetement}"
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">
</div>
<div>
<label for="pointure" class="block text-sm font-medium text-gray-700 mb-1">Pointure chaussettes</label>
<input type="text" id="pointure" th:field="*{pointure}"
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">
</div>
</div>
<div class="mt-6">
<label for="commentConnuClub" class="block text-sm font-medium text-gray-700 mb-1">Comment a-t-il connu le club ?</label>
<input type="text" id="commentConnuClub" th:field="*{commentConnuClub}"
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">
</div> </div>
<!-- Removed Adresse --> <!-- Removed Adresse -->
@@ -393,12 +417,12 @@
<option th:each="t : ${#strings.arraySplit(dot.equipement.taillesDisponibles, ',')}" <option th:each="t : ${#strings.arraySplit(dot.equipement.taillesDisponibles, ',')}"
th:value="${#strings.trim(t)}" th:value="${#strings.trim(t)}"
th:text="${#strings.trim(t)}" th:text="${#strings.trim(t)}"
th:selected="${dot.taille == #strings.trim(t)}"></option> th:selected="${(dot.taille != null and !dot.taille.isEmpty()) ? (dot.taille == #strings.trim(t)) : (#strings.trim(t) == adherent.tailleVetement or #strings.trim(t) == adherent.pointure)}"></option>
</select> </select>
</div> </div>
<div th:if="${(dot.equipement.taillesDisponibles == null or dot.equipement.taillesDisponibles.trim().isEmpty()) and (dot.taille != null and !dot.taille.isEmpty())}"> <div th:if="${(dot.equipement.taillesDisponibles == null or dot.equipement.taillesDisponibles.trim().isEmpty())}">
<label class="block text-[9px] uppercase font-bold text-gray-400">Taille</label> <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}" class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 outline-none bg-gray-50 text-gray-500" readonly> <input type="text" th:name="'taille_' + ${dot.id}" th:value="${dot.taille != null and !dot.taille.isEmpty() ? dot.taille : (adherent.tailleVetement != null ? adherent.tailleVetement : '')}" class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 outline-none bg-gray-50 text-gray-500" placeholder="Taille/Pointure">
</div> </div>
<div th:if="${dot.equipement.couleursDisponibles != null and !dot.equipement.couleursDisponibles.trim().isEmpty()}"> <div th:if="${dot.equipement.couleursDisponibles != null and !dot.equipement.couleursDisponibles.trim().isEmpty()}">
@@ -55,6 +55,11 @@
<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 outline-none" placeholder="Nom du club (laisser vide si aucun)"> <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 outline-none" placeholder="Nom du club (laisser vide si aucun)">
</div> </div>
<div id="raisonChangementClubBlock" class="hidden">
<label class="block text-sm font-medium text-gray-700 mb-1">Raison du changement de club <span class="text-red-500">*</span></label>
<input type="text" id="raisonChangementClub" th:field="*{raisonChangementClub}" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none" placeholder="Pourquoi souhaitez-vous nous rejoindre ?">
</div>
<div id="ancienneCategorieBlock" class="hidden"> <div id="ancienneCategorieBlock" class="hidden">
<label class="block text-sm font-medium text-gray-700 mb-1">Ancienne catégorie <span class="text-red-500">*</span></label> <label class="block text-sm font-medium text-gray-700 mb-1">Ancienne catégorie <span class="text-red-500">*</span></label>
<select id="ancienneCategorie" th:field="*{ancienneCategorie}" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none"> <select id="ancienneCategorie" th:field="*{ancienneCategorie}" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
@@ -152,6 +157,28 @@
</div> </div>
</div> </div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Taille de vêtement souhaitée (équipement)</label>
<select th:field="*{tailleVetement}" 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 taille...</option>
<option th:each="taille : ${taillesDisponibles}" th:value="${taille}" th:text="${taille}"></option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Pointure souhaitée (chaussettes)</label>
<select th:field="*{pointure}" 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 pointure...</option>
<option th:each="pt : ${pointuresDisponibles}" th:value="${pt}" th:text="${pt}"></option>
</select>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Comment avez-vous connu l'AS Talange ?</label>
<input type="text" th:field="*{commentConnuClub}" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none" placeholder="Ex: Réseaux sociaux, amis, forum des associations...">
</div>
<div class="flex items-start pt-2"> <div class="flex items-start pt-2">
<div class="flex items-center h-5"> <div class="flex items-center h-5">
<input id="consentementRgpd" name="consentementRgpd" type="checkbox" required class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500"> <input id="consentementRgpd" name="consentementRgpd" type="checkbox" required class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
@@ -221,21 +248,29 @@
const ancienClubInput = document.getElementById('ancienClub'); const ancienClubInput = document.getElementById('ancienClub');
const ancienneCategorieBlock = document.getElementById('ancienneCategorieBlock'); const ancienneCategorieBlock = document.getElementById('ancienneCategorieBlock');
const ancienneCategorieSelect = document.getElementById('ancienneCategorie'); const ancienneCategorieSelect = document.getElementById('ancienneCategorie');
const raisonChangementClubBlock = document.getElementById('raisonChangementClubBlock');
const raisonChangementClubInput = document.getElementById('raisonChangementClub');
if (ancienClubInput) { if (ancienClubInput) {
ancienClubInput.addEventListener('input', function() { ancienClubInput.addEventListener('input', function() {
if (this.value.trim().length > 0) { if (this.value.trim().length > 0) {
ancienneCategorieBlock.classList.remove('hidden'); ancienneCategorieBlock.classList.remove('hidden');
ancienneCategorieSelect.required = true; ancienneCategorieSelect.required = true;
raisonChangementClubBlock.classList.remove('hidden');
raisonChangementClubInput.required = true;
} else { } else {
ancienneCategorieBlock.classList.add('hidden'); ancienneCategorieBlock.classList.add('hidden');
ancienneCategorieSelect.required = false; ancienneCategorieSelect.required = false;
raisonChangementClubBlock.classList.add('hidden');
raisonChangementClubInput.required = false;
} }
}); });
// Initial check // Initial check
if (ancienClubInput.value.trim().length > 0) { if (ancienClubInput.value.trim().length > 0) {
ancienneCategorieBlock.classList.remove('hidden'); ancienneCategorieBlock.classList.remove('hidden');
ancienneCategorieSelect.required = true; ancienneCategorieSelect.required = true;
raisonChangementClubBlock.classList.remove('hidden');
raisonChangementClubInput.required = true;
} }
} }