fix: give Failed its own branch in the two single-step forms (RD-06)
Before this fix, a failed submit on the besluit-form or the change-request-form left the user stuck. Both templates rendered `Failed` through the same `@else` branch as the editable form. In besluit-form the fields read from `Editing` only, so they went blank. In change-request-form the fields still showed the sent value, but `SetField` only applies to `Editing`, so typing did nothing. In both forms the submit button stayed enabled, but `Submit` is a no-op outside `Editing`. The only escape was a page reload. After this fix, `Failed` gets its own template branch: an error message, a read-only summary of what was sent (an `app-data-block`, reused from the existing BRP-address pattern), and a "Opnieuw proberen" button that dispatches `Retry`. Both machines already handle `Retry` (`Failed -> Submitting` with the preserved data), so no machine change was needed. Both components also move to `createStore`'s effect map (RD-05): the `Submitting` handler replaces the hand-called `runIfSubmitting`, so `onSubmit` is now a single `dispatch`. `runIfSubmitting`/`runIfIndienen` now remain only in the three wizards, migrated later by RD-08. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+33
-18
@@ -65,6 +65,26 @@ import { createSubmitChangeRequest } from '@registratie/application/submit-chang
|
||||
>Nieuwe wijziging doorgeven</app-button
|
||||
>
|
||||
</div>
|
||||
} @else if (state().tag === 'Failed') {
|
||||
<app-heading [level]="2" i18n="@@changeRequest.heading">Contactgegevens wijzigen</app-heading>
|
||||
|
||||
<app-alert type="error"
|
||||
><ng-container i18n="@@changeRequest.failed">Het indienen is niet gelukt:</ng-container>
|
||||
{{ failedError() }}</app-alert
|
||||
>
|
||||
|
||||
<app-data-block class="app-section" [ariaLabel]="telefoonLabelText">
|
||||
<div app-data-row [key]="telefoonLabelText" [value]="telefoon()"></div>
|
||||
</app-data-block>
|
||||
|
||||
<div class="app-section">
|
||||
<app-button
|
||||
variant="secondary"
|
||||
(click)="dispatch({ tag: 'Retry' })"
|
||||
i18n="@@wizard.opnieuwProberen"
|
||||
>Opnieuw proberen</app-button
|
||||
>
|
||||
</div>
|
||||
} @else {
|
||||
<app-heading [level]="2" i18n="@@changeRequest.heading">Contactgegevens wijzigen</app-heading>
|
||||
|
||||
@@ -108,13 +128,6 @@ import { createSubmitChangeRequest } from '@registratie/application/submit-chang
|
||||
</app-form-field>
|
||||
</fieldset>
|
||||
|
||||
@if (failedError()) {
|
||||
<app-alert type="error"
|
||||
><ng-container i18n="@@changeRequest.failed">Het indienen is niet gelukt:</ng-container>
|
||||
{{ failedError() }}</app-alert
|
||||
>
|
||||
}
|
||||
|
||||
<app-button type="submit" variant="primary" [disabled]="state().tag === 'Submitting'">
|
||||
{{ state().tag === 'Submitting' ? submitBezigLabel : submitLabel }}
|
||||
</app-button>
|
||||
@@ -127,7 +140,15 @@ export class ChangeRequestFormComponent {
|
||||
// adapter); the UI holds only this bound command. Field initializer = injection
|
||||
// context, like createStore below.
|
||||
private submit = createSubmitChangeRequest();
|
||||
private store = createStore<ChangeRequestState, ChangeRequestMsg>(initial, reduce);
|
||||
// Effect fires once, on Editing -> Submitting (RD-05's tag-transition rule; `Seed` is
|
||||
// exempt, so a story mounting straight into `Submitting` does not call the network).
|
||||
private store = createStore<ChangeRequestState, ChangeRequestMsg>(initial, reduce, {
|
||||
Submitting: async (s, store) => {
|
||||
const r = await this.submit(s.data);
|
||||
if (r.ok) store.dispatch({ tag: 'SubmitConfirmed', referentie: r.value });
|
||||
else store.dispatch({ tag: 'SubmitFailed', error: r.error });
|
||||
},
|
||||
});
|
||||
|
||||
/** BRP address, shown read-only. Undefined until the profile loads. */
|
||||
brpAdres = input<Adres | undefined>(undefined);
|
||||
@@ -148,6 +169,10 @@ export class ChangeRequestFormComponent {
|
||||
protected readonly postcodeLabel = $localize`:@@address.postcode:Postcode`;
|
||||
protected readonly woonplaatsLabel = $localize`:@@address.woonplaats:Woonplaats`;
|
||||
|
||||
// Same id as the telefoon form-field's label above, reused for the Failed
|
||||
// data-block's row key.
|
||||
protected readonly telefoonLabelText = $localize`:@@changeRequest.telefoonLabel:Telefoonnummer`;
|
||||
|
||||
private editing = computed(() => whenTag(this.state(), 'Editing'));
|
||||
protected errors = computed(() => this.editing()?.errors ?? {});
|
||||
protected failedError = computed(() => whenTag(this.state(), 'Failed')?.error ?? '');
|
||||
@@ -168,15 +193,5 @@ export class ChangeRequestFormComponent {
|
||||
|
||||
onSubmit() {
|
||||
this.dispatch({ tag: 'Submit' });
|
||||
this.runIfSubmitting();
|
||||
}
|
||||
|
||||
/** Effect: when we entered Submitting, call the command, then dispatch the outcome. */
|
||||
private async runIfSubmitting() {
|
||||
const s = this.state();
|
||||
if (s.tag !== 'Submitting') return;
|
||||
const r = await this.submit(s.data);
|
||||
if (r.ok) this.dispatch({ tag: 'SubmitConfirmed', referentie: r.value });
|
||||
else this.dispatch({ tag: 'SubmitFailed', error: r.error });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user