Carte : navigation jour limitée aux jours ayant des trajets

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.
This commit is contained in:
2026-09-15 21:05:46 +02:00
parent 3342fd8ec2
commit 0c9f280b7f
@@ -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<string>(
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