Carnet d'adresses : ajout/modification via une popup modale

- Formulaire de création/modification affiché dans une fenêtre modale
  (bouton « Ajouter une adresse » + action « Modifier » d'une ligne)
- Fermeture au succès, sur « Annuler » ou clic sur l'arrière-plan
- Suggestions BAN rendues dans le flux du panneau pour éviter la troncature
- Specs : Exigence 15 (nouveau critère 17) + description CarnetAdressesComponent
This commit is contained in:
2026-09-23 09:59:15 +02:00
parent ee47d04b90
commit 1c65c4dc74
5 changed files with 89 additions and 11 deletions
@@ -1,8 +1,18 @@
<section class="carnet">
<h1>Carnet d'adresses</h1>
<div class="carnet__entete">
<h1>Carnet d'adresses</h1>
<button type="button" class="btn--ajouter" (click)="ouvrirCreation()">
+ Ajouter une adresse
</button>
</div>
<!-- Formulaire de création / modification -->
<form class="carnet__form" [formGroup]="form" (ngSubmit)="enregistrer()">
<!-- Popup de création / modification -->
<div
class="modale-overlay"
*ngIf="modaleOuverte()"
(click)="fermerSurOverlay($event)"
>
<form class="modale-panneau carnet__form" [formGroup]="form" (ngSubmit)="enregistrer()">
<h2>{{ enEdition ? 'Modifier une adresse' : 'Ajouter une adresse' }}</h2>
<div class="field">
@@ -56,11 +66,12 @@
<button type="submit" [disabled]="form.invalid || enregistrement()">
{{ enEdition ? 'Enregistrer' : 'Ajouter' }}
</button>
<button type="button" class="btn--secondary" (click)="annuler()" *ngIf="enEdition">
<button type="button" class="btn--secondary" (click)="annuler()">
Annuler
</button>
</div>
</form>
</form>
</div>
<!-- Liste des adresses nommées, triée par dénomination -->
<div class="carnet__liste">
@@ -17,14 +17,57 @@
}
}
.carnet__entete {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
}
.btn--ajouter {
background: #0074b8;
color: #fff;
white-space: nowrap;
&:hover {
background: #f28c28;
}
}
.modale-overlay {
position: fixed;
inset: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
padding: 1rem;
background: rgba(0, 0, 0, 0.45);
}
.modale-panneau {
width: 100%;
max-width: 480px;
max-height: 90vh;
overflow-y: auto;
background: #fff;
border-radius: 10px;
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.25);
}
// Dans la popup, l'overlay 'overflow-y: auto' du panneau tronque un menu
// positionné en absolu : on affiche donc les suggestions dans le flux normal.
.modale-panneau .suggestions {
position: static;
box-shadow: none;
max-height: 180px;
}
.carnet__form {
display: flex;
flex-direction: column;
gap: 1rem;
padding: 1rem;
border: 1px solid #dcdcdc;
border-radius: 8px;
background: #fafafa;
padding: 1.25rem;
}
.field {
@@ -60,6 +60,9 @@ export class CarnetAdressesComponent implements OnInit, OnDestroy {
/** Identifiant de l'adresse en cours d'édition (null = création). */
readonly editionId = signal<number | null>(null);
/** Ouverture de la popup de création / modification. */
readonly modaleOuverte = signal(false);
/** Suggestions BAN courantes pour le champ adresse. */
readonly suggestions = signal<BANFeature[]>([]);
@@ -131,6 +134,24 @@ export class CarnetAdressesComponent implements OnInit, OnDestroy {
denomination: adresse.denomination,
adresse: adresse.adresse,
});
this.modaleOuverte.set(true);
}
/** Ouvre la popup en mode création (formulaire vierge). */
ouvrirCreation(): void {
this.editionId.set(null);
this.latitude = null;
this.longitude = null;
this.suggestions.set([]);
this.form.reset({ denomination: '', adresse: '' });
this.modaleOuverte.set(true);
}
/** Ferme la popup uniquement lors d'un clic sur le fond (pas sur le panneau). */
fermerSurOverlay(event: MouseEvent): void {
if (event.target === event.currentTarget) {
this.annuler();
}
}
/** Réinitialise le formulaire en mode création. */
@@ -140,6 +161,7 @@ export class CarnetAdressesComponent implements OnInit, OnDestroy {
this.longitude = null;
this.suggestions.set([]);
this.form.reset({ denomination: '', adresse: '' });
this.modaleOuverte.set(false);
}
/** Réagit à la saisie du champ adresse pour alimenter l'autocomplétion BAN. */