Merge remote-tracking branch 'refs/remotes/origin/main'

This commit is contained in:
Alexis Leboeuf
2026-01-12 14:06:36 +01:00
6 changed files with 108 additions and 49 deletions

View File

@@ -1,48 +1,89 @@
# hackathon # FrisbyEE (Projet Hackathon)
## Pour lancer Ce projet contient : un backend Spring Boot et un frontend React en TypeScript développé lors du hackathon. L'authentification est gérée par Keycloak et la base de données est PostgreSQL; les deux peuvent être lancés via Docker.
---
## Présentation rapide
- **Backend** : Spring Boot (Java 17) dans `back_end/`
- **Frontend** : React et TypeScript dans `front_end/`
- **Auth** : Keycloak (voir `keycloak/` pour la thème et configuré via `docker-compose.yml`)
- **Base de données** : PostgreSQL (configuré via `docker-compose.yml`)
## Pré-requis
- Java 17
- Maven (utiliez `mvn`)
- Node.js et npm
- Docker et Docker Compose
## Installation et démarrage
1. Récupérez le dépôt et placez-vous à la racine du projet.
2. Démarrez Keycloak et PostgreSQL avec Docker:
```bash
sudo docker compose up -d sudo docker compose up -d
```
### back_end 3. Backend: construire et lancer (depuis la racine du projet):
cd back_end
#### Pour installer java 17 ```bash
sudo apt install openjdk-17-jdk cd back_end
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 ./mvn clean install
export PATH=$JAVA_HOME/bin:$PATH ./mvn spring-boot:run
```
#### Clean 4. Frontend: installer les dépendances et démarrer :
mvn clean install
#### Pour lancer back_end ```bash
mvn spring-boot:run
### front_end
cd front_end cd front_end
npm install
#### Install
npm install
#### Lancer front_end
npm start npm start
```
#### Docker Le serveur de développement du frontend écoute par défaut sur `http://localhost:3000`, le backend sur `http://localhost:8080`, et api sur `http://localhost:8081` sauf configuration différente.
## Commandes utiles
- Arrêter et supprimer tous les conteneurs Docker:
```bash
sudo docker stop $(sudo docker ps -a -q) sudo docker stop $(sudo docker ps -a -q)
sudo docker rm $(sudo docker ps -a -q)
```
#### Pour acceder sur docker - Ouvrir un shell Postgres dans le conteneur en cours d'exécution (exemple : conteneur `frisbyee-postgres`):
```bash
sudo docker exec -it frisbyee-postgres psql -U frisbyee_user -d frisbyee sudo docker exec -it frisbyee-postgres psql -U frisbyee_user -d frisbyee
# puis, par exemple : \dt ou SELECT * FROM session;
```
#### Voir les données: ## Keycloak / Thème de connexion
\dt - Au début, il faut crée run realm qui s'appelle `Frisbyee_realm`, ensuite dans ce realm, créez un `Frisbyee_client` avec ce config debug:
SELECT * FROM session; ```
ROOT URL: http://localhost:3000/
HOME URL: http://localhost:3000/
Valid redirect URIs: http://localhost:3000/*
Web origins: *
```
- Après, ajoutez les rôles : `admin`, `coach`, `athlete`
- Et, mettez chaque groupe `ADMIN`, `COACH`, `ATHLETE` et mapping chaque rôle pour chaque groupe.
- Dans User Registration, mettez le `defaut groupe`: `ATHLETE` et activez le user self registration.
Pour appliquer le thème de connexion personnalisé fourni dans `keycloak/themes/frisbyee` :
- Ouvrez la console d'administration Keycloak -> sélectionnez le realm -> `Realm Settings` -> modifiez le `Display name` si vous le souhaitez.
- Dans `Themes`, définissez `Login Theme` sur `frisbyee` puis enregistrez.
#### Appliquer le CSS pour la page de login Keycloak ## Configuration / Environnement
- Les propriétés du backend se trouvent dans `back_end/src/main/resources/application.properties`.
Sur la console Keycloak aller dans realm setting - Le frontend utilise `public/keycloak.json` pour la configuration du client Keycloak.
-> Changer le display name (par exemple: Bienvenue sur Frisbyee !) - Assurez-vous que le client Keycloak et le realm correspondent aux valeurs utilisées par les deux applications.
-> Theme puis changer le login theme sur frisbyee
## Contribution
- Thibaut ROCHAS
- Tuan Minh VU
- Amäel KESTEMAN
- Alexis LEBOEUF
## Domain model class diagram ## Domain model class diagram
```mermaid ```mermaid

