From 0cfb01f12c4298904abb2733be655fdf6cad8d0b Mon Sep 17 00:00:00 2001 From: Edwin van den Houdt Date: Fri, 3 Jul 2026 23:37:58 +0200 Subject: [PATCH] =?UTF-8?q?feat(fp):=20WP-15=20=E2=80=94=20missing=20stori?= =?UTF-8?q?es:=20shell=20+=20brief=20components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the 7 stories CLAUDE.md's testing rule ("UI is exercised via Storybook stories") was missing: shared/layout/shell (Design System/Templates/Shell) and all six previously-unstoried brief components (passage-picker, rejection-comments, diagnostics-panel, letter-block, letter-preview, letter-section — Domein/Brief/*), each with a default state plus the meaningful variants (locked/editable, findings/clean, show/entry, etc). Every *.component.ts in the repo now has a co-located story; *.page.ts files stay unstoried, matching the existing norm. Co-Authored-By: Claude Sonnet 5 --- docs/backlog/README.md | 2 +- docs/backlog/WP-15-missing-stories.md | 20 +- documentation.json | 2774 ++++++++--------- .../diagnostics-panel.stories.ts | 33 + .../ui/letter-block/letter-block.stories.ts | 47 + .../letter-preview/letter-preview.stories.ts | 88 + .../letter-section/letter-section.stories.ts | 55 + .../passage-picker/passage-picker.stories.ts | 37 + .../rejection-comments.stories.ts | 16 + src/app/shared/layout/shell/shell.stories.ts | 16 + 10 files changed, 1695 insertions(+), 1393 deletions(-) create mode 100644 src/app/brief/ui/diagnostics-panel/diagnostics-panel.stories.ts create mode 100644 src/app/brief/ui/letter-block/letter-block.stories.ts create mode 100644 src/app/brief/ui/letter-preview/letter-preview.stories.ts create mode 100644 src/app/brief/ui/letter-section/letter-section.stories.ts create mode 100644 src/app/brief/ui/passage-picker/passage-picker.stories.ts create mode 100644 src/app/brief/ui/rejection-comments/rejection-comments.stories.ts create mode 100644 src/app/shared/layout/shell/shell.stories.ts diff --git a/docs/backlog/README.md b/docs/backlog/README.md index 43a8953..bb285f2 100644 --- a/docs/backlog/README.md +++ b/docs/backlog/README.md @@ -54,7 +54,7 @@ for its existing violations, so every WP ends green. | [WP-12](WP-12-datablock.md) | CIBG Datablock for application data | 2 · CIBG | done | | [WP-13](WP-13-cibg-gap-register.md) | CIBG-gap register + hygiene + MDX | 2 · CIBG | done | | [WP-14](WP-14-storybook-taxonomy.md) | Storybook taxonomy reorg + Layers MDX | 3 · Storybook | done | -| [WP-15](WP-15-missing-stories.md) | Missing stories: shell + brief components | 3 · Storybook | todo | +| [WP-15](WP-15-missing-stories.md) | Missing stories: shell + brief components | 3 · Storybook | done | | [WP-16](WP-16-component-a11y.md) | Component a11y: description wiring + alert role | 4 · a11y | todo | | [WP-17](WP-17-app-a11y.md) | App-level a11y: route focus, template lint, WCAG checklist | 4 · a11y | todo | | [WP-18](WP-18-abac-capability-spine.md) | ABAC capability spine (Principal + capabilities, phase P1) | 5 · productie-volwassenheid | done | diff --git a/docs/backlog/WP-15-missing-stories.md b/docs/backlog/WP-15-missing-stories.md index 6c928f3..872b809 100644 --- a/docs/backlog/WP-15-missing-stories.md +++ b/docs/backlog/WP-15-missing-stories.md @@ -1,9 +1,18 @@ # WP-15 — Missing stories: shell + brief components -Status: todo +Status: done () Phase: 3 — Storybook as curriculum Depends on: WP-14 (titles), WP-01 (axe gate covers the new stories automatically) +> **Note:** fixture duplication across the four brief stories that need `Brief`/ +> `LetterSection`/`LetterBlock` shapes (letter-block, letter-preview, letter-section, plus +> the pre-existing letter-composer) didn't bite enough to justify the shared-fixtures +> escape hatch — each story only builds the minimal slice it actually renders (letter-block +> needs one block, not a whole `Brief`), so the co-located fixtures stayed small and +> non-duplicative in practice. A pre-existing, unrelated axe finding on +> `text-input--invalid` (informational only — `test-storybook:ci` doesn't fail on it) shows +> up in the run; it predates this WP and isn't caused by anything here. + ## Why "UI is exercised via Storybook stories" (CLAUDE.md §5) — but 7 components have none: @@ -44,11 +53,12 @@ invisible to the axe gate. ## Acceptance criteria -- [ ] Every component in `src/app` has ≥1 story (verify: list components without a +- [x] Every component in `src/app` has ≥1 story (verify: list components without a co-located `*.stories.ts`; expect zero, pages excepted if that's the existing - norm — note the norm in this file when checked). -- [ ] All new stories pass the axe gate (or carry a justified skip). -- [ ] Titles follow WP-14. + norm — note the norm in this file when checked). **Confirmed norm:** `*.page.ts` + files (9 of them) have never had stories; every `*.component.ts` now does. +- [x] All new stories pass the axe gate (or carry a justified skip). +- [x] Titles follow WP-14. ## Verification diff --git a/documentation.json b/documentation.json index 824bd4a..c4c8e19 100644 --- a/documentation.json +++ b/documentation.json @@ -2082,7 +2082,54 @@ }, { "name": "Draft", - "id": "interface-Draft-51c29a3fca3c5bd3eba53c9bc57714c79817ae8c86b1ed9c1cd76652d31b45ee7c635d35f7eb0a3a7e5bf9ea7c5da5c066cee3908c8fe4b9fe053586f834b133", + "id": "interface-Draft-3f75a0ff51d12ccab50bfa13789cace778d5acff9f4feaa1607cdf1acb4a5ab4fcc687512424cb2252ec07568f6aea07a0b4f04469cbeed733c28654443ffd9e", + "file": "src/app/herregistratie/domain/herregistratie.machine.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "interface", + "sourceCode": "import { Result, assertNever } from '@shared/kernel/fp';\nimport { Uren, parseUren } from '@registratie/domain/value-objects/uren';\nimport {\n UploadState,\n UploadMsg,\n initialUpload,\n reduceUpload,\n requiredCategoriesSatisfied,\n deliveryRefs,\n} from '@shared/upload/upload.machine';\n\n/** What the user is typing (raw, possibly invalid). */\nexport interface Draft {\n uren: string;\n jaren: string;\n punten: string;\n}\n\nexport type StepErrors = Partial>;\n\n/** What we have AFTER parsing — branded/typed, guaranteed valid. */\nexport interface Valid {\n uren: Uren;\n jaren: number;\n punten: number;\n documents: Array<{ categoryId: string; channel: 'digital' | 'post'; documentId?: string }>;\n}\n\n/**\n * The whole wizard as one tagged union. `step` and `errors` exist ONLY while\n * Editing; Submitting/Submitted/Failed carry a `Valid` payload and nothing else.\n * So \"submitting while a field is invalid\" or \"showing the success screen with\n * errors set\" are unrepresentable — the bug class is gone by construction.\n */\nexport type WizardState =\n | { tag: 'Editing'; step: 1 | 2 | 3; draft: Draft; errors: StepErrors; upload: UploadState }\n | { tag: 'Submitting'; data: Valid }\n | { tag: 'Submitted'; data: Valid }\n | { tag: 'Failed'; data: Valid; error: string };\n\nexport const initial: WizardState = {\n tag: 'Editing',\n step: 1,\n draft: { uren: '', jaren: '', punten: '' },\n errors: {},\n upload: initialUpload,\n};\n\n/** Has the user meaningfully started, so it's worth persisting as a Concept? */\nexport function hasProgress(s: Extract): boolean {\n return (\n s.step > 1 ||\n !!s.draft.uren ||\n !!s.draft.jaren ||\n !!s.draft.punten ||\n deliveryRefs(s.upload).some((r) => r.channel === 'digital' && !!r.documentId)\n );\n}\n\n/** Parse every field; on success hand back a Valid, else the per-field errors. */\nfunction validate(draft: Draft, upload: UploadState): Result {\n const uren = parseUren(draft.uren);\n const jaren = parseUren(draft.jaren);\n const punten = parseUren(draft.punten);\n const errors: StepErrors = {};\n if (!uren.ok) errors.uren = uren.error;\n if (!jaren.ok) errors.jaren = jaren.error;\n if (!punten.ok) errors.punten = punten.error;\n if (!requiredCategoriesSatisfied(upload)) {\n errors.documenten = $localize`:@@validation.documenten:Lever de verplichte documenten aan (upload of kies \"per post nasturen\").`;\n }\n if (uren.ok && jaren.ok && punten.ok && !errors.documenten) {\n return {\n ok: true,\n value: {\n uren: uren.value,\n jaren: jaren.value,\n punten: punten.value,\n documents: deliveryRefs(upload),\n },\n };\n }\n return { ok: false, error: errors };\n}\n\n/** Advance one step, gating on that step's fields. Illegal elsewhere = no-op. */\nexport function next(s: WizardState): WizardState {\n if (s.tag !== 'Editing') return s;\n const errors: StepErrors = {};\n if (s.step === 1) {\n const uren = parseUren(s.draft.uren);\n const jaren = parseUren(s.draft.jaren);\n if (!uren.ok) errors.uren = uren.error;\n if (!jaren.ok) errors.jaren = jaren.error;\n return Object.keys(errors).length === 0 ? { ...s, step: 2, errors: {} } : { ...s, errors };\n }\n if (s.step === 2) {\n const punten = parseUren(s.draft.punten);\n if (!punten.ok) errors.punten = punten.error;\n return punten.ok ? { ...s, step: 3, errors: {} } : { ...s, errors };\n }\n return s;\n}\n\nexport function back(s: WizardState): WizardState {\n if (s.tag !== 'Editing' || s.step === 1) return s;\n return { ...s, step: (s.step - 1) as 1 | 2, errors: {} };\n}\n\n/** Jump back to an earlier step to correct data (controle → step N). Forward\n jumps are not allowed (would skip validation). */\nexport function gaNaarStap(s: WizardState, step: 1 | 2 | 3): WizardState {\n if (s.tag !== 'Editing' || step >= s.step) return s;\n return { ...s, step, errors: {} };\n}\n\n/** Step 3 submit: parse everything + require documents; Submitting only with Valid. */\nexport function submit(s: WizardState): WizardState {\n if (s.tag !== 'Editing' || s.step !== 3) return s;\n const result = validate(s.draft, s.upload);\n return result.ok ? { tag: 'Submitting', data: result.value } : { ...s, errors: result.error };\n}\n\n/** Route an upload sub-message through the pure upload reducer (Editing only). */\nexport function upload(s: WizardState, msg: UploadMsg): WizardState {\n if (s.tag !== 'Editing') return s;\n return { ...s, upload: reduceUpload(s.upload, msg) };\n}\n\n/** Resolve the async submit. Only meaningful while Submitting. */\nexport function resolve(s: WizardState, r: Result): WizardState {\n if (s.tag !== 'Submitting') return s;\n return r.ok\n ? { tag: 'Submitted', data: s.data }\n : { tag: 'Failed', data: s.data, error: r.error };\n}\n\n/** Update one draft field while editing; ignored in any other state. */\nexport function setField(s: WizardState, key: keyof Draft, value: string): WizardState {\n if (s.tag !== 'Editing') return s;\n return { ...s, draft: { ...s.draft, [key]: value } };\n}\n\n/**\n * Every event that can happen to the wizard, as one message type. The component\n * sends a WizardMsg; `reduce` decides the next state. This is the Elm\n * Model+Msg+update pattern: ONE pure function describes all state changes.\n */\nexport type WizardMsg =\n | { tag: 'SetField'; key: keyof Draft; value: string }\n | { tag: 'Next' }\n | { tag: 'Back' }\n | { tag: 'GaNaarStap'; step: 1 | 2 | 3 }\n | { tag: 'Submit' }\n | { tag: 'Retry' }\n | { tag: 'SubmitConfirmed' }\n | { tag: 'SubmitFailed'; error: string }\n | { tag: 'Upload'; msg: UploadMsg }\n | { tag: 'Seed'; state: WizardState }; // mount a specific state (stories/showcase)\n\nexport function reduce(s: WizardState, m: WizardMsg): WizardState {\n switch (m.tag) {\n case 'SetField':\n return setField(s, m.key, m.value);\n case 'Next':\n return next(s);\n case 'Back':\n return back(s);\n case 'GaNaarStap':\n return gaNaarStap(s, m.step);\n case 'Submit':\n return submit(s);\n case 'Retry':\n return s.tag === 'Failed' ? { tag: 'Submitting', data: s.data } : s;\n case 'SubmitConfirmed':\n return s.tag === 'Submitting' ? { tag: 'Submitted', data: s.data } : s;\n case 'SubmitFailed':\n return s.tag === 'Submitting' ? { tag: 'Failed', data: s.data, error: m.error } : s;\n case 'Upload':\n return upload(s, m.msg);\n case 'Seed':\n return m.state;\n default:\n return assertNever(m);\n }\n}\n", + "properties": [ + { + "name": "jaren", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "indexKey": "", + "optional": false, + "description": "", + "line": 15 + }, + { + "name": "punten", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "indexKey": "", + "optional": false, + "description": "", + "line": 16 + }, + { + "name": "uren", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "indexKey": "", + "optional": false, + "description": "", + "line": 14 + } + ], + "indexSignatures": [], + "kind": 172, + "description": "

What the user is typing (raw, possibly invalid).

\n", + "rawdescription": "\nWhat the user is typing (raw, possibly invalid).", + "methods": [], + "extends": [] + }, + { + "name": "Draft", + "id": "interface-Draft-51c29a3fca3c5bd3eba53c9bc57714c79817ae8c86b1ed9c1cd76652d31b45ee7c635d35f7eb0a3a7e5bf9ea7c5da5c066cee3908c8fe4b9fe053586f834b133-1", "file": "src/app/registratie/domain/change-request.machine.ts", "deprecated": false, "deprecationMessage": "", @@ -2125,11 +2172,14 @@ "description": "

What the user is typing (raw, possibly invalid).

\n", "rawdescription": "\nWhat the user is typing (raw, possibly invalid).", "methods": [], - "extends": [] + "extends": [], + "isDuplicate": true, + "duplicateId": 1, + "duplicateName": "Draft-1" }, { "name": "Draft", - "id": "interface-Draft-9669bb22f8d4cc591a3bd64d9fc83275b70ad9e7275d59b4d1d394db7252e8820908b20c593f0b3a16c415c40ad1232ed7d04ba684d0dee9d72bc1ae820d06b6-1", + "id": "interface-Draft-9669bb22f8d4cc591a3bd64d9fc83275b70ad9e7275d59b4d1d394db7252e8820908b20c593f0b3a16c415c40ad1232ed7d04ba684d0dee9d72bc1ae820d06b6-2", "file": "src/app/registratie/domain/registratie-wizard.machine.ts", "deprecated": false, "deprecationMessage": "", @@ -2254,56 +2304,6 @@ "methods": [], "extends": [], "isDuplicate": true, - "duplicateId": 1, - "duplicateName": "Draft-1" - }, - { - "name": "Draft", - "id": "interface-Draft-3f75a0ff51d12ccab50bfa13789cace778d5acff9f4feaa1607cdf1acb4a5ab4fcc687512424cb2252ec07568f6aea07a0b4f04469cbeed733c28654443ffd9e-2", - "file": "src/app/herregistratie/domain/herregistratie.machine.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Result, assertNever } from '@shared/kernel/fp';\nimport { Uren, parseUren } from '@registratie/domain/value-objects/uren';\nimport {\n UploadState,\n UploadMsg,\n initialUpload,\n reduceUpload,\n requiredCategoriesSatisfied,\n deliveryRefs,\n} from '@shared/upload/upload.machine';\n\n/** What the user is typing (raw, possibly invalid). */\nexport interface Draft {\n uren: string;\n jaren: string;\n punten: string;\n}\n\nexport type StepErrors = Partial>;\n\n/** What we have AFTER parsing — branded/typed, guaranteed valid. */\nexport interface Valid {\n uren: Uren;\n jaren: number;\n punten: number;\n documents: Array<{ categoryId: string; channel: 'digital' | 'post'; documentId?: string }>;\n}\n\n/**\n * The whole wizard as one tagged union. `step` and `errors` exist ONLY while\n * Editing; Submitting/Submitted/Failed carry a `Valid` payload and nothing else.\n * So \"submitting while a field is invalid\" or \"showing the success screen with\n * errors set\" are unrepresentable — the bug class is gone by construction.\n */\nexport type WizardState =\n | { tag: 'Editing'; step: 1 | 2 | 3; draft: Draft; errors: StepErrors; upload: UploadState }\n | { tag: 'Submitting'; data: Valid }\n | { tag: 'Submitted'; data: Valid }\n | { tag: 'Failed'; data: Valid; error: string };\n\nexport const initial: WizardState = {\n tag: 'Editing',\n step: 1,\n draft: { uren: '', jaren: '', punten: '' },\n errors: {},\n upload: initialUpload,\n};\n\n/** Has the user meaningfully started, so it's worth persisting as a Concept? */\nexport function hasProgress(s: Extract): boolean {\n return (\n s.step > 1 ||\n !!s.draft.uren ||\n !!s.draft.jaren ||\n !!s.draft.punten ||\n deliveryRefs(s.upload).some((r) => r.channel === 'digital' && !!r.documentId)\n );\n}\n\n/** Parse every field; on success hand back a Valid, else the per-field errors. */\nfunction validate(draft: Draft, upload: UploadState): Result {\n const uren = parseUren(draft.uren);\n const jaren = parseUren(draft.jaren);\n const punten = parseUren(draft.punten);\n const errors: StepErrors = {};\n if (!uren.ok) errors.uren = uren.error;\n if (!jaren.ok) errors.jaren = jaren.error;\n if (!punten.ok) errors.punten = punten.error;\n if (!requiredCategoriesSatisfied(upload)) {\n errors.documenten = $localize`:@@validation.documenten:Lever de verplichte documenten aan (upload of kies \"per post nasturen\").`;\n }\n if (uren.ok && jaren.ok && punten.ok && !errors.documenten) {\n return {\n ok: true,\n value: {\n uren: uren.value,\n jaren: jaren.value,\n punten: punten.value,\n documents: deliveryRefs(upload),\n },\n };\n }\n return { ok: false, error: errors };\n}\n\n/** Advance one step, gating on that step's fields. Illegal elsewhere = no-op. */\nexport function next(s: WizardState): WizardState {\n if (s.tag !== 'Editing') return s;\n const errors: StepErrors = {};\n if (s.step === 1) {\n const uren = parseUren(s.draft.uren);\n const jaren = parseUren(s.draft.jaren);\n if (!uren.ok) errors.uren = uren.error;\n if (!jaren.ok) errors.jaren = jaren.error;\n return Object.keys(errors).length === 0 ? { ...s, step: 2, errors: {} } : { ...s, errors };\n }\n if (s.step === 2) {\n const punten = parseUren(s.draft.punten);\n if (!punten.ok) errors.punten = punten.error;\n return punten.ok ? { ...s, step: 3, errors: {} } : { ...s, errors };\n }\n return s;\n}\n\nexport function back(s: WizardState): WizardState {\n if (s.tag !== 'Editing' || s.step === 1) return s;\n return { ...s, step: (s.step - 1) as 1 | 2, errors: {} };\n}\n\n/** Jump back to an earlier step to correct data (controle → step N). Forward\n jumps are not allowed (would skip validation). */\nexport function gaNaarStap(s: WizardState, step: 1 | 2 | 3): WizardState {\n if (s.tag !== 'Editing' || step >= s.step) return s;\n return { ...s, step, errors: {} };\n}\n\n/** Step 3 submit: parse everything + require documents; Submitting only with Valid. */\nexport function submit(s: WizardState): WizardState {\n if (s.tag !== 'Editing' || s.step !== 3) return s;\n const result = validate(s.draft, s.upload);\n return result.ok ? { tag: 'Submitting', data: result.value } : { ...s, errors: result.error };\n}\n\n/** Route an upload sub-message through the pure upload reducer (Editing only). */\nexport function upload(s: WizardState, msg: UploadMsg): WizardState {\n if (s.tag !== 'Editing') return s;\n return { ...s, upload: reduceUpload(s.upload, msg) };\n}\n\n/** Resolve the async submit. Only meaningful while Submitting. */\nexport function resolve(s: WizardState, r: Result): WizardState {\n if (s.tag !== 'Submitting') return s;\n return r.ok\n ? { tag: 'Submitted', data: s.data }\n : { tag: 'Failed', data: s.data, error: r.error };\n}\n\n/** Update one draft field while editing; ignored in any other state. */\nexport function setField(s: WizardState, key: keyof Draft, value: string): WizardState {\n if (s.tag !== 'Editing') return s;\n return { ...s, draft: { ...s.draft, [key]: value } };\n}\n\n/**\n * Every event that can happen to the wizard, as one message type. The component\n * sends a WizardMsg; `reduce` decides the next state. This is the Elm\n * Model+Msg+update pattern: ONE pure function describes all state changes.\n */\nexport type WizardMsg =\n | { tag: 'SetField'; key: keyof Draft; value: string }\n | { tag: 'Next' }\n | { tag: 'Back' }\n | { tag: 'GaNaarStap'; step: 1 | 2 | 3 }\n | { tag: 'Submit' }\n | { tag: 'Retry' }\n | { tag: 'SubmitConfirmed' }\n | { tag: 'SubmitFailed'; error: string }\n | { tag: 'Upload'; msg: UploadMsg }\n | { tag: 'Seed'; state: WizardState }; // mount a specific state (stories/showcase)\n\nexport function reduce(s: WizardState, m: WizardMsg): WizardState {\n switch (m.tag) {\n case 'SetField':\n return setField(s, m.key, m.value);\n case 'Next':\n return next(s);\n case 'Back':\n return back(s);\n case 'GaNaarStap':\n return gaNaarStap(s, m.step);\n case 'Submit':\n return submit(s);\n case 'Retry':\n return s.tag === 'Failed' ? { tag: 'Submitting', data: s.data } : s;\n case 'SubmitConfirmed':\n return s.tag === 'Submitting' ? { tag: 'Submitted', data: s.data } : s;\n case 'SubmitFailed':\n return s.tag === 'Submitting' ? { tag: 'Failed', data: s.data, error: m.error } : s;\n case 'Upload':\n return upload(s, m.msg);\n case 'Seed':\n return m.state;\n default:\n return assertNever(m);\n }\n}\n", - "properties": [ - { - "name": "jaren", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "indexKey": "", - "optional": false, - "description": "", - "line": 15 - }, - { - "name": "punten", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "indexKey": "", - "optional": false, - "description": "", - "line": 16 - }, - { - "name": "uren", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "indexKey": "", - "optional": false, - "description": "", - "line": 14 - } - ], - "indexSignatures": [], - "kind": 172, - "description": "

What the user is typing (raw, possibly invalid).

\n", - "rawdescription": "\nWhat the user is typing (raw, possibly invalid).", - "methods": [], - "extends": [], - "isDuplicate": true, "duplicateId": 2, "duplicateName": "Draft-2" }, @@ -5533,54 +5533,7 @@ }, { "name": "Valid", - "id": "interface-Valid-51c29a3fca3c5bd3eba53c9bc57714c79817ae8c86b1ed9c1cd76652d31b45ee7c635d35f7eb0a3a7e5bf9ea7c5da5c066cee3908c8fe4b9fe053586f834b133", - "file": "src/app/registratie/domain/change-request.machine.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "interface", - "sourceCode": "import { Result, assertNever } from '@shared/kernel/fp';\nimport { Postcode, parsePostcode } from '@registratie/domain/value-objects/postcode';\n\n/** What the user is typing (raw, possibly invalid). */\nexport interface Draft {\n straat: string;\n postcode: string;\n woonplaats: string;\n}\n\n/** After parsing — postcode is the branded type, so downstream can't get a raw one. */\nexport interface Valid {\n straat: string;\n postcode: Postcode;\n woonplaats: string;\n}\n\nexport type Errors = Partial>;\n\n/**\n * The change-request (adreswijziging) form as one tagged union — the SAME idiom\n * as the wizards, just single-step. `draft`/`errors` exist only while Editing;\n * Submitting/Submitted/Failed carry the parsed `Valid`. Illegal states (submitting\n * an invalid draft, a success screen with errors) are unrepresentable.\n */\nexport type ChangeRequestState =\n | { tag: 'Editing'; draft: Draft; errors: Errors }\n | { tag: 'Submitting'; data: Valid }\n | { tag: 'Submitted'; data: Valid; referentie: string }\n | { tag: 'Failed'; data: Valid; error: string };\n\nexport const initial: ChangeRequestState = {\n tag: 'Editing',\n draft: { straat: '', postcode: '', woonplaats: '' },\n errors: {},\n};\n\n/** Parse via the value objects; on success hand back a Valid, else per-field errors. */\nfunction validate(draft: Draft): Result {\n const straat = draft.straat.trim();\n const postcode = parsePostcode(draft.postcode);\n const errors: Errors = {};\n if (!straat) errors.straat = $localize`:@@validation.straat:Vul straat en huisnummer in.`;\n if (!postcode.ok) errors.postcode = postcode.error;\n if (straat && postcode.ok) {\n return {\n ok: true,\n value: { straat, postcode: postcode.value, woonplaats: draft.woonplaats.trim() },\n };\n }\n return { ok: false, error: errors };\n}\n\nexport type ChangeRequestMsg =\n | { tag: 'SetField'; key: keyof Draft; value: string }\n | { tag: 'Submit' }\n | { tag: 'Retry' }\n | { tag: 'SubmitConfirmed'; referentie: string }\n | { tag: 'SubmitFailed'; error: string }\n | { tag: 'Reset' }\n | { tag: 'Seed'; state: ChangeRequestState }; // mount a specific state (stories/tests)\n\nexport function reduce(s: ChangeRequestState, m: ChangeRequestMsg): ChangeRequestState {\n switch (m.tag) {\n case 'SetField':\n return s.tag === 'Editing' ? { ...s, draft: { ...s.draft, [m.key]: m.value } } : s;\n case 'Submit': {\n if (s.tag !== 'Editing') return s;\n const r = validate(s.draft);\n return r.ok ? { tag: 'Submitting', data: r.value } : { ...s, errors: r.error };\n }\n case 'Retry':\n return s.tag === 'Failed' ? { tag: 'Submitting', data: s.data } : s;\n case 'SubmitConfirmed':\n return s.tag === 'Submitting'\n ? { tag: 'Submitted', data: s.data, referentie: m.referentie }\n : s;\n case 'SubmitFailed':\n return s.tag === 'Submitting' ? { tag: 'Failed', data: s.data, error: m.error } : s;\n case 'Reset':\n return initial;\n case 'Seed':\n return m.state;\n default:\n return assertNever(m);\n }\n}\n", - "properties": [ - { - "name": "postcode", - "deprecated": false, - "deprecationMessage": "", - "type": "Postcode", - "indexKey": "", - "optional": false, - "description": "", - "line": 14 - }, - { - "name": "straat", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "indexKey": "", - "optional": false, - "description": "", - "line": 13 - }, - { - "name": "woonplaats", - "deprecated": false, - "deprecationMessage": "", - "type": "string", - "indexKey": "", - "optional": false, - "description": "", - "line": 15 - } - ], - "indexSignatures": [], - "kind": 172, - "description": "

After parsing — postcode is the branded type, so downstream can't get a raw one.

\n", - "rawdescription": "\nAfter parsing — postcode is the branded type, so downstream can't get a raw one.", - "methods": [], - "extends": [] - }, - { - "name": "Valid", - "id": "interface-Valid-3f75a0ff51d12ccab50bfa13789cace778d5acff9f4feaa1607cdf1acb4a5ab4fcc687512424cb2252ec07568f6aea07a0b4f04469cbeed733c28654443ffd9e-1", + "id": "interface-Valid-3f75a0ff51d12ccab50bfa13789cace778d5acff9f4feaa1607cdf1acb4a5ab4fcc687512424cb2252ec07568f6aea07a0b4f04469cbeed733c28654443ffd9e", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", "deprecated": false, "deprecationMessage": "", @@ -5633,6 +5586,53 @@ "description": "

What we have AFTER parsing — branded/typed, guaranteed valid.

\n", "rawdescription": "\nWhat we have AFTER parsing — branded/typed, guaranteed valid.", "methods": [], + "extends": [] + }, + { + "name": "Valid", + "id": "interface-Valid-51c29a3fca3c5bd3eba53c9bc57714c79817ae8c86b1ed9c1cd76652d31b45ee7c635d35f7eb0a3a7e5bf9ea7c5da5c066cee3908c8fe4b9fe053586f834b133-1", + "file": "src/app/registratie/domain/change-request.machine.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "interface", + "sourceCode": "import { Result, assertNever } from '@shared/kernel/fp';\nimport { Postcode, parsePostcode } from '@registratie/domain/value-objects/postcode';\n\n/** What the user is typing (raw, possibly invalid). */\nexport interface Draft {\n straat: string;\n postcode: string;\n woonplaats: string;\n}\n\n/** After parsing — postcode is the branded type, so downstream can't get a raw one. */\nexport interface Valid {\n straat: string;\n postcode: Postcode;\n woonplaats: string;\n}\n\nexport type Errors = Partial>;\n\n/**\n * The change-request (adreswijziging) form as one tagged union — the SAME idiom\n * as the wizards, just single-step. `draft`/`errors` exist only while Editing;\n * Submitting/Submitted/Failed carry the parsed `Valid`. Illegal states (submitting\n * an invalid draft, a success screen with errors) are unrepresentable.\n */\nexport type ChangeRequestState =\n | { tag: 'Editing'; draft: Draft; errors: Errors }\n | { tag: 'Submitting'; data: Valid }\n | { tag: 'Submitted'; data: Valid; referentie: string }\n | { tag: 'Failed'; data: Valid; error: string };\n\nexport const initial: ChangeRequestState = {\n tag: 'Editing',\n draft: { straat: '', postcode: '', woonplaats: '' },\n errors: {},\n};\n\n/** Parse via the value objects; on success hand back a Valid, else per-field errors. */\nfunction validate(draft: Draft): Result {\n const straat = draft.straat.trim();\n const postcode = parsePostcode(draft.postcode);\n const errors: Errors = {};\n if (!straat) errors.straat = $localize`:@@validation.straat:Vul straat en huisnummer in.`;\n if (!postcode.ok) errors.postcode = postcode.error;\n if (straat && postcode.ok) {\n return {\n ok: true,\n value: { straat, postcode: postcode.value, woonplaats: draft.woonplaats.trim() },\n };\n }\n return { ok: false, error: errors };\n}\n\nexport type ChangeRequestMsg =\n | { tag: 'SetField'; key: keyof Draft; value: string }\n | { tag: 'Submit' }\n | { tag: 'Retry' }\n | { tag: 'SubmitConfirmed'; referentie: string }\n | { tag: 'SubmitFailed'; error: string }\n | { tag: 'Reset' }\n | { tag: 'Seed'; state: ChangeRequestState }; // mount a specific state (stories/tests)\n\nexport function reduce(s: ChangeRequestState, m: ChangeRequestMsg): ChangeRequestState {\n switch (m.tag) {\n case 'SetField':\n return s.tag === 'Editing' ? { ...s, draft: { ...s.draft, [m.key]: m.value } } : s;\n case 'Submit': {\n if (s.tag !== 'Editing') return s;\n const r = validate(s.draft);\n return r.ok ? { tag: 'Submitting', data: r.value } : { ...s, errors: r.error };\n }\n case 'Retry':\n return s.tag === 'Failed' ? { tag: 'Submitting', data: s.data } : s;\n case 'SubmitConfirmed':\n return s.tag === 'Submitting'\n ? { tag: 'Submitted', data: s.data, referentie: m.referentie }\n : s;\n case 'SubmitFailed':\n return s.tag === 'Submitting' ? { tag: 'Failed', data: s.data, error: m.error } : s;\n case 'Reset':\n return initial;\n case 'Seed':\n return m.state;\n default:\n return assertNever(m);\n }\n}\n", + "properties": [ + { + "name": "postcode", + "deprecated": false, + "deprecationMessage": "", + "type": "Postcode", + "indexKey": "", + "optional": false, + "description": "", + "line": 14 + }, + { + "name": "straat", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "indexKey": "", + "optional": false, + "description": "", + "line": 13 + }, + { + "name": "woonplaats", + "deprecated": false, + "deprecationMessage": "", + "type": "string", + "indexKey": "", + "optional": false, + "description": "", + "line": 15 + } + ], + "indexSignatures": [], + "kind": 172, + "description": "

