etape4
This commit is contained in:
@@ -1,21 +1,113 @@
|
||||
# Étape 4 — Vue 2 : profil complet
|
||||
|
||||
> **Prérequis :** [étape 3 — recherche](etape-03-vue-recherche.md) (navigation vers vue 2 avec login valide).
|
||||
> **Prérequis :** [étape 3 — recherche](etape-03-vue-recherche.md) (navigation vers vue 2 avec un login valide).
|
||||
|
||||
## Objectif sujet (partie obligatoire)
|
||||
## Objectif sujet
|
||||
|
||||
| Exigence | Détail |
|
||||
|----------|--------|
|
||||
| ≥ 4 infos | login, email, mobile, level, location, wallet, evaluations, … |
|
||||
| Photo | Image de profil (`image_url` / `image.link` selon API) |
|
||||
| Skills | Niveau + pourcentage |
|
||||
| Projets | Terminés **y compris failed** |
|
||||
| Retour | Bouton retour vers vue 1 |
|
||||
| Layout | Responsive (étape 5 peut affiner) |
|
||||
| Exigence | Cette étape |
|
||||
|----------|-------------|
|
||||
| ≥ 4 infos + photo | login (titre / avatar), email, téléphone, niveau cursus, localisation, wallet |
|
||||
| Skills | Niveau entier + **pourcentage** (partie décimale du `level` API) |
|
||||
| Projets | Statuts **`finished`** et **`failed`** |
|
||||
| Erreurs | Réseau, 401, réponse API inattendue — message + réessai |
|
||||
| Token | Un seul OAuth : `IntraAuthService` pour tous les `GET` |
|
||||
| Retour vue 1 | `AppBar` + bouton retour système (`Navigator.pop`) |
|
||||
| Layout | `LayoutBuilder` : colonne sur téléphone, 2 colonnes si largeur ≥ 720 px |
|
||||
|
||||
## API
|
||||
---
|
||||
|
||||
- `GET /v2/users/{id}` avec champs / includes selon apidoc (`cursus_users`, `projects_users`, `skills`, etc.).
|
||||
- Token : toujours via `IntraAuthService`.
|
||||
## Parcours utilisateur (vue 2)
|
||||
|
||||
Guide détaillé à rédiger quand l’étape 3 est codée — demande l’implémentation pas à pas dans le chat.
|
||||
1. Arrivée depuis la recherche avec un objet `user` minimal (`id`, `login`, parfois `image`).
|
||||
2. **Chargement** : appels API en parallèle (spinner plein écran).
|
||||
3. **Succès** : photo, carte « Informations », liste skills, liste projets.
|
||||
4. **Échec** : message rouge + bouton **Réessayer**.
|
||||
5. **Retour** : flèche AppBar → vue 1, nouvelle recherche possible.
|
||||
|
||||
---
|
||||
|
||||
## API 42 utilisée
|
||||
|
||||
Doc : [api.intra.42.fr/apidoc](https://api.intra.42.fr/apidoc)
|
||||
|
||||
| Donnée | Endpoint | Notes |
|
||||
|--------|----------|--------|
|
||||
| Fiche user | *(déjà renvoyée par la recherche étape 3)* | email, phone, location, wallet, image — pas de 2ᵉ `GET /users/{id}` pour limiter le quota |
|
||||
| Fiche complète | `GET /v2/users/{login}` | inclut souvent `cursus_users` + `skills` par cursus |
|
||||
| Niveau / skills | `cursus_users[].skills` | pas `/experiences` (souvent **403** avec token étudiant) |
|
||||
| Projets | `GET /v2/users/{id}/projects_users?page[size]=100` | scope OAuth **`projects`** ; filtrer côté app : `finished` / `failed` |
|
||||
|
||||
Tous les appels :
|
||||
|
||||
```http
|
||||
Authorization: Bearer <access_token>
|
||||
Accept: application/json
|
||||
```
|
||||
|
||||
**Confidentialité :** certains champs peuvent être masqués par l’API selon le profil consulté — afficher `—` si absent (sujet OAuth).
|
||||
|
||||
### Skills — niveau et pourcentage
|
||||
|
||||
L’API renvoie un `level` flottant (ex. `8.42`) :
|
||||
|
||||
- **Niveau affiché** : partie entière (`8`)
|
||||
- **Pourcentage** : partie décimale × 100 (`42 %`)
|
||||
|
||||
---
|
||||
|
||||
## Fichiers (étape 4)
|
||||
|
||||
```
|
||||
lib/
|
||||
├── services/
|
||||
│ ├── intra_auth_service.dart # existant — headers Bearer
|
||||
│ ├── intra_user_service.dart # existant — recherche
|
||||
│ └── intra_profile_service.dart # NEW — agrégation profil
|
||||
└── screens/
|
||||
└── profile_screen.dart # StatefulWidget — chargement + UI
|
||||
```
|
||||
|
||||
### `IntraProfileService`
|
||||
|
||||
- `fetchProfile(Map<String, dynamic> summaryUser)` → `IntraUserProfile`
|
||||
- Requêtes **séquentielles** (pause ~450 ms) + retry sur 429 (`intra_http.dart`)
|
||||
- Cache profil 2 min par `user_id` pour éviter de re-taper l’API au retour arrière
|
||||
- Mêmes exceptions que l’étape 3 : `IntraNetworkException`, `IntraUnauthorizedException`, etc.
|
||||
|
||||
### `ProfileScreen`
|
||||
|
||||
- Reçoit le `user` de l’étape 3
|
||||
- `initState` → `_load()`
|
||||
- Pas de second OAuth
|
||||
|
||||
---
|
||||
|
||||
## Gestion des erreurs (vue 2)
|
||||
|
||||
| Situation | Comportement |
|
||||
|-----------|----------------|
|
||||
| Pas de réseau | Message + **Réessayer** |
|
||||
| Token expiré (401) | « Session expirée… » — reconnecter depuis vue 1 |
|
||||
| Trop de requêtes (429) | Message dédié ; retry automatique côté client + attendre avant de réessayer |
|
||||
| Accès refusé (403) | Scopes `public` + `projects` sur l’app OAuth, puis **reconnexion** dans l’app |
|
||||
| ID manquant | Erreur métier explicite |
|
||||
| Listes vides skills / projets | Texte informatif, pas de crash |
|
||||
|
||||
---
|
||||
|
||||
## Critères « étape 4 terminée »
|
||||
|
||||
| # | Test |
|
||||
|---|------|
|
||||
| 1 | Login valide → photo + au moins 4 champs remplis ou `—` |
|
||||
| 2 | Section skills avec niveau **et** pourcentage |
|
||||
| 3 | Au moins un projet `finished` ou `failed` visible (si l’étudiant en a) |
|
||||
| 4 | Mode avion sur vue 2 → erreur + réessai |
|
||||
| 5 | Retour → vue 1 sans perdre la session OAuth |
|
||||
| 6 | Largeur tablette / fenêtre large → mise en page 2 colonnes |
|
||||
|
||||
---
|
||||
|
||||
## Ensuite — étape 5
|
||||
|
||||
→ Affiner navigation, contraintes et polish responsive sur **les deux vues** (`etape-05-navigation-layout.md` à rédiger).
|
||||
|
||||
Reference in New Issue
Block a user