feat(document): surface end-before-start inline on the date form (#678)

Add an endBeforeStart $derived to WhoWhenSection (lexicographic ISO compare,
no Date object) that renders an inline error on the end-date field —
border-red-400, aria-invalid, aria-describedby, and a #end-date-error <p>
inside the existing aria-live region — with a ⚠ glyph so the cue is not
colour-alone (WCAG 1.4.1). Save is not disabled; the server stays the gate.

Wire ErrorCode INVALID_DATE_RANGE through errors.ts getErrorMessage and add
the single key error_invalid_date_range to de/en/es, so the same translated
string is used inline (client) and via getErrorMessage (server fallback).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-01 09:27:57 +02:00
parent 3a4c2c6225
commit 654ac1478c
6 changed files with 71 additions and 1 deletions

View File

@@ -70,6 +70,13 @@ onMount(() => {
const dateInvalid = $derived(dateDirty && dateDisplay.length > 0 && dateIso === '');
// Inline mirror of the server guard (#678). ISO YYYY-MM-DD strings compare
// lexicographically, so no Date object is needed. Server stays the gate —
// this only surfaces the error early; it never disables Save.
const endBeforeStart = $derived(
showEndDate && endDateIso !== '' && dateIso !== '' && endDateIso < dateIso
);
function handleDateInput(e: Event) {
const result = handleGermanDateInput(e);
dateDisplay = result.display;
@@ -155,8 +162,19 @@ $effect(() => {
oninput={handleEndDateInput}
placeholder={m.form_placeholder_date()}
maxlength="10"
class="block min-h-[48px] w-full rounded border border-line px-2 py-3 text-sm shadow-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring"
aria-invalid={endBeforeStart ? 'true' : undefined}
aria-describedby={endBeforeStart ? 'end-date-error' : undefined}
class="block min-h-[48px] w-full rounded border border-line px-2 py-3 text-sm shadow-sm
{endBeforeStart
? 'border-red-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500'
: 'focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring'}"
/>
{#if endBeforeStart}
<!-- Non-colour cue (WCAG 1.4.1): warning glyph + text, not red alone. -->
<p id="end-date-error" class="mt-1 text-xs text-red-600">
<span aria-hidden="true"></span>{m.error_invalid_date_range()}
</p>
{/if}
</div>
{/if}
</div>