fix(timeline): clear required-field errors when the field is corrected

titleError/dateError short-circuited on the server fail payload
(`form?.titleError ?? …`, `form?.dateError ?? ''`), so after a fail(400)
the red border and message stuck until the next submit even once the user
typed a valid value. Derive both from the current field value instead: the
server error still seeds the message, but a non-empty title/date clears it
immediately.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-14 09:03:11 +02:00
parent 5f2cf5f2c2
commit 4d5fa7a26f
2 changed files with 29 additions and 4 deletions

View File

@@ -91,12 +91,13 @@ let submitting = $state(false);
let dirty = $state(false);
const titleEmpty = $derived(title.trim().length === 0);
// Client-side title error fires instantly on a save attempt; the server's
// titleError is the simultaneous-multi-field source on a real round-trip.
// Required-field errors derive from the CURRENT field value, not the stale server
// payload: a server titleError/dateError seeds the message, but typing a valid
// value clears it immediately instead of sticking until the next submit.
const titleError = $derived(
form?.titleError ?? (titleTouched && titleEmpty ? m.event_editor_title_required() : '')
titleEmpty && (titleTouched || !!form?.titleError) ? m.event_editor_title_required() : ''
);
const dateError = $derived(form?.dateError ?? '');
const dateError = $derived(dateIso ? '' : (form?.dateError ?? ''));
beforeNavigate(({ cancel }) => {
if (dirty && !submitting) {

View File

@@ -141,6 +141,30 @@ describe('EventForm — server date error wired per-field (REQ-011)', () => {
});
});
describe('EventForm — validation errors clear on correction (review #4)', () => {
it('clears the server title error once a valid title is entered', async () => {
renderForm({ form: { titleError: 'Bitte einen Titel eingeben.', title: '' } });
await expect.element(page.getByText('Bitte einen Titel eingeben.')).toBeInTheDocument();
const titleInput = document.querySelector('#event-title') as HTMLInputElement;
titleInput.value = 'Ein Titel';
titleInput.dispatchEvent(new Event('input', { bubbles: true }));
await expect.element(page.getByText('Bitte einen Titel eingeben.')).not.toBeInTheDocument();
});
it('clears the server date error once a valid date is entered', async () => {
renderForm({ form: { dateError: 'Bitte ein Datum eingeben.' } });
await expect.element(page.getByText('Bitte ein Datum eingeben.')).toBeInTheDocument();
const dateInput = document.querySelector('#eventDate') as HTMLInputElement;
dateInput.value = '01.04.1925';
dateInput.dispatchEvent(new Event('input', { bubbles: true }));
await expect.element(page.getByText('Bitte ein Datum eingeben.')).not.toBeInTheDocument();
});
});
describe('EventForm — submitting state (named AC, Decision 8)', () => {
it('disables the submit button while submitting', async () => {
// A never-resolving fetch keeps use:enhance in flight so the disabled