Feat: Stats athlètes fonctionnel
This commit is contained in:
@@ -1,10 +1,14 @@
|
|||||||
package hackathon.FrisbYEE.jpa.service;
|
package hackathon.FrisbYEE.jpa.service;
|
||||||
|
|
||||||
import hackathon.FrisbYEE.jpa.metier.Session;
|
import hackathon.FrisbYEE.jpa.metier.Session;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
public interface SessionDAO extends JpaRepository<Session, Integer> {
|
public interface SessionDAO extends JpaRepository<Session, Integer> {
|
||||||
|
List<Session> findByAthletes_Id(Integer athleteId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.time.LocalDate;
|
|||||||
import java.time.chrono.ChronoLocalDateTime;
|
import java.time.chrono.ChronoLocalDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@@ -164,41 +165,43 @@ public class AthleteResource {
|
|||||||
})
|
})
|
||||||
@GetMapping("/athlete/{athleteId}/session")
|
@GetMapping("/athlete/{athleteId}/session")
|
||||||
public List<SessionDTO> getSessionsAthlete(@PathVariable Integer athleteId) {
|
public List<SessionDTO> getSessionsAthlete(@PathVariable Integer athleteId) {
|
||||||
// return pet
|
Optional<Athlete> athleteOpt = athleteDAO.findById(athleteId);
|
||||||
System.out.println("ID A CHERCHER" + athleteId);
|
if (athleteOpt.isEmpty()) {
|
||||||
java.util.Optional<Athlete> j = athleteDAO.findById(athleteId);
|
return new ArrayList<>();
|
||||||
List<Session> sessions = sessionDAO.findAll();
|
|
||||||
List<SessionDTO> 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<Integer> 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<Integer> athleteIds = new ArrayList<>();
|
|
||||||
for (Athlete athlete : s.getAthletes()) {
|
|
||||||
athleteIds.add(athlete.getId());
|
|
||||||
}
|
|
||||||
dto.setAthleteIds(athleteIds);
|
|
||||||
|
|
||||||
// Map other fields as necessary
|
|
||||||
athleteSessions.add(dto);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
System.out.println(j);
|
|
||||||
|
List<Session> sessions = sessionDAO.findByAthletes_Id(athleteId);
|
||||||
|
List<SessionDTO> 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<Integer> activiteIDs = new ArrayList<>();
|
||||||
|
for (Activite activite : s.getActivites()) {
|
||||||
|
activiteIDs.add(activite.getId());
|
||||||
|
}
|
||||||
|
dto.setActiviteIds(activiteIDs);
|
||||||
|
|
||||||
|
List<Integer> athleteIds = new ArrayList<>();
|
||||||
|
for (Athlete a : s.getAthletes()) {
|
||||||
|
athleteIds.add(a.getId());
|
||||||
|
}
|
||||||
|
dto.setAthleteIds(athleteIds);
|
||||||
|
|
||||||
|
athleteSessions.add(dto);
|
||||||
|
}
|
||||||
|
|
||||||
return athleteSessions;
|
return athleteSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Operation(summary = "Récupère toutes les sessions")
|
@Operation(summary = "Récupère toutes les sessions")
|
||||||
@ApiResponses(value = {
|
@ApiResponses(value = {
|
||||||
@ApiResponse(responseCode = "200", description = "Récupération effectuée", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SessionDTO.class)))
|
@ApiResponse(responseCode = "200", description = "Récupération effectuée", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SessionDTO.class)))
|
||||||
|
|||||||
@@ -43,8 +43,12 @@ public class SessionResource {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@PreAuthorize("hasRole('coach')")
|
@PreAuthorize("hasRole('coach')")
|
||||||
public ResponseEntity<?> create(@RequestBody SessionDTO dto) {
|
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 {
|
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.");
|
return ResponseEntity.status(HttpStatus.OK).body("Session with ID " + dto.getId() + " already exists.");
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -54,6 +58,7 @@ public class SessionResource {
|
|||||||
sessionDAO.save(session);
|
sessionDAO.save(session);
|
||||||
return ResponseEntity.status(HttpStatus.CREATED).body(maptoDTO(session));
|
return ResponseEntity.status(HttpStatus.CREATED).body(maptoDTO(session));
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,78 @@
|
|||||||
import React from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Athlete, Session } from "../classes";
|
import { Athlete, Session } from "../classes";
|
||||||
import { calculStatsAthlete, niveauAlerte, StatsAthlete } from "../utils/athleteUtils"
|
import { calculStatsAthlete, niveauAlerte, StatsAthlete } from "../utils/athleteUtils"
|
||||||
|
import { getSessionsByAthleteId, getSessionsOfUserAPI } from "../requetes";
|
||||||
|
|
||||||
interface AthleteStatsProps {
|
interface AthleteStatsProps {
|
||||||
athlete: Athlete;
|
athlete: Athlete;
|
||||||
}
|
}
|
||||||
|
|
||||||
function StatAthlete({ athlete }: AthleteStatsProps) {
|
function StatAthlete({ athlete }: AthleteStatsProps) {
|
||||||
const [dateDebut, setDateDebut] = React.useState(new Date());
|
console.log("Athlete:", athlete);
|
||||||
const [dateFin, setDateFin] = React.useState(new Date());
|
console.log("Sessions:", athlete.sessions);
|
||||||
const [seuilCritique, setSeuilCritique] = React.useState(0);
|
const [sessions, setSessions] = useState<Session[]>([]);
|
||||||
const [seuilMax, setSeuilMax] = React.useState(0);
|
const [loading, setLoading] = useState<boolean>(false);
|
||||||
const [stats, setStats] = React.useState<StatsAthlete | null>(null);
|
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<StatsAthlete | null>(null);
|
||||||
const dateToDatetimeLocal = (date: Date) => {
|
const dateToDatetimeLocal = (date: Date) => {
|
||||||
const pad = (n: number) => n.toString().padStart(2, "0");
|
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())}`;
|
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 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);
|
setStats(statsCalculees);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="creneau-stats">
|
<div className="creneau-stats">
|
||||||
<div>Nb Session : {athlete.sessions.length};</div>
|
<div>Nb Session : {sessions.length};</div>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Début :</th>
|
<th>Début :</th>
|
||||||
@@ -52,7 +99,7 @@ function StatAthlete({ athlete }: AthleteStatsProps) {
|
|||||||
|
|
||||||
{stats && (
|
{stats && (
|
||||||
<div className="stats-display">
|
<div className="stats-display">
|
||||||
<h3>Statistiques de {athlete.nom}</h3>
|
<h3>Statistiques de {athlete.prenom} {athlete.nom}</h3>
|
||||||
<p><strong>Nombre total de sessions :</strong> {stats.nbSessions}</p>
|
<p><strong>Nombre total de sessions :</strong> {stats.nbSessions}</p>
|
||||||
<p><strong>Sessions par semaine :</strong> {stats.nbSessionsPerWeek.toFixed(2)}</p>
|
<p><strong>Sessions par semaine :</strong> {stats.nbSessionsPerWeek.toFixed(2)}</p>
|
||||||
<p><strong>Statut :</strong> {niveauAlerte(stats, seuilCritique, seuilMax)}</p>
|
<p><strong>Statut :</strong> {niveauAlerte(stats, seuilCritique, seuilMax)}</p>
|
||||||
|
|||||||
@@ -361,3 +361,29 @@ export async function getAllAthlete(): Promise<Athlete[]> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getSessionsByAthleteId(athleteId: number): Promise<Session[]> {
|
||||||
|
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 [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,7 +18,8 @@ export function calculStatsAthlete(sessions: Session[], athlete: Athlete, debut:
|
|||||||
let nb_semaine = 1; //forcément une semaine
|
let nb_semaine = 1; //forcément une semaine
|
||||||
const distributions: Map<string, number> = new Map();
|
const distributions: Map<string, number> = new Map();
|
||||||
const timeDiff = Math.abs(fin.getTime() - debut.getTime());
|
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 => {
|
sessions.forEach(session => {
|
||||||
// verification session dans l'intervalle
|
// verification session dans l'intervalle
|
||||||
|
|||||||
Reference in New Issue
Block a user