diff --git a/back_end/src/main/java/hackathon/FrisbYEE/jpa/dto/AdminDTO.java b/back_end/src/main/java/hackathon/FrisbYEE/jpa/dto/AdminDTO.java index 30bac97..3d11a1f 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/jpa/dto/AdminDTO.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/jpa/dto/AdminDTO.java @@ -1,12 +1,10 @@ package hackathon.FrisbYEE.jpa.dto; -import hackathon.FrisbYEE.jpa.metier.Role; import lombok.Data; @Data public class AdminDTO { - private String id_keycloak; private Integer id; + private String id_keycloak; private String name; private String prenom; - private Role role; } diff --git a/back_end/src/main/java/hackathon/FrisbYEE/rest/AdminResource.java b/back_end/src/main/java/hackathon/FrisbYEE/rest/AdminResource.java index 2a47a97..e5d1e4c 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/rest/AdminResource.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/rest/AdminResource.java @@ -3,17 +3,12 @@ package hackathon.FrisbYEE.rest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import hackathon.FrisbYEE.jpa.dto.AdminDTO; import hackathon.FrisbYEE.jpa.metier.Admin; import hackathon.FrisbYEE.jpa.service.AdminDAO; -import io.swagger.v3.oas.annotations.parameters.RequestBody; +import hackathon.FrisbYEE.jpa.service.UserDAO; @RestController @RequestMapping("/admin") @@ -22,12 +17,24 @@ public class AdminResource { @Autowired private AdminDAO adminDAO; + @Autowired + private UserDAO userDAO; @PostMapping("/create") - @PreAuthorize("hasRole('Admin')") // Only admin can create + @PreAuthorize("hasRole('admin')") // Only admin can create public ResponseEntity create(@RequestBody AdminDTO dto) { + + userDAO.findByKeycloakId(dto.getId_keycloak()) + .ifPresent(existing -> { + if (!(existing instanceof Admin)) { + userDAO.delete(existing); + userDAO.flush(); + } + }); + Admin admin = mapToEntity(dto); + if(adminDAO.findByKeycloakId(admin.getKeycloakId()).isPresent()) { return ResponseEntity.status(200).body(mapToDTO(adminDAO.findByKeycloakId(admin.getKeycloakId()).get())); } @@ -55,7 +62,6 @@ public class AdminResource { dto.setId_keycloak(admin.getKeycloakId()); dto.setName(admin.getName()); dto.setPrenom(admin.getPrenom()); - dto.setRole(admin.getRole()); return dto; } @@ -65,7 +71,7 @@ public class AdminResource { admin.setKeycloakId(dto.getId_keycloak()); admin.setName(dto.getName()); admin.setPrenom(dto.getPrenom()); - admin.setRole(dto.getRole()); + admin.setRole(hackathon.FrisbYEE.jpa.metier.Role.admin); return admin; } diff --git a/back_end/src/main/java/hackathon/FrisbYEE/rest/CoachResource.java b/back_end/src/main/java/hackathon/FrisbYEE/rest/CoachResource.java index 6e22191..2537e0d 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/rest/CoachResource.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/rest/CoachResource.java @@ -1,8 +1,11 @@ package hackathon.FrisbYEE.rest; import hackathon.FrisbYEE.jpa.dto.CoachDTO; +import hackathon.FrisbYEE.jpa.metier.Admin; import hackathon.FrisbYEE.jpa.metier.Coach; import hackathon.FrisbYEE.jpa.service.CoachDAO; +import hackathon.FrisbYEE.jpa.service.UserDAO; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -17,13 +20,26 @@ import java.util.List; @RestController @RequestMapping("/coach") public class CoachResource { + @Autowired private CoachDAO coachDAO; + @Autowired + private UserDAO userDAO; @PostMapping("/create") - @PreAuthorize("hasRole('Admin')") // Only admin can create + @PreAuthorize("hasRole('admin') or hasRole('coach')") // Only admin can create public ResponseEntity create(@RequestBody CoachDTO dto) { + + userDAO.findByKeycloakId(dto.getId_keycloak()) + .ifPresent(existing -> { + if (!(existing instanceof Coach)) { + userDAO.delete(existing); + userDAO.flush(); + } + }); + Coach coach = mapToEntity(dto); + if(coachDAO.existsByKeycloakId(coach.getKeycloakId())) { return ResponseEntity.status(200).body(mapToDTO(coachDAO.findByKeycloakId(coach.getKeycloakId()).get())); } 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..5c095be 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java @@ -19,6 +19,7 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.server.ResponseStatusException; +import java.time.LocalDate; import java.util.ArrayList; import java.util.List; @@ -69,6 +70,30 @@ public class SessionResource { return ResponseEntity.ok(dtos); } + @GetMapping("/all-between-dates") + @PreAuthorize("hasRole('admin') or hasRole('coach') or hasRole('athlete')") + public ResponseEntity> getAllBetweenDates( + @RequestParam LocalDate startDate, + @RequestParam LocalDate endDate + ) { + List sessions = sessionDAO.findAll(); + List dtos = new ArrayList<>(); + System.out.println("date : " + startDate + " " + endDate); + for (Session session : sessions) { + LocalDate sessionDate = session.getCreneau().toLocalDate(); + + boolean isBetween = + (!sessionDate.isBefore(startDate) || session.getIsRecurrent()) && + !sessionDate.isAfter(endDate); + + if (isBetween) { + dtos.add(maptoDTO(session)); + } + } + + return ResponseEntity.ok(dtos); + } + @GetMapping("/{id}") @PreAuthorize("hasRole('coach') or hasRole('athlete')") public ResponseEntity getById(@PathVariable Integer id) { diff --git a/front_end/src/api.ts b/front_end/src/api.ts index b57e12c..95c7de5 100644 --- a/front_end/src/api.ts +++ b/front_end/src/api.ts @@ -62,11 +62,16 @@ export const activiteService = { getByTheme: (theme: string) => api.get(`/activite/theme/${encodeURIComponent(theme)}`), getDataActivite: (id: number | string) => api.get(`/activite/${id}`), }; +type DateBetween = { + startDate: string; + endDate: string; +} export const sessionService = { // controller uses singular /session/* endpoints - create: (data: any) => api.post(`/session/create`, data), + create: (data: SessionDTO) => api.post(`/session/create`, data), getAll: () => api.get(`/session/all`), + getAllBetweenDate: (data: any) => api.get(`/session/all-between-dates`,{params: data,}), getById: (id: number | null) => api.get(`/session/${id}`), delete: (id: number | null) => api.delete(`/session/delete/${id}`), update: (id: number | null, data: any) => api.put(`/session/update/${id}`, data), @@ -79,7 +84,7 @@ export const sessionService = { export const coachService = { // controller doesn't declare a class-level path consistently; support both common patterns - create: (data: any) => api.post(`/coach/create`, data), + create: (data: CoachDTO) => api.post(`/coach/create`, data), getAll: () => api.get(`/coach/all`), getById: (id: number) => api.get(`/coach/${id}`), getByKeycloakId: (keycloakId: string) => api.get(`/coach/keycloak/${keycloakId}`), @@ -97,7 +102,8 @@ export const userService = { export const adminService = { getByKeycloakId: (keycloak_id: string) => api.get(`/admin/keycloak/${keycloak_id}`), - getById: (id: number | string) => api.get(`/admin/${id}`), + getById: (id: number | string) => api.get(`/admin/${id}`), + create: (data: AdminDTO) => api.post("/admin/create", data), }; export default api; \ No newline at end of file diff --git a/front_end/src/classes.tsx b/front_end/src/classes.tsx index b176e37..5cd3919 100644 --- a/front_end/src/classes.tsx +++ b/front_end/src/classes.tsx @@ -55,7 +55,7 @@ export class Athlete extends User{ constructor(dto?:AthleteDTO){ super(); - this.id = dto?.id ?? 0; + this.id = dto?.id ?? null; this.keycloakId = dto?.id_keycloak ?? ""; this.nom = dto?.name ?? ""; this.prenom = dto?.prenom ?? "" ; @@ -90,7 +90,7 @@ export class Coach extends User{ constructor(dto?:CoachDTO){ super(); - this.id = dto?.id ?? 0; + this.id = dto?.id ?? null; this.keycloakId = dto?.id_keycloak ?? ""; this.nom = dto?.name ?? ""; this.prenom = dto?.prenom ?? ""; diff --git a/front_end/src/components/createSession.tsx b/front_end/src/components/createSession.tsx index a4937ac..550d9f1 100644 --- a/front_end/src/components/createSession.tsx +++ b/front_end/src/components/createSession.tsx @@ -6,7 +6,7 @@ import { createSessionAPI, postSession } from "../requetes"; import './style/createSession.css'; export const CreateSession = () => { - const {user} = useLocalData(); + const {userLocal: user} = useLocalData(); const [session,setSession] = useState(new Session()); const [activities, setActivities] = useState([]); const [name,setName] = useState(""); diff --git a/front_end/src/components/edt.tsx b/front_end/src/components/edt.tsx index 18ad6e9..9dd0ce5 100644 --- a/front_end/src/components/edt.tsx +++ b/front_end/src/components/edt.tsx @@ -1,8 +1,8 @@ import { useEffect, useState } from "react" -import { Athlete, Coach, Session} from "../classes" +import { Admin, Athlete, Coach, Session} from "../classes" import { useLocalData } from "../context/useLocalData" import './style/edt.css'; -import {getSessionsOfUserAPI } from "../requetes"; +import {getAllSessionsAPI, getAllSessionsBetweenAPI, getSessionsOfUserAPI } from "../requetes"; import EdtSession from "./edt_session"; import {delay} from "../requetes"; import Loading from "./loading"; @@ -26,7 +26,8 @@ export function hoursToString(date:Date){ export const EDT =() =>{ - const {user,setUser} = useLocalData() + const {userLocal} = useLocalData() + const {sessionsLocal,setSessionsLocal} = useLocalData() const [sessions, setSessions] = useState([]) const [week,setWeek] = useState(getFirstDay(new Date())); const [loadedWeek,setLoadedWeek] = useState(null); @@ -35,12 +36,21 @@ export const EDT =() =>{ const week_days_nums:number[] = [1,2,3,4,5,6,0]; function loadSessions(date:Date){ - var maxDate = getNextDay(date,6) + var maxDate = toDateOnly(getNextDay(date,6)); var newWeek: Session[] = [] - if(user instanceof Athlete || user instanceof Coach){ - user.sessions.forEach(session => { - if((session.creneau >= date && session.creneau <= maxDate && !session.isRecurrent) || (session.isRecurrent && session.creneau { + const creneau = toDateOnly(session.creneau); + if((creneau >= date || session.isRecurrent) && (creneau <= maxDate)){ + newWeek.push(session); + } + }); + } + else if(userLocal instanceof Admin){ + sessionsLocal.forEach(session => { + const creneau = toDateOnly(session.creneau); + if((creneau >= date || session.isRecurrent) && (creneau <= maxDate)){ newWeek.push(session); } }); @@ -50,7 +60,7 @@ export const EDT =() =>{ } function changeWeek(date:Date){ - setWeek(date); + setWeek(toDateOnly(date)); } function isSameDay(date1:Date,date2:Date){ @@ -65,7 +75,7 @@ export const EDT =() =>{ updateWeek(week); loadSessions(week) setLoading(true); - },[week,user]) + },[week,userLocal]) useEffect(() => { if(loadedWeek!==null){ @@ -83,9 +93,22 @@ export const EDT =() =>{ //TODO updateSession //await delay(2000); //await updateSessionsOfUser(user,null,null); - if(user instanceof Athlete || user instanceof Coach){ - const newSessions:Session[] = await getSessionsOfUserAPI(user); - user.sessions = newSessions; + if(userLocal instanceof Athlete || userLocal instanceof Coach){ + const newSessions:Session[] = await getSessionsOfUserAPI(userLocal); + userLocal.sessions = newSessions; + } + else if(userLocal instanceof Admin){ + const newSessions:Session[] = await getAllSessionsBetweenAPI(week,getNextDay(week,6)); + const date = toDateOnly(week); + var maxDate = toDateOnly(getNextDay(date,6)); + sessionsLocal.forEach(sessionLocal => { //update seulement la semaine + const creneau = toDateOnly(sessionLocal.creneau); + if(!((creneau >= date || sessionLocal.isRecurrent) && (creneau <= maxDate))){ + newSessions.push(sessionLocal); + } + }); + + setSessionsLocal(newSessions); } setLoadedWeek(week); } @@ -108,7 +131,15 @@ export const EDT =() =>{ else{ firstDate = getNextDay(date,-numWeek+1); } - return firstDate; + return toDateOnly(firstDate); + } + + function toDateOnly(date: Date): Date { + return new Date( + date.getFullYear(), + date.getMonth(), + date.getDate() + ); } function getNextDay(date:Date,nb:number):Date{ diff --git a/front_end/src/components/login.tsx b/front_end/src/components/login.tsx index bc68a74..546dcc2 100644 --- a/front_end/src/components/login.tsx +++ b/front_end/src/components/login.tsx @@ -9,7 +9,7 @@ import { Modal } from './Modal'; import './style/topBar.css'; export const Login =() =>{ - const {user,setUser} = useLocalData() + const {userLocal: user,setUserLocal: setUser} = useLocalData() const { keycloak } = useKeycloak(); const [open,setOpen] = useState(false); diff --git a/front_end/src/components/object/detailSession.tsx b/front_end/src/components/object/detailSession.tsx index 5782390..5b79a7b 100644 --- a/front_end/src/components/object/detailSession.tsx +++ b/front_end/src/components/object/detailSession.tsx @@ -15,7 +15,7 @@ type Props = { function DetailSession({session,open,setOpen}:Props){ - const {user,setUser} = useLocalData() + const {userLocal: user,setUserLocal: setUser} = useLocalData() const [activites,setActivites] = useState([]); const [open2, setOpen2] = useState(false); diff --git a/front_end/src/components/object/user.tsx b/front_end/src/components/object/user.tsx index 5408acf..149f003 100644 --- a/front_end/src/components/object/user.tsx +++ b/front_end/src/components/object/user.tsx @@ -104,6 +104,9 @@ function ObjectUser({user}:Props){
{user.prenom}
{user.nom}
+ {user instanceof Athlete &&
Role : Athlete
} + {user instanceof Coach &&
Role : Coach
} + {user instanceof Admin &&
Role : Admin
} {(user instanceof Athlete || user instanceof Coach) &&
diff --git a/front_end/src/components/ressourcePanel.tsx b/front_end/src/components/ressourcePanel.tsx index 8216402..c7da4d3 100644 --- a/front_end/src/components/ressourcePanel.tsx +++ b/front_end/src/components/ressourcePanel.tsx @@ -15,7 +15,7 @@ import ObjectLigne from "./object/lignes"; export default function RessourcePanel() { const { keycloak } = useKeycloak(); - const { user } = useLocalData(); + const { userLocal: user } = useLocalData(); //const user = getUserTest(); //TODO const [value,setValue] = useState("sessions"); diff --git a/front_end/src/context/LocalDataContext.tsx b/front_end/src/context/LocalDataContext.tsx index 296753f..8d9ee70 100644 --- a/front_end/src/context/LocalDataContext.tsx +++ b/front_end/src/context/LocalDataContext.tsx @@ -2,12 +2,10 @@ import { createContext } from 'react' import { Session, User } from '../classes'; interface LocalDataContextType { - user:User; - setUser: React.Dispatch> - sessions: Session[]; - setSessions: React.Dispatch> - users: User[]; - setUsers: React.Dispatch> + userLocal:User; + setUserLocal: React.Dispatch> + sessionsLocal: Session[]; + setSessionsLocal: React.Dispatch> } diff --git a/front_end/src/provider/LocalDataProvider.tsx b/front_end/src/provider/LocalDataProvider.tsx index a5682a9..53e8da8 100644 --- a/front_end/src/provider/LocalDataProvider.tsx +++ b/front_end/src/provider/LocalDataProvider.tsx @@ -3,15 +3,14 @@ import { Session, User } from '../classes' import { LocalDataContext } from '../context/LocalDataContext' export const LocalDataProvider = ({ children }: { children: React.ReactNode }) => { - const [user, setUser] = useState(new User()) - const [sessions, setSessions] = useState([]) - const [users, setUsers] = useState([]) + const [userLocal, setUserLocal] = useState(new User()) + const [sessionsLocal, setSessionsLocal] = useState([]) return ( + value={{ userLocal, setUserLocal, sessionsLocal,setSessionsLocal}}> {children} ) diff --git a/front_end/src/requetes.tsx b/front_end/src/requetes.tsx index e36b6f2..092b836 100644 --- a/front_end/src/requetes.tsx +++ b/front_end/src/requetes.tsx @@ -1,4 +1,4 @@ -import api, { activiteService, athleteService, coachService, sessionService } from "./api"; +import api, { activiteService, adminService, athleteService, coachService, sessionService } from "./api"; import { Activite, Admin, Athlete, Coach, Session, User } from "./classes"; import Keycloak from 'keycloak-js' import { AdminDTO, AthleteDTO, CoachDTO, SessionDTO } from "./classesDTO"; @@ -27,7 +27,9 @@ export async function loginOrRegister(keycloak:Keycloak): Promise{ newAdmin.email = keycloak.tokenParsed.email || ""; newAdmin.nom = keycloak.tokenParsed.family_name || ""; newAdmin.prenom = keycloak.tokenParsed.given_name || ""; - const response = await athleteService.create(newAdmin.toDTO()); + console.log(newAdmin.keycloakId); + console.log(newAdmin.toDTO().id_keycloak); + const response = await adminService.create(newAdmin.toDTO()); const admin = new Admin(response.data); return admin; } @@ -217,7 +219,7 @@ export async function postAthlete(athlete: Athlete):Promise{ export async function postSession(session: Session){ try { - const data = { + /* const data = { name: session.name, creneau: session.creneau, // string ISO OK duree: session.duree, @@ -225,9 +227,9 @@ export async function postSession(session: Session){ coachId: session.coach?.id, groupe: session.groupe ? session.groupe : undefined, - } + }*/ - const response = await sessionService.create(data); + const response = await sessionService.create(session.toDTO()); session.id = response.data.id; //TODO ? session.activites.forEach(activite => { @@ -331,6 +333,44 @@ export async function getAllSessionsAPI():Promise{ } } + +function formatDateLocal(date: Date): string { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + + return `${year}-${month}-${day}`; +} + + +export async function getAllSessionsBetweenAPI(d1:Date,d2:Date):Promise{ + try { + const data = { + startDate: formatDateLocal(d1), + endDate: formatDateLocal(d2) + } + console.log(d1 + " " + d2); + console.log(data); + const response = await sessionService.getAllBetweenDate(data); + const sessions = await Promise.all( + response.data.map(async sessionDTO => { + const session = new Session(sessionDTO); + const coach = await getCoachByIdAPI(sessionDTO.coachId); + + if (coach != null) { + session.coach = coach; + } + return session; + }) + ); + + return sessions; + } catch (error) { + console.error("Error fetching sessions:", error); + throw error; + } +} + //COACH export async function getAllCoach(): Promise { try { diff --git a/keycloak/themes/frisbyee/login/resources/css/styles.css b/keycloak/themes/frisbyee/login/resources/css/styles.css index 5294378..71bb2a7 100644 --- a/keycloak/themes/frisbyee/login/resources/css/styles.css +++ b/keycloak/themes/frisbyee/login/resources/css/styles.css @@ -30,6 +30,8 @@ background-color: rgba(255, 255, 255, 0.98); overflow: hidden; transition: transform 0.3s ease; + width: fit-content; + margin: 0 auto; } .card-pf:hover { @@ -38,6 +40,7 @@ 0 8px 20px rgba(16, 185, 129, 0.15); } + /* Header de la card */ #kc-form-login .card-pf h1, .login-pf-page h1 {