Files
atomic-design-poc/apps/ssp/src/app/registratie/ui/aanvraag-block/aanvraag-block.component.ts
T
ehoandClaude Sonnet 5 43dc3210cd refactor: move libs/shared/src/ui/ into atoms/molecules/organisms (RD-27)
The folder now equals the layer, as CLAUDE.md decision 2 requires. 33
directories move by git mv (25 flat, plus upload/'s 8 subfolders split
across all three layers). 28 distinct @shared/ui/* specifiers rewrite
across 73 files, longest-first. Five relative imports inside upload/
become @shared/ui aliases because their sibling now lives in a
different layer; two stay relative because both ends stay in the same
layer. Four .mdx docs get their seven broken story imports fixed;
atomic-design.mdx's page-shell import is untouched, because layout/
does not move.

No component, template, story title, or layer-tag comment changes.
That is RD-28's job.

Verified against the ticket's acceptance commands: the 26 flat
directories become exactly 3 layer folders with the counts the ticket
names, only three @shared/ui/* prefixes remain (atoms, molecules,
organisms), the .mdx import count holds at 7, and the relative-import
count inside ui/ drops from 7 to 2 as decision 4 requires. The
@shared/ui/ occurrence count moves from 200 to 205: decision 4
mandates turning 5 of those 7 relative imports into @shared/ui/*
aliases, which decision 3's "200 before, 200 after" check does not
account for. The 5-occurrence gap is exactly the 5 conversions decision
4 names, not a lost or duplicated specifier.

npm run ci --full passes: lint, typecheck, dep:check, format, tokens,
seam, both apps' + both libraries' tests, both apps' localized build,
audit, backend tests, all three generated-artifact drift checks, and
both Storybook instances' build + axe-core a11y suite (67+45 suites,
198+112 tests, all green).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-05 08:14:10 +02:00

72 lines
2.8 KiB
TypeScript

import { Component, computed, input, output } from '@angular/core';
import { formatDatumNl } from '@shared/kernel/datum';
import { ButtonComponent } from '@shared/ui/atoms/button/button.component';
import { AlertComponent } from '@shared/ui/atoms/alert/alert.component';
import { Aanvraag } from '@registratie/domain/aanvraag';
import { TYPE_LABELS } from '@registratie/domain/aanvraag-view';
import { blockActions } from '@registratie/domain/block-actions';
/** Organism: a resumable Concept ("lopende aanvraag") on the dashboard, rendered as
a CIBG "melding" (warning) with its actions — verwijderen as a link, aanvraag
openen as a button. Which actions show is driven by the pure `blockActions(status)`;
the block only renders. Submitted/resolved aanvragen are NOT rendered here — they
render as CIBG "aanvragen" rows (see application-link + aanvraag-view). */
@Component({
selector: 'app-aanvraag-block',
imports: [ButtonComponent, AlertComponent],
styles: [
`
.actions {
display: flex;
align-items: center;
gap: var(--rhc-space-max-md);
margin-block-start: var(--rhc-space-max-sm);
}
`,
],
template: `
@if (aanvraag().status.tag === 'Concept') {
<app-alert type="warning">
<h3 class="h5">{{ typeLabel() }}</h3>
<p>{{ conceptText() }}</p>
<div class="actions">
@if (actions().includes('cancel')) {
<app-button variant="subtle" (click)="cancel.emit()" i18n="@@aanvraagBlock.verwijderen"
>Verwijderen</app-button
>
}
@if (actions().includes('resume')) {
<app-button (click)="resume.emit()" i18n="@@aanvraagBlock.openen"
>Aanvraag openen</app-button
>
}
</div>
</app-alert>
}
`,
})
export class AanvraagBlockComponent {
aanvraag = input.required<Aanvraag>();
resume = output<void>();
cancel = output<void>();
protected typeLabel = computed(() => TYPE_LABELS[this.aanvraag().type]);
protected actions = computed(() => blockActions(this.aanvraag().status));
// ponytail: display-only deadline derived as createdAt + 30 dagen; move to a
// server-sent `completeBefore` on the DTO when the expiry rule becomes real.
private deadline = computed(() => {
const d = new Date(this.aanvraag().createdAt);
d.setDate(d.getDate() + 30);
return d.toISOString();
});
/** The melding body for a Concept: wizard not finished + complete-before date. */
protected conceptText = computed(() => {
const s = this.aanvraag().status;
if (s.tag !== 'Concept') return '';
return $localize`:@@aanvraagBlock.conceptMelding:Deze aanvraag is nog niet volledig afgerond — u bent gebleven bij stap ${s.stepIndex + 1}:stap: van ${s.stepCount}:totaal:. Rond de aanvraag af vóór ${formatDatumNl(this.deadline())}:datum:.`;
});
}