From 099fb29faffcf4ac9f0c22634a59bc0aa756fbd8 Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Fri, 25 Aug 2023 12:57:03 +0800 Subject: [PATCH 1/3] [MISC][RL] Ensure empty input is converted to a valid dayjs object --- src/date-range-input/date-range-input.tsx | 3 ++- .../calendar-day-style-helper.ts | 10 +++++++--- .../internal-calendar/calendar-manager.tsx | 20 ++++++++++--------- .../time-slot-week-view.tsx | 11 +++++++--- src/util/date-helper.ts | 6 +++++- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/date-range-input/date-range-input.tsx b/src/date-range-input/date-range-input.tsx index 7efc59758..a1015a7ba 100644 --- a/src/date-range-input/date-range-input.tsx +++ b/src/date-range-input/date-range-input.tsx @@ -13,6 +13,7 @@ import { StandaloneDateInput, StandaloneDateInputRef, } from "../shared/standalone-date-input/standalone-date-input"; +import { DateHelper } from "../util"; import { DateInputHelper } from "../util/date-input-helper"; import { useStateActions } from "../util/use-state-actions"; import { @@ -349,7 +350,7 @@ export const DateRangeInput = ({ const handleWeekSelectionInputFocus = () => { if (isWeekSelection) { - const firstDayOfWeek = dayjs(selectedStart) + const firstDayOfWeek = DateHelper.toDayjs(selectedStart) .startOf("week") .format("YYYY-MM-DD"); diff --git a/src/shared/internal-calendar/calendar-day-style-helper.ts b/src/shared/internal-calendar/calendar-day-style-helper.ts index cc68e3300..17f4e1bfb 100644 --- a/src/shared/internal-calendar/calendar-day-style-helper.ts +++ b/src/shared/internal-calendar/calendar-day-style-helper.ts @@ -1,7 +1,7 @@ import dayjs, { Dayjs } from "dayjs"; import isBetween from "dayjs/plugin/isBetween"; import { FocusType } from "./types"; -import { CalendarHelper } from "../../util"; +import { CalendarHelper, DateHelper } from "../../util"; import { StyleProps } from "./internal-calendar-day.style"; import { OverflowCircleProps } from "./internal-week-selection-calendar-day.style"; import { HoverDirection } from "./internal-calendar-day"; @@ -381,8 +381,12 @@ const isOutsideSelectedRange = ( }; const getDayOfWeek = (value: string) => { - const firstDayOfWeek = dayjs(value).startOf("week").format("YYYY-MM-DD"); - const lastDayOfWeek = dayjs(value).endOf("week").format("YYYY-MM-DD"); + const firstDayOfWeek = DateHelper.toDayjs(value) + .startOf("week") + .format("YYYY-MM-DD"); + const lastDayOfWeek = DateHelper.toDayjs(value) + .endOf("week") + .format("YYYY-MM-DD"); return { firstDayOfWeek, diff --git a/src/shared/internal-calendar/calendar-manager.tsx b/src/shared/internal-calendar/calendar-manager.tsx index 443138807..319df91e2 100644 --- a/src/shared/internal-calendar/calendar-manager.tsx +++ b/src/shared/internal-calendar/calendar-manager.tsx @@ -1,5 +1,6 @@ import dayjs, { Dayjs } from "dayjs"; import React, { useEffect, useImperativeHandle, useRef, useState } from "react"; +import { DateHelper } from "../../util"; import { CalendarHelper } from "../../util/calendar-helper"; import { ActionButton, @@ -61,11 +62,11 @@ const Component = ( // ============================================================================= // the current visible date in month/year views and header const [calendarDate, setCalendarDate] = useState( - dayjs(initialCalendarDate) + DateHelper.toDayjs(initialCalendarDate) ); // the selected date in month/year views and the current visible date in day view const [viewCalendarDate, setViewCalendarDate] = useState( - dayjs(initialCalendarDate) + DateHelper.toDayjs(initialCalendarDate) ); const [currentView, setCurrentView] = useState("default"); @@ -82,14 +83,14 @@ const Component = ( setCurrentView("default"); }, resetView() { - const date = dayjs(initialCalendarDate); + const date = DateHelper.toDayjs(initialCalendarDate); setCalendarDate(date); setViewCalendarDate(date); setCurrentView("default"); }, setCalendarDate(value?: string) { - const date = value ? dayjs(value) : dayjs(); + const date = DateHelper.toDayjs(value); setCalendarDate(date); setViewCalendarDate(date); }, @@ -97,7 +98,7 @@ const Component = ( }); useEffect(() => { - const date = initialCalendarDate ? dayjs(initialCalendarDate) : dayjs(); + const date = DateHelper.toDayjs(initialCalendarDate); setCalendarDate(date); setViewCalendarDate(date); }, [initialCalendarDate]); @@ -187,8 +188,9 @@ const Component = ( }; const handleCancelButton = () => { - setCalendarDate(dayjs(initialCalendarDate)); - setViewCalendarDate(dayjs(initialCalendarDate)); + const initialValue = DateHelper.toDayjs(initialCalendarDate); + setCalendarDate(initialValue); + setViewCalendarDate(initialValue); if (currentView === "default") { performOnDismissHandler("reset"); @@ -279,14 +281,14 @@ const Component = ( } else { return getYearHeaderLabel ? getYearHeaderLabel(calendarDate) - : dayjs(calendarDate).format("YYYY"); + : calendarDate.format("YYYY"); } }; const renderDropdownButtons = () => { const monthLabel = getMonthHeaderLabel ? getMonthHeaderLabel(calendarDate) - : dayjs(calendarDate).format("MMM"); + : calendarDate.format("MMM"); return ( <> { + return DateHelper.toDayjs(selectedDate || currentCalendarDate) + .endOf("week") + .format(DATE_FORMAT); + }; + // ============================================================================= // RENDER FUNCTIONS // ============================================================================= @@ -92,9 +99,7 @@ export const TimeSlotWeekView = ({ ref={calendarManagerRef} type="standalone" dynamicHeight - initialCalendarDate={dayjs(selectedDate || currentCalendarDate) - .endOf("week") - .format(DATE_FORMAT)} + initialCalendarDate={getInitialCalendarDate()} selectedStartDate={selectedDate} getLeftArrowDate={(day) => day.subtract(1, "week")} getRightArrowDate={(day) => day.add(1, "week")} diff --git a/src/util/date-helper.ts b/src/util/date-helper.ts index f52edcd9b..c352fd8d7 100644 --- a/src/util/date-helper.ts +++ b/src/util/date-helper.ts @@ -1,4 +1,4 @@ -import dayjs from "dayjs"; +import dayjs, { Dayjs } from "dayjs"; const MONTHS_WITH_31_DAYS = [1, 3, 5, 7, 8, 10, 12]; const MONTHS_WITH_30_DAYS = [4, 6, 9, 11]; @@ -80,4 +80,8 @@ export namespace DateHelper { const endTime = dayjs(end, format); return endTime.diff(startTime, "minute"); }; + + export const toDayjs = (date: string): Dayjs => { + return date ? dayjs(date) : dayjs(); + }; } From 0966d53fd6202a8dc27d6045597ea055711344bf Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Wed, 30 Aug 2023 09:12:50 +0800 Subject: [PATCH 2/3] [MISC][RL] Barrel export date input helper --- src/date-input/date-input.tsx | 2 +- src/date-range-input/date-range-input.tsx | 3 +-- src/util/index.ts | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/date-input/date-input.tsx b/src/date-input/date-input.tsx index 566d59eff..7098a3cf5 100644 --- a/src/date-input/date-input.tsx +++ b/src/date-input/date-input.tsx @@ -10,7 +10,7 @@ import { StandaloneDateInputRef, } from "../shared/standalone-date-input/standalone-date-input"; import { MediaWidths } from "../spec/media-spec"; -import { DateInputHelper } from "../util/date-input-helper"; +import { DateInputHelper } from "../util"; import { Container } from "./date-input.style"; import { DateInputProps } from "./types"; diff --git a/src/date-range-input/date-range-input.tsx b/src/date-range-input/date-range-input.tsx index a1015a7ba..284891c03 100644 --- a/src/date-range-input/date-range-input.tsx +++ b/src/date-range-input/date-range-input.tsx @@ -13,8 +13,7 @@ import { StandaloneDateInput, StandaloneDateInputRef, } from "../shared/standalone-date-input/standalone-date-input"; -import { DateHelper } from "../util"; -import { DateInputHelper } from "../util/date-input-helper"; +import { DateHelper, DateInputHelper } from "../util"; import { useStateActions } from "../util/use-state-actions"; import { Container, diff --git a/src/util/index.ts b/src/util/index.ts index e1871da07..8ac77afd7 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -1,5 +1,6 @@ export * from "./calendar-helper"; export * from "./date-helper"; +export * from "./date-input-helper"; export * from "./simple-id-generator"; export * from "./string-helper"; export * from "./use-next-input-state"; From f513fcf6b27a7d9455b45d2f6af3eb871207cbea Mon Sep 17 00:00:00 2001 From: Quek Ruo Ling Date: Wed, 30 Aug 2023 09:41:04 +0800 Subject: [PATCH 3/3] [MISC][RL] Ignore invalid dates to avoid NaN display --- src/date-input/date-input.tsx | 13 +++++++++---- src/date-range-input/date-range-input.tsx | 5 ++++- src/util/date-input-helper.ts | 13 ++++++++++--- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/date-input/date-input.tsx b/src/date-input/date-input.tsx index 7098a3cf5..80e517d46 100644 --- a/src/date-input/date-input.tsx +++ b/src/date-input/date-input.tsx @@ -34,8 +34,12 @@ export const DateInput = ({ // ============================================================================= // CONST, STATE, REF // ============================================================================= - const [initialDate, setInitialDate] = useState(value); - const [selectedDate, setSelectedDate] = useState(value); + const [initialDate, setInitialDate] = useState( + DateInputHelper.sanitizeInput(value) + ); + const [selectedDate, setSelectedDate] = useState( + DateInputHelper.sanitizeInput(value) + ); const [hoveredDate, setHoveredDate] = useState(undefined); const [calendarOpen, setCalendarOpen] = useState(false); @@ -53,8 +57,9 @@ export const DateInput = ({ // EFFECTS // ============================================================================= useEffect(() => { - setInitialDate(value); - setSelectedDate(value); + const newValue = DateInputHelper.sanitizeInput(value); + setInitialDate(newValue); + setSelectedDate(newValue); }, [value]); // ============================================================================= diff --git a/src/date-range-input/date-range-input.tsx b/src/date-range-input/date-range-input.tsx index 284891c03..b5376448d 100644 --- a/src/date-range-input/date-range-input.tsx +++ b/src/date-range-input/date-range-input.tsx @@ -172,7 +172,10 @@ export const DateRangeInput = ({ // EFFECTS // ============================================================================= useEffect(() => { - actions.resetRange({ start: value, end: valueEnd }); + actions.resetRange({ + start: DateInputHelper.sanitizeInput(value), + end: DateInputHelper.sanitizeInput(valueEnd), + }); }, [value, valueEnd]); useEffect(() => { diff --git a/src/util/date-input-helper.ts b/src/util/date-input-helper.ts index 93ce2537a..942c9e706 100644 --- a/src/util/date-input-helper.ts +++ b/src/util/date-input-helper.ts @@ -1,7 +1,4 @@ import dayjs from "dayjs"; -import isBetween from "dayjs/plugin/isBetween"; - -dayjs.extend(isBetween); export namespace DateInputHelper { export const isDateDisabled = ( @@ -31,4 +28,14 @@ export namespace DateInputHelper { return false; }; + + export const sanitizeInput = (date: string): string => { + if (date) { + const day = dayjs(date); + if (day.isValid()) { + return date; + } + } + return ""; + }; }