After parsing — postcode is the branded type, so downstream can't get a raw one.

\n", + "rawdescription": "\nAfter parsing — postcode is the branded type, so downstream can't get a raw one.", + "methods": [], "extends": [], "isDuplicate": true, "duplicateId": 1, @@ -22952,11 +22952,21 @@ "name": "initial", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/app/brief/domain/brief.machine.ts", + "file": "src/app/herregistratie/domain/herregistratie.machine.ts", "deprecated": false, "deprecationMessage": "", - "type": "BriefState", - "defaultValue": "{ tag: 'loading' }" + "type": "WizardState", + "defaultValue": "{\n tag: 'Editing',\n step: 1,\n draft: { uren: '', jaren: '', punten: '' },\n errors: {},\n upload: initialUpload,\n}" + }, + { + "name": "initial", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/app/herregistratie/domain/intake.machine.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "IntakeState", + "defaultValue": "{\n tag: 'Answering',\n answers: {},\n cursor: 0,\n errors: {},\n scholingThreshold: SCHOLING_THRESHOLD_DEFAULT,\n}" }, { "name": "initial", @@ -22982,21 +22992,11 @@ "name": "initial", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/app/herregistratie/domain/herregistratie.machine.ts", + "file": "src/app/brief/domain/brief.machine.ts", "deprecated": false, "deprecationMessage": "", - "type": "WizardState", - "defaultValue": "{\n tag: 'Editing',\n step: 1,\n draft: { uren: '', jaren: '', punten: '' },\n errors: {},\n upload: initialUpload,\n}" - }, - { - "name": "initial", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/herregistratie/domain/intake.machine.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "IntakeState", - "defaultValue": "{\n tag: 'Answering',\n answers: {},\n cursor: 0,\n errors: {},\n scholingThreshold: SCHOLING_THRESHOLD_DEFAULT,\n}" + "type": "BriefState", + "defaultValue": "{ tag: 'loading' }" }, { "name": "initialUpload", @@ -23278,11 +23278,11 @@ "name": "STEPS", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "file": "src/app/herregistratie/domain/intake.machine.ts", "deprecated": false, "deprecationMessage": "", "type": "StepId[]", - "defaultValue": "['adres', 'beroep', 'controle']", + "defaultValue": "['buitenland', 'werk', 'review']", "rawdescription": "The fixed step list. Number of steps never changes; questions reveal inline.", "description": "

