feat(fp): WP-09 — pure-logic closure: dates + missing command specs
Consolidate four hand-rolled nl-NL date formatters (tasks.ts, aanvraag- block, letter-preview, aanvraag-view -- one more than the WP found) into one shared/kernel/datum.ts::formatDatumNl, spec-pinned and empty-safe. Add the two missing command specs CLAUDE.md's testing rule calls for: draft-sync.spec.ts (debounce coalescing + trailing-call + submit Result shape, via fake timers) and submit-change-request.spec.ts. Remove the unused RemoteData.map3 (updating the three docs that mentioned it); the variant input on confirmation.component.ts was already gone. Documents both stale-WP-text corrections in the backlog file. This closes out backlog Phase 1 (FP/DDD core, WP-05..09).
This commit is contained in:
@@ -71,20 +71,6 @@ export function map2<E, A, B, R>(
|
||||
return { tag: 'Success', value: f(a.value, b.value) };
|
||||
}
|
||||
|
||||
/** Combine three sources (built on map2). */
|
||||
export function map3<E, A, B, C, R>(
|
||||
a: RemoteData<E, A>,
|
||||
b: RemoteData<E, B>,
|
||||
c: RemoteData<E, C>,
|
||||
f: (a: A, b: B, c: C) => R,
|
||||
): RemoteData<E, R> {
|
||||
return map2(
|
||||
map2(a, b, (x, y) => [x, y] as const),
|
||||
c,
|
||||
([x, y], z) => f(x, y, z),
|
||||
);
|
||||
}
|
||||
|
||||
/** Chain a second source that depends on the first one's value. */
|
||||
export function andThen<E, A, B>(
|
||||
rd: RemoteData<E, A>,
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { formatDatumNl } from './datum';
|
||||
|
||||
describe('formatDatumNl', () => {
|
||||
it('formats a Date in long Dutch form', () => {
|
||||
expect(formatDatumNl(new Date(2026, 6, 2))).toBe('2 juli 2026');
|
||||
});
|
||||
|
||||
it('formats an ISO string the same way', () => {
|
||||
expect(formatDatumNl('2026-07-02')).toBe('2 juli 2026');
|
||||
});
|
||||
|
||||
it('is empty-safe: undefined, null, and empty string all yield the empty string', () => {
|
||||
expect(formatDatumNl(undefined)).toBe('');
|
||||
expect(formatDatumNl(null)).toBe('');
|
||||
expect(formatDatumNl('')).toBe('');
|
||||
});
|
||||
|
||||
it('returns empty for an unparseable string rather than "Invalid Date"', () => {
|
||||
expect(formatDatumNl('not-a-date')).toBe('');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* The one hand-written date formatter for pure TS (non-template) code — a domain
|
||||
* rule or a `$localize` string can't reach for Angular's `DatePipe`, so this covers
|
||||
* that gap. Templates use `DatePipe` (`| date: 'longDate'`) instead; don't add a
|
||||
* second hand-rolled formatter for either case.
|
||||
*/
|
||||
export function formatDatumNl(d: Date | string | undefined | null): string {
|
||||
if (!d) return '';
|
||||
const date = typeof d === 'string' ? new Date(d) : d;
|
||||
if (Number.isNaN(date.getTime())) return '';
|
||||
return new Intl.DateTimeFormat('nl-NL', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric',
|
||||
}).format(date);
|
||||
}
|
||||
Reference in New Issue
Block a user