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:
@@ -91,12 +91,13 @@ let submitting = $state(false);
|
|||||||
let dirty = $state(false);
|
let dirty = $state(false);
|
||||||
|
|
||||||
const titleEmpty = $derived(title.trim().length === 0);
|
const titleEmpty = $derived(title.trim().length === 0);
|
||||||
// Client-side title error fires instantly on a save attempt; the server's
|
// Required-field errors derive from the CURRENT field value, not the stale server
|
||||||
// titleError is the simultaneous-multi-field source on a real round-trip.
|
// 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(
|
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 }) => {
|
beforeNavigate(({ cancel }) => {
|
||||||
if (dirty && !submitting) {
|
if (dirty && !submitting) {
|
||||||
|
|||||||
@@ -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)', () => {
|
describe('EventForm — submitting state (named AC, Decision 8)', () => {
|
||||||
it('disables the submit button while submitting', async () => {
|
it('disables the submit button while submitting', async () => {
|
||||||
// A never-resolving fetch keeps use:enhance in flight so the disabled
|
// A never-resolving fetch keeps use:enhance in flight so the disabled
|
||||||
|
|||||||
Reference in New Issue
Block a user