From 19a3be7b1b1d8351414549c90d521e30b4a20324 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Tue, 16 Apr 2024 16:58:08 +0200 Subject: [PATCH] Date picker for Date and DateTime field input (#4981) - Implemented correct mask for Date and DateTime field in InternalDatePicker - Use only keyDown event and click outside in InternalDatePicker and DateInput - Refactored InternalDatePicker UI to have month and year displayed - Fixed bug and synchronized date value between the different inputs that can change it --------- Co-authored-by: gitstart-twenty Co-authored-by: v1b3m Co-authored-by: Matheus --- package.json | 4 +- .../record-field/components/FieldInput.tsx | 2 + .../record-field/hooks/useIsFieldClearable.ts | 10 +- .../components/DateTimeFieldDisplay.tsx | 4 +- .../input/components/DateFieldInput.tsx | 13 ++- .../input/components/DateTimeFieldInput.tsx | 13 ++- .../display/components/DateTimeDisplay.tsx | 13 +++ .../ui/field/input/components/DateInput.tsx | 47 +++++++--- .../components/LightIconButtonGroup.tsx | 1 + .../date/components/DateTimeInput.tsx | 39 +++++--- .../date/components/InternalDatePicker.tsx | 91 +++++++++++++++---- .../date/components/MonthAndYearDropdown.tsx | 3 +- .../internal/date/constants/DateBlocks.ts | 22 +++++ .../internal/date/constants/DateMask.ts | 1 + .../internal/date/constants/DateTimeBlocks.ts | 19 +--- .../internal/date/constants/DateTimeMask.ts | 2 +- .../internal/date/constants/MaxDate.ts | 1 + .../internal/date/constants/MinDate.ts | 1 + .../internal/date/constants/TimeBlocks.ts | 2 +- .../internal/date/constants/TimeMask.ts | 2 +- packages/twenty-front/src/utils/index.ts | 12 +++ yarn.lock | 81 +++++++++-------- 22 files changed, 261 insertions(+), 122 deletions(-) create mode 100644 packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx create mode 100644 packages/twenty-front/src/modules/ui/input/components/internal/date/constants/DateBlocks.ts create mode 100644 packages/twenty-front/src/modules/ui/input/components/internal/date/constants/DateMask.ts create mode 100644 packages/twenty-front/src/modules/ui/input/components/internal/date/constants/MaxDate.ts create mode 100644 packages/twenty-front/src/modules/ui/input/components/internal/date/constants/MinDate.ts diff --git a/package.json b/package.json index e5a44158a7..ba0e662f53 100644 --- a/package.json +++ b/package.json @@ -144,7 +144,7 @@ "qs": "^6.11.2", "react": "^18.2.0", "react-data-grid": "7.0.0-beta.13", - "react-datepicker": "^4.11.0", + "react-datepicker": "^6.7.1", "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", "react-error-boundary": "^4.0.11", @@ -252,7 +252,7 @@ "@types/passport-google-oauth20": "^2.0.11", "@types/passport-jwt": "^3.0.8", "@types/react": "^18.2.39", - "@types/react-datepicker": "^4.11.2", + "@types/react-datepicker": "^6.2.0", "@types/react-dom": "^18.2.15", "@types/scroll-into-view": "^1.16.0", "@types/supertest": "^2.0.11", 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 d2a28e6a77..841a90f7f3 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 @@ -106,12 +106,14 @@ export const FieldInput = ({ onEnter={onEnter} onEscape={onEscape} onClickOutside={onClickOutside} + onClear={onSubmit} /> ) : isFieldDate(fieldDefinition) ? ( ) : isFieldNumber(fieldDefinition) ? ( { - const { clearable, isLabelIdentifier, fieldDefinition } = - useContext(FieldContext); + const { clearable, isLabelIdentifier } = useContext(FieldContext); - const isDateField = isFieldDateTime(fieldDefinition); - - const fieldCanBeCleared = - !isLabelIdentifier && !isDateField && clearable !== false; + const fieldCanBeCleared = !isLabelIdentifier && clearable !== false; return fieldCanBeCleared; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx index cffbd0473c..54f8d0ecd5 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/display/components/DateTimeFieldDisplay.tsx @@ -1,9 +1,9 @@ -import { DateDisplay } from '@/ui/field/display/components/DateDisplay'; +import { DateTimeDisplay } from '@/ui/field/display/components/DateTimeDisplay'; import { useDateTimeField } from '../../hooks/useDateTimeField'; export const DateTimeFieldDisplay = () => { const { fieldValue } = useDateTimeField(); - return ; + return ; }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx index ea4406a42b..acc4dfff17 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx +++ b/packages/twenty-front/src/modules/object-record/record-field/meta-types/input/components/DateFieldInput.tsx @@ -2,6 +2,7 @@ import { Nullable } from 'twenty-ui'; import { useDateField } from '@/object-record/record-field/meta-types/hooks/useDateField'; import { DateInput } from '@/ui/field/input/components/DateInput'; +import { isDefined } from '~/utils/isDefined'; import { usePersistField } from '../../../hooks/usePersistField'; @@ -11,19 +12,21 @@ export type DateFieldInputProps = { onClickOutside?: FieldInputEvent; onEnter?: FieldInputEvent; onEscape?: FieldInputEvent; + onClear?: FieldInputEvent; }; export const DateFieldInput = ({ onEnter, onEscape, onClickOutside, + onClear, }: DateFieldInputProps) => { - const { fieldValue, hotkeyScope, setDraftValue } = useDateField(); + const { fieldValue, setDraftValue } = useDateField(); const persistField = usePersistField(); const persistDate = (newDate: Nullable) => { - if (!newDate) { + if (!isDefined(newDate)) { persistField(null); } else { const newDateISO = newDate?.toISOString(); @@ -51,17 +54,21 @@ export const DateFieldInput = ({ setDraftValue(newDate?.toDateString() ?? ''); }; + const handleClear = () => { + onClear?.(() => persistDate(null)); + }; + const dateValue = fieldValue ? new Date(fieldValue) : null; return ( ); }; 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 b3c2291ca4..15c6280ee9 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 @@ -11,15 +11,16 @@ export type DateTimeFieldInputProps = { onClickOutside?: FieldInputEvent; onEnter?: FieldInputEvent; onEscape?: FieldInputEvent; + onClear?: FieldInputEvent; }; export const DateTimeFieldInput = ({ onEnter, onEscape, onClickOutside, + onClear, }: DateTimeFieldInputProps) => { - const { fieldValue, hotkeyScope, clearable, setDraftValue } = - useDateTimeField(); + const { fieldValue, setDraftValue } = useDateTimeField(); const persistField = usePersistField(); @@ -52,18 +53,22 @@ export const DateTimeFieldInput = ({ setDraftValue(newDate?.toDateString() ?? ''); }; + const handleClear = () => { + onClear?.(() => persistDate(null)); + }; + const dateValue = fieldValue ? new Date(fieldValue) : null; return ( ); }; diff --git a/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx new file mode 100644 index 0000000000..d1381489e0 --- /dev/null +++ b/packages/twenty-front/src/modules/ui/field/display/components/DateTimeDisplay.tsx @@ -0,0 +1,13 @@ +import { formatToHumanReadableDateTime } from '~/utils'; + +import { EllipsisDisplay } from './EllipsisDisplay'; + +type DateTimeDisplayProps = { + value: Date | string | null | undefined; +}; + +export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => ( + + {value && formatToHumanReadableDateTime(value)} + +); diff --git a/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx b/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx index 89b039ad5e..d1dce3f3d9 100644 --- a/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx +++ b/packages/twenty-front/src/modules/ui/field/input/components/DateInput.tsx @@ -4,9 +4,15 @@ import styled from '@emotion/styled'; import { flip, offset, useFloating } from '@floating-ui/react'; import { Nullable } from 'twenty-ui'; -import { useRegisterInputEvents } from '@/object-record/record-field/meta-types/input/hooks/useRegisterInputEvents'; import { DateDisplay } from '@/ui/field/display/components/DateDisplay'; import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker'; +import { + MONTH_AND_YEAR_DROPDOWN_ID, + MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID, + MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID, +} from '@/ui/input/components/internal/date/components/MonthAndYearDropdown'; +import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; +import { useListenClickOutsideV2 } from '@/ui/utilities/pointer-event/hooks/useListenClickOutsideV2'; const StyledCalendarContainer = styled.div` background: ${({ theme }) => theme.background.secondary}; @@ -33,21 +39,21 @@ export type DateInputProps = { event: MouseEvent | TouchEvent, newDate: Nullable, ) => void; - hotkeyScope: string; clearable?: boolean; onChange?: (newDate: Nullable) => void; isDateTimeInput?: boolean; + onClear?: () => void; }; export const DateInput = ({ value, onEnter, onEscape, - hotkeyScope, onClickOutside, clearable, onChange, isDateTimeInput, + onClear, }: DateInputProps) => { const theme = useTheme(); @@ -70,13 +76,30 @@ export const DateInput = ({ onChange?.(newDate); }; - useRegisterInputEvents({ - inputRef: wrapperRef, - inputValue: internalValue, - onEnter, - onEscape, - onClickOutside, - hotkeyScope, + const handleClear = () => { + setInternalValue(null); + onClear?.(); + }; + + const { closeDropdown } = useDropdown(MONTH_AND_YEAR_DROPDOWN_ID); + const { closeDropdown: closeDropdownMonthSelect } = useDropdown( + MONTH_AND_YEAR_DROPDOWN_MONTH_SELECT_ID, + ); + const { closeDropdown: closeDropdownYearSelect } = useDropdown( + MONTH_AND_YEAR_DROPDOWN_YEAR_SELECT_ID, + ); + + useListenClickOutsideV2({ + refs: [wrapperRef], + listenerId: 'DateInput', + callback: (event) => { + event.stopImmediatePropagation(); + + closeDropdownYearSelect(); + closeDropdownMonthSelect(); + closeDropdown(); + onClickOutside(event, internalValue); + }, }); return ( @@ -96,7 +119,9 @@ export const DateInput = ({ }} clearable={clearable ? clearable : false} isDateTimeInput={isDateTimeInput} - onClickOutside={onClickOutside} + onEnter={onEnter} + onEscape={onEscape} + onClear={handleClear} /> diff --git a/packages/twenty-front/src/modules/ui/input/button/components/LightIconButtonGroup.tsx b/packages/twenty-front/src/modules/ui/input/button/components/LightIconButtonGroup.tsx index f1369cbf99..fd3f20ce15 100644 --- a/packages/twenty-front/src/modules/ui/input/button/components/LightIconButtonGroup.tsx +++ b/packages/twenty-front/src/modules/ui/input/button/components/LightIconButtonGroup.tsx @@ -16,6 +16,7 @@ export type LightIconButtonGroupProps = Pick< iconButtons: { Icon: IconComponent; onClick?: (event: MouseEvent) => void; + disabled?: boolean; }[]; }; 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 f4b33aca36..cc1ccbd4ea 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 @@ -1,10 +1,14 @@ -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { useIMask } from 'react-imask'; import styled from '@emotion/styled'; import { DateTime } from 'luxon'; +import { DATE_BLOCKS } from '@/ui/input/components/internal/date/constants/DateBlocks'; +import { DATE_MASK } from '@/ui/input/components/internal/date/constants/DateMask'; import { DATE_TIME_BLOCKS } from '@/ui/input/components/internal/date/constants/DateTimeBlocks'; import { DATE_TIME_MASK } from '@/ui/input/components/internal/date/constants/DateTimeMask'; +import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate'; +import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate'; const StyledInputContainer = styled.div` width: 100%; @@ -37,20 +41,27 @@ export const DateTimeInput = ({ onChange, isDateTimeInput, }: DateTimeInputProps) => { + const parsingFormat = isDateTimeInput ? 'MM/dd/yyyy HH:mm' : 'MM/dd/yyyy'; + const [hasError, setHasError] = useState(false); - const parseDateToString = (date: any) => { - const dateParsed = DateTime.fromJSDate(date); + const parseDateToString = useCallback( + (date: any) => { + const dateParsed = DateTime.fromJSDate(date); - const formattedDate = dateParsed.toFormat('MM/dd/yyyy HH:mm'); + const formattedDate = dateParsed.toFormat(parsingFormat); - return formattedDate; - }; + return formattedDate; + }, + [parsingFormat], + ); const parseStringToDate = (str: string) => { setHasError(false); - const parsedDate = DateTime.fromFormat(str, 'MM/dd/yyyy HH:mm'); + const parsedDate = isDateTimeInput + ? DateTime.fromFormat(str, parsingFormat) + : DateTime.fromFormat(str, parsingFormat, { zone: 'utc' }); const isValid = parsedDate.isValid; @@ -65,13 +76,16 @@ export const DateTimeInput = ({ return jsDate; }; + const pattern = isDateTimeInput ? DATE_TIME_MASK : DATE_MASK; + const blocks = isDateTimeInput ? DATE_TIME_BLOCKS : DATE_BLOCKS; + const { ref, setValue, value } = useIMask( { mask: Date, - pattern: DATE_TIME_MASK, - blocks: DATE_TIME_BLOCKS, - min: new Date(1970, 0, 1), - max: new Date(2100, 0, 1), + pattern, + blocks, + min: MIN_DATE, + max: MAX_DATE, format: parseDateToString, parse: parseStringToDate, lazy: false, @@ -91,7 +105,7 @@ export const DateTimeInput = ({ useEffect(() => { setValue(parseDateToString(date)); - }, [date, setValue]); + }, [date, setValue, parseDateToString]); return ( @@ -102,6 +116,7 @@ export const DateTimeInput = ({ isDateTimeInput ? ' and time' : ' (mm/dd/yyyy)' }`} value={value} + onChange={() => {}} // Prevent React warning hasError={hasError} /> 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 28b4ecb4fc..7bc43b8668 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 @@ -1,6 +1,7 @@ import ReactDatePicker from 'react-datepicker'; import styled from '@emotion/styled'; import { DateTime } from 'luxon'; +import { Key } from 'ts-key-enum'; import { IconCalendarX, IconChevronLeft, IconChevronRight } from 'twenty-ui'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; @@ -16,6 +17,7 @@ import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown'; import { MenuItemLeftContent } from '@/ui/navigation/menu-item/internals/components/MenuItemLeftContent'; import { StyledHoverableMenuItemBase } from '@/ui/navigation/menu-item/internals/components/StyledMenuItemBase'; import { OVERLAY_BACKGROUND } from '@/ui/theme/constants/OverlayBackground'; +import { isDefined } from '~/utils/isDefined'; import 'react-datepicker/dist/react-datepicker.css'; @@ -37,6 +39,10 @@ const StyledContainer = styled.div` padding: 0 !important; } + & .react-datepicker__triangle { + display: none; + } + & .react-datepicker__triangle::after { display: none; } @@ -259,7 +265,7 @@ const StyledButton = styled(MenuItemLeftContent)` const StyledCustomDatePickerHeader = styled.div` align-items: center; display: flex; - justify-content: space-between; + justify-content: flex-end; padding-left: ${({ theme }) => theme.spacing(2)}; padding-right: ${({ theme }) => theme.spacing(2)}; padding-top: ${({ theme }) => theme.spacing(2)}; @@ -267,29 +273,40 @@ const StyledCustomDatePickerHeader = styled.div` gap: ${({ theme }) => theme.spacing(1)}; `; +const StyledMonthText = styled.div` + color: ${({ theme }) => theme.font.color.secondary}; + font-family: ${({ theme }) => theme.font.family}; + font-size: ${({ theme }) => theme.font.size.md}; + padding: ${({ theme }) => theme.spacing(2)}; +`; + export type InternalDatePickerProps = { date: Date; onMouseSelect?: (date: Date | null) => void; onChange?: (date: Date | null) => void; clearable?: boolean; isDateTimeInput?: boolean; - onClickOutside?: (event: MouseEvent | TouchEvent, date: Date | null) => void; + onEnter?: (date: Date | null) => void; + onEscape?: (date: Date | null) => void; + keyboardEventsDisabled?: boolean; + onClear?: () => void; }; -const PICKER_DATE_FORMAT = 'MM/dd/yyyy'; - export const InternalDatePicker = ({ date, onChange, onMouseSelect, + onEnter, + onEscape, clearable = true, isDateTimeInput, - onClickOutside, + keyboardEventsDisabled, + onClear, }: InternalDatePickerProps) => { const internalDate = date ?? new Date(); - const dateFormatted = - DateTime.fromJSDate(internalDate).toFormat(PICKER_DATE_FORMAT); + const monthLabel = DateTime.fromJSDate(internalDate).toFormat('LLLL'); + const yearLabel = DateTime.fromJSDate(internalDate).toFormat('yyyy'); const { closeDropdown } = useDropdown(MONTH_AND_YEAR_DROPDOWN_ID); const { closeDropdown: closeDropdownMonthSelect } = useDropdown( @@ -301,7 +318,7 @@ export const InternalDatePicker = ({ const handleClear = () => { closeDropdowns(); - onMouseSelect?.(null); + onClear?.(); }; const closeDropdowns = () => { @@ -310,28 +327,59 @@ export const InternalDatePicker = ({ closeDropdown(); }; - const handleClickOutside = (event: any) => { - closeDropdowns(); - onClickOutside?.(event, internalDate); - }; - const handleMouseSelect = (newDate: Date) => { closeDropdowns(); onMouseSelect?.(newDate); }; - // TODO: implement keyboard events here + const handleKeyDown = (event: React.KeyboardEvent) => { + if (isDefined(keyboardEventsDisabled) && keyboardEventsDisabled) { + return; + } + + switch (event.key) { + case Key.Enter: { + event.stopPropagation(); + event.preventDefault(); + + closeDropdowns(); + onEnter?.(internalDate); + break; + } + case Key.Escape: { + event.stopPropagation(); + event.preventDefault(); + + closeDropdowns(); + onEscape?.(internalDate); + break; + } + } + }; return ( - +
{ onChange?.(newDate); }} + customInput={ + + } + onMonthChange={(newDate) => { + onChange?.(newDate); + }} + onYearChange={(newDate) => { + onChange?.(newDate); + }} renderCustomHeader={({ decreaseMonth, increaseMonth, @@ -345,7 +393,9 @@ export const InternalDatePicker = ({ onChange={onChange} /> - + {isDateTimeInput && ( + + )} + + {monthLabel} - {yearLabel} + )} - customInput={<>} onSelect={(date: Date, event) => { const dateUTC = DateTime.fromJSDate(date, { zone: 'utc', @@ -374,8 +426,7 @@ export const InternalDatePicker = ({ onChange?.(dateUTC); } }} - onClickOutside={handleClickOutside} - > + />
{clearable && ( diff --git a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/MonthAndYearDropdown.tsx b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/MonthAndYearDropdown.tsx index d92abebd78..a07b65eb51 100644 --- a/packages/twenty-front/src/modules/ui/input/components/internal/date/components/MonthAndYearDropdown.tsx +++ b/packages/twenty-front/src/modules/ui/input/components/internal/date/components/MonthAndYearDropdown.tsx @@ -1,6 +1,5 @@ import { IconCalendarDue } from 'twenty-ui'; -import { TableHotkeyScope } from '@/object-record/record-table/types/TableHotkeyScope'; import { LightIconButton } from '@/ui/input/button/components/LightIconButton'; import { Select } from '@/ui/input/components/Select'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; @@ -57,7 +56,7 @@ export const MonthAndYearDropdown = ({ { }).format(parsedJSDate); }; +export const formatToHumanReadableDateTime = (date: Date | string) => { + const parsedJSDate = parseDate(date).toJSDate(); + + return new Intl.DateTimeFormat(undefined, { + month: 'short', + day: 'numeric', + year: 'numeric', + hour: 'numeric', + minute: 'numeric', + }).format(parsedJSDate); +}; + export const sanitizeURL = (link: string | null | undefined) => { return link ? link.replace(/(https?:\/\/)|(www\.)/g, '').replace(/\/$/, '') diff --git a/yarn.lock b/yarn.lock index 22595c1ce1..ce3bbc7e7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5533,6 +5533,20 @@ __metadata: languageName: node linkType: hard +"@floating-ui/react@npm:^0.26.2": + version: 0.26.12 + resolution: "@floating-ui/react@npm:0.26.12" + dependencies: + "@floating-ui/react-dom": "npm:^2.0.0" + "@floating-ui/utils": "npm:^0.2.0" + tabbable: "npm:^6.0.0" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: f47e133b9fe5dd404886c4e69e760dc0d6ab30774de82b5547cba83d0cd6e7a3bb4c221587e115a3c0c466ac344578c3db78b5808b5acd70ae5d43d587de9fd1 + languageName: node + linkType: hard + "@floating-ui/react@npm:^0.26.4": version: 0.26.8 resolution: "@floating-ui/react@npm:0.26.8" @@ -5554,7 +5568,7 @@ __metadata: languageName: node linkType: hard -"@floating-ui/utils@npm:^0.2.1": +"@floating-ui/utils@npm:^0.2.0, @floating-ui/utils@npm:^0.2.1": version: 0.2.1 resolution: "@floating-ui/utils@npm:0.2.1" checksum: ee77756712cf5b000c6bacf11992ffb364f3ea2d0d51cc45197a7e646a17aeb86ea4b192c0b42f3fbb29487aee918a565e84f710b8c3645827767f406a6b4cc9 @@ -9791,7 +9805,7 @@ __metadata: languageName: node linkType: hard -"@popperjs/core@npm:^2.11.8, @popperjs/core@npm:^2.9.0, @popperjs/core@npm:^2.9.2": +"@popperjs/core@npm:^2.9.0": version: 2.11.8 resolution: "@popperjs/core@npm:2.11.8" checksum: 4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 @@ -16975,15 +16989,14 @@ __metadata: languageName: node linkType: hard -"@types/react-datepicker@npm:^4.11.2": - version: 4.19.5 - resolution: "@types/react-datepicker@npm:4.19.5" +"@types/react-datepicker@npm:^6.2.0": + version: 6.2.0 + resolution: "@types/react-datepicker@npm:6.2.0" dependencies: - "@popperjs/core": "npm:^2.9.2" + "@floating-ui/react": "npm:^0.26.2" "@types/react": "npm:*" - date-fns: "npm:^2.0.1" - react-popper: "npm:^2.2.5" - checksum: 8b3402338e842a2d5c4d4c0ceefc9fc280607662d9073db860b59e31a3b3977eec6ec3d36b388ec5a3a3874adec00ab0f6a9405cd0de1f8dcf75de3328a84eb8 + date-fns: "npm:^3.3.1" + checksum: 40342f0a5e15bac6f2b35072a2f7041db20b924692123aface78f2cbf0e896c0c02c299a9173583e01e5b6dad38e3da86ad0e56e943e74e0c0dc7d5c60129bdf languageName: node linkType: hard @@ -22376,7 +22389,7 @@ __metadata: languageName: node linkType: hard -"clsx@npm:^2.0.0": +"clsx@npm:^2.0.0, clsx@npm:^2.1.0": version: 2.1.0 resolution: "clsx@npm:2.1.0" checksum: c09c00ad14f638366ca814097e6cab533dfa1972a358da5b557be487168acbb25b4c1395e89ffa842a8a61ba87a462d2b4885bc9d4f8410b598f3cb339599cdb @@ -23986,7 +23999,7 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:^2.0.1, date-fns@npm:^2.30.0": +"date-fns@npm:^2.30.0": version: 2.30.0 resolution: "date-fns@npm:2.30.0" dependencies: @@ -23995,6 +24008,13 @@ __metadata: languageName: node linkType: hard +"date-fns@npm:^3.3.1": + version: 3.6.0 + resolution: "date-fns@npm:3.6.0" + checksum: 0b5fb981590ef2f8e5a3ba6cd6d77faece0ea7f7158948f2eaae7bbb7c80a8f63ae30b01236c2923cf89bb3719c33aeb150c715ea4fe4e86e37dcf06bed42fb6 + languageName: node + linkType: hard + "dateformat@npm:^4.5.0": version: 4.6.3 resolution: "dateformat@npm:4.6.3" @@ -40815,20 +40835,19 @@ __metadata: languageName: node linkType: hard -"react-datepicker@npm:^4.11.0": - version: 4.25.0 - resolution: "react-datepicker@npm:4.25.0" +"react-datepicker@npm:^6.7.1": + version: 6.7.1 + resolution: "react-datepicker@npm:6.7.1" dependencies: - "@popperjs/core": "npm:^2.11.8" - classnames: "npm:^2.2.6" - date-fns: "npm:^2.30.0" + "@floating-ui/react": "npm:^0.26.2" + clsx: "npm:^2.1.0" + date-fns: "npm:^3.3.1" prop-types: "npm:^15.7.2" react-onclickoutside: "npm:^6.13.0" - react-popper: "npm:^2.3.0" peerDependencies: react: ^16.9.0 || ^17 || ^18 react-dom: ^16.9.0 || ^17 || ^18 - checksum: 714fc6cffdf9fa76d1a74581375acb4c86ac81e6c2cde372448ab447370b7e9ffb1840cf388020485028e7b0f43edf82c1cfd2dab7d2c6b964cdd6f4dd560e92 + checksum: 9029c358254ef011e3a6b82fd542a87efa30a67b7aa2814178d28354e2b18f69b863861fb852f236a91be57a0b684455c9127c87232b7ed2f4fae6737e3248e6 languageName: node linkType: hard @@ -40957,7 +40976,7 @@ __metadata: languageName: node linkType: hard -"react-fast-compare@npm:3.2.2, react-fast-compare@npm:^3.0.1, react-fast-compare@npm:^3.2.0, react-fast-compare@npm:^3.2.2": +"react-fast-compare@npm:3.2.2, react-fast-compare@npm:^3.2.0, react-fast-compare@npm:^3.2.2": version: 3.2.2 resolution: "react-fast-compare@npm:3.2.2" checksum: 0bbd2f3eb41ab2ff7380daaa55105db698d965c396df73e6874831dbafec8c4b5b08ba36ff09df01526caa3c61595247e3269558c284e37646241cba2b90a367 @@ -41157,20 +41176,6 @@ __metadata: languageName: node linkType: hard -"react-popper@npm:^2.2.5, react-popper@npm:^2.3.0": - version: 2.3.0 - resolution: "react-popper@npm:2.3.0" - dependencies: - react-fast-compare: "npm:^3.0.1" - warning: "npm:^4.0.2" - peerDependencies: - "@popperjs/core": ^2.0.0 - react: ^16.8.0 || ^17 || ^18 - react-dom: ^16.8.0 || ^17 || ^18 - checksum: 23f93540537ca4c035425bb8d5e51b11131fbc921d7ac1d041d0ae557feac8c877f3a012d36b94df8787803f52ed81e6df9257ac9e58719875f7805518d6db3f - languageName: node - linkType: hard - "react-query@npm:^3.34.19": version: 3.39.3 resolution: "react-query@npm:3.39.3" @@ -45046,7 +45051,7 @@ __metadata: languageName: node linkType: hard -"tabbable@npm:^6.0.1, tabbable@npm:^6.2.0": +"tabbable@npm:^6.0.0, tabbable@npm:^6.0.1, tabbable@npm:^6.2.0": version: 6.2.0 resolution: "tabbable@npm:6.2.0" checksum: ced8b38f05f2de62cd46836d77c2646c42b8c9713f5bd265daf0e78ff5ac73d3ba48a7ca45f348bafeef29b23da7187c72250742d37627883ef89cbd7fa76898 @@ -46222,7 +46227,7 @@ __metadata: "@types/passport-google-oauth20": "npm:^2.0.11" "@types/passport-jwt": "npm:^3.0.8" "@types/react": "npm:^18.2.39" - "@types/react-datepicker": "npm:^4.11.2" + "@types/react-datepicker": "npm:^6.2.0" "@types/react-dom": "npm:^18.2.15" "@types/scroll-into-view": "npm:^1.16.0" "@types/supertest": "npm:^2.0.11" @@ -46346,7 +46351,7 @@ __metadata: raw-loader: "npm:^4.0.2" react: "npm:^18.2.0" react-data-grid: "npm:7.0.0-beta.13" - react-datepicker: "npm:^4.11.0" + react-datepicker: "npm:^6.7.1" react-dom: "npm:^18.2.0" react-dropzone: "npm:^14.2.3" react-error-boundary: "npm:^4.0.11" @@ -48240,7 +48245,7 @@ __metadata: languageName: node linkType: hard -"warning@npm:^4.0.2, warning@npm:^4.0.3": +"warning@npm:^4.0.3": version: 4.0.3 resolution: "warning@npm:4.0.3" dependencies: