feat(fp): WP-25 — server-rendered letter HTML preview

Adds LetterHtml.Render, a pure composer mirroring the FE letter canvas'
class vocabulary, behind two ExcludeFromDescription()'d endpoints
(GET /brief/preview, GET /admin/org-template/{subOrgId}/preview).
Auto-resolvable placeholders pull from seed/case data; unresolved
manual ones render as "[NOG IN TE VULLEN: label]". A sent brief
archives its composed HTML (BriefEntity.ArchivedHtml) so a later
org-template republish never changes it. FE gets a hand-written fetch
adapter (text/html, not JSON) and a "Voorbeeld" button that opens the
preview in a new tab.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-07-05 12:56:36 +02:00
co-authored by Claude Sonnet 5
parent c07a33ee3e
commit 1bb9383344
17 changed files with 1020 additions and 8 deletions
+1
View File
@@ -63,6 +63,7 @@ import { LetterComposerComponent } from '@brief/ui/letter-composer/letter-compos
(approve)="store.approve()"
(reject)="store.reject($event)"
(send)="store.send()"
(preview)="store.previewLetter()"
/>
}
}
@@ -41,6 +41,11 @@ import { RejectionCommentsComponent } from '@brief/ui/rejection-comments/rejecti
flex-wrap: wrap;
margin-block-end: var(--rhc-space-max-lg);
}
.head-end {
display: flex;
align-items: center;
gap: var(--rhc-space-max-md);
}
.panel {
margin-block: var(--rhc-space-max-xl);
}
@@ -56,7 +61,12 @@ import { RejectionCommentsComponent } from '@brief/ui/rejection-comments/rejecti
template: `
<div class="head">
<app-heading [level]="2">{{ title() }}</app-heading>
<app-status-badge [label]="statusLabel()" [color]="statusColor()" />
<div class="head-end">
<app-button variant="subtle" [disabled]="busy()" (click)="preview.emit()">{{
previewLabel()
}}</app-button>
<app-status-badge [label]="statusLabel()" [color]="statusColor()" />
</div>
</div>
@if (status() === 'rejected') {
@@ -143,9 +153,11 @@ export class LetterComposerComponent {
approve = output<void>();
reject = output<string>();
send = output<void>();
preview = output<void>();
locate = output<Diagnostic>();
title = input($localize`:@@brief.title:Brief aan de zorgverlener`);
previewLabel = input($localize`:@@brief.preview.open:Voorbeeld`);
submitLabel = input($localize`:@@brief.submit:Indienen ter beoordeling`);
resubmitLabel = input($localize`:@@brief.resubmit:Opnieuw indienen`);
submitHint = input(