From 0c9f280b7fd2770e987694a6ecabb63afe32c263 Mon Sep 17 00:00:00 2001 From: Nikolaz Date: Tue, 15 Sep 2026 21:05:46 +0200 Subject: [PATCH] =?UTF-8?q?Carte=20:=20navigation=20jour=20limit=C3=A9e=20?= =?UTF-8?q?aux=20jours=20ayant=20des=20trajets?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les boutons « Jour préc. » / « Jour suiv. » de la carte ne s'arrêtent plus sur tous les jours du mois mais uniquement sur les jours comportant des trajets. Exception : dans le mois en cours, le jour courant reste navigable même sans trajet (pour pouvoir y ajouter un trajet). - joursNavigables() : jours du mois avec trajets (+ aujourd'hui si mois courant), triés. La date affichée n'a pas besoin d'en faire partie. - jourNavigableAdjacent() : jour navigable strictement avant/après la date affichée ; boutons désactivés s'il n'y en a pas. - À la sélection d'un mois passé, la carte se recale sur le dernier jour ayant des trajets si le jour par défaut tombe sur une journée vide. Builds dev et prod OK. --- .../consultation-jour.component.ts | 101 ++++++++++++++---- 1 file changed, 81 insertions(+), 20 deletions(-) diff --git a/frontend/src/app/features/consultation-jour/consultation-jour.component.ts b/frontend/src/app/features/consultation-jour/consultation-jour.component.ts index d50c383..9a5ec05 100644 --- a/frontend/src/app/features/consultation-jour/consultation-jour.component.ts +++ b/frontend/src/app/features/consultation-jour/consultation-jour.component.ts @@ -111,6 +111,12 @@ export class ConsultationJourComponent implements OnInit, OnDestroy { private jourSub?: Subscription; private vehiculesSub?: Subscription; + /** + * Indique qu'après le prochain chargement mensuel, la date affichée doit être + * recalée sur un jour ayant des trajets (activé lors d'une sélection de mois). + */ + private recalerJourApresChargement = false; + ngOnInit(): void { // Par défaut : mois courant, et jour = aujourd'hui (contenu dans le mois courant). const auj = new Date(); @@ -135,6 +141,9 @@ export class ConsultationJourComponent implements OnInit, OnDestroy { this.mois.set(selection); this.date.set(this.jourParDefautDuMois(selection.annee, selection.mois)); this.formulaire.set(null); + // Une fois les trajets du mois chargés, recaler la carte sur un jour ayant des + // trajets (le jour par défaut peut tomber sur une journée vide d'un mois passé). + this.recalerJourApresChargement = true; this.rafraichirJournee(); } @@ -146,51 +155,85 @@ export class ConsultationJourComponent implements OnInit, OnDestroy { this.rafraichirJournee(); } - // --- Navigation jour ±1, BORNÉE AU MOIS sélectionné --- + // --- Navigation jour, LIMITÉE AUX JOURS AYANT DES TRAJETS --- /** - * Jour affiché sur la carte : navigue vers le jour précédent DANS LE MOIS. Seul - * `date` change (le mois reste inchangé) ; la carte est rechargée. + * Jour affiché sur la carte : navigue vers le jour ayant des trajets précédent + * (dans le mois). Seul `date` change ; la carte est rechargée. */ jourPrecedent(): void { - if (this.jourPrecedentDesactive) { + const cible = this.jourNavigableAdjacent(-1); + if (cible == null) { return; } - this.date.set(this.decalerJour(this.dateCourante(), -1)); + this.date.set(cible); this.formulaire.set(null); this.rafraichirCarteJour(); } /** - * Jour affiché sur la carte : navigue vers le jour suivant DANS LE MOIS. Seul - * `date` change (le mois reste inchangé) ; la carte est rechargée. + * Jour affiché sur la carte : navigue vers le jour ayant des trajets suivant + * (dans le mois). Seul `date` change ; la carte est rechargée. */ jourSuivant(): void { - if (this.jourSuivantDesactive) { + const cible = this.jourNavigableAdjacent(1); + if (cible == null) { return; } - this.date.set(this.decalerJour(this.dateCourante(), 1)); + this.date.set(cible); this.formulaire.set(null); this.rafraichirCarteJour(); } - /** « Jour préc. » désactivé si la date affichée est le 1er jour du mois sélectionné. */ + /** « Jour préc. » désactivé s'il n'existe pas de jour navigable antérieur. */ get jourPrecedentDesactive(): boolean { - return Number(this.dateCourante().slice(8, 10)) <= 1; + return this.jourNavigableAdjacent(-1) == null; + } + + /** « Jour suiv. » désactivé s'il n'existe pas de jour navigable postérieur. */ + get jourSuivantDesactive(): boolean { + return this.jourNavigableAdjacent(1) == null; } /** - * « Jour suiv. » désactivé si la date affichée est le dernier jour du mois - * sélectionné, OU si le jour suivant serait dans le futur. + * Jours navigables du mois affiché, triés en ordre croissant (ISO `yyyy-MM-dd`) : + * les jours comportant des trajets, plus le jour courant si le mois affiché est + * le mois en cours (afin de pouvoir cibler aujourd'hui même sans trajet). */ - get jourSuivantDesactive(): boolean { - const courante = this.dateCourante(); - const suivant = this.decalerJour(courante, 1); - // Sortie du mois affiché (le mois du jour suivant diffère de la date courante). - if (suivant.slice(0, 7) !== courante.slice(0, 7)) { - return true; + private joursNavigables(): string[] { + const jours = new Set( + this.trajets() + .map((t) => (t.date ?? '').slice(0, 10)) + .filter((d) => d.length === 10) + ); + + // Le jour courant reste accessible dans le mois en cours, même sans trajet. + const m = this.mois(); + const auj = new Date(); + if (m && m.annee === auj.getFullYear() && m.mois === auj.getMonth() + 1) { + jours.add(this.isoAujourdHui()); } - return suivant > this.isoAujourdHui(); + + return [...jours].sort(); + } + + /** + * Renvoie le jour navigable immédiatement avant (`direction < 0`) ou après + * (`direction > 0`) la date affichée, ou `null` s'il n'existe pas. La date + * courante n'a pas besoin d'appartenir à l'ensemble navigable. + */ + private jourNavigableAdjacent(direction: number): string | null { + const jours = this.joursNavigables(); + if (jours.length === 0) { + return null; + } + const courante = this.dateCourante(); + if (direction < 0) { + const anterieurs = jours.filter((j) => j < courante); + return anterieurs.length > 0 ? anterieurs[anterieurs.length - 1] : null; + } + const posterieurs = jours.filter((j) => j > courante); + return posterieurs.length > 0 ? posterieurs[0] : null; } /** Date courante affichée au format JJ/MM/AAAA (lisible), ou `—` si absente. */ @@ -326,6 +369,24 @@ export class ConsultationJourComponent implements OnInit, OnDestroy { // sans restriction au jour. Le tri final (date puis position) est assuré // par la liste elle-même. this.trajets.set(resume.trajets ?? []); + + // Recalage éventuel sur un jour ayant des trajets (après sélection d'un + // mois). Si la date par défaut n'est pas navigable (journée vide d'un mois + // passé), on cible le dernier jour du mois comportant des trajets. + if (this.recalerJourApresChargement) { + this.recalerJourApresChargement = false; + const jours = this.joursNavigables(); + const courante = this.date(); + if (jours.length > 0 && (courante == null || !jours.includes(courante))) { + const nouvelleDate = jours[jours.length - 1]; + this.date.set(nouvelleDate); + // Recharge la carte du jour recalé (le résumé/liste restent inchangés). + this.rafraichirCarteJour(); + this.cdr.markForCheck(); + return; + } + } + // Carte : trajets du jour filtrés par le véhicule sélectionné. this.trajetsCarte.set( this.vehiculeId() == null