@@ -88,5 +88,54 @@ L'application utilise un système de routage manuel natif basé sur l'API `windo
* Affichage conditionnel des composants via les directives natives `if={ state.view === ... }`.
***
## Cycle de vie de l'application
### Initialisation de la carte dans map-view.riot
```javascript
onMounted(){
this.map=L.map(element).setView([46.8,2.5],6)// crée la carte Leaflet
L.tileLayer('https://...').addTo(this.map)// ajoute les tuiles OpenStreetMap
}
```
**Étape 9 — L'application est prête, elle attend l'utilisateur**
À ce stade le navigateur affiche la page avec la barre de recherche, la carte vide centrée sur la France, et aucun résultat. Tout est en mémoire, prêt à réagir.
**Étape 10 — L'utilisateur interagit**
```
L'utilisateur tape "BUT informatique" et clique Rechercher
→ le navigateur déclenche l'événement onclick sur le bouton
→ Riot appelle submitSearch() dans search-bar.riot
→ qui appelle props.onsearch(requete, filtres)
→ qui appelle lancerRecherche() dans app.riot
→ qui appelle chargerPage(1)
→ qui appelle fetch() vers l'API
→ l'API retourne le JSON
→ app.riot fait this.update({ resultats: formations })
- Sauvegarde des données dans Firestore avec `setDoc(doc(db, "users", uid), data, { merge: true })`
-`merge: true` → ne **pas écraser** les champs existants, juste **fusionner**
### `loadUserData(uid)` *(async)*
- Lit un document Firestore avec `getDoc(doc(db, "users", uid))`
- Vérifie avec `snap.exists()` avant de retourner `snap.data()`
---
## 📄 `formation.js` — Transformation des données
### `creerFormation(brut)` *(exportée)*
- **Rôle** : Prend un enregistrement brut de l'API (avec des noms de champs techniques comme `lib_for_voe_ins`, `voe_tot`, `acc_tot`…) et retourne un objet **propre et lisible**.
- **Concepts clés** :
- Objet littéral `{}`
- Accès aux propriétés imbriquées : `brut.g_olocalisation_des_formations.lat`
-`Math.round()` pour calculer `tauxAcces`
- Valeurs par défaut avec `||` : `brut.voe_tot || 0`
---
## 📄 `app.riot` — Composant principal (Riot.js)
### Cycle de vie Riot.js
| Méthode | Déclenchement |
|---|---|
| `onMounted()` | Quand le composant est ajouté au DOM |
| `onUpdated()` | Après chaque `this.update()` |
| `onBeforeUnmount()` | Juste avant la suppression du composant |
### `onMounted()`
- Lit la sélection sauvegardée avec `localStorage.getItem('selectionFormations')`
- Parse le JSON avec `JSON.parse(saved)` (dans un `try/catch`)
- Appelle `window.firebaseServices.onUserChanged(...)` pour surveiller la connexion
- Écoute les changements de hash URL avec `window.addEventListener('hashchange', ...)`
- Appelle `this.gererRoute()` pour démarrer le bon affichage
### `gererRoute()`
- **Rôle** : Système de **routing par hash** (`#/`, `#/formation/id`, `#/comparateur`)
- Lit `window.location.hash`
- Utilise `chemin.startsWith('/formation/')` et `decodeURIComponent()`
- Met à jour `state.view` pour afficher le bon écran
### `chargerFormationParId(id)` *(async)*
- Cherche d'abord dans `state.results`, puis dans `state.selectedFormations`
- Si non trouvé → appelle `window.chargerFormations()` pour récupérer depuis l'API
### `lancerRecherche(requete, filtres)` *(async)*
- Remet `page` à 1, met `loading: true`, puis appelle `this.chargerPage(1)`
| **Firebase Firestore** | Stockage de la sélection en cloud | CDN (`gstatic.com`) |
| **Riot.js** | Framework composants UI | Via `index.html` |
| **Leaflet.js (`L`)** | Carte interactive | Via `index.html` (variable globale `L`) |
| **Charts.css** | Graphiques en CSS pur | Via `index.html` |
| **API Open Data Parcoursup** | Données des formations | `fetch()` vers `data.enseignementsup-recherche.gouv.fr` |
| **OpenStreetMap** | Tuiles de fond de carte | URL `tile.openstreetmap.org` |
---
## ❓ Questions probables du prof — Réponses préparées
**Q : Pourquoi utilises-tu `async/await` ?**
→ Parce que `fetch()` et les appels Firebase sont **asynchrones** (ils prennent du temps). Sans `await`, le code continuerait sans attendre la réponse, ce qui rendrait le résultat `undefined`.
**Q : À quoi sert `encodeURIComponent()` ?**
→ L'URL ne peut pas contenir certains caractères spéciaux (espaces, apostrophes, `&`...). Cette fonction les convertit en codes URL sûrs (ex: `%20` pour l'espace).
**Q : Pourquoi utilises-tu `localStorage` ?**
→ Pour **persister** la sélection de formations entre les visites, même sans être connecté. C'est un stockage côté navigateur, sans serveur.
**Q : Qu'est-ce que `e.preventDefault()` ?**
→ Empêche le **comportement par défaut** du navigateur. Sur un `<form>`, le comportement par défaut est de recharger la page. On l'annule pour gérer la soumission en JavaScript.
**Q : Pourquoi `this.carte.remove()` dans `onBeforeUnmount()` ?**
→ Leaflet attache des **event listeners** et occupe de la mémoire. Si on ne détruit pas proprement la carte, cela crée des **memory leaks** (fuites mémoire).
**Q : Qu'est-ce que `merge: true` dans Firestore `setDoc(...)` ?**
→ Cela **fusionne** les données avec celles existantes au lieu de tout écraser. Utile pour ne mettre à jour qu'un seul champ (la sélection) sans toucher aux autres.
**Q : Comment fonctionne le routing de ton app ?**
→ On utilise les **hash URL** (`#/`, `#/formation/id`, `#/comparateur`). On écoute l'événement `hashchange` pour détecter les changements, et on affiche le bon écran via `state.view`. C'est un routing côté client, sans rechargement de page — c'est ce qu'on appelle une **SPA** (Single Page Application).
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.