From 9e08445bff7a6ae2bf0dd0b229615141de782c11 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Thu, 20 Jun 2024 17:13:30 +0200 Subject: [PATCH] Fix date picker wrong on certain timezones (#5972) Timezone with a negative offset weren't working good with date pickers. I split the logic for display and parsing between date only and datetime. Date time is sending and displaying using timezone, and date only is sending and displaying by forcing the date to take its UTC day and month and 00:00:00 time. This way its consistent across all timezones. --- .../record-field/components/FieldInput.tsx | 2 + .../input/components/DateFieldInput.tsx | 7 +++ .../input/components/DateTimeFieldInput.tsx | 7 +++ .../components/RecordTableCellContainer.tsx | 5 +- .../ui/field/input/components/DateInput.tsx | 11 ++-- .../date/components/DateTimeInput.tsx | 18 ++++++- .../date/components/InternalDatePicker.tsx | 52 ++++++++++++++----- 7 files changed, 80 insertions(+), 22 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx index ce1240e64..f13e59e3a 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/components/FieldInput.tsx @@ -121,6 +121,7 @@ export const FieldInput = ({ onEscape={onEscape} onClickOutside={onClickOutside} onClear={onSubmit} + onSubmit={onSubmit} /> ) : isFieldDate(fieldDefinition) ? ( ) : isFieldNumber(fieldDefinition) ? ( { const { fieldValue, setDraftValue } = useDateField(); @@ -39,6 +41,10 @@ export const DateFieldInput = ({ onEnter?.(() => persistDate(newDate)); }; + const handleSubmit = (newDate: Nullable) => { + onSubmit?.(() => persistDate(newDate)); + }; + const handleEscape = (newDate: Nullable) => { onEscape?.(() => persistDate(newDate)); }; @@ -69,6 +75,7 @@ export const DateFieldInput = ({ clearable onChange={handleChange} onClear={handleClear} + onSubmit={handleSubmit} /> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx index 15c6280ee..6a5749008 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateTimeFieldInput.tsx @@ -12,6 +12,7 @@ export type DateTimeFieldInputProps = { onEnter?: FieldInputEvent; onEscape?: FieldInputEvent; onClear?: FieldInputEvent; + onSubmit?: FieldInputEvent; }; export const DateTimeFieldInput = ({ @@ -19,6 +20,7 @@ export const DateTimeFieldInput = ({ onEscape, onClickOutside, onClear, + onSubmit, }: DateTimeFieldInputProps) => { const { fieldValue, setDraftValue } = useDateTimeField(); @@ -57,6 +59,10 @@ export const DateTimeFieldInput = ({ onClear?.(() => persistDate(null)); }; + const handleSubmit = (newDate: Nullable) => { + onSubmit?.(() => persistDate(newDate)); + }; + const dateValue = fieldValue ? new Date(fieldValue) : null; return ( @@ -69,6 +75,7 @@ export const DateTimeFieldInput = ({ onChange={handleChange} isDateTimeInput onClear={handleClear} + onSubmit={handleSubmit} /> ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx index 48b3f5ce2..3ef55faf1 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-cell/components/RecordTableCellContainer.tsx @@ -142,10 +142,9 @@ export const RecordTableCellContainer = ({ [styles.cellBaseContainerSoftFocus]: hasSoftFocus, })} > - {isInEditMode && ( + {isInEditMode ? ( {editModeContent} - )} - {hasSoftFocus ? ( + ) : hasSoftFocus ? ( ) => void; isDateTimeInput?: boolean; onClear?: () => void; + onSubmit?: (newDate: Nullable) => void; }; export const DateInput = ({ @@ -44,6 +45,7 @@ export const DateInput = ({ onChange, isDateTimeInput, onClear, + onSubmit, }: DateInputProps) => { const [internalValue, setInternalValue] = useState(value); @@ -59,6 +61,11 @@ export const DateInput = ({ onClear?.(); }; + const handleMouseSelect = (newDate: Date | null) => { + setInternalValue(newDate); + onSubmit?.(newDate); + }; + const { closeDropdown } = useDropdown(MONTH_AND_YEAR_DROPDOWN_ID); const { closeDropdown: closeDropdownMonthSelect } = useDropdown( MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID, @@ -86,9 +93,7 @@ export const DateInput = ({ { - onEnter(newDate); - }} + onMouseSelect={handleMouseSelect} clearable={clearable ? clearable : false} isDateTimeInput={isDateTimeInput} onEnter={onEnter} diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx index fb17e19b9..239f80509 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/DateTimeInput.tsx @@ -57,11 +57,25 @@ export const DateTimeInput = ({ (date: any) => { const dateParsed = DateTime.fromJSDate(date); - const formattedDate = dateParsed.toFormat(parsingFormat); + const dateWithoutTime = DateTime.fromJSDate(date) + .toLocal() + .set({ + day: date.getUTCDate(), + month: date.getUTCMonth() + 1, + year: date.getUTCFullYear(), + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + }); + + const formattedDate = isDateTimeInput + ? dateParsed.toFormat(parsingFormat) + : dateWithoutTime.toFormat(parsingFormat); return formattedDate; }, - [parsingFormat], + [parsingFormat, isDateTimeInput], ); const parseStringToDate = (str: string) => { diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx index a45855074..89f13fef9 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/InternalDatePicker.tsx @@ -383,19 +383,35 @@ export const InternalDatePicker = ({ onChange?.(newDate); }; + const dateWithoutTime = DateTime.fromJSDate(date) + .toLocal() + .set({ + day: date.getUTCDate(), + month: date.getUTCMonth() + 1, + year: date.getUTCFullYear(), + hour: 0, + minute: 0, + second: 0, + millisecond: 0, + }) + .toJSDate(); + + const dateToUse = isDateTimeInput ? date : dateWithoutTime; + return (
{ onChange?.(newDate); }} customInput={ @@ -424,13 +440,13 @@ export const InternalDatePicker = ({ options={months} disableBlur onChange={handleChangeMonth} - value={date.getMonth()} + value={date.getUTCMonth()} fullWidth />