feat(aanvragen): richer rows (purpose + status) linking to a case-detail page

- Aanvragen rows now show what the aanvraag is for (purpose subtitle) and an
  explicit status label (In behandeling / Goedgekeurd / Afgewezen) alongside the
  reference + submit date, via an expanded aanvraag-view (purposeLabel,
  statusLabel, referentie, detailRows) + spec.
- Rows link to a new /aanvraag/:id case-detail page, so the CIBG chevron shows
  and each aanvraag opens as a (stub) case — it lists soort/waarvoor/status/
  referentie/ingediend in a Datablock, with a note that full handling is future.

GREEN: lint, tokens, 183 tests, build, 137 axe stories. Verified visually
(dashboard aanvragen rows, upload drop-zone, datablock) via Storybook screenshots.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-02 21:55:21 +02:00
parent b5c5d30a65
commit ccc0184342
7 changed files with 629 additions and 130 deletions

View File

@@ -0,0 +1,50 @@
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { PageShellComponent } from '@shared/layout/page-shell/page-shell.component';
import { SkeletonComponent } from '@shared/ui/skeleton/skeleton.component';
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 { Aanvraag } from '@registratie/domain/aanvraag';
import { detailRows } from '@registratie/domain/aanvraag-view';
/** Page: a single aanvraag ("case"). Stub — it renders the aanvraag's known fields
(soort, waarvoor, status, referentie, ingediend) in a CIBG Datablock; full case
handling is future work. The dashboard "Mijn aanvragen" rows link here. */
@Component({
selector: 'app-aanvraag-detail-page',
imports: [PageShellComponent, SkeletonComponent, AlertComponent, DataBlockComponent, DataRowComponent, ...ASYNC],
template: `
<app-page-shell i18n-heading="@@aanvraagDetail.heading" heading="Aanvraag" backLink="/dashboard">
<app-async [data]="store.applications()">
<ng-template appAsyncLoaded let-list>
@let a = find($any(list));
@if (a) {
<app-data-block i18n-ariaLabel="@@aanvraagDetail.ariaLabel" ariaLabel="Aanvraaggegevens">
@for (row of rows(a); track row.key) {
<div app-data-row [key]="row.key" [value]="row.value"></div>
}
</app-data-block>
<app-alert class="app-section" type="info" i18n="@@aanvraagDetail.stub">
De volledige afhandeling van deze aanvraag is nog niet beschikbaar in deze POC.
</app-alert>
} @else {
<app-alert type="warning" i18n="@@aanvraagDetail.nietGevonden">Deze aanvraag is niet gevonden.</app-alert>
}
</ng-template>
<ng-template appAsyncLoading>
<app-skeleton height="2.5rem" [count]="5" />
</ng-template>
</app-async>
</app-page-shell>
`,
})
export class AanvraagDetailPage {
protected store = inject(ApplicationsStore);
private id = inject(ActivatedRoute).snapshot.paramMap.get('id') ?? '';
protected find = (list: Aanvraag[]): Aanvraag | undefined => list.find((a) => a.id === this.id);
protected rows = detailRows;
}

View File

@@ -43,7 +43,7 @@ import { tasksFromProfile } from '@registratie/domain/tasks';
<app-application-list>
@for (a of ingediend(); track a.id) {
@let row = submittedRow(a);
<li app-application-link animate.enter="app-item-enter" animate.leave="app-item-leave" [heading]="row.heading" [status]="row.status" [subtitle]="row.subtitle"></li>
<li app-application-link animate.enter="app-item-enter" animate.leave="app-item-leave" [heading]="row.heading" [subtitle]="row.subtitle" [status]="row.status" [to]="'/aanvraag/' + a.id"></li>
}
</app-application-list>
}