feat(fp): brief v3 — besluit-driven guided drafting
Compose the herregistratie letter from the besluit instead of a library hunt: the behandelaar picks positief/negatief (+ reden-checkboxes for a negatief) and the kern's standaardteksten follow the selection live. Front-end (this increment): - Kern is recomposed reactively from the besluit selection (new BesluitSelected machine msg + composeKern); the "Genereer conceptbrief" button is gone. The drafter's free text is preserved across a selection change. - The editor shows only the editable sections; the locked aanhef/slot render in the preview, not the authoring surface. Slot is a case-type template section (per templateId), documented as such. - The panel re-seeds from the letter via inferSelection() — the besluit + redenen are read back off the kern's passage blocks, so the selection survives reload with no new wire fields (derive, don't store). - letter-section drops the now-redundant per-section passage picker (besluit owns standaardteksten); keeps free-text + block edit/move/remove. Fix: app-checkbox now falls back to a unique per-instance id when checkboxId is omitted. The CIBG styled checkbox routes clicks through the label, so the shared id="undefined" made every reason label toggle the first input — the second checkbox could never be checked. Verified live (Playwright): each reason toggles independently. Backend/seam (brief v3 WIP): besluit/reason passage tags on the wire + seed, carried through the adapter parse boundary. Specs updated (besluit, brief.machine) and the affected stories re-pointed at the new API. FE lint + build + 253 vitest specs green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import { RemoteData } from '@shared/application/remote-data';
|
||||
import { createStore } from '@shared/application/store';
|
||||
import {
|
||||
Brief,
|
||||
CaseContext,
|
||||
allDiagnostics,
|
||||
canSubmit,
|
||||
hasBlockingErrors,
|
||||
@@ -87,6 +88,10 @@ export class BriefStore {
|
||||
stays untouched by design). Set from every server view that carries it. */
|
||||
readonly orgTemplate = signal<OrgTemplate | null>(null);
|
||||
|
||||
/** The case (zorgverlener + aanvraag) this letter concerns — server-joined context for
|
||||
the behandel scherm header, not letter state. Set from every server view. */
|
||||
readonly caseContext = signal<CaseContext | null>(null);
|
||||
|
||||
/** The org logo's content URL for the letterhead, or null when the template has none. */
|
||||
readonly logoUrl = computed<string | null>(() => {
|
||||
const id = this.orgTemplate()?.logoDocumentId;
|
||||
@@ -134,6 +139,7 @@ export class BriefStore {
|
||||
const r = await this.adapter.load();
|
||||
if (r.ok) {
|
||||
this.orgTemplate.set(r.value.orgTemplate);
|
||||
this.caseContext.set(r.value.caseContext);
|
||||
this.clearHistory();
|
||||
this.store.dispatch({ tag: 'BriefLoaded', ...r.value });
|
||||
} else {
|
||||
@@ -212,6 +218,7 @@ export class BriefStore {
|
||||
if (r.ok) {
|
||||
this.actionState.set({ tag: 'Idle' });
|
||||
this.orgTemplate.set(r.value.orgTemplate);
|
||||
this.caseContext.set(r.value.caseContext);
|
||||
this.clearHistory();
|
||||
this.rejectionSnapshot.set(null);
|
||||
this.store.dispatch({ tag: 'BriefLoaded', ...r.value });
|
||||
@@ -257,6 +264,7 @@ export class BriefStore {
|
||||
private applyServerStatus(view: BriefView) {
|
||||
// `send` pins the org-template version server-side — mirror whatever came back.
|
||||
this.orgTemplate.set(view.orgTemplate);
|
||||
this.caseContext.set(view.caseContext);
|
||||
const { brief, decisions } = view;
|
||||
const s = brief.status;
|
||||
switch (s.tag) {
|
||||
|
||||
Reference in New Issue
Block a user