Extract reusable address-fields organism, adopt in both registratie call-sites

The editable address block (straat/postcode/woonplaats) was hand-built inline in
two places — the registratie wizard and the change-request form. Factor it into one
pure presentational organism (values in, errors in, per-field change out) grouped in
a fieldset/legend, and adopt it in both. Behaviour, validation and state flow are
unchanged: the wizard still dispatches SetField (flipping adresHerkomst on edit) and
the change-request form still parses the postcode on submit. Storybook entry added;
other field clusters left inline by design (single-use or genuinely divergent).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 17:25:39 +02:00
parent 64385999eb
commit 770d454a32
4 changed files with 101 additions and 22 deletions

View File

@@ -10,6 +10,7 @@ import { SkeletonComponent } from '@shared/ui/skeleton/skeleton.component';
import { DataRowComponent } from '@shared/ui/data-row/data-row.component';
import { StepperComponent } from '@shared/ui/stepper/stepper.component';
import { ASYNC } from '@shared/ui/async/async.component';
import { AddressFieldsComponent } from '@registratie/ui/address-fields/address-fields.component';
import { createStore } from '@shared/application/store';
import { RemoteData, fromResource } from '@shared/application/remote-data';
import { BrpAdapter, parseBrpAddress } from '@registratie/infrastructure/brp.adapter';
@@ -43,7 +44,8 @@ const HANDMATIG = '__handmatig__'; // sentinel option: "my diploma isn't listed"
selector: 'app-registratie-wizard',
imports: [
FormsModule, FormFieldComponent, TextInputComponent, RadioGroupComponent, ButtonComponent,
AlertComponent, SpinnerComponent, SkeletonComponent, DataRowComponent, StepperComponent, ...ASYNC,
AlertComponent, SpinnerComponent, SkeletonComponent, DataRowComponent, StepperComponent,
AddressFieldsComponent, ...ASYNC,
],
template: `
@switch (state().tag) {
@@ -67,15 +69,10 @@ const HANDMATIG = '__handmatig__'; // sentinel option: "my diploma isn't listed"
<app-alert type="warning">We konden de BRP nu niet bereiken. Vul uw adres hieronder handmatig in.</app-alert>
}
}
<app-form-field label="Straat en huisnummer" fieldId="straat" [error]="err('straat')">
<app-text-input inputId="straat" [invalid]="!!err('straat')" [ngModel]="draft().straat ?? ''" (ngModelChange)="set('straat', $event)" name="straat" />
</app-form-field>
<app-form-field label="Postcode" fieldId="postcode" [error]="err('postcode')">
<app-text-input inputId="postcode" [invalid]="!!err('postcode')" [ngModel]="draft().postcode ?? ''" (ngModelChange)="set('postcode', $event)" name="postcode" placeholder="1234 AB" />
</app-form-field>
<app-form-field label="Woonplaats" fieldId="woonplaats" [error]="err('woonplaats')">
<app-text-input inputId="woonplaats" [invalid]="!!err('woonplaats')" [ngModel]="draft().woonplaats ?? ''" (ngModelChange)="set('woonplaats', $event)" name="woonplaats" />
</app-form-field>
<app-address-fields
[value]="{ straat: draft().straat ?? '', postcode: draft().postcode ?? '', woonplaats: draft().woonplaats ?? '' }"
[errors]="{ straat: err('straat'), postcode: err('postcode'), woonplaats: err('woonplaats') }"
(fieldChange)="set($event.key, $event.value)" />
<app-form-field label="Hoe wilt u correspondentie ontvangen?" fieldId="correspondentie" [error]="err('correspondentie')">
<app-radio-group name="correspondentie" [options]="kanalen" [invalid]="!!err('correspondentie')"
[ngModel]="draft().correspondentie ?? ''" (ngModelChange)="setKanaal($event)" />