diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/CreneauEntrainement.java b/as-talange-core/src/main/java/com/astalange/core/entity/CreneauEntrainement.java index e958446..a2d097f 100644 --- a/as-talange-core/src/main/java/com/astalange/core/entity/CreneauEntrainement.java +++ b/as-talange-core/src/main/java/com/astalange/core/entity/CreneauEntrainement.java @@ -52,6 +52,9 @@ public class CreneauEntrainement { @Transient private Set categoriesEnConflit = new HashSet<>(); + @Transient + private String initialesEducateurs = ""; + // Logic for Gantt diagram grid placement public int getStartColumn() { @@ -214,4 +217,12 @@ public class CreneauEntrainement { public void setCategoriesEnConflit(Set categoriesEnConflit) { this.categoriesEnConflit = categoriesEnConflit; } + + public String getInitialesEducateurs() { + return initialesEducateurs; + } + + public void setInitialesEducateurs(String initialesEducateurs) { + this.initialesEducateurs = initialesEducateurs; + } } diff --git a/as-talange-core/src/main/java/com/astalange/core/entity/Educateur.java b/as-talange-core/src/main/java/com/astalange/core/entity/Educateur.java index f9300aa..7fde47a 100644 --- a/as-talange-core/src/main/java/com/astalange/core/entity/Educateur.java +++ b/as-talange-core/src/main/java/com/astalange/core/entity/Educateur.java @@ -26,6 +26,10 @@ public class Educateur { @JoinColumn(name = "categorie_id") private Categorie categorie; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "equipe_id") + private Equipe equipe; + // Getters and Setters public Long getId() { return id; } @@ -45,4 +49,13 @@ public class Educateur { public Categorie getCategorie() { return categorie; } public void setCategorie(Categorie categorie) { this.categorie = categorie; } + + public Equipe getEquipe() { return equipe; } + public void setEquipe(Equipe equipe) { this.equipe = equipe; } + + public String getInitiales() { + String p = (prenom != null && !prenom.isEmpty()) ? prenom.substring(0, 1).toUpperCase() : ""; + String n = (nom != null && !nom.isEmpty()) ? nom.substring(0, 1).toUpperCase() : ""; + return p + n; + } } diff --git a/as-talange-core/src/main/java/com/astalange/core/repository/EducateurRepository.java b/as-talange-core/src/main/java/com/astalange/core/repository/EducateurRepository.java new file mode 100644 index 0000000..a807342 --- /dev/null +++ b/as-talange-core/src/main/java/com/astalange/core/repository/EducateurRepository.java @@ -0,0 +1,15 @@ +package com.astalange.core.repository; + +import com.astalange.core.entity.Educateur; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import org.springframework.data.jpa.repository.Query; +import java.util.List; + +@Repository +public interface EducateurRepository extends JpaRepository { + + @Query("SELECT e FROM Educateur e LEFT JOIN FETCH e.categorie LEFT JOIN FETCH e.equipe") + List findAllWithCategorieAndEquipe(); +} diff --git a/as-talange-core/src/main/java/com/astalange/core/repository/EquipeRepository.java b/as-talange-core/src/main/java/com/astalange/core/repository/EquipeRepository.java index 39c5435..b135a60 100644 --- a/as-talange-core/src/main/java/com/astalange/core/repository/EquipeRepository.java +++ b/as-talange-core/src/main/java/com/astalange/core/repository/EquipeRepository.java @@ -4,10 +4,16 @@ import com.astalange.core.entity.Equipe; import com.astalange.core.entity.Saison; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import org.springframework.data.jpa.repository.Query; import java.util.List; @Repository public interface EquipeRepository extends JpaRepository { List findByCategorieId(Long categorieId); + + @Query("SELECT e FROM Equipe e JOIN FETCH e.categorie WHERE e.saison = :saison") List findBySaison(Saison saison); + + @Query("SELECT e FROM Equipe e JOIN FETCH e.categorie") + List findAllWithCategorie(); } diff --git a/as-talange-core/src/main/resources/db/migration/V13__add_equipe_to_educateur.sql b/as-talange-core/src/main/resources/db/migration/V13__add_equipe_to_educateur.sql new file mode 100644 index 0000000..3a67df2 --- /dev/null +++ b/as-talange-core/src/main/resources/db/migration/V13__add_equipe_to_educateur.sql @@ -0,0 +1,3 @@ +-- V13__add_equipe_to_educateur.sql +ALTER TABLE educateur ADD COLUMN equipe_id BIGINT; +ALTER TABLE educateur ADD CONSTRAINT fk_educateur_equipe FOREIGN KEY (equipe_id) REFERENCES equipe(id) ON DELETE SET NULL; diff --git a/as-talange-core/src/test/java/com/astalange/core/EducateurTest.java b/as-talange-core/src/test/java/com/astalange/core/EducateurTest.java new file mode 100644 index 0000000..ddcab67 --- /dev/null +++ b/as-talange-core/src/test/java/com/astalange/core/EducateurTest.java @@ -0,0 +1,34 @@ +package com.astalange.core; + +import com.astalange.core.entity.*; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class EducateurTest { + + @Test + public void testEducateurEntityAndAssociations() { + Categorie U15 = new Categorie(); + U15.setNom("U15"); + + Equipe equipeA = new Equipe(); + equipeA.setNom("Équipe A"); + equipeA.setCategorie(U15); + + Educateur educateur = new Educateur(); + educateur.setNom("Dupont"); + educateur.setPrenom("Jean"); + educateur.setTelephone("0612345678"); + educateur.setEmail("jean.dupont@example.com"); + educateur.setCategorie(U15); + educateur.setEquipe(equipeA); + + assertEquals("Dupont", educateur.getNom()); + assertEquals("Jean", educateur.getPrenom()); + assertEquals("0612345678", educateur.getTelephone()); + assertEquals("jean.dupont@example.com", educateur.getEmail()); + assertEquals(U15, educateur.getCategorie()); + assertEquals(equipeA, educateur.getEquipe()); + } +} diff --git a/as-talange-web/src/main/java/com/astalange/web/controller/EducateurController.java b/as-talange-web/src/main/java/com/astalange/web/controller/EducateurController.java new file mode 100644 index 0000000..664edb8 --- /dev/null +++ b/as-talange-web/src/main/java/com/astalange/web/controller/EducateurController.java @@ -0,0 +1,88 @@ +package com.astalange.web.controller; + +import com.astalange.core.entity.Educateur; +import com.astalange.core.entity.Categorie; +import com.astalange.core.entity.Equipe; +import com.astalange.core.entity.Saison; +import com.astalange.core.repository.EducateurRepository; +import com.astalange.core.repository.CategorieRepository; +import com.astalange.core.repository.EquipeRepository; +import com.astalange.core.repository.SaisonRepository; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Controller +@RequestMapping("/educateurs") +public class EducateurController { + + private final EducateurRepository educateurRepository; + private final CategorieRepository categorieRepository; + private final EquipeRepository equipeRepository; + private final SaisonRepository saisonRepository; + + public EducateurController(EducateurRepository educateurRepository, + CategorieRepository categorieRepository, + EquipeRepository equipeRepository, + SaisonRepository saisonRepository) { + this.educateurRepository = educateurRepository; + this.categorieRepository = categorieRepository; + this.equipeRepository = equipeRepository; + this.saisonRepository = saisonRepository; + } + + @GetMapping + public String listEducateurs(Model model) { + model.addAttribute("educateurs", educateurRepository.findAllWithCategorieAndEquipe()); + return "parametrage/educateurs_list"; + } + + @GetMapping("/new") + public String showCreateForm(Model model) { + model.addAttribute("educateur", new Educateur()); + populateModelAttributes(model); + return "parametrage/educateurs_form"; + } + + @GetMapping("/{id}/edit") + public String showEditForm(@PathVariable Long id, Model model) { + Educateur educateur = educateurRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Invalid educator ID: " + id)); + model.addAttribute("educateur", educateur); + populateModelAttributes(model); + return "parametrage/educateurs_form"; + } + + @PostMapping + public String saveEducateur(@ModelAttribute("educateur") Educateur educateur) { + if (educateur.getCategorie() != null && educateur.getCategorie().getId() == null) { + educateur.setCategorie(null); + } + if (educateur.getEquipe() != null && educateur.getEquipe().getId() == null) { + educateur.setEquipe(null); + } + educateurRepository.save(educateur); + return "redirect:/educateurs"; + } + + @PostMapping("/{id}/delete") + public String deleteEducateur(@PathVariable Long id) { + Educateur educateur = educateurRepository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("Invalid educator ID: " + id)); + educateurRepository.delete(educateur); + return "redirect:/educateurs"; + } + + private void populateModelAttributes(Model model) { + Saison saisonActive = saisonRepository.findByEstActiveTrue().orElse(null); + if (saisonActive != null) { + model.addAttribute("categories", categorieRepository.findBySaison(saisonActive)); + model.addAttribute("equipes", equipeRepository.findBySaison(saisonActive)); + } else { + model.addAttribute("categories", categorieRepository.findAll()); + model.addAttribute("equipes", equipeRepository.findAllWithCategorie()); + } + } +} diff --git a/as-talange-web/src/main/java/com/astalange/web/controller/PlanningController.java b/as-talange-web/src/main/java/com/astalange/web/controller/PlanningController.java index c3fcbf9..f2ee7ce 100644 --- a/as-talange-web/src/main/java/com/astalange/web/controller/PlanningController.java +++ b/as-talange-web/src/main/java/com/astalange/web/controller/PlanningController.java @@ -3,6 +3,7 @@ package com.astalange.web.controller; import com.astalange.core.entity.*; import com.astalange.core.repository.CategorieRepository; import com.astalange.core.repository.CreneauEntrainementRepository; +import com.astalange.core.repository.EducateurRepository; import com.astalange.core.repository.EquipeRepository; import com.astalange.core.repository.SaisonRepository; import com.astalange.core.repository.TerrainRepository; @@ -23,17 +24,20 @@ public class PlanningController { private final CategorieRepository categorieRepository; private final SaisonRepository saisonRepository; private final EquipeRepository equipeRepository; + private final EducateurRepository educateurRepository; public PlanningController(CreneauEntrainementRepository creneauRepository, TerrainRepository terrainRepository, CategorieRepository categorieRepository, SaisonRepository saisonRepository, - EquipeRepository equipeRepository) { + EquipeRepository equipeRepository, + EducateurRepository educateurRepository) { this.creneauRepository = creneauRepository; this.terrainRepository = terrainRepository; this.categorieRepository = categorieRepository; this.saisonRepository = saisonRepository; this.equipeRepository = equipeRepository; + this.educateurRepository = educateurRepository; } @GetMapping @@ -56,10 +60,33 @@ public class PlanningController { } List creneaux = creneauRepository.findBySaisonAndJourSemaineFetch(saisonActive, selectedDay); + List educateurs = educateurRepository.findAllWithCategorieAndEquipe(); - // Detect conflicts + // Detect conflicts and populate educator initials for (int i = 0; i < creneaux.size(); i++) { CreneauEntrainement c1 = creneaux.get(i); + + // Populate educator initials + List initials = new ArrayList<>(); + for (Educateur ed : educateurs) { + boolean match = false; + if (c1.getEquipe() != null) { + if (ed.getEquipe() != null && ed.getEquipe().getId().equals(c1.getEquipe().getId())) { + match = true; + } + } else if (c1.getCategorie() != null) { + if (ed.getCategorie() != null && ed.getCategorie().getId().equals(c1.getCategorie().getId())) { + match = true; + } else if (ed.getEquipe() != null && ed.getEquipe().getCategorie() != null && ed.getEquipe().getCategorie().getId().equals(c1.getCategorie().getId())) { + match = true; + } + } + if (match) { + initials.add(ed.getInitiales()); + } + } + c1.setInitialesEducateurs(String.join(", ", initials)); + for (int j = 0; j < creneaux.size(); j++) { if (i == j) continue; CreneauEntrainement c2 = creneaux.get(j); diff --git a/as-talange-web/src/main/resources/templates/fragments/sidebar.html b/as-talange-web/src/main/resources/templates/fragments/sidebar.html index 3ebc938..2b24ec1 100644 --- a/as-talange-web/src/main/resources/templates/fragments/sidebar.html +++ b/as-talange-web/src/main/resources/templates/fragments/sidebar.html @@ -24,6 +24,7 @@ Saisons Catégories Équipes + Éducateurs Modes de Paiement Équipements diff --git a/as-talange-web/src/main/resources/templates/parametrage/educateurs_form.html b/as-talange-web/src/main/resources/templates/parametrage/educateurs_form.html new file mode 100644 index 0000000..0efe15d --- /dev/null +++ b/as-talange-web/src/main/resources/templates/parametrage/educateurs_form.html @@ -0,0 +1,71 @@ + + + + + Éducateur - AS Talange + + + + + + +
+ +
+
+

Éducateur

+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+ + +
+
+ +
+ Annuler + +
+
+
+
+
+ + diff --git a/as-talange-web/src/main/resources/templates/parametrage/educateurs_list.html b/as-talange-web/src/main/resources/templates/parametrage/educateurs_list.html new file mode 100644 index 0000000..a38f531 --- /dev/null +++ b/as-talange-web/src/main/resources/templates/parametrage/educateurs_list.html @@ -0,0 +1,70 @@ + + + + + Paramétrage - Éducateurs + + + + + + +
+ +
+
+

Éducateurs / Entraîneurs

+
+ +
+
+

Liste des Éducateurs

+ + + Nouvel Éducateur + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
NomPrénomTéléphoneEmailCatégorieÉquipeActions
Aucun éducateur n'est paramétré.
DupontJean-- + U15 + - + + Équipe A + - + + Modifier +
+ +
+
+
+
+
+ + diff --git a/as-talange-web/src/main/resources/templates/planning/planning.html b/as-talange-web/src/main/resources/templates/planning/planning.html index 28e95e8..1ea44d9 100644 --- a/as-talange-web/src/main/resources/templates/planning/planning.html +++ b/as-talange-web/src/main/resources/templates/planning/planning.html @@ -147,7 +147,7 @@ class="border-l-4 p-2 rounded shadow-sm flex flex-col justify-between overflow-hidden cursor-pointer hover:shadow transition-all relative z-10 m-0.5">
- U15 + U15
Modifier @@ -192,7 +192,13 @@ Aucun entraînement planifié pour ce jour. - U11 + + U11 + JD + Terrain Synthétique Demi A