import { Component, ElementRef, computed, input, output, viewChild } from '@angular/core';
import { PlaceholderOption } from '@shared/ui/rich-text-editor/rich-text-editor.component';
import { ButtonComponent } from '@shared/ui/button/button.component';
import { HeadingComponent } from '@shared/ui/heading/heading.component';
import { StepperComponent } from '@shared/ui/stepper/stepper.component';
import { Besluit, Brief, CaseContext, LibraryPassage } from '@brief/domain/brief';
import { inferSelection } from '@brief/domain/besluit';
import { Diagnostic } from '@brief/domain/placeholders';
import { OrgTemplate } from '@brief/domain/org-template';
import { BriefMsg } from '@brief/domain/brief.machine';
import { LetterCanvasComponent } from '@brief/ui/letter-canvas/letter-canvas.component';
import { DiagnosticsPanelComponent } from '@brief/ui/diagnostics-panel/diagnostics-panel.component';
import { RejectionCommentsComponent } from '@brief/ui/rejection-comments/rejection-comments.component';
import { LetterEditorComponent } from '@brief/ui/letter-editor/letter-editor.component';
import { BesluitPanelComponent } from '@brief/ui/besluit-panel/besluit-panel.component';
/** Organism: the behandelaar's drafting step. Frames "Brief opstellen" as one step in
the case workflow — a case-context header + stepper (Beoordelen → Brief opstellen →
Indienen, neighbours stubbed) — with the besluit-driven guidance, the lean letter
editor, and an on-demand full-letter preview in a modal. Only ever renders for an
editable brief (draft/rejected); the approver's read-only flow stays in
letter-composer. Presentational: emits edit/submit/preview intents. */
@Component({
selector: 'app-behandel-scherm',
imports: [
ButtonComponent,
HeadingComponent,
StepperComponent,
LetterCanvasComponent,
DiagnosticsPanelComponent,
RejectionCommentsComponent,
LetterEditorComponent,
BesluitPanelComponent,
],
styles: [
`
:host {
display: block;
}
.case-head {
margin-block-end: var(--rhc-space-max-lg);
padding: var(--rhc-space-max-md) var(--rhc-space-max-lg);
border-inline-start: 4px solid var(--rhc-color-primary, var(--rhc-color-border-strong));
background: var(--rhc-color-background-subtle, transparent);
}
.case-meta {
display: flex;
flex-wrap: wrap;
gap: var(--rhc-space-max-md);
color: var(--rhc-color-foreground-subtle);
}
.step-body {
display: grid;
gap: var(--rhc-space-max-xl);
margin-block-start: var(--rhc-space-max-lg);
}
.bar {
display: flex;
flex-wrap: wrap;
gap: var(--rhc-space-max-md);
align-items: center;
margin-block-start: var(--rhc-space-max-xl);
}
dialog {
border: none;
border-radius: var(--rhc-radius-md, 4px);
padding: 0;
max-width: min(900px, 95vw);
width: 100%;
}
dialog::backdrop {
background: rgb(0 0 0 / 45%); /* token-ok: modal scrim, not a palette colour */
}
.modal-body {
padding: var(--rhc-space-max-lg);
max-height: 80vh;
overflow: auto;
}
.modal-bar {
display: flex;
justify-content: space-between;
gap: var(--rhc-space-max-md);
padding: var(--rhc-space-max-md) var(--rhc-space-max-lg);
border-block-start: 1px solid var(--rhc-color-border);
}
`,
],
template: `
@if (status() === 'rejected') {
}
{{ previewLabel() }}
{{
submitLabel()
}}
@if (!canSubmit()) {
{{ submitHint() }}
}
`,
})
export class BehandelSchermComponent {
brief = input.required();
orgTemplate = input.required();
logoUrl = input(null);
availablePassages = input([]);
diagnostics = input([]);
caseContext = input.required();
canSubmit = input(false);
busy = input(false);
/** Server decision (PRD-0002 §5c): may this actor unmask the case BIG-nummer? */
canRevealBigNummer = input(false);
edit = output();
submit = output();
preview = output();
locate = output();
revealBigNummer = output();
/** The BIG-nummer arrives masked (contains `*`); once revealed the swapped value has
no `*`, so the reveal action hides itself — no separate "revealed" flag needed. */
protected isMasked = computed(() => this.caseContext().bigNummer.includes('*'));
/** Step-up (PRD-0002 §5d) stubbed as a native confirm — the extra verification gesture
before an audited PII reveal. ponytail: real systems prompt MFA / recent re-auth. */
protected onReveal() {
if (confirm(this.stepUpPrompt())) this.revealBigNummer.emit();
}
private previewDialog = viewChild>('previewDialog');
protected status = computed(() => this.brief().status.tag);
protected rejectComments = computed(() => {
const s = this.brief().status;
return s.tag === 'rejected' ? s.comments : '';
});
/** The besluit + redenen the letter currently reflects, read back off the kern's
passages — this seeds the panel so it survives reload/undo (no separate storage). */
protected selection = computed(() => {
const kern = this.brief().sections.find((s) => s.sectionKey === 'kern');
return inferSelection(kern?.blocks ?? [], this.availablePassages());
});
// Same insert menu as the composer: only valid, fillable, non-deprecated fields.
protected menu = computed(() =>
this.brief()
.placeholders.filter((p) => p.fillable !== false && !p.deprecated)
.map((p) => ({ key: p.key, label: p.label, autoResolvable: p.autoResolvable })),
);
/** Besluit/redenen changed → recompose the kern as one edit (= one undo step). */
protected onSelection(sel: { besluit: Besluit | null; reasons: string[] }) {
this.edit.emit({ tag: 'BesluitSelected', besluit: sel.besluit, reasons: sel.reasons });
}
protected openPreview() {
this.previewDialog()?.nativeElement.showModal();
}
protected closePreview() {
this.previewDialog()?.nativeElement.close();
}
protected submitLabel = computed(() =>
this.status() === 'rejected'
? $localize`:@@brief.resubmit:Opnieuw indienen`
: $localize`:@@brief.submit:Indienen ter beoordeling`,
);
protected steps = input([
$localize`:@@brief.step.beoordelen:Beoordelen`,
$localize`:@@brief.step.opstellen:Brief opstellen`,
$localize`:@@brief.step.indienen:Indienen`,
]);
protected processName = input($localize`:@@brief.process:Herregistratie behandelen`);
protected stepTitle = input($localize`:@@brief.step.opstellen:Brief opstellen`);
protected caseHeading = input($localize`:@@brief.case.heading:Aanvraag herregistratie`);
protected bigLabel = input($localize`:@@brief.case.big:BIG-nummer`);
protected revealLabel = input($localize`:@@brief.case.reveal:Toon BIG-nummer`);
protected stepUpPrompt = input(
$localize`:@@brief.case.revealConfirm:Extra verificatie vereist. Het tonen van het BIG-nummer wordt vastgelegd. Doorgaan?`,
);
protected previewLabel = input($localize`:@@brief.preview.open:Voorbeeld`);
protected openDocumentLabel = input(
$localize`:@@brief.preview.openDocument:Openen als document (PDF)`,
);
protected closeLabel = input($localize`:@@common.close:Sluiten`);
protected submitHint = input(
$localize`:@@brief.submitHint:Vul eerst alle verplichte secties en los fouten op.`,
);
}