feat: paramétrage dynamique des dotations (sexe, tailles, couleurs)
This commit is contained in:
@@ -21,6 +21,9 @@ public class Dotation {
|
|||||||
@Column(length = 10)
|
@Column(length = 10)
|
||||||
private String taille;
|
private String taille;
|
||||||
|
|
||||||
|
@Column(length = 50)
|
||||||
|
private String couleur;
|
||||||
|
|
||||||
@Column(length = 50)
|
@Column(length = 50)
|
||||||
private String flocage;
|
private String flocage;
|
||||||
|
|
||||||
@@ -47,6 +50,9 @@ public class Dotation {
|
|||||||
public String getTaille() { return taille; }
|
public String getTaille() { return taille; }
|
||||||
public void setTaille(String taille) { this.taille = taille; }
|
public void setTaille(String taille) { this.taille = taille; }
|
||||||
|
|
||||||
|
public String getCouleur() { return couleur; }
|
||||||
|
public void setCouleur(String couleur) { this.couleur = couleur; }
|
||||||
|
|
||||||
public String getFlocage() { return flocage; }
|
public String getFlocage() { return flocage; }
|
||||||
public void setFlocage(String flocage) { this.flocage = flocage; }
|
public void setFlocage(String flocage) { this.flocage = flocage; }
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,15 @@ public class Equipement {
|
|||||||
@Column(columnDefinition = "TEXT")
|
@Column(columnDefinition = "TEXT")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
@Column(name = "gestion_sexe", nullable = false)
|
||||||
|
private boolean gestionSexe = false;
|
||||||
|
|
||||||
|
@Column(name = "tailles_disponibles", length = 500)
|
||||||
|
private String taillesDisponibles;
|
||||||
|
|
||||||
|
@Column(name = "couleurs_disponibles", length = 500)
|
||||||
|
private String couleursDisponibles;
|
||||||
|
|
||||||
|
|
||||||
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
@ManyToOne(optional = false, fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "saison_id", nullable = false)
|
@JoinColumn(name = "saison_id", nullable = false)
|
||||||
@@ -39,6 +48,15 @@ public class Equipement {
|
|||||||
public String getDescription() { return description; }
|
public String getDescription() { return description; }
|
||||||
public void setDescription(String description) { this.description = description; }
|
public void setDescription(String description) { this.description = description; }
|
||||||
|
|
||||||
|
public boolean isGestionSexe() { return gestionSexe; }
|
||||||
|
public void setGestionSexe(boolean gestionSexe) { this.gestionSexe = gestionSexe; }
|
||||||
|
|
||||||
|
public String getTaillesDisponibles() { return taillesDisponibles; }
|
||||||
|
public void setTaillesDisponibles(String taillesDisponibles) { this.taillesDisponibles = taillesDisponibles; }
|
||||||
|
|
||||||
|
public String getCouleursDisponibles() { return couleursDisponibles; }
|
||||||
|
public void setCouleursDisponibles(String couleursDisponibles) { this.couleursDisponibles = couleursDisponibles; }
|
||||||
|
|
||||||
public Saison getSaison() { return saison; }
|
public Saison getSaison() { return saison; }
|
||||||
public void setSaison(Saison saison) { this.saison = saison; }
|
public void setSaison(Saison saison) { this.saison = saison; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
ALTER TABLE equipement ADD COLUMN gestion_sexe BOOLEAN DEFAULT FALSE NOT NULL;
|
||||||
|
ALTER TABLE equipement ADD COLUMN tailles_disponibles VARCHAR(500);
|
||||||
|
ALTER TABLE equipement ADD COLUMN couleurs_disponibles VARCHAR(500);
|
||||||
|
|
||||||
|
ALTER TABLE dotation ADD COLUMN couleur VARCHAR(50);
|
||||||
@@ -168,12 +168,14 @@ public class DotationController {
|
|||||||
.orElseThrow(() -> new IllegalArgumentException("Invalid Dotation ID: " + id));
|
.orElseThrow(() -> new IllegalArgumentException("Invalid Dotation ID: " + id));
|
||||||
|
|
||||||
String taille = request.getParameter("taille_" + id);
|
String taille = request.getParameter("taille_" + id);
|
||||||
|
String couleur = request.getParameter("couleur_" + id);
|
||||||
String numero = request.getParameter("numero_" + id);
|
String numero = request.getParameter("numero_" + id);
|
||||||
String flocage = request.getParameter("flocage_" + id);
|
String flocage = request.getParameter("flocage_" + id);
|
||||||
String choisiParam = request.getParameter("choisi_" + id);
|
String choisiParam = request.getParameter("choisi_" + id);
|
||||||
String fourniParam = request.getParameter("fourni_" + id);
|
String fourniParam = request.getParameter("fourni_" + id);
|
||||||
|
|
||||||
if (taille != null) dotation.setTaille(taille);
|
if (taille != null) dotation.setTaille(taille);
|
||||||
|
if (couleur != null) dotation.setCouleur(couleur);
|
||||||
if (numero != null) dotation.setNumero(numero);
|
if (numero != null) dotation.setNumero(numero);
|
||||||
if (flocage != null) dotation.setFlocage(flocage);
|
if (flocage != null) dotation.setFlocage(flocage);
|
||||||
|
|
||||||
|
|||||||
@@ -354,17 +354,10 @@
|
|||||||
</div>
|
</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>
|
<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 -->
|
<!-- 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'}">
|
<div class="mb-2" th:if="${dot.equipement.gestionSexe}">
|
||||||
<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"
|
<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:data-equipement="${dot.equipement.nom}"
|
||||||
th:text="${adherent.sexe == 'FEMININ' ? 'Modèle Femme' : 'Modèle Homme'} + ' - ' + ${adherent.typeMaillot == 'GARDIEN' ? 'Gardien' : 'Joueur'}">
|
th:text="${adherent.sexe == 'FEMININ' ? 'Modèle Femme' : 'Modèle Homme'} + (${dot.equipement.nom == 'Maillot' or dot.equipement.nom == 'Short' or dot.equipement.nom == 'Chaussettes'} ? ' - ' + (${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
|
Modèle Homme
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -381,17 +374,43 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-2 gap-1.5 mb-1.5">
|
<div class="grid grid-cols-2 gap-1.5 mb-1.5">
|
||||||
<div>
|
<div th:if="${dot.equipement.taillesDisponibles != null and !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}" placeholder="S, M, L..."
|
<select th:name="'taille_' + ${dot.id}" class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 focus:ring-1 focus:ring-blue-500 outline-none">
|
||||||
class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 focus:ring-1 focus:ring-blue-500 outline-none">
|
<option value="">Choisir...</option>
|
||||||
|
<option th:each="t : ${#strings.arraySplit(dot.equipement.taillesDisponibles, ',')}"
|
||||||
|
th:value="${#strings.trim(t)}"
|
||||||
|
th:text="${#strings.trim(t)}"
|
||||||
|
th:selected="${dot.taille == #strings.trim(t)}"></option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div th:if="${(dot.equipement.taillesDisponibles == null or dot.equipement.taillesDisponibles.trim().isEmpty()) and (dot.taille != null and !dot.taille.isEmpty())}">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div th:if="${dot.equipement.couleursDisponibles != null and !dot.equipement.couleursDisponibles.trim().isEmpty()}">
|
||||||
|
<label class="block text-[9px] uppercase font-bold text-gray-400">Couleur</label>
|
||||||
|
<select th:name="'couleur_' + ${dot.id}" class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 focus:ring-1 focus:ring-blue-500 outline-none">
|
||||||
|
<option value="">Choisir...</option>
|
||||||
|
<option th:each="c : ${#strings.arraySplit(dot.equipement.couleursDisponibles, ',')}"
|
||||||
|
th:value="${#strings.trim(c)}"
|
||||||
|
th:text="${#strings.trim(c)}"
|
||||||
|
th:selected="${dot.couleur == #strings.trim(c)}"></option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div th:if="${(dot.equipement.couleursDisponibles == null or dot.equipement.couleursDisponibles.trim().isEmpty()) and (dot.couleur != null and !dot.couleur.isEmpty())}">
|
||||||
|
<label class="block text-[9px] uppercase font-bold text-gray-400">Couleur</label>
|
||||||
|
<input type="text" th:name="'couleur_' + ${dot.id}" th:value="${dot.couleur}" class="w-full text-xs border border-gray-300 rounded px-1 py-0.5 outline-none bg-gray-50 text-gray-500" readonly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-1.5 mb-1.5">
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-[9px] uppercase font-bold text-gray-400">Numéro</label>
|
<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"
|
<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">
|
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>
|
|
||||||
<div>
|
<div>
|
||||||
<label class="block text-[9px] uppercase font-bold text-gray-400">Flocage</label>
|
<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"
|
<input type="text" th:name="'flocage_' + ${dot.id}" th:value="${dot.flocage}" placeholder="Nom du joueur"
|
||||||
|
|||||||
@@ -36,10 +36,28 @@
|
|||||||
<label class="block text-sm font-medium text-gray-700 mb-1">Description (ex: Maillot domicile officiel)</label>
|
<label class="block text-sm font-medium text-gray-700 mb-1">Description (ex: Maillot domicile officiel)</label>
|
||||||
<textarea th:field="*{description}" rows="3" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none"></textarea>
|
<textarea th:field="*{description}" rows="3" class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="pt-4 border-t border-gray-100">
|
||||||
|
<h3 class="text-sm font-medium text-gray-900 mb-4">Options de déclinaison (facultatif)</h3>
|
||||||
|
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<input type="checkbox" th:field="*{gestionSexe}" class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500">
|
||||||
|
<label class="ml-2 block text-sm text-gray-700">Gérer les coupes Homme/Femme</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Tailles disponibles</label>
|
||||||
|
<input type="text" th:field="*{taillesDisponibles}" placeholder="ex: XS, S, M, L, XL ou 5/6 ANS, 7/8 ANS..." class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
||||||
|
<p class="text-xs text-gray-500 mt-1">Séparez les tailles par des virgules. Laissez vide si taille unique ou standard.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">Couleurs disponibles</label>
|
||||||
|
<input type="text" th:field="*{couleursDisponibles}" placeholder="ex: Bleu, Rouge, Blanc..." class="w-full border border-gray-300 rounded-lg px-4 py-2 text-sm focus:ring-2 focus:ring-blue-500 outline-none">
|
||||||
|
<p class="text-xs text-gray-500 mt-1">Séparez les couleurs par des virgules. Laissez vide si couleur unique.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="pt-4 flex justify-end space-x-3 border-t border-gray-100">
|
<div class="pt-4 flex justify-end space-x-3 border-t border-gray-100">
|
||||||
<a th:href="@{/equipements}" class="px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-50">Annuler</a>
|
<a th:href="@{/equipements}" class="px-4 py-2 text-sm font-medium text-gray-700 border border-gray-300 rounded-lg hover:bg-gray-50">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">Enregistrer</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>
|
||||||
|
|||||||
Reference in New Issue
Block a user