Merge branch 'main' of https://gitlab2.istic.univ-rennes1.fr/tuvu/hackathon
This commit is contained in:
@@ -1,12 +1,10 @@
|
|||||||
package hackathon.FrisbYEE.jpa.dto;
|
package hackathon.FrisbYEE.jpa.dto;
|
||||||
import hackathon.FrisbYEE.jpa.metier.Role;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class AdminDTO {
|
public class AdminDTO {
|
||||||
private String id_keycloak;
|
|
||||||
private Integer id;
|
private Integer id;
|
||||||
|
private String id_keycloak;
|
||||||
private String name;
|
private String name;
|
||||||
private String prenom;
|
private String prenom;
|
||||||
private Role role;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,12 @@ package hackathon.FrisbYEE.rest;
|
|||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
import org.springframework.web.bind.annotation.*;
|
||||||
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 hackathon.FrisbYEE.jpa.dto.AdminDTO;
|
import hackathon.FrisbYEE.jpa.dto.AdminDTO;
|
||||||
import hackathon.FrisbYEE.jpa.metier.Admin;
|
import hackathon.FrisbYEE.jpa.metier.Admin;
|
||||||
import hackathon.FrisbYEE.jpa.service.AdminDAO;
|
import hackathon.FrisbYEE.jpa.service.AdminDAO;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
import hackathon.FrisbYEE.jpa.service.UserDAO;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/admin")
|
@RequestMapping("/admin")
|
||||||
@@ -22,12 +17,24 @@ public class AdminResource {
|
|||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private AdminDAO adminDAO;
|
private AdminDAO adminDAO;
|
||||||
|
@Autowired
|
||||||
|
private UserDAO userDAO;
|
||||||
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@PreAuthorize("hasRole('Admin')") // Only admin can create
|
@PreAuthorize("hasRole('admin')") // Only admin can create
|
||||||
public ResponseEntity<AdminDTO> create(@RequestBody AdminDTO dto) {
|
public ResponseEntity<AdminDTO> create(@RequestBody AdminDTO dto) {
|
||||||
|
|
||||||
|
userDAO.findByKeycloakId(dto.getId_keycloak())
|
||||||
|
.ifPresent(existing -> {
|
||||||
|
if (!(existing instanceof Admin)) {
|
||||||
|
userDAO.delete(existing);
|
||||||
|
userDAO.flush();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Admin admin = mapToEntity(dto);
|
Admin admin = mapToEntity(dto);
|
||||||
|
|
||||||
if(adminDAO.findByKeycloakId(admin.getKeycloakId()).isPresent()) {
|
if(adminDAO.findByKeycloakId(admin.getKeycloakId()).isPresent()) {
|
||||||
return ResponseEntity.status(200).body(mapToDTO(adminDAO.findByKeycloakId(admin.getKeycloakId()).get()));
|
return ResponseEntity.status(200).body(mapToDTO(adminDAO.findByKeycloakId(admin.getKeycloakId()).get()));
|
||||||
}
|
}
|
||||||
@@ -55,7 +62,6 @@ public class AdminResource {
|
|||||||
dto.setId_keycloak(admin.getKeycloakId());
|
dto.setId_keycloak(admin.getKeycloakId());
|
||||||
dto.setName(admin.getName());
|
dto.setName(admin.getName());
|
||||||
dto.setPrenom(admin.getPrenom());
|
dto.setPrenom(admin.getPrenom());
|
||||||
dto.setRole(admin.getRole());
|
|
||||||
|
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
@@ -65,7 +71,7 @@ public class AdminResource {
|
|||||||
admin.setKeycloakId(dto.getId_keycloak());
|
admin.setKeycloakId(dto.getId_keycloak());
|
||||||
admin.setName(dto.getName());
|
admin.setName(dto.getName());
|
||||||
admin.setPrenom(dto.getPrenom());
|
admin.setPrenom(dto.getPrenom());
|
||||||
admin.setRole(dto.getRole());
|
admin.setRole(hackathon.FrisbYEE.jpa.metier.Role.admin);
|
||||||
|
|
||||||
return admin;
|
return admin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ public class AthleteResource {
|
|||||||
@ApiResponses(value = {
|
@ApiResponses(value = {
|
||||||
@ApiResponse(responseCode = "200", description = "Récupération effectuée", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SessionDTO.class)))
|
@ApiResponse(responseCode = "200", description = "Récupération effectuée", content = @Content(mediaType = "application/json", schema = @Schema(implementation = SessionDTO.class)))
|
||||||
})
|
})
|
||||||
@GetMapping("/athlete/{athleteId}/session")
|
@GetMapping("/{athleteId}/session")
|
||||||
public List<SessionDTO> getSessionsAthlete(@PathVariable Integer athleteId) {
|
public List<SessionDTO> getSessionsAthlete(@PathVariable Integer athleteId) {
|
||||||
Optional<Athlete> athleteOpt = athleteDAO.findById(athleteId);
|
Optional<Athlete> athleteOpt = athleteDAO.findById(athleteId);
|
||||||
if (athleteOpt.isEmpty()) {
|
if (athleteOpt.isEmpty()) {
|
||||||
@@ -174,30 +174,32 @@ public class AthleteResource {
|
|||||||
List<SessionDTO> athleteSessions = new ArrayList<>();
|
List<SessionDTO> athleteSessions = new ArrayList<>();
|
||||||
|
|
||||||
for (Session s : sessions) {
|
for (Session s : sessions) {
|
||||||
SessionDTO dto = new SessionDTO();
|
if (s.getAthletes().contains(athlete.get())) {
|
||||||
dto.setId(s.getId());
|
SessionDTO dto = new SessionDTO();
|
||||||
dto.setName(s.getName());
|
|
||||||
dto.setCreneau(s.getCreneau());
|
|
||||||
dto.setDuree(s.getDuree());
|
|
||||||
dto.setGroupe(s.getGroupe());
|
|
||||||
dto.setIsRecurrent(s.getIsRecurrent());
|
|
||||||
dto.setCoachId(s.getCoach() != null ? s.getCoach().getId() : null);
|
|
||||||
|
|
||||||
List<Integer> activiteIDs = new ArrayList<>();
|
dto.setId(s.getId());
|
||||||
for (Activite activite : s.getActivites()) {
|
dto.setName(s.getName());
|
||||||
activiteIDs.add(activite.getId());
|
dto.setCreneau(s.getCreneau());
|
||||||
|
List<Integer> activiteIDs = new ArrayList<>();
|
||||||
|
for (Activite activite : s.getActivites()) {
|
||||||
|
activiteIDs.add(activite.getId());
|
||||||
|
}
|
||||||
|
dto.setActiviteIds(activiteIDs);
|
||||||
|
dto.setCoachId(s.getCoach().getId());
|
||||||
|
dto.setDuree(s.getDuree());
|
||||||
|
dto.setGroupe(s.getGroupe());
|
||||||
|
dto.setIsRecurrent(s.getIsRecurrent());
|
||||||
|
List<Integer> athleteIds = new ArrayList<>();
|
||||||
|
for (Athlete athlete2 : s.getAthletes()) {
|
||||||
|
athleteIds.add(athlete2.getId());
|
||||||
|
}
|
||||||
|
dto.setAthleteIds(athleteIds);
|
||||||
|
|
||||||
|
// Map other fields as necessary
|
||||||
|
athleteSessions.add(dto);
|
||||||
}
|
}
|
||||||
dto.setActiviteIds(activiteIDs);
|
|
||||||
|
|
||||||
List<Integer> athleteIds = new ArrayList<>();
|
|
||||||
for (Athlete a : s.getAthletes()) {
|
|
||||||
athleteIds.add(a.getId());
|
|
||||||
}
|
|
||||||
dto.setAthleteIds(athleteIds);
|
|
||||||
|
|
||||||
athleteSessions.add(dto);
|
|
||||||
}
|
}
|
||||||
|
System.out.println(athlete);
|
||||||
return athleteSessions;
|
return athleteSessions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,16 @@
|
|||||||
package hackathon.FrisbYEE.rest;
|
package hackathon.FrisbYEE.rest;
|
||||||
|
|
||||||
import hackathon.FrisbYEE.jpa.dto.CoachDTO;
|
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.Coach;
|
||||||
|
import hackathon.FrisbYEE.jpa.metier.Session;
|
||||||
import hackathon.FrisbYEE.jpa.service.CoachDAO;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
@@ -17,13 +25,28 @@ import java.util.List;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/coach")
|
@RequestMapping("/coach")
|
||||||
public class CoachResource {
|
public class CoachResource {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private CoachDAO coachDAO;
|
private CoachDAO coachDAO;
|
||||||
|
@Autowired
|
||||||
|
private UserDAO userDAO;
|
||||||
|
@Autowired
|
||||||
|
private SessionDAO sessionDAO;
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@PreAuthorize("hasRole('Admin')") // Only admin can create
|
@PreAuthorize("hasRole('admin') or hasRole('coach')") // Only admin can create
|
||||||
public ResponseEntity<CoachDTO> create(@RequestBody CoachDTO dto) {
|
public ResponseEntity<CoachDTO> create(@RequestBody CoachDTO dto) {
|
||||||
|
|
||||||
|
userDAO.findByKeycloakId(dto.getId_keycloak())
|
||||||
|
.ifPresent(existing -> {
|
||||||
|
if (!(existing instanceof Coach)) {
|
||||||
|
userDAO.delete(existing);
|
||||||
|
userDAO.flush();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Coach coach = mapToEntity(dto);
|
Coach coach = mapToEntity(dto);
|
||||||
|
|
||||||
if(coachDAO.existsByKeycloakId(coach.getKeycloakId())) {
|
if(coachDAO.existsByKeycloakId(coach.getKeycloakId())) {
|
||||||
return ResponseEntity.status(200).body(mapToDTO(coachDAO.findByKeycloakId(coach.getKeycloakId()).get()));
|
return ResponseEntity.status(200).body(mapToDTO(coachDAO.findByKeycloakId(coach.getKeycloakId()).get()));
|
||||||
}
|
}
|
||||||
@@ -72,11 +95,38 @@ public class CoachResource {
|
|||||||
|
|
||||||
@GetMapping("/{id}/session")
|
@GetMapping("/{id}/session")
|
||||||
@PreAuthorize("hasRole('Admin') or hasRole('Coach')")
|
@PreAuthorize("hasRole('Admin') or hasRole('Coach')")
|
||||||
public ResponseEntity<List<?>> getSessionsForCoach(@PathVariable Integer id) {
|
public ResponseEntity<List<SessionDTO>> getSessionsForCoach(@PathVariable Integer id) {
|
||||||
Coach coach = coachDAO.findById(id)
|
Coach coach = coachDAO.findById(id)
|
||||||
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Coach not found"));
|
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Coach not found"));
|
||||||
List<?> sessions = coach.getSessions();
|
List<Session> sessions = sessionDAO.findAll();
|
||||||
return ResponseEntity.ok(sessions);
|
List<SessionDTO> 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<Integer> activiteIDs = new ArrayList<>();
|
||||||
|
for (Activite activite : s.getActivites()) {
|
||||||
|
activiteIDs.add(activite.getId());
|
||||||
|
}
|
||||||
|
dto.setActiviteIds(activiteIDs);
|
||||||
|
dto.setCoachId(s.getCoach().getId());
|
||||||
|
dto.setDuree(s.getDuree());
|
||||||
|
dto.setGroupe(s.getGroupe());
|
||||||
|
dto.setIsRecurrent(s.getIsRecurrent());
|
||||||
|
List<Integer> athleteIds = new ArrayList<>();
|
||||||
|
for (Athlete athlete : s.getAthletes()) {
|
||||||
|
athleteIds.add(athlete.getId());
|
||||||
|
}
|
||||||
|
dto.setAthleteIds(athleteIds);
|
||||||
|
|
||||||
|
// Map other fields as necessary
|
||||||
|
coachSessions.add(dto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResponseEntity.ok(coachSessions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete/{id}")
|
@DeleteMapping("/delete/{id}")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package hackathon.FrisbYEE.rest;
|
package hackathon.FrisbYEE.rest;
|
||||||
|
|
||||||
import hackathon.FrisbYEE.jpa.dto.ActiviteDTO;
|
import hackathon.FrisbYEE.jpa.dto.ActiviteDTO;
|
||||||
|
import hackathon.FrisbYEE.jpa.dto.CoachDTO;
|
||||||
import hackathon.FrisbYEE.jpa.dto.SessionDTO;
|
import hackathon.FrisbYEE.jpa.dto.SessionDTO;
|
||||||
import hackathon.FrisbYEE.jpa.metier.Activite;
|
import hackathon.FrisbYEE.jpa.metier.Activite;
|
||||||
import hackathon.FrisbYEE.jpa.metier.Athlete;
|
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.bind.annotation.*;
|
||||||
import org.springframework.web.server.ResponseStatusException;
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -74,6 +76,30 @@ public class SessionResource {
|
|||||||
return ResponseEntity.ok(dtos);
|
return ResponseEntity.ok(dtos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/all-between-dates")
|
||||||
|
@PreAuthorize("hasRole('admin') or hasRole('coach') or hasRole('athlete')")
|
||||||
|
public ResponseEntity<List<SessionDTO>> getAllBetweenDates(
|
||||||
|
@RequestParam LocalDate startDate,
|
||||||
|
@RequestParam LocalDate endDate
|
||||||
|
) {
|
||||||
|
List<Session> sessions = sessionDAO.findAll();
|
||||||
|
List<SessionDTO> 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}")
|
@GetMapping("/{id}")
|
||||||
@PreAuthorize("hasRole('coach') or hasRole('athlete')")
|
@PreAuthorize("hasRole('coach') or hasRole('athlete')")
|
||||||
public ResponseEntity<?> getById(@PathVariable Integer id) {
|
public ResponseEntity<?> getById(@PathVariable Integer id) {
|
||||||
@@ -150,6 +176,29 @@ public class SessionResource {
|
|||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{id}/coach")
|
||||||
|
@PreAuthorize("hasRole('coach') or hasRole('athlete')")
|
||||||
|
public ResponseEntity<CoachDTO> 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<Integer> listSession = new ArrayList<Integer>();
|
||||||
|
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")
|
@GetMapping("/{id}/activities")
|
||||||
@PreAuthorize("hasRole('coach') or hasRole('athlete')")
|
@PreAuthorize("hasRole('coach') or hasRole('athlete')")
|
||||||
|
|||||||
139
front_end/package-lock.json
generated
139
front_end/package-lock.json
generated
@@ -20,9 +20,10 @@
|
|||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
"keycloak-js": "^26.2.2",
|
"keycloak-js": "^26.2.2",
|
||||||
"react": "^19.2.3",
|
"react": "18.2.0",
|
||||||
"react-bootstrap": "^2.10.10",
|
"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",
|
"react-scripts": "5.0.1",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
@@ -74,6 +75,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
|
||||||
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.5",
|
"@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",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz",
|
||||||
"integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
|
"integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.27.1"
|
"@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",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz",
|
||||||
"integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
|
"integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-annotate-as-pure": "^7.27.1",
|
"@babel/helper-annotate-as-pure": "^7.27.1",
|
||||||
"@babel/helper-module-imports": "^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",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
@@ -3465,6 +3470,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz",
|
||||||
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
"integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.10.4",
|
"@babel/code-frame": "^7.10.4",
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
@@ -3850,6 +3856,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz",
|
||||||
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
"integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.2.2"
|
"csstype": "^3.2.2"
|
||||||
}
|
}
|
||||||
@@ -3859,6 +3866,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
|
||||||
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
"integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^19.2.0"
|
"@types/react": "^19.2.0"
|
||||||
}
|
}
|
||||||
@@ -3988,6 +3996,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
|
||||||
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
"integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.4.0",
|
"@eslint-community/regexpp": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "5.62.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",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz",
|
||||||
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
"integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==",
|
||||||
"license": "BSD-2-Clause",
|
"license": "BSD-2-Clause",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "5.62.0",
|
"@typescript-eslint/scope-manager": "5.62.0",
|
||||||
"@typescript-eslint/types": "5.62.0",
|
"@typescript-eslint/types": "5.62.0",
|
||||||
@@ -4410,6 +4420,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -4508,6 +4519,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.1",
|
"fast-deep-equal": "^3.1.1",
|
||||||
"fast-json-stable-stringify": "^2.0.0",
|
"fast-json-stable-stringify": "^2.0.0",
|
||||||
@@ -5447,6 +5459,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.9.0",
|
"baseline-browser-mapping": "^2.9.0",
|
||||||
"caniuse-lite": "^1.0.30001759",
|
"caniuse-lite": "^1.0.30001759",
|
||||||
@@ -7302,6 +7315,7 @@
|
|||||||
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
|
||||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.6.1",
|
"@eslint-community/regexpp": "^4.6.1",
|
||||||
@@ -10066,6 +10080,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz",
|
||||||
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
|
"integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/core": "^27.5.1",
|
"@jest/core": "^27.5.1",
|
||||||
"import-local": "^3.0.2",
|
"import-local": "^3.0.2",
|
||||||
@@ -10963,6 +10978,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
|
||||||
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"jiti": "bin/jiti.js"
|
"jiti": "bin/jiti.js"
|
||||||
}
|
}
|
||||||
@@ -11166,6 +11182,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-26.2.2.tgz",
|
||||||
"integrity": "sha512-ug7pNZ1xNkd7PPkerOJCEU2VnUhS7CYStDOCFJgqCNQ64h53ppxaKrh4iXH0xM8hFu5b1W6e6lsyYWqBMvaQFg==",
|
"integrity": "sha512-ug7pNZ1xNkd7PPkerOJCEU2VnUhS7CYStDOCFJgqCNQ64h53ppxaKrh4iXH0xM8hFu5b1W6e6lsyYWqBMvaQFg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"test"
|
"test"
|
||||||
]
|
]
|
||||||
@@ -12325,6 +12342,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nanoid": "^3.3.11",
|
"nanoid": "^3.3.11",
|
||||||
"picocolors": "^1.1.1",
|
"picocolors": "^1.1.1",
|
||||||
@@ -13459,6 +13477,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
|
||||||
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cssesc": "^3.0.0",
|
"cssesc": "^3.0.0",
|
||||||
"util-deprecate": "^1.0.2"
|
"util-deprecate": "^1.0.2"
|
||||||
@@ -13833,10 +13852,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react": {
|
"node_modules/react": {
|
||||||
"version": "19.2.3",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||||
"integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==",
|
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
@@ -13995,15 +14018,17 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "19.2.3",
|
"version": "18.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||||
"integrity": "sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==",
|
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"loose-envify": "^1.1.0",
|
||||||
|
"scheduler": "^0.23.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^19.2.3"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-error-overlay": {
|
"node_modules/react-error-overlay": {
|
||||||
@@ -14035,10 +14060,62 @@
|
|||||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||||
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
|
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"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": {
|
"node_modules/react-scripts": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
||||||
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
},
|
},
|
||||||
@@ -14710,10 +14788,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/scheduler": {
|
"node_modules/scheduler": {
|
||||||
"version": "0.27.0",
|
"version": "0.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||||
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||||
"license": "MIT"
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"loose-envify": "^1.1.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/schema-utils": {
|
"node_modules/schema-utils": {
|
||||||
"version": "4.3.3",
|
"version": "4.3.3",
|
||||||
@@ -14739,6 +14820,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-uri": "^3.0.1",
|
"fast-uri": "^3.0.1",
|
||||||
@@ -14940,6 +15022,12 @@
|
|||||||
"node": ">= 0.8.0"
|
"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": {
|
"node_modules/set-function-length": {
|
||||||
"version": "1.2.2",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
"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": {
|
"node_modules/tapable": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12"
|
"node": ">=12"
|
||||||
},
|
},
|
||||||
@@ -16387,6 +16459,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
|
||||||
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
|
||||||
"license": "(MIT OR CC0-1.0)",
|
"license": "(MIT OR CC0-1.0)",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
},
|
},
|
||||||
@@ -16495,6 +16568,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
|
||||||
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -16833,6 +16907,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz",
|
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.104.1.tgz",
|
||||||
"integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
|
"integrity": "sha512-Qphch25abbMNtekmEGJmeRUhLDbe+QfiWTiqpKYkpCOWY64v9eyl+KRRLmqOFA2AvKPpc9DC6+u2n76tQLBoaA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/eslint-scope": "^3.7.7",
|
"@types/eslint-scope": "^3.7.7",
|
||||||
"@types/estree": "^1.0.8",
|
"@types/estree": "^1.0.8",
|
||||||
@@ -16904,6 +16979,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz",
|
||||||
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
"integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/bonjour": "^3.5.9",
|
"@types/bonjour": "^3.5.9",
|
||||||
"@types/connect-history-api-fallback": "^1.3.5",
|
"@types/connect-history-api-fallback": "^1.3.5",
|
||||||
@@ -17317,6 +17393,7 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"fast-uri": "^3.0.1",
|
"fast-uri": "^3.0.1",
|
||||||
|
|||||||
@@ -15,9 +15,10 @@
|
|||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"bootstrap": "^5.3.8",
|
"bootstrap": "^5.3.8",
|
||||||
"keycloak-js": "^26.2.2",
|
"keycloak-js": "^26.2.2",
|
||||||
"react": "^19.2.3",
|
"react": "18.2.0",
|
||||||
"react-bootstrap": "^2.10.10",
|
"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",
|
"react-scripts": "5.0.1",
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
|
|||||||
@@ -1,38 +1,52 @@
|
|||||||
/* Variables de thème */
|
/* Variables de thème */
|
||||||
[data-theme='dark'] {
|
[data-theme='dark'] {
|
||||||
--tint0: #000000;
|
--tint0: #0a0e27;
|
||||||
--tint1: #0b0c0e;
|
--tint1: #1a1f3a;
|
||||||
--tint2: #16181d;
|
--tint2: #232d4a;
|
||||||
--tint3: #21252b;
|
--tint3: #2e3a59;
|
||||||
--tint4: #2c313a;
|
--tint4: #3d4a6f;
|
||||||
--tint5: #373d48;
|
--tint5: #4a5a85;
|
||||||
--text: #FFFFFF;
|
--text: #f0f4f8;
|
||||||
--text2: #000000;
|
--text2: #000000;
|
||||||
--disable: #02291d;
|
--disable: #02291d;
|
||||||
--green-primary: #10b981;
|
--green-primary: #10b981;
|
||||||
--green-secondary: #059669;
|
--green-secondary: #059669;
|
||||||
--green-dark: #047857;
|
--green-dark: #047857;
|
||||||
--green-A-primary: #10b98120;
|
--green-A-primary: #10b98130;
|
||||||
--green-A-secondary: #05966920;
|
--green-A-secondary: #05966930;
|
||||||
--green-A-dark: #04785720;
|
--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'] {
|
[data-theme='light'] {
|
||||||
--tint0: #ffffff;
|
--tint0: #f8fafc;
|
||||||
--tint1: #f4f1f1;
|
--tint1: #f1f5f9;
|
||||||
--tint2: #e8e4e3;
|
--tint2: #e2e8f0;
|
||||||
--tint3: #ddd6d5;
|
--tint3: #cbd5e1;
|
||||||
--tint4: #d2c8c6;
|
--tint4: #b0bac4;
|
||||||
--tint5: #c6bab8;
|
--tint5: #94a3b8;
|
||||||
--text: #000000;
|
--text: #0f172a;
|
||||||
--text2: #FFFFFF;
|
--text2: #FFFFFF;
|
||||||
--disable: #02291d;
|
--disable: #02291d;
|
||||||
--green-primary: #00ce89;
|
--green-primary: #10b981;
|
||||||
--green-secondary: #00a571;
|
--green-secondary: #059669;
|
||||||
--green-dark: #00825d;
|
--green-dark: #047857;
|
||||||
--green-A-primary: #00ce8920;
|
--green-A-primary: #10b98125;
|
||||||
--green-A-secondary: #00a57120;
|
--green-A-secondary: #05966925;
|
||||||
--green-A-dark: #00825d20;
|
--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 */
|
/* Reset et base */
|
||||||
@@ -42,19 +56,27 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
html,body{
|
||||||
margin: 0;
|
width: 100%;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
height: 100%;
|
||||||
'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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.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
|
padding: 10px
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,20 +91,47 @@ code {
|
|||||||
color: var(--green-primary);
|
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 */
|
/* Container principal */
|
||||||
.app-container {
|
.app-container {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: linear-gradient(180deg, var(--tint0) 0%, var(--tint1) 100%);
|
background: linear-gradient(180deg, var(--tint0) 0%, var(--tint1) 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.composant-container{
|
.composant-padding {
|
||||||
background-color: var(--tint2);
|
|
||||||
border-radius: 30px;
|
|
||||||
padding: 10px;
|
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 */
|
/* Header / Navigation */
|
||||||
.app-header {
|
.app-header {
|
||||||
background-color: var(--tint1);
|
background-color: var(--tint1);
|
||||||
@@ -122,18 +171,18 @@ code {
|
|||||||
|
|
||||||
/* Cards et containers */
|
/* Cards et containers */
|
||||||
.card {
|
.card {
|
||||||
background-color: var(--tint1);
|
background: linear-gradient(135deg, var(--tint1) 0%, var(--tint2) 100%);
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
padding: 20px;
|
padding: 24px;
|
||||||
border: 2px solid var(--green-A-secondary);
|
border: 1px solid var(--tint4);
|
||||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
box-shadow: var(--shadow-md);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover {
|
.card:hover {
|
||||||
border-color: var(--green-primary);
|
border-color: var(--green-primary);
|
||||||
box-shadow: 0 6px 16px var(--green-A-primary);
|
box-shadow: 0 8px 24px var(--green-A-primary);
|
||||||
transform: translateY(-2px);
|
transform: translateY(-4px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
@@ -159,20 +208,21 @@ input[type="time"],
|
|||||||
input[type="search"],
|
input[type="search"],
|
||||||
input[type="datetime-local"],
|
input[type="datetime-local"],
|
||||||
textarea {
|
textarea {
|
||||||
background-color: var(--tint3);
|
background-color: var(--tint2);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
border: 2px solid var(--tint5);
|
border: 1px solid var(--tint4);
|
||||||
border-radius: 8px;
|
border-radius: 12px;
|
||||||
padding: 10px 14px;
|
padding: 12px 14px;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
input:focus,
|
input:focus,
|
||||||
textarea:focus {
|
textarea:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--green-primary);
|
border-color: var(--green-primary);
|
||||||
background-color: var(--tint3);
|
background-color: var(--tint1);
|
||||||
box-shadow: 0 0 0 3px var(--green-A-primary);
|
box-shadow: 0 0 0 3px var(--green-A-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,23 +265,29 @@ select option {
|
|||||||
/* Buttons */
|
/* Buttons */
|
||||||
button {
|
button {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
background-color: var(--tint3);
|
background: linear-gradient(135deg, var(--tint3) 0%, var(--tint4) 100%);
|
||||||
border: 2px solid var(--tint5);
|
border: 1px solid var(--tint4);
|
||||||
border-radius: 8px;
|
border-radius: 12px;
|
||||||
padding: 5px 10px;
|
padding: 10px 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: auto;
|
width: auto;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover {
|
button:hover {
|
||||||
background-color: var(--tint4);
|
background: linear-gradient(135deg, var(--green-primary) 0%, var(--green-secondary) 100%);
|
||||||
border-color: var(--green-primary);
|
border-color: var(--green-primary);
|
||||||
|
color: white;
|
||||||
transform: translateY(-2px);
|
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 {
|
button:active {
|
||||||
@@ -278,7 +334,7 @@ button.secondary:hover {
|
|||||||
.deleteButton,
|
.deleteButton,
|
||||||
button.delete,
|
button.delete,
|
||||||
.btn-danger {
|
.btn-danger {
|
||||||
background-color: #dc2626;
|
background: #dc2626;
|
||||||
border: 2px solid #991b1b;
|
border: 2px solid #991b1b;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
color: white;
|
color: white;
|
||||||
@@ -287,7 +343,7 @@ button.delete,
|
|||||||
.deleteButton:hover,
|
.deleteButton:hover,
|
||||||
button.delete:hover,
|
button.delete:hover,
|
||||||
.btn-danger:hover {
|
.btn-danger:hover {
|
||||||
background-color: #b91c1c;
|
background: #b91c1c;
|
||||||
border-color: #7f1d1d;
|
border-color: #7f1d1d;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +351,7 @@ button.delete:hover,
|
|||||||
.addButton,
|
.addButton,
|
||||||
button.add,
|
button.add,
|
||||||
.btn-success {
|
.btn-success {
|
||||||
background-color: var(--green-primary);
|
background: var(--green-primary);
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
color: white;
|
color: white;
|
||||||
@@ -418,7 +474,8 @@ td {
|
|||||||
|
|
||||||
|
|
||||||
/* Lists */
|
/* Lists */
|
||||||
ul, ol {
|
ul,
|
||||||
|
ol {
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
@@ -535,6 +592,7 @@ input[type="radio"] {
|
|||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@@ -545,6 +603,7 @@ input[type="radio"] {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateY(20px);
|
transform: translateY(20px);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ import CreateSession from './components/createSession'
|
|||||||
import EdtCoach from './components/edt_coach'
|
import EdtCoach from './components/edt_coach'
|
||||||
import { Coach } from "./classes";
|
import { Coach } from "./classes";
|
||||||
import RessourcePanel from './components/ressourcePanel';
|
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 = {
|
const keycloakInitOptions = {
|
||||||
onLoad: 'login-required',
|
onLoad: 'login-required',
|
||||||
@@ -22,13 +28,13 @@ function App() {
|
|||||||
<ReactKeycloakProvider authClient={keycloak} /*initOptions={keycloakInitOptions}*/>
|
<ReactKeycloakProvider authClient={keycloak} /*initOptions={keycloakInitOptions}*/>
|
||||||
<LocalDataProvider>
|
<LocalDataProvider>
|
||||||
<div className="App">
|
<div className="App">
|
||||||
<SwitchThemeColor/>
|
<TopBar/>
|
||||||
<h1>Frisbyee</h1>
|
<Routes>
|
||||||
<Login/>
|
<Route path="/" element={<Home/>}/>
|
||||||
<RessourcePanel/>
|
<Route path="/sessions" element={<SelectionSession/>}/>
|
||||||
<EDT/>
|
<Route path="/gestion" element={<Gestion/>}/>
|
||||||
<CreateSession/>
|
<Route path="/admin" element={<Admin/>}/>
|
||||||
<TestAPI/>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
</LocalDataProvider>
|
</LocalDataProvider>
|
||||||
</ReactKeycloakProvider>
|
</ReactKeycloakProvider>
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export const athleteService = {
|
|||||||
delete: (id: number | string) => api.delete(`/athlete/${id}`),
|
delete: (id: number | string) => api.delete(`/athlete/${id}`),
|
||||||
|
|
||||||
// session-related endpoints exposed by AthleteResource
|
// session-related endpoints exposed by AthleteResource
|
||||||
getSessionsForAthlete: (athleteId: number | null) => api.get<SessionDTO[]>(`/athlete/athlete/${athleteId}/session`),
|
getSessionsForAthlete: (athleteId: number | null) => api.get<SessionDTO[]>(`/athlete/${athleteId}/session`),
|
||||||
getAllSessions: () => api.get(`/athletes/session`),
|
getAllSessions: () => api.get(`/athletes/session`),
|
||||||
getActivitiesForSession: (sessionId: number | string) => api.get(`/athletes/session/${sessionId}/activities`),
|
getActivitiesForSession: (sessionId: number | string) => api.get(`/athletes/session/${sessionId}/activities`),
|
||||||
getSessionsAfterDate: (athleteId: number | string, date: string) => api.get(`/athletes/${athleteId}/session/after/${encodeURIComponent(date)}`),
|
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)}`),
|
getByTheme: (theme: string) => api.get(`/activite/theme/${encodeURIComponent(theme)}`),
|
||||||
getDataActivite: (id: number | string) => api.get(`/activite/${id}`),
|
getDataActivite: (id: number | string) => api.get(`/activite/${id}`),
|
||||||
};
|
};
|
||||||
|
type DateBetween = {
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const sessionService = {
|
export const sessionService = {
|
||||||
// controller uses singular /session/* endpoints
|
// controller uses singular /session/* endpoints
|
||||||
create: (data: any) => api.post(`/session/create`, data),
|
create: (data: SessionDTO) => api.post(`/session/create`, data),
|
||||||
getAll: () => api.get<SessionDTO[]>(`/session/all`),
|
getAll: () => api.get<SessionDTO[]>(`/session/all`),
|
||||||
|
getAllBetweenDate: (data: any) => api.get<SessionDTO[]>(`/session/all-between-dates`,{params: data,}),
|
||||||
getById: (id: number | null) => api.get(`/session/${id}`),
|
getById: (id: number | null) => api.get(`/session/${id}`),
|
||||||
delete: (id: number | null) => api.delete(`/session/delete/${id}`),
|
delete: (id: number | null) => api.delete(`/session/delete/${id}`),
|
||||||
update: (id: number | null, data: any) => api.put(`/session/update/${id}`, data),
|
update: (id: number | null, data: any) => api.put(`/session/update/${id}`, data),
|
||||||
|
|
||||||
getActivities: (sessionId: number | null) => api.get<ActiviteDTO[]>(`/session/${sessionId}/activities`),
|
getActivities: (sessionId: number | null) => api.get<ActiviteDTO[]>(`/session/${sessionId}/activities`),
|
||||||
addActivity: (sessionId: number | null, activityId: number) => api.post(`/session/${sessionId}/activities/${activityId}`),
|
addActivity: (sessionId: number | null, activityId: number) => api.post(`/session/${sessionId}/activities/${activityId}`),
|
||||||
|
getCoach: (sessionId: number | null) => api.get<CoachDTO>(`/session/${sessionId}/coach`),
|
||||||
subscribe: (sessionId: number | null, userId: number) => api.put(`/session/${sessionId}/subscribe/${userId}`),
|
subscribe: (sessionId: number | null, userId: number) => api.put(`/session/${sessionId}/subscribe/${userId}`),
|
||||||
unsubscribe: (sessionId: number | null, userId: number) => api.put(`/session/${sessionId}/unsubscribe/${userId}`),
|
unsubscribe: (sessionId: number | null, userId: number) => api.put(`/session/${sessionId}/unsubscribe/${userId}`),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const coachService = {
|
export const coachService = {
|
||||||
// controller doesn't declare a class-level path consistently; support both common patterns
|
// controller doesn't declare a class-level path consistently; support both common patterns
|
||||||
create: (data: any) => api.post<CoachDTO>(`/coach/create`, data),
|
create: (data: CoachDTO) => api.post<CoachDTO>(`/coach/create`, data),
|
||||||
getAll: () => api.get<CoachDTO[]>(`/coach/all`),
|
getAll: () => api.get<CoachDTO[]>(`/coach/all`),
|
||||||
getById: (id: number) => api.get(`/coach/${id}`),
|
getById: (id: number) => api.get(`/coach/${id}`),
|
||||||
getByKeycloakId: (keycloakId: string) => api.get(`/coach/keycloak/${keycloakId}`),
|
getByKeycloakId: (keycloakId: string) => api.get(`/coach/keycloak/${keycloakId}`),
|
||||||
@@ -97,7 +103,8 @@ export const userService = {
|
|||||||
|
|
||||||
export const adminService = {
|
export const adminService = {
|
||||||
getByKeycloakId: (keycloak_id: string) => api.get(`/admin/keycloak/${keycloak_id}`),
|
getByKeycloakId: (keycloak_id: string) => api.get(`/admin/keycloak/${keycloak_id}`),
|
||||||
getById: (id: number | string) => api.get(`/admin/${id}`),
|
getById: (id: number | string) => api.get<AdminDTO>(`/admin/${id}`),
|
||||||
|
create: (data: AdminDTO) => api.post<AdminDTO>("/admin/create", data),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
@@ -55,7 +55,7 @@ export class Athlete extends User{
|
|||||||
|
|
||||||
constructor(dto?:AthleteDTO){
|
constructor(dto?:AthleteDTO){
|
||||||
super();
|
super();
|
||||||
this.id = dto?.id ?? 0;
|
this.id = dto?.id ?? null;
|
||||||
this.keycloakId = dto?.id_keycloak ?? "";
|
this.keycloakId = dto?.id_keycloak ?? "";
|
||||||
this.nom = dto?.name ?? "";
|
this.nom = dto?.name ?? "";
|
||||||
this.prenom = dto?.prenom ?? "" ;
|
this.prenom = dto?.prenom ?? "" ;
|
||||||
@@ -90,7 +90,7 @@ export class Coach extends User{
|
|||||||
|
|
||||||
constructor(dto?:CoachDTO){
|
constructor(dto?:CoachDTO){
|
||||||
super();
|
super();
|
||||||
this.id = dto?.id ?? 0;
|
this.id = dto?.id ?? null;
|
||||||
this.keycloakId = dto?.id_keycloak ?? "";
|
this.keycloakId = dto?.id_keycloak ?? "";
|
||||||
this.nom = dto?.name ?? "";
|
this.nom = dto?.name ?? "";
|
||||||
this.prenom = dto?.prenom ?? "";
|
this.prenom = dto?.prenom ?? "";
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { useState,useEffect } from 'react';
|
import { useState,useEffect } from 'react';
|
||||||
import './style/SwitchThemeColor.css';
|
|
||||||
|
|
||||||
|
|
||||||
const SwitchThemeColor = () => {
|
const SwitchThemeColor = () => {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { createSessionAPI, postSession } from "../requetes";
|
|||||||
import './style/createSession.css';
|
import './style/createSession.css';
|
||||||
|
|
||||||
export const CreateSession = () => {
|
export const CreateSession = () => {
|
||||||
const {user} = useLocalData();
|
const {userLocal: user} = useLocalData();
|
||||||
const [session,setSession] = useState<Session>(new Session());
|
const [session,setSession] = useState<Session>(new Session());
|
||||||
const [activities, setActivities] = useState<Activite[]>([]);
|
const [activities, setActivities] = useState<Activite[]>([]);
|
||||||
const [name,setName] = useState("");
|
const [name,setName] = useState("");
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { Athlete, Coach, Session} from "../classes"
|
import { Admin, Athlete, Coach, Session} from "../classes"
|
||||||
import { useLocalData } from "../context/useLocalData"
|
import { useLocalData } from "../context/useLocalData"
|
||||||
import './style/edt.css';
|
import './style/edt.css';
|
||||||
import {getSessionsOfUserAPI } from "../requetes";
|
import {getAllSessionsAPI, getAllSessionsBetweenAPI, getSessionsOfUserAPI } from "../requetes";
|
||||||
import EdtSession from "./edt_session";
|
import EdtSession from "./edt_session";
|
||||||
import {delay} from "../requetes";
|
import {delay} from "../requetes";
|
||||||
import Loading from "./loading";
|
import Loading from "./loading";
|
||||||
@@ -26,7 +26,8 @@ export function hoursToString(date:Date){
|
|||||||
|
|
||||||
|
|
||||||
export const EDT =() =>{
|
export const EDT =() =>{
|
||||||
const {user,setUser} = useLocalData()
|
const {userLocal} = useLocalData()
|
||||||
|
const {sessionsLocal,setSessionsLocal} = useLocalData()
|
||||||
const [sessions, setSessions] = useState<Session[]>([])
|
const [sessions, setSessions] = useState<Session[]>([])
|
||||||
const [week,setWeek] = useState<Date>(getFirstDay(new Date()));
|
const [week,setWeek] = useState<Date>(getFirstDay(new Date()));
|
||||||
const [loadedWeek,setLoadedWeek] = useState<Date|null>(null);
|
const [loadedWeek,setLoadedWeek] = useState<Date|null>(null);
|
||||||
@@ -35,12 +36,21 @@ export const EDT =() =>{
|
|||||||
const week_days_nums:number[] = [1,2,3,4,5,6,0];
|
const week_days_nums:number[] = [1,2,3,4,5,6,0];
|
||||||
|
|
||||||
function loadSessions(date:Date){
|
function loadSessions(date:Date){
|
||||||
var maxDate = getNextDay(date,6)
|
var maxDate = toDateOnly(getNextDay(date,6));
|
||||||
|
|
||||||
var newWeek: Session[] = []
|
var newWeek: Session[] = []
|
||||||
if(user instanceof Athlete || user instanceof Coach){
|
if(userLocal instanceof Athlete || userLocal instanceof Coach){
|
||||||
user.sessions.forEach(session => {
|
userLocal.sessions.forEach(session => {
|
||||||
if((session.creneau >= date && session.creneau <= maxDate && !session.isRecurrent) || (session.isRecurrent && session.creneau<maxDate)){
|
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);
|
newWeek.push(session);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -50,7 +60,7 @@ export const EDT =() =>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
function changeWeek(date:Date){
|
function changeWeek(date:Date){
|
||||||
setWeek(date);
|
setWeek(toDateOnly(date));
|
||||||
}
|
}
|
||||||
|
|
||||||
function isSameDay(date1:Date,date2:Date){
|
function isSameDay(date1:Date,date2:Date){
|
||||||
@@ -65,7 +75,7 @@ export const EDT =() =>{
|
|||||||
updateWeek(week);
|
updateWeek(week);
|
||||||
loadSessions(week)
|
loadSessions(week)
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
},[week,user])
|
},[week,userLocal])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(loadedWeek!==null){
|
if(loadedWeek!==null){
|
||||||
@@ -83,9 +93,22 @@ export const EDT =() =>{
|
|||||||
//TODO updateSession
|
//TODO updateSession
|
||||||
//await delay(2000);
|
//await delay(2000);
|
||||||
//await updateSessionsOfUser(user,null,null);
|
//await updateSessionsOfUser(user,null,null);
|
||||||
if(user instanceof Athlete || user instanceof Coach){
|
if(userLocal instanceof Athlete || userLocal instanceof Coach){
|
||||||
const newSessions:Session[] = await getSessionsOfUserAPI(user);
|
const newSessions:Session[] = await getSessionsOfUserAPI(userLocal);
|
||||||
user.sessions = newSessions;
|
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);
|
setLoadedWeek(week);
|
||||||
}
|
}
|
||||||
@@ -108,7 +131,15 @@ export const EDT =() =>{
|
|||||||
else{
|
else{
|
||||||
firstDate = getNextDay(date,-numWeek+1);
|
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{
|
function getNextDay(date:Date,nb:number):Date{
|
||||||
@@ -139,7 +170,7 @@ export const EDT =() =>{
|
|||||||
<div className="edt_colonnes">
|
<div className="edt_colonnes">
|
||||||
<div className="top_left_loading">{loading && <Loading/>}</div>
|
<div className="top_left_loading">{loading && <Loading/>}</div>
|
||||||
{week_days_nums.map((num,index)=>(
|
{week_days_nums.map((num,index)=>(
|
||||||
<div className={`edt_colonne`}>
|
<div className={`edt_colonne ${sameDay(getNextDay(week, index), new Date()) ? "today" : ""}`}>
|
||||||
<div className={`edt_day_header ${sameDay(getNextDay(week, index), new Date()) ? "today" : ""}`}>
|
<div className={`edt_day_header ${sameDay(getNextDay(week, index), new Date()) ? "today" : ""}`}>
|
||||||
<div> {week_days[index]} </div>
|
<div> {week_days[index]} </div>
|
||||||
<div className="edt_date"> {dateToString(getNextDay(week,index))} </div>
|
<div className="edt_date"> {dateToString(getNextDay(week,index))} </div>
|
||||||
|
|||||||
@@ -1,49 +1,42 @@
|
|||||||
import { useKeycloak } from '@react-keycloak/web'
|
import { useKeycloak } from '@react-keycloak/web'
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { Admin, Athlete, Coach, User } from '../classes';
|
import { Admin, Athlete, Coach, User } from '../classes';
|
||||||
import { useLocalData } from '../context/useLocalData';
|
import { useLocalData } from '../context/useLocalData';
|
||||||
import { loginOrRegister, postAthlete } from '../requetes';
|
import { loginOrRegister, postAthlete } from '../requetes';
|
||||||
import { clearAuthToken, setAuthToken } from '../api';
|
import { clearAuthToken, setAuthToken } from '../api';
|
||||||
import { AthleteDTO } from '../classesDTO';
|
import { AthleteDTO } from '../classesDTO';
|
||||||
|
import { Modal } from './Modal';
|
||||||
|
import './style/topBar.css';
|
||||||
|
|
||||||
export const Login =() =>{
|
export const Login =() =>{
|
||||||
const {user,setUser} = useLocalData()
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
|
const {userLocal: user,setUserLocal: setUser} = useLocalData()
|
||||||
const { keycloak } = useKeycloak();
|
const { keycloak } = useKeycloak();
|
||||||
|
const [open,setOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
/*useEffect(() => {
|
useEffect(() => {
|
||||||
const syncAndLoadUser = async () => {
|
const handleClickOutside = (e: MouseEvent) => {
|
||||||
if (keycloak.authenticated && keycloak.token && keycloak.tokenParsed) {
|
if (ref.current && !ref.current.contains(e.target as Node)) {
|
||||||
try {
|
setOpen(false);
|
||||||
const newAthlete: Athlete = new Athlete();
|
}
|
||||||
newAthlete.keycloakId = keycloak.tokenParsed.sub || "";
|
};
|
||||||
newAthlete.email = keycloak.tokenParsed.email || "";
|
|
||||||
newAthlete.nom = keycloak.tokenParsed.family_name || "";
|
document.addEventListener("mousedown", handleClickOutside);
|
||||||
newAthlete.prenom = keycloak.tokenParsed.given_name || "";
|
|
||||||
|
return () => {
|
||||||
setAuthToken(keycloak.token);
|
document.removeEventListener("mousedown", handleClickOutside);
|
||||||
|
};
|
||||||
const athlete: Athlete = await postAthlete(newAthlete);
|
}, []);
|
||||||
setUser(athlete);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error :", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
syncAndLoadUser();
|
|
||||||
}, [keycloak.authenticated, keycloak.token, setUser]);
|
|
||||||
*/
|
|
||||||
|
|
||||||
async function loginUser(){
|
async function loginUser(){
|
||||||
if(keycloak.authenticated){
|
if(keycloak.authenticated){
|
||||||
setAuthToken(keycloak.token);
|
setAuthToken(keycloak.token);
|
||||||
//alert("Connexion en cours : " + keycloak.tokenParsed?.sub + " " + keycloak.tokenParsed?.realm_access?.roles);
|
|
||||||
|
|
||||||
const logedUser = await loginOrRegister(keycloak);
|
const logedUser = await loginOrRegister(keycloak);
|
||||||
console.log(logedUser);
|
console.log(logedUser);
|
||||||
if(logedUser!==null){
|
if(logedUser!==null){
|
||||||
setUser(logedUser);
|
setUser(logedUser);
|
||||||
// alert("Connexion avec succès ! " + keycloak.tokenParsed?.sub);
|
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
alert("Erreur de connexion " + keycloak.tokenParsed?.sub + " " + keycloak.tokenParsed?.realm_access?.roles);
|
alert("Erreur de connexion " + keycloak.tokenParsed?.sub + " " + keycloak.tokenParsed?.realm_access?.roles);
|
||||||
@@ -63,37 +56,51 @@ export const Login =() =>{
|
|||||||
keycloak.logout()
|
keycloak.logout()
|
||||||
setUser(new User());
|
setUser(new User());
|
||||||
clearAuthToken();
|
clearAuthToken();
|
||||||
|
setOpen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleOpen(): void {
|
||||||
|
setOpen(!open);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(keycloak.authenticated){
|
||||||
return(
|
return(
|
||||||
<div>
|
<div ref={ref} className='loginContainer'>
|
||||||
<div>
|
<button className="loginButton" onClick={()=>handleOpen()}>{user.prenom}</button>
|
||||||
Etat : {keycloak.authenticated ? 'connecté' : 'non connecté'}
|
{open &&
|
||||||
|
<div className='login'>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
Prenom : { user.prenom}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Nom : { user.nom}
|
||||||
|
</div>
|
||||||
|
{/* <div>Keycloak ID : { keycloak.tokenParsed?.sub}</div> */}
|
||||||
|
{user instanceof Athlete && <div>Role : Athlete</div>}
|
||||||
|
{user instanceof Coach && <div>Role : Coach</div>}
|
||||||
|
{user instanceof Admin && <div>Role : Admin</div>}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button onClick={() => handleLogout()}>
|
||||||
|
Se déconnecter
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
{keycloak.authenticated &&
|
)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return(
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<button onClick={() => handleLogin()}>
|
||||||
Keycloak ID : { keycloak.tokenParsed?.sub}
|
Se connecter
|
||||||
</div>
|
</button>
|
||||||
<div>
|
|
||||||
Prenom : { user.prenom}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
Nom : { user.nom}
|
|
||||||
</div>
|
|
||||||
{user instanceof Athlete && <div>Role : Athlete</div>}
|
|
||||||
{user instanceof Coach && <div>Role : Coach</div>}
|
|
||||||
{user instanceof Admin && <div>Role : Admin</div>}
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
}
|
)
|
||||||
<button onClick={() => handleLogin()}>
|
}
|
||||||
Se connecter
|
|
||||||
</button>
|
|
||||||
<button onClick={() => handleLogout()}>
|
|
||||||
Se déconnecter
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Login
|
export default Login
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { dateToString, hoursToString } from "../edt";
|
|||||||
import { Modal } from "../Modal";
|
import { Modal } from "../Modal";
|
||||||
import CreateActivite from "../createActivite";
|
import CreateActivite from "../createActivite";
|
||||||
import Loading from "../loading";
|
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";
|
import { useLocalData } from "../../context/useLocalData";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -15,7 +15,7 @@ type Props = {
|
|||||||
|
|
||||||
function DetailSession({session,open,setOpen}:Props){
|
function DetailSession({session,open,setOpen}:Props){
|
||||||
|
|
||||||
const {user,setUser} = useLocalData()
|
const {userLocal: user,setUserLocal: setUser} = useLocalData()
|
||||||
|
|
||||||
const [activites,setActivites] = useState<Activite[]>([]);
|
const [activites,setActivites] = useState<Activite[]>([]);
|
||||||
const [open2, setOpen2] = useState<boolean>(false);
|
const [open2, setOpen2] = useState<boolean>(false);
|
||||||
@@ -93,10 +93,13 @@ function DetailSession({session,open,setOpen}:Props){
|
|||||||
|
|
||||||
return(
|
return(
|
||||||
<Modal isOpen={open} onClose={() => setOpen(false)}>
|
<Modal isOpen={open} onClose={() => setOpen(false)}>
|
||||||
<div className="object_modal">
|
<div>
|
||||||
<h2>{session.name}</h2>
|
<h2>{session.name}</h2>
|
||||||
|
|
||||||
<div>{hoursToString(sDate)}</div>
|
<div>{hoursToString(sDate)}</div>
|
||||||
<div>{dateToString(sDate)}</div>
|
<div>{dateToString(sDate)}</div>
|
||||||
|
<div>encadré par :</div>
|
||||||
|
<div>{session.coach?.prenom} {session.coach?.nom}</div>
|
||||||
{user instanceof Athlete &&
|
{user instanceof Athlete &&
|
||||||
<div>
|
<div>
|
||||||
{user.sessions.includes(session) ? <button onClick={()=>unsubscribeSession()}>quitter</button>
|
{user.sessions.includes(session) ? <button onClick={()=>unsubscribeSession()}>quitter</button>
|
||||||
@@ -108,8 +111,8 @@ function DetailSession({session,open,setOpen}:Props){
|
|||||||
Activités :
|
Activités :
|
||||||
<div className="session_modal_activite_list">
|
<div className="session_modal_activite_list">
|
||||||
{activites.map((activite,index)=>(
|
{activites.map((activite,index)=>(
|
||||||
<div>
|
<div className="activiteList">
|
||||||
{activite.nom}
|
- {activite.nom}
|
||||||
{canEdit && (
|
{canEdit && (
|
||||||
<button className="deleteButton" onClick={() => handleDeleteActivite(activite)}>x</button>
|
<button className="deleteButton" onClick={() => handleDeleteActivite(activite)}>x</button>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -104,6 +104,9 @@ function ObjectUser({user}:Props){
|
|||||||
<div className="object_modal">
|
<div className="object_modal">
|
||||||
<div>{user.prenom}</div>
|
<div>{user.prenom}</div>
|
||||||
<div>{user.nom}</div>
|
<div>{user.nom}</div>
|
||||||
|
{user instanceof Athlete && <div>Role : Athlete</div>}
|
||||||
|
{user instanceof Coach && <div>Role : Coach</div>}
|
||||||
|
{user instanceof Admin && <div>Role : Admin</div>}
|
||||||
{(user instanceof Athlete || user instanceof Coach) &&
|
{(user instanceof Athlete || user instanceof Coach) &&
|
||||||
<div className='padding'>
|
<div className='padding'>
|
||||||
<div className='list_object_modal'>
|
<div className='list_object_modal'>
|
||||||
|
|||||||
13
front_end/src/components/pages/pageAdmin.tsx
Normal file
13
front_end/src/components/pages/pageAdmin.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import CreateSession from "../createSession"
|
||||||
|
import TopBar from "../topBar"
|
||||||
|
|
||||||
|
function Admin() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Admin</h1>
|
||||||
|
rien pour l'instant
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Admin
|
||||||
13
front_end/src/components/pages/pageGestion.tsx
Normal file
13
front_end/src/components/pages/pageGestion.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import CreateSession from "../createSession"
|
||||||
|
import TopBar from "../topBar"
|
||||||
|
|
||||||
|
function Gestion() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Gestion</h1>
|
||||||
|
<CreateSession/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Gestion
|
||||||
13
front_end/src/components/pages/pageHome.tsx
Normal file
13
front_end/src/components/pages/pageHome.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import EDT from "../edt"
|
||||||
|
import TopBar from "../topBar"
|
||||||
|
|
||||||
|
function Home() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Home</h1>
|
||||||
|
<EDT/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home
|
||||||
13
front_end/src/components/pages/pageSectionSession.tsx
Normal file
13
front_end/src/components/pages/pageSectionSession.tsx
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import RessourcePanel from "../ressourcePanel"
|
||||||
|
import TopBar from "../topBar"
|
||||||
|
|
||||||
|
function SelectionSession() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Selection Session</h1>
|
||||||
|
<RessourcePanel/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectionSession
|
||||||
@@ -15,7 +15,7 @@ import ObjectLigne from "./object/lignes";
|
|||||||
|
|
||||||
export default function RessourcePanel() {
|
export default function RessourcePanel() {
|
||||||
const { keycloak } = useKeycloak();
|
const { keycloak } = useKeycloak();
|
||||||
const { user } = useLocalData();
|
const { userLocal: user } = useLocalData();
|
||||||
//const user = getUserTest(); //TODO
|
//const user = getUserTest(); //TODO
|
||||||
const [value,setValue] = useState<keyWord>("sessions");
|
const [value,setValue] = useState<keyWord>("sessions");
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,8 @@
|
|||||||
.createActivite{
|
.createActivite {
|
||||||
background: var(--tint1);
|
background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%);
|
||||||
padding: 15px;
|
padding: 20px;
|
||||||
border-radius: 15px;
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,17 +1,24 @@
|
|||||||
.edt{
|
.edt {
|
||||||
background-color: var(--tint2);
|
background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%);
|
||||||
border-radius: 30px;
|
border-radius: 24px;
|
||||||
padding: 10px;
|
padding: 20px;
|
||||||
border: 2px solid var(--tint4);
|
border: 1px solid var(--tint4);
|
||||||
box-shadow: 0 4px 6px rgba(16, 185, 129, 0.1);
|
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;
|
justify-content: center;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 0.5fr);
|
grid-template-columns: repeat(3, 0.5fr);
|
||||||
padding-bottom: 10px;
|
padding-bottom: 16px;
|
||||||
gap: 5%;
|
gap: 12px;
|
||||||
|
margin-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_colonnes {
|
.edt_colonnes {
|
||||||
@@ -24,7 +31,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_loading{
|
.edt_loading {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -32,31 +39,43 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.edt_colonne {
|
.edt_colonne {
|
||||||
display: grid;
|
background: linear-gradient(135deg, var(--tint2) 0%, var(--tint4) 100%);
|
||||||
background-color: var(--tint3);
|
border-radius: 16px;
|
||||||
border-radius: 20px;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
container-type: inline-size;
|
height: 100%;
|
||||||
transition: all 0.3s ease;
|
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);
|
font-size: clamp(5px, 1vw, 18px);
|
||||||
padding: 8px;
|
padding: 12px;
|
||||||
border-radius: 20px;
|
border-radius: 12px;
|
||||||
height: fit-content;
|
height: fit-content;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
background: linear-gradient(135deg, var(--green-A-primary), var(--green-A-dark));
|
background: linear-gradient(135deg, var(--green-primary) 0%, var(--green-secondary) 100%);
|
||||||
font-weight: 600;
|
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{
|
.edt_day_header.today {
|
||||||
background: linear-gradient(135deg, var(--green-primary), var(--green-dark));
|
background: linear-gradient(135deg, var(--green-dark) 0%, var(--cyan-accent) 100%);
|
||||||
color: #FFFFFF;
|
color: #FFFFFF;
|
||||||
|
box-shadow: 0 6px 20px var(--green-A-primary);
|
||||||
|
transform: scale(1.02);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_day_content{
|
.edt_day_content {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@@ -68,39 +87,39 @@
|
|||||||
.edt_session {
|
.edt_session {
|
||||||
font-size: clamp(1px, 8cqi, 18px);
|
font-size: clamp(1px, 8cqi, 18px);
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
background-color: var(--tint4);
|
background: linear-gradient(135deg, var(--tint4) 0%, var(--tint5) 100%);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 5%;
|
padding: 12px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
border-left: 3px solid var(--green-primary); /* Accent vert à gauche */
|
border-left: 4px solid var(--green-primary);
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_session:hover {
|
.edt_session:hover {
|
||||||
background-color: var(--tint2);
|
background: linear-gradient(135deg, var(--green-A-primary), var(--green-A-secondary));
|
||||||
border-left-width: 5px;
|
border-left-width: 6px;
|
||||||
transform: translateX(3px);
|
transform: translateX(4px);
|
||||||
box-shadow: -2px 2px 8px var(--green-A-primary);
|
box-shadow: 0 8px 16px var(--green-A-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_session:active {
|
.edt_session:active {
|
||||||
background-color: var(--tint5);
|
|
||||||
transform: translateX(1px);
|
transform: translateX(1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_session_header{
|
.edt_session_header {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_date{
|
.edt_date {
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_button_week_select{
|
.edt_button_week_select {
|
||||||
background: linear-gradient(135deg, var(--green-primary), var( --green-secondary));
|
background: linear-gradient(135deg, var(--green-primary), var(--green-secondary));
|
||||||
color: white;
|
color: white;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
@@ -123,7 +142,7 @@
|
|||||||
box-shadow: 0 1px 2px var(--green-A-primary);
|
box-shadow: 0 1px 2px var(--green-A-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_session_modal{
|
.edt_session_modal {
|
||||||
background-color: var(--tint2);
|
background-color: var(--tint2);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 20px;
|
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);
|
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;
|
padding: 10px;
|
||||||
background-color: var(--tint3);
|
background-color: var(--tint3);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border: 1px solid var(--green-A-primary);
|
border: 1px solid var(--green-A-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.edt_activite_modal{
|
.edt_activite_modal {
|
||||||
background-color: var(--tint3);
|
background-color: var(--tint3);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
|
|||||||
@@ -1,58 +1,81 @@
|
|||||||
.list_object{
|
.list_object{
|
||||||
display: grid;
|
display: grid;
|
||||||
gap:10px;
|
gap: 12px;
|
||||||
background-color: var(--tint1);
|
background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%);
|
||||||
padding: 10px;
|
padding: 16px;
|
||||||
border-radius: 20px;
|
border-radius: 16px;
|
||||||
|
border: 1px solid var(--tint4);
|
||||||
|
box-shadow: var(--shadow-md);
|
||||||
}
|
}
|
||||||
|
|
||||||
.list_object_modal{
|
.list_object_modal{
|
||||||
display: grid;
|
display: grid;
|
||||||
gap:10px;
|
gap: 12px;
|
||||||
background-color: var(--tint1);
|
background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%);
|
||||||
padding: 10px;
|
padding: 16px;
|
||||||
border-radius: 20px;
|
border-radius: 16px;
|
||||||
max-height: 200px;
|
max-height: 280px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
border: 1px solid var(--tint4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.object {
|
.object {
|
||||||
|
|
||||||
font-size: clamp(1px, 8cqi, 18px);
|
font-size: clamp(1px, 8cqi, 18px);
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
background-color: var(--tint3);
|
background: linear-gradient(135deg, var(--tint3) 0%, var(--tint4) 100%);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
padding: 10px;
|
padding: 12px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
border: 2px solid;
|
border: 1px solid var(--tint4);
|
||||||
border-color: var(--tint3);
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: var(--shadow-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.object:hover {
|
.object:hover {
|
||||||
background-color: var(--tint2);
|
background: linear-gradient(135deg, var(--green-A-primary), var(--green-A-secondary));
|
||||||
border-color: var(--green-primary);
|
border-color: var(--green-primary);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 8px 16px var(--green-A-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.object:active {
|
.object:active {
|
||||||
background-color: var(--tint4);
|
background: linear-gradient(135deg, var(--tint4) 0%, var(--tint5) 100%);
|
||||||
|
transform: translateY(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.object_header{
|
.object_header{
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
.object_small{
|
.object_small{
|
||||||
font-size: 0.75em;
|
font-size: 0.75em;
|
||||||
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.object_modal{
|
.object_modal{
|
||||||
background-color: var(--tint2);
|
background: linear-gradient(135deg, var(--tint2) 0%, var(--tint3) 100%);
|
||||||
padding: 10px;
|
padding: 14px;
|
||||||
border-radius: 20px;
|
border-radius: 12px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
border: 1px solid var(--tint4);
|
||||||
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.session_modal_activite_list{
|
.session_modal_activite_list{
|
||||||
padding: 10px;
|
display: grid;
|
||||||
background-color: var(--tint3);
|
padding: 12px;
|
||||||
border-radius: 10px;
|
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;
|
||||||
}
|
}
|
||||||
|
|||||||
129
front_end/src/components/style/topBar.css
Normal file
129
front_end/src/components/style/topBar.css
Normal file
@@ -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;
|
||||||
|
}
|
||||||
@@ -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(
|
|
||||||
<div style={{padding:30, backgroundColor:"#000000"}}>
|
|
||||||
<button onClick={()=>handleGetUsers()}>getUsers</button>
|
|
||||||
<button onClick={()=>handleSendAdmin()}>sendAdmin</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default TestAPI
|
|
||||||
33
front_end/src/components/topBar.tsx
Normal file
33
front_end/src/components/topBar.tsx
Normal file
@@ -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(
|
||||||
|
<div className="topBar">
|
||||||
|
<div className="toBarLeft">
|
||||||
|
<Link className="logoLink" to="/"><img className="logo" src="/Frisbyee_logo.png"/></Link>
|
||||||
|
<h2>Frisbyee</h2>
|
||||||
|
</div>
|
||||||
|
<div className="toBarMidle">
|
||||||
|
<Link to="/">Home</Link>
|
||||||
|
<Link to="/sessions">Sessions</Link>
|
||||||
|
{userLocal instanceof Coach &&<Link to="/gestion">Gestion</Link>}
|
||||||
|
{userLocal instanceof Admin &&<Link to="/admin">Admin</Link>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="topBarRight">
|
||||||
|
<SwitchThemeColor/>
|
||||||
|
<Login/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TopBar
|
||||||
@@ -2,12 +2,10 @@ import { createContext } from 'react'
|
|||||||
import { Session, User } from '../classes';
|
import { Session, User } from '../classes';
|
||||||
|
|
||||||
interface LocalDataContextType {
|
interface LocalDataContextType {
|
||||||
user:User;
|
userLocal:User;
|
||||||
setUser: React.Dispatch<React.SetStateAction<User>>
|
setUserLocal: React.Dispatch<React.SetStateAction<User>>
|
||||||
sessions: Session[];
|
sessionsLocal: Session[];
|
||||||
setSessions: React.Dispatch<React.SetStateAction<Session[]>>
|
setSessionsLocal: React.Dispatch<React.SetStateAction<Session[]>>
|
||||||
users: User[];
|
|
||||||
setUsers: React.Dispatch<React.SetStateAction<User[]>>
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ import ReactDOM from 'react-dom/client';
|
|||||||
import './index.css';
|
import './index.css';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import reportWebVitals from './reportWebVitals';
|
import reportWebVitals from './reportWebVitals';
|
||||||
|
import { BrowserRouter } from 'react-router-dom'
|
||||||
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
document.getElementById('root') as HTMLElement
|
document.getElementById('root') as HTMLElement
|
||||||
);
|
);
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<BrowserRouter>
|
||||||
|
<App />
|
||||||
|
</BrowserRouter>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,14 @@ import { Session, User } from '../classes'
|
|||||||
import { LocalDataContext } from '../context/LocalDataContext'
|
import { LocalDataContext } from '../context/LocalDataContext'
|
||||||
|
|
||||||
export const LocalDataProvider = ({ children }: { children: React.ReactNode }) => {
|
export const LocalDataProvider = ({ children }: { children: React.ReactNode }) => {
|
||||||
const [user, setUser] = useState<User>(new User())
|
const [userLocal, setUserLocal] = useState<User>(new User())
|
||||||
const [sessions, setSessions] = useState<Session[]>([])
|
const [sessionsLocal, setSessionsLocal] = useState<Session[]>([])
|
||||||
const [users, setUsers] = useState<User[]>([])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LocalDataContext.Provider
|
<LocalDataContext.Provider
|
||||||
value={{ user, setUser, sessions, setSessions, users, setUsers }}>
|
value={{ userLocal, setUserLocal, sessionsLocal,setSessionsLocal}}>
|
||||||
{children}
|
{children}
|
||||||
</LocalDataContext.Provider>
|
</LocalDataContext.Provider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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 { Activite, Admin, Athlete, Coach, Session, User } from "./classes";
|
||||||
import Keycloak from 'keycloak-js'
|
import Keycloak from 'keycloak-js'
|
||||||
import { AdminDTO, AthleteDTO, CoachDTO, SessionDTO } from "./classesDTO";
|
import { AdminDTO, AthleteDTO, CoachDTO, SessionDTO } from "./classesDTO";
|
||||||
@@ -27,7 +27,9 @@ export async function loginOrRegister(keycloak:Keycloak): Promise<User|null>{
|
|||||||
newAdmin.email = keycloak.tokenParsed.email || "";
|
newAdmin.email = keycloak.tokenParsed.email || "";
|
||||||
newAdmin.nom = keycloak.tokenParsed.family_name || "";
|
newAdmin.nom = keycloak.tokenParsed.family_name || "";
|
||||||
newAdmin.prenom = keycloak.tokenParsed.given_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);
|
const admin = new Admin(response.data);
|
||||||
return admin;
|
return admin;
|
||||||
}
|
}
|
||||||
@@ -217,28 +219,11 @@ export async function postAthlete(athlete: Athlete):Promise<Athlete>{
|
|||||||
|
|
||||||
export async function postSession(session: Session){
|
export async function postSession(session: Session){
|
||||||
try {
|
try {
|
||||||
const data = {
|
const response = await sessionService.create(session.toDTO());
|
||||||
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.id = response.data.id; //TODO ?
|
||||||
|
|
||||||
session.activites.forEach(activite => {
|
session.activites.forEach(activite => {
|
||||||
const data2 = {
|
activiteService.create(activite.toDTO());
|
||||||
name: activite.nom,
|
|
||||||
duree: activite.duree,
|
|
||||||
date: activite.data,
|
|
||||||
theme: activite.theme,
|
|
||||||
sessionId: session.id, //TODO
|
|
||||||
}
|
|
||||||
activiteService.create(data2);
|
|
||||||
// console.log("Session créée");
|
// console.log("Session créée");
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -298,9 +283,14 @@ export async function getSessionsOfUserAPI(user:User): Promise<Session[]>{
|
|||||||
sessionsDTO = response.data;
|
sessionsDTO = response.data;
|
||||||
}
|
}
|
||||||
const sessions:Session[] = [];
|
const sessions:Session[] = [];
|
||||||
sessionsDTO.forEach(sessionDTO => {
|
for (const sessionDTO of sessionsDTO) {
|
||||||
sessions.push(new Session(sessionDTO));
|
const session = new Session(sessionDTO);
|
||||||
});
|
const coach = await getCoachByIdAPI(sessionDTO.coachId);
|
||||||
|
if(coach!=null){
|
||||||
|
session.coach = coach;
|
||||||
|
}
|
||||||
|
sessions.push(session);
|
||||||
|
}
|
||||||
return sessions;
|
return sessions;
|
||||||
|
|
||||||
}catch (error) {
|
}catch (error) {
|
||||||
@@ -331,6 +321,55 @@ export async function getAllSessionsAPI():Promise<Session[]>{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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<Session[]>{
|
||||||
|
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<Coach>{
|
||||||
|
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
|
//COACH
|
||||||
export async function getAllCoach(): Promise<Coach[]> {
|
export async function getAllCoach(): Promise<Coach[]> {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -30,6 +30,8 @@
|
|||||||
background-color: rgba(255, 255, 255, 0.98);
|
background-color: rgba(255, 255, 255, 0.98);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-pf:hover {
|
.card-pf:hover {
|
||||||
@@ -38,6 +40,7 @@
|
|||||||
0 8px 20px rgba(16, 185, 129, 0.15);
|
0 8px 20px rgba(16, 185, 129, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Header de la card */
|
/* Header de la card */
|
||||||
#kc-form-login .card-pf h1,
|
#kc-form-login .card-pf h1,
|
||||||
.login-pf-page h1 {
|
.login-pf-page h1 {
|
||||||
|
|||||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "hackathon",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
||||||
5
package.json
Normal file
5
package.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"react-router-dom": "^7.12.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user