The fixed step list. Number of steps never changes; questions reveal inline.

\n" }, @@ -23290,11 +23290,11 @@ "name": "STEPS", "ctype": "miscellaneous", "subtype": "variable", - "file": "src/app/herregistratie/domain/intake.machine.ts", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", "deprecated": false, "deprecationMessage": "", "type": "StepId[]", - "defaultValue": "['buitenland', 'werk', 'review']", + "defaultValue": "['adres', 'beroep', 'controle']", "rawdescription": "The fixed step list. Number of steps never changes; questions reveal inline.", "description": "

The fixed step list. Number of steps never changes; questions reveal inline.

\n" }, @@ -23606,35 +23606,6 @@ } ] }, - { - "name": "back", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "back", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", @@ -23693,6 +23664,35 @@ } ] }, + { + "name": "back", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "blockActions", "file": "src/app/registratie/domain/block-actions.ts", @@ -24172,7 +24172,7 @@ }, { "name": "currentStep", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "file": "src/app/herregistratie/domain/intake.machine.ts", "ctype": "miscellaneous", "subtype": "function", "deprecated": false, @@ -24201,7 +24201,7 @@ }, { "name": "currentStep", - "file": "src/app/herregistratie/domain/intake.machine.ts", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", "ctype": "miscellaneous", "subtype": "function", "deprecated": false, @@ -24753,50 +24753,6 @@ } ] }, - { - "name": "gaNaarStap", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Jump back to an earlier step to correct data (controle → step N). Forward\njumps are not allowed (would skip validation). Preserves the draft.

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cursor", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cursor", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "gaNaarStap", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", @@ -24883,6 +24839,50 @@ } ] }, + { + "name": "gaNaarStap", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Jump back to an earlier step to correct data (controle → step N). Forward\njumps are not allowed (would skip validation). Preserves the draft.

\n", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "cursor", + "type": "number", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "cursor", + "type": "number", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "groupParagraphs", "file": "src/app/brief/ui/letter-preview/letter-preview.component.ts", @@ -24937,35 +24937,6 @@ } ] }, - { - "name": "hasProgress", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Has the user meaningfully started, so it's worth persisting as a Concept? Excludes\nthe automatic BRP address prefill on step 0 — a bare page visit creates nothing.\nponytail: an address typed at step 0 without any of these signals is not yet\npersisted (created once they advance/choose); accepted regression vs. sessionStorage.

\n", - "args": [ - { - "name": "s", - "type": "Extract", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "boolean", - "jsdoctags": [ - { - "name": "s", - "type": "Extract", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "hasProgress", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", @@ -25024,6 +24995,35 @@ } ] }, + { + "name": "hasProgress", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Has the user meaningfully started, so it's worth persisting as a Concept? Excludes\nthe automatic BRP address prefill on step 0 — a bare page visit creates nothing.\nponytail: an address typed at step 0 without any of these signals is not yet\npersisted (created once they advance/choose); accepted regression vs. sessionStorage.

\n", + "args": [ + { + "name": "s", + "type": "Extract", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "boolean", + "jsdoctags": [ + { + "name": "s", + "type": "Extract", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "herregistratieDeadline", "file": "src/app/registratie/domain/registration.policy.ts", @@ -26086,35 +26086,6 @@ } ] }, - { - "name": "next", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "next", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", @@ -26173,6 +26144,35 @@ } ] }, + { + "name": "next", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "nextLocalIndex", "file": "src/app/brief/domain/brief.machine.ts", @@ -27260,7 +27260,7 @@ }, { "name": "reduce", - "file": "src/app/brief/domain/brief.machine.ts", + "file": "src/app/herregistratie/domain/herregistratie.machine.ts", "ctype": "miscellaneous", "subtype": "function", "deprecated": false, @@ -27269,22 +27269,22 @@ "args": [ { "name": "s", - "type": "BriefState", + "type": "WizardState", "deprecated": false, "deprecationMessage": "" }, { "name": "m", - "type": "BriefMsg", + "type": "WizardMsg", "deprecated": false, "deprecationMessage": "" } ], - "returnType": "BriefState", + "returnType": "WizardState", "jsdoctags": [ { "name": "s", - "type": "BriefState", + "type": "WizardState", "deprecated": false, "deprecationMessage": "", "tagName": { @@ -27293,7 +27293,51 @@ }, { "name": "m", - "type": "BriefMsg", + "type": "WizardMsg", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "reduce", + "file": "src/app/herregistratie/domain/intake.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "IntakeState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "m", + "type": "IntakeMsg", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "IntakeState", + "jsdoctags": [ + { + "name": "s", + "type": "IntakeState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "m", + "type": "IntakeMsg", "deprecated": false, "deprecationMessage": "", "tagName": { @@ -27392,7 +27436,7 @@ }, { "name": "reduce", - "file": "src/app/herregistratie/domain/herregistratie.machine.ts", + "file": "src/app/brief/domain/brief.machine.ts", "ctype": "miscellaneous", "subtype": "function", "deprecated": false, @@ -27401,22 +27445,22 @@ "args": [ { "name": "s", - "type": "WizardState", + "type": "BriefState", "deprecated": false, "deprecationMessage": "" }, { "name": "m", - "type": "WizardMsg", + "type": "BriefMsg", "deprecated": false, "deprecationMessage": "" } ], - "returnType": "WizardState", + "returnType": "BriefState", "jsdoctags": [ { "name": "s", - "type": "WizardState", + "type": "BriefState", "deprecated": false, "deprecationMessage": "", "tagName": { @@ -27425,51 +27469,7 @@ }, { "name": "m", - "type": "WizardMsg", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "reduce", - "file": "src/app/herregistratie/domain/intake.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "IntakeState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "m", - "type": "IntakeMsg", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "IntakeState", - "jsdoctags": [ - { - "name": "s", - "type": "IntakeState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "m", - "type": "IntakeMsg", + "type": "BriefMsg", "deprecated": false, "deprecationMessage": "", "tagName": { @@ -27766,50 +27766,6 @@ } ] }, - { - "name": "resolve", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "r", - "type": "Result", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "r", - "type": "Result", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "resolve", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", @@ -27898,6 +27854,50 @@ } ] }, + { + "name": "resolve", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "r", + "type": "Result", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "r", + "type": "Result", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "restore", "file": "src/app/auth/application/session.store.ts", @@ -28184,6 +28184,63 @@ } ] }, + { + "name": "setField", + "file": "src/app/herregistratie/domain/herregistratie.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Update one draft field while editing; ignored in any other state.

\n", + "args": [ + { + "name": "s", + "type": "WizardState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "key", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "value", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "WizardState", + "jsdoctags": [ + { + "name": "s", + "type": "WizardState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "key", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "value", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "setField", "file": "src/app/registratie/domain/registratie-wizard.machine.ts", @@ -28243,63 +28300,6 @@ } ] }, - { - "name": "setField", - "file": "src/app/herregistratie/domain/herregistratie.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Update one draft field while editing; ignored in any other state.

\n", - "args": [ - { - "name": "s", - "type": "WizardState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "key", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "WizardState", - "jsdoctags": [ - { - "name": "s", - "type": "WizardState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "key", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "setPolicy", "file": "src/app/herregistratie/domain/intake.machine.ts", @@ -28500,35 +28500,6 @@ } ] }, - { - "name": "submit", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "submit", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", @@ -28587,6 +28558,35 @@ } ] }, + { + "name": "submit", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "submittedRow", "file": "src/app/registratie/domain/aanvraag-view.ts", @@ -28950,50 +28950,6 @@ } ] }, - { - "name": "upload", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Route an upload sub-message through the pure upload reducer (Invullen only).

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "msg", - "type": "UploadMsg", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "msg", - "type": "UploadMsg", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, { "name": "upload", "file": "src/app/herregistratie/domain/herregistratie.machine.ts", @@ -29039,26 +28995,41 @@ ] }, { - "name": "validate", - "file": "src/app/registratie/domain/change-request.machine.ts", + "name": "upload", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", "ctype": "miscellaneous", "subtype": "function", "deprecated": false, "deprecationMessage": "", - "description": "

Parse via the value objects; on success hand back a Valid, else per-field errors.

\n", + "description": "

Route an upload sub-message through the pure upload reducer (Invullen only).

\n", "args": [ { - "name": "draft", - "type": "Draft", + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "msg", + "type": "UploadMsg", "deprecated": false, "deprecationMessage": "" } ], - "returnType": "Result", + "returnType": "RegistratieState", "jsdoctags": [ { - "name": "draft", - "type": "Draft", + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "msg", + "type": "UploadMsg", "deprecated": false, "deprecationMessage": "", "tagName": { @@ -29112,46 +29083,31 @@ ] }, { - "name": "validateAll", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "name": "validate", + "file": "src/app/registratie/domain/change-request.machine.ts", "ctype": "miscellaneous", "subtype": "function", "deprecated": false, "deprecationMessage": "", - "description": "

Parse the whole wizard into a ValidRegistratie (called on submit).

\n", + "description": "

Parse via the value objects; on success hand back a Valid, else per-field errors.

\n", "args": [ { - "name": "d", + "name": "draft", "type": "Draft", "deprecated": false, "deprecationMessage": "" - }, - { - "name": "upload", - "type": "UploadState", - "deprecated": false, - "deprecationMessage": "" } ], - "returnType": "Result", + "returnType": "Result", "jsdoctags": [ { - "name": "d", + "name": "draft", "type": "Draft", "deprecated": false, "deprecationMessage": "", "tagName": { "text": "param" } - }, - { - "name": "upload", - "type": "UploadState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } } ] }, @@ -29200,20 +29156,14 @@ ] }, { - "name": "validateStep", + "name": "validateAll", "file": "src/app/registratie/domain/registratie-wizard.machine.ts", "ctype": "miscellaneous", "subtype": "function", "deprecated": false, "deprecationMessage": "", - "description": "

Validate every question currently visible in ONE step. Errors keyed per field.

\n", + "description": "

Parse the whole wizard into a ValidRegistratie (called on submit).

\n", "args": [ - { - "name": "step", - "type": "StepId", - "deprecated": false, - "deprecationMessage": "" - }, { "name": "d", "type": "Draft", @@ -29227,17 +29177,8 @@ "deprecationMessage": "" } ], - "returnType": "Result", + "returnType": "Result", "jsdoctags": [ - { - "name": "step", - "type": "StepId", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, { "name": "d", "type": "Draft", @@ -29317,6 +29258,65 @@ } ] }, + { + "name": "validateStep", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Validate every question currently visible in ONE step. Errors keyed per field.

\n", + "args": [ + { + "name": "step", + "type": "StepId", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "d", + "type": "Draft", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "upload", + "type": "UploadState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "Result", + "jsdoctags": [ + { + "name": "step", + "type": "StepId", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "d", + "type": "Draft", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "upload", + "type": "UploadState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, { "name": "whenTag", "file": "src/app/shared/kernel/fp.ts", @@ -29717,22 +29717,22 @@ "name": "Errors", "ctype": "miscellaneous", "subtype": "typealias", - "rawtype": "Partial>", - "file": "src/app/registratie/domain/change-request.machine.ts", + "rawtype": "Partial>", + "file": "src/app/herregistratie/domain/intake.machine.ts", "deprecated": false, "deprecationMessage": "", - "description": "", + "description": "

Per-field error map: one message per question, since a step holds several.

\n", "kind": 184 }, { "name": "Errors", "ctype": "miscellaneous", "subtype": "typealias", - "rawtype": "Partial>", - "file": "src/app/herregistratie/domain/intake.machine.ts", + "rawtype": "Partial>", + "file": "src/app/registratie/domain/change-request.machine.ts", "deprecated": false, "deprecationMessage": "", - "description": "

Per-field error map: one message per question, since a step holds several.

\n", + "description": "", "kind": 184 }, { @@ -29970,22 +29970,22 @@ "name": "StepId", "ctype": "miscellaneous", "subtype": "typealias", - "rawtype": "\"adres\" | \"beroep\" | \"controle\"", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "rawtype": "\"buitenland\" | \"werk\" | \"review\"", + "file": "src/app/herregistratie/domain/intake.machine.ts", "deprecated": false, "deprecationMessage": "", - "description": "

A FIXED 3-step registration wizard. The steps never change in number (always\nSTEPS): (1) adres + correspondentievoorkeur, (2) beroep o.b.v. diploma,\n(3) controle & indienen. Follow-up questions appear inline within a step\n(e.g. choosing 'email' reveals the e-mail field). "Is this field required\nright now" is a pure function (validateStep), so it is trivial to test and\nimpossible to get out of sync with the data. Invariants live here, not in the\nUI: the wizard reaches Indienen only when a complete ValidRegistratie parses.

\n", + "description": "

The three fixed steps. Each step groups one or more questions.

\n", "kind": 193 }, { "name": "StepId", "ctype": "miscellaneous", "subtype": "typealias", - "rawtype": "\"buitenland\" | \"werk\" | \"review\"", - "file": "src/app/herregistratie/domain/intake.machine.ts", + "rawtype": "\"adres\" | \"beroep\" | \"controle\"", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", "deprecated": false, "deprecationMessage": "", - "description": "

The three fixed steps. Each step groups one or more questions.

\n", + "description": "

A FIXED 3-step registration wizard. The steps never change in number (always\nSTEPS): (1) adres + correspondentievoorkeur, (2) beroep o.b.v. diploma,\n(3) controle & indienen. Follow-up questions appear inline within a step\n(e.g. choosing 'email' reveals the e-mail field). "Is this field required\nright now" is a pure function (validateStep), so it is trivial to test and\nimpossible to get out of sync with the data. Invariants live here, not in the\nUI: the wizard reaches Indienen only when a complete ValidRegistratie parses.

\n", "kind": 193 }, { @@ -30414,30 +30414,6 @@ "defaultValue": "{\n info: $localize`:@@alert.icon.info:Informatie`,\n ok: $localize`:@@alert.icon.ok:Gelukt`,\n warning: $localize`:@@alert.icon.warning:Waarschuwing`,\n error: $localize`:@@alert.icon.error:Foutmelding`,\n}" } ], - "src/app/brief/domain/brief.machine.ts": [ - { - "name": "initial", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/brief/domain/brief.machine.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "BriefState", - "defaultValue": "{ tag: 'loading' }" - } - ], - "src/app/registratie/domain/change-request.machine.ts": [ - { - "name": "initial", - "ctype": "miscellaneous", - "subtype": "variable", - "file": "src/app/registratie/domain/change-request.machine.ts", - "deprecated": false, - "deprecationMessage": "", - "type": "ChangeRequestState", - "defaultValue": "{\n tag: 'Editing',\n draft: { straat: '', postcode: '', woonplaats: '' },\n errors: {},\n}" - } - ], "src/app/herregistratie/domain/herregistratie.machine.ts": [ { "name": "initial", @@ -30486,6 +30462,30 @@ "description": "

The fixed step list. Number of steps never changes; questions reveal inline.

\n" } ], + "src/app/registratie/domain/change-request.machine.ts": [ + { + "name": "initial", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/app/registratie/domain/change-request.machine.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "ChangeRequestState", + "defaultValue": "{\n tag: 'Editing',\n draft: { straat: '', postcode: '', woonplaats: '' },\n errors: {},\n}" + } + ], + "src/app/brief/domain/brief.machine.ts": [ + { + "name": "initial", + "ctype": "miscellaneous", + "subtype": "variable", + "file": "src/app/brief/domain/brief.machine.ts", + "deprecated": false, + "deprecationMessage": "", + "type": "BriefState", + "defaultValue": "{ tag: 'loading' }" + } + ], "src/app/shared/ui/radio-group/radio-group.component.ts": [ { "name": "JA_NEE", @@ -32420,826 +32420,6 @@ ] } ], - "src/app/registratie/domain/registratie-wizard.machine.ts": [ - { - "name": "back", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "currentStep", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Which step the cursor currently points at (clamped to the fixed list).

\n", - "args": [ - { - "name": "s", - "type": "Extract", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "StepId", - "jsdoctags": [ - { - "name": "s", - "type": "Extract", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "declareerBeroep", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Declare the beroep for a manually-entered diploma (chosen from a fixed list).

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "beroep", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "beroep", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "gaNaarStap", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Jump back to an earlier step to correct data (controle → step N). Forward\njumps are not allowed (would skip validation). Preserves the draft.

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "cursor", - "type": "number", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "cursor", - "type": "number", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "hasProgress", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Has the user meaningfully started, so it's worth persisting as a Concept? Excludes\nthe automatic BRP address prefill on step 0 — a bare page visit creates nothing.\nponytail: an address typed at step 0 without any of these signals is not yet\npersisted (created once they advance/choose); accepted regression vs. sessionStorage.

\n", - "args": [ - { - "name": "s", - "type": "Extract", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "boolean", - "jsdoctags": [ - { - "name": "s", - "type": "Extract", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "kiesDiploma", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Pick a DUO diploma; the beroep is derived from it and the applicable policy\nquestions (vraagIds) come with it (both server-computed, passed in).

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "diplomaId", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "beroep", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "vraagIds", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "diplomaId", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "beroep", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "vraagIds", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "kiesHandmatig", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Switch to manual diploma entry: the diploma isn't in DUO, so the MAXIMAL\npolicy-question set applies and the entry is flagged handmatig/unverified. The\nberoep is declared separately (declareerBeroep).

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "vraagIds", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "vraagIds", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "next", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "prefillAdres", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Prefill the address from a BRP lookup and flag its origin (PRD §7).

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "straat", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "postcode", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "woonplaats", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "straat", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "postcode", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "woonplaats", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "reduce", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "m", - "type": "RegistratieMsg", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "m", - "type": "RegistratieMsg", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "resolve", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "r", - "type": "Result", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "r", - "type": "Result", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setAntwoord", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "vraagId", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "vraagId", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setCorrespondentie", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "Correspondentie", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "Correspondentie", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "setField", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "key", - "type": "DraftField", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "key", - "type": "DraftField", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "value", - "type": "string", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "submit", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "upload", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Route an upload sub-message through the pure upload reducer (Invullen only).

\n", - "args": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "msg", - "type": "UploadMsg", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "RegistratieState", - "jsdoctags": [ - { - "name": "s", - "type": "RegistratieState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "msg", - "type": "UploadMsg", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "validateAll", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Parse the whole wizard into a ValidRegistratie (called on submit).

\n", - "args": [ - { - "name": "d", - "type": "Draft", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "upload", - "type": "UploadState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Result", - "jsdoctags": [ - { - "name": "d", - "type": "Draft", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "upload", - "type": "UploadState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - }, - { - "name": "validateStep", - "file": "src/app/registratie/domain/registratie-wizard.machine.ts", - "ctype": "miscellaneous", - "subtype": "function", - "deprecated": false, - "deprecationMessage": "", - "description": "

Validate every question currently visible in ONE step. Errors keyed per field.

\n", - "args": [ - { - "name": "step", - "type": "StepId", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "d", - "type": "Draft", - "deprecated": false, - "deprecationMessage": "" - }, - { - "name": "upload", - "type": "UploadState", - "deprecated": false, - "deprecationMessage": "" - } - ], - "returnType": "Result", - "jsdoctags": [ - { - "name": "step", - "type": "StepId", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "d", - "type": "Draft", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - }, - { - "name": "upload", - "type": "UploadState", - "deprecated": false, - "deprecationMessage": "", - "tagName": { - "text": "param" - } - } - ] - } - ], "src/app/herregistratie/domain/herregistratie.machine.ts": [ { "name": "back", @@ -34162,6 +33342,826 @@ ] } ], + "src/app/registratie/domain/registratie-wizard.machine.ts": [ + { + "name": "back", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "currentStep", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Which step the cursor currently points at (clamped to the fixed list).

\n", + "args": [ + { + "name": "s", + "type": "Extract", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "StepId", + "jsdoctags": [ + { + "name": "s", + "type": "Extract", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "declareerBeroep", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Declare the beroep for a manually-entered diploma (chosen from a fixed list).

\n", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "beroep", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "beroep", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "gaNaarStap", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Jump back to an earlier step to correct data (controle → step N). Forward\njumps are not allowed (would skip validation). Preserves the draft.

\n", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "cursor", + "type": "number", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "cursor", + "type": "number", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "hasProgress", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Has the user meaningfully started, so it's worth persisting as a Concept? Excludes\nthe automatic BRP address prefill on step 0 — a bare page visit creates nothing.\nponytail: an address typed at step 0 without any of these signals is not yet\npersisted (created once they advance/choose); accepted regression vs. sessionStorage.

\n", + "args": [ + { + "name": "s", + "type": "Extract", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "boolean", + "jsdoctags": [ + { + "name": "s", + "type": "Extract", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "kiesDiploma", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Pick a DUO diploma; the beroep is derived from it and the applicable policy\nquestions (vraagIds) come with it (both server-computed, passed in).

\n", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "diplomaId", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "beroep", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "vraagIds", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "diplomaId", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "beroep", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "vraagIds", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "kiesHandmatig", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Switch to manual diploma entry: the diploma isn't in DUO, so the MAXIMAL\npolicy-question set applies and the entry is flagged handmatig/unverified. The\nberoep is declared separately (declareerBeroep).

\n", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "vraagIds", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "vraagIds", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "next", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "prefillAdres", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Prefill the address from a BRP lookup and flag its origin (PRD §7).

\n", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "straat", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "postcode", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "woonplaats", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "straat", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "postcode", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "woonplaats", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "reduce", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "m", + "type": "RegistratieMsg", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "m", + "type": "RegistratieMsg", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "resolve", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "r", + "type": "Result", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "r", + "type": "Result", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "setAntwoord", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "vraagId", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "value", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "vraagId", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "value", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "setCorrespondentie", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "value", + "type": "Correspondentie", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "value", + "type": "Correspondentie", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "setField", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "key", + "type": "DraftField", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "value", + "type": "string", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "key", + "type": "DraftField", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "value", + "type": "string", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "submit", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "upload", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Route an upload sub-message through the pure upload reducer (Invullen only).

\n", + "args": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "msg", + "type": "UploadMsg", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "RegistratieState", + "jsdoctags": [ + { + "name": "s", + "type": "RegistratieState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "msg", + "type": "UploadMsg", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "validateAll", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Parse the whole wizard into a ValidRegistratie (called on submit).

\n", + "args": [ + { + "name": "d", + "type": "Draft", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "upload", + "type": "UploadState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "Result", + "jsdoctags": [ + { + "name": "d", + "type": "Draft", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "upload", + "type": "UploadState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + }, + { + "name": "validateStep", + "file": "src/app/registratie/domain/registratie-wizard.machine.ts", + "ctype": "miscellaneous", + "subtype": "function", + "deprecated": false, + "deprecationMessage": "", + "description": "

Validate every question currently visible in ONE step. Errors keyed per field.

\n", + "args": [ + { + "name": "step", + "type": "StepId", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "d", + "type": "Draft", + "deprecated": false, + "deprecationMessage": "" + }, + { + "name": "upload", + "type": "UploadState", + "deprecated": false, + "deprecationMessage": "" + } + ], + "returnType": "Result", + "jsdoctags": [ + { + "name": "step", + "type": "StepId", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "d", + "type": "Draft", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + }, + { + "name": "upload", + "type": "UploadState", + "deprecated": false, + "deprecationMessage": "", + "tagName": { + "text": "param" + } + } + ] + } + ], "src/app/registratie/domain/block-actions.ts": [ { "name": "blockActions", diff --git a/src/app/brief/ui/diagnostics-panel/diagnostics-panel.stories.ts b/src/app/brief/ui/diagnostics-panel/diagnostics-panel.stories.ts new file mode 100644 index 0000000..9db4965 --- /dev/null +++ b/src/app/brief/ui/diagnostics-panel/diagnostics-panel.stories.ts @@ -0,0 +1,33 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { Diagnostic } from '@brief/domain/placeholders'; +import { DiagnosticsPanelComponent } from './diagnostics-panel.component'; + +const location = { blockId: 'local-2', paragraphIndex: 0, nodeIndex: 1 }; + +const errorAndWarning: Diagnostic[] = [ + { + severity: 'error', + code: 'unknown-placeholder', + placeholderKey: 'onbekend_veld', + location, + message: 'Onbekend veld "onbekend_veld" — controleer de spelling.', + }, + { + severity: 'warning', + code: 'unresolved-at-send', + placeholderKey: 'reden_besluit', + location, + message: '"Reden besluit" is nog niet ingevuld.', + }, +]; + +const meta: Meta = { + title: 'Domein/Brief/Diagnostics Panel', + component: DiagnosticsPanelComponent, + args: { locate: () => {} }, +}; +export default meta; +type Story = StoryObj; + +export const Findings: Story = { args: { diagnostics: errorAndWarning } }; +export const Clean: Story = { args: { diagnostics: [] } }; diff --git a/src/app/brief/ui/letter-block/letter-block.stories.ts b/src/app/brief/ui/letter-block/letter-block.stories.ts new file mode 100644 index 0000000..efcc1cc --- /dev/null +++ b/src/app/brief/ui/letter-block/letter-block.stories.ts @@ -0,0 +1,47 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { LetterBlock } from '@brief/domain/brief'; +import { LetterBlockComponent } from './letter-block.component'; + +const passageBlock: LetterBlock = { + type: 'passage', + blockId: 'local-1', + sourcePassageId: 'p1', + sourceVersion: 1, + edited: false, + content: { paragraphs: [{ nodes: [{ type: 'text', text: 'Geachte heer/mevrouw,' }] }] }, +}; + +const freeTextBlock: LetterBlock = { + type: 'freeText', + blockId: 'local-2', + content: { + paragraphs: [ + { + nodes: [ + { type: 'text', text: 'Wij hebben besloten om reden ' }, + { type: 'placeholder', key: 'reden_besluit' }, + { type: 'text', text: '.' }, + ], + }, + ], + }, +}; + +const placeholders = [{ key: 'reden_besluit', label: 'Reden besluit' }]; + +const meta: Meta = { + title: 'Domein/Brief/Letter Block', + component: LetterBlockComponent, + args: { + block: passageBlock, + placeholders, + contentChanged: () => {}, + removed: () => {}, + moved: () => {}, + }, +}; +export default meta; +type Story = StoryObj; + +export const ReadOnlyPassage: Story = { args: { editable: false } }; +export const EditableFreeText: Story = { args: { block: freeTextBlock, editable: true } }; diff --git a/src/app/brief/ui/letter-preview/letter-preview.stories.ts b/src/app/brief/ui/letter-preview/letter-preview.stories.ts new file mode 100644 index 0000000..f3678fe --- /dev/null +++ b/src/app/brief/ui/letter-preview/letter-preview.stories.ts @@ -0,0 +1,88 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { Brief } from '@brief/domain/brief'; +import { Diagnostic } from '@brief/domain/placeholders'; +import { LetterPreviewComponent } from './letter-preview.component'; + +const brief: Brief = { + briefId: 'b1', + beroep: 'arts', + templateId: 't1', + drafterId: 'demo-drafter', + status: { tag: 'draft' }, + placeholders: [ + { key: 'naam_zorgverlener', label: 'Naam zorgverlener', autoResolvable: true }, + { key: 'reden_besluit', label: 'Reden besluit', autoResolvable: false }, + ], + sections: [ + { + sectionKey: 'aanhef', + title: 'Aanhef', + required: true, + locked: true, + blocks: [ + { + type: 'passage', + blockId: 'local-1', + sourcePassageId: 'p1', + sourceVersion: 1, + edited: false, + content: { + paragraphs: [ + { + nodes: [ + { type: 'text', text: 'Geachte heer/mevrouw ' }, + { type: 'placeholder', key: 'naam_zorgverlener' }, + { type: 'text', text: ',' }, + ], + }, + ], + }, + }, + ], + }, + { + sectionKey: 'kern', + title: 'Kern van het besluit', + required: true, + locked: false, + blocks: [ + { + type: 'freeText', + blockId: 'local-2', + content: { + paragraphs: [ + { + nodes: [ + { type: 'text', text: 'Wij hebben besloten om reden ' }, + { type: 'placeholder', key: 'reden_besluit' }, + { type: 'text', text: '.' }, + ], + }, + ], + }, + }, + ], + }, + ], +}; + +const diagnostics: Diagnostic[] = [ + { + severity: 'warning', + code: 'unresolved-at-send', + placeholderKey: 'reden_besluit', + location: { blockId: 'local-2', paragraphIndex: 0, nodeIndex: 1 }, + message: '"Reden besluit" is nog niet ingevuld.', + }, +]; + +const meta: Meta = { + title: 'Domein/Brief/Letter Preview', + component: LetterPreviewComponent, + args: { brief, diagnostics }, +}; +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; +export const ZonderBevindingen: Story = { args: { diagnostics: [] } }; diff --git a/src/app/brief/ui/letter-section/letter-section.stories.ts b/src/app/brief/ui/letter-section/letter-section.stories.ts new file mode 100644 index 0000000..da9c5cb --- /dev/null +++ b/src/app/brief/ui/letter-section/letter-section.stories.ts @@ -0,0 +1,55 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { LetterSection, LibraryPassage } from '@brief/domain/brief'; +import { LetterSectionComponent } from './letter-section.component'; + +const section: LetterSection = { + sectionKey: 'kern', + title: 'Kern van het besluit', + required: true, + locked: false, + blocks: [ + { + type: 'freeText', + blockId: 'local-2', + content: { + paragraphs: [ + { + nodes: [ + { type: 'text', text: 'Wij hebben besloten om reden ' }, + { type: 'placeholder', key: 'reden_besluit' }, + { type: 'text', text: '.' }, + ], + }, + ], + }, + }, + ], +}; + +const emptySection: LetterSection = { ...section, blocks: [] }; + +const passages: LibraryPassage[] = [ + { + passageId: 'p2', + scope: 'beroep', + beroep: 'arts', + sectionKey: 'kern', + label: 'Toelichting arts', + version: 1, + content: { paragraphs: [{ nodes: [{ type: 'text', text: 'Als arts ...' }] }] }, + }, +]; + +const placeholders = [{ key: 'reden_besluit', label: 'Reden besluit' }]; + +const meta: Meta = { + title: 'Domein/Brief/Letter Section', + component: LetterSectionComponent, + args: { section, availablePassages: passages, placeholders, edit: () => {} }, +}; +export default meta; +type Story = StoryObj; + +export const ReadOnly: Story = { args: { editable: false } }; +export const Editable: Story = { args: { editable: true } }; +export const EditableEmpty: Story = { args: { section: emptySection, editable: true } }; diff --git a/src/app/brief/ui/passage-picker/passage-picker.stories.ts b/src/app/brief/ui/passage-picker/passage-picker.stories.ts new file mode 100644 index 0000000..9c43f78 --- /dev/null +++ b/src/app/brief/ui/passage-picker/passage-picker.stories.ts @@ -0,0 +1,37 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { LibraryPassage } from '@brief/domain/brief'; +import { PassagePickerComponent } from './passage-picker.component'; + +const passages: LibraryPassage[] = [ + { + passageId: 'p1', + scope: 'global', + sectionKey: 'aanhef', + label: 'Standaard aanhef', + version: 1, + content: { paragraphs: [{ nodes: [{ type: 'text', text: 'Geachte heer/mevrouw,' }] }] }, + }, + { + passageId: 'p2', + scope: 'beroep', + beroep: 'arts', + sectionKey: 'aanhef', + label: 'Aanhef, arts-specifiek', + version: 1, + content: { paragraphs: [{ nodes: [{ type: 'text', text: 'Geachte collega,' }] }] }, + }, +]; + +const meta: Meta = { + title: 'Domein/Brief/Passage Picker', + component: PassagePickerComponent, + render: (args) => ({ + props: args, + template: ``, + }), + args: { passages, insert: () => {} }, +}; +export default meta; +type Story = StoryObj; + +export const Default: Story = {}; diff --git a/src/app/brief/ui/rejection-comments/rejection-comments.stories.ts b/src/app/brief/ui/rejection-comments/rejection-comments.stories.ts new file mode 100644 index 0000000..0a2c210 --- /dev/null +++ b/src/app/brief/ui/rejection-comments/rejection-comments.stories.ts @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { RejectionCommentsComponent } from './rejection-comments.component'; + +const meta: Meta = { + title: 'Domein/Brief/Rejection Comments', + component: RejectionCommentsComponent, + args: { reject: () => {} }, +}; +export default meta; +type Story = StoryObj; + +export const Show: Story = { + args: { mode: 'show', comments: 'Graag de aanhef formeler.' }, +}; +export const Entry: Story = { args: { mode: 'entry' } }; +export const EntryBusy: Story = { args: { mode: 'entry', busy: true } }; diff --git a/src/app/shared/layout/shell/shell.stories.ts b/src/app/shared/layout/shell/shell.stories.ts new file mode 100644 index 0000000..afef88a --- /dev/null +++ b/src/app/shared/layout/shell/shell.stories.ts @@ -0,0 +1,16 @@ +import type { Meta, StoryObj } from '@storybook/angular'; +import { applicationConfig } from '@storybook/angular'; +import { provideRouter } from '@angular/router'; +import { ShellComponent } from './shell.component'; + +const meta: Meta = { + title: 'Design System/Templates/Shell', + component: ShellComponent, + decorators: [applicationConfig({ providers: [provideRouter([])] })], +}; +export default meta; +type Story = StoryObj; + +// No route matches, so renders nothing — this story is about the +// persistent chrome (skip-link, header, footer), not routed page content. +export const Default: Story = {};