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 <gitstart-twenty@users.noreply.github.com>
Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Matheus <matheus_benini@hotmail.com>
This commit is contained in:
Lucas Bordeau 2024-04-16 16:58:08 +02:00 committed by GitHub
parent d63937ec6f
commit 19a3be7b1b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 261 additions and 122 deletions

View File

@ -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",

View File

@ -106,12 +106,14 @@ export const FieldInput = ({
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onClear={onSubmit}
/>
) : isFieldDate(fieldDefinition) ? (
<DateFieldInput
onEnter={onEnter}
onEscape={onEscape}
onClickOutside={onClickOutside}
onClear={onSubmit}
/>
) : isFieldNumber(fieldDefinition) ? (
<NumberFieldInput

View File

@ -1,7 +1,5 @@
import { useContext } from 'react';
import { isFieldDateTime } from '@/object-record/record-field/types/guards/isFieldDateTime';
import { FieldContext } from '../contexts/FieldContext';
// TODO: have a better clearable settings in metadata ?
@ -9,13 +7,9 @@ import { FieldContext } from '../contexts/FieldContext';
// Instead of passing it in the context
// See: https://github.com/twentyhq/twenty/issues/4403
export const useIsFieldClearable = (): boolean => {
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;
};

View File

@ -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 <DateDisplay value={fieldValue} />;
return <DateTimeDisplay value={fieldValue} />;
};

View File

@ -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<Date>) => {
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 (
<DateInput
hotkeyScope={hotkeyScope}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
value={dateValue}
clearable
onChange={handleChange}
onClear={handleClear}
/>
);
};

View File

@ -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 (
<DateInput
hotkeyScope={hotkeyScope}
onClickOutside={handleClickOutside}
onEnter={handleEnter}
onEscape={handleEscape}
value={dateValue}
clearable={clearable}
clearable
onChange={handleChange}
isDateTimeInput
onClear={handleClear}
/>
);
};

View File

@ -0,0 +1,13 @@
import { formatToHumanReadableDateTime } from '~/utils';
import { EllipsisDisplay } from './EllipsisDisplay';
type DateTimeDisplayProps = {
value: Date | string | null | undefined;
};
export const DateTimeDisplay = ({ value }: DateTimeDisplayProps) => (
<EllipsisDisplay>
{value && formatToHumanReadableDateTime(value)}
</EllipsisDisplay>
);

View File

@ -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<Date>,
) => void;
hotkeyScope: string;
clearable?: boolean;
onChange?: (newDate: Nullable<Date>) => 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}
/>
</StyledCalendarContainer>
</div>

View File

@ -16,6 +16,7 @@ export type LightIconButtonGroupProps = Pick<
iconButtons: {
Icon: IconComponent;
onClick?: (event: MouseEvent<any>) => void;
disabled?: boolean;
}[];
};

View File

