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/AthleteResource.java b/back_end/src/main/java/hackathon/FrisbYEE/rest/AthleteResource.java index 61189c4..dd675b3 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/rest/AthleteResource.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/rest/AthleteResource.java @@ -163,7 +163,7 @@ public class AthleteResource { @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Récupération effectuée", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SessionDTO.class))) }) - @GetMapping("/athlete/{athleteId}/session") + @GetMapping("/{athleteId}/session") public List getSessionsAthlete(@PathVariable Integer athleteId) { Optional athleteOpt = athleteDAO.findById(athleteId); if (athleteOpt.isEmpty()) { @@ -174,30 +174,32 @@ public class AthleteResource { 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); + if (s.getAthletes().contains(athlete.get())) { + SessionDTO dto = new SessionDTO(); - List activiteIDs = new ArrayList<>(); - for (Activite activite : s.getActivites()) { - activiteIDs.add(activite.getId()); + 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 athlete2 : s.getAthletes()) { + athleteIds.add(athlete2.getId()); + } + dto.setAthleteIds(athleteIds); + + // Map other fields as necessary + athleteSessions.add(dto); } - dto.setActiviteIds(activiteIDs); - - List athleteIds = new ArrayList<>(); - for (Athlete a : s.getAthletes()) { - athleteIds.add(a.getId()); - } - dto.setAthleteIds(athleteIds); - - athleteSessions.add(dto); } - + System.out.println(athlete); return athleteSessions; } 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..69146bd 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,16 @@ package hackathon.FrisbYEE.rest; import hackathon.FrisbYEE.jpa.dto.CoachDTO; +import hackathon.FrisbYEE.jpa.dto.SessionDTO; +import hackathon.FrisbYEE.jpa.metier.Activite; +import hackathon.FrisbYEE.jpa.metier.Admin; +import hackathon.FrisbYEE.jpa.metier.Athlete; import hackathon.FrisbYEE.jpa.metier.Coach; +import hackathon.FrisbYEE.jpa.metier.Session; import hackathon.FrisbYEE.jpa.service.CoachDAO; +import hackathon.FrisbYEE.jpa.service.SessionDAO; +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 +25,28 @@ import java.util.List; @RestController @RequestMapping("/coach") public class CoachResource { + @Autowired private CoachDAO coachDAO; + @Autowired + private UserDAO userDAO; + @Autowired + private SessionDAO sessionDAO; @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())); } @@ -72,11 +95,38 @@ public class CoachResource { @GetMapping("/{id}/session") @PreAuthorize("hasRole('Admin') or hasRole('Coach')") - public ResponseEntity> getSessionsForCoach(@PathVariable Integer id) { + public ResponseEntity> getSessionsForCoach(@PathVariable Integer id) { Coach coach = coachDAO.findById(id) .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Coach not found")); - List sessions = coach.getSessions(); - return ResponseEntity.ok(sessions); + List sessions = sessionDAO.findAll(); + List coachSessions = new ArrayList<>(); + for (Session s : sessions) { + if (s.getCoach().equals(coach)) { + 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 + coachSessions.add(dto); + } + } + return ResponseEntity.ok(coachSessions); } @DeleteMapping("/delete/{id}") 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 736037c..1568e8d 100644 --- a/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java +++ b/back_end/src/main/java/hackathon/FrisbYEE/rest/SessionResource.java @@ -1,6 +1,7 @@ package hackathon.FrisbYEE.rest; import hackathon.FrisbYEE.jpa.dto.ActiviteDTO; +import hackathon.FrisbYEE.jpa.dto.CoachDTO; import hackathon.FrisbYEE.jpa.dto.SessionDTO; import hackathon.FrisbYEE.jpa.metier.Activite; import hackathon.FrisbYEE.jpa.metier.Athlete; @@ -19,6 +20,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; @@ -74,6 +76,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) { @@ -150,6 +176,29 @@ public class SessionResource { return ResponseEntity.noContent().build(); } + @GetMapping("/{id}/coach") + @PreAuthorize("hasRole('coach') or hasRole('athlete')") + public ResponseEntity getCoachBySessionId(@PathVariable Integer id) { + try { + Session session = sessionDAO.findById(id).orElseThrow(); + Coach coach = session.getCoach(); + + CoachDTO dto = new CoachDTO(); + dto.setId(coach.getId()); + dto.setName(coach.getName()); + dto.setPrenom(coach.getPrenom()); + List listSession = new ArrayList(); + for (Session s : coach.getSessions()) { + listSession.add(session.getId()); + } + dto.setSessionIds(listSession); + + return ResponseEntity.ok(dto); + } catch (Exception ex) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new CoachDTO()); + } + } + @GetMapping("/{id}/activities") @PreAuthorize("hasRole('coach') or hasRole('athlete')") diff --git a/front_end/package-lock.json b/front_end/package-lock.json index 9cd9e01..bd0d3df 100644 --- a/front_end/package-lock.json +++ b/front_end/package-lock.json @@ -20,9 +20,10 @@ "axios": "^1.13.2", "bootstrap": "^5.3.8", "keycloak-js": "^26.2.2", - "react": "^19.2.3", + "react": "18.2.0", "react-bootstrap": "^2.10.10", - "react-dom": "^19.2.3", + "react-dom": "18.2.0", + "react-router-dom": "^7.12.0", "react-scripts": "5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" @@ -74,6 +75,7 @@ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -723,6 +725,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1606,6 +1609,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.27.1", "@babel/helper-module-imports": "^7.27.1", @@ -2987,6 +2991,7 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/popperjs" @@ -3465,6 +3470,7 @@ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -3850,6 +3856,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -3859,6 +3866,7 @@ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -3988,6 +3996,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -4041,6 +4050,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -4410,6 +4420,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4508,6 +4519,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -5447,6 +5459,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -7302,6 +7315,7 @@ "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -10066,6 +10080,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^27.5.1", "import-local": "^3.0.2", @@ -10963,6 +10978,7 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", "license": "MIT", + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -11166,6 +11182,7 @@ "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.2.tgz", "integrity": "sha512-ug7pNZ1xNkd7PPkerOJCEU2VnUhS7CYStDOCFJgqCNQ64h53ppxaKrh4iXH0xM8hFu5b1W6e6lsyYWqBMvaQFg==", "license": "Apache-2.0", + "peer": true, "workspaces": [ "test" ] @@ -12325,6 +12342,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -13459,6 +13477,7 @@ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", "license": "MIT", + "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -13833,10 +13852,14 @@ } }, "node_modules/react": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", - "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, "engines": { "node": ">=0.10.0" } @@ -13995,15 +14018,17 @@ } }, "node_modules/react-dom": { - "version": "19.2.3", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz", - "integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", "license": "MIT", + "peer": true, "dependencies": { - "scheduler": "^0.27.0" + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" }, "peerDependencies": { - "react": "^19.2.3" + "react": "^18.2.0" } }, "node_modules/react-error-overlay": { @@ -14035,10 +14060,62 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/react-router": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.12.0.tgz", + "integrity": "sha512-kTPDYPFzDVGIIGNLS5VJykK0HfHLY5MF3b+xj0/tTyNYL1gF1qs7u67Z9jEhQk2sQ98SUaHxlG31g1JtF7IfVw==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.12.0", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.12.0.tgz", + "integrity": "sha512-pfO9fiBcpEfX4Tx+iTYKDtPbrSLLCbwJ5EqP+SPYQu1VYCXdy79GSj0wttR0U4cikVdlImZuEZ/9ZNCgoaxwBA==", + "license": "MIT", + "dependencies": { + "react-router": "7.12.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router/node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/react-scripts": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", @@ -14497,6 +14574,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "license": "MIT", + "peer": true, "bin": { "rollup": "dist/bin/rollup" }, @@ -14710,10 +14788,13 @@ } }, "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } }, "node_modules/schema-utils": { "version": "4.3.3", @@ -14739,6 +14820,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -14940,6 +15022,12 @@ "node": ">= 0.8.0" } }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -15985,23 +16073,6 @@ } } }, - "node_modules/tailwindcss/node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/tapable": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", @@ -16219,6 +16290,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -16387,6 +16459,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "license": "(MIT OR CC0-1.0)", + "peer": true, "engines": { "node": ">=10" }, @@ -16495,6 +16568,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16833,6 +16907,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz", "integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==", "license": "MIT", + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -16904,6 +16979,7 @@ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "license": "MIT", + "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -17317,6 +17393,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/front_end/package.json b/front_end/package.json index 1b2e66e..7ac6bbf 100644 --- a/front_end/package.json +++ b/front_end/package.json @@ -15,9 +15,10 @@ "axios": "^1.13.2", "bootstrap": "^5.3.8", "keycloak-js": "^26.2.2", - "react": "^19.2.3", + "react": "18.2.0", "react-bootstrap": "^2.10.10", - "react-dom": "^19.2.3", + "react-dom": "18.2.0", + "react-router-dom": "^7.12.0", "react-scripts": "5.0.1", "typescript": "^4.9.5", "web-vitals": "^2.1.4" diff --git a/front_end/src/App.css b/front_end/src/App.css index 4108493..97c164e 100644 --- a/front_end/src/App.css +++ b/front_end/src/App.css @@ -1,38 +1,52 @@ /* Variables de thème */ [data-theme='dark'] { - --tint0: #000000; - --tint1: #0b0c0e; - --tint2: #16181d; - --tint3: #21252b; - --tint4: #2c313a; - --tint5: #373d48; - --text: #FFFFFF; + --tint0: #0a0e27; + --tint1: #1a1f3a; + --tint2: #232d4a; + --tint3: #2e3a59; + --tint4: #3d4a6f; + --tint5: #4a5a85; + --text: #f0f4f8; --text2: #000000; --disable: #02291d; --green-primary: #10b981; --green-secondary: #059669; --green-dark: #047857; - --green-A-primary: #10b98120; - --green-A-secondary: #05966920; - --green-A-dark: #04785720; + --green-A-primary: #10b98130; + --green-A-secondary: #05966930; + --green-A-dark: #04785730; + --themeButtonColor: #00AAFF; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5); + --blue-accent: #3b82f6; + --purple-accent: #a78bfa; + --cyan-accent: #06b6d4; } [data-theme='light'] { - --tint0: #ffffff; - --tint1: #f4f1f1; - --tint2: #e8e4e3; - --tint3: #ddd6d5; - --tint4: #d2c8c6; - --tint5: #c6bab8; - --text: #000000; + --tint0: #f8fafc; + --tint1: #f1f5f9; + --tint2: #e2e8f0; + --tint3: #cbd5e1; + --tint4: #b0bac4; + --tint5: #94a3b8; + --text: #0f172a; --text2: #FFFFFF; --disable: #02291d; - --green-primary: #00ce89; - --green-secondary: #00a571; - --green-dark: #00825d; - --green-A-primary: #00ce8920; - --green-A-secondary: #00a57120; - --green-A-dark: #00825d20; + --green-primary: #10b981; + --green-secondary: #059669; + --green-dark: #047857; + --green-A-primary: #10b98125; + --green-A-secondary: #05966925; + --green-A-dark: #04785725; + --themeButtonColor: #f59e0b; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1); + --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.15); + --blue-accent: #3b82f6; + --purple-accent: #a855f7; + --cyan-accent: #06b6d4; } /* Reset et base */ @@ -42,19 +56,27 @@ padding: 0; } -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - background-color: var(--tint0); - color: var(--text); - transition: background-color 0.3s ease, color 0.3s ease; +html,body{ + width: 100%; + height: 100%; } -.padding{ +body { + margin: 0; + font-family: 'Inter', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Oxygen', + 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + background: linear-gradient(135deg, var(--tint0) 0%, var(--tint1) 100%); + height: 100%; + color: var(--text); + transition: background 0.4s ease, color 0.4s ease; + font-weight: 400; + line-height: 1.6; + background-attachment: fixed; +} + +.padding { padding: 10px } @@ -69,20 +91,47 @@ code { color: var(--green-primary); } +.App { + display: grid; + padding: 20px; + gap: 24px; + max-width: 1400px; + margin: 0 auto; +} + +.App h1 { + font-size: clamp(2rem, 5vw, 3.5rem); + font-weight: 700; + background: linear-gradient(135deg, var(--green-primary) 0%, var(--cyan-accent) 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + margin-bottom: 8px; + letter-spacing: -0.5px; +} + /* Container principal */ .app-container { min-height: 100vh; background: linear-gradient(180deg, var(--tint0) 0%, var(--tint1) 100%); } -.composant-container{ - background-color: var(--tint2); - border-radius: 30px; +.composant-padding { padding: 10px; - border: 2px solid var(--tint4); - box-shadow: 0 4px 6px rgba(16, 185, 129, 0.1); } +.composant-container { + display: grid; + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + border-radius: 24px; + padding: 24px; + border: 1px solid var(--tint4); + box-shadow: var(--shadow-lg); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + gap:15px; +} + + /* Header / Navigation */ .app-header { background-color: var(--tint1); @@ -122,18 +171,18 @@ code { /* Cards et containers */ .card { - background-color: var(--tint1); + background: linear-gradient(135deg, var(--tint1) 0%, var(--tint2) 100%); border-radius: 20px; - padding: 20px; - border: 2px solid var(--green-A-secondary); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); - transition: all 0.3s ease; + padding: 24px; + border: 1px solid var(--tint4); + box-shadow: var(--shadow-md); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .card:hover { border-color: var(--green-primary); - box-shadow: 0 6px 16px var(--green-A-primary); - transform: translateY(-2px); + box-shadow: 0 8px 24px var(--green-A-primary); + transform: translateY(-4px); } .card-header { @@ -159,20 +208,21 @@ input[type="time"], input[type="search"], input[type="datetime-local"], textarea { - background-color: var(--tint3); + background-color: var(--tint2); color: var(--text); - border: 2px solid var(--tint5); - border-radius: 8px; - padding: 10px 14px; - transition: all 0.3s ease; + border: 1px solid var(--tint4); + border-radius: 12px; + padding: 12px 14px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); font-size: 15px; + font-family: inherit; } input:focus, textarea:focus { outline: none; border-color: var(--green-primary); - background-color: var(--tint3); + background-color: var(--tint1); box-shadow: 0 0 0 3px var(--green-A-primary); } @@ -215,23 +265,29 @@ select option { /* Buttons */ button { color: var(--text); - background-color: var(--tint3); - border: 2px solid var(--tint5); - border-radius: 8px; - padding: 5px 10px; + background: linear-gradient(135deg, var(--tint3) 0%, var(--tint4) 100%); + border: 1px solid var(--tint4); + border-radius: 12px; + padding: 10px 16px; cursor: pointer; - transition: all 0.3s ease; - font-weight: 500; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + font-weight: 600; font-size: 14px; display: inline-block; width: auto; + box-shadow: var(--shadow-sm); } button:hover { - background-color: var(--tint4); + background: linear-gradient(135deg, var(--green-primary) 0%, var(--green-secondary) 100%); border-color: var(--green-primary); + color: white; transform: translateY(-2px); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); + box-shadow: 0 6px 20px var(--green-A-primary); +} + +button:active { + transform: translateY(0); } button:active { @@ -278,7 +334,7 @@ button.secondary:hover { .deleteButton, button.delete, .btn-danger { - background-color: #dc2626; + background: #dc2626; border: 2px solid #991b1b; border-radius: 10px; color: white; @@ -287,7 +343,7 @@ button.delete, .deleteButton:hover, button.delete:hover, .btn-danger:hover { - background-color: #b91c1c; + background: #b91c1c; border-color: #7f1d1d; } @@ -295,7 +351,7 @@ button.delete:hover, .addButton, button.add, .btn-success { - background-color: var(--green-primary); + background: var(--green-primary); border: none; border-radius: 10px; color: white; @@ -418,7 +474,8 @@ td { /* Lists */ -ul, ol { +ul, +ol { color: var(--text); padding-left: 20px; } @@ -535,6 +592,7 @@ input[type="radio"] { from { opacity: 0; } + to { opacity: 1; } @@ -545,6 +603,7 @@ input[type="radio"] { opacity: 0; transform: translateY(20px); } + to { opacity: 1; transform: translateY(0); diff --git a/front_end/src/App.tsx b/front_end/src/App.tsx index 5e78330..7a81946 100644 --- a/front_end/src/App.tsx +++ b/front_end/src/App.tsx @@ -10,7 +10,13 @@ import CreateSession from './components/createSession' import EdtCoach from './components/edt_coach' import { Coach } from "./classes"; import RessourcePanel from './components/ressourcePanel'; -import TestAPI from './components/test_api'; +import TopBar from './components/topBar'; +import { Routes, Route } from 'react-router-dom' +import Home from './components/pages/pageHome'; +import SelectionSession from './components/pages/pageSectionSession'; +import Gestion from './components/pages/pageGestion'; +import Admin from './components/pages/pageAdmin'; + const keycloakInitOptions = { onLoad: 'login-required', @@ -22,13 +28,13 @@ function App() {
- -

