fix(admin): stop the event-date field crashing the page on backspace

Repro: create an event, click into the date field, backspace a day digit.
The whole page white-screened and needed a reload.

Root cause: LocalizedDateInput's `toIso` only checked the day/month were
1-2 digits, not that they formed a real date — so a mid-backspace value
like "0/07/2026" was coerced to the string "2026-07-00" and committed to
`event_date`. CreateEventPage then rendered
`format(addDays(new Date('2026-07-00'), days))`, and date-fns `format`
throws RangeError on an Invalid Date — thrown during render, so React
tore the tree down to the error boundary.

Two complementary fixes:
- `toIso` round-trips the parsed y/m/d through `Date` and rejects
  impossible dates (day 00, month 13, 31 Feb…), so the field never
  commits a value that isn't a real calendar date.
- `useLocalizedDate.format`/`formatDistanceToNow` guard with `isValid`
  and return '' instead of throwing — defence in depth for the ~57 call
  sites that could otherwise white-screen on a bad date.

Verified live: backspacing to a partial/invalid date no longer crashes
(the form stays rendered), a valid date still commits + the expiry
preview renders. Adds a LocalizedDateInput regression test; tsc + build
green.
This commit is contained in:
Paul Nothaft
2026-07-07 08:56:04 +02:00
parent 2522d7e1ce
commit 945026d446
3 changed files with 53 additions and 1 deletions
+7 -1
View File
@@ -1,5 +1,5 @@
import { useTranslation } from 'react-i18next';
import { format as dateFnsFormat, formatDistanceToNow as dateFnsFormatDistanceToNow } from 'date-fns';
import { format as dateFnsFormat, formatDistanceToNow as dateFnsFormatDistanceToNow, isValid } from 'date-fns';
import { de, enUS, ptBR, fr } from 'date-fns/locale';
import { usePublicSettings } from './usePublicSettings';
@@ -32,6 +32,11 @@ export const useLocalizedDate = () => {
const format = (date: Date | string, formatStr?: string) => {
const dateObj = typeof date === 'string' ? new Date(date) : date;
// date-fns `format` throws RangeError on an Invalid Date, which crashes the
// whole page when a call site renders a transient/partial date (e.g. the
// event-date field mid-edit). Return '' instead so a bad value degrades to
// blank rather than tearing down the tree.
if (!isValid(dateObj)) return '';
// Use admin-configured date format if available and no format string provided
let dateFormat = formatStr;
if (!dateFormat && settings?.general_date_format) {
@@ -50,6 +55,7 @@ export const useLocalizedDate = () => {
const formatDistanceToNow = (date: Date | string, options?: { addSuffix?: boolean }) => {
const dateObj = typeof date === 'string' ? new Date(date) : date;
if (!isValid(dateObj)) return '';
return dateFnsFormatDistanceToNow(dateObj, { ...options, locale: getLocale() });
};