Merge branch 'datepicker' into 'main'

Remove react-datepicker, add a custom Datepicker component

See merge request soapbox-pub/soapbox!3169
This commit is contained in:
Alex Gleason 2024-10-19 20:52:30 +00:00
commit 1a70afe98d
13 changed files with 81 additions and 355 deletions

View File

@ -80,7 +80,6 @@
"@types/path-browserify": "^1.0.0",
"@types/react": "^18.3.9",
"@types/react-color": "^3.0.6",
"@types/react-datepicker": "^4.4.2",
"@types/react-dom": "^18.3.0",
"@types/react-helmet": "^6.1.5",
"@types/react-motion": "^0.0.40",
@ -128,7 +127,6 @@
"qrcode.react": "^3.1.0",
"react": "^18.3.1",
"react-color": "^2.19.3",
"react-datepicker": "^4.8.0",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.11",
"react-helmet": "^6.1.0",

View File

@ -1,10 +1,10 @@
import React, { useMemo } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import IconButton from 'soapbox/components/icon-button';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { useInstance, useFeatures } from 'soapbox/hooks';
import { Datetime } from './ui/datetime/datetime';
const messages = defineMessages({
birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' },
previousMonth: { id: 'datepicker.previous_month', defaultMessage: 'Previous month' },
@ -28,7 +28,7 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
const minAge = instance.pleroma.metadata.birthday_min_age;
const maxDate = useMemo(() => {
if (!supportsBirthdays) return null;
if (!supportsBirthdays) return;
let maxDate = new Date();
maxDate = new Date(maxDate.getTime() - minAge * 1000 * 60 * 60 * 24 + maxDate.getTimezoneOffset() * 1000 * 60);
@ -36,7 +36,7 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
}, [minAge]);
const selected = useMemo(() => {
if (!supportsBirthdays || !value) return null;
if (!supportsBirthdays || !value) return;
const date = new Date(value);
return new Date(date.getTime() + (date.getTimezoneOffset() * 60000));
@ -44,85 +44,17 @@ const BirthdayInput: React.FC<IBirthdayInput> = ({ value, onChange, required })
if (!supportsBirthdays) return null;
const renderCustomHeader = ({
decreaseMonth,
increaseMonth,
prevMonthButtonDisabled,
nextMonthButtonDisabled,
decreaseYear,
increaseYear,
prevYearButtonDisabled,
nextYearButtonDisabled,
date,
}: {
decreaseMonth(): void;
increaseMonth(): void;
prevMonthButtonDisabled: boolean;
nextMonthButtonDisabled: boolean;
decreaseYear(): void;
increaseYear(): void;
prevYearButtonDisabled: boolean;
nextYearButtonDisabled: boolean;
date: Date;
}) => {
return (
<div className='flex flex-col gap-2'>
<div className='flex items-center justify-between'>
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-left.svg')}
onClick={decreaseMonth}
disabled={prevMonthButtonDisabled}
aria-label={intl.formatMessage(messages.previousMonth)}
title={intl.formatMessage(messages.previousMonth)}
/>
{intl.formatDate(date, { month: 'long' })}
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-right.svg')}
onClick={increaseMonth}
disabled={nextMonthButtonDisabled}
aria-label={intl.formatMessage(messages.nextMonth)}
title={intl.formatMessage(messages.nextMonth)}
/>
</div>
<div className='flex items-center justify-between'>
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-left.svg')}
onClick={decreaseYear}
disabled={prevYearButtonDisabled}
aria-label={intl.formatMessage(messages.previousYear)}
title={intl.formatMessage(messages.previousYear)}
/>
{intl.formatDate(date, { year: 'numeric' })}
<IconButton
className='datepicker__button rtl:rotate-180'
src={require('@tabler/icons/outline/chevron-right.svg')}
onClick={increaseYear}
disabled={nextYearButtonDisabled}
aria-label={intl.formatMessage(messages.nextYear)}
title={intl.formatMessage(messages.nextYear)}
/>
</div>
</div>
);
};
const handleChange = (date: Date) => onChange(date ? new Date(date.getTime() - (date.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) : '');
return (
<div className='relative mt-1 rounded-md shadow-sm'>
<DatePicker
selected={selected}
wrapperClassName='react-datepicker-wrapper'
<Datetime
value={selected ?? new Date()}
onChange={handleChange}
placeholderText={intl.formatMessage(messages.birthdayPlaceholder)}
minDate={new Date('1900-01-01')}
maxDate={maxDate}
placeholder={intl.formatMessage(messages.birthdayPlaceholder)}
min={new Date('1900-01-01')}
max={maxDate}
required={required}
renderCustomHeader={renderCustomHeader}
isClearable={!required}
/>
</div>
);

View File

@ -0,0 +1,39 @@
import React from 'react';
import Input from '../input/input';
interface DatetimeProps {
value: Date;
onChange(date: Date): void;
min?: Date;
max?: Date;
placeholder?: string;
required?: boolean;
}
/**
* Date input with time.
*/
export const Datetime: React.FC<DatetimeProps> = ({ value, onChange, min, max, ...rest }) => {
return (
<Input
type='datetime-local'
onChange={(e) => onChange(new Date(e.target.value))}
value={formatDateLocal(value)}
min={min ? formatDateLocal(min) : undefined}
max={max ? formatDateLocal(max) : undefined}
{...rest}
/>
);
};
/** Format a Date object to 'YYYY-MM-DDTHH:MM' format, used by `<input type="datetime-local">` elements. */
function formatDateLocal(date: Date): string {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day}T${hours}:${minutes}`;
}

View File

@ -17,7 +17,7 @@ const messages = defineMessages({
/** Possible theme names for an Input. */
type InputThemes = 'normal' | 'search'
interface IInput extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'maxLength' | 'onChange' | 'onBlur' | 'type' | 'autoComplete' | 'autoCorrect' | 'autoCapitalize' | 'required' | 'disabled' | 'onClick' | 'readOnly' | 'min' | 'pattern' | 'onKeyDown' | 'onKeyUp' | 'onFocus' | 'style' | 'id'> {
interface IInput extends Pick<React.InputHTMLAttributes<HTMLInputElement>, 'maxLength' | 'onChange' | 'onBlur' | 'type' | 'autoComplete' | 'autoCorrect' | 'autoCapitalize' | 'required' | 'disabled' | 'onClick' | 'readOnly' | 'min' | 'max' | 'pattern' | 'onKeyDown' | 'onKeyUp' | 'onFocus' | 'style' | 'id'> {
/** Put the cursor into the input on mount. */
autoFocus?: boolean;
/** The initial text in the input. */

View File

@ -1,4 +0,0 @@
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
export default DatePicker;

View File

@ -1,24 +1,12 @@
import clsx from 'clsx';
import React, { Suspense } from 'react';
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { setSchedule, removeSchedule } from 'soapbox/actions/compose';
import IconButton from 'soapbox/components/icon-button';
import { HStack, Input, Stack, Text } from 'soapbox/components/ui';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { HStack, Stack, Text } from 'soapbox/components/ui';
import { Datetime } from 'soapbox/components/ui/datetime/datetime';
import { useAppDispatch, useCompose } from 'soapbox/hooks';
export const isCurrentOrFutureDate = (date: Date) => {
return date && new Date().setHours(0, 0, 0, 0) <= new Date(date).setHours(0, 0, 0, 0);
};
const isFiveMinutesFromNow = (time: Date) => {
const fiveMinutesFromNow = new Date(new Date().getTime() + 300000); // now, plus five minutes (Pleroma won't schedule posts )
const selectedDate = new Date(time);
return fiveMinutesFromNow.getTime() < selectedDate.getTime();
};
const messages = defineMessages({
schedule: { id: 'schedule.post_time', defaultMessage: 'Post Date/Time' },
remove: { id: 'schedule.remove', defaultMessage: 'Remove schedule' },
@ -35,6 +23,8 @@ const ScheduleForm: React.FC<IScheduleForm> = ({ composeId }) => {
const scheduledAt = useCompose(composeId).schedule;
const active = !!scheduledAt;
const fiveMinutesFromNow = new Date(new Date().getTime() + 300_000);
const onSchedule = (date: Date) => {
dispatch(setSchedule(composeId, date));
};
@ -54,22 +44,11 @@ const ScheduleForm: React.FC<IScheduleForm> = ({ composeId }) => {
<FormattedMessage id='datepicker.hint' defaultMessage='Scheduled to post at…' />
</Text>
<HStack space={2} alignItems='center'>
<Suspense fallback={<Input type='text' disabled />}>
<DatePicker
selected={scheduledAt}
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
onChange={onSchedule}
placeholderText={intl.formatMessage(messages.schedule)}
filterDate={isCurrentOrFutureDate}
filterTime={isFiveMinutesFromNow}
className={clsx({
'has-error': !isFiveMinutesFromNow(scheduledAt),
})}
/>
</Suspense>
<Datetime
onChange={onSchedule}
value={scheduledAt}
min={fiveMinutesFromNow}
/>
<IconButton
iconClassName='h-4 w-4'
className='bg-transparent text-gray-400 hover:text-gray-600'

View File

@ -22,9 +22,9 @@ import { ADDRESS_ICONS } from 'soapbox/components/autosuggest-location';
import LocationSearch from 'soapbox/components/location-search';
import { checkEventComposeContent } from 'soapbox/components/modal-root';
import { Button, Form, FormGroup, HStack, Icon, IconButton, Input, Modal, Spinner, Stack, Tabs, Text, Toggle } from 'soapbox/components/ui';
import { Datetime } from 'soapbox/components/ui/datetime/datetime';
import AccountContainer from 'soapbox/containers/account-container';
import { isCurrentOrFutureDate } from 'soapbox/features/compose/components/schedule-form';
import { ComposeEditor, DatePicker } from 'soapbox/features/ui/util/async-components';
import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import UploadButton from './upload-button';
@ -254,15 +254,10 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
<FormGroup
labelText={<FormattedMessage id='compose_event.fields.start_time_label' defaultMessage='Event start date' />}
>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventStartTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={startTime}
<Datetime
value={startTime}
onChange={onChangeStartTime}
placeholder={intl.formatMessage(messages.eventStartTimePlaceholder)}
/>
</FormGroup>
<HStack alignItems='center' space={2}>
@ -278,15 +273,10 @@ const ComposeEventModal: React.FC<IComposeEventModal> = ({ onClose }) => {
<FormGroup
labelText={<FormattedMessage id='compose_event.fields.end_time_label' defaultMessage='Event end date' />}
>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.eventEndTimePlaceholder)}
filterDate={isCurrentOrFutureDate}
selected={endTime}
<Datetime
value={endTime}
onChange={onChangeEndTime}
placeholder={intl.formatMessage(messages.eventEndTimePlaceholder)}
/>
</FormGroup>
)}

View File

@ -4,7 +4,7 @@ import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { closeModal } from 'soapbox/actions/modals';
import { useAnnouncements } from 'soapbox/api/hooks/admin/useAnnouncements';
import { Form, FormGroup, HStack, Modal, Stack, Text, Textarea, Toggle } from 'soapbox/components/ui';
import { DatePicker } from 'soapbox/features/ui/util/async-components';
import { Datetime } from 'soapbox/components/ui/datetime/datetime';
import { useAppDispatch } from 'soapbox/hooks';
import toast from 'soapbox/toast';
@ -30,15 +30,15 @@ const EditAnnouncementModal: React.FC<IEditAnnouncementModal> = ({ onClose, anno
const intl = useIntl();
const [content, setContent] = useState(announcement?.content || '');
const [startTime, setStartTime] = useState(announcement?.starts_at ? new Date(announcement.starts_at) : null);
const [endTime, setEndTime] = useState(announcement?.ends_at ? new Date(announcement.ends_at) : null);
const [startTime, setStartTime] = useState(announcement?.starts_at ? new Date(announcement.starts_at) : undefined);
const [endTime, setEndTime] = useState(announcement?.ends_at ? new Date(announcement.ends_at) : undefined);
const [allDay, setAllDay] = useState(announcement?.all_day || false);
const onChangeContent: React.ChangeEventHandler<HTMLTextAreaElement> = ({ target }) => setContent(target.value);
const onChangeStartTime = (date: Date | null) => setStartTime(date);
const onChangeStartTime = (date: Date | undefined) => setStartTime(date);
const onChangeEndTime = (date: Date | null) => setEndTime(date);
const onChangeEndTime = (date: Date | undefined) => setEndTime(date);
const onChangeAllDay: React.ChangeEventHandler<HTMLInputElement> = ({ target }) => setAllDay(target.checked);
@ -94,29 +94,19 @@ const EditAnnouncementModal: React.FC<IEditAnnouncementModal> = ({ onClose, anno
<FormGroup
labelText={<FormattedMessage id='admin.edit_announcement.fields.start_time_label' defaultMessage='Start date' />}
>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementStartTimePlaceholder)}
selected={startTime}
<Datetime
value={startTime ?? new Date()}
onChange={onChangeStartTime}
isClearable
placeholder={intl.formatMessage(messages.announcementStartTimePlaceholder)}
/>
</FormGroup>
<FormGroup
labelText={<FormattedMessage id='admin.edit_announcement.fields.end_time_label' defaultMessage='End date' />}
>
<DatePicker
showTimeSelect
dateFormat='MMMM d, yyyy h:mm aa'
timeIntervals={15}
wrapperClassName='react-datepicker-wrapper'
placeholderText={intl.formatMessage(messages.announcementEndTimePlaceholder)}
selected={endTime}
<Datetime
value={endTime ?? new Date()}
onChange={onChangeEndTime}
isClearable
placeholder={intl.formatMessage(messages.announcementEndTimePlaceholder)}
/>
</FormGroup>
<HStack alignItems='center' space={2}>

View File

@ -120,7 +120,6 @@ export const CreateApp = lazy(() => import('soapbox/features/developers/apps/cre
export const SettingsStore = lazy(() => import('soapbox/features/developers/settings-store'));
export const TestTimeline = lazy(() => import('soapbox/features/test-timeline'));
export const ServiceWorkerInfo = lazy(() => import('soapbox/features/developers/service-worker-info'));
export const DatePicker = lazy(() => import('soapbox/features/birthdays/date-picker'));
export const CompareHistoryModal = lazy(() => import('soapbox/features/ui/components/modals/compare-history-modal'));
export const AuthTokenList = lazy(() => import('soapbox/features/auth-token-list'));
export const FamiliarFollowersModal = lazy(() => import('soapbox/features/ui/components/modals/familiar-followers-modal'));

View File

@ -14,7 +14,6 @@ import '@fontsource/inter/700.css';
import '@fontsource/inter/900.css';
import '@fontsource/roboto-mono/400.css';
import 'line-awesome/dist/font-awesome-line-awesome/css/all.css';
import 'react-datepicker/dist/react-datepicker.css';
import 'soapbox/features/nostr/keys';
import './iframe';

View File

@ -28,4 +28,3 @@
@import 'components/icon';
@import 'forms';
@import 'utilities';
@import 'components/datepicker';

View File

@ -1,150 +0,0 @@
.react-datepicker {
@apply black:bg-black dark:bg-gray-900 dark:border-gray-700 p-4 font-sans text-xs text-gray-900 dark:text-gray-300 border border-solid border-gray-200 rounded-lg;
}
.react-datepicker__input-container > input {
@apply black:bg-black dark:bg-gray-900 dark:text-gray-100 block w-full sm:text-sm border-gray-400 dark:border-gray-800 rounded-md focus:ring-primary-500 focus:border-primary-500;
&.has-error {
@apply text-red-600 border-red-600;
}
}
.react-datepicker-popper[data-placement^='bottom'] .react-datepicker__triangle::before,
.react-datepicker-popper[data-placement^='bottom'] .react-datepicker__triangle::after {
@apply border-b-white dark:border-b-gray-900 black:border-b-black;
}
.react-datepicker-popper[data-placement^='bottom'] .react-datepicker__triangle::before {
@apply border-b-gray-200 dark:border-b-gray-700;
}
.react-datepicker__header:not(.react-datepicker__header--has-time-select) {
@apply rounded-tr-lg;
}
.react-datepicker__header {
@apply bg-white black:bg-black dark:bg-gray-900 border-b-0 py-1 px-0;
}
.react-datepicker__current-month,
.react-datepicker-time__header,
.react-datepicker-year-header {
@apply text-gray-900 dark:text-gray-300 font-bold text-sm;
}
.react-datepicker__current-month {
margin-top: 2px;
}
.react-datepicker__navigation {
@apply top-4 h-8 w-8 rounded hover:bg-gray-50 dark:hover:bg-gray-900/50;
}
.react-datepicker__navigation-icon {
margin-top: -3px;
}
.react-datepicker__navigation-icon--previous::before {
right: -5px;
}
.react-datepicker__navigation-icon--next::before {
left: -5px;
}
.react-datepicker__navigation--previous {
left: 16px;
}
.react-datepicker__navigation--next {
right: 16px;
&--with-time:not(.react-datepicker__navigation--next--with-today-button) {
right: 100px;
}
}
.react-datepicker__year-read-view--down-arrow,
.react-datepicker__month-read-view--down-arrow,
.react-datepicker__month-year-read-view--down-arrow,
.react-datepicker__navigation-icon::before {
border-width: 2px 2px 0 0;
height: 7px;
width: 7px;
top: 8px;
}
.react-datepicker__header__dropdown {
@apply py-4;
}
.react-datepicker__day-names,
.react-datepicker__week {
@apply flex justify-between;
}
.react-datepicker__time {
&-container & {
@apply dark:bg-gray-900 black:bg-black;
}
}
.react-datepicker__time-container {
@apply dark:border-gray-700 black:border-gray-800;
}
.react-datepicker__day-name,
.react-datepicker__day,
.react-datepicker__time-name {
@apply text-gray-900 dark:text-gray-300;
width: 30px;
height: 30px;
line-height: 30px;
}
.react-datepicker__time-list-item--disabled,
.react-datepicker__day--disabled {
@apply text-gray-400 dark:text-gray-500;
}
.react-datepicker__day:hover,
.react-datepicker__month-text:hover,
.react-datepicker__quarter-text:hover,
.react-datepicker__year-text:hover,
.react-datepicker__time-list-item:hover {
@apply bg-gray-100 dark:bg-gray-700 rounded;
}
.react-datepicker__day--selected,
.react-datepicker__day--in-selecting-range,
.react-datepicker__day--in-range,
.react-datepicker__month-text--selected,
.react-datepicker__month-text--in-selecting-range,
.react-datepicker__month-text--in-range,
.react-datepicker__quarter-text--selected,
.react-datepicker__quarter-text--in-selecting-range,
.react-datepicker__quarter-text--in-range,
.react-datepicker__year-text--selected,
.react-datepicker__year-text--in-selecting-range,
.react-datepicker__year-text--in-range {
@apply bg-primary-600 hover:bg-primary-700 dark:bg-gray-300 dark:hover:bg-gray-200 text-white dark:text-black rounded;
}
.react-datepicker__day--keyboard-selected,
.react-datepicker__month-text--keyboard-selected,
.react-datepicker__quarter-text--keyboard-selected,
.react-datepicker__year-text--keyboard-selected {
@apply bg-primary-50 hover:bg-primary-100 dark:bg-gray-700 dark:hover:bg-gray-600 text-primary-600 dark:text-primary-400;
}
.react-datepicker__close-icon {
@apply rtl:left-0 rtl:right-auto rtl:pr-0 rtl:pl-[6px];
}
.react-datepicker__close-icon::after {
@apply bg-transparent text-gray-600 dark:text-gray-400 text-base;
font-family: 'Font Awesome 5 Free';
content: '';
font-weight: 900;
}

View File

@ -1948,11 +1948,6 @@
"@parcel/watcher-win32-ia32" "2.4.1"
"@parcel/watcher-win32-x64" "2.4.1"
"@popperjs/core@^2.9.2":
version "2.11.5"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.5.tgz#db5a11bf66bdab39569719555b0f76e138d7bd64"
integrity sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==
"@reach/auto-id@0.18.0":
version "0.18.0"
resolved "https://registry.yarnpkg.com/@reach/auto-id/-/auto-id-0.18.0.tgz#4b97085cd1cf1360a9bedc6e9c78e97824014f0d"
@ -2648,16 +2643,6 @@
"@types/react" "*"
"@types/reactcss" "*"
"@types/react-datepicker@^4.4.2":
version "4.4.2"
resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.4.2.tgz#13ab25a5fff7f3da4c5380c471efd8b38f53010e"
integrity sha512-g8DhWvYmaIMLzVrIEVLXncylyImyBaoPsEUr3yR13JDaaHoebhDorqnVv4tLkNGa8SjBB8SAOQvxD5jaPNBX8A==
dependencies:
"@popperjs/core" "^2.9.2"
"@types/react" "*"
date-fns "^2.0.1"
react-popper "^2.2.5"
"@types/react-dom@^18.0.0", "@types/react-dom@^18.3.0":
version "18.3.0"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0"
@ -3705,7 +3690,7 @@ chrome-trace-event@^1.0.2:
resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac"
integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==
classnames@^2.2.5, classnames@^2.2.6:
classnames@^2.2.5:
version "2.3.1"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
@ -4057,11 +4042,6 @@ data-urls@^5.0.0:
whatwg-mimetype "^4.0.0"
whatwg-url "^14.0.0"
date-fns@^2.0.1, date-fns@^2.24.0:
version "2.28.0"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2"
integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==
debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.3.7:
version "4.3.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
@ -7232,18 +7212,6 @@ react-color@^2.19.3:
reactcss "^1.2.0"
tinycolor2 "^1.4.1"
react-datepicker@^4.8.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.8.0.tgz#11b8918d085a1ce4781eee4c8e4641b3cd592010"
integrity sha512-u69zXGHMpxAa4LeYR83vucQoUCJQ6m/WBsSxmUMu/M8ahTSVMMyiyQzauHgZA2NUr9y0FUgOAix71hGYUb6tvg==
dependencies:
"@popperjs/core" "^2.9.2"
classnames "^2.2.6"
date-fns "^2.24.0"
prop-types "^15.7.2"
react-onclickoutside "^6.12.0"
react-popper "^2.2.5"
react-dom@^18.3.1:
version "18.3.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
@ -7275,7 +7243,7 @@ react-event-listener@^0.6.0:
prop-types "^15.6.0"
warning "^4.0.1"
react-fast-compare@^3.0.1, react-fast-compare@^3.1.1:
react-fast-compare@^3.1.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
@ -7349,11 +7317,6 @@ react-motion@^0.5.2:
prop-types "^15.5.8"
raf "^3.1.0"
react-onclickoutside@^6.12.0:
version "6.12.1"
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz#92dddd28f55e483a1838c5c2930e051168c1e96b"
integrity sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q==
react-overlays@^0.9.0:
version "0.9.3"
resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-0.9.3.tgz#5bac8c1e9e7e057a125181dee2d784864dd62902"
@ -7366,14 +7329,6 @@ react-overlays@^0.9.0:
react-transition-group "^2.2.1"
warning "^3.0.0"
react-popper@^2.2.5:
version "2.3.0"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.3.0.tgz#17891c620e1320dce318bad9fede46a5f71c70ba"
integrity sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==
dependencies:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-property@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/react-property/-/react-property-2.0.2.tgz#d5ac9e244cef564880a610bc8d868bd6f60fdda6"
@ -8938,7 +8893,7 @@ warning@^3.0.0:
dependencies:
loose-envify "^1.0.0"
warning@^4.0.0, warning@^4.0.1, warning@^4.0.2:
warning@^4.0.0, warning@^4.0.1:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==