refactor: rename Application → Aanvraag across the wire (Step 1/8)
The wire said Application, the domain said Aanvraag — one aggregate with two names at every hop. Rename the backend DTOs and the /applications route to /aanvragen, regenerate the typed client, and rename the frontend adapter/store to match. Renamed: ApplicationSummaryDto/DetailDto, CreateApplicationRequest, SubmitApplicationRequest/Response → Aanvraag* equivalents; ApplicationsAdapter/Store → AanvragenAdapter/Store; applications.adapter.ts/applications.store.ts → aanvragen.*. Left untouched: the admin Case/Zaak vocabulary (/admin/cases, AdminCasesStore) — a separate read model, not part of this rename; the internal BigRegister.Domain.Applications namespace and the Applications EF table (renaming those needs a new EF migration, out of scope here). Part of the dashboard-readability refactor (see the approved plan). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+9
-9
@@ -1,8 +1,8 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { SUBMIT_FAILED } from '@shared/application/submit';
|
||||
import { ApplicationsAdapter } from '@registratie/infrastructure/applications.adapter';
|
||||
import { ApplicationsStore } from './applications.store';
|
||||
import { AanvragenAdapter } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
import { AanvragenStore } from './aanvragen.store';
|
||||
|
||||
const summary = (id: string) => ({
|
||||
id,
|
||||
@@ -13,20 +13,20 @@ const summary = (id: string) => ({
|
||||
updatedAt: '2026-07-23T10:00:00Z',
|
||||
});
|
||||
|
||||
function setup(adapter: Partial<ApplicationsAdapter>): ApplicationsStore {
|
||||
function setup(adapter: Partial<AanvragenAdapter>): AanvragenStore {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{ provide: ApplicationsAdapter, useValue: adapter }],
|
||||
providers: [{ provide: AanvragenAdapter, useValue: adapter }],
|
||||
});
|
||||
// The store's own constructor kicks off `load()` (dashboard revisit refresh) —
|
||||
// give every test a `list` so that initial call has something to resolve.
|
||||
return TestBed.inject(ApplicationsStore);
|
||||
return TestBed.inject(AanvragenStore);
|
||||
}
|
||||
|
||||
describe('ApplicationsStore', () => {
|
||||
describe('AanvragenStore', () => {
|
||||
it('loads and parses the list', async () => {
|
||||
const store = setup({ list: () => Promise.resolve([summary('a'), summary('b')]) });
|
||||
await store.load();
|
||||
const s = store.applications();
|
||||
const s = store.aanvragen();
|
||||
expect(s.tag).toBe('Success');
|
||||
expect(s.tag === 'Success' && s.value.map((a) => a.id)).toEqual(['a', 'b']);
|
||||
});
|
||||
@@ -41,7 +41,7 @@ describe('ApplicationsStore', () => {
|
||||
|
||||
await store.cancel('a');
|
||||
expect(cancel).toHaveBeenCalledWith('a');
|
||||
const s = store.applications();
|
||||
const s = store.aanvragen();
|
||||
expect(s.tag === 'Success' && s.value.map((a) => a.id)).toEqual(['b']);
|
||||
expect(store.lastError()).toBeNull();
|
||||
});
|
||||
@@ -55,7 +55,7 @@ describe('ApplicationsStore', () => {
|
||||
await store.load();
|
||||
|
||||
await store.cancel('a');
|
||||
const s = store.applications();
|
||||
const s = store.aanvragen();
|
||||
expect(s.tag === 'Success' && s.value.map((a) => a.id)).toEqual(['a']); // reappears
|
||||
expect(store.lastError()).toBe(SUBMIT_FAILED);
|
||||
});
|
||||
+6
-9
@@ -2,15 +2,12 @@ import { Injectable, inject, signal } from '@angular/core';
|
||||
import { RemoteData } from '@shared/application/remote-data';
|
||||
import { runSubmit, SUBMIT_FAILED } from '@shared/application/submit';
|
||||
import { Aanvraag } from '@registratie/domain/aanvraag';
|
||||
import {
|
||||
ApplicationsAdapter,
|
||||
parseApplications,
|
||||
} from '@registratie/infrastructure/applications.adapter';
|
||||
import { AanvragenAdapter, parseAanvragen } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
|
||||
type Err = Error | undefined;
|
||||
|
||||
/**
|
||||
* The dashboard's view of the user's applications (aanvragen) — the backend is the
|
||||
* The dashboard's view of the user's aanvragen — the backend is the
|
||||
* system of record (PRD 0001). One root singleton OWNS the list as a writable
|
||||
* RemoteData signal (CLAUDE.md §3: change state only through methods). Cancel removes
|
||||
* the row SYNCHRONOUSLY, so the block disappears deterministically — no dependence on
|
||||
@@ -20,11 +17,11 @@ type Err = Error | undefined;
|
||||
* surfaces `lastError` on failure (RB-20).
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ApplicationsStore {
|
||||
private adapter = inject(ApplicationsAdapter);
|
||||
export class AanvragenStore {
|
||||
private adapter = inject(AanvragenAdapter);
|
||||
|
||||
private state = signal<RemoteData<Err, Aanvraag[]>>({ tag: 'Loading' });
|
||||
readonly applications = this.state.asReadonly();
|
||||
readonly aanvragen = this.state.asReadonly();
|
||||
|
||||
/** Set on a failed cancel (RB-20): the optimistic removal already rolled back by
|
||||
then, this is only the message for the alert the page renders above the list. */
|
||||
@@ -40,7 +37,7 @@ export class ApplicationsStore {
|
||||
async load() {
|
||||
if (this.state().tag !== 'Success') this.state.set({ tag: 'Loading' });
|
||||
try {
|
||||
const parsed = parseApplications(await this.adapter.list());
|
||||
const parsed = parseAanvragen(await this.adapter.list());
|
||||
this.state.set(
|
||||
parsed.ok
|
||||
? { tag: 'Success', value: parsed.value }
|
||||
@@ -1,7 +1,7 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { describe, it, expect, vi } from 'vitest';
|
||||
import { SUBMIT_FAILED } from '@shared/application/submit';
|
||||
import { ApplicationsAdapter } from '@registratie/infrastructure/applications.adapter';
|
||||
import { AanvragenAdapter } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
import { AdminCasesStore } from './admin-cases.store';
|
||||
|
||||
const summary = (id: string) => ({
|
||||
@@ -14,9 +14,9 @@ const summary = (id: string) => ({
|
||||
owner: '19012345601',
|
||||
});
|
||||
|
||||
function setup(adapter: Partial<ApplicationsAdapter>): AdminCasesStore {
|
||||
function setup(adapter: Partial<AanvragenAdapter>): AdminCasesStore {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [{ provide: ApplicationsAdapter, useValue: adapter }],
|
||||
providers: [{ provide: AanvragenAdapter, useValue: adapter }],
|
||||
});
|
||||
return TestBed.inject(AdminCasesStore);
|
||||
}
|
||||
|
||||
@@ -2,16 +2,13 @@ import { Injectable, inject, signal } from '@angular/core';
|
||||
import { RemoteData } from '@shared/application/remote-data';
|
||||
import { runSubmit, SUBMIT_FAILED } from '@shared/application/submit';
|
||||
import { Aanvraag } from '@registratie/domain/aanvraag';
|
||||
import {
|
||||
ApplicationsAdapter,
|
||||
parseApplications,
|
||||
} from '@registratie/infrastructure/applications.adapter';
|
||||
import { AanvragenAdapter, parseAanvragen } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
|
||||
type Err = Error | undefined;
|
||||
|
||||
/**
|
||||
* Admin view of ALL cases across owners (WP-36; `cases:manage`) — the back-office
|
||||
* counterpart of the user-facing `ApplicationsStore`. Same shape: one root singleton
|
||||
* counterpart of the user-facing `AanvragenStore`. Same shape: one root singleton
|
||||
* owns the list as a writable RemoteData signal, delete removes the row synchronously
|
||||
* (optimistic), goes through `runSubmit`, and rolls back plus surfaces `lastError` on
|
||||
* failure (RB-20). Admin delete removes any case (any owner, submitted or not — the
|
||||
@@ -19,7 +16,7 @@ type Err = Error | undefined;
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AdminCasesStore {
|
||||
private adapter = inject(ApplicationsAdapter);
|
||||
private adapter = inject(AanvragenAdapter);
|
||||
|
||||
private state = signal<RemoteData<Err, Aanvraag[]>>({ tag: 'Loading' });
|
||||
readonly cases = this.state.asReadonly();
|
||||
@@ -34,7 +31,7 @@ export class AdminCasesStore {
|
||||
async load() {
|
||||
if (this.state().tag !== 'Success') this.state.set({ tag: 'Loading' });
|
||||
try {
|
||||
const parsed = parseApplications(await this.adapter.listAll());
|
||||
const parsed = parseAanvragen(await this.adapter.listAll());
|
||||
this.state.set(
|
||||
parsed.ok
|
||||
? { tag: 'Success', value: parsed.value }
|
||||
|
||||
@@ -2,14 +2,14 @@ import { ApplicationRef, signal } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { ApplicationsAdapter } from '@registratie/infrastructure/applications.adapter';
|
||||
import { AanvragenAdapter } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
import { createDraftSync, DraftSnapshot } from './draft-sync';
|
||||
|
||||
function setup(adapter: Partial<ApplicationsAdapter>) {
|
||||
function setup(adapter: Partial<AanvragenAdapter>) {
|
||||
const navigate = vi.fn().mockResolvedValue(true);
|
||||
TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{ provide: ApplicationsAdapter, useValue: adapter },
|
||||
{ provide: AanvragenAdapter, useValue: adapter },
|
||||
{ provide: Router, useValue: { navigate } },
|
||||
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => null } } } },
|
||||
],
|
||||
|
||||
@@ -4,11 +4,11 @@ import { Result } from '@shared/kernel/fp';
|
||||
import { runSubmit, SUBMIT_FAILED } from '@shared/application/submit';
|
||||
import { registerPendingSave } from '@shared/application/pending-saves';
|
||||
import type {
|
||||
SubmitApplicationRequest,
|
||||
SubmitApplicationResponse,
|
||||
AanvraagIndienenRequest,
|
||||
AanvraagIndienenResponse,
|
||||
} from '@shared/infrastructure/api-client';
|
||||
import { AanvraagType } from '@registratie/domain/aanvraag';
|
||||
import { ApplicationsAdapter } from '@registratie/infrastructure/applications.adapter';
|
||||
import { AanvragenAdapter } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
import { findConcept, loadConcept } from './find-concept';
|
||||
|
||||
/** What a wizard persists per step: the opaque machine snapshot + progress + docs. */
|
||||
@@ -46,7 +46,7 @@ const DEBOUNCE_MS = 600; // ponytail: fixed debounce; tune if the sync feels lag
|
||||
* Inert without a Router (stories) or when `enabled()` is false — no network, no resume.
|
||||
*/
|
||||
export function createDraftSync(deps: DraftSyncDeps) {
|
||||
const adapter = inject(ApplicationsAdapter);
|
||||
const adapter = inject(AanvragenAdapter);
|
||||
const router = inject(Router, { optional: true });
|
||||
const route = inject(ActivatedRoute, { optional: true });
|
||||
const active = () => deps.enabled() && !!router && !!route;
|
||||
@@ -190,7 +190,7 @@ export function createDraftSync(deps: DraftSyncDeps) {
|
||||
/** Submit through the aanvraag lifecycle: ensure the Concept exists, then
|
||||
`POST /applications/{id}/submit` (server sets autoApprovable + transitions).
|
||||
Folded into a Result like the old submit-* commands. */
|
||||
submit(body: SubmitApplicationRequest): Promise<Result<string, SubmitApplicationResponse>> {
|
||||
submit(body: AanvraagIndienenRequest): Promise<Result<string, AanvraagIndienenResponse>> {
|
||||
return runSubmit(async () => adapter.submit(await ensureId(), body), SUBMIT_FAILED);
|
||||
},
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { ApplicationsAdapter } from '@registratie/infrastructure/applications.adapter';
|
||||
import { AanvragenAdapter } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
import { findConcept, loadConcept } from './find-concept';
|
||||
|
||||
// Free functions taking the adapter as a parameter (no inject()) — a plain fake
|
||||
// object is enough, no Angular TestBed needed.
|
||||
function fakeAdapter(overrides: Partial<ApplicationsAdapter>): ApplicationsAdapter {
|
||||
return overrides as ApplicationsAdapter;
|
||||
function fakeAdapter(overrides: Partial<AanvragenAdapter>): AanvragenAdapter {
|
||||
return overrides as AanvragenAdapter;
|
||||
}
|
||||
|
||||
describe('findConcept', () => {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
import { AanvraagType } from '@registratie/domain/aanvraag';
|
||||
import {
|
||||
ApplicationsAdapter,
|
||||
parseApplications,
|
||||
} from '@registratie/infrastructure/applications.adapter';
|
||||
import { AanvragenAdapter, parseAanvragen } from '@registratie/infrastructure/aanvragen.adapter';
|
||||
|
||||
/**
|
||||
* Read half of the Concept lookup that `createDraftSync` (`draft-sync.ts`) needs
|
||||
@@ -14,11 +11,11 @@ import {
|
||||
|
||||
/** Find the user's existing Concept of a given type (at most one), if any. */
|
||||
export async function findConcept(
|
||||
adapter: ApplicationsAdapter,
|
||||
adapter: AanvragenAdapter,
|
||||
type: AanvraagType,
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
const parsed = parseApplications(await adapter.list());
|
||||
const parsed = parseAanvragen(await adapter.list());
|
||||
return parsed.ok
|
||||
? parsed.value.find((a) => a.type === type && a.status.tag === 'Concept')?.id
|
||||
: undefined;
|
||||
@@ -34,10 +31,7 @@ export async function findConcept(
|
||||
export type LoadedConcept = { tag: 'concept'; draft: unknown | null } | { tag: 'not-concept' };
|
||||
|
||||
/** Load a specific Concept by id and report whether it is still editable. */
|
||||
export async function loadConcept(
|
||||
adapter: ApplicationsAdapter,
|
||||
id: string,
|
||||
): Promise<LoadedConcept> {
|
||||
export async function loadConcept(adapter: AanvragenAdapter, id: string): Promise<LoadedConcept> {
|
||||
try {
|
||||
const dto = await adapter.detail(id);
|
||||
if (dto.status && dto.status.tag !== 'Concept') return { tag: 'not-concept' };
|
||||
|
||||
+14
-14
@@ -1,10 +1,10 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import {
|
||||
parseAanvraagStatus,
|
||||
parseApplicationSummary,
|
||||
parseApplications,
|
||||
parseApplicationDetail,
|
||||
} from './applications.adapter';
|
||||
parseAanvraagSummary,
|
||||
parseAanvragen,
|
||||
parseAanvraagDetail,
|
||||
} from './aanvragen.adapter';
|
||||
|
||||
const concept = {
|
||||
id: 'a1',
|
||||
@@ -42,29 +42,29 @@ describe('parseAanvraagStatus', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseApplicationSummary', () => {
|
||||
describe('parseAanvraagSummary', () => {
|
||||
it('maps a valid DTO to domain', () => {
|
||||
const r = parseApplicationSummary(concept);
|
||||
const r = parseAanvraagSummary(concept);
|
||||
expect(r.ok && r.value.type).toBe('registratie');
|
||||
expect(r.ok && r.value.status.tag).toBe('Concept');
|
||||
});
|
||||
|
||||
it('rejects a bad type and non-objects', () => {
|
||||
expect(parseApplicationSummary({ ...concept, type: 'onbekend' }).ok).toBe(false);
|
||||
expect(parseApplicationSummary(null).ok).toBe(false);
|
||||
expect(parseApplicationSummary({ ...concept, id: 42 }).ok).toBe(false);
|
||||
expect(parseAanvraagSummary({ ...concept, type: 'onbekend' }).ok).toBe(false);
|
||||
expect(parseAanvraagSummary(null).ok).toBe(false);
|
||||
expect(parseAanvraagSummary({ ...concept, id: 42 }).ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseApplications / parseApplicationDetail', () => {
|
||||
describe('parseAanvragen / parseAanvraagDetail', () => {
|
||||
it('parses a list and fails fast on a bad element', () => {
|
||||
expect(parseApplications([concept, concept]).ok).toBe(true);
|
||||
expect(parseApplications([concept, { ...concept, status: { tag: 'x' } }]).ok).toBe(false);
|
||||
expect(parseApplications({}).ok).toBe(false);
|
||||
expect(parseAanvragen([concept, concept]).ok).toBe(true);
|
||||
expect(parseAanvragen([concept, { ...concept, status: { tag: 'x' } }]).ok).toBe(false);
|
||||
expect(parseAanvragen({}).ok).toBe(false);
|
||||
});
|
||||
|
||||
it('carries the opaque draft through detail', () => {
|
||||
const r = parseApplicationDetail({ ...concept, draft: { beroep: 'arts' } });
|
||||
const r = parseAanvraagDetail({ ...concept, draft: { beroep: 'arts' } });
|
||||
expect(r.ok && (r.value.draft as { beroep: string }).beroep).toBe('arts');
|
||||
});
|
||||
});
|
||||
+24
-24
@@ -3,11 +3,11 @@ import { Result, ok, err } from '@shared/kernel/fp';
|
||||
import {
|
||||
ApiClient,
|
||||
AanvraagStatusDto,
|
||||
ApplicationSummaryDto,
|
||||
ApplicationDetailDto,
|
||||
AanvraagSummaryDto,
|
||||
AanvraagDetailDto,
|
||||
DraftSyncRequest,
|
||||
SubmitApplicationRequest,
|
||||
SubmitApplicationResponse,
|
||||
AanvraagIndienenRequest,
|
||||
AanvraagIndienenResponse,
|
||||
} from '@shared/infrastructure/api-client';
|
||||
import {
|
||||
Aanvraag,
|
||||
@@ -19,21 +19,21 @@ import {
|
||||
/**
|
||||
* Infrastructure adapter for the backend-owned Aanvraag aggregate — the only place
|
||||
* its HTTP lives (ADR-0001 anti-corruption boundary). The list is a resource; the
|
||||
* mutations (create/sync/cancel/submit) are thin commands the ApplicationsStore
|
||||
* mutations (create/sync/cancel/submit) are thin commands the AanvragenStore
|
||||
* orchestrates optimistically. The untrusted response is validated + mapped to
|
||||
* domain by the hand-written parse* boundary below.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ApplicationsAdapter {
|
||||
export class AanvragenAdapter {
|
||||
private client = inject(ApiClient);
|
||||
|
||||
/** The dashboard's application list (raw DTOs; the store parses at the boundary). */
|
||||
list(): Promise<ApplicationSummaryDto[]> {
|
||||
return this.client.applicationsAll();
|
||||
/** The dashboard's aanvraag list (raw DTOs; the store parses at the boundary). */
|
||||
list(): Promise<AanvraagSummaryDto[]> {
|
||||
return this.client.aanvragenAll();
|
||||
}
|
||||
|
||||
/** Admin: every case across all owners (WP-36; `cases:manage`). Parsed at the boundary. */
|
||||
listAll(): Promise<ApplicationSummaryDto[]> {
|
||||
listAll(): Promise<AanvraagSummaryDto[]> {
|
||||
return this.client.casesAll();
|
||||
}
|
||||
|
||||
@@ -42,26 +42,26 @@ export class ApplicationsAdapter {
|
||||
return this.client.cases(id);
|
||||
}
|
||||
|
||||
detail(id: string): Promise<ApplicationDetailDto> {
|
||||
return this.client.applicationsGET(id);
|
||||
detail(id: string): Promise<AanvraagDetailDto> {
|
||||
return this.client.aanvragenGET(id);
|
||||
}
|
||||
|
||||
/** Create a Concept for a wizard type; resolves to the new aanvraag id. */
|
||||
create(type: AanvraagType): Promise<string> {
|
||||
return this.client.applicationsPOST({ type }).then((d) => d.id ?? '');
|
||||
return this.client.aanvragenPOST({ type }).then((d) => d.id ?? '');
|
||||
}
|
||||
|
||||
/** Draft sync per step (idempotent). Keep it debounced at the call site — it is chatty. */
|
||||
syncDraft(id: string, body: DraftSyncRequest): Promise<void> {
|
||||
return this.client.applicationsPUT(id, body);
|
||||
return this.client.aanvragenPUT(id, body);
|
||||
}
|
||||
|
||||
/** Cancel a Concept (cascades to its unlinked documents server-side). */
|
||||
cancel(id: string): Promise<void> {
|
||||
return this.client.applicationsDELETE(id);
|
||||
return this.client.aanvragenDELETE(id);
|
||||
}
|
||||
|
||||
submit(id: string, body: SubmitApplicationRequest): Promise<SubmitApplicationResponse> {
|
||||
submit(id: string, body: AanvraagIndienenRequest): Promise<AanvraagIndienenResponse> {
|
||||
return this.client.submit(id, body);
|
||||
}
|
||||
}
|
||||
@@ -101,7 +101,7 @@ export function parseAanvraagStatus(
|
||||
}
|
||||
}
|
||||
|
||||
function parseCommon(dto: ApplicationSummaryDto): Result<string, Aanvraag> {
|
||||
function parseCommon(dto: AanvraagSummaryDto): Result<string, Aanvraag> {
|
||||
if (typeof dto.id !== 'string') return err('aanvraag: missing id');
|
||||
if (typeof dto.type !== 'string' || !AANVRAAG_TYPES.includes(dto.type))
|
||||
return err(`aanvraag: bad type ${dto.type}`);
|
||||
@@ -121,25 +121,25 @@ function parseCommon(dto: ApplicationSummaryDto): Result<string, Aanvraag> {
|
||||
});
|
||||
}
|
||||
|
||||
export function parseApplicationSummary(json: unknown): Result<string, Aanvraag> {
|
||||
export function parseAanvraagSummary(json: unknown): Result<string, Aanvraag> {
|
||||
if (typeof json !== 'object' || json === null) return err('aanvraag: not an object');
|
||||
return parseCommon(json as ApplicationSummaryDto);
|
||||
return parseCommon(json as AanvraagSummaryDto);
|
||||
}
|
||||
|
||||
export function parseApplications(json: unknown): Result<string, Aanvraag[]> {
|
||||
export function parseAanvragen(json: unknown): Result<string, Aanvraag[]> {
|
||||
if (!Array.isArray(json)) return err('aanvragen: not an array');
|
||||
const out: Aanvraag[] = [];
|
||||
for (const item of json) {
|
||||
const parsed = parseApplicationSummary(item);
|
||||
const parsed = parseAanvraagSummary(item);
|
||||
if (!parsed.ok) return parsed;
|
||||
out.push(parsed.value);
|
||||
}
|
||||
return ok(out);
|
||||
}
|
||||
|
||||
export function parseApplicationDetail(json: unknown): Result<string, AanvraagDetail> {
|
||||
export function parseAanvraagDetail(json: unknown): Result<string, AanvraagDetail> {
|
||||
if (typeof json !== 'object' || json === null) return err('aanvraag: not an object');
|
||||
const base = parseCommon(json as ApplicationDetailDto);
|
||||
const base = parseCommon(json as AanvraagDetailDto);
|
||||
if (!base.ok) return base;
|
||||
return ok({ ...base.value, draft: (json as ApplicationDetailDto).draft ?? null });
|
||||
return ok({ ...base.value, draft: (json as AanvraagDetailDto).draft ?? null });
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { AlertComponent } from '@shared/ui/alert/alert.component';
|
||||
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 { ApplicationsStore } from '@registratie/application/applications.store';
|
||||
import { AanvragenStore } from '@registratie/application/aanvragen.store';
|
||||
import { Aanvraag } from '@registratie/domain/aanvraag';
|
||||
import { detailRows } from '@registratie/domain/aanvraag-view';
|
||||
|
||||
@@ -29,9 +29,9 @@ import { detailRows } from '@registratie/domain/aanvraag-view';
|
||||
heading="Aanvraag"
|
||||
backLink="/dashboard"
|
||||
>
|
||||
<app-async [data]="store.applications()">
|
||||
<app-async [data]="store.aanvragen()">
|
||||
<ng-template appAsyncLoaded>
|
||||
@if (applications(); as list) {
|
||||
@if (aanvragen(); as list) {
|
||||
@let a = find(list);
|
||||
@if (a) {
|
||||
<app-data-block
|
||||
@@ -60,15 +60,15 @@ import { detailRows } from '@registratie/domain/aanvraag-view';
|
||||
`,
|
||||
})
|
||||
export class AanvraagDetailPage {
|
||||
protected store = inject(ApplicationsStore);
|
||||
protected store = inject(AanvragenStore);
|
||||
private id = inject(ActivatedRoute).snapshot.paramMap.get('id') ?? '';
|
||||
|
||||
protected find = (list: Aanvraag[]): Aanvraag | undefined => list.find((a) => a.id === this.id);
|
||||
protected rows = detailRows;
|
||||
|
||||
/** See DashboardPage's `profile` for why this narrows via a computed instead of `let-`. */
|
||||
protected readonly applications = computed(() => {
|
||||
const rd = this.store.applications();
|
||||
protected readonly aanvragen = computed(() => {
|
||||
const rd = this.store.aanvragen();
|
||||
return rd.tag === 'Success' ? rd.value : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import { RegistrationSummaryComponent } from '@registratie/ui/registration-summa
|
||||
import { RegistrationTableComponent } from '@registratie/ui/registration-table/registration-table.component';
|
||||
import { AanvraagBlockComponent } from '@registratie/ui/aanvraag-block/aanvraag-block.component';
|
||||
import { BigProfileStore } from '@registratie/application/big-profile.store';
|
||||
import { ApplicationsStore } from '@registratie/application/applications.store';
|
||||
import { AanvragenStore } from '@registratie/application/aanvragen.store';
|
||||
import { Registration } from '@registratie/domain/registration';
|
||||
import { Aanvraag, AanvraagType } from '@registratie/domain/aanvraag';
|
||||
import { submittedRow } from '@registratie/domain/aanvraag-view';
|
||||
@@ -214,7 +214,7 @@ import { tasksFromProfile } from '@registratie/domain/tasks';
|
||||
})
|
||||
export class DashboardPage {
|
||||
protected store = inject(BigProfileStore);
|
||||
private apps = inject(ApplicationsStore);
|
||||
private apps = inject(AanvragenStore);
|
||||
private access = inject(AccessStore);
|
||||
private flags = inject(FeatureFlagStore);
|
||||
private router = inject(Router);
|
||||
@@ -232,10 +232,10 @@ export class DashboardPage {
|
||||
this.apps.reload();
|
||||
}
|
||||
|
||||
/** The user's applications, sorted Concept → In behandeling → resolved. Empty →
|
||||
/** The user's aanvragen, sorted Concept → In behandeling → resolved. Empty →
|
||||
the"Mijn aanvragen" section is hidden (see template). */
|
||||
protected aanvragen = computed<Aanvraag[]>(() => {
|
||||
const rd = this.apps.applications();
|
||||
const rd = this.apps.aanvragen();
|
||||
if (rd.tag !== 'Success') return [];
|
||||
const order: Record<Aanvraag['status']['tag'], number> = {
|
||||
Concept: 0,
|
||||
|
||||
Reference in New Issue
Block a user