fix: convert ISO datetime to plain date string before passing to DatePicker
https://sonarly.com/issue/18717?type=bug The DatePicker component crashes with a RangeError when it receives a full ISO datetime string (e.g. `2025-10-02T17:32:55.570Z`) because `Temporal.PlainDate.from()` only accepts date-only strings like `2025-10-02`. Fix: Replaced `Temporal.PlainDate.from(plainDateString)` with the team's existing `parseToPlainDateOrThrow(plainDateString)` utility from `twenty-shared/utils` at two sites: 1. **`DatePicker.tsx` (line 359)** — The primary crash site from the Sentry error. When a user clicks a date cell on the opportunities page, the raw field value from the record store is a full ISO datetime string (e.g. `2025-10-02T17:32:55.570Z`). `Temporal.PlainDate.from()` cannot parse this format and throws `RangeError: Cannot parse`. `parseToPlainDateOrThrow` first attempts `Temporal.Instant.from().toZonedDateTimeISO('UTC').toPlainDate()` (handles ISO datetime), then falls back to `Temporal.PlainDate.from()` (handles plain dates). 2. **`DatePickerWithoutCalendar.tsx` (line 326)** — Same defensive fix for the calendar top bar's date picker, which accepts `Nullable<string>` and could receive a datetime string through the same data path. Both changes import `parseToPlainDateOrThrow` alongside the existing imports from `twenty-shared/utils`. The return type remains `Temporal.PlainDate`, so all downstream code is unaffected.
This commit is contained in:
+2
-1
@@ -21,6 +21,7 @@ import { Temporal } from 'temporal-polyfill';
|
||||
import { type Nullable } from 'twenty-shared/types';
|
||||
import {
|
||||
isDefined,
|
||||
parseToPlainDateOrThrow,
|
||||
turnJSDateToPlainDate,
|
||||
type RelativeDateFilter,
|
||||
} from 'twenty-shared/utils';
|
||||
@@ -356,7 +357,7 @@ export const DatePicker = ({
|
||||
}: DatePickerProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const plainDate = isDefined(plainDateString)
|
||||
? Temporal.PlainDate.from(plainDateString)
|
||||
? parseToPlainDateOrThrow(plainDateString)
|
||||
: Temporal.Now.plainDateISO();
|
||||
|
||||
const { userTimezone } = useUserTimezone();
|
||||
|
||||
+6
-2
@@ -15,7 +15,11 @@ import 'react-datepicker/dist/react-datepicker.css';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { Temporal } from 'temporal-polyfill';
|
||||
import { type Nullable } from 'twenty-shared/types';
|
||||
import { isDefined, turnJSDateToPlainDate } from 'twenty-shared/utils';
|
||||
import {
|
||||
isDefined,
|
||||
parseToPlainDateOrThrow,
|
||||
turnJSDateToPlainDate,
|
||||
} from 'twenty-shared/utils';
|
||||
import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
|
||||
export const MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID =
|
||||
@@ -323,7 +327,7 @@ export const DatePickerWithoutCalendar = ({
|
||||
onClose,
|
||||
}: DatePickerWithoutCalendarProps) => {
|
||||
const { theme } = useContext(ThemeContext);
|
||||
const plainDate = isDefined(date) ? Temporal.PlainDate.from(date) : null;
|
||||
const plainDate = isDefined(date) ? parseToPlainDateOrThrow(date) : null;
|
||||
|
||||
const { closeDropdown: closeDropdownMonthSelect } = useCloseDropdown();
|
||||
const { closeDropdown: closeDropdownYearSelect } = useCloseDropdown();
|
||||
|
||||
Reference in New Issue
Block a user