Typescript, convert some components to functional
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
267ab4b153
commit
2943b91034
43 changed files with 480 additions and 6 deletions
Binary file not shown.
Binary file not shown.
|
@ -31,7 +31,7 @@ const getToken = (state: RootState, authType: string) => {
|
|||
const maybeParseJSON = (data: string) => {
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
} catch(Exception) {
|
||||
} catch (Exception) {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
|
Binary file not shown.
Binary file not shown.
51
app/soapbox/components/domain.tsx
Normal file
51
app/soapbox/components/domain.tsx
Normal file
|
@ -0,0 +1,51 @@
|
|||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { unblockDomain } from 'soapbox/actions/domain_blocks';
|
||||
|
||||
import IconButton from './icon_button';
|
||||
|
||||
const messages = defineMessages({
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
});
|
||||
|
||||
interface IDomain {
|
||||
domain: string,
|
||||
}
|
||||
|
||||
const Domain: React.FC<IDomain> = ({ domain }) => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
// const onBlockDomain = () => {
|
||||
// dispatch(openModal('CONFIRM', {
|
||||
// icon: require('@tabler/icons/icons/ban.svg'),
|
||||
// heading: <FormattedMessage id='confirmations.domain_block.heading' defaultMessage='Block {domain}' values={{ domain }} />,
|
||||
// message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
|
||||
// confirm: intl.formatMessage(messages.blockDomainConfirm),
|
||||
// onConfirm: () => dispatch(blockDomain(domain)),
|
||||
// }));
|
||||
// }
|
||||
|
||||
const handleDomainUnblock = () => {
|
||||
dispatch(unblockDomain(domain));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='domain'>
|
||||
<div className='domain__wrapper'>
|
||||
<span className='domain__domain-name'>
|
||||
<strong>{domain}</strong>
|
||||
</span>
|
||||
|
||||
<div className='domain__buttons'>
|
||||
<IconButton active src={require('@tabler/icons/icons/lock-open.svg')} title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={handleDomainUnblock} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Domain;
|
|
@ -278,7 +278,7 @@ class Dropdown extends React.PureComponent<IDropdown, IDropdownState> {
|
|||
onShiftClick(e);
|
||||
} else if (this.state.id === openDropdownId) {
|
||||
this.handleClose();
|
||||
} else if(onOpen) {
|
||||
} else if (onOpen) {
|
||||
const { top } = e.currentTarget.getBoundingClientRect();
|
||||
const placement: DropdownPlacement = top * 2 < innerHeight ? 'bottom' : 'top';
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,34 @@
|
|||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import AvatarOverlay from 'soapbox/components/avatar_overlay';
|
||||
import DisplayName from 'soapbox/components/display_name';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
|
||||
import type { Account as AccountEntity } from 'soapbox/types/entities';
|
||||
|
||||
interface IMovedNote {
|
||||
from: AccountEntity,
|
||||
to: AccountEntity,
|
||||
}
|
||||
|
||||
const MovedNote: React.FC<IMovedNote> = ({ from, to }) => {
|
||||
const displayNameHtml = { __html: from.display_name_html };
|
||||
|
||||
return (
|
||||
<div className='account__moved-note'>
|
||||
<div className='account__moved-note__message'>
|
||||
<div className='account__moved-note__icon-wrapper'><Icon src={require('feather-icons/dist/icons/briefcase.svg')} className='account__moved-note__icon' fixedWidth /></div>
|
||||
<FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi> }} />
|
||||
</div>
|
||||
|
||||
<NavLink to={`/@${to.acct}`} className='detailed-status__display-name'>
|
||||
<div className='detailed-status__display-avatar'><AvatarOverlay account={to} friend={from} /></div>
|
||||
<DisplayName account={to} />
|
||||
</NavLink>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MovedNote;
|
Binary file not shown.
Binary file not shown.
64
app/soapbox/features/birthdays/account.tsx
Normal file
64
app/soapbox/features/birthdays/account.tsx
Normal file
|
@ -0,0 +1,64 @@
|
|||
import React from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import Avatar from 'soapbox/components/avatar';
|
||||
import DisplayName from 'soapbox/components/display_name';
|
||||
import Icon from 'soapbox/components/icon';
|
||||
import Permalink from 'soapbox/components/permalink';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { makeGetAccount } from 'soapbox/selectors';
|
||||
|
||||
const messages = defineMessages({
|
||||
birthday: { id: 'account.birthday', defaultMessage: 'Born {date}' },
|
||||
});
|
||||
|
||||
const getAccount = makeGetAccount();
|
||||
|
||||
interface IAccount {
|
||||
accountId: string,
|
||||
fetchAccount: (id: string) => void,
|
||||
}
|
||||
|
||||
const Account: React.FC<IAccount> = ({ accountId, fetchAccount }) => {
|
||||
const intl = useIntl();
|
||||
const account = useAppSelector((state) => getAccount(state, accountId));
|
||||
|
||||
useEffect(() => {
|
||||
if (accountId && !account) {
|
||||
fetchAccount(accountId);
|
||||
}
|
||||
}, [accountId]);
|
||||
|
||||
if (!account) return null;
|
||||
|
||||
const birthday = account.get('birthday');
|
||||
if (!birthday) return null;
|
||||
|
||||
const formattedBirthday = intl.formatDate(birthday, { day: 'numeric', month: 'short', year: 'numeric' });
|
||||
|
||||
return (
|
||||
<div className='account'>
|
||||
<div className='account__wrapper'>
|
||||
<Permalink className='account__display-name' title={account.get('acct')} href={`/@${account.get('acct')}`} to={`/@${account.get('acct')}`}>
|
||||
<div className='account__display-name'>
|
||||
<div className='account__avatar-wrapper'><Avatar account={account} size={36} /></div>
|
||||
<DisplayName account={account} />
|
||||
|
||||
</div>
|
||||
</Permalink>
|
||||
<div
|
||||
className='account__birthday'
|
||||
title={intl.formatMessage(messages.birthday, {
|
||||
date: formattedBirthday,
|
||||
})}
|
||||
>
|
||||
<Icon src={require('@tabler/icons/icons/ballon.svg')} />
|
||||
{formattedBirthday}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Account;
|
Binary file not shown.
58
app/soapbox/features/blocks/index.tsx
Normal file
58
app/soapbox/features/blocks/index.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import { debounce } from 'lodash';
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { fetchBlocks, expandBlocks } from 'soapbox/actions/blocks';
|
||||
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||
import { Column, Spinner } from 'soapbox/components/ui';
|
||||
import AccountContainer from 'soapbox/containers/account_container';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },
|
||||
});
|
||||
|
||||
const handleLoadMore = debounce((dispatch) => {
|
||||
dispatch(expandBlocks());
|
||||
}, 300, { leading: true });
|
||||
|
||||
const Blocks: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const accountIds = useAppSelector((state) => state.user_lists.getIn(['blocks', 'items']));
|
||||
const hasMore = useAppSelector((state) => !!state.user_lists.getIn(['blocks', 'next']));
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(fetchBlocks());
|
||||
}, []);
|
||||
|
||||
if (!accountIds) {
|
||||
return (
|
||||
<Column>
|
||||
<Spinner />
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />;
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='blocks'
|
||||
onLoadMore={() => handleLoadMore(dispatch)}
|
||||
hasMore={hasMore}
|
||||
emptyMessage={emptyMessage}
|
||||
className='space-y-4'
|
||||
>
|
||||
{accountIds.map((id: string) =>
|
||||
<AccountContainer key={id} id={id} />,
|
||||
)}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export default Blocks;
|
Binary file not shown.
56
app/soapbox/features/bookmarks/index.tsx
Normal file
56
app/soapbox/features/bookmarks/index.tsx
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { debounce } from 'lodash';
|
||||
import React from 'react';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import SubNavigation from 'soapbox/components/sub_navigation';
|
||||
import { Column } from 'soapbox/components/ui';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from '../../actions/bookmarks';
|
||||
import StatusList from '../../components/status_list';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' },
|
||||
});
|
||||
|
||||
const handleLoadMore = debounce((dispatch) => {
|
||||
dispatch(expandBookmarkedStatuses());
|
||||
}, 300, { leading: true });
|
||||
|
||||
const Bookmarks: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const statusIds = useAppSelector((state) => state.status_lists.getIn(['bookmarks', 'items']));
|
||||
const isLoading = useAppSelector((state) => state.status_lists.getIn(['bookmarks', 'isLoading'], true));
|
||||
const hasMore = useAppSelector((state) => !!state.status_lists.getIn(['bookmarks', 'next']));
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(fetchBookmarkedStatuses());
|
||||
}, []);
|
||||
|
||||
const handleRefresh = () => {
|
||||
return dispatch(fetchBookmarkedStatuses());
|
||||
};
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.bookmarks' defaultMessage="You don't have any bookmarks yet. When you add one, it will show up here." />;
|
||||
|
||||
return (
|
||||
<Column transparent>
|
||||
<SubNavigation message={intl.formatMessage(messages.heading)} />
|
||||
<StatusList
|
||||
statusIds={statusIds}
|
||||
scrollKey={'bookmarked_statuses'}
|
||||
hasMore={hasMore}
|
||||
isLoading={isLoading}
|
||||
onLoadMore={() => handleLoadMore(dispatch)}
|
||||
onRefresh={handleRefresh}
|
||||
emptyMessage={emptyMessage}
|
||||
divideType='space'
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export default Bookmarks;
|
Binary file not shown.
Binary file not shown.
60
app/soapbox/features/domain_blocks/index.tsx
Normal file
60
app/soapbox/features/domain_blocks/index.tsx
Normal file
|
@ -0,0 +1,60 @@
|
|||
import { debounce } from 'lodash';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { fetchDomainBlocks, expandDomainBlocks } from 'soapbox/actions/domain_blocks';
|
||||
import Domain from 'soapbox/components/domain';
|
||||
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||
import { Spinner } from 'soapbox/components/ui';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
import Column from '../ui/components/column';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
});
|
||||
|
||||
const handleLoadMore = debounce((dispatch) => {
|
||||
dispatch(expandDomainBlocks());
|
||||
}, 300, { leading: true });
|
||||
|
||||
const DomainBlocks: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const domains = useAppSelector((state) => state.domain_lists.getIn(['blocks', 'items'])) as string[];
|
||||
const hasMore = useAppSelector((state) => !!state.domain_lists.getIn(['blocks', 'next']));
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(fetchDomainBlocks());
|
||||
}, []);
|
||||
|
||||
if (!domains) {
|
||||
return (
|
||||
<Column>
|
||||
<Spinner />
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;
|
||||
|
||||
return (
|
||||
<Column icon='minus-circle' label={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='domain_blocks'
|
||||
onLoadMore={() => handleLoadMore(dispatch)}
|
||||
hasMore={hasMore}
|
||||
emptyMessage={emptyMessage}
|
||||
>
|
||||
{domains.map((domain) =>
|
||||
<Domain key={domain} domain={domain} />,
|
||||
)}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export default DomainBlocks;
|
Binary file not shown.
Binary file not shown.
58
app/soapbox/features/mutes/index.tsx
Normal file
58
app/soapbox/features/mutes/index.tsx
Normal file
|
@ -0,0 +1,58 @@
|
|||
import { debounce } from 'lodash';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
import { fetchMutes, expandMutes } from 'soapbox/actions/mutes';
|
||||
import ScrollableList from 'soapbox/components/scrollable_list';
|
||||
import { Column, Spinner } from 'soapbox/components/ui';
|
||||
import AccountContainer from 'soapbox/containers/account_container';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.mutes', defaultMessage: 'Muted users' },
|
||||
});
|
||||
|
||||
const handleLoadMore = debounce((dispatch) => {
|
||||
dispatch(expandMutes());
|
||||
}, 300, { leading: true });
|
||||
|
||||
const Mutes: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const accountIds = useAppSelector((state) => state.user_lists.getIn(['mutes', 'items']));
|
||||
const hasMore = useAppSelector((state) => !!state.user_lists.getIn(['mutes', 'next']));
|
||||
|
||||
React.useEffect(() => {
|
||||
dispatch(fetchMutes());
|
||||
}, []);
|
||||
|
||||
if (!accountIds) {
|
||||
return (
|
||||
<Column>
|
||||
<Spinner />
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)}>
|
||||
<ScrollableList
|
||||
scrollKey='mutes'
|
||||
onLoadMore={() => handleLoadMore(dispatch)}
|
||||
hasMore={hasMore}
|
||||
emptyMessage={emptyMessage}
|
||||
className='space-y-4'
|
||||
>
|
||||
{accountIds.map(id =>
|
||||
<AccountContainer key={id} id={id} />,
|
||||
)}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
export default Mutes;
|
|
@ -8,7 +8,8 @@ import { withRouter } from 'react-router-dom';
|
|||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||
import { Stack, Text } from 'soapbox/components/ui';
|
||||
import AccountContainer from 'soapbox/containers/account_container';
|
||||
import { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
const messages = defineMessages({
|
||||
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
66
app/soapbox/utils/auth.ts
Normal file
66
app/soapbox/utils/auth.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import { List as ImmutableList } from 'immutable';
|
||||
|
||||
import type { RootState } from 'soapbox/store';
|
||||
|
||||
export const validId = (id: any) => typeof id === 'string' && id !== 'null' && id !== 'undefined';
|
||||
|
||||
export const isURL = (url: string) => {
|
||||
try {
|
||||
new URL(url);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const parseBaseURL = (url: any) => {
|
||||
try {
|
||||
return new URL(url).origin;
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
export const getLoggedInAccount = (state: RootState) => {
|
||||
const me = state.me;
|
||||
return state.accounts.get(me);
|
||||
};
|
||||
|
||||
export const isLoggedIn = (getState: () => RootState) => {
|
||||
return validId(getState().me);
|
||||
};
|
||||
|
||||
export const getAppToken = (state: RootState) => state.auth.getIn(['app', 'access_token']);
|
||||
|
||||
export const getUserToken = (state: RootState, accountId?: string | false | null) => {
|
||||
const accountUrl = state.accounts.getIn([accountId, 'url']);
|
||||
return state.auth.getIn(['users', accountUrl, 'access_token']);
|
||||
};
|
||||
|
||||
export const getAccessToken = (state: RootState) => {
|
||||
const me = state.me;
|
||||
return getUserToken(state, me);
|
||||
};
|
||||
|
||||
export const getAuthUserId = (state: RootState) => {
|
||||
const me = state.auth.get('me');
|
||||
|
||||
return ImmutableList([
|
||||
state.auth.getIn(['users', me, 'id']),
|
||||
me,
|
||||
]).find(validId);
|
||||
};
|
||||
|
||||
export const getAuthUserUrl = (state: RootState) => {
|
||||
const me = state.auth.get('me');
|
||||
|
||||
return ImmutableList([
|
||||
state.auth.getIn(['users', me, 'url']),
|
||||
me,
|
||||
]).find(isURL);
|
||||
};
|
||||
|
||||
/** Get the VAPID public key. */
|
||||
export const getVapidKey = (state: RootState) => {
|
||||
return state.auth.getIn(['app', 'vapid_key']) || state.instance.getIn(['pleroma', 'vapid_public_key']);
|
||||
};
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
15
app/soapbox/utils/timelines.ts
Normal file
15
app/soapbox/utils/timelines.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import { Map as ImmutableMap } from 'immutable';
|
||||
|
||||
import type { Status as StatusEntity } from 'soapbox/types/entities';
|
||||
|
||||
export const shouldFilter = (status: StatusEntity, columnSettings: any) => {
|
||||
const shows = ImmutableMap({
|
||||
reblog: status.reblog !== null,
|
||||
reply: status.in_reply_to_id !== null,
|
||||
direct: status.visibility === 'direct',
|
||||
});
|
||||
|
||||
return shows.some((value, key) => {
|
||||
return columnSettings.getIn(['shows', key]) === false && value;
|
||||
});
|
||||
};
|
|
@ -75,6 +75,7 @@
|
|||
"@types/jest": "^27.4.1",
|
||||
"@types/lodash": "^4.14.180",
|
||||
"@types/qrcode.react": "^1.0.2",
|
||||
"@types/react-datepicker": "^4.4.0",
|
||||
"@types/react-helmet": "^6.1.5",
|
||||
"@types/react-motion": "^0.0.32",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
|
@ -145,7 +146,7 @@
|
|||
"qrcode.react": "^1.0.0",
|
||||
"react": "^16.13.1",
|
||||
"react-color": "^2.18.1",
|
||||
"react-datepicker": "^4.6.0",
|
||||
"react-datepicker": "^4.7.0",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-helmet": "^6.0.0",
|
||||
"react-hotkeys": "^1.1.4",
|
||||
|
|
14
yarn.lock
14
yarn.lock
|
@ -2171,6 +2171,16 @@
|
|||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-datepicker@^4.4.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-datepicker/-/react-datepicker-4.4.0.tgz#0072e18536ad305fd57786f9b6f9e499eed2b475"
|
||||
integrity sha512-wzmevaO51rLFwSZd5HSqBU0aAvZlRRkj6QhHqj0jfRDSKnN3y5IKXyhgxPS8R0LOWOtjdpirI1DBryjnIp/7gA==
|
||||
dependencies:
|
||||
"@popperjs/core" "^2.9.2"
|
||||
"@types/react" "*"
|
||||
date-fns "^2.0.1"
|
||||
react-popper "^2.2.5"
|
||||
|
||||
"@types/react-dom@*":
|
||||
version "17.0.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.14.tgz#c8f917156b652ddf807711f5becbd2ab018dea9f"
|
||||
|
@ -4006,7 +4016,7 @@ data-urls@^2.0.0:
|
|||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
|
||||
date-fns@^2.24.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==
|
||||
|
@ -8662,7 +8672,7 @@ react-color@^2.18.1:
|
|||
reactcss "^1.2.0"
|
||||
tinycolor2 "^1.4.1"
|
||||
|
||||
react-datepicker@^4.6.0:
|
||||
react-datepicker@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.7.0.tgz#75e03b0a6718b97b84287933307faf2ed5f03cf4"
|
||||
integrity sha512-FS8KgbwqpxmJBv/bUdA42MYqYZa+fEYcpc746DZiHvVE2nhjrW/dg7c5B5fIUuI8gZET6FOzuDgezNcj568Czw==
|
||||
|
|
Loading…
Reference in a new issue