refactor: add successOr, sweep remaining inline unwraps (RD-17)

Eight sites hand-rolled `rd.tag === 'Success' ? rd.value : fallback`. Six
take the new `successOr(rd, fallback)`, one takes the existing `successOf`,
and one (`big-profile.store.ts`) uses the existing `map`, since it returns a
RemoteData rather than an unwrapped value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-09-04 20:33:56 +02:00
co-authored by Claude Sonnet 5
parent c36d9e3ff0
commit e221834f6e
13 changed files with 212 additions and 37 deletions
@@ -1,5 +1,6 @@
import { Component, computed, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { successOf } from '@shared/application/remote-data';
import { PageShellComponent } from '@shared/layout/page-shell/page-shell.component';
import { AlertComponent } from '@shared/ui/alert/alert.component';
import { ButtonComponent } from '@shared/ui/button/button.component';
@@ -73,10 +74,7 @@ export class BeoordelingPage {
protected retryText = $localize`:@@beoordeling.retry:Opnieuw proberen`;
protected rows = detailRows;
protected readonly view = computed(() => {
const rd = this.store.view();
return rd.tag === 'Success' ? rd.value : undefined;
});
protected readonly view = computed(() => successOf(this.store.view()));
constructor() {
void this.store.load(this.id);
@@ -5,6 +5,7 @@ import { ButtonComponent } from '@shared/ui/button/button.component';
import { SkeletonComponent } from '@shared/ui/skeleton/skeleton.component';
import { ASYNC } from '@shared/ui/async/async.component';
import { AccessStore } from '@shared/application/access.store';
import { successOr } from '@shared/application/remote-data';
import { WerkvoorraadStore } from '@behandeling/application/werkvoorraad.store';
import { WerkvoorraadListComponent } from '@behandeling/ui/werkvoorraad-list/werkvoorraad-list.component';
@@ -56,10 +57,7 @@ export class WerkvoorraadPage {
protected access = inject(AccessStore);
protected canBeoordelen = computed(() => this.access.can('aanvraag:beoordelen'));
protected items = computed(() => {
const rd = this.store.items();
return rd.tag === 'Success' ? rd.value : [];
});
protected items = computed(() => successOr(this.store.items(), []));
protected heading = $localize`:@@werkvoorraad.heading:Werkvoorraad`;
protected intro = $localize`:@@werkvoorraad.intro:Aanvragen die op beoordeling wachten.`;
@@ -52,10 +52,12 @@ export class BigProfileStore {
);
/** Specialisms/notes stay a separate stream (they have their own empty state). */
readonly aantekeningen = computed<RemoteData<Err, Aantekening[]>>(() => {
const rd = fromResource(this.aantekeningenRes, (v) => !v || v.length === 0);
return rd.tag === 'Success' ? { tag: 'Success', value: rd.value ?? [] } : rd;
});
readonly aantekeningen = computed<RemoteData<Err, Aantekening[]>>(() =>
map(
fromResource(this.aantekeningenRes, (v) => !v || v.length === 0),
(v) => v ?? [],
),
);
// --- Optimistic herregistratie state, shared with the dashboard -----------
private pending = signal(false);
@@ -6,6 +6,7 @@ import { DataBlockComponent } from '@shared/ui/data-block/data-block.component';
import { DataRowComponent } from '@shared/ui/data-row/data-row.component';
import { ASYNC } from '@shared/ui/async/async.component';
import { AccessStore } from '@shared/application/access.store';
import { successOr } from '@shared/application/remote-data';
import { formatDatumNl } from '@shared/kernel/datum';
import { Aanvraag } from '@registratie/domain/aanvraag';
import { TYPE_LABELS, statusLabel, referentie } from '@registratie/domain/aanvraag-view';
@@ -78,10 +79,7 @@ export class AdminCasesPage {
protected access = inject(AccessStore);
protected canManage = computed(() => this.access.can('cases:manage'));
protected cases = computed(() => {
const rd = this.store.cases();
return rd.tag === 'Success' ? rd.value : [];
});
protected cases = computed(() => successOr(this.store.cases(), []));
protected heading = $localize`:@@adminCases.heading:Aanvragen beheren`;
protected intro = $localize`:@@adminCases.intro:Alle aanvragen in het register. Een aanvraag verwijderen kan niet ongedaan worden gemaakt.`;
@@ -6,6 +6,7 @@ import { HeadingComponent } from '@shared/ui/heading/heading.component';
import { ApplicationListComponent } from '@shared/ui/application-list/application-list.component';
import { ApplicationLinkComponent } from '@shared/ui/application-link/application-link.component';
import { ASYNC } from '@shared/ui/async/async.component';
import { successOr } from '@shared/application/remote-data';
import { AanvragenStore } from '@registratie/application/aanvragen.store';
import { Aanvraag, AanvraagType } from '@registratie/domain/aanvraag';
import {
@@ -88,10 +89,9 @@ export class MijnAanvragenSection {
protected submittedRow = submittedRow;
protected aanvragen = computed<Aanvraag[]>(() => {
const rd = this.store.aanvragen();
return rd.tag === 'Success' ? sortForDashboard(rd.value) : [];
});
protected aanvragen = computed<Aanvraag[]>(() =>
sortForDashboard(successOr(this.store.aanvragen(), [])),
);
protected concepten_ = computed(() => concepten(this.aanvragen()));
protected ingediend_ = computed(() => ingediend(this.aanvragen()));
@@ -21,7 +21,7 @@ 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 { whenTag } from '@shared/kernel/fp';
import { RemoteData } from '@shared/application/remote-data';
import { RemoteData, successOr } from '@shared/application/remote-data';
import { RegistratieLookupStore } from '@registratie/application/registratie-lookup.store';
import { DuoLookupDto, PolicyQuestionDto } from '@registratie/contracts/duo-diplomas.dto';
import {
@@ -516,10 +516,7 @@ export class RegistratieWizardComponent {
inside it too: `<ng-template appAsyncLoaded>`'s own context can't inherit a
generic from the sibling [data] input (Angular only infers a structural
directive's type parameter from an input on that same node). */
protected duoData = computed<DuoLookupDto | null>(() => {
const rd = this.lookupRd();
return rd.tag === 'Success' ? rd.value : null;
});
protected duoData = computed<DuoLookupDto | null>(() => successOr(this.lookupRd(), null));
readonly jaNee = JA_NEE;