Frisbyee

- - - - - + + + }/> + }/> + }/> + }/> +
diff --git a/front_end/src/api.ts b/front_end/src/api.ts index b57e12c..f87c7dd 100644 --- a/front_end/src/api.ts +++ b/front_end/src/api.ts @@ -45,7 +45,7 @@ export const athleteService = { delete: (id: number | string) => api.delete(`/athlete/${id}`), // session-related endpoints exposed by AthleteResource - getSessionsForAthlete: (athleteId: number | null) => api.get(`/athlete/athlete/${athleteId}/session`), + getSessionsForAthlete: (athleteId: number | null) => api.get(`/athlete/${athleteId}/session`), getAllSessions: () => api.get(`/athletes/session`), getActivitiesForSession: (sessionId: number | string) => api.get(`/athletes/session/${sessionId}/activities`), getSessionsAfterDate: (athleteId: number | string, date: string) => api.get(`/athletes/${athleteId}/session/after/${encodeURIComponent(date)}`), @@ -62,24 +62,30 @@ 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), getActivities: (sessionId: number | null) => api.get(`/session/${sessionId}/activities`), addActivity: (sessionId: number | null, activityId: number) => api.post(`/session/${sessionId}/activities/${activityId}`), + getCoach: (sessionId: number | null) => api.get(`/session/${sessionId}/coach`), subscribe: (sessionId: number | null, userId: number) => api.put(`/session/${sessionId}/subscribe/${userId}`), unsubscribe: (sessionId: number | null, userId: number) => api.put(`/session/${sessionId}/unsubscribe/${userId}`), }; 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 +103,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/SwitchThemeColor.tsx b/front_end/src/components/SwitchThemeColor.tsx index 6b92c37..913d2ed 100644 --- a/front_end/src/components/SwitchThemeColor.tsx +++ b/front_end/src/components/SwitchThemeColor.tsx @@ -1,5 +1,4 @@ import { useState,useEffect } from 'react'; -import './style/SwitchThemeColor.css'; const SwitchThemeColor = () => { 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..c2894a6 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{ @@ -139,7 +170,7 @@ export const EDT =() =>{
{loading && }
{week_days_nums.map((num,index)=>( -
+
{week_days[index]}
{dateToString(getNextDay(week,index))}
diff --git a/front_end/src/components/login.tsx b/front_end/src/components/login.tsx index 8f367f0..84c0843 100644 --- a/front_end/src/components/login.tsx +++ b/front_end/src/components/login.tsx @@ -1,49 +1,42 @@ import { useKeycloak } from '@react-keycloak/web' -import { useEffect } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { Admin, Athlete, Coach, User } from '../classes'; import { useLocalData } from '../context/useLocalData'; import { loginOrRegister, postAthlete } from '../requetes'; import { clearAuthToken, setAuthToken } from '../api'; import { AthleteDTO } from '../classesDTO'; +import { Modal } from './Modal'; +import './style/topBar.css'; export const Login =() =>{ - const {user,setUser} = useLocalData() + const ref = useRef(null); + const {userLocal: user,setUserLocal: setUser} = useLocalData() const { keycloak } = useKeycloak(); + const [open,setOpen] = useState(false); - /*useEffect(() => { - const syncAndLoadUser = async () => { - if (keycloak.authenticated && keycloak.token && keycloak.tokenParsed) { - try { - const newAthlete: Athlete = new Athlete(); - newAthlete.keycloakId = keycloak.tokenParsed.sub || ""; - newAthlete.email = keycloak.tokenParsed.email || ""; - newAthlete.nom = keycloak.tokenParsed.family_name || ""; - newAthlete.prenom = keycloak.tokenParsed.given_name || ""; - - setAuthToken(keycloak.token); - - const athlete: Athlete = await postAthlete(newAthlete); - setUser(athlete); - } catch (error) { - console.error("Error :", error); - } - } - }; + useEffect(() => { + const handleClickOutside = (e: MouseEvent) => { + if (ref.current && !ref.current.contains(e.target as Node)) { + setOpen(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + + return () => { + document.removeEventListener("mousedown", handleClickOutside); + }; + }, []); - syncAndLoadUser(); - }, [keycloak.authenticated, keycloak.token, setUser]); - */ async function loginUser(){ if(keycloak.authenticated){ setAuthToken(keycloak.token); - //alert("Connexion en cours : " + keycloak.tokenParsed?.sub + " " + keycloak.tokenParsed?.realm_access?.roles); const logedUser = await loginOrRegister(keycloak); console.log(logedUser); if(logedUser!==null){ setUser(logedUser); - // alert("Connexion avec succès ! " + keycloak.tokenParsed?.sub); } else{ alert("Erreur de connexion " + keycloak.tokenParsed?.sub + " " + keycloak.tokenParsed?.realm_access?.roles); @@ -63,37 +56,51 @@ export const Login =() =>{ keycloak.logout() setUser(new User()); clearAuthToken(); + setOpen(false); } + + function handleOpen(): void { + setOpen(!open); + } + + if(keycloak.authenticated){ return( -
-
- Etat : {keycloak.authenticated ? 'connecté' : 'non connecté'} +
+ + {open && +
+
+
+ Prenom : { user.prenom} +
+
+ Nom : { user.nom} +
+ {/*
Keycloak ID : { keycloak.tokenParsed?.sub}
*/} + {user instanceof Athlete &&
Role : Athlete
} + {user instanceof Coach &&
Role : Coach
} + {user instanceof Admin &&
Role : Admin
} + +
+ + +
+ }
- {keycloak.authenticated && + ) + } + else{ + return(
-
- Keycloak ID : { keycloak.tokenParsed?.sub} -
-
- Prenom : { user.prenom} -
-
- Nom : { user.nom} -
- {user instanceof Athlete &&
Role : Athlete
} - {user instanceof Coach &&
Role : Coach
} - {user instanceof Admin &&
Role : Admin
} - +
- } - - -
- ) + ) + } + } export default Login diff --git a/front_end/src/components/object/detailSession.tsx b/front_end/src/components/object/detailSession.tsx index c9df293..5408326 100644 --- a/front_end/src/components/object/detailSession.tsx +++ b/front_end/src/components/object/detailSession.tsx @@ -4,7 +4,7 @@ import { dateToString, hoursToString } from "../edt"; import { Modal } from "../Modal"; import CreateActivite from "../createActivite"; import Loading from "../loading"; -import { addActiviteToSession, createActivityAPI, delay, deletActiviteFromSession, getSessionOfActivite, subscribeSessionAPI, unsubscribeSessionAPI } from "../../requetes"; +import { addActiviteToSession, createActivityAPI, delay, deletActiviteFromSession, getCoachOfSession, getSessionOfActivite, subscribeSessionAPI, unsubscribeSessionAPI } from "../../requetes"; import { useLocalData } from "../../context/useLocalData"; type Props = { @@ -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); @@ -93,10 +93,13 @@ function DetailSession({session,open,setOpen}:Props){ return( setOpen(false)}> -
+

{session.name}

+
{hoursToString(sDate)}
{dateToString(sDate)}
+
encadré par :
+
{session.coach?.prenom} {session.coach?.nom}
{user instanceof Athlete &&
{user.sessions.includes(session) ? @@ -108,8 +111,8 @@ function DetailSession({session,open,setOpen}:Props){ Activités :
{activites.map((activite,index)=>( -
- {activite.nom} +
+ - {activite.nom} {canEdit && ( )} 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/pages/pageAdmin.tsx b/front_end/src/components/pages/pageAdmin.tsx new file mode 100644 index 0000000..62e4197 --- /dev/null +++ b/front_end/src/components/pages/pageAdmin.tsx @@ -0,0 +1,13 @@ +import CreateSession from "../createSession" +import TopBar from "../topBar" + +function Admin() { + return ( +
+

Admin

+ rien pour l'instant +
+ ) +} + +export default Admin \ No newline at end of file diff --git a/front_end/src/components/pages/pageGestion.tsx b/front_end/src/components/pages/pageGestion.tsx new file mode 100644 index 0000000..14762fa --- /dev/null +++ b/front_end/src/components/pages/pageGestion.tsx @@ -0,0 +1,13 @@ +import CreateSession from "../createSession" +import TopBar from "../topBar" + +function Gestion() { + return ( +
+

Gestion

+ +
+ ) +} + +export default Gestion \ No newline at end of file diff --git a/front_end/src/components/pages/pageHome.tsx b/front_end/src/components/pages/pageHome.tsx new file mode 100644 index 0000000..2acb75b --- /dev/null +++ b/front_end/src/components/pages/pageHome.tsx @@ -0,0 +1,13 @@ +import EDT from "../edt" +import TopBar from "../topBar" + +function Home() { + return ( +
+

Home

+ +
+ ) +} + +export default Home \ No newline at end of file diff --git a/front_end/src/components/pages/pageSectionSession.tsx b/front_end/src/components/pages/pageSectionSession.tsx new file mode 100644 index 0000000..571b627 --- /dev/null +++ b/front_end/src/components/pages/pageSectionSession.tsx @@ -0,0 +1,13 @@ +import RessourcePanel from "../ressourcePanel" +import TopBar from "../topBar" + +function SelectionSession() { + return ( +
+

Selection Session

+ +
+ ) +} + +export default SelectionSession \ No newline at end of file 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/components/style/SwitchThemeColor.css b/front_end/src/components/style/SwitchThemeColor.css deleted file mode 100644 index 0779267..0000000 --- a/front_end/src/components/style/SwitchThemeColor.css +++ /dev/null @@ -1,11 +0,0 @@ -.ButtonTheme{ - height: 35px; - width: 39px; - color: var(--text); - background-color: var(--tint3); - border-radius: 10px; - margin: 0px; - font-size: 20px; - display: inline; - border-color: var(--green-A-primary); -} diff --git a/front_end/src/components/style/createSession.css b/front_end/src/components/style/createSession.css index 89000af..f22eabf 100644 --- a/front_end/src/components/style/createSession.css +++ b/front_end/src/components/style/createSession.css @@ -1,5 +1,8 @@ -.createActivite{ - background: var(--tint1); - padding: 15px; - border-radius: 15px; -} \ No newline at end of file +.createActivite { + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + padding: 20px; + border-radius: 16px; + border: 1px solid var(--tint4); + box-shadow: var(--shadow-md); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} diff --git a/front_end/src/components/style/edt.css b/front_end/src/components/style/edt.css index 642b743..14a8f0c 100644 --- a/front_end/src/components/style/edt.css +++ b/front_end/src/components/style/edt.css @@ -1,17 +1,24 @@ -.edt{ - background-color: var(--tint2); - border-radius: 30px; - padding: 10px; - border: 2px solid var(--tint4); - box-shadow: 0 4px 6px rgba(16, 185, 129, 0.1); +.edt { + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + border-radius: 24px; + padding: 20px; + border: 1px solid var(--tint4); + box-shadow: var(--shadow-lg); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } -.edt_header{ +.edt:hover { + border-color: var(--green-primary); + box-shadow: 0 12px 40px var(--green-A-primary); +} + +.edt_header { justify-content: center; display: grid; grid-template-columns: repeat(3, 0.5fr); - padding-bottom: 10px; - gap: 5%; + padding-bottom: 16px; + gap: 12px; + margin-bottom: 12px; } .edt_colonnes { @@ -24,7 +31,7 @@ width: 100%; } -.edt_loading{ +.edt_loading { position: absolute; inset: 0; display: grid; @@ -32,31 +39,43 @@ } .edt_colonne { - display: grid; - background-color: var(--tint3); - border-radius: 20px; - container-type: inline-size; - transition: all 0.3s ease; + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint4) 100%); + border-radius: 16px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + height: 100%; + border: 1px solid var(--tint4); + padding: 12px; +} + +.edt_colonne.today { + background: linear-gradient(135deg, var(--tint1) 25%, var(--tint2) 100%); + border: 1px solid var(--green-primary); } -.edt_day_header{ +.edt_day_header { font-size: clamp(5px, 1vw, 18px); - padding: 8px; - border-radius: 20px; + padding: 12px; + border-radius: 12px; height: fit-content; text-align: center; font-size: 1em; - background: linear-gradient(135deg, var(--green-A-primary), var(--green-A-dark)); - font-weight: 600; + background: linear-gradient(135deg, var(--green-primary) 0%, var(--green-secondary) 100%); + font-weight: 700; + font-size: large; + color: white; + box-shadow: 0 4px 12px rgba(16, 185, 129, 0.3); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } -.today{ - background: linear-gradient(135deg, var(--green-primary), var(--green-dark)); +.edt_day_header.today { + background: linear-gradient(135deg, var(--green-dark) 0%, var(--cyan-accent) 100%); color: #FFFFFF; + box-shadow: 0 6px 20px var(--green-A-primary); + transform: scale(1.02); } -.edt_day_content{ +.edt_day_content { display: flex; flex-direction: column; gap: 8px; @@ -68,39 +87,39 @@ .edt_session { font-size: clamp(1px, 8cqi, 18px); gap: 8px; - background-color: var(--tint4); + background: linear-gradient(135deg, var(--tint4) 0%, var(--tint5) 100%); border-radius: 12px; - padding: 5%; + padding: 12px; min-width: 0; - border-left: 3px solid var(--green-primary); /* Accent vert à gauche */ - transition: all 0.3s ease; + border-left: 4px solid var(--green-primary); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); cursor: pointer; + box-shadow: var(--shadow-sm); } .edt_session:hover { - background-color: var(--tint2); - border-left-width: 5px; - transform: translateX(3px); - box-shadow: -2px 2px 8px var(--green-A-primary); + background: linear-gradient(135deg, var(--green-A-primary), var(--green-A-secondary)); + border-left-width: 6px; + transform: translateX(4px); + box-shadow: 0 8px 16px var(--green-A-primary); } .edt_session:active { - background-color: var(--tint5); transform: translateX(1px); } -.edt_session_header{ +.edt_session_header { display: flex; gap: 5px; } -.edt_date{ +.edt_date { font-size: 0.75em; font-weight: 500; } -.edt_button_week_select{ - background: linear-gradient(135deg, var(--green-primary), var( --green-secondary)); +.edt_button_week_select { + background: linear-gradient(135deg, var(--green-primary), var(--green-secondary)); color: white; height: 40px; border-radius: 20px; @@ -123,7 +142,7 @@ box-shadow: 0 1px 2px var(--green-A-primary); } -.edt_session_modal{ +.edt_session_modal { background-color: var(--tint2); padding: 10px; border-radius: 20px; @@ -132,14 +151,14 @@ box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1), 0 0 0 1px var(--green-A-primary); } -.ent_activite_list{ +.ent_activite_list { padding: 10px; background-color: var(--tint3); border-radius: 10px; border: 1px solid var(--green-A-primary); } -.edt_activite_modal{ +.edt_activite_modal { background-color: var(--tint3); padding: 10px; border-radius: 20px; diff --git a/front_end/src/components/style/objectList.css b/front_end/src/components/style/objectList.css index 09028d3..be7fdaf 100644 --- a/front_end/src/components/style/objectList.css +++ b/front_end/src/components/style/objectList.css @@ -1,58 +1,81 @@ .list_object{ display: grid; - gap:10px; - background-color: var(--tint1); - padding: 10px; - border-radius: 20px; + gap: 12px; + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + padding: 16px; + border-radius: 16px; + border: 1px solid var(--tint4); + box-shadow: var(--shadow-md); } .list_object_modal{ display: grid; - gap:10px; - background-color: var(--tint1); - padding: 10px; - border-radius: 20px; - max-height: 200px; + gap: 12px; + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + padding: 16px; + border-radius: 16px; + max-height: 280px; overflow-y: auto; + border: 1px solid var(--tint4); } .object { - font-size: clamp(1px, 8cqi, 18px); gap: 8px; - background-color: var(--tint3); + background: linear-gradient(135deg, var(--tint3) 0%, var(--tint4) 100%); border-radius: 12px; - padding: 10px; + padding: 12px; min-width: 0; - border: 2px solid; - border-color: var(--tint3); + border: 1px solid var(--tint4); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + box-shadow: var(--shadow-sm); } + .object:hover { - background-color: var(--tint2); + background: linear-gradient(135deg, var(--green-A-primary), var(--green-A-secondary)); border-color: var(--green-primary); + transform: translateY(-2px); + box-shadow: 0 8px 16px var(--green-A-primary); } .object:active { - background-color: var(--tint4); + background: linear-gradient(135deg, var(--tint4) 0%, var(--tint5) 100%); + transform: translateY(0); } + .object_header{ display: flex; - gap: 5px; + gap: 8px; + align-items: center; + font-weight: 600; } .object_small{ font-size: 0.75em; + opacity: 0.8; } .object_modal{ - background-color: var(--tint2); - padding: 10px; - border-radius: 20px; + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + padding: 14px; + border-radius: 12px; position: relative; + border: 1px solid var(--tint4); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); } + .session_modal_activite_list{ - padding: 10px; - background-color: var(--tint3); - border-radius: 10px; + display: grid; + padding: 12px; + background: linear-gradient(135deg, var(--tint3) 0%, var(--tint4) 100%); + border-radius: 12px; + gap: 8px; + border: 1px solid var(--tint4); +} + +.activiteList{ + display: flex; + gap: 12px; + flex-wrap: wrap; } diff --git a/front_end/src/components/style/topBar.css b/front_end/src/components/style/topBar.css new file mode 100644 index 0000000..e912edd --- /dev/null +++ b/front_end/src/components/style/topBar.css @@ -0,0 +1,129 @@ +.topBar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px 24px; + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + border-radius: 20px; + height: auto; + min-height: 70px; + border: 1px solid var(--tint4); + box-shadow: var(--shadow-md); + backdrop-filter: blur(10px); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.topBar:hover { + border-color: var(--green-primary); + box-shadow: 0 8px 32px var(--green-A-primary); +} + +.toBarLeft{ + flex: 1; + display: flex; + gap: 16px; + align-items: center; + +} + +.toBarMidle{ + display: flex; + flex: 1; + justify-content: center; + gap: 10px; +} + + +.topBarRight{ + flex: 1; + font-weight: 600; +} + +.toBarLeft h2 { + background: linear-gradient(135deg, var(--green-primary) 0%, var(--cyan-accent) 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + margin: 0; + font-size: 1.5rem; +} + + +.topBarRight { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 10px; +} + +.loginContainer { + position: relative; +} + +.login { + position: absolute; + right: 0; + top: calc(100% + 8px); + display: grid; + gap: 12px; + width: fit-content; + white-space: nowrap; + align-items: left; + background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%); + padding: 16px; + border-radius: 16px; + border: 1px solid var(--tint4); + box-shadow: var(--shadow-lg); + z-index: 1000; + backdrop-filter: blur(10px); +} + +.loginButton { + display: flex; + align-items: center; + justify-content: center; + width: 120px; + height: 30px; + border-radius: 15px; +} + + +.ButtonTheme { + display: flex; + align-items: center; + justify-content: center; + height: 44px; + width: 44px; + color: var(--text); + background: linear-gradient(135deg, var(--tint3) 0%, var(--tint4) 100%); + border: 1px solid var(--tint4); + border-radius: 12px; + font-size: 18px; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); + cursor: pointer; +} + +.ButtonTheme:hover { + border-color: var(--themeButtonColor); + /* color: var(--themeButtonColor); */ + box-shadow: 0 4px 12px rgba(0, 170, 255, 0.3); + transform: scale(1.05) rotateZ(-180deg); +} + +.logo { + height: 40px; + filter: drop-shadow(0 2px 8px rgba(16, 185, 129, 0.3)); + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); +} + +.logo:hover { + transform: scale(1.1) rotateY(10deg); +} + +.logoLink:hover{ + border: 0px; +} + +.logoLink{ + border: 0px; +} diff --git a/front_end/src/components/test_api.tsx b/front_end/src/components/test_api.tsx deleted file mode 100644 index e4ed6d0..0000000 --- a/front_end/src/components/test_api.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useKeycloak } from "@react-keycloak/web" -import { getAllCoach } from "../requetes" -import { Admin } from "../classes"; - - -function TestAPI(){ - const { keycloak } = useKeycloak() - - function handleGetUsers(): void { - getAllCoach(); - } - - function handleSendAdmin(): void { - const admin = new Admin; - admin.nom = "admin"; - admin.email = "admin@gmail.com"; - - //createAdminAPI(admin); - } - - return( -
- - -
- ) -} - -export default TestAPI diff --git a/front_end/src/components/topBar.tsx b/front_end/src/components/topBar.tsx new file mode 100644 index 0000000..039fc69 --- /dev/null +++ b/front_end/src/components/topBar.tsx @@ -0,0 +1,33 @@ +import { Link } from "react-router-dom" +import { Admin, Athlete, Coach } from "../classes" +import { useLocalData } from "../context/useLocalData" +import Login from "./login" +import SwitchThemeColor from "./SwitchThemeColor" + +function TopBar(){ + + const {userLocal} = useLocalData() + + + return( +
+
+ +

Frisbyee

+
+
+ Home + Sessions + {userLocal instanceof Coach &&Gestion} + {userLocal instanceof Admin &&Admin} +
+ +
+ + +
+
+ ) +} + +export default TopBar 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/index.tsx b/front_end/src/index.tsx index 032464f..04143b1 100644 --- a/front_end/src/index.tsx +++ b/front_end/src/index.tsx @@ -3,13 +3,17 @@ import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; +import { BrowserRouter } from 'react-router-dom' + const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement ); root.render( - + + + ); 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 488e634..16a03b0 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,28 +219,11 @@ export async function postAthlete(athlete: Athlete):Promise{ 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); + const response = await sessionService.create(session.toDTO()); 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); + activiteService.create(activite.toDTO()); // console.log("Session créée"); }); } catch (error) { @@ -298,9 +283,14 @@ export async function getSessionsOfUserAPI(user:User): Promise{ sessionsDTO = response.data; } const sessions:Session[] = []; - sessionsDTO.forEach(sessionDTO => { - sessions.push(new Session(sessionDTO)); - }); + for (const sessionDTO of sessionsDTO) { + const session = new Session(sessionDTO); + const coach = await getCoachByIdAPI(sessionDTO.coachId); + if(coach!=null){ + session.coach = coach; + } + sessions.push(session); + } return sessions; }catch (error) { @@ -331,6 +321,55 @@ 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; + } +} + +export async function getCoachOfSession(session:Session): Promise{ + try { + const response = await sessionService.getCoach(session.id); + const coach:Coach = new Coach(response.data); + return coach; + } catch (error) { + console.error("Error fetching coachs:", 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 { diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 89b9cd5..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "hackathon", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} diff --git a/package.json b/package.json new file mode 100644 index 0000000..40817e1 --- /dev/null +++ b/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "react-router-dom": "^7.12.0" + } +}