From c133c4cc899b0b2794a56e9ef7eaec50f6cfb985 Mon Sep 17 00:00:00 2001 From: Nessar Date: Mon, 27 Jul 2026 13:14:13 +0200 Subject: [PATCH] feat: refactor forms to use Angular Material components for improved consistency and user experience --- .../lease-end-notice-card.css | 14 +-- .../lease-end-notice-card.html | 34 +++---- .../lease-end-notice-form.css | 16 +--- .../lease-end-notice-form.html | 89 +++++++++---------- .../lease-end-notice-form.ts | 2 + .../lease-end-resolution-forms.css | 14 +-- .../lease-end-resolution-forms.html | 12 +-- .../rent-revision-application.css | 11 +-- .../rent-revision-application.html | 23 +++-- .../rent-revision-application.spec.ts | 20 +++-- .../rent-revision-application.ts | 2 + .../rent-revision-preview.html | 17 ++-- .../rent-revision-preview.spec.ts | 27 +++--- .../rent-revision-preview.ts | 2 + .../rent-revision-proposals.css | 17 +--- .../rent-revision-proposals.html | 68 +++++++------- .../rent-revision-proposals.spec.ts | 11 ++- 17 files changed, 174 insertions(+), 205 deletions(-) diff --git a/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.css b/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.css index c1929a2..9ca33de 100644 --- a/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.css +++ b/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.css @@ -59,8 +59,7 @@ dd { padding-block-start: 1.25rem; border-block-start: 1px solid var(--border, #dfe3e6); } -fieldset, -label { +fieldset { display: grid; gap: 0.5rem; min-width: 0; @@ -74,16 +73,9 @@ legend { margin-block-end: 0.75rem; font-weight: 700; } -input, -textarea { +mat-form-field { min-width: 0; - min-height: 2.75rem; - box-sizing: border-box; -} -input:focus-visible, -textarea:focus-visible { - outline: 2px solid var(--accent, #236b5d); - outline-offset: 0.15rem; + width: 100%; } .operation-error { color: var(--danger, #b42318); diff --git a/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.html b/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.html index 3c84fbb..8763506 100644 --- a/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.html +++ b/frontend/src/app/components/lease-end-notice-card/lease-end-notice-card.html @@ -137,8 +137,8 @@ @if (notice().evidenceVersions.length) { - + } @if (evidenceError() || evidenceOperationError()) {
Accepter un retrait - + @if (withdrawalDateError()) { } @@ -186,16 +186,16 @@ {{ serverError(withdrawalFieldErrors(), 'acceptedOn') }}

} - + @if (withdrawalReasonError()) {
Invalider administrativement - + @if (invalidationDateError()) { } - + @if (invalidationReasonError()) {
- - + + @if (requestedDepartureOnError()) { + + } + @if (serverError('requestedDepartureOn')) { + + }
- + + + @if (deliveryModeError()) { + + } @if (model().deliveryMode === 'OTHER') { - + + @if (otherDeliveryModeError()) { + + } + @if (serverError('otherDeliveryMode')) { + + } > = { MatCheckboxModule, MatFormFieldModule, MatInputModule, + MatSelectModule, ], templateUrl: './lease-end-notice-form.html', styleUrl: './lease-end-notice-form.css', diff --git a/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.css b/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.css index 80f0684..bcb48e6 100644 --- a/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.css +++ b/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.css @@ -20,8 +20,7 @@ h2 { margin-block-start: 0; } -fieldset, -label:not(.confirmation-field) { +fieldset { display: grid; gap: 0.75rem; min-width: 0; @@ -31,11 +30,9 @@ fieldset { padding: 0; border: 0; } -input, -textarea { +mat-form-field { min-width: 0; - min-height: 2.75rem; - box-sizing: border-box; + width: 100%; } .confirmation-field { display: flex; @@ -54,11 +51,6 @@ textarea { .report-date span { color: var(--text-muted, #5f6368); } -input:focus-visible, -textarea:focus-visible { - outline: 2px solid var(--accent, #236b5d); - outline-offset: 0.15rem; -} .operation-error { color: var(--danger, #b42318); } diff --git a/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.html b/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.html index 039afa5..72205cd 100644 --- a/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.html +++ b/frontend/src/app/components/lease-end-resolution-forms/lease-end-resolution-forms.html @@ -8,8 +8,8 @@ (submit)="submitAgreement(); $event.preventDefault()" >
- + @if (agreementDateError()) { } @@ -26,8 +26,8 @@ {{ serverError(agreementFieldErrors(), 'endOn') }}

} - + @if (agreementReasonError()) { } diff --git a/frontend/src/app/components/rent-revision-application/rent-revision-application.css b/frontend/src/app/components/rent-revision-application/rent-revision-application.css index 5b844ca..472e840 100644 --- a/frontend/src/app/components/rent-revision-application/rent-revision-application.css +++ b/frontend/src/app/components/rent-revision-application/rent-revision-application.css @@ -38,17 +38,8 @@ form label { font-weight: 700; } -select, -input[type='file'] { - box-sizing: border-box; +mat-form-field { width: 100%; - min-height: 2.75rem; - max-width: 100%; - border: 1px solid var(--border-strong, #aebbb4); - border-radius: var(--radius-sm, 0.5rem); - background: var(--surface, #fff); - color: var(--text, #17211e); - font: inherit; } .attestation { diff --git a/frontend/src/app/components/rent-revision-application/rent-revision-application.html b/frontend/src/app/components/rent-revision-application/rent-revision-application.html index d9a36b7..d64b5df 100644 --- a/frontend/src/app/components/rent-revision-application/rent-revision-application.html +++ b/frontend/src/app/components/rent-revision-application/rent-revision-application.html @@ -11,23 +11,22 @@ (submit)="submit(); $event.preventDefault()" >
- + + + @if (fieldError('deliveryMethod')) { + {{ fieldError('deliveryMethod') }} + }
Preuve d’envoi PDF (facultative) { expect(fixture.nativeElement.textContent).toContain('Choisissez le mode d’envoi.'); http.expectNone((request) => request.method === 'POST'); - const delivery: HTMLSelectElement = fixture.nativeElement.querySelector('.delivery-method'); - delivery.value = 'EMAIL'; - delivery.dispatchEvent(new Event('input')); - await fixture.whenStable(); + const loader = TestbedHarnessEnvironment.loader(fixture); + const delivery = await loader.getHarness( + MatSelectHarness.with({ selector: '.delivery-method' }), + ); + await delivery.clickOptions({ text: 'Courriel' }); fixture.detectChanges(); fixture.nativeElement.querySelector('.apply-submit').click(); fixture.detectChanges(); @@ -82,10 +85,11 @@ describe('RentRevisionApplicationComponent', () => { const fixture = createComponent(); const applied = vi.fn(); fixture.componentInstance.applied.subscribe(applied); - const delivery: HTMLSelectElement = fixture.nativeElement.querySelector('.delivery-method'); - delivery.value = 'REGISTERED_LETTER'; - delivery.dispatchEvent(new Event('input')); - await fixture.whenStable(); + const loader = TestbedHarnessEnvironment.loader(fixture); + const delivery = await loader.getHarness( + MatSelectHarness.with({ selector: '.delivery-method' }), + ); + await delivery.clickOptions({ text: 'Lettre recommandée' }); fixture.nativeElement.querySelector('.delivery-confirmed input').click(); const proof = new File(['pdf'], 'preuve-envoi.pdf', { type: 'application/pdf' }); const proofInput: HTMLInputElement = diff --git a/frontend/src/app/components/rent-revision-application/rent-revision-application.ts b/frontend/src/app/components/rent-revision-application/rent-revision-application.ts index 0491f37..a3b1807 100644 --- a/frontend/src/app/components/rent-revision-application/rent-revision-application.ts +++ b/frontend/src/app/components/rent-revision-application/rent-revision-application.ts @@ -6,6 +6,7 @@ import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { finalize } from 'rxjs'; import { ApplyRentRevisionResponse, @@ -32,6 +33,7 @@ const frenchDate = new Intl.DateTimeFormat('fr-FR', { MatCheckboxModule, MatFormFieldModule, MatInputModule, + MatSelectModule, ], templateUrl: './rent-revision-application.html', styleUrl: './rent-revision-application.css', diff --git a/frontend/src/app/components/rent-revision-preview/rent-revision-preview.html b/frontend/src/app/components/rent-revision-preview/rent-revision-preview.html index 4bf8467..96a2018 100644 --- a/frontend/src/app/components/rent-revision-preview/rent-revision-preview.html +++ b/frontend/src/app/components/rent-revision-preview/rent-revision-preview.html @@ -21,19 +21,18 @@ > Nouvelle série officielle - + + @if (fieldError('seriesIdOverride')) { {{ fieldError('seriesIdOverride') }} diff --git a/frontend/src/app/components/rent-revision-preview/rent-revision-preview.spec.ts b/frontend/src/app/components/rent-revision-preview/rent-revision-preview.spec.ts index 4e3b1bd..8fef5ef 100644 --- a/frontend/src/app/components/rent-revision-preview/rent-revision-preview.spec.ts +++ b/frontend/src/app/components/rent-revision-preview/rent-revision-preview.spec.ts @@ -1,6 +1,8 @@ import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestBed } from '@angular/core/testing'; +import { MatSelectHarness } from '@angular/material/select/testing'; import { RentRevisionPreview } from '../../services/lease.service'; import { WorkspaceService } from '../../services/workspace.service'; import { RentRevisionPreviewComponent } from './rent-revision-preview'; @@ -148,19 +150,20 @@ describe('RentRevisionPreviewComponent', () => { it('requires an attestation before overriding the INSEE series', async () => { const fixture = createComponent(); - const series: HTMLSelectElement = fixture.nativeElement.querySelector('.series-override'); - expect([...series.options].map((option) => option.value)).toEqual([ - '', - '001515333', - '010760507', - '010760509', + const loader = TestbedHarnessEnvironment.loader(fixture); + const series = await loader.getHarness( + MatSelectHarness.with({ selector: '.series-override' }), + ); + await series.open(); + const options = await series.getOptions(); + expect(await Promise.all(options.map((option) => option.getText()))).toEqual([ + 'Série prévue dans le bail', + 'Métropole — 001515333', + 'Corse — 010760507', + 'Départements d’outre-mer (article 73) — 010760509', ]); - expect(series.textContent).toContain('Métropole — 001515333'); - expect(series.textContent).toContain('Corse — 010760507'); - expect(series.textContent).toContain('Départements d’outre-mer (article 73) — 010760509'); - series.value = '001515333'; - series.dispatchEvent(new Event('input')); - await fixture.whenStable(); + await series.close(); + await series.clickOptions({ text: 'Métropole — 001515333' }); fixture.detectChanges(); fixture.nativeElement.querySelector('.preview-submit').click(); diff --git a/frontend/src/app/components/rent-revision-preview/rent-revision-preview.ts b/frontend/src/app/components/rent-revision-preview/rent-revision-preview.ts index 84541e1..bd50836 100644 --- a/frontend/src/app/components/rent-revision-preview/rent-revision-preview.ts +++ b/frontend/src/app/components/rent-revision-preview/rent-revision-preview.ts @@ -7,6 +7,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; +import { MatSelectModule } from '@angular/material/select'; import { finalize } from 'rxjs'; import { LeaseService, @@ -42,6 +43,7 @@ const indexFormatter = new Intl.NumberFormat('fr-FR', { maximumFractionDigits: 4 MatExpansionModule, MatFormFieldModule, MatInputModule, + MatSelectModule, RentRevisionProposalsComponent, ], templateUrl: './rent-revision-preview.html', diff --git a/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.css b/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.css index 08aa008..50023a4 100644 --- a/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.css +++ b/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.css @@ -36,28 +36,15 @@ gap: var(--space-3, 0.75rem); } -.field-grid label, +.proposal-field, .proposal-warnings, .attestation { display: grid; gap: var(--space-2, 0.5rem); } -.field-grid label { - font-size: 0.78rem; - font-weight: 700; -} - -.field-grid input { - box-sizing: border-box; +mat-form-field { width: 100%; - min-height: 2.75rem; - padding-inline: var(--space-3, 0.75rem); - border: 1px solid var(--border-strong, #aebbb4); - border-radius: var(--radius-sm, 0.5rem); - background: var(--surface, #fff); - color: var(--text, #17211e); - font: inherit; } .bounds, diff --git a/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.html b/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.html index bad7303..c093acd 100644 --- a/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.html +++ b/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.html @@ -22,50 +22,56 @@

Créer la proposition et sa lettre

-

diff --git a/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.spec.ts b/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.spec.ts index fc317e8..f1ce3e3 100644 --- a/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.spec.ts +++ b/frontend/src/app/components/rent-revision-proposals/rent-revision-proposals.spec.ts @@ -1,6 +1,8 @@ import { provideHttpClient } from '@angular/common/http'; import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; +import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestBed } from '@angular/core/testing'; +import { MatSelectHarness } from '@angular/material/select/testing'; import { vi } from 'vitest'; import { RentRevisionPreview, @@ -258,10 +260,11 @@ describe('RentRevisionProposalsComponent', () => { fixture.nativeElement.querySelectorAll('app-rent-revision-application'), ).toHaveLength(2); expect(fixture.nativeElement.querySelector('.proposal-form')).not.toBeNull(); - const delivery: HTMLSelectElement = fixture.nativeElement.querySelector('.delivery-method'); - delivery.value = 'EMAIL'; - delivery.dispatchEvent(new Event('input')); - await fixture.whenStable(); + const loader = TestbedHarnessEnvironment.loader(fixture); + const delivery = await loader.getHarness( + MatSelectHarness.with({ selector: '.delivery-method' }), + ); + await delivery.clickOptions({ text: 'Courriel' }); fixture.nativeElement.querySelector('.delivery-confirmed input').click(); fixture.detectChanges(); fixture.nativeElement.querySelector('.apply-submit').click();