Liste : jour de semaine dans l'en-tête + bouton dédié d'ajout par journée

Retour d'usage : avec plusieurs journées ouvertes, viser le bouton principal
d'ajout en traversant la liste faisait dériver la date ciblée (le survol pilote
la journée affichée sur la carte).

- En-tête de journée réorganisé : jour de la semaine avant la date (ex. « Lundi
  15/09/2026 »), nombre de trajets à la suite, puis un bouton dédié « + » à
  l'extrémité droite (infobulle « Ajouter un trajet sur cette journée »).
- Le bouton « + » ouvre la création avec la date de SA journée, indépendamment
  de la date affichée sur la carte (Output ajouterSurJournee -> conteneur fixe
  lun. 21 sept. 2026 12:54:31 CEST avant ouverture via ouvrirCreationSur). stopPropagation pour ne pas
  déclencher le repliage/dépliage au clic.
- Style : fond bleu IAD / texte blanc par défaut, survol orange (cohérent avec
  les autres boutons d'action).
- Locale française enregistrée (registerLocaleData(localeFr) + LOCALE_ID
  'fr-FR' dans app.config.ts) pour l'affichage du jour de la semaine.

Specs : requirements.md (exigence 12, critères 6 et 24) et design.md
(TrajetListComponent, locale) mis à jour.
This commit is contained in:
2026-09-21 12:54:31 +02:00
parent 91b59d4ce7
commit 058481c192
8 changed files with 110 additions and 19 deletions
+9 -2
View File
@@ -1,11 +1,17 @@
import { ApplicationConfig, provideZonelessChangeDetection } from '@angular/core';
import { ApplicationConfig, LOCALE_ID, provideZonelessChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import { routes } from './app.routes';
import { authInterceptor } from './core/interceptors/auth.interceptor';
import { timeoutInterceptor } from './core/interceptors/timeout.interceptor';
// Locale française : nécessaire pour que le pipe `date` (ex. 'EEEE' → jour de la
// semaine) affiche les noms en français plutôt qu'en anglais par défaut.
registerLocaleData(localeFr);
export const appConfig: ApplicationConfig = {
providers: [
// Détection de changement SANS zone.js (zoneless). L'état affiché est exposé via
@@ -19,6 +25,7 @@ export const appConfig: ApplicationConfig = {
// - timeoutInterceptor : timeout 10s + gestion des erreurs réseau (Exigence 1.9).
// authInterceptor est placé AVANT timeoutInterceptor pour injecter le Bearer
// avant le contrôle de timeout.
provideHttpClient(withInterceptors([authInterceptor, timeoutInterceptor]))
provideHttpClient(withInterceptors([authInterceptor, timeoutInterceptor])),
{ provide: LOCALE_ID, useValue: 'fr-FR' }
]
};
@@ -71,6 +71,7 @@
(insertBetween)="onInsert($event)"
(changed)="onListeChangee()"
(survol)="onSurvolTrajet($event)"
(ajouterSurJournee)="ouvrirCreationSur($event)"
></app-trajet-list>
</div>
</main>
@@ -212,6 +212,19 @@ export class ConsultationJourComponent implements OnInit, OnDestroy {
this.formulaire.set({ type: 'create' });
}
/**
* Ouvre le formulaire de création avec la date FIXÉE sur `dateIso` (bouton « + » de
* l'en-tête d'une journée). Cale `date` avant l'ouverture, afin que la date par
* défaut du formulaire soit celle voulue, indépendamment d'un éventuel survol en
* cours (qui pilote aussi `date`, mais un clic explicite doit primer).
*/
ouvrirCreationSur(dateIso: string): void {
if (dateIso) {
this.date.set(dateIso);
}
this.formulaire.set({ type: 'create' });
}
/** Ouvre le formulaire en mode édition (Output `edit` de la liste). */
onEdit(trajet: Trajet): void {
this.formulaire.set({ type: 'edit', trajet });
@@ -7,17 +7,31 @@
[class.jour--affiche]="estJourAffiche(groupe)"
aria-label="Trajets d'une journée"
>
<!-- En-tête repliable : chevron + date + nombre de trajets. -->
<button
type="button"
class="jour__entete"
[attr.aria-expanded]="estOuvert(groupe)"
(click)="basculerJour(groupe)"
>
<span class="jour__chevron" aria-hidden="true">{{ estOuvert(groupe) ? '▾' : '▸' }}</span>
<span class="jour__date">{{ groupe.date | date: 'dd/MM/yyyy' }}</span>
<span class="jour__compteur">{{ groupe.trajets.length }} trajet{{ groupe.trajets.length > 1 ? 's' : '' }}</span>
</button>
<!-- En-tête repliable : chevron + jour de semaine + date + nombre de trajets,
puis un bouton « + » dédié pour ajouter un trajet SUR CETTE JOURNÉE (indépendant
de la date affichée sur la carte, pilotée par le survol : viser le bouton
principal d'ajout en traversant plusieurs journées ouvertes ferait dériver la
date ciblée). -->
<div class="jour__entete" [attr.aria-expanded]="estOuvert(groupe)">
<button
type="button"
class="jour__entete-bouton"
(click)="basculerJour(groupe)"
>
<span class="jour__chevron" aria-hidden="true">{{ estOuvert(groupe) ? '▾' : '▸' }}</span>
<span class="jour__date">{{ groupe.date | date: 'EEEE dd/MM/yyyy' }}</span>
<span class="jour__compteur">{{ groupe.trajets.length }} trajet{{ groupe.trajets.length > 1 ? 's' : '' }}</span>
</button>
<button
type="button"
class="jour__ajouter"
title="Ajouter un trajet sur cette journée"
aria-label="Ajouter un trajet sur cette journée"
(click)="ajouterSur(groupe, $event)"
>
+
</button>
</div>
@if (estOuvert(groupe)) {
<ul
@@ -10,30 +10,65 @@
.jour {
padding: 0.5rem 0;
// Conteneur de l'en-tête : le bouton de repliage (zone cliquable principale) et,
// à droite, le bouton dédié « + » (ajouter un trajet sur cette journée).
&__entete {
display: flex;
align-items: center;
align-items: stretch;
gap: 0.5rem;
width: 100%;
margin: 0 0 0.4rem;
padding: 0.4rem 0.5rem;
font-size: 0.85rem;
font-weight: 700;
color: #334155;
background: #f1f5f9;
border: 1px solid #e2e8f0;
border-radius: 6px;
text-align: left;
cursor: pointer;
position: sticky;
top: 0;
z-index: 1;
}
&__entete-bouton {
display: flex;
align-items: center;
gap: 0.5rem;
flex: 1 1 auto;
min-width: 0;
padding: 0.4rem 0.5rem;
border: none;
background: transparent;
color: inherit;
font: inherit;
text-align: left;
cursor: pointer;
border-radius: 6px 0 0 6px;
&:hover {
background: #e9eef4;
}
}
// Bouton dédié : ajouter un trajet SUR CETTE JOURNÉE, indépendant de la date de
// la carte (pilotée par le survol). Toujours visible, à droite de l'en-tête.
&__ajouter {
flex: 0 0 auto;
width: 2rem;
margin: 0.25rem 0.25rem 0.25rem 0;
border: none;
border-radius: 4px;
background: var(--couleur-bleu, #1976d2);
color: #fff;
font-size: 1.1rem;
font-weight: 700;
line-height: 1;
cursor: pointer;
&:hover {
background: var(--couleur-orange, #f28c28);
}
}
// Journée affichée sur la carte : en-tête accentué (bleu) pour la repérer.
&--affiche &__entete {
background: #e3f0ff;
@@ -42,6 +77,7 @@
box-shadow: inset 3px 0 0 #1976d2;
}
&__chevron {
flex: 0 0 auto;
color: #64748b;
@@ -121,6 +121,14 @@ export class TrajetListComponent {
/** Émis pour insérer un trajet entre le courant et le suivant (Exigence 11.3/11.4). */
@Output() insertBetween = new EventEmitter<TrajetInsertionContext>();
/**
* Émis pour ajouter un Trajet sur une journée précise (date ISO `yyyy-MM-dd`), via
* le bouton « + » de l'en-tête de journée. Évite de dépendre de la date affichée sur
* la carte (pilotée par le survol), qui peut avoir dérivé pendant le déplacement de
* la souris vers le bouton.
*/
@Output() ajouterSurJournee = new EventEmitter<string>();
/**
* Émis lorsque la liste a changé (suppression, réordonnancement) et que le
* conteneur doit recharger la journée / le résumé mensuel (Exigences 5.7, 11.6).
@@ -244,6 +252,15 @@ export class TrajetListComponent {
});
}
/**
* Demande l'ajout d'un Trajet sur cette journée (bouton « + » de l'en-tête). Empêche
* la propagation du clic vers le bouton de repliage (l'en-tête est elle-même cliquable).
*/
ajouterSur(groupe: GroupeJour, event: MouseEvent): void {
event.stopPropagation();
this.ajouterSurJournee.emit(groupe.date);
}
/**
* Déplie explicitement la journée `dateIso` (`yyyy-MM-dd`), sans toucher aux autres.
* Appelé par le conteneur après l'ajout/insertion d'un trajet pour rendre la journée