View File

@@ -242,9 +242,9 @@ textarea::placeholder {
/* Select */ /* Select */
select { select {
background-color: var(--tint2);
color: var(--text); color: var(--text);
background-color: var(--tint3); border: 1px solid var(--tint4);
border: 2px solid var(--tint5);
border-radius: 8px; border-radius: 8px;
padding: 10px 14px; padding: 10px 14px;
cursor: pointer; cursor: pointer;
@@ -260,6 +260,7 @@ select:focus {
select option { select option {
background-color: var(--tint2); background-color: var(--tint2);
color: var(--text); color: var(--text);
border-radius: 5px;
} }
/* Buttons */ /* Buttons */
@@ -364,7 +365,7 @@ button.add:hover,
} }
/* Modal */ /* Modal */
.modal { .modalContent {
background-color: var(--tint2); background-color: var(--tint2);
padding: 20px; padding: 20px;
min-width: 300px; min-width: 300px;
@@ -373,8 +374,22 @@ button.add:hover,
border: 2px solid var(--green-primary); border: 2px solid var(--green-primary);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
position: relative; position: relative;
max-height:100%;
overflow-y: auto;
} }
.modal {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.25);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
max-height:100%;
}
.modal-overlay { .modal-overlay {
position: fixed; position: fixed;
inset: 0; inset: 0;

View File

@@ -153,7 +153,7 @@ export class Session{
isRecurrent: this.isRecurrent, isRecurrent: this.isRecurrent,
creneau: this.creneau.toISOString(), creneau: this.creneau.toISOString(),
duree: this.duree, duree: this.duree,
groupe: "", //TODO groupe: this.groupe,
coachId: this.coach?.id ?? null, coachId: this.coach?.id ?? null,
athleteIds: [], athleteIds: [],
activiteIds: [] activiteIds: []

View File

@@ -13,22 +13,10 @@ export function Modal({ isOpen, onClose, children }: ModalProps) {
if (!isOpen) return null if (!isOpen) return null
return ( return (
<div <div className="modal" onClick={onClose}>
style={{ <div className="modalContent" onClick={(e) => e.stopPropagation()}>
position: "fixed", {children}
inset: 0, </div>
backgroundColor: "rgba(0,0,0,0.25)",
display: "flex",
alignItems: "center",
justifyContent: "center",
zIndex: 1000,
}}
onClick={onClose}
>
<div className="modal" onClick={(e) => e.stopPropagation()}
>
{children}
</div>
</div> </div>
) )
} }

View File

@@ -74,6 +74,20 @@ export const CreateSession = () => {
</tr> </tr>
<tr> <tr>
<th>Groupe:</th> <th>Groupe:</th>
<th>
<select
onChange={(e) => {
const v = (e.target as HTMLSelectElement).value;
setGroupe(v as Groupe)
console.log(v);
}}>
<option value=""> Sans groupe</option>
<option value="Loisir">Loisir</option>
<option value="Entrainement">Entrainement</option>
<option value="Competition">Competition</option>
</select>
</th>
</tr> </tr>
<tr> <tr>
<th>Creneau:</th> <th>Creneau:</th>

View File

@@ -161,6 +161,7 @@ export async function createSessionAPI(session: Session): Promise<Session> {
} }
try { try {
console.log("GROUPE = " + session.groupe);
const response = await api.post<SessionDTO>("/session/create", session.toDTO()); const response = await api.post<SessionDTO>("/session/create", session.toDTO());
const sessionRes:Session = new Session(response.data); const sessionRes:Session = new Session(response.data);
await Promise.all( await Promise.all(