correction ressource list, clean composant

This commit is contained in:
trochas
2026-01-08 12:41:25 +01:00
parent 7c6ee6b65f
commit be4ab7d7cf
16 changed files with 491 additions and 228 deletions

View File

@@ -66,6 +66,7 @@ export function getUserTest():User{
const athlete1 = new Athlete();
athlete1.id = 1;
athlete1.nom = "Alice Dupont";
athlete1.email = "alice@nootnoot.yee";
athlete1.groupe = "Entrainement";
const athlete2 = new Athlete();
@@ -100,6 +101,7 @@ export function getUserTest():User{
user.id = 0;
user.nom = "Emilien-Yee NootNoot";
user.email = "emilien@nootnoot.yee";
user.role = "Coach"
s1.creneau = new Date();
s1.id = 1;

View File

@@ -39,7 +39,7 @@ export function CreateActivite({ returnActivite }: CreateActiciteProps){
return (
<Modal isOpen={true} onClose={() => cancel()}>
<div className="edt_activite_modal">
<div className="create_activite_modal">
<h2>Nouvelle Activité :</h2>
<div>
Nom de l'activité:

View File

@@ -2,14 +2,16 @@ import { useState, useEffect } from "react";
import { Session, User, Coach, Activite, Groupe } from "../classes";
import { useLocalData } from "../context/useLocalData";
import { sessionService } from "../api";
import { postSession } from "../requetes";
export const CreateSession = () => {
const {user} = useLocalData()
const {user} = useLocalData();
const [session,setSession] = useState<Session>(new Session());
const [activities, setActivities] = useState<Activite[]>([]);
const [name,setName] = useState("");
const [groupe, setGroupe] = useState<Groupe>("");
const [creneau, setCreneau] = useState("");
const [duree, setDuree] = useState<number>(0);
const [activities, setActivities] = useState<Activite[]>([]);
const [activiteNom, setActiviteNom] = useState("");
const [activiteTheme, setActiviteTheme] = useState("");
const [activiteDuree, setActiviteDuree] = useState(0);
@@ -23,101 +25,78 @@ export const CreateSession = () => {
newActivite.theme=activiteTheme;
newActivite.duree= activiteDuree;
newActivite.data= new Map<string,string>();
try{
await sessionService.create(newActivite);
console.log("Session créée");
setActivities([...activities, newActivite]);
session.activites.push(newActivite);
setActivities([...activities, newActivite]);
setActiviteNom("");
setActiviteTheme("");
setActiviteDuree(0);
} catch (error) {
console.error("Erreur lors de la création de la session", error);
}
}
async function handleCreateSession() {
const data = {
name: name,
creneau: creneau, // string ISO OK
duree: duree,
isRecurrent: isRecurent,
coachId: user?.id,
groupe: groupe ? groupe : undefined,
postSession(session);
console.log("Session créée");
activites: activities.map(a => ({
nom: a.nom,
theme: a.theme,
duree: a.duree
}))
};
// reset
setName("");
setGroupe("");
setCreneau("");
setDuree(0);
setIsRecurent(false);
setActivities([]);
try {
await sessionService.create(data);
console.log("Session créée");
// reset
setName("");
setGroupe("");
setCreneau("");
setDuree(0);
setIsRecurent(false);
setActivities([]);
} catch (err) {
console.error("Erreur lors de la création de la session", err);
}
}
return (
<div className="ent">
<h2>Activité</h2>
<label>
Name:
<input type="text" value={activiteNom} onChange={e => setActiviteNom(e.target.value)} />
</label>
<label>
Theme:
<input type="text" value={activiteTheme} onChange={e => setActiviteTheme(e.target.value)} />
</label>
<label>
Duree (minutes):
<input type="number" value={activiteDuree} onChange={e => setActiviteDuree(Number(e.target.value))} />
</label>
<button type="button" onClick={addAcitivte}>Add Activite</button>
<h2>Créer une session</h2>
<label>
Nom:
<input type="text" value={name} onChange={e => setName(e.target.value)} />
</label>
<label>
Groupe:
</label>
<label>
Creneau:
<input type="datetime-local" value={creneau} onChange={e => setCreneau(e.target.value)} />
</label>
<label>
Duree (minutes):
<input type="number" value={duree} onChange={e => setDuree(Number(e.target.value))} />
</label>
<label>
Recurrent:
<input type="checkbox" checked={isRecurent} onChange={e => setIsRecurent(e.target.checked)} />
</label>
<h3>Ajouter une activité : </h3>
<label>
Nom de l'activitée:
<input type="text" value={activiteNom} onChange={e => setActiviteNom(e.target.value)} />
</label>
<label>
Theme:
<input type="text" value={activiteTheme} onChange={e => setActiviteTheme(e.target.value)} />
</label>
<label>
Duree (minutes):
<input type="number" value={activiteDuree} onChange={e => setActiviteDuree(Number(e.target.value))} />
</label>
<button type="button" onClick={addAcitivte}>Ajouter</button>
<ul>
{activities.map((act, idx) => (
<li key={idx}>{act.nom} - {act.theme} ({act.duree} min)</li>
))}
</ul>
<h2>Create Session</h2>
<label>
Name:
<input type="text" value={name} onChange={e => setName(e.target.value)} />
</label>
<label>
Groupe:
</label>
<label>
Creneau:
<input type="datetime-local" value={creneau} onChange={e => setCreneau(e.target.value)} />
</label>
<label>
Duree (minutes):
<input type="number" value={duree} onChange={e => setDuree(Number(e.target.value))} />
</label>
<label>
Recurrent:
<input type="checkbox" checked={isRecurent} onChange={e => setIsRecurent(e.target.checked)} />
</label>
<ul>
{activities.map((act, idx) => (
<li key={idx}>{act.nom} - {act.theme} ({act.duree} min)</li>
))}
</ul>
<button type="button" onClick={handleCreateSession}>Create Session</button>
<button type="button" onClick={handleCreateSession}>Create Session</button>
</div>
);
);
};
export default CreateSession;

View File

@@ -42,7 +42,7 @@ export const EDT =() =>{
var newWeek: Session[] = []
user.sessions.forEach(session => {
if((session.creneau >= date && session.creneau <= maxDate && !session.isRecurrent) || session.isRecurrent){
if((session.creneau >= date && session.creneau <= maxDate && !session.isRecurrent) || (session.isRecurrent && session.creneau<maxDate)){
newWeek.push(session);
}
});
@@ -121,7 +121,7 @@ export const EDT =() =>{
<button className="edt_button_week_select" onClick={() => handleNext()}>Next</button>
</div>
<div className="edt_colonnes">
<div className="edt_loading">{loading && <Loading/>}</div>
<div className="top_left_loading">{loading && <Loading/>}</div>
{week_days_nums.map((num,index)=>(
<div className="edt_colonne">
<div className="edt_day_header">

View File

@@ -6,6 +6,7 @@ import { Modal } from './Modal';
import Loading from './loading';
import {delay} from "../requetes";
import CreateActivite from './createActivite';
import DetailSession from './object/detailSession';
type Props = {
@@ -15,91 +16,24 @@ type Props = {
function EdtSession({session}:Props){
const [open, setOpen] = useState<boolean>(false);
const [open2, setOpen2] = useState<boolean>(false);
const [loading,setLoading] = useState<boolean>(false);
const [activites,setActivites] = useState<Activite[]>([]);
function handleOpen(): void {
setOpen(!open);
}
function handleDeleteActivite(activite:Activite): void {
session.activites.splice(session.activites.indexOf(activite), 1);
setActivites([...session.activites])
}
function handleAddActivite(): void {
setOpen2(true)
}
async function updateActivites(){
//TODO
await delay(2000);
//await updateActivitiesOfSessionAPI(session);
setLoading(false);
}
useEffect(() => {
if(open){
setLoading(true);
updateActivites()
}
},[open])
useEffect(() => {
if(!loading){
setActivites([...session.activites])
}
},[loading])
const sDate = session.creneau;
function returnActivite(activite: Activite|null){
if(activite!==null){
session.activites.push(activite);
setActivites([...session.activites])
}
setOpen2(false);
}
return(
<div>
<div className="edt_session" onClick={() => handleOpen()}>
<div className="edt_session_header">
<div className="edt_date">{hoursToString(sDate)}</div>
{session.isRecurrent && <div className="edt_date"> recurrent</div>}
</div>
<div>{session.name}</div>
<div className="edt_session_header">
<div className="edt_date">{hoursToString(sDate)}</div>
{session.isRecurrent && <div className="edt_date"> recurrent</div>}
</div>
<div>{session.name}</div>
</div>
{open &&
<Modal isOpen={open} onClose={() => setOpen(false)}>
<div className="edt_session_modal">
<div>{session.name}</div>
<div>{hoursToString(sDate)}</div>
<div>{dateToString(sDate)}</div>
<div>
Activités :
<div className="ent_activite_list">
{activites.map((activite,index)=>(
<div>
{activite.nom}
<button className="deleteButton" onClick={() => handleDeleteActivite(activite)}>x</button>
</div>
))}
<button className="addButton" onClick={() => handleAddActivite()}>+</button>
{loading && <div className='edt_loading'><Loading/></div>}
</div>
</div>
{open2 &&
<CreateActivite returnActivite={(activite) => returnActivite(activite)}/>
}
</div>
</Modal>
}
<DetailSession session={session} open={open} setOpen={setOpen}/>
</div>
)
}

View File

@@ -0,0 +1,93 @@
import { useEffect, useState } from "react";
import { Activite, Session } from "../../classes";
import { dateToString, hoursToString } from "../edt";
import { Modal } from "../Modal";
import CreateActivite from "../createActivite";
import Loading from "../loading";
import { delay } from "../../requetes";
type Props = {
session:Session;
open:boolean;
setOpen:(b:boolean)=>void
}
function DetailSession({session,open,setOpen}:Props){
const [activites,setActivites] = useState<Activite[]>([]);
const [open2, setOpen2] = useState<boolean>(false);
const [loading,setLoading] = useState<boolean>(false);
const sDate = session.creneau;
function handleDeleteActivite(activite:Activite): void {
session.activites.splice(session.activites.indexOf(activite), 1);
setActivites([...session.activites])
}
function handleAddActivite(): void {
setOpen2(true)
}
async function updateActivites(){
//TODO
await delay(2000);
//await updateActivitiesOfSessionAPI(session);
setLoading(false);
}
useEffect(() => {
if(open){
setLoading(true);
updateActivites()
}
},[open])
function returnActivite(activite: Activite|null){
if(activite!==null){
session.activites.push(activite);
setActivites([...session.activites])
}
setOpen2(false);
}
useEffect(() => {
if(!loading){
setActivites([...session.activites])
}
},[loading])
return(
<Modal isOpen={open} onClose={() => setOpen(false)}>
<div className="object_modal">
<div>{session.name}</div>
<div>{hoursToString(sDate)}</div>
<div>{dateToString(sDate)}</div>
<div>
Activités :
<div className="session_modal_activite_list">
{activites.map((activite,index)=>(
<div>
{activite.nom}
<button className="deleteButton" onClick={() => handleDeleteActivite(activite)}>x</button>
</div>
))}
<button className="addButton" onClick={() => handleAddActivite()}>+</button>
{loading && <div className='top_left_loading'><Loading/></div>}
</div>
</div>
{open2 &&
<CreateActivite returnActivite={(activite) => returnActivite(activite)}/>
}
</div>
</Modal>
)
}
export default DetailSession;

View File

@@ -0,0 +1,47 @@
import { useEffect, useState } from 'react';
import { Activite, Session } from '../../classes';
import { dateToString, hoursToString } from '../edt';
import '../style/objectList.css';
import { Modal } from '../Modal';
import Loading from '../loading';
import {delay} from "../../requetes";
import CreateActivite from '../createActivite';
import DetailSession from './detailSession';
type Props = {
session:Session;
}
function ObjectSession({session}:Props){
const [open, setOpen] = useState<boolean>(false);
function handleOpen(): void {
setOpen(!open);
}
const sDate = session.creneau;
return(
<div>
<div className="object" onClick={() => handleOpen()}>
<div className="object_header">
{session.isRecurrent ?
<div className="object_small"> Recurrent</div> :
<div className="object_small"> {dateToString(session.creneau)}</div>
}
<div className="object_small">{hoursToString(sDate)}</div>
</div>
<div>{session.name}</div>
<div>{session.groupe}</div>
<div>{session.coach ? session.coach.nom : "Pas de coach sur la séance"}</div>
{session.ligne ? session.ligne.map(ligne => ligne.nom).join(", ") : "Pas de ligne sur la séance"}
</div>
<DetailSession session={session} open={open} setOpen={setOpen}/>
</div>
)
}
export default ObjectSession

View File

@@ -0,0 +1,127 @@
import { useEffect, useState } from 'react';
import { Activite, Admin, Athlete, Coach, Session, User } from '../../classes';
import { dateToString, hoursToString } from '../edt';
import '../style/objectList.css';
import { Modal } from '../Modal';
import Loading from '../loading';
import {delay} from "../../requetes";
import CreateActivite from '../createActivite';
import { useLocalData } from '../../context/useLocalData';
import ObjectSession from './session';
type Props = {
admin?:Admin|null;
athlete?:Athlete|null;
coach?:Coach|null;
}
function ObjectUser({admin=null,athlete=null,coach=null}:Props){
const {user,setUser} = useLocalData()
const[user2,setUser2]= useState<User>(getUser());
const [open, setOpen] = useState<boolean>(false);
const [open2, setOpen2] = useState<boolean>(false);
const [loading,setLoading] = useState<boolean>(false);
const [sessions,setSessions] = useState<Session[]>([]);
function getUser(): User{
if(admin!=null) return admin;
if(athlete!=null) return athlete;
if(coach!=null) return coach;
else return new User();
}
function handleOpen(): void {
setOpen(!open);
}
function handleDeleteSession(session:Session): void {
if(athlete!==null){
athlete.sessions.splice(athlete.sessions.indexOf(session), 1);
setSessions([...athlete.sessions])
}
if(coach!==null){
coach.sessions.splice(coach.sessions.indexOf(session), 1);
setSessions([...coach.sessions])
}
}
function handleAddSession(): void {
if(athlete!==null){
setOpen2(true)
}
}
async function updateSession(){
if(athlete!==null){
//TODO
await delay(2000);
//await update ... (athlete);
setLoading(false);
}
}
useEffect(() => {
if(open){
setLoading(true);
updateSession()
}
},[open])
useEffect(() => {
if(!loading){
if(athlete!==null){
setSessions([...athlete.sessions])
}
if(coach!==null){
setSessions([...coach.sessions])
}
}
},[loading])
function returnSession(session: Session|null){
if(session!==null){
if(athlete!==null){
athlete.sessions.push(session);
setSessions([...athlete.sessions])
}
if(coach!==null){
coach.sessions.push(session);
setSessions([...coach.sessions])
}
}
setOpen2(false);
}
return(
<div>
<div className="object" onClick={() => handleOpen()}>
<div>{user2.nom} ({user2.role})</div>
{/* <div>{user2.role}</div> */}
</div>
{open &&
<Modal isOpen={open} onClose={() => setOpen(false)}>
<div className="object_modal">
<div>{user2.nom} ({user2.role})</div>
<div>{user2.email}</div>
<div className='list_object'>
<div>Sessions :</div>
{user.sessions.map((session,index)=>(
<ObjectSession session={session}/>
))}
</div>
</div>
</Modal>
}
</div>
)
}
export default ObjectUser

View File

@@ -1,4 +1,5 @@
import { Athlete, Activite, Coach, Session, Ligne } from "../classes";
import ObjectSession from "./object/session";
type AthleteListProps = { athletes: Athlete[] };
type ActiviteListProps = { activites: Activite[] };
@@ -6,6 +7,9 @@ type CoachListProps = { coachs: Coach[] };
type SessionListProps = { sessions: Session[]};
type LigneListProps = { lignes: Ligne[]};
function AthleteList({ athletes }: AthleteListProps) {
return (
<ul className="AthleteList">
@@ -56,28 +60,12 @@ function CoachList({ coachs }: CoachListProps) {
function SessionList({ sessions }: SessionListProps) {
return (
<ul className="SessionList">
{sessions.map((sessions) => (
<li key={sessions.id}>
<div>
<strong>Nom:</strong> {sessions.name}
</div>
<div>
<strong>Groupe:</strong> {sessions.groupe}
</div>
<div>
<strong>Recurrent:</strong> {sessions.isRecurrent ? "Oui" : "Non"}
</div>
<div>
<strong>Coach:</strong> {sessions.coach ? sessions.coach.nom : "Pas de coach sur la séance"}
</div>
<div>
<strong>Ligne:</strong> {sessions.ligne ? sessions.ligne.map(ligne => ligne.nom).join(", ") : "Pas de ligne sur la séance"}
</div>
</li>
<div className="list_object">
{sessions.map((session) => (
<ObjectSession session={session}/>
))}
</ul>
</div>
);
}

View File

@@ -3,6 +3,8 @@
import { AthleteList, ActiviteList, CoachList, SessionList, LigneList} from "./ressourceList";
import { Activite, Athlete, Coach , Session, Ligne } from "../classes";
import { keyboard } from "@testing-library/user-event/dist/keyboard";
import ObjectSession from "./object/session";
import ObjectUser from "./object/user";
export type keyWord = "athletes" | "activites" | "coachs" | "sessions"| "lignes";
@@ -54,8 +56,6 @@ import { keyboard } from "@testing-library/user-event/dist/keyboard";
const allLignes: Ligne[] = Array.from(ligneMap.values());
return (
<div className="ressource_panel">
<div>
@@ -74,43 +74,36 @@ import { keyboard } from "@testing-library/user-event/dist/keyboard";
</select>
{value==="athletes" && (
<div className="edt_athletes_panel">
<h3>Liste des athlètes</h3>
<AthleteList athletes={allAthletes} />
</div>
)}
{value==="activites" && (
<div className="edt_activites_panel">
<h3>Liste des activités</h3>
<ActiviteList activites={allActivites} />
</div>
)}
{value==="coachs" && (
<div className="edt_coachs_panel">
<h3>Liste des coachs</h3>
<CoachList coachs={allCoachs} />
</div>
)}
{value==="sessions" && (
<div className="edt_sessions_panel">
<h3>Liste des sessions</h3>
<SessionList sessions={allSessions} />
</div>
)}
{value==="lignes" && (
<div className="edt_lignes_panel">
<h3>Liste des lignes</h3>
<LigneList lignes={allLignes} />
</div>
)}
<div className="edt_sessions_panel">
<h3>Liste des {value}</h3>
<div className="list_object">
{value==="athletes" && (
allAthletes.map((athlete) => ( //TODO
<ObjectUser athlete={athlete}/>
))
)}
{value==="activites" && (
allSessions.map((session) => ( //TODO
<ObjectSession session={session}/>
))
)}
{value==="coachs" && (
allSessions.map((session) => ( //TODO
<ObjectSession session={session}/>
))
)}
{value==="sessions" && (
allSessions.map((session) => (
<ObjectSession session={session}/>
))
)}
{value==="lignes" && (
allSessions.map((session) => ( //TODO
<ObjectSession session={session}/>
))
)}
</div>
</div>
</div>
);
}

View File

@@ -109,16 +109,6 @@
border-radius: 10px;
}
.deleteButton{
background-color: #FF0000;
border-color: #AA0000;
border-radius: 10px;
}
.addButton{
background-color: var(--tint5);
border-radius: 10px;
}
.edt_activite_modal{
background-color: var(--tint3);

View File

@@ -0,0 +1,52 @@
.list_object{
display: grid;
gap:10px;
background-color: var(--tint1);
padding: 10px;
border-radius: 20px;
}
.object {
font-size: clamp(1px, 8cqi, 18px);
gap: 8px;
background-color: var(--tint3);
border-radius: 12px;
padding: 10px;
min-width: 0;
}
.object:hover {
background-color: var(--tint2);
}
.object:active {
background-color: var(--tint4);
}
.object_header{
display: flex;
gap: 5px;
}
.object_small{
font-size: 0.75em;
}
.object_modal{
background-color: var(--tint2);
padding: 10px;
border-radius: 20px;
position: relative;
}
.session_modal_activite_list{
padding: 10px;
background-color: var(--tint3);
border-radius: 10px;
}
.create_activite_modal{
background-color: var(--tint3);
padding: 10px;
border-radius: 20px;
position: relative;
}

View File

@@ -76,9 +76,35 @@ input{
button{
color: var(--text);
background-color: var(--tint3);
border-radius: 8px;
}
select{
color: var(--text);
background-color: var(--tint3);
border-radius: 8px;
}
.deleteButton{
background-color: #FF0000;
border-color: #AA0000;
border-radius: 10px;
}
.addButton{
background-color: var(--tint5);
border-radius: 10px;
}
.top_left_loading{
position: absolute;
inset: 0;
pointer-events: none;
}
.center_loading{
position: absolute;
inset: 0;
place-items: center;
pointer-events: none;
}

View File

@@ -1,4 +1,4 @@
import api from "./api";
import api, { activiteService, sessionService } from "./api";
import { Activite, Admin, Athlete, Coach, Session, User } from "./classes";
//debug:
@@ -115,6 +115,38 @@ export async function postAthlete(athlete: Athlete):Promise<Athlete>{
}
}
export async function postSession(session: Session){
try {
const data = {
name: session.name,
creneau: session.creneau, // string ISO OK
duree: session.duree,
isRecurrent: session.isRecurrent,
coachId: session.coach?.id,
groupe: session.groupe ? session.groupe : undefined,
}
const response = await sessionService.create(data);
session.id = response.data.id; //TODO ?
session.activites.forEach(activite => {
const data2 = {
name: activite.nom,
duree: activite.duree,
date: activite.data,
theme: activite.theme,
sessionId: session.id, //TODO
}
activiteService.create(data2);
// console.log("Session créée");
});
} catch (error) {
console.error("Error post Session:", error);
throw error;
}
}
export async function postAdmin(athlete: Admin):Promise<Admin>{
try {
const response = await api.post<Admin>("/admin/create/",athlete);