@ -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 (
<StyledInputContainer>
@ -102,6 +116,7 @@ export const DateTimeInput = ({
isDateTimeInput ? ' and time' : ' (mm/dd/yyyy)'
}`}
value={value}
onChange={() => {}} // Prevent React warning
hasError={hasError}
/>
</StyledInputContainer>

View File

@ -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<HTMLDivElement>) => {
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 (
<StyledContainer>
<StyledContainer onKeyDown={handleKeyDown}>
<div className={clearable ? 'clearable ' : ''}>
<ReactDatePicker
open={true}
selected={internalDate}
value={dateFormatted}
openToDate={internalDate}
onChange={(newDate) => {
onChange?.(newDate);
}}
customInput={
<DateTimeInput
date={internalDate}
isDateTimeInput={isDateTimeInput}
onChange={onChange}
/>
}
onMonthChange={(newDate) => {
onChange?.(newDate);
}}
onYearChange={(newDate) => {
onChange?.(newDate);
}}
renderCustomHeader={({
decreaseMonth,
increaseMonth,
@ -345,7 +393,9 @@ export const InternalDatePicker = ({
onChange={onChange}
/>
<StyledCustomDatePickerHeader>
<TimeInput date={internalDate} onChange={onChange} />
{isDateTimeInput && (
<TimeInput date={internalDate} onChange={onChange} />
)}
<MonthAndYearDropdown date={internalDate} onChange={onChange} />
<LightIconButton
Icon={IconChevronLeft}
@ -360,9 +410,11 @@ export const InternalDatePicker = ({
disabled={nextMonthButtonDisabled}
/>
</StyledCustomDatePickerHeader>
<StyledMonthText>
{monthLabel} - {yearLabel}
</StyledMonthText>
</>
)}
customInput={<></>}
onSelect={(date: Date, event) => {
const dateUTC = DateTime.fromJSDate(date, {
zone: 'utc',
@ -374,8 +426,7 @@ export const InternalDatePicker = ({
onChange?.(dateUTC);
}
}}
onClickOutside={handleClickOutside}
></ReactDatePicker>
/>
</div>
{clearable && (
<StyledButtonContainer onClick={handleClear} isMenuOpen={false}>

View File

@ -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 = ({
<Dropdown
dropdownId={MONTH_AND_YEAR_DROPDOWN_ID}
dropdownHotkeyScope={{
scope: TableHotkeyScope.CellEditMode,
scope: MONTH_AND_YEAR_DROPDOWN_ID,
}}
dropdownPlacement="bottom-start"
clickableComponent={

View File

@ -0,0 +1,22 @@
import { IMask } from 'react-imask';
import { MAX_DATE } from '@/ui/input/components/internal/date/constants/MaxDate';
import { MIN_DATE } from '@/ui/input/components/internal/date/constants/MinDate';
export const DATE_BLOCKS = {
YYYY: {
mask: IMask.MaskedRange,
from: MIN_DATE.getFullYear(),
to: MAX_DATE.getFullYear(),
},
MM: {
mask: IMask.MaskedRange,
from: 1,
to: 12,
},
DD: {
mask: IMask.MaskedRange,
from: 1,
to: 31,
},
};

View File

@ -0,0 +1 @@
export const DATE_MASK = 'm`/d`/Y`'; // See https://imask.js.org/guide.html#masked-date

View File

@ -1,22 +1,7 @@
import { IMask } from 'react-imask';
import { DATE_BLOCKS } from '@/ui/input/components/internal/date/constants/DateBlocks';
import { TIME_BLOCKS } from '@/ui/input/components/internal/date/constants/TimeBlocks';
export const DATE_TIME_BLOCKS = {
YYYY: {
mask: IMask.MaskedRange,
from: 1970,
to: 2100,
},
MM: {
mask: IMask.MaskedRange,
from: 1,
to: 12,
},
DD: {
mask: IMask.MaskedRange,
from: 1,
to: 31,
},
...DATE_BLOCKS,
...TIME_BLOCKS,
};

View File

@ -1,3 +1,3 @@
import { TIME_MASK } from '@/ui/input/components/internal/date/constants/TimeMask';
export const DATE_TIME_MASK = `MM/DD/YYYY ${TIME_MASK}`;
export const DATE_TIME_MASK = `m\`/d\`/Y\` ${TIME_MASK}`;

View File

@ -0,0 +1 @@
export const MAX_DATE = new Date(2100, 11, 31);

View File

@ -0,0 +1 @@
export const MIN_DATE = new Date(1900, 0, 1);

View File

@ -9,6 +9,6 @@ export const TIME_BLOCKS = {
mm: {
mask: IMask.MaskedRange, // Use MaskedRange for valid minute range (0-59)
from: 0,
to: 61,
to: 59,
},
};

View File

@ -1 +1 @@
export const TIME_MASK = 'HH:mm'; // Define blocks for hours and minutes
export const TIME_MASK = 'HH`:mm`'; // Define blocks for hours and minutes

View File

@ -10,6 +10,18 @@ export const formatToHumanReadableDate = (date: Date | string) => {
}).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(/\/$/, '')

View File

@ -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: