# Projet 4 SR03 : Application web avec React
Projet réalisé par Valentin CHELLE & Colin LAFOND pour le semestre P20.
Lien du projet sur Git : https://gitlab.utc.fr/vlou-uvs/gi04/sr03-all/sr03-projet-4
Lien direct du rapport sur Git : https://gitlab.utc.fr/vlou-uvs/gi04/sr03-all/sr03-projet-4/-/blob/master/Rapport.md
Vidéo d'utilisation de l'application : https://www.youtube.com/watch?v=CUnpKoM5bBo
***/!\ Il est fortement recommandé de lire ce rapport en ligne sur le Gitlab car il contient beaucoup d'images. Un export PDF casserait le bon formattage du fichier et rendrait ce rapport peu lisible.***
## Introduction
Dans ce devoir nous devions développer une application web permettant l'affichage d'un ou de plusieurs emplois du temps d'étudiants de l'UTC. Nous devions utiliser HTML 5, JavaScript avec comme bibliothèque **React** ainsi que du CSS, les frameworks étant autorisés.
L'APi permettant de récupérer un emploi du temps est la suivante :
`https://webapplis.utc.fr/Edt_ent_rest/myedt/result/?login=<login_etudiant>`
---
## Sommaire
1. Fonctionnalités développées
2. Architecture de l'application
1. Présentation générale des choix architecturaux
2. L'App
3. Le module de récupération des EDTs
4. Le menu de sélection des logins
5. Le module d'affichage des EDTs
3. Galerie de screenshot et vidéo
4. Instructions d'installation
Pour pouvoir afficher l'emploi du temps, nous avons décidé d'utiliser le modèle `Schedule`.
C'est à travers ce rapport nous allons vous exposer la structure de notre application ainsi que son fonctionnement.
---
## 1. Fonctionnalités développées
- Module de récupération des EDTs:
- Contrôle de saisie sur le login
- Bouton dynamique qui s'adapte à la saisie de l'utilisateur et à l'état de l'application :
- `Retrieve timetable` en vert quand le login tapé n'est pas déjà téléchargé
- `Update timetable` en jaune quand l'EDT du login tapé est déjà téléchargé
- Le bouton devient rouge si une erreur lors de la récupération de l'EDT est détectée
- Le contenu du boutton devient un cercle qui tourne sur fond bleu, afin de notifier l'utilisateur que l'action de téléchargement de l'EDT est en cours. Le titre de la page web change également.
- Si une erreur est survenue, en plus de passer le bouton en rouge, un message d'alerte est affichée avec le contenu de l'erreur
- EDTs stockés dans le local storage après téléchargement, pour la persistance
- Module de gestion des EDTs téléchargés:
- Tous les EDTs téléchargés peuvent être affichés, en cliquant sur le login de l'étudiant. Le fond du login devient alors bleu.
- Possibilité de sélectionner 0, 1 ou autant d'EDTs d'étudiants que nécessaires
- Si sélection multiple, le fond du login prend alors la couleur des UVs de l'étudiant sur le module d'affichage
- EDTs restaurés depuis le local storage lors de l'accès à l'application
- Possibilité de supprimer individuellement chaque EDT grâce à la petite croix à côté de chaque login
- Possibilité de supprimer tous les EDTs d'un coup grâce à l'icône de poubelle
- Possibilité de sélectionner / déselectionner tous les EDTs d'un coup à la fois grâce à 2 boutons dédiés
- Après suppression, les EDTs sont automatiquement déselectionnés et supprimé du localStorage
- Module d'affichage des EDTs:
- Si un seul EDT est affiché, chaque évènement prend une même couleur par UV. Sinon, chaque évènement prend la couleur de l'étudiant, que l'on retrouve dans le menu de sélection
- Si plusieurs EDTs affichés, le login de l'étudiant est également affiché dans le titre de l'évènement.
- Le nom de l'UV + le type de cours est affiché en tant que titre.
- Toutes les autres informations : horaires, salle et groupe sont également disponibles
- Alternance des TPs une semaine sur 2 (sans informations supplémentaires ...)
- Les UVs ne sont affichés que dans le semestre courant :
- Début février jusqu'à fin juin pour le semestre de printemps
- Début septembre jusqu'à fin janvier pour le semestre d'automne
- Les dates de début et de fin de semestre sont fixées arbitrairement puisque l'API ne les fournit pas.
- Les évènements sont cliquables pour obtenir plus d'informations
- 4 vues sont disponibles :
- `Mois` : qui affiche les évènements du mois sélectionné
- `Semaine de travail` : qui affiche uniquement les jours de la semaine qui contiennent au moins un évènement
- `Semaine` : qui affiche les évènements de la semaine sélectionnée
- `Jour` : qui affiche les évènements du jour sélectionné
- Possibilité de sélectionner une date grâce à un calendrier
- Par défaut : vue de la semaine courante. Le jour actuel est en surbrillance en rouge, et également l'heure actuelle.
- Toutes les autres interactions avec l'agenda, comme l'ajout d'évènement, est désactivé.
- Planning échelonné de 8h à 20h pour correspondre aux horaires extrêmes à l'UTC.
- 4 sous-sections par heures sont présentes afin de respecter les horaires de cours de l'UTC
- Design général de l'application
- Tooltips omniprésents lorsque l'on passe la souris sur les boutons de sélection
- Design auto-adaptatif : L'application s'adapte à l'appareil qui la consulte : ordinateur, téléphone, etc.
- Redimensionnement du module d'affichage pour éviter d'avoir à scroller
---
## 2. Architecture de l'application
### Présentation générale des choix architecturaux
#### Hooks et fonctions composants
Dans notre application nous utilisons exclusivement la nouvelle syntaxe **React**, basée sur les **fonctions** et les **hooks**, au lieu des classes. Nous utilisons des variables d'état qui nous permettent de faire fonctionner chaque module. Les **hooks** nous permettent d'avoir une approche basée sur les évènements, ce qui est plus simple à manipuler. Leur utilisation confère de nombreux avantages notamment leur simplicité, un code moins verbeux comparé à l'utilisation de classes, et l'évitement des problèmes dues à `this`.
##### Exemple d'utilisation de hooks
###### Hooks d'état
`useState` est un Hook qui permet d’ajouter un état local à des fonctions composants. Pour l'utiliser il faut importer de react `useState`:
``` javascript
import React, { useState } from 'react';
```
Sa déclaration se fait à l'intérieur d'une fonction composante :
``` jsx
function Example() {
const [selectedLogins, setSelectedLogins] = useState(["chelleva"]);
}
```
Ici notre variable est appelée `selectedLogins` et initialisée avec la valeur `["chelleva"]`. L'équivalent avec des classes aurait donné :
``` jsx
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
SelectedLogins: "chelleva"
};
}
```
Pour lire l'état il suffit d'utiliser:
``` javascript
<p>Le login sélectionné est {selectedLogins}</p>
```
Et pour le modifier :
``` javascript
setSelectedLogins(newLoginSelection);
```
###### Hook d'effet
`useEffect` est un Hook qui permet d’ajouter d'effectuer des actions lorsqu'un état local est modifié. Pour l'utiliser il faut importer de react `useEffect`:
``` JSX
import React, { useEffect } from 'react';
```
`useEffect` permet de déclencher des effets de bord dans les composants, ce qui est similaire aux méthodes de cycle de vie dans les classes. Il est beaucoup utilisé dans notre projet, par exemple pour modifier la couleur du bouton lors d'une erreur :
``` JSX
// Print each error in the console, and change the color of the button
useEffect(() => {
if (error) {
console.log(`Error : ${error}`);
setButtonVariant("danger");
}
}, [error]);
```
#### Les librairies utilisées
##### Bootstrap
Afin de gérer facilement l'aspect visuel et le CSS de notre application, nous utilisons `Bootstrap`. `Bootstrap` est très bien intégré à `React` et nous permet d'utiliser des composants `React` afin de bénéficier de toutes ses fonctions. Bootstrap nous permet de rendre le design de l'application adaptatif, et donc l'utilisation possible sur mobile autant que sur un ordinateur, grâce au redimensionnement dynamique des composants de l'interface. Bootstrap nous permet également de facilement gérer les différents boutons, les alignements, et l'aspect visuel global de notre application sans prise de tête.
La documentation est disponible ici : https://react-bootstrap.github.io/getting-started/introduction
##### Iwanthue
Lorsque l'on superpose l'affichage de plusieurs emplois du temps, ou bien que l'on veut distinguer chaque UV, il est nécessaire de choisir correctement la palette de couleur utilisée afin de guider et d'aider visuellement l'utilisateur de l'application. Pour cela, nous utilisons la librairie `Iwanthue`, qui permet de générer une palette de couleur, dont chaque couleur est la plus distincte possible visuellement des autres. Nous utilisons des palettes pré-générées, sauf dans le cas ou il y a plus de 15 couleurs différentes à générer. Dans ce cas, la palette est générée à la volée.
La librairie est disponible ici : https://www.npmjs.com/package/iwanthue
##### Schedule de **Syncfusion**
**Syncfusion** propose un grand nombre de composants `React` de toute sorte. Nous avons décidé d'utiliser le composant `Schedule` afin de réaliser l'affichage des EDTs, car il présente un grand nombre de configurations possibles, plusieurs types d'affichages, un rendu visuel soigné, et une documentation détaillée. La documentation est disponible ici : https://ej2.syncfusion.com/react/documentation/schedule/
---
Notre application est basée sur `create-react-app`, ce qui nous a permis d'otenir rapidement un environnement de travail fonctionnel. L'application est divisée en 4 composants principaux que nous allons pouvoir détailler par la suite. Ils sont sur fond jaune dans l'image suivante :

---
### L'App
L'application principale est définie dans `src/App.js`, dans le composant `App`. Ce composant encapsule toute notre application web. C'est le chef d'orchestre qui va permettre de faire interagir les autres composants entre eux. C'est lui qui détient certaines variables comme les EDTs téléchargés, les logins sélectionnés, ou bien les couleurs des étudiants sélectionnés. Pour cela, nos utilisons le design pattern ***Lift up State*** préconisé par Facebook. Ce pattern permet de faire remonter les données à partager à un module parent, qui sera seul responsable de ces données. Il peut ensuite les distribuer à ses composants enfants, à travers les ***props***.
C'est dans `App` que l'on va aussi pouvoir faire la restauration depuis le localStorage des EDTs précédemment téléchargés. Si on n'en trouve pas, alors on initialise alors une variable vide :
```jsx
const [availableTimetables, setAvailableTimetables] = useState(JSON.parse(localStorage.getItem(LOCAL_STORAGE_TIMETABLES)) || {});
```
Des exemples d'utilisation du ***Lift Up State*** :
- l'affichage du module de gestion des EDTs dans `App` :
```jsx
<LoginSelector
availableLogins={Object.keys(availableTimetables)}
selectedLogins={selectedLogins}
selectedLoginsColor={studentColors}
onChangeSelectedLogin={onSelectedLoginChange}
onDeleteLogin={onDeleteLogin}
onUnselectAll={onUnselectAll}
onSelectAll={onSelectAll}
onDeleteAllTimetables={onDeleteAllTimetables}
/>
```
- l'affichage du module de téléchargement des EDTs dans `App` :
```jsx
<LoginRetriever
onTimetableFetched={storeFetchedTimetable}
availableLogins={Object.keys(availableTimetables)}
/>
```
- l'affichage du composant d'affichage des EDTs dans `App` :
```jsx
<Schedule
selectedTimetables={getTimetablesOfStudents(selectedLogins)}
studentColors={studentColors}
/>
```
Toutes ces méthodes de callback permettant de modifier les variables d'états sont ainsi passés en ***props*** afin d'être utilisable par les composants fils.
Ainsi, toutes les actions conçernant la sélection des EDTs est effectuée dans `App`, car il y aura également des répercussions sur le composant d'affichage des EDTs. `App` étant le parent commun de ces 2 composants, c'est lui qui doit gérer ces variables-là. De même pour la coloration des UVs par étudiants : les couleurs doivent être accessibles depuis le composant de sélection, afin de colorier l'arrière-plan des logins sélectionnées, mais également par le composant d'affichage des EDTs, qui utilise ces couleurs pour colorer les évènements.
Les variables pouvant être utilisés par plusieurs modules sont ainsi factorisées dans `App`, qui gère leur vie. Chaque modification de ces variables passés en ***props*** entrainera le re-render des composants fils.
Tous les composants fils sont dans le dossier `src/childComponents/`.
---
### Le module de récupération des EDTs
La première étape pour pouvoir afficher l'emploi du temps d'un étudiant est de récupérer son login, et de télécharger son emploi du temps. C'est dans le fichier `LoginRetriever.js` qu'est défini le composant `LoginRetriever` qui gère ce comportement. Visuellement, nous avons donc une boîte de type texte pour saisir le login, et un bouton pour télécharger l'EDT.
Par défaut nous voyons *User login*, et le bouton **Retrieve timetable** en vert.

Mais si on entre le login d'un utilisateur et que celui si est valide alors on aura par défaut le login entré et sur le bouton update Timetable.

Ce changement se fait grâce au hook d'effet.
Une fois le login entré on utilise la fonction `handleSubmit`. Fonction déclenchée une fois que l'on a cliqué sur le bouton. Si le login est valide on initialise setIsSearching à true, setError à NULL et on appelle `fetchTimetable` qui va utiliser l'`API` pour récupérer les informations de l'étudiant :
`https://corsanywhere.herokuapp.com/https://webapplis.utc.fr/Edt_ent_rest/myedt/result/?login=${login}`
Nous sommes obligés de passer par `https://corsanywhere.herokuapp.com/` afin d'éviter les erreurs ***CORS***.
Les données récupérées sont au format `JSON`. Si la réponse est vide `(json.length === 0)` alors on renvoie une erreur : cela signifie que le login saisi n'existe pas. On affiche également une erreur si le code de retour n'est pas `200`.
Sinon, l'EDT téléchargé est passé à `App` grâce à la fonction passée en ***prop*** : `onTimetableFetched`. Cette fonction permet d'enregistrer le nouvel emploi du temps téléchargé, et de mettre à jour tous les composants pour prendre en compte ce nouvel EDT. Dans `App`, on peut très facilement mettre à jour le localStorage grâce au hook suivant qui sera appelé a chaque modification des EDTs, dans la variable `availableTimetables` :
```jsx
// Update the local storage after a fetched timetable change
useEffect(() => {
localStorage.setItem(LOCAL_STORAGE_TIMETABLES,JSON.stringify(availableTimetables));
}, [availableTimetables]);
```
La gestion des EDTs téléchargée se fait grâce à `LoginSelector.js` et l'affichage de l'emploi du temps grâce à `Schedule.js`.
Une fois téléchargé, l'EDT est automatiquement sélectionné et affiché.
### Le composant d'affichage des EDTs
L'affichage de l'emploi du temps est assurée par `Schedule.js`, un composant basé sur le composant de **Syncfusion** :`ScheduleComponent`.
Comme vu précédemment on a choisi d'utiliser les modules de schedule pour l'affichage de l'emploie du temps. Il nous faut tout d'abord importer tous les éléments que nous souhaitons utiliser dans notre calendrier.
On peut définir les modes de vues du calendrier ainsi :
``` jsx
<ViewsDirective>
<ViewDirective option='Day'/>
<ViewDirective option='Week'/>
<ViewDirective option='WorkWeek'/>
<ViewDirective option='Month'/>
</ViewsDirective>
<Inject services={[Day, Week, WorkWeek, Month, Agenda]}/>
```
Pour le reste on définit les propriétés du calendrier et les paramètres
à l'intérieur des balises `<ScheduleComponent ... </ScheduleComponent>`.
``` jsx
<ScheduleComponent
allowDragAndDrop={false}
currentView='WorkWeek'
readonly={true}
eventSettings={{dataSource: coursesEventList}}
workDays={workDays}
showWeekNumber={true}
workHours={{highlight: true, start: '08:00', end: '20:00'}}
startHour='08:00'
endHour='20:00'
eventRendered={onEventRendered}
cssClass="schedule-cells" //Pour patcher la hauteur des cellules
timeScale={{
enable: true,
interval: 60,
slotCount: 4
}}>
...
</ScheduleComponent>);
```
`Schedule.js` contient également tout l'arsenal nécessaire pour créer et convertir un emploi du temps, à partir des données téléchargées précédemment. Ainsi, les EDTs sous forme `JSON` bruts passés en ***props*** permettent de générer ,grâce à plusieurs fonctions, les évènements récurrents qui constituent l'EDT, et de définir leur date de début, de fin, etc.
`coursesEventList` est la variable contenant la liste des évènements à afficher. Cette liste est créée par la fonction `createEventListFromTimetables` qui utilise les fichiers `JSON` téléchargés par le composant `LoginRetriever`. La coloration par UV est également directement effectué dans ce module, a contrario de la coloration par étudiant effectuée dans `App`.
### Le composant de gestion des EDTs téléchargés
Ce composant permet de sélectionner, déselectionner ou supprimer individuellement ou tout d'un coup des EDTs téléchargés, à travers une interface simple d'utilisation.
Pour sélectionner un EDT à afficher, il suffit de cliquer sur le login correspondant. Alors, le fond du login se colore, en bleu si un seul est sélectionné, ou dans la couleur de l'étudiant et des ses UVs, si plusieurs EDTs sont sélectionnés. Les couleurs et les logins disponibles sont, comme toujours, passés en ***props***, car c'est `App` qui en est responsable. La génération du menu se fait alors à la volée lors du rendering du composant. A travers ces fonctions de callback, il est possible de supprimer, sélectionner, ou déselectionner les EDTs au niveau de `App`.
Voici un exemple d'utilisation de ce composant, lorsque `chelleva`, `mdommerg` et `hussonlo` sont sélectionnés, mais pas `lafondco` :

Le `Schedule` associé est le suivant :

## 3. Galerie de capture d'écrans et vidéo
### Vidéo de présentation de l'utilisation de l'application
https://www.youtube.com/watch?v=CUnpKoM5bBo
### Vue générale
- `chelleva` et `lafondco` sont sélectionnés. La coloration se fait donc par étudiant.

### Téléchargement d'un EDT
- Etat normal du bouton au démarrage de l'application

- Etat du bouton après saisie d'un login non déjà téléchargé

- Etat du bouton après avoir été cliqué, lorsque le téléchargement de l'EDT est en cours

- Le bouton devient jaune afin d'avertir l'utilisateur que l'EDT est déjà téléchargé.

- Etat du bouton après une erreur de téléchargement

### Affichage de l'emploi du temps de personne

### Affichage de l'emploi du temps d'une personne (`chelleva`)
- en vue Semaine de travail :

- en vue Mois :

- en vue Jour :

- en vue Semaine complète :

### Affichage de l'emploi du temps de deux personnes (`chelleva` et `lafondco`)

### Affichage de l'emploi du temps de quatre personnes

### Affichage d'erreur
- erreur réseau

- login invalide

### Les 3 boutons
- Tout sélectionner / Tout déselectionner / Tout supprimer

Des tooltips sont également visibles sur tous les boutons.
### Changement de la date courante

### Visuel d'un cours sur le calendrier

### L'application s'adapte à la taille de l'écran

## 4. Instructions d'installation
Le code source de notre projet est disponible sur ce lien git: https://gitlab.utc.fr/vlou-uvs/gi04/sr03-all/sr03-projet-4
Nous avons utilisé Intellij IDEA pour travailler sur le projet.
Pour l'installation, vous devez disposer de :
- npm :
```
npm install
```
- iwanthue :
```
npm install iwanthue
```
- bootstrap:
```
npm install bootstrap
```
- yarn :
```
yarn install
```
Pour lancer l'application :
```
yarn start
```
Pour accéder à l'application il suffit de rentrer l'adresse : `http://localhost:3000` dans un navigateur