import { Component, computed, input, signal } from '@angular/core'; import { NgTemplateOutlet } from '@angular/common'; import { HeadingComponent } from '@shared/ui/heading/heading.component'; import { ButtonComponent } from '@shared/ui/button/button.component'; import { PlaceholderChipComponent } from '@shared/ui/placeholder-chip/placeholder-chip.component'; import { Paragraph } from '@shared/kernel/rich-text'; import { Brief, LetterBlock } from '@brief/domain/brief'; import { Diagnostic } from '@brief/domain/placeholders'; /** A run of consecutive lines to render together: a list (bullet/number) or a single plain line. */ type PreviewSegment = { readonly list: 'bullet' | 'number' | null; readonly items: readonly Paragraph[] }; function groupParagraphs(paras: readonly Paragraph[]): PreviewSegment[] { const out: { list: 'bullet' | 'number' | null; items: Paragraph[] }[] = []; for (const para of paras) { const kind = para.list ?? null; const last = out[out.length - 1]; if (kind && last && last.list === kind) last.items.push(para); else out.push({ list: kind, items: [para] }); } return out; } // Illustrative values for the "Voorbeeld" toggle — what send resolves server-side. const SAMPLE_VALUES: Record = { naam_zorgverlener: 'J. Jansen', big_nummer: '12345678901', }; /** Organism: read-only rendering of the letter as the approver/recipient sees it. Placeholders show as labelled chips (values are resolved server-side only at send); a chip flagged by the linter shows its error/warning state. The "Voorbeeld" toggle fills auto-resolvable placeholders with sample values to preview the sent result. */ @Component({ selector: 'app-letter-preview', imports: [NgTemplateOutlet, HeadingComponent, ButtonComponent, PlaceholderChipComponent], styles: [` :host{display:block} .toolbar{display:flex;justify-content:flex-end;margin-block-end:var(--rhc-space-max-sm)} .letter{background:var(--rhc-color-wit);border:var(--rhc-border-width-sm) solid var(--rhc-color-border-default);border-radius:var(--rhc-border-radius-md);padding:var(--rhc-space-max-2xl)} section{margin-block-end:var(--rhc-space-max-xl)} p{margin:0 0 var(--rhc-space-max-sm)} ul,ol{margin:0 0 var(--rhc-space-max-sm);padding-inline-start:1.4em} `], template: ` @for (node of nodes; track $index) { @switch (node.type) { @case ('text') { {{ node.text }} } @case ('lineBreak') {
} @case ('placeholder') { @if (showSample() && autoFor(node.key)) { {{ sampleFor(node.key) }} } @else { } } } }
{{ showSample() ? hideSampleLabel() : showSampleLabel() }}
@for (section of brief().sections; track section.sectionKey) {
{{ section.title }} @for (block of section.blocks; track block.blockId) { @for (seg of segmentsOf(block); track $index) { @if (seg.list === 'bullet') {
    @for (para of seg.items; track $index) {
  • }
} @else if (seg.list === 'number') {
    @for (para of seg.items; track $index) {
  1. }
} @else {

} } }
}
`, }) export class LetterPreviewComponent { brief = input.required(); diagnostics = input([]); showSampleLabel = input($localize`:@@brief.preview.showSample:Voorbeeld met testwaarden`); hideSampleLabel = input($localize`:@@brief.preview.hideSample:Testwaarden verbergen`); protected showSample = signal(false); private today = new Date().toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' }); private defs = computed(() => new Map(this.brief().placeholders.map((p) => [p.key, p]))); private worst = computed(() => { const m = new Map(); for (const d of this.diagnostics()) { if (!d.placeholderKey) continue; if (d.severity === 'error') m.set(d.placeholderKey, 'error'); else if (!m.has(d.placeholderKey)) m.set(d.placeholderKey, 'warning'); } return m; }); protected segmentsOf = (block: LetterBlock) => groupParagraphs(block.content.paragraphs); protected labelFor = (key: string) => this.defs().get(key)?.label ?? key; protected autoFor = (key: string) => this.defs().get(key)?.autoResolvable ?? false; protected stateFor = (key: string): 'ok' | 'warning' | 'error' => this.worst().get(key) ?? 'ok'; protected sampleFor = (key: string) => SAMPLE_VALUES[key] ?? (key === 'datum' ? this.today : this.labelFor(key)); }