style: format frontend, docs and skills with prettier; add .prettierignore
One-time prettier --write so the new format:check CI gate starts green. .prettierignore excludes generated (api-client.ts, documentation.json), vendored (public/cibg-huisstijl), and backend (dotnet format owns it). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,9 +13,16 @@ import { blockActions } from '@registratie/domain/block-actions';
|
||||
@Component({
|
||||
selector: 'app-aanvraag-block',
|
||||
imports: [ButtonComponent, AlertComponent],
|
||||
styles: [`
|
||||
.actions{display:flex;align-items:center;gap:var(--rhc-space-max-md);margin-block-start:var(--rhc-space-max-sm)}
|
||||
`],
|
||||
styles: [
|
||||
`
|
||||
.actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--rhc-space-max-md);
|
||||
margin-block-start: var(--rhc-space-max-sm);
|
||||
}
|
||||
`,
|
||||
],
|
||||
template: `
|
||||
@if (aanvraag().status.tag === 'Concept') {
|
||||
<app-alert type="warning">
|
||||
@@ -23,10 +30,14 @@ import { blockActions } from '@registratie/domain/block-actions';
|
||||
<p>{{ conceptText() }}</p>
|
||||
<div class="actions">
|
||||
@if (actions().includes('cancel')) {
|
||||
<app-button variant="subtle" (click)="cancel.emit()" i18n="@@aanvraagBlock.verwijderen">Verwijderen</app-button>
|
||||
<app-button variant="subtle" (click)="cancel.emit()" i18n="@@aanvraagBlock.verwijderen"
|
||||
>Verwijderen</app-button
|
||||
>
|
||||
}
|
||||
@if (actions().includes('resume')) {
|
||||
<app-button (click)="resume.emit()" i18n="@@aanvraagBlock.openen">Aanvraag openen</app-button>
|
||||
<app-button (click)="resume.emit()" i18n="@@aanvraagBlock.openen"
|
||||
>Aanvraag openen</app-button
|
||||
>
|
||||
}
|
||||
</div>
|
||||
</app-alert>
|
||||
@@ -59,5 +70,7 @@ export class AanvraagBlockComponent {
|
||||
}
|
||||
|
||||
function formatNL(iso?: string): string {
|
||||
return iso ? new Date(iso).toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' }) : '';
|
||||
return iso
|
||||
? new Date(iso).toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' })
|
||||
: '';
|
||||
}
|
||||
|
||||
@@ -38,7 +38,36 @@ export const Concept: Story = {
|
||||
args: { aanvraag: { ...base, status: { tag: 'Concept', stepIndex: 1, stepCount: 3 } } },
|
||||
render: (args) => ({ props: args, template: `<app-aanvraag-block [aanvraag]="aanvraag" />` }),
|
||||
};
|
||||
export const InBehandelingAuto: Story = { args: { aanvraag: { ...base, status: { tag: 'InBehandeling', referentie: 'BIG-2026-456789', manual: false } } } };
|
||||
export const InBehandelingManual: Story = { args: { aanvraag: { ...base, type: 'registratie', status: { tag: 'InBehandeling', referentie: 'BIG-2026-456789', manual: true } } } };
|
||||
export const Goedgekeurd: Story = { args: { aanvraag: { ...base, status: { tag: 'Goedgekeurd', referentie: 'BIG-2026-456789' } } } };
|
||||
export const Afgewezen: Story = { args: { aanvraag: { ...base, type: 'herregistratie', status: { tag: 'Afgewezen', referentie: 'BIG-2026-456789', reden: 'Aanvraag afgewezen: geen gewerkte uren geregistreerd.' } } } };
|
||||
export const InBehandelingAuto: Story = {
|
||||
args: {
|
||||
aanvraag: {
|
||||
...base,
|
||||
status: { tag: 'InBehandeling', referentie: 'BIG-2026-456789', manual: false },
|
||||
},
|
||||
},
|
||||
};
|
||||
export const InBehandelingManual: Story = {
|
||||
args: {
|
||||
aanvraag: {
|
||||
...base,
|
||||
type: 'registratie',
|
||||
status: { tag: 'InBehandeling', referentie: 'BIG-2026-456789', manual: true },
|
||||
},
|
||||
},
|
||||
};
|
||||
export const Goedgekeurd: Story = {
|
||||
args: { aanvraag: { ...base, status: { tag: 'Goedgekeurd', referentie: 'BIG-2026-456789' } } },
|
||||
};
|
||||
export const Afgewezen: Story = {
|
||||
args: {
|
||||
aanvraag: {
|
||||
...base,
|
||||
type: 'herregistratie',
|
||||
status: {
|
||||
tag: 'Afgewezen',
|
||||
referentie: 'BIG-2026-456789',
|
||||
reden: 'Aanvraag afgewezen: geen gewerkte uren geregistreerd.',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -15,14 +15,28 @@ import { detailRows } from '@registratie/domain/aanvraag-view';
|
||||
handling is future work. The dashboard "Mijn aanvragen" rows link here. */
|
||||
@Component({
|
||||
selector: 'app-aanvraag-detail-page',
|
||||
imports: [PageShellComponent, SkeletonComponent, AlertComponent, DataBlockComponent, DataRowComponent, ...ASYNC],
|
||||
imports: [
|
||||
PageShellComponent,
|
||||
SkeletonComponent,
|
||||
AlertComponent,
|
||||
DataBlockComponent,
|
||||
DataRowComponent,
|
||||
...ASYNC,
|
||||
],
|
||||
template: `
|
||||
<app-page-shell i18n-heading="@@aanvraagDetail.heading" heading="Aanvraag" backLink="/dashboard">
|
||||
<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">
|
||||
<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>
|
||||
}
|
||||
@@ -31,7 +45,9 @@ import { detailRows } from '@registratie/domain/aanvraag-view';
|
||||
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>
|
||||
<app-alert type="warning" i18n="@@aanvraagDetail.nietGevonden"
|
||||
>Deze aanvraag is niet gevonden.</app-alert
|
||||
>
|
||||
}
|
||||
</ng-template>
|
||||
<ng-template appAsyncLoading>
|
||||
|
||||
@@ -19,27 +19,73 @@ export type AdresErrors = Partial<Record<keyof AdresValue, string>>;
|
||||
@Component({
|
||||
selector: 'app-address-fields',
|
||||
imports: [FormsModule, FormFieldComponent, TextInputComponent],
|
||||
styles: [`
|
||||
fieldset{border:0;margin:0;padding:0;min-inline-size:0}
|
||||
legend{padding:0;font-weight:var(--rhc-text-font-weight-semi-bold);margin-block-end:var(--rhc-space-max-md)}
|
||||
`],
|
||||
styles: [
|
||||
`
|
||||
fieldset {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-inline-size: 0;
|
||||
}
|
||||
legend {
|
||||
padding: 0;
|
||||
font-weight: var(--rhc-text-font-weight-semi-bold);
|
||||
margin-block-end: var(--rhc-space-max-md);
|
||||
}
|
||||
`,
|
||||
],
|
||||
template: `
|
||||
<fieldset>
|
||||
<legend>{{ legend() }}</legend>
|
||||
<app-form-field i18n-label="@@address.straat" label="Straat en huisnummer" [fieldId]="idPrefix() + '-straat'" required [error]="errors().straat">
|
||||
<app-text-input [inputId]="idPrefix() + '-straat'" [invalid]="!!errors().straat"
|
||||
[ngModel]="value().straat" (ngModelChange)="fieldChange.emit({ key: 'straat', value: $event })"
|
||||
name="straat" [ngModelOptions]="{ standalone: true }" />
|
||||
<app-form-field
|
||||
i18n-label="@@address.straat"
|
||||
label="Straat en huisnummer"
|
||||
[fieldId]="idPrefix() + '-straat'"
|
||||
required
|
||||
[error]="errors().straat"
|
||||
>
|
||||
<app-text-input
|
||||
[inputId]="idPrefix() + '-straat'"
|
||||
[invalid]="!!errors().straat"
|
||||
[ngModel]="value().straat"
|
||||
(ngModelChange)="fieldChange.emit({ key: 'straat', value: $event })"
|
||||
name="straat"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</app-form-field>
|
||||
<app-form-field i18n-label="@@address.postcode" label="Postcode" [fieldId]="idPrefix() + '-postcode'" required [error]="errors().postcode">
|
||||
<app-text-input [inputId]="idPrefix() + '-postcode'" [invalid]="!!errors().postcode"
|
||||
[ngModel]="value().postcode" (ngModelChange)="fieldChange.emit({ key: 'postcode', value: $event })"
|
||||
name="postcode" i18n-placeholder="@@address.postcodePlaceholder" placeholder="1234 AB" [ngModelOptions]="{ standalone: true }" />
|
||||
<app-form-field
|
||||
i18n-label="@@address.postcode"
|
||||
label="Postcode"
|
||||
[fieldId]="idPrefix() + '-postcode'"
|
||||
required
|
||||
[error]="errors().postcode"
|
||||
>
|
||||
<app-text-input
|
||||
[inputId]="idPrefix() + '-postcode'"
|
||||
[invalid]="!!errors().postcode"
|
||||
[ngModel]="value().postcode"
|
||||
(ngModelChange)="fieldChange.emit({ key: 'postcode', value: $event })"
|
||||
name="postcode"
|
||||
i18n-placeholder="@@address.postcodePlaceholder"
|
||||
placeholder="1234 AB"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</app-form-field>
|
||||
<app-form-field i18n-label="@@address.woonplaats" label="Woonplaats" [fieldId]="idPrefix() + '-woonplaats'" required [error]="errors().woonplaats">
|
||||
<app-text-input [inputId]="idPrefix() + '-woonplaats'" [invalid]="!!errors().woonplaats"
|
||||
[ngModel]="value().woonplaats" (ngModelChange)="fieldChange.emit({ key: 'woonplaats', value: $event })"
|
||||
name="woonplaats" [ngModelOptions]="{ standalone: true }" />
|
||||
<app-form-field
|
||||
i18n-label="@@address.woonplaats"
|
||||
label="Woonplaats"
|
||||
[fieldId]="idPrefix() + '-woonplaats'"
|
||||
required
|
||||
[error]="errors().woonplaats"
|
||||
>
|
||||
<app-text-input
|
||||
[inputId]="idPrefix() + '-woonplaats'"
|
||||
[invalid]="!!errors().woonplaats"
|
||||
[ngModel]="value().woonplaats"
|
||||
(ngModelChange)="fieldChange.emit({ key: 'woonplaats', value: $event })"
|
||||
name="woonplaats"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
</app-form-field>
|
||||
</fieldset>
|
||||
`,
|
||||
|
||||
@@ -20,12 +20,18 @@ const empty = { straat: '', postcode: '', woonplaats: '' };
|
||||
export const Default: Story = { args: { value: empty, errors: {} } };
|
||||
|
||||
export const Prefilled: Story = {
|
||||
args: { value: { straat: 'Stationsplein 1', postcode: '3511 ED', woonplaats: 'Utrecht' }, errors: {} },
|
||||
args: {
|
||||
value: { straat: 'Stationsplein 1', postcode: '3511 ED', woonplaats: 'Utrecht' },
|
||||
errors: {},
|
||||
},
|
||||
};
|
||||
|
||||
export const WithErrors: Story = {
|
||||
args: {
|
||||
value: { straat: '', postcode: '12', woonplaats: '' },
|
||||
errors: { straat: 'Vul een straat en huisnummer in.', postcode: 'Voer een geldige postcode in, bijv. 1234 AB.' },
|
||||
errors: {
|
||||
straat: 'Vul een straat en huisnummer in.',
|
||||
postcode: 'Voer een geldige postcode in, bijv. 1234 AB.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -3,7 +3,11 @@ import { FormsModule } from '@angular/forms';
|
||||
import { ButtonComponent } from '@shared/ui/button/button.component';
|
||||
import { HeadingComponent } from '@shared/ui/heading/heading.component';
|
||||
import { AlertComponent } from '@shared/ui/alert/alert.component';
|
||||
import { AddressFieldsComponent, AdresValue, AdresErrors } from '@registratie/ui/address-fields/address-fields.component';
|
||||
import {
|
||||
AddressFieldsComponent,
|
||||
AdresValue,
|
||||
AdresErrors,
|
||||
} from '@registratie/ui/address-fields/address-fields.component';
|
||||
import { createStore } from '@shared/application/store';
|
||||
import { whenTag } from '@shared/kernel/fp';
|
||||
import { State, Msg, initial, reduce } from '@registratie/domain/change-request.machine';
|
||||
@@ -21,25 +25,37 @@ import { createSubmitChangeRequest } from '@registratie/application/submit-chang
|
||||
template: `
|
||||
@if (state().tag === 'Submitted') {
|
||||
<app-alert type="ok" i18n="@@changeRequest.success">
|
||||
Uw adreswijziging is ontvangen (referentie {{ referentie() }}). U ontvangt binnen 5 werkdagen bericht.
|
||||
Uw adreswijziging is ontvangen (referentie {{ referentie() }}). U ontvangt binnen 5
|
||||
werkdagen bericht.
|
||||
</app-alert>
|
||||
<div class="app-section">
|
||||
<app-button variant="secondary" (click)="dispatch({ tag: 'Reset' })" i18n="@@changeRequest.nieuwe">Nieuwe wijziging doorgeven</app-button>
|
||||
<app-button
|
||||
variant="secondary"
|
||||
(click)="dispatch({ tag: 'Reset' })"
|
||||
i18n="@@changeRequest.nieuwe"
|
||||
>Nieuwe wijziging doorgeven</app-button
|
||||
>
|
||||
</div>
|
||||
} @else {
|
||||
<app-heading [level]="2" i18n="@@changeRequest.heading">Adreswijziging doorgeven</app-heading>
|
||||
<form (ngSubmit)="onSubmit()" class="form-horizontal app-section">
|
||||
<div class="form-header">
|
||||
<div class="form-action"><span class="meta" i18n="@@form.verplichteVelden">* verplichte velden</span></div>
|
||||
<div class="form-action">
|
||||
<span class="meta" i18n="@@form.verplichteVelden">* verplichte velden</span>
|
||||
</div>
|
||||
</div>
|
||||
<app-address-fields
|
||||
idPrefix="cr"
|
||||
[value]="adres()"
|
||||
[errors]="errors()"
|
||||
(fieldChange)="dispatch({ tag: 'SetField', key: $event.key, value: $event.value })" />
|
||||
(fieldChange)="dispatch({ tag: 'SetField', key: $event.key, value: $event.value })"
|
||||
/>
|
||||
|
||||
@if (failedError()) {
|
||||
<app-alert type="error"><ng-container i18n="@@changeRequest.failed">Het indienen is niet gelukt:</ng-container> {{ failedError() }}</app-alert>
|
||||
<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'">
|
||||
|
||||
@@ -5,7 +5,11 @@ import { ChangeRequestFormComponent } from './change-request-form.component';
|
||||
import { provideApiClient } from '@shared/infrastructure/api-client.provider';
|
||||
import { Postcode } from '@registratie/domain/value-objects/postcode';
|
||||
|
||||
const validData = { straat: 'Lange Voorhout 9', postcode: '2514 EA' as Postcode, woonplaats: 'Den Haag' };
|
||||
const validData = {
|
||||
straat: 'Lange Voorhout 9',
|
||||
postcode: '2514 EA' as Postcode,
|
||||
woonplaats: 'Den Haag',
|
||||
};
|
||||
|
||||
const meta: Meta<ChangeRequestFormComponent> = {
|
||||
title: 'Organisms/Change Request Form',
|
||||
@@ -17,16 +21,27 @@ export default meta;
|
||||
type Story = StoryObj<ChangeRequestFormComponent>;
|
||||
|
||||
// One render per state of the machine.
|
||||
export const Empty: Story = { args: { seed: { tag: 'Editing', draft: { straat: '', postcode: '', woonplaats: '' }, errors: {} } } };
|
||||
export const Empty: Story = {
|
||||
args: {
|
||||
seed: { tag: 'Editing', draft: { straat: '', postcode: '', woonplaats: '' }, errors: {} },
|
||||
},
|
||||
};
|
||||
export const WithErrors: Story = {
|
||||
args: {
|
||||
seed: {
|
||||
tag: 'Editing',
|
||||
draft: { straat: '', postcode: 'nope', woonplaats: '' },
|
||||
errors: { straat: 'Vul straat en huisnummer in.', postcode: 'Voer een geldige postcode in, bijv. 1234 AB.' },
|
||||
errors: {
|
||||
straat: 'Vul straat en huisnummer in.',
|
||||
postcode: 'Voer een geldige postcode in, bijv. 1234 AB.',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
export const Submitting: Story = { args: { seed: { tag: 'Submitting', data: validData } } };
|
||||
export const Submitted: Story = { args: { seed: { tag: 'Submitted', data: validData, referentie: 'BIG-2026-123456' } } };
|
||||
export const Failed: Story = { args: { seed: { tag: 'Failed', data: validData, error: 'Netwerkfout' } } };
|
||||
export const Submitted: Story = {
|
||||
args: { seed: { tag: 'Submitted', data: validData, referentie: 'BIG-2026-123456' } },
|
||||
};
|
||||
export const Failed: Story = {
|
||||
args: { seed: { tag: 'Failed', data: validData, error: 'Netwerkfout' } },
|
||||
};
|
||||
|
||||
@@ -25,91 +25,163 @@ import { tasksFromProfile } from '@registratie/domain/tasks';
|
||||
@Component({
|
||||
selector: 'app-dashboard-page',
|
||||
imports: [
|
||||
PageShellComponent, HeadingComponent, AlertComponent, SkeletonComponent,
|
||||
DataRowComponent, DataBlockComponent, TaskListComponent, ApplicationListComponent, ApplicationLinkComponent,
|
||||
PageShellComponent,
|
||||
HeadingComponent,
|
||||
AlertComponent,
|
||||
SkeletonComponent,
|
||||
DataRowComponent,
|
||||
DataBlockComponent,
|
||||
TaskListComponent,
|
||||
ApplicationListComponent,
|
||||
ApplicationLinkComponent,
|
||||
...ASYNC,
|
||||
RegistrationSummaryComponent, RegistrationTableComponent, AanvraagBlockComponent,
|
||||
RegistrationSummaryComponent,
|
||||
RegistrationTableComponent,
|
||||
AanvraagBlockComponent,
|
||||
],
|
||||
template: `
|
||||
<app-page-shell i18n-heading="@@dashboard.heading" heading="Mijn overzicht" i18n-intro="@@dashboard.intro" intro="Welkom in uw persoonlijke omgeving van het BIG-register. Hier ziet u uw registratie en regelt u uw zaken.">
|
||||
<div class="app-stack">
|
||||
@if (aanvragen().length) {
|
||||
<app-page-shell
|
||||
i18n-heading="@@dashboard.heading"
|
||||
heading="Mijn overzicht"
|
||||
i18n-intro="@@dashboard.intro"
|
||||
intro="Welkom in uw persoonlijke omgeving van het BIG-register. Hier ziet u uw registratie en regelt u uw zaken."
|
||||
>
|
||||
<div class="app-stack">
|
||||
@if (aanvragen().length) {
|
||||
<section>
|
||||
@for (a of concepten(); track a.id) {
|
||||
<app-aanvraag-block
|
||||
animate.enter="app-item-enter"
|
||||
animate.leave="app-item-leave"
|
||||
[aanvraag]="a"
|
||||
(resume)="resume(a)"
|
||||
(cancel)="cancelAanvraag(a)"
|
||||
/>
|
||||
}
|
||||
@if (ingediend().length) {
|
||||
<app-heading [level]="2" class="app-section" i18n="@@dashboard.mijnAanvragen"
|
||||
>Mijn aanvragen</app-heading
|
||||
>
|
||||
<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"
|
||||
[subtitle]="row.subtitle"
|
||||
[status]="row.status"
|
||||
[to]="'/aanvraag/' + a.id"
|
||||
></li>
|
||||
}
|
||||
</app-application-list>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
|
||||
@if (store.pendingHerregistratie()) {
|
||||
<app-alert type="info" i18n="@@dashboard.pendingHerregistratie"
|
||||
>Uw herregistratie-aanvraag is in behandeling.</app-alert
|
||||
>
|
||||
}
|
||||
|
||||
<app-async [data]="store.profile()">
|
||||
<ng-template appAsyncLoaded let-p>
|
||||
@let tasks = tasksFor($any(p).registration);
|
||||
|
||||
<section>
|
||||
@for (a of concepten(); track a.id) {
|
||||
<app-aanvraag-block animate.enter="app-item-enter" animate.leave="app-item-leave" [aanvraag]="a" (resume)="resume(a)" (cancel)="cancelAanvraag(a)" />
|
||||
}
|
||||
@if (ingediend().length) {
|
||||
<app-heading [level]="2" class="app-section" i18n="@@dashboard.mijnAanvragen">Mijn aanvragen</app-heading>
|
||||
<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" [subtitle]="row.subtitle" [status]="row.status" [to]="'/aanvraag/' + a.id"></li>
|
||||
}
|
||||
</app-application-list>
|
||||
@if (tasks.length) {
|
||||
<app-task-list
|
||||
class="app-section"
|
||||
i18n-listHeading="@@dashboard.watMoetIkRegelen"
|
||||
listHeading="Wat moet ik regelen"
|
||||
[tasks]="tasks"
|
||||
/>
|
||||
} @else {
|
||||
<app-heading [level]="2" i18n="@@dashboard.watMoetIkRegelen"
|
||||
>Wat moet ik regelen</app-heading
|
||||
>
|
||||
<p class="app-text-subtle" i18n="@@dashboard.nietsOpenstaan">
|
||||
U heeft op dit moment niets openstaan.
|
||||
</p>
|
||||
}
|
||||
</section>
|
||||
}
|
||||
|
||||
@if (store.pendingHerregistratie()) {
|
||||
<app-alert type="info" i18n="@@dashboard.pendingHerregistratie">Uw herregistratie-aanvraag is in behandeling.</app-alert>
|
||||
}
|
||||
<section>
|
||||
<app-heading [level]="2" i18n="@@dashboard.mijnRegistratie"
|
||||
>Mijn registratie</app-heading
|
||||
>
|
||||
<div class="app-section">
|
||||
<app-registration-summary [reg]="$any(p).registration" />
|
||||
</div>
|
||||
<app-data-block
|
||||
class="app-section"
|
||||
i18n-heading="@@dashboard.persoonsgegevens"
|
||||
heading="Persoonsgegevens (BRP)"
|
||||
>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@dashboard.straat"
|
||||
key="Straat"
|
||||
[value]="$any(p).person.adres.straat"
|
||||
></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@dashboard.postcode"
|
||||
key="Postcode"
|
||||
[value]="$any(p).person.adres.postcode"
|
||||
></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@dashboard.woonplaats"
|
||||
key="Woonplaats"
|
||||
[value]="$any(p).person.adres.woonplaats"
|
||||
></div>
|
||||
</app-data-block>
|
||||
</section>
|
||||
</ng-template>
|
||||
<ng-template appAsyncLoading>
|
||||
<app-skeleton height="2.5rem" [count]="6" />
|
||||
</ng-template>
|
||||
</app-async>
|
||||
|
||||
<app-async [data]="store.profile()">
|
||||
<ng-template appAsyncLoaded let-p>
|
||||
@let tasks = tasksFor($any(p).registration);
|
||||
<section>
|
||||
<app-heading [level]="2" i18n="@@dashboard.specialismen"
|
||||
>Specialismen en aantekeningen</app-heading
|
||||
>
|
||||
<div class="app-section">
|
||||
<app-async [data]="store.aantekeningen()">
|
||||
<ng-template appAsyncLoaded let-r>
|
||||
<app-registration-table [rows]="$any(r)" />
|
||||
</ng-template>
|
||||
<ng-template appAsyncLoading>
|
||||
<app-skeleton height="2.5rem" [count]="3" />
|
||||
</ng-template>
|
||||
<ng-template appAsyncEmpty>
|
||||
<p class="app-text-subtle" i18n="@@dashboard.geenSpecialismen">
|
||||
U heeft nog geen specialismen of aantekeningen.
|
||||
</p>
|
||||
</ng-template>
|
||||
</app-async>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@if (tasks.length) {
|
||||
<app-task-list class="app-section" i18n-listHeading="@@dashboard.watMoetIkRegelen" listHeading="Wat moet ik regelen" [tasks]="tasks" />
|
||||
} @else {
|
||||
<app-heading [level]="2" i18n="@@dashboard.watMoetIkRegelen">Wat moet ik regelen</app-heading>
|
||||
<p class="app-text-subtle" i18n="@@dashboard.nietsOpenstaan">U heeft op dit moment niets openstaan.</p>
|
||||
}
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<app-heading [level]="2" i18n="@@dashboard.mijnRegistratie">Mijn registratie</app-heading>
|
||||
<div class="app-section">
|
||||
<app-registration-summary [reg]="$any(p).registration" />
|
||||
</div>
|
||||
<app-data-block class="app-section" i18n-heading="@@dashboard.persoonsgegevens" heading="Persoonsgegevens (BRP)">
|
||||
<div app-data-row i18n-key="@@dashboard.straat" key="Straat" [value]="$any(p).person.adres.straat"></div>
|
||||
<div app-data-row i18n-key="@@dashboard.postcode" key="Postcode" [value]="$any(p).person.adres.postcode"></div>
|
||||
<div app-data-row i18n-key="@@dashboard.woonplaats" key="Woonplaats" [value]="$any(p).person.adres.woonplaats"></div>
|
||||
</app-data-block>
|
||||
</section>
|
||||
</ng-template>
|
||||
<ng-template appAsyncLoading>
|
||||
<app-skeleton height="2.5rem" [count]="6" />
|
||||
</ng-template>
|
||||
</app-async>
|
||||
|
||||
<section>
|
||||
<app-heading [level]="2" i18n="@@dashboard.specialismen">Specialismen en aantekeningen</app-heading>
|
||||
<div class="app-section">
|
||||
<app-async [data]="store.aantekeningen()">
|
||||
<ng-template appAsyncLoaded let-r>
|
||||
<app-registration-table [rows]="$any(r)" />
|
||||
</ng-template>
|
||||
<ng-template appAsyncLoading>
|
||||
<app-skeleton height="2.5rem" [count]="3" />
|
||||
</ng-template>
|
||||
<ng-template appAsyncEmpty>
|
||||
<p class="app-text-subtle" i18n="@@dashboard.geenSpecialismen">U heeft nog geen specialismen of aantekeningen.</p>
|
||||
</ng-template>
|
||||
</app-async>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<app-heading [level]="2" i18n="@@dashboard.watWiltUDoen">Wat wilt u doen?</app-heading>
|
||||
<app-application-list class="app-section">
|
||||
@for (a of acties; track a.to) {
|
||||
<li app-application-link [heading]="a.titel" [subtitle]="a.tekst" [cta]="a.actie" [to]="a.to"></li>
|
||||
}
|
||||
</app-application-list>
|
||||
</section>
|
||||
</div>
|
||||
<section>
|
||||
<app-heading [level]="2" i18n="@@dashboard.watWiltUDoen">Wat wilt u doen?</app-heading>
|
||||
<app-application-list class="app-section">
|
||||
@for (a of acties; track a.to) {
|
||||
<li
|
||||
app-application-link
|
||||
[heading]="a.titel"
|
||||
[subtitle]="a.tekst"
|
||||
[cta]="a.actie"
|
||||
[to]="a.to"
|
||||
></li>
|
||||
}
|
||||
</app-application-list>
|
||||
</section>
|
||||
</div>
|
||||
</app-page-shell>
|
||||
`,
|
||||
})
|
||||
@@ -132,7 +204,12 @@ export class DashboardPage {
|
||||
protected aanvragen = computed<Aanvraag[]>(() => {
|
||||
const rd = this.apps.applications();
|
||||
if (rd.tag !== 'Success') return [];
|
||||
const order: Record<Aanvraag['status']['tag'], number> = { Concept: 0, InBehandeling: 1, Goedgekeurd: 2, Afgewezen: 2 };
|
||||
const order: Record<Aanvraag['status']['tag'], number> = {
|
||||
Concept: 0,
|
||||
InBehandeling: 1,
|
||||
Goedgekeurd: 2,
|
||||
Afgewezen: 2,
|
||||
};
|
||||
return rd.value.slice().sort((a, b) => order[a.status.tag] - order[b.status.tag]);
|
||||
});
|
||||
/** A Concept ("lopende aanvraag") renders as a melding above the list; the rest
|
||||
@@ -166,11 +243,41 @@ export class DashboardPage {
|
||||
componenten/aanvragen). The core portal sections live in the header nav now;
|
||||
the teaching pages (concepts/brief) are only reachable from here. */
|
||||
protected readonly acties = [
|
||||
{ to: '/registreren', titel: $localize`:@@dashboard.actie.inschrijven.titel:Inschrijven`, tekst: $localize`:@@dashboard.actie.inschrijven.tekst:Schrijf u in in het BIG-register via de registratiewizard.`, actie: $localize`:@@dashboard.actie.inschrijven.actie:Start inschrijving` },
|
||||
{ to: '/herregistratie', titel: $localize`:@@dashboard.actie.herregistratie.titel:Herregistratie aanvragen`, tekst: $localize`:@@dashboard.actie.herregistratie.tekst:Verleng uw registratie voor de komende periode.`, actie: $localize`:@@dashboard.actie.herregistratie.actie:Vraag aan` },
|
||||
{ to: '/intake', titel: $localize`:@@dashboard.actie.intake.titel:Herregistratie-intake`, tekst: $localize`:@@dashboard.actie.intake.tekst:Vragenlijst met vertakkingen.`, actie: $localize`:@@dashboard.actie.intake.actie:Start intake` },
|
||||
{ to: '/registratie', titel: $localize`:@@dashboard.actie.wijzigen.titel:Gegevens wijzigen`, tekst: $localize`:@@dashboard.actie.wijzigen.tekst:Bekijk uw gegevens of geef een wijziging door.`, actie: $localize`:@@dashboard.actie.wijzigen.actie:Bekijk gegevens` },
|
||||
{ to: '/concepts', titel: $localize`:@@dashboard.actie.concepten.titel:Functionele patronen`, tekst: $localize`:@@dashboard.actie.concepten.tekst:Bekijk de FP/TEA-bouwstenen van deze POC.`, actie: $localize`:@@dashboard.actie.concepten.actie:Bekijk patronen` },
|
||||
{ to: '/brief', titel: $localize`:@@dashboard.actie.brief.titel:Brief opstellen`, tekst: $localize`:@@dashboard.actie.brief.tekst:Stel een brief samen uit vaste en vrije onderdelen.`, actie: $localize`:@@dashboard.actie.brief.actie:Start brief` },
|
||||
{
|
||||
to: '/registreren',
|
||||
titel: $localize`:@@dashboard.actie.inschrijven.titel:Inschrijven`,
|
||||
tekst: $localize`:@@dashboard.actie.inschrijven.tekst:Schrijf u in in het BIG-register via de registratiewizard.`,
|
||||
actie: $localize`:@@dashboard.actie.inschrijven.actie:Start inschrijving`,
|
||||
},
|
||||
{
|
||||
to: '/herregistratie',
|
||||
titel: $localize`:@@dashboard.actie.herregistratie.titel:Herregistratie aanvragen`,
|
||||
tekst: $localize`:@@dashboard.actie.herregistratie.tekst:Verleng uw registratie voor de komende periode.`,
|
||||
actie: $localize`:@@dashboard.actie.herregistratie.actie:Vraag aan`,
|
||||
},
|
||||
{
|
||||
to: '/intake',
|
||||
titel: $localize`:@@dashboard.actie.intake.titel:Herregistratie-intake`,
|
||||
tekst: $localize`:@@dashboard.actie.intake.tekst:Vragenlijst met vertakkingen.`,
|
||||
actie: $localize`:@@dashboard.actie.intake.actie:Start intake`,
|
||||
},
|
||||
{
|
||||
to: '/registratie',
|
||||
titel: $localize`:@@dashboard.actie.wijzigen.titel:Gegevens wijzigen`,
|
||||
tekst: $localize`:@@dashboard.actie.wijzigen.tekst:Bekijk uw gegevens of geef een wijziging door.`,
|
||||
actie: $localize`:@@dashboard.actie.wijzigen.actie:Bekijk gegevens`,
|
||||
},
|
||||
{
|
||||
to: '/concepts',
|
||||
titel: $localize`:@@dashboard.actie.concepten.titel:Functionele patronen`,
|
||||
tekst: $localize`:@@dashboard.actie.concepten.tekst:Bekijk de FP/TEA-bouwstenen van deze POC.`,
|
||||
actie: $localize`:@@dashboard.actie.concepten.actie:Bekijk patronen`,
|
||||
},
|
||||
{
|
||||
to: '/brief',
|
||||
titel: $localize`:@@dashboard.actie.brief.titel:Brief opstellen`,
|
||||
tekst: $localize`:@@dashboard.actie.brief.tekst:Stel een brief samen uit vaste en vrije onderdelen.`,
|
||||
actie: $localize`:@@dashboard.actie.brief.actie:Start brief`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -9,7 +9,12 @@ import { SkeletonComponent } from '@shared/ui/skeleton/skeleton.component';
|
||||
import { DataRowComponent } from '@shared/ui/data-row/data-row.component';
|
||||
import { ReviewSectionComponent } from '@shared/ui/review-section/review-section.component';
|
||||
import { ConfirmationComponent } from '@shared/ui/confirmation/confirmation.component';
|
||||
import { WizardShellComponent, WizardError, WizardStatus, naarStapLabel } from '@shared/layout/wizard-shell/wizard-shell.component';
|
||||
import {
|
||||
WizardShellComponent,
|
||||
WizardError,
|
||||
WizardStatus,
|
||||
naarStapLabel,
|
||||
} from '@shared/layout/wizard-shell/wizard-shell.component';
|
||||
import { ASYNC } from '@shared/ui/async/async.component';
|
||||
import { AddressFieldsComponent } from '@registratie/ui/address-fields/address-fields.component';
|
||||
import { createStore } from '@shared/application/store';
|
||||
@@ -54,138 +59,291 @@ const NL_TAALVAARDIGHEID_VRAAG = 'nl-taalvaardigheid';
|
||||
@Component({
|
||||
selector: 'app-registratie-wizard',
|
||||
imports: [
|
||||
FormsModule, FormFieldComponent, TextInputComponent, RadioGroupComponent, ButtonComponent,
|
||||
AlertComponent, SkeletonComponent, DataRowComponent, ReviewSectionComponent, ConfirmationComponent, WizardShellComponent,
|
||||
AddressFieldsComponent, DocumentUploadComponent, ...ASYNC,
|
||||
FormsModule,
|
||||
FormFieldComponent,
|
||||
TextInputComponent,
|
||||
RadioGroupComponent,
|
||||
ButtonComponent,
|
||||
AlertComponent,
|
||||
SkeletonComponent,
|
||||
DataRowComponent,
|
||||
ReviewSectionComponent,
|
||||
ConfirmationComponent,
|
||||
WizardShellComponent,
|
||||
AddressFieldsComponent,
|
||||
DocumentUploadComponent,
|
||||
...ASYNC,
|
||||
],
|
||||
template: `
|
||||
<app-wizard-shell
|
||||
[steps]="stepLabels"
|
||||
[current]="cursor()"
|
||||
[stepTitle]="stepTitle()"
|
||||
i18n-processName="@@regWizard.processName" processName="Inschrijven in het BIG-register"
|
||||
i18n-processName="@@regWizard.processName"
|
||||
processName="Inschrijven in het BIG-register"
|
||||
[status]="shellStatus()"
|
||||
[primaryLabel]="primaryLabel()"
|
||||
[canGoBack]="cursor() > 0"
|
||||
[errors]="errorList()"
|
||||
[errorMessage]="errorMessage()"
|
||||
i18n-submittingLabel="@@regWizard.submitting" submittingLabel="Uw registratie wordt verwerkt…"
|
||||
i18n-submittingLabel="@@regWizard.submitting"
|
||||
submittingLabel="Uw registratie wordt verwerkt…"
|
||||
(primary)="onPrimary()"
|
||||
(back)="dispatch({ tag: 'Back' })"
|
||||
(cancel)="restart()"
|
||||
(retry)="onRetry()"
|
||||
(goToStep)="dispatch({ tag: 'GaNaarStap', cursor: $event })">
|
||||
|
||||
(goToStep)="dispatch({ tag: 'GaNaarStap', cursor: $event })"
|
||||
>
|
||||
@switch (step()) {
|
||||
@case ('adres') {
|
||||
@if (adresStatus() === 'laden') {
|
||||
<app-skeleton height="2.5rem" [count]="4" />
|
||||
} @else {
|
||||
@switch (adresStatus()) {
|
||||
@case ('gevonden') {
|
||||
<app-alert type="info" i18n="@@regWizard.brpGevonden">Vooraf ingevuld op basis van de BRP. Controleer en pas zo nodig aan.</app-alert>
|
||||
}
|
||||
@case ('geen') {
|
||||
<app-alert type="warning" i18n="@@regWizard.brpGeen">We vonden geen adres in de BRP. Vul uw adres hieronder handmatig in.</app-alert>
|
||||
}
|
||||
@case ('fout') {
|
||||
<app-alert type="warning" i18n="@@regWizard.brpFout">We konden de BRP nu niet bereiken. Vul uw adres hieronder handmatig in.</app-alert>
|
||||
}
|
||||
}
|
||||
<app-address-fields
|
||||
[value]="{ straat: draft().straat ?? '', postcode: draft().postcode ?? '', woonplaats: draft().woonplaats ?? '' }"
|
||||
[errors]="{ straat: err('straat'), postcode: err('postcode'), woonplaats: err('woonplaats') }"
|
||||
(fieldChange)="set($event.key, $event.value)" />
|
||||
<app-form-field i18n-label="@@regWizard.correspondentieLabel" label="Hoe wilt u correspondentie ontvangen?" fieldId="correspondentie" required [error]="err('correspondentie')">
|
||||
<app-radio-group name="correspondentie" [options]="kanalen" [invalid]="!!err('correspondentie')"
|
||||
[ngModel]="draft().correspondentie ?? ''" (ngModelChange)="setKanaal($event)" />
|
||||
@if (adresStatus() === 'laden') {
|
||||
<app-skeleton height="2.5rem" [count]="4" />
|
||||
} @else {
|
||||
@switch (adresStatus()) {
|
||||
@case ('gevonden') {
|
||||
<app-alert type="info" i18n="@@regWizard.brpGevonden"
|
||||
>Vooraf ingevuld op basis van de BRP. Controleer en pas zo nodig aan.</app-alert
|
||||
>
|
||||
}
|
||||
@case ('geen') {
|
||||
<app-alert type="warning" i18n="@@regWizard.brpGeen"
|
||||
>We vonden geen adres in de BRP. Vul uw adres hieronder handmatig in.</app-alert
|
||||
>
|
||||
}
|
||||
@case ('fout') {
|
||||
<app-alert type="warning" i18n="@@regWizard.brpFout"
|
||||
>We konden de BRP nu niet bereiken. Vul uw adres hieronder handmatig
|
||||
in.</app-alert
|
||||
>
|
||||
}
|
||||
}
|
||||
<app-address-fields
|
||||
[value]="{
|
||||
straat: draft().straat ?? '',
|
||||
postcode: draft().postcode ?? '',
|
||||
woonplaats: draft().woonplaats ?? '',
|
||||
}"
|
||||
[errors]="{
|
||||
straat: err('straat'),
|
||||
postcode: err('postcode'),
|
||||
woonplaats: err('woonplaats'),
|
||||
}"
|
||||
(fieldChange)="set($event.key, $event.value)"
|
||||
/>
|
||||
<app-form-field
|
||||
i18n-label="@@regWizard.correspondentieLabel"
|
||||
label="Hoe wilt u correspondentie ontvangen?"
|
||||
fieldId="correspondentie"
|
||||
required
|
||||
[error]="err('correspondentie')"
|
||||
>
|
||||
<app-radio-group
|
||||
name="correspondentie"
|
||||
[options]="kanalen"
|
||||
[invalid]="!!err('correspondentie')"
|
||||
[ngModel]="draft().correspondentie ?? ''"
|
||||
(ngModelChange)="setKanaal($event)"
|
||||
/>
|
||||
</app-form-field>
|
||||
@if (draft().correspondentie === 'email') {
|
||||
<app-form-field
|
||||
i18n-label="@@regWizard.emailLabel"
|
||||
label="E-mailadres"
|
||||
fieldId="email"
|
||||
required
|
||||
[error]="err('email')"
|
||||
>
|
||||
<app-text-input
|
||||
inputId="email"
|
||||
type="email"
|
||||
[invalid]="!!err('email')"
|
||||
[ngModel]="draft().email ?? ''"
|
||||
(ngModelChange)="set('email', $event)"
|
||||
name="email"
|
||||
i18n-placeholder="@@regWizard.emailPlaceholder"
|
||||
placeholder="naam@voorbeeld.nl"
|
||||
/>
|
||||
</app-form-field>
|
||||
}
|
||||
}
|
||||
}
|
||||
@case ('beroep') {
|
||||
<app-async [data]="lookupRd()">
|
||||
<ng-template appAsyncLoaded let-data>
|
||||
<app-form-field
|
||||
i18n-label="@@regWizard.diplomaLabel"
|
||||
label="Kies het diploma waarmee u zich wilt registreren"
|
||||
fieldId="diploma"
|
||||
required
|
||||
[error]="err('diploma')"
|
||||
>
|
||||
<app-radio-group
|
||||
name="diploma"
|
||||
[options]="diplomaOptions($any(data))"
|
||||
[invalid]="!!err('diploma')"
|
||||
[ngModel]="diplomaKeuze()"
|
||||
(ngModelChange)="onDiplomaKeuze($any(data), $event)"
|
||||
/>
|
||||
</app-form-field>
|
||||
|
||||
@if (handmatigActief()) {
|
||||
<app-alert type="warning" i18n="@@regWizard.handmatigWaarschuwing"
|
||||
>Een handmatig ingevoerd diploma kan niet automatisch worden geverifieerd. Kies uw
|
||||
beroep en beantwoord de aanvullende vragen; uw aanvraag wordt daarna handmatig
|
||||
beoordeeld.</app-alert
|
||||
>
|
||||
<app-form-field
|
||||
i18n-label="@@regWizard.beroepLabel"
|
||||
label="Voor welk beroep wilt u zich registreren?"
|
||||
fieldId="hm-beroep"
|
||||
[error]="err('diploma')"
|
||||
>
|
||||
<app-radio-group
|
||||
name="hm-beroep"
|
||||
[options]="beroepOptions($any(data))"
|
||||
[invalid]="!!err('diploma')"
|
||||
[ngModel]="draft().beroep ?? ''"
|
||||
(ngModelChange)="dispatch({ tag: 'DeclareerBeroep', beroep: $event })"
|
||||
/>
|
||||
</app-form-field>
|
||||
@if (draft().correspondentie === 'email') {
|
||||
<app-form-field i18n-label="@@regWizard.emailLabel" label="E-mailadres" fieldId="email" required [error]="err('email')">
|
||||
<app-text-input inputId="email" type="email" [invalid]="!!err('email')" [ngModel]="draft().email ?? ''" (ngModelChange)="set('email', $event)" name="email" i18n-placeholder="@@regWizard.emailPlaceholder" placeholder="naam@voorbeeld.nl" />
|
||||
</app-form-field>
|
||||
}
|
||||
} @else if (draft().beroep) {
|
||||
<dl class="mb-0 app-section">
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@regWizard.beroepAfgeleid"
|
||||
key="Beroep (afgeleid uit diploma)"
|
||||
[value]="draft().beroep ?? ''"
|
||||
></div>
|
||||
</dl>
|
||||
}
|
||||
}
|
||||
@case ('beroep') {
|
||||
<app-async [data]="lookupRd()">
|
||||
<ng-template appAsyncLoaded let-data>
|
||||
<app-form-field i18n-label="@@regWizard.diplomaLabel" label="Kies het diploma waarmee u zich wilt registreren" fieldId="diploma" required [error]="err('diploma')">
|
||||
<app-radio-group name="diploma" [options]="diplomaOptions($any(data))" [invalid]="!!err('diploma')"
|
||||
[ngModel]="diplomaKeuze()" (ngModelChange)="onDiplomaKeuze($any(data), $event)" />
|
||||
</app-form-field>
|
||||
|
||||
@if (handmatigActief()) {
|
||||
<app-alert type="warning" i18n="@@regWizard.handmatigWaarschuwing">Een handmatig ingevoerd diploma kan niet automatisch worden geverifieerd. Kies uw beroep en beantwoord de aanvullende vragen; uw aanvraag wordt daarna handmatig beoordeeld.</app-alert>
|
||||
<app-form-field i18n-label="@@regWizard.beroepLabel" label="Voor welk beroep wilt u zich registreren?" fieldId="hm-beroep" [error]="err('diploma')">
|
||||
<app-radio-group name="hm-beroep" [options]="beroepOptions($any(data))" [invalid]="!!err('diploma')"
|
||||
[ngModel]="draft().beroep ?? ''" (ngModelChange)="dispatch({ tag: 'DeclareerBeroep', beroep: $event })" />
|
||||
</app-form-field>
|
||||
} @else if (draft().beroep) {
|
||||
<dl class="mb-0 app-section">
|
||||
<div app-data-row i18n-key="@@regWizard.beroepAfgeleid" key="Beroep (afgeleid uit diploma)" [value]="draft().beroep ?? ''"></div>
|
||||
</dl>
|
||||
@for (q of actieveVragen($any(data)); track q.id) {
|
||||
<app-form-field
|
||||
[label]="q.vraag"
|
||||
[fieldId]="'vraag-' + q.id"
|
||||
[error]="vraagErr(q.id)"
|
||||
>
|
||||
@if (q.type === 'ja-nee') {
|
||||
<app-radio-group
|
||||
[name]="'vraag-' + q.id"
|
||||
[options]="jaNee"
|
||||
[invalid]="!!vraagErr(q.id)"
|
||||
[ngModel]="antwoord(q.id)"
|
||||
(ngModelChange)="
|
||||
dispatch({ tag: 'SetAntwoord', vraagId: q.id, value: $event })
|
||||
"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
} @else {
|
||||
<app-text-input
|
||||
[inputId]="'vraag-' + q.id"
|
||||
[invalid]="!!vraagErr(q.id)"
|
||||
[ngModel]="antwoord(q.id)"
|
||||
(ngModelChange)="
|
||||
dispatch({ tag: 'SetAntwoord', vraagId: q.id, value: $event })
|
||||
"
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
/>
|
||||
}
|
||||
|
||||
@for (q of actieveVragen($any(data)); track q.id) {
|
||||
<app-form-field [label]="q.vraag" [fieldId]="'vraag-' + q.id" [error]="vraagErr(q.id)">
|
||||
@if (q.type === 'ja-nee') {
|
||||
<app-radio-group [name]="'vraag-' + q.id" [options]="jaNee" [invalid]="!!vraagErr(q.id)"
|
||||
[ngModel]="antwoord(q.id)" (ngModelChange)="dispatch({ tag: 'SetAntwoord', vraagId: q.id, value: $event })" [ngModelOptions]="{ standalone: true }" />
|
||||
} @else {
|
||||
<app-text-input [inputId]="'vraag-' + q.id" [invalid]="!!vraagErr(q.id)" [ngModel]="antwoord(q.id)"
|
||||
(ngModelChange)="dispatch({ tag: 'SetAntwoord', vraagId: q.id, value: $event })" [ngModelOptions]="{ standalone: true }" />
|
||||
}
|
||||
</app-form-field>
|
||||
}
|
||||
</ng-template>
|
||||
<ng-template appAsyncLoading>
|
||||
<app-skeleton height="2.5rem" [count]="3" />
|
||||
</ng-template>
|
||||
</app-async>
|
||||
|
||||
<app-document-upload
|
||||
class="app-section"
|
||||
[state]="upload()"
|
||||
[previewUrlFor]="previewUrlFor"
|
||||
(fileSelected)="uploadCtl.onFileSelected($event.categoryId, $event.files)"
|
||||
(removeUpload)="uploadCtl.onRemove($event)"
|
||||
(retryUpload)="uploadCtl.onRetry($event)"
|
||||
(deleteUpload)="uploadCtl.onDelete($event)"
|
||||
(channelChange)="uploadCtl.onChannelChange($event.categoryId, $event.channel)" />
|
||||
@if (err('documenten')) {
|
||||
<app-alert type="warning">{{ err('documenten') }}</app-alert>
|
||||
</app-form-field>
|
||||
}
|
||||
</ng-template>
|
||||
<ng-template appAsyncLoading>
|
||||
<app-skeleton height="2.5rem" [count]="3" />
|
||||
</ng-template>
|
||||
</app-async>
|
||||
|
||||
<app-document-upload
|
||||
class="app-section"
|
||||
[state]="upload()"
|
||||
[previewUrlFor]="previewUrlFor"
|
||||
(fileSelected)="uploadCtl.onFileSelected($event.categoryId, $event.files)"
|
||||
(removeUpload)="uploadCtl.onRemove($event)"
|
||||
(retryUpload)="uploadCtl.onRetry($event)"
|
||||
(deleteUpload)="uploadCtl.onDelete($event)"
|
||||
(channelChange)="uploadCtl.onChannelChange($event.categoryId, $event.channel)"
|
||||
/>
|
||||
@if (err('documenten')) {
|
||||
<app-alert type="warning">{{ err('documenten') }}</app-alert>
|
||||
}
|
||||
}
|
||||
@case ('controle') {
|
||||
<app-alert type="info" i18n="@@regWizard.controleer"
|
||||
>Controleer uw gegevens en dien de registratie in.</app-alert
|
||||
>
|
||||
<app-review-section
|
||||
i18n-heading="@@regWizard.sectie.adres"
|
||||
heading="Adres en correspondentie"
|
||||
i18n-editAriaLabel="@@regWizard.adresWijzigenAria"
|
||||
editAriaLabel="Wijzigen adresgegevens"
|
||||
(edit)="dispatch({ tag: 'GaNaarStap', cursor: 0 })"
|
||||
>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@regWizard.summary.adres"
|
||||
key="Adres"
|
||||
[value]="adresSamenvatting()"
|
||||
></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@regWizard.summary.herkomstAdres"
|
||||
key="Herkomst adres"
|
||||
[value]="adresHerkomstLabel()"
|
||||
></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@regWizard.summary.correspondentie"
|
||||
key="Correspondentie"
|
||||
[value]="correspondentieLabel()"
|
||||
></div>
|
||||
@if (draft().correspondentie === 'email') {
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@regWizard.summary.email"
|
||||
key="E-mailadres"
|
||||
[value]="draft().email ?? ''"
|
||||
></div>
|
||||
}
|
||||
@case ('controle') {
|
||||
<app-alert type="info" i18n="@@regWizard.controleer">Controleer uw gegevens en dien de registratie in.</app-alert>
|
||||
<app-review-section i18n-heading="@@regWizard.sectie.adres" heading="Adres en correspondentie"
|
||||
i18n-editAriaLabel="@@regWizard.adresWijzigenAria" editAriaLabel="Wijzigen adresgegevens"
|
||||
(edit)="dispatch({ tag: 'GaNaarStap', cursor: 0 })">
|
||||
<div app-data-row i18n-key="@@regWizard.summary.adres" key="Adres" [value]="adresSamenvatting()"></div>
|
||||
<div app-data-row i18n-key="@@regWizard.summary.herkomstAdres" key="Herkomst adres" [value]="adresHerkomstLabel()"></div>
|
||||
<div app-data-row i18n-key="@@regWizard.summary.correspondentie" key="Correspondentie" [value]="correspondentieLabel()"></div>
|
||||
@if (draft().correspondentie === 'email') {
|
||||
<div app-data-row i18n-key="@@regWizard.summary.email" key="E-mailadres" [value]="draft().email ?? ''"></div>
|
||||
}
|
||||
</app-review-section>
|
||||
<app-review-section class="app-section" i18n-heading="@@regWizard.sectie.beroep" heading="Beroep en diploma"
|
||||
i18n-editAriaLabel="@@regWizard.diplomaWijzigenAria" editAriaLabel="Wijzigen beroep en diploma"
|
||||
(edit)="dispatch({ tag: 'GaNaarStap', cursor: 1 })">
|
||||
<div app-data-row i18n-key="@@regWizard.summary.beroep" key="Beroep" [value]="draft().beroep ?? ''"></div>
|
||||
<div app-data-row i18n-key="@@regWizard.summary.herkomstDiploma" key="Herkomst diploma" [value]="diplomaHerkomstLabel()"></div>
|
||||
@for (item of samenvattingVragen(); track item.vraag) {
|
||||
<div app-data-row [key]="item.vraag" [value]="item.antwoord"></div>
|
||||
}
|
||||
</app-review-section>
|
||||
</app-review-section>
|
||||
<app-review-section
|
||||
class="app-section"
|
||||
i18n-heading="@@regWizard.sectie.beroep"
|
||||
heading="Beroep en diploma"
|
||||
i18n-editAriaLabel="@@regWizard.diplomaWijzigenAria"
|
||||
editAriaLabel="Wijzigen beroep en diploma"
|
||||
(edit)="dispatch({ tag: 'GaNaarStap', cursor: 1 })"
|
||||
>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@regWizard.summary.beroep"
|
||||
key="Beroep"
|
||||
[value]="draft().beroep ?? ''"
|
||||
></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@regWizard.summary.herkomstDiploma"
|
||||
key="Herkomst diploma"
|
||||
[value]="diplomaHerkomstLabel()"
|
||||
></div>
|
||||
@for (item of samenvattingVragen(); track item.vraag) {
|
||||
<div app-data-row [key]="item.vraag" [value]="item.antwoord"></div>
|
||||
}
|
||||
</app-review-section>
|
||||
}
|
||||
}
|
||||
|
||||
<div wizardSuccess>
|
||||
<app-confirmation i18n-title="@@regWizard.success.title" title="Uw registratie is ontvangen">
|
||||
<p class="app-section" i18n="@@regWizard.success.referentie">Uw referentienummer is {{ referentie() }}. Bewaar dit nummer voor uw administratie.</p>
|
||||
<app-confirmation
|
||||
i18n-title="@@regWizard.success.title"
|
||||
title="Uw registratie is ontvangen"
|
||||
>
|
||||
<p class="app-section" i18n="@@regWizard.success.referentie">
|
||||
Uw referentienummer is {{ referentie() }}. Bewaar dit nummer voor uw administratie.
|
||||
</p>
|
||||
<div class="app-section">
|
||||
<app-button variant="secondary" (click)="restart()" i18n="@@regWizard.nieuweRegistratie">Nieuwe registratie starten</app-button>
|
||||
<app-button variant="secondary" (click)="restart()" i18n="@@regWizard.nieuweRegistratie"
|
||||
>Nieuwe registratie starten</app-button
|
||||
>
|
||||
</div>
|
||||
</app-confirmation>
|
||||
</div>
|
||||
@@ -206,8 +364,16 @@ export class RegistratieWizardComponent {
|
||||
seed = input<RegistratieState>(initial);
|
||||
|
||||
readonly kanalen = KANALEN;
|
||||
readonly stepLabels = [$localize`:@@regWizard.step.adres:Adres`, $localize`:@@regWizard.step.beroep:Beroep`, $localize`:@@regWizard.step.controle:Controle`]; // short labels for the stepper
|
||||
private stepTitles = [$localize`:@@regWizard.title.adres:Adres en correspondentievoorkeur`, $localize`:@@regWizard.title.beroep:Beroep op basis van uw diploma`, $localize`:@@regWizard.title.controle:Controleren en indienen`];
|
||||
readonly stepLabels = [
|
||||
$localize`:@@regWizard.step.adres:Adres`,
|
||||
$localize`:@@regWizard.step.beroep:Beroep`,
|
||||
$localize`:@@regWizard.step.controle:Controle`,
|
||||
]; // short labels for the stepper
|
||||
private stepTitles = [
|
||||
$localize`:@@regWizard.title.adres:Adres en correspondentievoorkeur`,
|
||||
$localize`:@@regWizard.title.beroep:Beroep op basis van uw diploma`,
|
||||
$localize`:@@regWizard.title.controle:Controleren en indienen`,
|
||||
];
|
||||
readonly state = this.store.model;
|
||||
readonly dispatch = this.store.dispatch;
|
||||
|
||||
@@ -234,14 +400,18 @@ export class RegistratieWizardComponent {
|
||||
snapshot: () => {
|
||||
const s = this.state();
|
||||
if (s.tag !== 'Invullen' || !hasProgress(s)) return null;
|
||||
const documentIds = deliveryRefs(s.upload).filter((r) => r.channel === 'digital' && r.documentId).map((r) => r.documentId!);
|
||||
const documentIds = deliveryRefs(s.upload)
|
||||
.filter((r) => r.channel === 'digital' && r.documentId)
|
||||
.map((r) => r.documentId!);
|
||||
return { draft: s, stepIndex: s.cursor, stepCount: STEPS.length, documentIds };
|
||||
},
|
||||
onResume: (draft) => this.dispatch({ tag: 'Seed', state: draft as RegistratieState }),
|
||||
enabled: () => this.seed() === initial,
|
||||
});
|
||||
protected step = computed<StepId>(() => STEPS[Math.min(this.cursor(), STEPS.length - 1)]);
|
||||
protected stepTitle = computed(() => this.stepTitles[Math.min(this.cursor(), this.stepTitles.length - 1)]);
|
||||
protected stepTitle = computed(
|
||||
() => this.stepTitles[Math.min(this.cursor(), this.stepTitles.length - 1)],
|
||||
);
|
||||
protected referentie = computed(() => whenTag(this.state(), 'Ingediend')?.referentie ?? '');
|
||||
protected failedError = computed(() => whenTag(this.state(), 'Mislukt')?.error ?? '');
|
||||
|
||||
@@ -251,13 +421,21 @@ export class RegistratieWizardComponent {
|
||||
const next = this.cursor() + 1;
|
||||
return naarStapLabel(next + 1, this.stepLabels[next]);
|
||||
});
|
||||
protected errorMessage = computed(() => $localize`:@@regWizard.indienenMislukt:Het indienen is niet gelukt:` + ` ${this.failedError()}`);
|
||||
protected errorMessage = computed(
|
||||
() =>
|
||||
$localize`:@@regWizard.indienenMislukt:Het indienen is niet gelukt:` +
|
||||
` ${this.failedError()}`,
|
||||
);
|
||||
protected shellStatus = computed<WizardStatus>(() => {
|
||||
switch (this.state().tag) {
|
||||
case 'Invullen': return 'editing';
|
||||
case 'Indienen': return 'submitting';
|
||||
case 'Ingediend': return 'submitted';
|
||||
case 'Mislukt': return 'failed';
|
||||
case 'Invullen':
|
||||
return 'editing';
|
||||
case 'Indienen':
|
||||
return 'submitting';
|
||||
case 'Ingediend':
|
||||
return 'submitted';
|
||||
case 'Mislukt':
|
||||
return 'failed';
|
||||
}
|
||||
});
|
||||
/** Current step's errors (incl. per-question), flattened for the error summary. */
|
||||
@@ -274,12 +452,32 @@ export class RegistratieWizardComponent {
|
||||
});
|
||||
protected adresSamenvatting = computed(() => {
|
||||
const d = this.draft();
|
||||
return [d.straat, [d.postcode, d.woonplaats].filter(Boolean).join(' ')].filter(Boolean).join(', ');
|
||||
return [d.straat, [d.postcode, d.woonplaats].filter(Boolean).join(' ')]
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
});
|
||||
// Readable labels for the controle summary (instead of raw enum values).
|
||||
protected adresHerkomstLabel = computed(() => ({ brp: $localize`:@@regWizard.herkomst.adresBrp:Automatisch uit de BRP`, handmatig: $localize`:@@regWizard.herkomst.adresHandmatig:Handmatig ingevoerd` }[this.draft().adresHerkomst ?? 'handmatig']));
|
||||
protected correspondentieLabel = computed(() => ({ email: $localize`:@@regWizard.corr.email:Per e-mail`, post: $localize`:@@regWizard.corr.post:Per post` }[this.draft().correspondentie ?? 'post']));
|
||||
protected diplomaHerkomstLabel = computed(() => ({ duo: $localize`:@@regWizard.herkomst.diplomaDuo:Geverifieerd via DUO`, handmatig: $localize`:@@regWizard.herkomst.diplomaHandmatig:Handmatig ingevoerd (wordt beoordeeld)` }[this.draft().diplomaHerkomst ?? 'handmatig']));
|
||||
protected adresHerkomstLabel = computed(
|
||||
() =>
|
||||
({
|
||||
brp: $localize`:@@regWizard.herkomst.adresBrp:Automatisch uit de BRP`,
|
||||
handmatig: $localize`:@@regWizard.herkomst.adresHandmatig:Handmatig ingevoerd`,
|
||||
})[this.draft().adresHerkomst ?? 'handmatig'],
|
||||
);
|
||||
protected correspondentieLabel = computed(
|
||||
() =>
|
||||
({
|
||||
email: $localize`:@@regWizard.corr.email:Per e-mail`,
|
||||
post: $localize`:@@regWizard.corr.post:Per post`,
|
||||
})[this.draft().correspondentie ?? 'post'],
|
||||
);
|
||||
protected diplomaHerkomstLabel = computed(
|
||||
() =>
|
||||
({
|
||||
duo: $localize`:@@regWizard.herkomst.diplomaDuo:Geverifieerd via DUO`,
|
||||
handmatig: $localize`:@@regWizard.herkomst.diplomaHandmatig:Handmatig ingevoerd (wordt beoordeeld)`,
|
||||
})[this.draft().diplomaHerkomst ?? 'handmatig'],
|
||||
);
|
||||
|
||||
/** BRP lookup outcome (laden/gevonden/geen/fout) and the parsed DUO lookup, both
|
||||
served by the application facade — the wizard renders, it does not fetch/parse. */
|
||||
@@ -295,23 +493,35 @@ export class RegistratieWizardComponent {
|
||||
|
||||
readonly jaNee = JA_NEE;
|
||||
|
||||
protected err = (k: DraftField | 'correspondentie' | 'diploma' | 'documenten') => this.invullen()?.errors[k] ?? '';
|
||||
protected err = (k: DraftField | 'correspondentie' | 'diploma' | 'documenten') =>
|
||||
this.invullen()?.errors[k] ?? '';
|
||||
protected vraagErr = (id: string) => this.invullen()?.errors.antwoorden?.[id] ?? '';
|
||||
protected antwoord = (id: string) => this.draft().antwoorden[id] ?? ''; // runtime guard: missing key → undefined
|
||||
protected set = (key: DraftField, value: string) => this.dispatch({ tag: 'SetField', key, value });
|
||||
protected setKanaal = (value: string) => this.dispatch({ tag: 'SetCorrespondentie', value: value as Correspondentie });
|
||||
protected set = (key: DraftField, value: string) =>
|
||||
this.dispatch({ tag: 'SetField', key, value });
|
||||
protected setKanaal = (value: string) =>
|
||||
this.dispatch({ tag: 'SetCorrespondentie', value: value as Correspondentie });
|
||||
|
||||
/** True while the user is entering a diploma manually (not in the DUO list). */
|
||||
protected handmatigActief = computed(() => this.draft().diplomaHerkomst === 'handmatig');
|
||||
/** The radio selection: a diploma id, or the"not listed" sentinel in manual mode. */
|
||||
protected diplomaKeuze = computed(() => (this.handmatigActief() ? HANDMATIG : this.draft().diplomaId ?? ''));
|
||||
protected diplomaKeuze = computed(() =>
|
||||
this.handmatigActief() ? HANDMATIG : (this.draft().diplomaId ?? ''),
|
||||
);
|
||||
|
||||
protected diplomaOptions = (data: DuoLookupDto) => [
|
||||
...data.diplomas.map((d) => ({ value: d.id, label: `${d.naam} — ${d.instelling} (${d.jaar})` })),
|
||||
{ value: HANDMATIG, label: $localize`:@@regWizard.diplomaNietBij:Mijn diploma staat er niet bij` },
|
||||
...data.diplomas.map((d) => ({
|
||||
value: d.id,
|
||||
label: `${d.naam} — ${d.instelling} (${d.jaar})`,
|
||||
})),
|
||||
{
|
||||
value: HANDMATIG,
|
||||
label: $localize`:@@regWizard.diplomaNietBij:Mijn diploma staat er niet bij`,
|
||||
},
|
||||
];
|
||||
|
||||
protected beroepOptions = (data: DuoLookupDto) => data.handmatig.beroepen.map((b) => ({ value: b, label: b }));
|
||||
protected beroepOptions = (data: DuoLookupDto) =>
|
||||
data.handmatig.beroepen.map((b) => ({ value: b, label: b }));
|
||||
|
||||
/** The policy questions that apply to the current choice (server-decided). */
|
||||
protected actieveVragen = (data: DuoLookupDto): PolicyQuestionDto[] => {
|
||||
@@ -324,24 +534,41 @@ export class RegistratieWizardComponent {
|
||||
const data = this.duoData();
|
||||
const d = this.draft();
|
||||
if (!data) return [] as { vraag: string; antwoord: string }[];
|
||||
const alle = [...data.diplomas.flatMap((x) => x.policyQuestions), ...data.handmatig.policyQuestions];
|
||||
return (d.vraagIds ?? []).map((id) => ({ vraag: alle.find((q) => q.id === id)?.vraag ?? id, antwoord: d.antwoorden[id] ?? '' }));
|
||||
const alle = [
|
||||
...data.diplomas.flatMap((x) => x.policyQuestions),
|
||||
...data.handmatig.policyQuestions,
|
||||
];
|
||||
return (d.vraagIds ?? []).map((id) => ({
|
||||
vraag: alle.find((q) => q.id === id)?.vraag ?? id,
|
||||
antwoord: d.antwoorden[id] ?? '',
|
||||
}));
|
||||
});
|
||||
|
||||
protected onDiplomaKeuze(data: DuoLookupDto, id: string) {
|
||||
if (id === HANDMATIG) {
|
||||
this.dispatch({ tag: 'KiesHandmatig', vraagIds: data.handmatig.policyQuestions.map((q) => q.id) });
|
||||
this.dispatch({
|
||||
tag: 'KiesHandmatig',
|
||||
vraagIds: data.handmatig.policyQuestions.map((q) => q.id),
|
||||
});
|
||||
return;
|
||||
}
|
||||
const d = data.diplomas.find((x) => x.id === id);
|
||||
if (d) this.dispatch({ tag: 'KiesDiploma', diplomaId: d.id, beroep: d.beroep, vraagIds: d.policyQuestions.map((q) => q.id) });
|
||||
if (d)
|
||||
this.dispatch({
|
||||
tag: 'KiesDiploma',
|
||||
diplomaId: d.id,
|
||||
beroep: d.beroep,
|
||||
vraagIds: d.policyQuestions.map((q) => q.id),
|
||||
});
|
||||
}
|
||||
|
||||
constructor() {
|
||||
// An explicit seed (stories/tests) wins; otherwise resume from the backend draft
|
||||
// (`?aanvraag=<id>`), or start fresh. Persistence is the draftSync controller's job.
|
||||
const seeded = this.seed();
|
||||
queueMicrotask(() => (seeded !== initial ? this.dispatch({ tag: 'Seed', state: seeded }) : this.draftSync.resume()));
|
||||
queueMicrotask(() =>
|
||||
seeded !== initial ? this.dispatch({ tag: 'Seed', state: seeded }) : this.draftSync.resume(),
|
||||
);
|
||||
// Prefill the address from the BRP lookup as it arrives. Track only the facade's
|
||||
// parsed prefill signal; untrack the dispatch (it reads the state signal, which
|
||||
// would otherwise make this effect loop on its own write). Don't clobber
|
||||
@@ -352,7 +579,12 @@ export class RegistratieWizardComponent {
|
||||
untracked(() => {
|
||||
const s = this.state();
|
||||
if (s.tag !== 'Invullen' || s.draft.straat) return;
|
||||
this.dispatch({ tag: 'PrefillAdres', straat: a.straat, postcode: a.postcode, woonplaats: a.woonplaats });
|
||||
this.dispatch({
|
||||
tag: 'PrefillAdres',
|
||||
straat: a.straat,
|
||||
postcode: a.postcode,
|
||||
woonplaats: a.woonplaats,
|
||||
});
|
||||
});
|
||||
});
|
||||
// A11y: focus management (step heading on step change, error summary on a
|
||||
@@ -384,7 +616,10 @@ export class RegistratieWizardComponent {
|
||||
private async runIfIndienen() {
|
||||
const s = this.state();
|
||||
if (s.tag !== 'Indienen') return;
|
||||
const r = await this.draftSync.submit({ diplomaHerkomst: s.data.diplomaHerkomst, documents: s.data.documents });
|
||||
const r = await this.draftSync.submit({
|
||||
diplomaHerkomst: s.data.diplomaHerkomst,
|
||||
documents: s.data.documents,
|
||||
});
|
||||
if (r.ok) this.dispatch({ tag: 'SubmitConfirmed', referentie: r.value.referentie ?? '' });
|
||||
else this.dispatch({ tag: 'SubmitFailed', error: r.error });
|
||||
}
|
||||
|
||||
@@ -3,14 +3,36 @@ import { applicationConfig } from '@storybook/angular';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import { provideApiClient } from '@shared/infrastructure/api-client.provider';
|
||||
import { RegistratieWizardComponent } from './registratie-wizard.component';
|
||||
import { Draft, RegistratieState, ValidRegistratie } from '@registratie/domain/registratie-wizard.machine';
|
||||
import {
|
||||
Draft,
|
||||
RegistratieState,
|
||||
ValidRegistratie,
|
||||
} from '@registratie/domain/registratie-wizard.machine';
|
||||
import { initialUpload } from '@shared/upload/upload.machine';
|
||||
import { Postcode } from '@registratie/domain/value-objects/postcode';
|
||||
|
||||
const adres: Partial<Draft> = { straat: 'Lange Voorhout 9', postcode: '2514 EA', woonplaats: 'Den Haag', adresHerkomst: 'brp', correspondentie: 'post' };
|
||||
const filled: Partial<Draft> = { ...adres, diplomaId: 'd1', beroep: 'Arts', diplomaHerkomst: 'duo', vraagIds: [] };
|
||||
const adres: Partial<Draft> = {
|
||||
straat: 'Lange Voorhout 9',
|
||||
postcode: '2514 EA',
|
||||
woonplaats: 'Den Haag',
|
||||
adresHerkomst: 'brp',
|
||||
correspondentie: 'post',
|
||||
};
|
||||
const filled: Partial<Draft> = {
|
||||
...adres,
|
||||
diplomaId: 'd1',
|
||||
beroep: 'Arts',
|
||||
diplomaHerkomst: 'duo',
|
||||
vraagIds: [],
|
||||
};
|
||||
|
||||
const invullen = (draft: Partial<Draft>, cursor = 0): RegistratieState => ({ tag: 'Invullen', draft: { antwoorden: {}, ...draft }, cursor, errors: {}, upload: initialUpload });
|
||||
const invullen = (draft: Partial<Draft>, cursor = 0): RegistratieState => ({
|
||||
tag: 'Invullen',
|
||||
draft: { antwoorden: {}, ...draft },
|
||||
cursor,
|
||||
errors: {},
|
||||
upload: initialUpload,
|
||||
});
|
||||
|
||||
const validData: ValidRegistratie = {
|
||||
adres: { straat: 'Lange Voorhout 9', postcode: '2514 EA' as Postcode, woonplaats: 'Den Haag' },
|
||||
@@ -34,10 +56,39 @@ type Story = StoryObj<RegistratieWizardComponent>;
|
||||
export const Adres: Story = { args: { seed: invullen(adres, 0) } };
|
||||
export const Beroep: Story = { args: { seed: invullen(filled, 1) } };
|
||||
/** English-language diploma → the Dutch-proficiency policy question appears. */
|
||||
export const BeroepEngelstalig: Story = { args: { seed: invullen({ ...adres, diplomaId: 'd2', beroep: 'Arts', diplomaHerkomst: 'duo', vraagIds: ['nl-taalvaardigheid'] }, 1) } };
|
||||
export const BeroepEngelstalig: Story = {
|
||||
args: {
|
||||
seed: invullen(
|
||||
{
|
||||
...adres,
|
||||
diplomaId: 'd2',
|
||||
beroep: 'Arts',
|
||||
diplomaHerkomst: 'duo',
|
||||
vraagIds: ['nl-taalvaardigheid'],
|
||||
},
|
||||
1,
|
||||
),
|
||||
},
|
||||
};
|
||||
/** Diploma not in DUO → declare beroep + the maximal policy-question set. */
|
||||
export const BeroepHandmatig: Story = { args: { seed: invullen({ ...adres, diplomaId: 'handmatig', diplomaHerkomst: 'handmatig', vraagIds: ['nl-taalvaardigheid', 'diploma-erkend', 'toelichting'] }, 1) } };
|
||||
export const BeroepHandmatig: Story = {
|
||||
args: {
|
||||
seed: invullen(
|
||||
{
|
||||
...adres,
|
||||
diplomaId: 'handmatig',
|
||||
diplomaHerkomst: 'handmatig',
|
||||
vraagIds: ['nl-taalvaardigheid', 'diploma-erkend', 'toelichting'],
|
||||
},
|
||||
1,
|
||||
),
|
||||
},
|
||||
};
|
||||
export const Controle: Story = { args: { seed: invullen(filled, 2) } };
|
||||
export const Indienen: Story = { args: { seed: { tag: 'Indienen', data: validData } } };
|
||||
export const Ingediend: Story = { args: { seed: { tag: 'Ingediend', data: validData, referentie: 'BIG-2026-123456' } } };
|
||||
export const Mislukt: Story = { args: { seed: { tag: 'Mislukt', data: validData, error: 'Netwerkfout' } } };
|
||||
export const Ingediend: Story = {
|
||||
args: { seed: { tag: 'Ingediend', data: validData, referentie: 'BIG-2026-123456' } },
|
||||
};
|
||||
export const Mislukt: Story = {
|
||||
args: { seed: { tag: 'Mislukt', data: validData, error: 'Netwerkfout' } },
|
||||
};
|
||||
|
||||
@@ -12,11 +12,11 @@ import { RegistratieWizardComponent } from '@registratie/ui/registratie-wizard/r
|
||||
<app-page-shell
|
||||
i18n-heading="@@registratie.heading"
|
||||
heading="Inschrijven in het BIG-register"
|
||||
backLink="/dashboard">
|
||||
backLink="/dashboard"
|
||||
>
|
||||
<app-alert type="info" i18n="@@registratie.intro">
|
||||
In drie stappen schrijft u zich in: uw adres en correspondentievoorkeur, het
|
||||
diploma waarmee u zich registreert, en een controle. Uw gegevens blijven bewaard
|
||||
als u de pagina herlaadt.
|
||||
In drie stappen schrijft u zich in: uw adres en correspondentievoorkeur, het diploma waarmee
|
||||
u zich registreert, en een controle. Uw gegevens blijven bewaard als u de pagina herlaadt.
|
||||
</app-alert>
|
||||
<div class="app-section">
|
||||
<app-registratie-wizard />
|
||||
|
||||
@@ -9,11 +9,18 @@ import { BigProfileStore } from '@registratie/application/big-profile.store';
|
||||
@Component({
|
||||
selector: 'app-registration-detail-page',
|
||||
imports: [
|
||||
PageShellComponent, SkeletonComponent, ...ASYNC,
|
||||
RegistrationSummaryComponent, ChangeRequestFormComponent,
|
||||
PageShellComponent,
|
||||
SkeletonComponent,
|
||||
...ASYNC,
|
||||
RegistrationSummaryComponent,
|
||||
ChangeRequestFormComponent,
|
||||
],
|
||||
template: `
|
||||
<app-page-shell i18n-heading="@@registratieDetail.heading" heading="Mijn gegevens" backLink="/dashboard">
|
||||
<app-page-shell
|
||||
i18n-heading="@@registratieDetail.heading"
|
||||
heading="Mijn gegevens"
|
||||
backLink="/dashboard"
|
||||
>
|
||||
<app-async [data]="store.profile()">
|
||||
<ng-template appAsyncLoaded let-p>
|
||||
<app-registration-summary [reg]="$any(p).registration" />
|
||||
|
||||
@@ -13,25 +13,60 @@ import { DataBlockComponent } from '@shared/ui/data-block/data-block.component';
|
||||
imports: [DatePipe, DataRowComponent, StatusBadgeComponent, DataBlockComponent],
|
||||
template: `
|
||||
<app-data-block i18n-ariaLabel="@@summary.ariaLabel" ariaLabel="Registratiegegevens">
|
||||
<div app-data-row i18n-key="@@summary.bigNummer" key="BIG-nummer" [value]="reg().bigNummer"></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@summary.bigNummer"
|
||||
key="BIG-nummer"
|
||||
[value]="reg().bigNummer"
|
||||
></div>
|
||||
<div app-data-row i18n-key="@@summary.naam" key="Naam" [value]="reg().naam"></div>
|
||||
<div app-data-row i18n-key="@@summary.beroep" key="Beroep" [value]="reg().beroep"></div>
|
||||
<div app-data-row i18n-key="@@summary.status" key="Status">
|
||||
<app-status-badge [label]="label()" [color]="color()" />
|
||||
</div>
|
||||
<div app-data-row i18n-key="@@summary.registratiedatum" key="Registratiedatum" [value]="reg().registratiedatum | date:'longDate'"></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@summary.registratiedatum"
|
||||
key="Registratiedatum"
|
||||
[value]="reg().registratiedatum | date: 'longDate'"
|
||||
></div>
|
||||
<!-- Each status variant renders only the row its own data supports. -->
|
||||
@switch (reg().status.tag) {
|
||||
@case ('Geregistreerd') {
|
||||
<div app-data-row i18n-key="@@summary.uiterste" key="Uiterste herregistratie" [value]="$any(reg().status).herregistratieDatum | date:'longDate'"></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@summary.uiterste"
|
||||
key="Uiterste herregistratie"
|
||||
[value]="$any(reg().status).herregistratieDatum | date: 'longDate'"
|
||||
></div>
|
||||
}
|
||||
@case ('Geschorst') {
|
||||
<div app-data-row i18n-key="@@summary.geschorstTot" key="Geschorst tot" [value]="$any(reg().status).geschorstTot | date:'longDate'"></div>
|
||||
<div app-data-row i18n-key="@@summary.reden" key="Reden" [value]="$any(reg().status).reden"></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@summary.geschorstTot"
|
||||
key="Geschorst tot"
|
||||
[value]="$any(reg().status).geschorstTot | date: 'longDate'"
|
||||
></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@summary.reden"
|
||||
key="Reden"
|
||||
[value]="$any(reg().status).reden"
|
||||
></div>
|
||||
}
|
||||
@case ('Doorgehaald') {
|
||||
<div app-data-row i18n-key="@@summary.doorgehaaldOp" key="Doorgehaald op" [value]="$any(reg().status).doorgehaaldOp | date:'longDate'"></div>
|
||||
<div app-data-row i18n-key="@@summary.reden" key="Reden" [value]="$any(reg().status).reden"></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@summary.doorgehaaldOp"
|
||||
key="Doorgehaald op"
|
||||
[value]="$any(reg().status).doorgehaaldOp | date: 'longDate'"
|
||||
></div>
|
||||
<div
|
||||
app-data-row
|
||||
i18n-key="@@summary.reden"
|
||||
key="Reden"
|
||||
[value]="$any(reg().status).reden"
|
||||
></div>
|
||||
}
|
||||
}
|
||||
</app-data-block>
|
||||
|
||||
@@ -23,8 +23,18 @@ export const Geregistreerd: Story = {
|
||||
args: { reg: { ...base, status: { tag: 'Geregistreerd', herregistratieDatum: '2027-09-01' } } },
|
||||
};
|
||||
export const Geschorst: Story = {
|
||||
args: { reg: { ...base, status: { tag: 'Geschorst', geschorstTot: '2026-12-31', reden: 'Lopend tuchtonderzoek' } } },
|
||||
args: {
|
||||
reg: {
|
||||
...base,
|
||||
status: { tag: 'Geschorst', geschorstTot: '2026-12-31', reden: 'Lopend tuchtonderzoek' },
|
||||
},
|
||||
},
|
||||
};
|
||||
export const Doorgehaald: Story = {
|
||||
args: { reg: { ...base, status: { tag: 'Doorgehaald', doorgehaaldOp: '2024-05-01', reden: 'Op eigen verzoek' } } },
|
||||
args: {
|
||||
reg: {
|
||||
...base,
|
||||
status: { tag: 'Doorgehaald', doorgehaaldOp: '2024-05-01', reden: 'Op eigen verzoek' },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Aantekening } from '@registratie/domain/registration';
|
||||
<tr>
|
||||
<td>{{ row.type }}</td>
|
||||
<td>{{ row.omschrijving }}</td>
|
||||
<td>{{ row.datum | date:'mediumDate' }}</td>
|
||||
<td>{{ row.datum | date: 'mediumDate' }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
|
||||
@@ -12,7 +12,11 @@ export const Default: Story = {
|
||||
args: {
|
||||
rows: [
|
||||
{ type: 'Specialisme', omschrijving: 'Huisartsgeneeskunde', datum: '2016-04-12' },
|
||||
{ type: 'Aantekening', omschrijving: 'Erkend opleider huisartsgeneeskunde', datum: '2019-01-08' },
|
||||
{
|
||||
type: 'Aantekening',
|
||||
omschrijving: 'Erkend opleider huisartsgeneeskunde',
|
||||
datum: '2019-01-08',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user