From f3465e04d2663ee0d5e09f39af321573549bd1bd Mon Sep 17 00:00:00 2001 From: Nikolaz Date: Tue, 15 Sep 2026 19:53:16 +0200 Subject: [PATCH] =?UTF-8?q?Corrections=20UX=20:=20premi=C3=A8re=20connexio?= =?UTF-8?q?n,=20carte=20Leaflet=20en=20prod,=20mise=20en=20page?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Onboarding : redirection automatique vers /register lorsqu'aucun compte n'existe (première utilisation), au lieu d'afficher la page de connexion. - Carte Leaflet en production : import normalisé (Leaflet est CommonJS, l'API pouvait se retrouver sous .default en build prod -> échec d'initialisation). Nettoyage du marqueur _leaflet_id du conteneur pour que « Réessayer » fonctionne après un échec. Logs d'erreur explicites en cas d'échec d'import/init. - Mise en page : layout applicatif en flex pleine hauteur (nav de hauteur naturelle,
occupe le reste et défile si besoin) sans étirer les vues courtes. La vue Trajets occupe l'espace restant (height:100%) sans scrollbar de page : seule la liste défile. Reset global (body margin 0, box-sizing border-box) supprimant la scrollbar de page parasite. - Centrage uniforme des pages : ajout de margin:0 auto aux vues profil, véhicules, barème, résumé mensuel/annuel et montants réglés (comme trajets et carnet). Builds backend (solution) et frontend (production) OK. --- frontend/src/app/app.component.scss | 18 ++++--------- .../features/auth/login/login.component.ts | 9 ++++++- .../app/features/bareme/bareme.component.scss | 1 + .../carte-trajets/carte-trajets.component.ts | 26 ++++++++++++++++--- .../consultation-jour.component.scss | 4 +++ .../montants-regles.component.scss | 1 + .../app/features/profil/profil.component.scss | 1 + .../resume-annuel.component.scss | 1 + .../resume-mensuel.component.scss | 1 + .../vehicules/vehicules.component.scss | 1 + frontend/src/styles.scss | 10 +++++++ 11 files changed, 56 insertions(+), 17 deletions(-) diff --git a/frontend/src/app/app.component.scss b/frontend/src/app/app.component.scss index 23766c9..e075593 100644 --- a/frontend/src/app/app.component.scss +++ b/frontend/src/app/app.component.scss @@ -1,12 +1,12 @@ :host { display: flex; flex-direction: column; - height: 100vh; + height: 100dvh; min-height: 0; } .nav-bar { - flex: 0 0 auto; + flex: 0 0 auto; // hauteur naturelle (même si les liens passent sur plusieurs lignes) display: flex; flex-wrap: wrap; align-items: center; @@ -37,18 +37,10 @@ } } - -/* Le contenu routé occupe toute la hauteur restante sous le menu. - Les vues qui le souhaitent (ex. consultation) peuvent ainsi figer leur mise en page - et ne faire défiler qu'une sous-zone interne. */ +/* Le contenu routé occupe la hauteur restante sous le menu et défile si nécessaire. + Les vues courtes gardent leur hauteur naturelle (aucun flex:1 imposé aux enfants). */ main { flex: 1 1 auto; min-height: 0; - display: flex; - flex-direction: column; -} - -main > * { - flex: 1 1 auto; - min-height: 0; + overflow-y: auto; } diff --git a/frontend/src/app/features/auth/login/login.component.ts b/frontend/src/app/features/auth/login/login.component.ts index 1d6db7e..897ca0f 100644 --- a/frontend/src/app/features/auth/login/login.component.ts +++ b/frontend/src/app/features/auth/login/login.component.ts @@ -56,7 +56,14 @@ export class LoginComponent implements OnInit { }); this.authService.compteExiste().subscribe({ - next: (resultat) => this.compteExiste.set(resultat.existe), + next: (resultat) => { + this.compteExiste.set(resultat.existe); + // Première utilisation (aucun compte) : on va directement à l'inscription + // pour simplifier le parcours, plutôt que d'afficher la connexion. + if (!resultat.existe) { + this.router.navigate(['/register']); + } + }, // En cas d'échec, on conserve la valeur par défaut (masque l'inscription). error: () => this.compteExiste.set(true) }); diff --git a/frontend/src/app/features/bareme/bareme.component.scss b/frontend/src/app/features/bareme/bareme.component.scss index b266631..133771b 100644 --- a/frontend/src/app/features/bareme/bareme.component.scss +++ b/frontend/src/app/features/bareme/bareme.component.scss @@ -1,6 +1,7 @@ .bareme { padding: 1.5rem; max-width: 960px; + margin: 0 auto; } h1 { diff --git a/frontend/src/app/features/carte-trajets/carte-trajets.component.ts b/frontend/src/app/features/carte-trajets/carte-trajets.component.ts index 3b4499a..a374502 100644 --- a/frontend/src/app/features/carte-trajets/carte-trajets.component.ts +++ b/frontend/src/app/features/carte-trajets/carte-trajets.component.ts @@ -158,9 +158,18 @@ export class CarteTrajetsComponent implements AfterViewInit, OnChanges, OnDestro try { if (!this.L) { - this.L = await import('leaflet'); + const mod = await import('leaflet'); + // Leaflet est un module CommonJS : selon l'interop du bundler (dev vs prod), + // l'API peut se trouver sur le module lui-même ou sous `default`. On normalise. + const candidate = mod as unknown as { default?: typeof import('leaflet') }; + const api = candidate.default ?? (mod as typeof import('leaflet')); + // Vérifie que l'API attendue est présente (sinon l'init échouerait silencieusement). + this.L = (api && typeof (api as { map?: unknown }).map === 'function') + ? api + : (mod as typeof import('leaflet')); } - } catch { + } catch (e) { + console.error('Échec du chargement de Leaflet :', e); this.basculerErreur('La librairie de carte n\'a pas pu être chargée.'); return; } @@ -188,7 +197,8 @@ export class CarteTrajetsComponent implements AfterViewInit, OnChanges, OnDestro this.tileLayer.addTo(this.map); this.layerGroup = L.layerGroup().addTo(this.map); - } catch { + } catch (e) { + console.error('Échec de l\'initialisation de la carte Leaflet :', e); this.basculerErreur('La carte n\'a pas pu être initialisée.'); return; } @@ -446,5 +456,15 @@ export class CarteTrajetsComponent implements AfterViewInit, OnChanges, OnDestro this.map.remove(); this.map = null; } + // Filet de sécurité : si une initialisation précédente a échoué APRÈS que Leaflet + // ait marqué le conteneur (`_leaflet_id`) mais AVANT l'assignation de `this.map`, + // le node reste « déjà initialisé » et un nouvel appel à `L.map()` lèverait + // « Map container is already initialized » (Réessayer resterait alors sans effet). + // On nettoie donc explicitement le marqueur et le contenu résiduel du conteneur. + const node = this.mapContainer?.nativeElement as (HTMLElement & { _leaflet_id?: number }) | undefined; + if (node) { + delete node._leaflet_id; + node.innerHTML = ''; + } } } diff --git a/frontend/src/app/features/consultation-jour/consultation-jour.component.scss b/frontend/src/app/features/consultation-jour/consultation-jour.component.scss index 6305073..a11a072 100644 --- a/frontend/src/app/features/consultation-jour/consultation-jour.component.scss +++ b/frontend/src/app/features/consultation-jour/consultation-jour.component.scss @@ -1,7 +1,11 @@ :host { display: block; + // La vue occupe toute la hauteur de
(qui vaut le viewport moins la barre de + // navigation, quelle que soit sa hauteur réelle grâce au layout flex global). + // overflow:hidden : aucune scrollbar de page ; seule la sous-zone liste défile. height: 100%; min-height: 0; + overflow: hidden; } .consultation { diff --git a/frontend/src/app/features/montants-regles/montants-regles.component.scss b/frontend/src/app/features/montants-regles/montants-regles.component.scss index a26d771..3a3813c 100644 --- a/frontend/src/app/features/montants-regles/montants-regles.component.scss +++ b/frontend/src/app/features/montants-regles/montants-regles.component.scss @@ -1,6 +1,7 @@ .montants-regles { padding: 1.5rem; max-width: 720px; + margin: 0 auto; } h1 { diff --git a/frontend/src/app/features/profil/profil.component.scss b/frontend/src/app/features/profil/profil.component.scss index de01dbb..f0803ef 100644 --- a/frontend/src/app/features/profil/profil.component.scss +++ b/frontend/src/app/features/profil/profil.component.scss @@ -1,6 +1,7 @@ .profil { padding: 1.5rem; max-width: 640px; + margin: 0 auto; } h1 { diff --git a/frontend/src/app/features/resume-annuel/resume-annuel.component.scss b/frontend/src/app/features/resume-annuel/resume-annuel.component.scss index d30ed70..c39106d 100644 --- a/frontend/src/app/features/resume-annuel/resume-annuel.component.scss +++ b/frontend/src/app/features/resume-annuel/resume-annuel.component.scss @@ -1,6 +1,7 @@ .resume-annuel { padding: 1.5rem; max-width: 640px; + margin: 0 auto; } h1 { diff --git a/frontend/src/app/features/resume-mensuel/resume-mensuel.component.scss b/frontend/src/app/features/resume-mensuel/resume-mensuel.component.scss index 31e3eb7..8024a0f 100644 --- a/frontend/src/app/features/resume-mensuel/resume-mensuel.component.scss +++ b/frontend/src/app/features/resume-mensuel/resume-mensuel.component.scss @@ -1,6 +1,7 @@ .resume-mensuel { padding: 1.5rem; max-width: 900px; + margin: 0 auto; } h1 { diff --git a/frontend/src/app/features/vehicules/vehicules.component.scss b/frontend/src/app/features/vehicules/vehicules.component.scss index faa43a3..2379498 100644 --- a/frontend/src/app/features/vehicules/vehicules.component.scss +++ b/frontend/src/app/features/vehicules/vehicules.component.scss @@ -1,6 +1,7 @@ .vehicules { padding: 1.5rem; max-width: 720px; + margin: 0 auto; } h1 { diff --git a/frontend/src/styles.scss b/frontend/src/styles.scss index 911aad8..3e8900f 100644 --- a/frontend/src/styles.scss +++ b/frontend/src/styles.scss @@ -1,5 +1,15 @@ /* You can add global styles to this file, and also import other style files */ +/* Reset global minimal : supprime la marge par défaut du body (sinon 100dvh + 8px + provoque une scrollbar de page parasite) et fixe une base de rendu cohérente. */ +html, body { + margin: 0; + padding: 0; +} +*, *::before, *::after { + box-sizing: border-box; +} + /* Styles globaux des éléments de carte injectés par Leaflet (hors encapsulation des composants) : pastilles de marqueurs et contenu des infobulles. */ .carte-marqueur {