Mijn aanvragen (F1): ApplicationsStore + dashboard blocks
The payoff — A–E become visible. The dashboard now shows a "Mijn aanvragen"
section at the top with a block per application.
- ApplicationsStore (registratie/application, root): the list as a RemoteData
signal, parsed at the trust boundary; reload() (dashboard revisit reflects
server-computed auto-approval); optimistic cancel (hide → reload / un-hide on fail).
- aanvraag-block (organism): badge (tag → colour/label) + per-status body
("Stap X van Y" / referentie + ingediend-datum / manual note / reden) + actions
from the pure blockActions. Composes card + status-badge + button. Stories per status.
- dashboard: "Mijn aanvragen" section (hidden when empty), sorted Concept → In
behandeling → resolved; Verder gaan deep-links the wizard (?aanvraag=<id>),
Annuleren cancels via the store.
Deferred to F2: document-chip preview/download affordance.
Gates green: vitest 128, lint, build, check:tokens; backend dotnet 56.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import { Component, computed, input, output } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { HeadingComponent } from '@shared/ui/heading/heading.component';
|
||||
import { StatusBadgeComponent } from '@shared/ui/status-badge/status-badge.component';
|
||||
import { ButtonComponent } from '@shared/ui/button/button.component';
|
||||
import { CardComponent } from '@shared/ui/card/card.component';
|
||||
import { Aanvraag, AanvraagType } from '@registratie/domain/aanvraag';
|
||||
import { blockActions } from '@registratie/domain/block-actions';
|
||||
|
||||
const TYPE_LABELS: Record<AanvraagType, string> = {
|
||||
registratie: $localize`:@@aanvraagBlock.type.registratie:Inschrijving`,
|
||||
herregistratie: $localize`:@@aanvraagBlock.type.herregistratie:Herregistratie`,
|
||||
intake: $localize`:@@aanvraagBlock.type.intake:Herregistratie-intake`,
|
||||
};
|
||||
|
||||
/** Organism: one application on the dashboard's "Mijn aanvragen" list. Which badge
|
||||
+ actions it shows is driven by the pure `blockActions(status)` and the status
|
||||
tag; the block only renders. Composes card + status-badge + button. */
|
||||
@Component({
|
||||
selector: 'app-aanvraag-block',
|
||||
imports: [DatePipe, HeadingComponent, StatusBadgeComponent, ButtonComponent, CardComponent],
|
||||
styles: [`
|
||||
.head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--rhc-space-max-md); flex-wrap: wrap; }
|
||||
.actions { display: flex; gap: var(--rhc-space-max-md); margin-block-start: var(--rhc-space-max-md); }
|
||||
`],
|
||||
template: `
|
||||
<app-card>
|
||||
<div class="head">
|
||||
<app-heading [level]="3">{{ typeLabel() }}</app-heading>
|
||||
<app-status-badge [label]="badgeLabel()" [color]="badgeColor()" />
|
||||
</div>
|
||||
|
||||
@switch (aanvraag().status.tag) {
|
||||
@case ('Concept') {
|
||||
<p class="rhc-paragraph" i18n="@@aanvraagBlock.stap">Stap {{ stap().index }} van {{ stap().count }}</p>
|
||||
}
|
||||
@case ('InBehandeling') {
|
||||
<p class="rhc-paragraph" i18n="@@aanvraagBlock.inBehandeling">Referentie {{ ref() }} · ingediend op {{ aanvraag().submittedAt | date: 'longDate' }}</p>
|
||||
@if (manual()) {
|
||||
<p class="rhc-paragraph app-text-subtle" i18n="@@aanvraagBlock.manual">Uw aanvraag wordt handmatig beoordeeld in de backoffice.</p>
|
||||
}
|
||||
}
|
||||
@case ('Goedgekeurd') {
|
||||
<p class="rhc-paragraph" i18n="@@aanvraagBlock.goedgekeurd">Referentie {{ ref() }}</p>
|
||||
}
|
||||
@case ('Afgewezen') {
|
||||
<p class="rhc-paragraph" i18n="@@aanvraagBlock.afgewezen">Referentie {{ ref() }}</p>
|
||||
<p class="rhc-paragraph app-text-subtle">{{ reden() }}</p>
|
||||
}
|
||||
}
|
||||
|
||||
@if (actions().length) {
|
||||
<div class="actions">
|
||||
@if (actions().includes('resume')) {
|
||||
<app-button (click)="resume.emit()" i18n="@@aanvraagBlock.verderGaan">Verder gaan</app-button>
|
||||
}
|
||||
@if (actions().includes('cancel')) {
|
||||
<app-button variant="subtle" (click)="cancel.emit()" i18n="@@aanvraagBlock.annuleren">Annuleren</app-button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</app-card>
|
||||
`,
|
||||
})
|
||||
export class AanvraagBlockComponent {
|
||||
aanvraag = input.required<Aanvraag>();
|
||||
|
||||
resume = output<void>();
|
||||
cancel = output<void>();
|
||||
|
||||
protected typeLabel = computed(() => TYPE_LABELS[this.aanvraag().type]);
|
||||
protected actions = computed(() => blockActions(this.aanvraag().status));
|
||||
|
||||
// Status-tag → badge presentation (the UI's mapping, not a domain rule).
|
||||
protected badgeLabel = computed(() => {
|
||||
switch (this.aanvraag().status.tag) {
|
||||
case 'Concept': return $localize`:@@aanvraagBlock.badge.concept:Concept`;
|
||||
case 'InBehandeling': return $localize`:@@aanvraagBlock.badge.inBehandeling:In behandeling`;
|
||||
case 'Goedgekeurd': return $localize`:@@aanvraagBlock.badge.goedgekeurd:Goedgekeurd`;
|
||||
case 'Afgewezen': return $localize`:@@aanvraagBlock.badge.afgewezen:Afgewezen`;
|
||||
}
|
||||
});
|
||||
protected badgeColor = computed(() => {
|
||||
switch (this.aanvraag().status.tag) {
|
||||
case 'Concept': return 'var(--rhc-color-cool-grey-300)';
|
||||
case 'InBehandeling': return 'var(--rhc-color-oranje-500)';
|
||||
case 'Goedgekeurd': return 'var(--rhc-color-groen-500)';
|
||||
case 'Afgewezen': return 'var(--rhc-color-rood-500)';
|
||||
}
|
||||
});
|
||||
|
||||
// Field accessors per tag (the template @switch guarantees the right shape).
|
||||
protected stap = computed(() => {
|
||||
const s = this.aanvraag().status;
|
||||
return s.tag === 'Concept' ? { index: s.stepIndex + 1, count: s.stepCount } : { index: 0, count: 0 };
|
||||
});
|
||||
protected ref = computed(() => {
|
||||
const s = this.aanvraag().status;
|
||||
return s.tag !== 'Concept' ? s.referentie : '';
|
||||
});
|
||||
protected manual = computed(() => {
|
||||
const s = this.aanvraag().status;
|
||||
return s.tag === 'InBehandeling' && s.manual;
|
||||
});
|
||||
protected reden = computed(() => {
|
||||
const s = this.aanvraag().status;
|
||||
return s.tag === 'Afgewezen' ? s.reden : '';
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user