From 5f62ba2a5454c7bbfc0f681e864d19f72c94e006 Mon Sep 17 00:00:00 2001 From: trochas Date: Wed, 7 Jan 2026 11:51:09 +0100 Subject: [PATCH 1/2] edt fix --- front_end/src/App.css | 1 + front_end/src/App.tsx | 5 ++- front_end/src/classes.tsx | 2 +- front_end/src/components/createSession.tsx | 2 +- front_end/src/components/edt.tsx | 45 ++++++++++++++++----- front_end/src/components/edt_session.tsx | 25 +++++++----- front_end/src/components/login.tsx | 25 +++++++++++- front_end/src/components/style/edt.css | 47 ++++++++++++++++++---- front_end/src/index.css | 6 +-- front_end/src/requetes.tsx | 9 ++++- 10 files changed, 130 insertions(+), 37 deletions(-) diff --git a/front_end/src/App.css b/front_end/src/App.css index d0307cd..7eb393d 100644 --- a/front_end/src/App.css +++ b/front_end/src/App.css @@ -3,4 +3,5 @@ background-color: var(--tint4); color: var(--text); min-height: 100vh; + padding: 16px; } diff --git a/front_end/src/App.tsx b/front_end/src/App.tsx index d78fb61..dbc7d01 100644 --- a/front_end/src/App.tsx +++ b/front_end/src/App.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import './App.css'; import { ReactKeycloakProvider } from '@react-keycloak/web' import keycloak from './keycloak' @@ -14,7 +14,10 @@ const keycloakInitOptions = { checkLoginIframe: false } + function App() { + + return ( diff --git a/front_end/src/classes.tsx b/front_end/src/classes.tsx index b66407a..3596225 100644 --- a/front_end/src/classes.tsx +++ b/front_end/src/classes.tsx @@ -23,7 +23,7 @@ export class Session{ id!: number; name!: String; activites: Activite[] = []; - isRecurent! : Boolean; + isRecurrent! : Boolean; creneau!: Date; coach!: Coach; athletes!: Athlete[] diff --git a/front_end/src/components/createSession.tsx b/front_end/src/components/createSession.tsx index e55407b..a375e1a 100644 --- a/front_end/src/components/createSession.tsx +++ b/front_end/src/components/createSession.tsx @@ -37,7 +37,7 @@ export const CreateSession = () => { newSession.groupe = groupe; newSession.creneau = new Date(creneau); newSession.duree= duree; - newSession.isRecurent= isRecurent; + newSession.isRecurrent= isRecurent; newSession.coach= user as Coach; newSession.athletes= []; newSession.activites= activities; diff --git a/front_end/src/components/edt.tsx b/front_end/src/components/edt.tsx index 3277335..ddda902 100644 --- a/front_end/src/components/edt.tsx +++ b/front_end/src/components/edt.tsx @@ -4,7 +4,8 @@ import { useLocalData } from "../context/useLocalData" import './style/edt.css'; import {updateSessionsOfUserAPI } from "../requetes"; import EdtSession from "./edt_session"; - +import {delay} from "../requetes"; +import Loading from "./loading"; export function dateToString(date:Date){ const dd_prefix = date.getDate()<10 ? "0" : ""; @@ -28,11 +29,14 @@ export const EDT =() =>{ const {user,setUser} = useLocalData() const [sessions, setSessions] = useState([]) const [week,setWeek] = useState(getFirstDay(new Date())); + const [loadedWeek,setLoadedWeek] = useState(null); + const [loading,setLoading] = useState(false); const week_days:String[] = ["Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi","Dimanche"]; const week_days_nums:number[] = [1,2,3,4,5,6,0]; + function loadSessions(date:Date){ var maxDate = getNextDay(date,6) @@ -47,18 +51,39 @@ export const EDT =() =>{ function changeWeek(date:Date){ setWeek(date); - loadSessions(date) + } + + function isSameDay(date1:Date,date2:Date){ + return ( + date1.getDay()===date2.getDay() && + date1.getMonth()===date2.getMonth() && + date1.getFullYear()===date2.getFullYear()); } useEffect(() => { - updateWeek(); - },[week]) + setLoadedWeek(null); + updateWeek(week); + loadSessions(week) + setLoading(true); + },[week,user]) + + useEffect(() => { + if(loadedWeek!==null){ + if(isSameDay(week,loadedWeek)){ + loadSessions(week) + setLoading(false); + } + else{ + setLoadedWeek(null); + } + } + },[loadedWeek]) - async function updateWeek(){ + async function updateWeek(week:Date){ //TODO updateSession + await delay(2000); //await updateSessionsOfUser(user,null,null); - loadSessions(week); - setUser(getUserTest()) + setLoadedWeek(week); } @@ -90,20 +115,20 @@ export const EDT =() =>{ return( -
+
- +
{loading && }
{week_days_nums.map((num,index)=>(
{week_days[index]}
{dateToString(getNextDay(week,index))}
-
+
{sessions.map((session,index2)=>( session.creneau.getDay()===num && diff --git a/front_end/src/components/edt_session.tsx b/front_end/src/components/edt_session.tsx index 66d0b0c..4b23c40 100644 --- a/front_end/src/components/edt_session.tsx +++ b/front_end/src/components/edt_session.tsx @@ -4,6 +4,7 @@ import { dateToString, hoursToString } from './edt'; import './style/edt.css'; import { Modal } from './Modal'; import Loading from './loading'; +import {delay} from "../requetes"; type Props = { @@ -21,6 +22,7 @@ function EdtSession({session}:Props){ async function updateActivites(){ //TODO + await delay(2000); //await updateActivitiesOfSessionAPI(session); setLoading(false); } @@ -37,19 +39,24 @@ function EdtSession({session}:Props){ return(
handleOpen()}> -
{hoursToString(sDate)}
+
+
{hoursToString(sDate)}
+ {!session.isRecurrent &&
recurrent
} +
{session.name}
{open && setOpen(false)}> -
{session.name}
-
{hoursToString(sDate)}
-
{dateToString(sDate)}
- {session.activites.map((activite,index)=>( -
activite
- ))} - - {loading && } +
+
{session.name}
+
{hoursToString(sDate)}
+
{dateToString(sDate)}
+ {session.activites.map((activite,index)=>( +
activite
+ ))} + {loading &&
} +
+
}
diff --git a/front_end/src/components/login.tsx b/front_end/src/components/login.tsx index a99949a..8facb90 100644 --- a/front_end/src/components/login.tsx +++ b/front_end/src/components/login.tsx @@ -1,19 +1,40 @@ import { useKeycloak } from '@react-keycloak/web' +import { useEffect } from 'react'; +import { getUserTest, User } from '../classes'; +import { useLocalData } from '../context/useLocalData'; export const Login =() =>{ + const {user,setUser} = useLocalData() + + + useEffect(() => { //TODO à supprimer + setUser(getUserTest()) + },[]); + + + function handleLogin(): void { + keycloak.login() + //TODO setUser + } + + function handleLogout(): void { + keycloak.logout() + setUser(new User()); + } + const { keycloak } = useKeycloak() return(
Authenticated : {keycloak.authenticated ? '✅' : '❌'}
- -
diff --git a/front_end/src/components/style/edt.css b/front_end/src/components/style/edt.css index 4c4d274..d715519 100644 --- a/front_end/src/components/style/edt.css +++ b/front_end/src/components/style/edt.css @@ -1,56 +1,74 @@ .edt{ - justify-contedt: cedter; + justify-content: center; background-color: var(--tint1); border-radius: 30px; padding: 10px; } + .edt_header{ - justify-contedt: cedter; + justify-content: center; display: grid; - grid-template-columns: repeat(2, 1fr); + grid-template-columns: repeat(2, 0.5fr); /* background-color: #0000FF; */ padding-bottom: 10px; gap: 30%; } .edt_colonnes { + position: relative; display: grid; align-items: flex-start; - grid-template-columns: repeat(7, 1fr); + grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 16px; color: var(--text); /* background-color: #00FF00; */ width: 100%; } +.edt_loading{ + position: absolute; + inset: 0; + display: grid; + /* place-items: center; */ + pointer-events: none; +} + .edt_colonne { display: grid; background-color: var(--tint3); border-radius: 20px; + container-type: inline-size; } .edt_day_header{ + font-size: clamp(5px, 1vw, 18px); padding: 8px; /* background-color: var(--tint2); */ border-radius: 20px; height: 30px; - text-align: cedter; + text-align: center; font-size: 1em; } -.edt_day_contedt{ - display: grid; +.edt_day_content{ + display: flex; + flex-direction: column; gap: 8px; padding: 8px; border-radius: 20px; + min-width: 0; + /* background-color: #FF0000; */ } .edt_session { + + font-size: clamp(1px, 8cqi, 18px); gap: 8px; background-color: var(--tint4); border-radius: 12px; - padding: 8px; + padding: 5%; + min-width: 0; } .edt_session:hover { @@ -61,6 +79,11 @@ background-color: var(--tint5); } +.edt_session_header{ + display: flex; + gap: 5px; +} + .edt_date{ font-size: 0.75em; } @@ -72,3 +95,11 @@ border-radius: 20px; } + +.edt_session_modal{ + background-color: var(--tint2); + padding: 20px; + border-radius: 20px; + position: relative; +} + diff --git a/front_end/src/index.css b/front_end/src/index.css index f82f209..bbb1bfe 100644 --- a/front_end/src/index.css +++ b/front_end/src/index.css @@ -49,16 +49,14 @@ code { } .modal{ - background-color: var(--tint2); padding: 10px; - border-radius: 20px; min-width: 200px; min-height: 100px; } .loading{ - width: 24px; - height: 24px; + width: 40px; + height: 40px; animation: spin 1s linear infinite; } diff --git a/front_end/src/requetes.tsx b/front_end/src/requetes.tsx index 1b13c48..08d3ec9 100644 --- a/front_end/src/requetes.tsx +++ b/front_end/src/requetes.tsx @@ -2,14 +2,21 @@ import api from "./api"; import { Activite, Athlete, Coach, Session, User } from "./classes"; import { useKeycloak } from '@react-keycloak/web' -const { keycloak } = useKeycloak() +/*const { keycloak } = useKeycloak() const useAuthHeader = () => { return keycloak?.token ? { Authorization: `Bearer ${keycloak.token}` } : {} +}*/ + +//debug: +export function delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); } + + //UPDATE ///////////////////////////////////////////////////////// //COACH / ATHLETE From 7a0bbb410f129f6b76ec4841f2fb70936339cdd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ama=C3=ABl=20Kesteman?= Date: Wed, 7 Jan 2026 12:00:07 +0100 Subject: [PATCH 2/2] =?UTF-8?q?Feat:=20ajout=20de=20la=20liste=20pour=20vo?= =?UTF-8?q?ir=20les=20activit=C3=A9s=20et=20les=20athl=C3=A8tes=20en=20tan?= =?UTF-8?q?t=20que=20coach/=20admin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front_end/src/App.tsx | 2 + front_end/src/classes.tsx | 82 ++++++++++++++++++++- front_end/src/components/dropdownButton.tsx | 27 +++++++ front_end/src/components/ressourceList.tsx | 47 ++++++++++++ front_end/src/components/ressourcePanel.tsx | 52 +++++++++++++ 5 files changed, 206 insertions(+), 4 deletions(-) create mode 100644 front_end/src/components/dropdownButton.tsx create mode 100644 front_end/src/components/ressourceList.tsx create mode 100644 front_end/src/components/ressourcePanel.tsx diff --git a/front_end/src/App.tsx b/front_end/src/App.tsx index d78fb61..95dbf7d 100644 --- a/front_end/src/App.tsx +++ b/front_end/src/App.tsx @@ -7,6 +7,7 @@ import { LocalDataProvider } from './provider/LocalDataProvider'; import EDT from './components/edt'; import SwitchThemeColor from './components/SwitchThemeColor'; import CreateSession from './components/createSession' +import RessourcePanel from './components/ressourcePanel'; const keycloakInitOptions = { @@ -22,6 +23,7 @@ function App() {

Frisbyee

+
diff --git a/front_end/src/classes.tsx b/front_end/src/classes.tsx index b66407a..1cd5e75 100644 --- a/front_end/src/classes.tsx +++ b/front_end/src/classes.tsx @@ -11,6 +11,7 @@ export class Admin extends User{ } export class Athlete extends User{ + nom!: String; groupe!: Groupe; } @@ -60,10 +61,83 @@ export function getUserTest():User{ s3.id = 3; s3.name = "entraintement3" - const a1:Activite = new Activite(); - const a2:Activite = new Activite(); - s1.activites.push(a1); - s1.activites.push(a2); + const athlete1 = new Athlete(); + athlete1.id = 1; + athlete1.nom = "Alice Dupont"; + athlete1.groupe = "Entrainement"; + + const athlete2 = new Athlete(); + athlete2.id = 2; + athlete2.nom = "Bob Martin"; + athlete2.groupe = "Competition"; + + const athlete3 = new Athlete(); + athlete3.id = 3; + athlete3.nom = "Clara Lopez"; + athlete3.groupe = "Loisir"; + + s1.athletes = [athlete1, athlete2]; + s2.athletes = [athlete2, athlete3]; + s3.athletes = [athlete1, athlete3]; + + + const act1 = new Activite(); + act1.id = 1; + act1.nom = "Échauffement"; + act1.theme = "Cardio"; + act1.duree = 15; + act1.session = s1; + act1.data = new Map([["objectif", "Préparer le corps"], ["matériel", "Ballon"]]); + + const act2 = new Activite(); + act2.id = 2; + act2.nom = "Dribbles et passes"; + act2.theme = "Technique"; + act2.duree = 30; + act2.session = s1; + act2.data = new Map([["objectif", "Améliorer les passes"], ["niveau", "Intermédiaire"]]); + + const act3 = new Activite(); + act3.id = 3; + act3.nom = "Renforcement musculaire"; + act3.theme = "Force"; + act3.duree = 25; + act3.session = s2; + act3.data = new Map([["objectif", "Renforcer les jambes"], ["matériel", "Haltères"]]); + + const act4 = new Activite(); + act4.id = 4; + act4.nom = "Sprint et agilité"; + act4.theme = "Vitesse"; + act4.duree = 20; + act4.session = s2; + act4.data = new Map([["objectif", "Améliorer les sprints"], ["matériel", "Plots"]]); + + const act5 = new Activite(); + act5.id = 5; + act5.nom = "Match 5v5"; + act5.theme = "Jeu"; + act5.duree = 60; + act5.session = s3; + act5.data = new Map([["objectif", "Appliquer les techniques"], ["niveau", "Avancé"]]); + + const act6 = new Activite(); + act6.id = 6; + act6.nom = "Étirements"; + act6.theme = "Récupération"; + act6.duree = 10; + act6.session = s3; + act6.data = new Map([["objectif", "Éviter les blessures"], ["matériel", "Tapis"]]); + + + // attach the concrete activities to their sessions + s1.activites.push(act1); + s1.activites.push(act2); + s2.activites.push(act3); + s2.activites.push(act4); + s3.activites.push(act5); + s3.activites.push(act6); + user.sessions.push(s1); user.sessions.push(s2); user.sessions.push(s3); diff --git a/front_end/src/components/dropdownButton.tsx b/front_end/src/components/dropdownButton.tsx new file mode 100644 index 0000000..2468337 --- /dev/null +++ b/front_end/src/components/dropdownButton.tsx @@ -0,0 +1,27 @@ +import Dropdown from 'react-bootstrap/Dropdown'; +import { Athlete } from '../classes'; + + type Props = { + onAthletesClick: () => void; + onActivitiesClick: () => void; + } + +function ListButton({ onAthletesClick, onActivitiesClick }: Props) { + return ( + + + Sélectionner la ressource + + + + Athlètes + + + Activités + + + + ); +} + +export default ListButton; \ No newline at end of file diff --git a/front_end/src/components/ressourceList.tsx b/front_end/src/components/ressourceList.tsx new file mode 100644 index 0000000..b398a54 --- /dev/null +++ b/front_end/src/components/ressourceList.tsx @@ -0,0 +1,47 @@ +import ListGroup from "react-bootstrap/ListGroup"; +import { Athlete, Activite } from "../classes"; + +type Props = { + athletes: Athlete[]; + activites: Activite[]; + +}; + +function AthleteList({ athletes }: Props) { + return ( + + {athletes.map((athlete) => ( + +
+ Nom: {athlete.nom} +
+
+ Groupe: {athlete.groupe} +
+
+ ))} +
+ ); +} + +function ActiviteList({ activites }: Props) { + return ( + + {activites.map((activite) => ( + +
+ Nom: {activite.nom} +
+
+ Thème: {activite.theme} +
+
+ Durée: {activite.duree} minutes +
+
+ ))} +
+ ); +} + +export { AthleteList, ActiviteList }; \ No newline at end of file diff --git a/front_end/src/components/ressourcePanel.tsx b/front_end/src/components/ressourcePanel.tsx new file mode 100644 index 0000000..0620ede --- /dev/null +++ b/front_end/src/components/ressourcePanel.tsx @@ -0,0 +1,52 @@ +import { useState } from "react"; +import { useLocalData } from "../context/useLocalData"; +import ListButton from "./dropdownButton"; +import { AthleteList, ActiviteList } from "./ressourceList"; +import { Activite, Athlete } from "../classes"; + +export default function RessourcePanel() { + const { user } = useLocalData(); + const [showAthletes, setShowAthletes] = useState(false); + const [showActivites, setShowActivites] = useState(false); + + + const athleteMap: Map = new Map(); + user.sessions.forEach(session => { + session.athletes?.forEach(a => athleteMap.set(a.id, a)); + }); + const allAthletes: Athlete[] = Array.from(athleteMap.values()); + + const activiteMap: Map = new Map(); + user.sessions.forEach(session => { + session.activites?.forEach(act => activiteMap.set(act.id, act)); + }); + const allActivites: Activite[] = Array.from(activiteMap.values()); + + return ( +
+ { + setShowAthletes(prev => !prev); + setShowActivites(false); + }} + onActivitiesClick={() => { + setShowActivites(prev => !prev); + setShowAthletes(false); + }} + /> + {showAthletes && ( +
+

Liste des athlètes

+ +
+ )} + {showActivites && ( +
+

Liste des activités

+ +
+ )} + +
+ ); +}