diff --git a/documentation.json b/documentation.json index 8911cd5..d49850e 100644 --- a/documentation.json +++ b/documentation.json @@ -207,12 +207,12 @@ }, { "name": "AanvraagRow", - "id": "interface-AanvraagRow-709f25c5f5290c2ead0c51d4c8fcc6607c66946560c07a1d3ea16be67c7442feaeefd021ced4f77b685484dec39e1ff5e7b7122472530b51887f573a69576956", + "id": "interface-AanvraagRow-6793264f2cc6a82fd203220ab82e1fe318943002bfdd08de089d20fb9bba17edd4775e5a8a36d3c69125a491442595c79a4e64a3115a37a4f27b698eab9113c8", "file": "src/app/registratie/domain/aanvraag-view.ts", "deprecated": false, "deprecationMessage": "", "type": "interface", - "sourceCode": "import { Aanvraag, AanvraagType } from './aanvraag';\n\n/** View-model mapping for an aanvraag: type → label, and a submitted aanvraag →\n the CIBG \"aanvragen\" row fields (heading/status/subtitle). Pure, no Angular —\n the UI renders these, it does not derive them. */\n\nexport const TYPE_LABELS: Record = {\n registratie: $localize`:@@aanvraagBlock.type.registratie:Inschrijving`,\n herregistratie: $localize`:@@aanvraagBlock.type.herregistratie:Herregistratie`,\n intake: $localize`:@@aanvraagBlock.type.intake:Herregistratie-intake`,\n};\n\nexport interface AanvraagRow {\n heading: string;\n /** Reference + submit-date line (the `.status` line of an aanvragen row). */\n status: string;\n /** Secondary note: manual-review notice or rejection reason. */\n subtitle: string;\n}\n\nfunction formatNL(iso?: string): string {\n return iso ? new Date(iso).toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' }) : '';\n}\n\n/** Fields for a submitted aanvraag's row (Concept has no row — it renders as a\n resumable melding, see aanvraag-block). */\nexport function submittedRow(a: Aanvraag): AanvraagRow {\n const s = a.status;\n const heading = TYPE_LABELS[a.type];\n switch (s.tag) {\n case 'Concept':\n return { heading, status: '', subtitle: '' };\n case 'InBehandeling':\n return {\n heading,\n status: $localize`:@@aanvraagBlock.inBehandeling:Referentie ${s.referentie}:ref: · ingediend op ${formatNL(a.submittedAt)}:datum:`,\n subtitle: s.manual ? $localize`:@@aanvraagBlock.manual:Uw aanvraag wordt handmatig beoordeeld in de backoffice.` : '',\n };\n case 'Goedgekeurd':\n return { heading, status: $localize`:@@aanvraagBlock.goedgekeurd:Referentie ${s.referentie}:ref:`, subtitle: '' };\n case 'Afgewezen':\n return { heading, status: $localize`:@@aanvraagBlock.afgewezen:Referentie ${s.referentie}:ref:`, subtitle: s.reden };\n }\n}\n", + "sourceCode": "import { Aanvraag, AanvraagStatus, AanvraagType } from './aanvraag';\n\n/** View-model mapping for an aanvraag: type → labels, status → label, and the fields\n for a CIBG \"aanvragen\" row / the case-detail page. Pure, no Angular — the UI\n renders these, it does not derive them. */\n\nexport const TYPE_LABELS: Record = {\n registratie: $localize`:@@aanvraagBlock.type.registratie:Inschrijving`,\n herregistratie: $localize`:@@aanvraagBlock.type.herregistratie:Herregistratie`,\n intake: $localize`:@@aanvraagBlock.type.intake:Herregistratie-intake`,\n};\n\n/** What the aanvraag is for (shown under the title). */\nexport function purposeLabel(type: AanvraagType): string {\n switch (type) {\n case 'registratie': return $localize`:@@aanvraag.purpose.registratie:Inschrijving in het BIG-register`;\n case 'herregistratie': return $localize`:@@aanvraag.purpose.herregistratie:Verlenging van uw BIG-registratie`;\n case 'intake': return $localize`:@@aanvraag.purpose.intake:Intake-vragenlijst voor uw herregistratie`;\n }\n}\n\n/** The status as a plain label (what state the aanvraag is in). */\nexport function statusLabel(status: AanvraagStatus): string {\n switch (status.tag) {\n case 'Concept': return $localize`:@@aanvraag.status.concept:Concept (nog niet ingediend)`;\n case 'InBehandeling': return $localize`:@@aanvraag.status.inBehandeling:In behandeling`;\n case 'Goedgekeurd': return $localize`:@@aanvraag.status.goedgekeurd:Goedgekeurd`;\n case 'Afgewezen': return $localize`:@@aanvraag.status.afgewezen:Afgewezen`;\n }\n}\n\n/** The reference number, or '' for a Concept (which has none yet). */\nexport function referentie(status: AanvraagStatus): string {\n return status.tag === 'Concept' ? '' : status.referentie;\n}\n\nexport interface AanvraagRow {\n heading: string;\n /** What the aanvraag is for (the `.subtitle` line). */\n subtitle: string;\n /** The status: label + reference + submit date (+ any note) — the `.status` line. */\n status: string;\n}\n\nfunction formatNL(iso?: string): string {\n return iso ? new Date(iso).toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' }) : '';\n}\n\n/** Fields for a submitted aanvraag's row in the dashboard \"aanvragen\" list (Concept\n has no row — it renders as a resumable melding, see aanvraag-block). */\nexport function submittedRow(a: Aanvraag): AanvraagRow {\n const s = a.status;\n const parts = [statusLabel(s)];\n const ref = referentie(s);\n if (ref) parts.push($localize`:@@aanvraag.row.ref:Referentie ${ref}:ref:`);\n if (a.submittedAt) parts.push($localize`:@@aanvraag.row.ingediend:ingediend op ${formatNL(a.submittedAt)}:datum:`);\n if (s.tag === 'InBehandeling' && s.manual) parts.push($localize`:@@aanvraagBlock.manual:Uw aanvraag wordt handmatig beoordeeld in de backoffice.`);\n if (s.tag === 'Afgewezen') parts.push(s.reden);\n return { heading: TYPE_LABELS[a.type], subtitle: purposeLabel(a.type), status: parts.join(' · ') };\n}\n\n/** Key/value rows for the case-detail page (CIBG Datablock). */\nexport function detailRows(a: Aanvraag): { key: string; value: string }[] {\n const rows = [\n { key: $localize`:@@aanvraag.detail.soort:Soort aanvraag`, value: TYPE_LABELS[a.type] },\n { key: $localize`:@@aanvraag.detail.waarvoor:Waarvoor`, value: purposeLabel(a.type) },\n { key: $localize`:@@aanvraag.detail.status:Status`, value: statusLabel(a.status) },\n { key: $localize`:@@aanvraag.detail.referentie:Referentie`, value: referentie(a.status) || '—' },\n { key: $localize`:@@aanvraag.detail.ingediend:Ingediend op`, value: a.submittedAt ? formatNL(a.submittedAt) : '—' },\n ];\n if (a.status.tag === 'Afgewezen') {\n rows.push({ key: $localize`:@@aanvraag.detail.reden:Reden van afwijzing`, value: a.status.reden });\n }\n return rows;\n}\n", "properties": [ { "name": "heading", @@ -222,7 +222,7 @@ "indexKey": "", "optional": false, "description": "", - "line": 14 + "line": 38 }, { "name": "status", @@ -231,9 +231,9 @@ "type": "string", "indexKey": "", "optional": false, - "description": "

Reference + submit-date line (the .status line of an aanvragen row).

\n", - "line": 16, - "rawdescription": "\nReference + submit-date line (the `.status` line of an aanvragen row)." + "description": "

The status: label + reference + submit date (+ any note) — the .status line.

\n", + "line": 42, + "rawdescription": "\nThe status: label + reference + submit date (+ any note) — the `.status` line." }, { "name": "subtitle", @@ -242,9 +242,9 @@ "type": "string", "indexKey": "", "optional": false, - "description": "

Secondary note: manual-review notice or rejection reason.

\n", - "line": 18, - "rawdescription": "\nSecondary note: manual-review notice or rejection reason." + "description": "

What the aanvraag is for (the .subtitle line).

\n", + "line": 40, + "rawdescription": "\nWhat the aanvraag is for (the `.subtitle` line)." } ], "indexSignatures": [], @@ -11142,6 +11142,122 @@ "stylesData": "\n .actions{display:flex;align-items:center;gap:var(--rhc-space-max-md);margin-block-start:var(--rhc-space-max-sm)}\n \n", "extends": [] }, + { + "name": "AanvraagDetailPage", + "id": "component-AanvraagDetailPage-7910a51693ea402450d839b06070ad8b57bbfc55f19837f5b687120c25d56df074eb44c9b42f7354019199466d671efa28677c8580d8fef423690fa95f179ead", + "file": "src/app/registratie/ui/aanvraag-detail.page.ts", + "encapsulation": [], + "entryComponents": [], + "inputs": [], + "outputs": [], + "providers": [], + "selector": "app-aanvraag-detail-page", + "styleUrls": [], + "styles": [], + "template": "\n \n \n @let a = find($any(list));\n @if (a) {\n \n @for (row of rows(a); track row.key) {\n
\n }\n
\n \n De volledige afhandeling van deze aanvraag is nog niet beschikbaar in deze POC.\n \n } @else {\n Deze aanvraag is niet gevonden.\n }\n
\n \n \n \n
\n
\n", + "templateUrl": [], + "viewProviders": [], + "hostDirectives": [], + "inputsClass": [], + "outputsClass": [], + "propertiesClass": [ + { + "name": "find", + "defaultValue": "() => {...}", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "indexKey": "", + "optional": false, + "description": "", + "line": 48, + "modifierKind": [ + 124 + ] + }, + { + "name": "id", + "defaultValue": "inject(ActivatedRoute).snapshot.paramMap.get('id') ?? ''", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "indexKey": "", + "optional": false, + "description": "", + "line": 46, + "modifierKind": [ + 123 + ] + }, + { + "name": "rows", + "defaultValue": "detailRows", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "indexKey": "", + "optional": false, + "description": "", + "line": 49, + "modifierKind": [ + 124 + ] + }, + { + "name": "store", + "defaultValue": "inject(ApplicationsStore)", + "deprecated": false, + "deprecationMessage": "", + "type": "unknown", + "indexKey": "", + "optional": false, + "description": "", + "line": 45, + "modifierKind": [ + 124 + ] + } + ], + "methodsClass": [], + "deprecated": false, + "deprecationMessage": "", + "hostBindings": [], + "hostListeners": [], + "standalone": false, + "imports": [ + { + "name": "PageShellComponent", + "type": "component" + }, + { + "name": "SkeletonComponent", + "type": "component" + }, + { + "name": "AlertComponent", + "type": "component" + }, + { + "name": "DataBlockComponent", + "type": "component" + }, + { + "name": "DataRowComponent", + "type": "component" + }, + { + "name": "ASYNC" + } + ], + "description": "

Page: a single aanvraag ("case"). Stub — it renders the aanvraag's known fields\n(soort, waarvoor, status, referentie, ingediend) in a CIBG Datablock; full case\nhandling is future work. The dashboard "Mijn aanvragen" rows link here.

\n", + "rawdescription": "\nPage: a single aanvraag (\"case\"). Stub — it renders the aanvraag's known fields\n(soort, waarvoor, status, referentie, ingediend) in a CIBG Datablock; full case\nhandling is future work. The dashboard \"Mijn aanvragen\" rows link here.", + "type": "component", + "sourceCode": "import { Component, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { PageShellComponent } from '@shared/layout/page-shell/page-shell.component';\nimport { SkeletonComponent } from '@shared/ui/skeleton/skeleton.component';\nimport { AlertComponent } from '@shared/ui/alert/alert.component';\nimport { DataBlockComponent } from '@shared/ui/data-block/data-block.component';\nimport { DataRowComponent } from '@shared/ui/data-row/data-row.component';\nimport { ASYNC } from '@shared/ui/async/async.component';\nimport { ApplicationsStore } from '@registratie/application/applications.store';\nimport { Aanvraag } from '@registratie/domain/aanvraag';\nimport { detailRows } from '@registratie/domain/aanvraag-view';\n\n/** Page: a single aanvraag (\"case\"). Stub — it renders the aanvraag's known fields\n (soort, waarvoor, status, referentie, ingediend) in a CIBG Datablock; full case\n handling is future work. The dashboard \"Mijn aanvragen\" rows link here. */\n@Component({\n selector: 'app-aanvraag-detail-page',\n imports: [PageShellComponent, SkeletonComponent, AlertComponent, DataBlockComponent, DataRowComponent, ...ASYNC],\n template: `\n \n \n \n @let a = find($any(list));\n @if (a) {\n \n @for (row of rows(a); track row.key) {\n
\n }\n
\n \n De volledige afhandeling van deze aanvraag is nog niet beschikbaar in deze POC.\n \n } @else {\n Deze aanvraag is niet gevonden.\n }\n
\n \n \n \n
\n
\n `,\n})\nexport class AanvraagDetailPage {\n protected store = inject(ApplicationsStore);\n private id = inject(ActivatedRoute).snapshot.paramMap.get('id') ?? '';\n\n protected find = (list: Aanvraag[]): Aanvraag | undefined => list.find((a) => a.id === this.id);\n protected rows = detailRows;\n}\n", + "assetsDirs": [], + "styleUrlsData": "", + "stylesData": "", + "extends": [] + }, { "name": "AddressFieldsComponent", "id": "component-AddressFieldsComponent-486bc51fe6e0580e73e1eaff7fadd0391ce7111e5b66294eff93f0f0dc84f19a80abb6dd269909450a94d13a2d7d24aa3b167dbe8472717ecd4208f00c5ae6bc", @@ -13258,7 +13374,7 @@ }, { "name": "DashboardPage", - "id": "component-DashboardPage-9c0ed7dc5db9c7e1224bc86145c299e016a08204e46b6c7ccb393320f3c0fde4d84ed075b3bff5b7a365cf3713c0d5545e4f91fa8ec119094ff53259216e71de", + "id": "component-DashboardPage-5b2a482fefb71e130ec9fe9ccc41b8ba0bc73cfea45e004342df4063a60d206f7bb85ba8fa506b497b10dc92de97e92ab7aaeb0a9c9ee20c5cc4d0c07258bdb5", "file": "src/app/registratie/ui/dashboard.page.ts", "encapsulation": [], "entryComponents": [], @@ -13268,7 +13384,7 @@ "selector": "app-dashboard-page", "styleUrls": [], "styles": [], - "template": "\n
\n @if (aanvragen().length) {\n
\n @for (a of concepten(); track a.id) {\n \n }\n @if (ingediend().length) {\n Mijn aanvragen\n \n @for (a of ingediend(); track a.id) {\n @let row = submittedRow(a);\n
  • \n }\n
    \n }\n
    \n }\n\n @if (store.pendingHerregistratie()) {\n Uw herregistratie-aanvraag is in behandeling.\n }\n\n \n \n @let tasks = tasksFor($any(p).registration);\n\n
    \n @if (tasks.length) {\n \n } @else {\n Wat moet ik regelen\n

    U heeft op dit moment niets openstaan.

    \n }\n
    \n\n
    \n Mijn registratie\n
    \n \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n \n \n \n
    \n\n
    \n Specialismen en aantekeningen\n
    \n \n \n \n \n \n \n \n \n

    U heeft nog geen specialismen of aantekeningen.

    \n
    \n
    \n
    \n
    \n\n
    \n Wat wilt u doen?\n \n @for (a of acties; track a.to) {\n
  • \n }\n
    \n
    \n
    \n
    \n", + "template": "\n
    \n @if (aanvragen().length) {\n
    \n @for (a of concepten(); track a.id) {\n \n }\n @if (ingediend().length) {\n Mijn aanvragen\n \n @for (a of ingediend(); track a.id) {\n @let row = submittedRow(a);\n
  • \n }\n
    \n }\n
    \n }\n\n @if (store.pendingHerregistratie()) {\n Uw herregistratie-aanvraag is in behandeling.\n }\n\n \n \n @let tasks = tasksFor($any(p).registration);\n\n
    \n @if (tasks.length) {\n \n } @else {\n Wat moet ik regelen\n

    U heeft op dit moment niets openstaan.

    \n }\n
    \n\n
    \n Mijn registratie\n
    \n \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n \n \n \n
    \n\n
    \n Specialismen en aantekeningen\n
    \n \n \n \n \n \n \n \n \n

    U heeft nog geen specialismen of aantekeningen.

    \n
    \n
    \n
    \n
    \n\n
    \n Wat wilt u doen?\n \n @for (a of acties; track a.to) {\n
  • \n }\n
    \n
    \n
    \n
    \n", "templateUrl": [], "viewProviders": [], "hostDirectives": [], @@ -13592,7 +13708,7 @@ "description": "

    Page:"Mijn overzicht" — the portal home, following the NL Design System\n"Mijn omgeving" pattern (side nav +"Wat moet ik regelen" +"Mijn zaken").

    \n", "rawdescription": "\nPage:\"Mijn overzicht\" — the portal home, following the NL Design System\n\"Mijn omgeving\" pattern (side nav +\"Wat moet ik regelen\" +\"Mijn zaken\").", "type": "component", - "sourceCode": "import { Component, computed, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { PageShellComponent } from '@shared/layout/page-shell/page-shell.component';\nimport { HeadingComponent } from '@shared/ui/heading/heading.component';\nimport { AlertComponent } from '@shared/ui/alert/alert.component';\nimport { SkeletonComponent } from '@shared/ui/skeleton/skeleton.component';\nimport { DataRowComponent } from '@shared/ui/data-row/data-row.component';\nimport { DataBlockComponent } from '@shared/ui/data-block/data-block.component';\nimport { TaskListComponent } from '@shared/ui/task-list/task-list.component';\nimport { ApplicationListComponent } from '@shared/ui/application-list/application-list.component';\nimport { ApplicationLinkComponent } from '@shared/ui/application-link/application-link.component';\nimport { ASYNC } from '@shared/ui/async/async.component';\nimport { RegistrationSummaryComponent } from '@registratie/ui/registration-summary/registration-summary.component';\nimport { RegistrationTableComponent } from '@registratie/ui/registration-table/registration-table.component';\nimport { AanvraagBlockComponent } from '@registratie/ui/aanvraag-block/aanvraag-block.component';\nimport { BigProfileStore } from '@registratie/application/big-profile.store';\nimport { ApplicationsStore } from '@registratie/application/applications.store';\nimport { Registration } from '@registratie/domain/registration';\nimport { Aanvraag, AanvraagType } from '@registratie/domain/aanvraag';\nimport { submittedRow } from '@registratie/domain/aanvraag-view';\nimport { tasksFromProfile } from '@registratie/domain/tasks';\n\n/** Page:\"Mijn overzicht\" — the portal home, following the NL Design System\n\"Mijn omgeving\" pattern (side nav +\"Wat moet ik regelen\" +\"Mijn zaken\"). */\n@Component({\n selector: 'app-dashboard-page',\n imports: [\n PageShellComponent, HeadingComponent, AlertComponent, SkeletonComponent,\n DataRowComponent, DataBlockComponent, TaskListComponent, ApplicationListComponent, ApplicationLinkComponent,\n ...ASYNC,\n RegistrationSummaryComponent, RegistrationTableComponent, AanvraagBlockComponent,\n ],\n template: `\n \n
    \n @if (aanvragen().length) {\n
    \n @for (a of concepten(); track a.id) {\n \n }\n @if (ingediend().length) {\n Mijn aanvragen\n \n @for (a of ingediend(); track a.id) {\n @let row = submittedRow(a);\n
  • \n }\n
    \n }\n
    \n }\n\n @if (store.pendingHerregistratie()) {\n Uw herregistratie-aanvraag is in behandeling.\n }\n\n \n \n @let tasks = tasksFor($any(p).registration);\n\n
    \n @if (tasks.length) {\n \n } @else {\n Wat moet ik regelen\n

    U heeft op dit moment niets openstaan.

    \n }\n
    \n\n
    \n Mijn registratie\n
    \n \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n \n \n \n
    \n\n
    \n Specialismen en aantekeningen\n
    \n \n \n \n \n \n \n \n \n

    U heeft nog geen specialismen of aantekeningen.

    \n
    \n
    \n
    \n
    \n\n
    \n Wat wilt u doen?\n \n @for (a of acties; track a.to) {\n
  • \n }\n
    \n
    \n
    \n
    \n `,\n})\nexport class DashboardPage {\n protected store = inject(BigProfileStore);\n private apps = inject(ApplicationsStore);\n private router = inject(Router);\n\n /** Pure view mapping for a submitted aanvraag → CIBG aanvragen-row fields. */\n protected submittedRow = submittedRow;\n\n constructor() {\n // Re-fetch on each visit so server-computed auto-approval transitions show up\n // (Concept → In behandeling → Goedgekeurd after the processing window).\n this.apps.reload();\n }\n\n /** The user's applications, sorted Concept → In behandeling → resolved. Empty →\n the\"Mijn aanvragen\" section is hidden (see template). */\n protected aanvragen = computed(() => {\n const rd = this.apps.applications();\n if (rd.tag !== 'Success') return [];\n const order: Record = { Concept: 0, InBehandeling: 1, Goedgekeurd: 2, Afgewezen: 2 };\n return rd.value.slice().sort((a, b) => order[a.status.tag] - order[b.status.tag]);\n });\n /** A Concept (\"lopende aanvraag\") renders as a melding above the list; the rest\n as keuzelijst items — the two shapes need different HTML contexts. */\n protected concepten = computed(() => this.aanvragen().filter((a) => a.status.tag === 'Concept'));\n protected ingediend = computed(() => this.aanvragen().filter((a) => a.status.tag !== 'Concept'));\n\n private readonly resumeRoutes: Record = {\n registratie: '/registreren',\n herregistratie: '/herregistratie',\n intake: '/intake',\n };\n protected resume(a: Aanvraag) {\n void this.router.navigate([this.resumeRoutes[a.type]], { queryParams: { aanvraag: a.id } });\n }\n protected cancelAanvraag(a: Aanvraag) {\n void this.apps.cancel(a.id);\n }\n\n /** Server-computed eligibility (rendered, not recomputed). */\n private readonly eligible = computed(() => {\n const d = this.store.decisions();\n return d.tag === 'Success' && d.value.eligibleForHerregistratie;\n });\n\n protected tasksFor(reg: Registration) {\n return tasksFromProfile(reg, this.eligible());\n }\n\n /** Primary transactional actions, as an \"aanvragen\" list (see CIBG's\n componenten/aanvragen). The core portal sections live in the header nav now;\n the teaching pages (concepts/brief) are only reachable from here. */\n protected readonly acties = [\n { 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` },\n { 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` },\n { 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` },\n { 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` },\n { 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` },\n { 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` },\n ];\n}\n", + "sourceCode": "import { Component, computed, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { PageShellComponent } from '@shared/layout/page-shell/page-shell.component';\nimport { HeadingComponent } from '@shared/ui/heading/heading.component';\nimport { AlertComponent } from '@shared/ui/alert/alert.component';\nimport { SkeletonComponent } from '@shared/ui/skeleton/skeleton.component';\nimport { DataRowComponent } from '@shared/ui/data-row/data-row.component';\nimport { DataBlockComponent } from '@shared/ui/data-block/data-block.component';\nimport { TaskListComponent } from '@shared/ui/task-list/task-list.component';\nimport { ApplicationListComponent } from '@shared/ui/application-list/application-list.component';\nimport { ApplicationLinkComponent } from '@shared/ui/application-link/application-link.component';\nimport { ASYNC } from '@shared/ui/async/async.component';\nimport { RegistrationSummaryComponent } from '@registratie/ui/registration-summary/registration-summary.component';\nimport { RegistrationTableComponent } from '@registratie/ui/registration-table/registration-table.component';\nimport { AanvraagBlockComponent } from '@registratie/ui/aanvraag-block/aanvraag-block.component';\nimport { BigProfileStore } from '@registratie/application/big-profile.store';\nimport { ApplicationsStore } from '@registratie/application/applications.store';\nimport { Registration } from '@registratie/domain/registration';\nimport { Aanvraag, AanvraagType } from '@registratie/domain/aanvraag';\nimport { submittedRow } from '@registratie/domain/aanvraag-view';\nimport { tasksFromProfile } from '@registratie/domain/tasks';\n\n/** Page:\"Mijn overzicht\" — the portal home, following the NL Design System\n\"Mijn omgeving\" pattern (side nav +\"Wat moet ik regelen\" +\"Mijn zaken\"). */\n@Component({\n selector: 'app-dashboard-page',\n imports: [\n PageShellComponent, HeadingComponent, AlertComponent, SkeletonComponent,\n DataRowComponent, DataBlockComponent, TaskListComponent, ApplicationListComponent, ApplicationLinkComponent,\n ...ASYNC,\n RegistrationSummaryComponent, RegistrationTableComponent, AanvraagBlockComponent,\n ],\n template: `\n \n
    \n @if (aanvragen().length) {\n
    \n @for (a of concepten(); track a.id) {\n \n }\n @if (ingediend().length) {\n Mijn aanvragen\n \n @for (a of ingediend(); track a.id) {\n @let row = submittedRow(a);\n
  • \n }\n
    \n }\n
    \n }\n\n @if (store.pendingHerregistratie()) {\n Uw herregistratie-aanvraag is in behandeling.\n }\n\n \n \n @let tasks = tasksFor($any(p).registration);\n\n
    \n @if (tasks.length) {\n \n } @else {\n Wat moet ik regelen\n

    U heeft op dit moment niets openstaan.

    \n }\n
    \n\n
    \n Mijn registratie\n
    \n \n
    \n \n
    \n
    \n
    \n
    \n
    \n
    \n \n \n \n
    \n\n
    \n Specialismen en aantekeningen\n
    \n \n \n \n \n \n \n \n \n

    U heeft nog geen specialismen of aantekeningen.

    \n
    \n
    \n
    \n
    \n\n
    \n Wat wilt u doen?\n \n @for (a of acties; track a.to) {\n
  • \n }\n
    \n
    \n
    \n
    \n `,\n})\nexport class DashboardPage {\n protected store = inject(BigProfileStore);\n private apps = inject(ApplicationsStore);\n private router = inject(Router);\n\n /** Pure view mapping for a submitted aanvraag → CIBG aanvragen-row fields. */\n protected submittedRow = submittedRow;\n\n constructor() {\n // Re-fetch on each visit so server-computed auto-approval transitions show up\n // (Concept → In behandeling → Goedgekeurd after the processing window).\n this.apps.reload();\n }\n\n /** The user's applications, sorted Concept → In behandeling → resolved. Empty →\n the\"Mijn aanvragen\" section is hidden (see template). */\n protected aanvragen = computed(() => {\n const rd = this.apps.applications();\n if (rd.tag !== 'Success') return [];\n const order: Record = { Concept: 0, InBehandeling: 1, Goedgekeurd: 2, Afgewezen: 2 };\n return rd.value.slice().sort((a, b) => order[a.status.tag] - order[b.status.tag]);\n });\n /** A Concept (\"lopende aanvraag\") renders as a melding above the list; the rest\n as keuzelijst items — the two shapes need different HTML contexts. */\n protected concepten = computed(() => this.aanvragen().filter((a) => a.status.tag === 'Concept'));\n protected ingediend = computed(() => this.aanvragen().filter((a) => a.status.tag !== 'Concept'));\n\n private readonly resumeRoutes: Record = {\n registratie: '/registreren',\n herregistratie: '/herregistratie',\n intake: '/intake',\n };\n protected resume(a: Aanvraag) {\n void this.router.navigate([this.resumeRoutes[a.type]], { queryParams: { aanvraag: a.id } });\n }\n protected cancelAanvraag(a: Aanvraag) {\n void this.apps.cancel(a.id);\n }\n\n /** Server-computed eligibility (rendered, not recomputed). */\n private readonly eligible = computed(() => {\n const d = this.store.decisions();\n return d.tag === 'Success' && d.value.eligibleForHerregistratie;\n });\n\n protected tasksFor(reg: Registration) {\n return tasksFromProfile(reg, this.eligible());\n }\n\n /** Primary transactional actions, as an \"aanvragen\" list (see CIBG's\n componenten/aanvragen). The core portal sections live in the header nav now;\n the teaching pages (concepts/brief) are only reachable from here. */\n protected readonly acties = [\n { 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` },\n { 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` },\n { 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` },\n { 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` },\n { 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` },\n { 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` },\n ];\n}\n", "assetsDirs": [], "styleUrlsData": "", "stylesData": "", @@ -22540,7 +22656,7 @@ "deprecated": false, "deprecationMessage": "", "type": "Routes", - "defaultValue": "[\n {\n path: '',\n component: ShellComponent, // persistent header/footer; only children swap\n children: [\n { path: '', pathMatch: 'full', redirectTo: 'login' },\n { path: 'login', loadComponent: () => \"import('@auth/ui/login.page').then(m => m.LoginPage)\" },\n { path: 'dashboard', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/dashboard.page').then(m => m.DashboardPage)\" },\n { path: 'registratie', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registration-detail.page').then(m => m.RegistrationDetailPage)\" },\n { path: 'registreren', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registratie.page').then(m => m.RegistratiePage)\" },\n { path: 'herregistratie', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/herregistratie.page').then(m => m.HerregistratiePage)\" },\n { path: 'intake', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/intake.page').then(m => m.IntakePage)\" },\n { path: 'brief', canActivate: [authGuard], loadComponent: () => \"import('@brief/ui/brief.page').then(m => m.BriefPage)\" },\n { path: 'concepts', loadComponent: () => \"import('./showcase/concepts.page').then(m => m.ConceptsPage)\" },\n { path: '**', redirectTo: 'login' },\n ],\n },\n]" + "defaultValue": "[\n {\n path: '',\n component: ShellComponent, // persistent header/footer; only children swap\n children: [\n { path: '', pathMatch: 'full', redirectTo: 'login' },\n { path: 'login', loadComponent: () => \"import('@auth/ui/login.page').then(m => m.LoginPage)\" },\n { path: 'dashboard', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/dashboard.page').then(m => m.DashboardPage)\" },\n { path: 'registratie', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registration-detail.page').then(m => m.RegistrationDetailPage)\" },\n { path: 'aanvraag/:id', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/aanvraag-detail.page').then(m => m.AanvraagDetailPage)\" },\n { path: 'registreren', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registratie.page').then(m => m.RegistratiePage)\" },\n { path: 'herregistratie', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/herregistratie.page').then(m => m.HerregistratiePage)\" },\n { path: 'intake', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/intake.page').then(m => m.IntakePage)\" },\n { path: 'brief', canActivate: [authGuard], loadComponent: () => \"import('@brief/ui/brief.page').then(m => m.BriefPage)\" },\n { path: 'concepts', loadComponent: () => \"import('./showcase/concepts.page').then(m => m.ConceptsPage)\" },\n { path: '**', redirectTo: 'login' },\n ],\n },\n]" }, { "name": "ROUTES", @@ -22659,8 +22775,8 @@ "deprecationMessage": "", "type": "Record", "defaultValue": "{\n registratie: $localize`:@@aanvraagBlock.type.registratie:Inschrijving`,\n herregistratie: $localize`:@@aanvraagBlock.type.herregistratie:Herregistratie`,\n intake: $localize`:@@aanvraagBlock.type.intake:Herregistratie-intake`,\n}", - "rawdescription": "View-model mapping for an aanvraag: type → label, and a submitted aanvraag →\nthe CIBG \"aanvragen\" row fields (heading/status/subtitle). Pure, no Angular —\nthe UI renders these, it does not derive them.", - "description": "

    View-model mapping for an aanvraag: type → label, and a submitted aanvraag →\nthe CIBG "aanvragen" row fields (heading/status/subtitle). Pure, no Angular —\nthe UI renders these, it does not derive them.

    \n" + "rawdescription": "View-model mapping for an aanvraag: type → labels, status → label, and the fields\nfor a CIBG \"aanvragen\" row / the case-detail page. Pure, no Angular — the UI\nrenders these, it does not derive them.", + "description": "

    View-model mapping for an aanvraag: type → labels, status → label, and the fields\nfor a CIBG "aanvragen" row / the case-detail page. Pure, no Angular — the UI\nrenders these, it does not derive them.

    \n" }, { "name": "TYPE_LABELS", @@ -23633,6 +23749,35 @@ } ] }, + { + "name": "detailRows", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    Key/value rows for the case-detail page (CIBG Datablock).

    \n", + "args": [ + { + "name": "a", + "type": "Aanvraag", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "literal type[]", + "jsdoctags": [ + { + "name": "a", + "type": "Aanvraag", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "diag", "file": "src/app/brief/domain/placeholders.ts", @@ -26442,6 +26587,35 @@ "args": [], "returnType": "Provider" }, + { + "name": "purposeLabel", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    What the aanvraag is for (shown under the title).

    \n", + "args": [ + { + "name": "type", + "type": "AanvraagType", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "string", + "jsdoctags": [ + { + "name": "type", + "type": "AanvraagType", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "readBlock", "file": "src/app/shared/ui/rich-text-editor/rich-text-dom.ts", @@ -26793,6 +26967,35 @@ } ] }, + { + "name": "referentie", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    The reference number, or '' for a Concept (which has none yet).

    \n", + "args": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "string", + "jsdoctags": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "rejectReason", "file": "src/app/shared/upload/upload.machine.ts", @@ -27684,6 +27887,35 @@ } ] }, + { + "name": "statusLabel", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    The status as a plain label (what state the aanvraag is in).

    \n", + "args": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "string", + "jsdoctags": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "statusLabel", "file": "src/app/registratie/domain/registration.policy.ts", @@ -27807,7 +28039,7 @@ "subtype": "function", "deprecated": false, "deprecationMessage": "", - "description": "

    Fields for a submitted aanvraag's row (Concept has no row — it renders as a\nresumable melding, see aanvraag-block).

    \n", + "description": "

    Fields for a submitted aanvraag's row in the dashboard "aanvragen" list (Concept\nhas no row — it renders as a resumable melding, see aanvraag-block).

    \n", "args": [ { "name": "a", @@ -29829,7 +30061,7 @@ "deprecated": false, "deprecationMessage": "", "type": "Routes", - "defaultValue": "[\n {\n path: '',\n component: ShellComponent, // persistent header/footer; only children swap\n children: [\n { path: '', pathMatch: 'full', redirectTo: 'login' },\n { path: 'login', loadComponent: () => \"import('@auth/ui/login.page').then(m => m.LoginPage)\" },\n { path: 'dashboard', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/dashboard.page').then(m => m.DashboardPage)\" },\n { path: 'registratie', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registration-detail.page').then(m => m.RegistrationDetailPage)\" },\n { path: 'registreren', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registratie.page').then(m => m.RegistratiePage)\" },\n { path: 'herregistratie', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/herregistratie.page').then(m => m.HerregistratiePage)\" },\n { path: 'intake', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/intake.page').then(m => m.IntakePage)\" },\n { path: 'brief', canActivate: [authGuard], loadComponent: () => \"import('@brief/ui/brief.page').then(m => m.BriefPage)\" },\n { path: 'concepts', loadComponent: () => \"import('./showcase/concepts.page').then(m => m.ConceptsPage)\" },\n { path: '**', redirectTo: 'login' },\n ],\n },\n]" + "defaultValue": "[\n {\n path: '',\n component: ShellComponent, // persistent header/footer; only children swap\n children: [\n { path: '', pathMatch: 'full', redirectTo: 'login' },\n { path: 'login', loadComponent: () => \"import('@auth/ui/login.page').then(m => m.LoginPage)\" },\n { path: 'dashboard', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/dashboard.page').then(m => m.DashboardPage)\" },\n { path: 'registratie', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registration-detail.page').then(m => m.RegistrationDetailPage)\" },\n { path: 'aanvraag/:id', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/aanvraag-detail.page').then(m => m.AanvraagDetailPage)\" },\n { path: 'registreren', canActivate: [authGuard], loadComponent: () => \"import('@registratie/ui/registratie.page').then(m => m.RegistratiePage)\" },\n { path: 'herregistratie', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/herregistratie.page').then(m => m.HerregistratiePage)\" },\n { path: 'intake', canActivate: [authGuard], loadComponent: () => \"import('@herregistratie/ui/intake.page').then(m => m.IntakePage)\" },\n { path: 'brief', canActivate: [authGuard], loadComponent: () => \"import('@brief/ui/brief.page').then(m => m.BriefPage)\" },\n { path: 'concepts', loadComponent: () => \"import('./showcase/concepts.page').then(m => m.ConceptsPage)\" },\n { path: '**', redirectTo: 'login' },\n ],\n },\n]" } ], "src/app/shared/layout/breadcrumb/breadcrumb-trail.ts": [ @@ -29928,8 +30160,8 @@ "deprecationMessage": "", "type": "Record", "defaultValue": "{\n registratie: $localize`:@@aanvraagBlock.type.registratie:Inschrijving`,\n herregistratie: $localize`:@@aanvraagBlock.type.herregistratie:Herregistratie`,\n intake: $localize`:@@aanvraagBlock.type.intake:Herregistratie-intake`,\n}", - "rawdescription": "View-model mapping for an aanvraag: type → label, and a submitted aanvraag →\nthe CIBG \"aanvragen\" row fields (heading/status/subtitle). Pure, no Angular —\nthe UI renders these, it does not derive them.", - "description": "

    View-model mapping for an aanvraag: type → label, and a submitted aanvraag →\nthe CIBG "aanvragen" row fields (heading/status/subtitle). Pure, no Angular —\nthe UI renders these, it does not derive them.

    \n" + "rawdescription": "View-model mapping for an aanvraag: type → labels, status → label, and the fields\nfor a CIBG \"aanvragen\" row / the case-detail page. Pure, no Angular — the UI\nrenders these, it does not derive them.", + "description": "

    View-model mapping for an aanvraag: type → labels, status → label, and the fields\nfor a CIBG "aanvragen" row / the case-detail page. Pure, no Angular — the UI\nrenders these, it does not derive them.

    \n" } ], "src/app/shared/infrastructure/scenario.ts": [ @@ -34284,6 +34516,184 @@ ] } ], + "src/app/registratie/domain/aanvraag-view.ts": [ + { + "name": "detailRows", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    Key/value rows for the case-detail page (CIBG Datablock).

    \n", + "args": [ + { + "name": "a", + "type": "Aanvraag", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "literal type[]", + "jsdoctags": [ + { + "name": "a", + "type": "Aanvraag", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "formatNL", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "iso", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "optional": true + } + ], + "returnType": "string", + "jsdoctags": [ + { + "name": "iso", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "optional": true, + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "purposeLabel", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    What the aanvraag is for (shown under the title).

    \n", + "args": [ + { + "name": "type", + "type": "AanvraagType", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "string", + "jsdoctags": [ + { + "name": "type", + "type": "AanvraagType", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "referentie", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    The reference number, or '' for a Concept (which has none yet).

    \n", + "args": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "string", + "jsdoctags": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "statusLabel", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    The status as a plain label (what state the aanvraag is in).

    \n", + "args": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "string", + "jsdoctags": [ + { + "name": "status", + "type": "AanvraagStatus", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "submittedRow", + "file": "src/app/registratie/domain/aanvraag-view.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

    Fields for a submitted aanvraag's row in the dashboard "aanvragen" list (Concept\nhas no row — it renders as a resumable melding, see aanvraag-block).

    \n", + "args": [ + { + "name": "a", + "type": "Aanvraag", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "AanvraagRow", + "jsdoctags": [ + { + "name": "a", + "type": "Aanvraag", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + } + ], "src/app/brief/domain/placeholders.ts": [ { "name": "diag", @@ -34544,68 +34954,6 @@ ] } ], - "src/app/registratie/domain/aanvraag-view.ts": [ - { - "name": "formatNL", - "file": "src/app/registratie/domain/aanvraag-view.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "iso", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true - } - ], - "returnType": "string", - "jsdoctags": [ - { - "name": "iso", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "optional": true, - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "submittedRow", - "file": "src/app/registratie/domain/aanvraag-view.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

    Fields for a submitted aanvraag's row (Concept has no row — it renders as a\nresumable melding, see aanvraag-block).

    \n", - "args": [ - { - "name": "a", - "type": "Aanvraag", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "AanvraagRow", - "jsdoctags": [ - { - "name": "a", - "type": "Aanvraag", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], "src/app/registratie/domain/tasks.ts": [ { "name": "formatNL", @@ -36676,6 +37024,11 @@ "kind": "route-path", "filename": "src/app/app.routes.ts" }, + { + "name": "aanvraag/:id", + "kind": "route-path", + "filename": "src/app/app.routes.ts" + }, { "name": "registreren", "kind": "route-path", @@ -36719,7 +37072,7 @@ ] }, "coverage": { - "count": 36, + "count": 37, "status": "medium", "files": [ { @@ -38143,6 +38496,16 @@ "coverageCount": "2/4", "status": "medium" }, + { + "filePath": "src/app/registratie/domain/aanvraag-view.ts", + "type": "function", + "linktype": "miscellaneous", + "linksubtype": "function", + "name": "detailRows", + "coveragePercent": 100, + "coverageCount": "1/1", + "status": "very-good" + }, { "filePath": "src/app/registratie/domain/aanvraag-view.ts", "type": "function", @@ -38153,6 +38516,36 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/app/registratie/domain/aanvraag-view.ts", + "type": "function", + "linktype": "miscellaneous", + "linksubtype": "function", + "name": "purposeLabel", + "coveragePercent": 100, + "coverageCount": "1/1", + "status": "very-good" + }, + { + "filePath": "src/app/registratie/domain/aanvraag-view.ts", + "type": "function", + "linktype": "miscellaneous", + "linksubtype": "function", + "name": "referentie", + "coveragePercent": 100, + "coverageCount": "1/1", + "status": "very-good" + }, + { + "filePath": "src/app/registratie/domain/aanvraag-view.ts", + "type": "function", + "linktype": "miscellaneous", + "linksubtype": "function", + "name": "statusLabel", + "coveragePercent": 100, + "coverageCount": "1/1", + "status": "very-good" + }, { "filePath": "src/app/registratie/domain/aanvraag-view.ts", "type": "function", @@ -39042,6 +39435,15 @@ "coverageCount": "0/1", "status": "low" }, + { + "filePath": "src/app/registratie/ui/aanvraag-detail.page.ts", + "type": "component", + "linktype": "component", + "name": "AanvraagDetailPage", + "coveragePercent": 20, + "coverageCount": "1/5", + "status": "low" + }, { "filePath": "src/app/registratie/ui/address-fields/address-fields.component.ts", "type": "component", diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index cfb6a8f..cced12a 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -11,6 +11,7 @@ export const routes: Routes = [ { path: 'login', loadComponent: () => import('@auth/ui/login.page').then(m => m.LoginPage) }, { path: 'dashboard', canActivate: [authGuard], loadComponent: () => import('@registratie/ui/dashboard.page').then(m => m.DashboardPage) }, { path: 'registratie', canActivate: [authGuard], loadComponent: () => import('@registratie/ui/registration-detail.page').then(m => m.RegistrationDetailPage) }, + { path: 'aanvraag/:id', canActivate: [authGuard], loadComponent: () => import('@registratie/ui/aanvraag-detail.page').then(m => m.AanvraagDetailPage) }, { path: 'registreren', canActivate: [authGuard], loadComponent: () => import('@registratie/ui/registratie.page').then(m => m.RegistratiePage) }, { path: 'herregistratie', canActivate: [authGuard], loadComponent: () => import('@herregistratie/ui/herregistratie.page').then(m => m.HerregistratiePage) }, { path: 'intake', canActivate: [authGuard], loadComponent: () => import('@herregistratie/ui/intake.page').then(m => m.IntakePage) }, diff --git a/src/app/registratie/domain/aanvraag-view.spec.ts b/src/app/registratie/domain/aanvraag-view.spec.ts index 34bab9a..b2048bd 100644 --- a/src/app/registratie/domain/aanvraag-view.spec.ts +++ b/src/app/registratie/domain/aanvraag-view.spec.ts @@ -1,30 +1,45 @@ import { describe, it, expect } from 'vitest'; -import { submittedRow, TYPE_LABELS } from './aanvraag-view'; +import { submittedRow, detailRows, purposeLabel, statusLabel, TYPE_LABELS } from './aanvraag-view'; import { Aanvraag } from './aanvraag'; const base = { id: '1', type: 'herregistratie' as const, documentIds: [], createdAt: '', updatedAt: '', submittedAt: '2024-05-12' }; describe('submittedRow', () => { - it('InBehandeling: reference + submit date; manual note only when manual', () => { - const auto = submittedRow({ ...base, status: { tag: 'InBehandeling', referentie: 'R1', manual: false } } as Aanvraag); - expect(auto.heading).toBe(TYPE_LABELS.herregistratie); - expect(auto.status).toContain('R1'); - expect(auto.status).toContain('12 mei 2024'); - expect(auto.subtitle).toBe(''); + it('heading is the type, subtitle is the purpose', () => { + const row = submittedRow({ ...base, status: { tag: 'InBehandeling', referentie: 'R1', manual: false } } as Aanvraag); + expect(row.heading).toBe(TYPE_LABELS.herregistratie); + expect(row.subtitle).toBe(purposeLabel('herregistratie')); + }); + it('status line carries the status label, reference and submit date', () => { + const row = submittedRow({ ...base, status: { tag: 'InBehandeling', referentie: 'R1', manual: false } } as Aanvraag); + expect(row.status).toContain(statusLabel({ tag: 'InBehandeling', referentie: 'R1', manual: false })); + expect(row.status).toContain('R1'); + expect(row.status).toContain('12 mei 2024'); + }); + + it('manual review adds a note; rejection adds its reason', () => { const manual = submittedRow({ ...base, status: { tag: 'InBehandeling', referentie: 'R1', manual: true } } as Aanvraag); - expect(manual.subtitle).not.toBe(''); - }); - - it('Afgewezen: reason becomes the subtitle', () => { - const row = submittedRow({ ...base, status: { tag: 'Afgewezen', referentie: 'R2', reden: 'Onvoldoende uren' } } as Aanvraag); - expect(row.status).toContain('R2'); - expect(row.subtitle).toBe('Onvoldoende uren'); - }); - - it('Goedgekeurd: reference only', () => { - const row = submittedRow({ ...base, status: { tag: 'Goedgekeurd', referentie: 'R3' } } as Aanvraag); - expect(row.status).toContain('R3'); - expect(row.subtitle).toBe(''); + expect(manual.status).toContain('handmatig'); + const rejected = submittedRow({ ...base, status: { tag: 'Afgewezen', referentie: 'R2', reden: 'Onvoldoende uren' } } as Aanvraag); + expect(rejected.status).toContain('Onvoldoende uren'); + }); +}); + +describe('detailRows', () => { + it('lists soort/waarvoor/status/referentie/ingediend, plus reason when rejected', () => { + const rows = detailRows({ ...base, status: { tag: 'Afgewezen', referentie: 'R2', reden: 'Onvoldoende uren' } } as Aanvraag); + const values = rows.map((r) => r.value); + expect(values).toContain(TYPE_LABELS.herregistratie); + expect(values).toContain('R2'); + expect(values).toContain('Onvoldoende uren'); + expect(rows.length).toBe(6); + }); + + it('reference falls back to em dash for a Concept', () => { + const rows = detailRows({ ...base, submittedAt: undefined, status: { tag: 'Concept', stepIndex: 0, stepCount: 3 } } as Aanvraag); + const ref = rows.find((r) => r.value === '—'); + expect(ref).toBeTruthy(); + expect(rows.length).toBe(5); }); }); diff --git a/src/app/registratie/domain/aanvraag-view.ts b/src/app/registratie/domain/aanvraag-view.ts index e5f70d2..94abf0b 100644 --- a/src/app/registratie/domain/aanvraag-view.ts +++ b/src/app/registratie/domain/aanvraag-view.ts @@ -1,8 +1,8 @@ -import { Aanvraag, AanvraagType } from './aanvraag'; +import { Aanvraag, AanvraagStatus, AanvraagType } from './aanvraag'; -/** View-model mapping for an aanvraag: type → label, and a submitted aanvraag → - the CIBG "aanvragen" row fields (heading/status/subtitle). Pure, no Angular — - the UI renders these, it does not derive them. */ +/** View-model mapping for an aanvraag: type → labels, status → label, and the fields + for a CIBG "aanvragen" row / the case-detail page. Pure, no Angular — the UI + renders these, it does not derive them. */ export const TYPE_LABELS: Record = { registratie: $localize`:@@aanvraagBlock.type.registratie:Inschrijving`, @@ -10,35 +10,66 @@ export const TYPE_LABELS: Record = { intake: $localize`:@@aanvraagBlock.type.intake:Herregistratie-intake`, }; +/** What the aanvraag is for (shown under the title). */ +export function purposeLabel(type: AanvraagType): string { + switch (type) { + case 'registratie': return $localize`:@@aanvraag.purpose.registratie:Inschrijving in het BIG-register`; + case 'herregistratie': return $localize`:@@aanvraag.purpose.herregistratie:Verlenging van uw BIG-registratie`; + case 'intake': return $localize`:@@aanvraag.purpose.intake:Intake-vragenlijst voor uw herregistratie`; + } +} + +/** The status as a plain label (what state the aanvraag is in). */ +export function statusLabel(status: AanvraagStatus): string { + switch (status.tag) { + case 'Concept': return $localize`:@@aanvraag.status.concept:Concept (nog niet ingediend)`; + case 'InBehandeling': return $localize`:@@aanvraag.status.inBehandeling:In behandeling`; + case 'Goedgekeurd': return $localize`:@@aanvraag.status.goedgekeurd:Goedgekeurd`; + case 'Afgewezen': return $localize`:@@aanvraag.status.afgewezen:Afgewezen`; + } +} + +/** The reference number, or '' for a Concept (which has none yet). */ +export function referentie(status: AanvraagStatus): string { + return status.tag === 'Concept' ? '' : status.referentie; +} + export interface AanvraagRow { heading: string; - /** Reference + submit-date line (the `.status` line of an aanvragen row). */ - status: string; - /** Secondary note: manual-review notice or rejection reason. */ + /** What the aanvraag is for (the `.subtitle` line). */ subtitle: string; + /** The status: label + reference + submit date (+ any note) — the `.status` line. */ + status: string; } function formatNL(iso?: string): string { return iso ? new Date(iso).toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' }) : ''; } -/** Fields for a submitted aanvraag's row (Concept has no row — it renders as a - resumable melding, see aanvraag-block). */ +/** Fields for a submitted aanvraag's row in the dashboard "aanvragen" list (Concept + has no row — it renders as a resumable melding, see aanvraag-block). */ export function submittedRow(a: Aanvraag): AanvraagRow { const s = a.status; - const heading = TYPE_LABELS[a.type]; - switch (s.tag) { - case 'Concept': - return { heading, status: '', subtitle: '' }; - case 'InBehandeling': - return { - heading, - status: $localize`:@@aanvraagBlock.inBehandeling:Referentie ${s.referentie}:ref: · ingediend op ${formatNL(a.submittedAt)}:datum:`, - subtitle: s.manual ? $localize`:@@aanvraagBlock.manual:Uw aanvraag wordt handmatig beoordeeld in de backoffice.` : '', - }; - case 'Goedgekeurd': - return { heading, status: $localize`:@@aanvraagBlock.goedgekeurd:Referentie ${s.referentie}:ref:`, subtitle: '' }; - case 'Afgewezen': - return { heading, status: $localize`:@@aanvraagBlock.afgewezen:Referentie ${s.referentie}:ref:`, subtitle: s.reden }; - } + const parts = [statusLabel(s)]; + const ref = referentie(s); + if (ref) parts.push($localize`:@@aanvraag.row.ref:Referentie ${ref}:ref:`); + if (a.submittedAt) parts.push($localize`:@@aanvraag.row.ingediend:ingediend op ${formatNL(a.submittedAt)}:datum:`); + if (s.tag === 'InBehandeling' && s.manual) parts.push($localize`:@@aanvraagBlock.manual:Uw aanvraag wordt handmatig beoordeeld in de backoffice.`); + if (s.tag === 'Afgewezen') parts.push(s.reden); + return { heading: TYPE_LABELS[a.type], subtitle: purposeLabel(a.type), status: parts.join(' · ') }; +} + +/** Key/value rows for the case-detail page (CIBG Datablock). */ +export function detailRows(a: Aanvraag): { key: string; value: string }[] { + const rows = [ + { key: $localize`:@@aanvraag.detail.soort:Soort aanvraag`, value: TYPE_LABELS[a.type] }, + { key: $localize`:@@aanvraag.detail.waarvoor:Waarvoor`, value: purposeLabel(a.type) }, + { key: $localize`:@@aanvraag.detail.status:Status`, value: statusLabel(a.status) }, + { key: $localize`:@@aanvraag.detail.referentie:Referentie`, value: referentie(a.status) || '—' }, + { key: $localize`:@@aanvraag.detail.ingediend:Ingediend op`, value: a.submittedAt ? formatNL(a.submittedAt) : '—' }, + ]; + if (a.status.tag === 'Afgewezen') { + rows.push({ key: $localize`:@@aanvraag.detail.reden:Reden van afwijzing`, value: a.status.reden }); + } + return rows; } diff --git a/src/app/registratie/ui/aanvraag-detail.page.ts b/src/app/registratie/ui/aanvraag-detail.page.ts new file mode 100644 index 0000000..0c59f4c --- /dev/null +++ b/src/app/registratie/ui/aanvraag-detail.page.ts @@ -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: ` + + + + @let a = find($any(list)); + @if (a) { + + @for (row of rows(a); track row.key) { +
    + } +
    + + De volledige afhandeling van deze aanvraag is nog niet beschikbaar in deze POC. + + } @else { + Deze aanvraag is niet gevonden. + } +
    + + + +
    +
    + `, +}) +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; +} diff --git a/src/app/registratie/ui/dashboard.page.ts b/src/app/registratie/ui/dashboard.page.ts index 9f5c4c6..2365f29 100644 --- a/src/app/registratie/ui/dashboard.page.ts +++ b/src/app/registratie/ui/dashboard.page.ts @@ -43,7 +43,7 @@ import { tasksFromProfile } from '@registratie/domain/tasks'; @for (a of ingediend(); track a.id) { @let row = submittedRow(a); -
  • +
  • }
    } diff --git a/src/app/shared/ui/application-list/application-list.stories.ts b/src/app/shared/ui/application-list/application-list.stories.ts index 87d72ac..4bb14e3 100644 --- a/src/app/shared/ui/application-list/application-list.stories.ts +++ b/src/app/shared/ui/application-list/application-list.stories.ts @@ -14,9 +14,9 @@ const meta: Meta = { render: () => ({ template: ` -
  • -
  • -
  • +
  • +
  • +
  • `, }), };