From cbd53ba47169a20213454cdbe0198966f635bcc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ama=C3=ABl=20Kesteman?= Date: Sun, 11 Jan 2026 21:27:32 +0100 Subject: [PATCH] =?UTF-8?q?Feat:=20Stats=20athl=C3=A8tes=20fonctionnel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FrisbYEE/jpa/service/SessionDAO.java | 4 ++ .../FrisbYEE/rest/AthleteResource.java | 65 +++++++++--------- .../FrisbYEE/rest/SessionResource.java | 7 +- front_end/src/components/StatsAthlete.tsx | 67 ++++++++++++++++--- front_end/src/requetes.tsx | 26 +++++++ front_end/src/utils/athleteUtils.tsx | 3 +- 6 files changed, 129 insertions(+), 43 deletions(-) diff --git a/back_end/src/main/java/hackathon/FrisbYEE/jpa/service/SessionDAO.java b/back_end/src/main/java/hackathon/FrisbYEE/jpa/service/SessionDAO.java index 9a68a26..fb50dab 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/jpa/service/SessionDAO.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/jpa/service/SessionDAO.java @@ -1,10 +1,14 @@ package hackathon.FrisbYEE.jpa.service; import hackathon.FrisbYEE.jpa.metier.Session; + +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface SessionDAO extends JpaRepository { + List findByAthletes_Id(Integer athleteId); } diff --git a/back_end/src/main/java/hackathon/FrisbYEE/rest/AthleteResource.java b/back_end/src/main/java/hackathon/FrisbYEE/rest/AthleteResource.java index 8bca5ff..61189c4 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/rest/AthleteResource.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/rest/AthleteResource.java @@ -4,6 +4,7 @@ import java.time.LocalDate; import java.time.chrono.ChronoLocalDateTime; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -164,41 +165,43 @@ public class AthleteResource { }) @GetMapping("/athlete/{athleteId}/session") public List getSessionsAthlete(@PathVariable Integer athleteId) { - // return pet - System.out.println("ID A CHERCHER" + athleteId); - java.util.Optional j = athleteDAO.findById(athleteId); - List sessions = sessionDAO.findAll(); - List athleteSessions = new ArrayList<>(); - for (Session s : sessions) { - if (s.getAthletes().contains(j.get())) { - SessionDTO dto = new SessionDTO(); - - dto.setId(s.getId()); - dto.setName(s.getName()); - dto.setCreneau(s.getCreneau()); - List activiteIDs = new ArrayList<>(); - for (Activite activite : s.getActivites()) { - activiteIDs.add(activite.getId()); - } - dto.setActiviteIds(activiteIDs); - dto.setCoachId(s.getCoach().getId()); - dto.setDuree(s.getDuree()); - dto.setGroupe(s.getGroupe()); - dto.setIsRecurrent(s.getIsRecurrent()); - List athleteIds = new ArrayList<>(); - for (Athlete athlete : s.getAthletes()) { - athleteIds.add(athlete.getId()); - } - dto.setAthleteIds(athleteIds); - - // Map other fields as necessary - athleteSessions.add(dto); - } + Optional athleteOpt = athleteDAO.findById(athleteId); + if (athleteOpt.isEmpty()) { + return new ArrayList<>(); } - System.out.println(j); + + List sessions = sessionDAO.findByAthletes_Id(athleteId); + List athleteSessions = new ArrayList<>(); + + for (Session s : sessions) { + SessionDTO dto = new SessionDTO(); + dto.setId(s.getId()); + dto.setName(s.getName()); + dto.setCreneau(s.getCreneau()); + dto.setDuree(s.getDuree()); + dto.setGroupe(s.getGroupe()); + dto.setIsRecurrent(s.getIsRecurrent()); + dto.setCoachId(s.getCoach() != null ? s.getCoach().getId() : null); + + List activiteIDs = new ArrayList<>(); + for (Activite activite : s.getActivites()) { + activiteIDs.add(activite.getId()); + } + dto.setActiviteIds(activiteIDs); + + List athleteIds = new ArrayList<>(); + for (Athlete a : s.getAthletes()) { + athleteIds.add(a.getId()); + } + dto.setAthleteIds(athleteIds); + + athleteSessions.add(dto); + } + return athleteSessions; } + @Operation(summary = "Récupère toutes les sessions") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Récupération effectuée", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SessionDTO.class))) diff --git a/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java b/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java index b37460d..736037c 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java @@ -43,8 +43,12 @@ public class SessionResource { @ResponseBody @PreAuthorize("hasRole('coach')") public ResponseEntity create(@RequestBody SessionDTO dto) { + System.out.println("=== SESSION DTO RECEIVED ==="); + System.out.println(dto); + System.out.println("Coach ID: " + dto.getCoachId()); + System.out.println("ID null"); try { - if (sessionDAO.findById(dto.getId()).isPresent()) { + if (dto.getId() != null && sessionDAO.findById(dto.getId()).isPresent()) { return ResponseEntity.status(HttpStatus.OK).body("Session with ID " + dto.getId() + " already exists."); } @@ -54,6 +58,7 @@ public class SessionResource { sessionDAO.save(session); return ResponseEntity.status(HttpStatus.CREATED).body(maptoDTO(session)); } catch (Exception ex) { + ex.printStackTrace(); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage()); } } diff --git a/front_end/src/components/StatsAthlete.tsx b/front_end/src/components/StatsAthlete.tsx index 641652d..97514a5 100644 --- a/front_end/src/components/StatsAthlete.tsx +++ b/front_end/src/components/StatsAthlete.tsx @@ -1,31 +1,78 @@ -import React from "react"; +import React, { useEffect, useState } from "react"; import { Athlete, Session } from "../classes"; import { calculStatsAthlete, niveauAlerte, StatsAthlete } from "../utils/athleteUtils" +import { getSessionsByAthleteId, getSessionsOfUserAPI } from "../requetes"; interface AthleteStatsProps { athlete: Athlete; } function StatAthlete({ athlete }: AthleteStatsProps) { - const [dateDebut, setDateDebut] = React.useState(new Date()); - const [dateFin, setDateFin] = React.useState(new Date()); - const [seuilCritique, setSeuilCritique] = React.useState(0); - const [seuilMax, setSeuilMax] = React.useState(0); - const [stats, setStats] = React.useState(null); - + console.log("Athlete:", athlete); + console.log("Sessions:", athlete.sessions); + const [sessions, setSessions] = useState([]); + const [loading, setLoading] = useState(false); + const [dateDebut, setDateDebut] = useState(new Date()); + const [dateFin, setDateFin] = useState(new Date()); + const [seuilCritique, setSeuilCritique] = useState(0); + const [seuilMax, setSeuilMax] = useState(0); + const [stats, setStats] = useState(null); const dateToDatetimeLocal = (date: Date) => { const pad = (n: number) => n.toString().padStart(2, "0"); return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`; }; + useEffect(() => { + async function loadSessions() { + if (!athlete.id) { + console.error("Athlete ID is null"); + setLoading(false); + return; + } + + setLoading(true); + try { + const sessionsData = await getSessionsByAthleteId(athlete.id); + setSessions(sessionsData); + console.log("Sessions chargées:", sessionsData); + console.log("Première session:", sessionsData[0]); + console.log("Athletes de la première session:", sessionsData[0]?.athletes); + } catch (error) { + console.error("Erreur lors du chargement des sessions:", error); + setSessions([]); + } finally { + setLoading(false); + } + } + + loadSessions(); +}, [athlete.id]); + const handleCalculerStats = () => { - const statsCalculees = calculStatsAthlete(athlete.sessions, athlete, dateDebut, dateFin); + let safeDebut = dateDebut; + let safeFin = dateFin; + if (sessions.length > 0) { + const times = sessions + .map(s => s.creneau?.getTime()) + .filter(t => typeof t === 'number') as number[]; + if (times.length > 0) { + const min = Math.min(...times); + const max = Math.max(...times); + // if user range is zero-length or inverted, default to sessions span + if (safeDebut.getTime() === safeFin.getTime() || safeDebut.getTime() > safeFin.getTime()) { + safeDebut = new Date(min); + safeFin = new Date(max); + } + } + } + + const statsCalculees = calculStatsAthlete(sessions, athlete, safeDebut, safeFin); setStats(statsCalculees); }; return (
-
Nb Session : {athlete.sessions.length};
+
Nb Session : {sessions.length};
@@ -52,7 +99,7 @@ function StatAthlete({ athlete }: AthleteStatsProps) { {stats && (
-

Statistiques de {athlete.nom}

+

Statistiques de {athlete.prenom} {athlete.nom}

Nombre total de sessions : {stats.nbSessions}

Sessions par semaine : {stats.nbSessionsPerWeek.toFixed(2)}

Statut : {niveauAlerte(stats, seuilCritique, seuilMax)}

diff --git a/front_end/src/requetes.tsx b/front_end/src/requetes.tsx index e36b6f2..488e634 100644 --- a/front_end/src/requetes.tsx +++ b/front_end/src/requetes.tsx @@ -361,3 +361,29 @@ export async function getAllAthlete(): Promise { } } +export async function getSessionsByAthleteId(athleteId: number): Promise { + try { + const response = await api.get(`/athlete/athlete/${athleteId}/session`); + const sessions: Session[] = []; + + const allAthletes = await getAllAthlete(); + + response.data.forEach((sessionDTO: SessionDTO) => { + const session = new Session(sessionDTO); + + if (sessionDTO.athleteIds && sessionDTO.athleteIds.length > 0) { + session.athletes = allAthletes.filter(a => + sessionDTO.athleteIds.includes(a.id!) + ); + } + + sessions.push(session); + }); + + console.log(`Sessions chargées pour l'athlète ${athleteId}:`, sessions); + return sessions; + } catch (error) { + console.error("Error fetching sessions for athlete:", error); + return []; + } +} \ No newline at end of file diff --git a/front_end/src/utils/athleteUtils.tsx b/front_end/src/utils/athleteUtils.tsx index 893bd68..9a4e58f 100644 --- a/front_end/src/utils/athleteUtils.tsx +++ b/front_end/src/utils/athleteUtils.tsx @@ -18,7 +18,8 @@ export function calculStatsAthlete(sessions: Session[], athlete: Athlete, debut: let nb_semaine = 1; //forcément une semaine const distributions: Map = new Map(); const timeDiff = Math.abs(fin.getTime() - debut.getTime()); - nb_semaine = Math.ceil(timeDiff / (1000 * 3600 * 24 * 7)); + const msPerWeek = 1000 * 3600 * 24 * 7; + nb_semaine = Math.max(1, Math.ceil(timeDiff / msPerWeek)); sessions.forEach(session => { // verification session dans l'intervalle
Début :