fix(timeline): validate RANGE end-date client-side with a field-level error

A RANGE event with a blank end date passed validateEventForm and reached
the backend, which 400s with a generic INVALID_DATE_RANGE mapped to "end
must not be before start" — wrong for a missing end date, and shown only as
a top-of-form alert. Validate it before the API call and surface a dedicated
event_editor_end_date_required message on the end-date field via a new
DatePrecisionField endDateError prop (defaults '', so the document form is
unchanged).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-14 09:11:20 +02:00
parent 9f2ae7bd2e
commit 23f6bc284d
8 changed files with 69 additions and 9 deletions

View File

@@ -71,17 +71,23 @@ export function parseEventForm(formData: FormData): ParsedEventForm {
}
/**
* Returns both failing required-field errors (title + date) simultaneously, or
* null when the form is valid. The route owns the `fail(400)` so it can enrich
* the payload with the preserved field values and rehydrated picker selections.
* Returns the failing required-field errors (title + date + RANGE end-date)
* simultaneously, or null when the form is valid. The route owns the `fail(400)`
* so it can enrich the payload with the preserved field values and rehydrated
* picker selections.
*/
export function validateEventForm(
parsed: ParsedEventForm
): { titleError: string; dateError: string } | null {
): { titleError: string; dateError: string; endDateError: string } | null {
const titleError = parsed.title.length === 0 ? m.event_editor_title_required() : '';
const dateError = parsed.eventDate.length === 0 ? m.event_editor_date_required() : '';
if (!titleError && !dateError) return null;
return { titleError, dateError };
// A RANGE event requires an end date. Catch it here so it never reaches the
// backend, which rejects with a generic INVALID_DATE_RANGE mapped to the wrong
// "end before start" message and no field-level cue.
const endDateError =
parsed.precision === 'RANGE' && !parsed.eventDateEnd ? m.event_editor_end_date_required() : '';
if (!titleError && !dateError && !endDateError) return null;
return { titleError, dateError, endDateError };
}
/** The entered field values echoed back in every `fail(...)` so the form re-renders without loss. */