kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Refactor: replace Immutable.js methods with plain JavaScript equivalents
rodzic
aac4798034
commit
f892cec183
|
@ -2,7 +2,6 @@ import backspaceIcon from '@tabler/icons/outline/backspace.svg';
|
||||||
import searchIcon from '@tabler/icons/outline/search.svg';
|
import searchIcon from '@tabler/icons/outline/search.svg';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { throttle } from 'es-toolkit';
|
import { throttle } from 'es-toolkit';
|
||||||
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
@ -26,7 +25,7 @@ interface ILocationSearch {
|
||||||
const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {
|
const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [locationIds, setLocationIds] = useState(ImmutableOrderedSet<string>());
|
const [locationIds, setLocationIds] = useState(new Set<string>());
|
||||||
const controller = useRef(new AbortController());
|
const controller = useRef(new AbortController());
|
||||||
|
|
||||||
const [value, setValue] = useState('');
|
const [value, setValue] = useState('');
|
||||||
|
@ -67,14 +66,14 @@ const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const clearResults = () => {
|
const clearResults = () => {
|
||||||
setLocationIds(ImmutableOrderedSet());
|
setLocationIds(new Set<string>());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleLocationSearch = useCallback(throttle(q => {
|
const handleLocationSearch = useCallback(throttle(q => {
|
||||||
dispatch(locationSearch(q, controller.current.signal))
|
dispatch(locationSearch(q, controller.current.signal))
|
||||||
.then((locations: { origin_id: string }[]) => {
|
.then((locations: { origin_id: string }[]) => {
|
||||||
const locationIds = locations.map(location => location.origin_id);
|
const locationIds = locations.map(location => location.origin_id);
|
||||||
setLocationIds(ImmutableOrderedSet(locationIds));
|
setLocationIds(new Set<string>(locationIds));
|
||||||
})
|
})
|
||||||
.catch(noOp);
|
.catch(noOp);
|
||||||
|
|
||||||
|
@ -93,7 +92,7 @@ const LocationSearch: React.FC<ILocationSearch> = ({ onSelected }) => {
|
||||||
placeholder={intl.formatMessage(messages.placeholder)}
|
placeholder={intl.formatMessage(messages.placeholder)}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
suggestions={locationIds.toList()}
|
suggestions={Array.from(locationIds)}
|
||||||
onSuggestionsFetchRequested={noOp}
|
onSuggestionsFetchRequested={noOp}
|
||||||
onSuggestionsClearRequested={noOp}
|
onSuggestionsClearRequested={noOp}
|
||||||
onSuggestionSelected={handleSelected}
|
onSuggestionSelected={handleSelected}
|
||||||
|
|
|
@ -156,7 +156,7 @@ const PollForm: React.FC<IPollForm> = ({ composeId }) => {
|
||||||
onChange={onChangeOption}
|
onChange={onChangeOption}
|
||||||
onRemove={onRemoveOption}
|
onRemove={onRemoveOption}
|
||||||
maxChars={maxOptionChars}
|
maxChars={maxOptionChars}
|
||||||
numOptions={options.size}
|
numOptions={options.length}
|
||||||
onRemovePoll={onRemovePoll}
|
onRemovePoll={onRemovePoll}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
@ -164,7 +164,7 @@ const PollForm: React.FC<IPollForm> = ({ composeId }) => {
|
||||||
<HStack space={2}>
|
<HStack space={2}>
|
||||||
<div className='w-6' />
|
<div className='w-6' />
|
||||||
|
|
||||||
{options.size < maxOptions && (
|
{options.length < maxOptions && (
|
||||||
<Button
|
<Button
|
||||||
theme='secondary'
|
theme='secondary'
|
||||||
onClick={handleAddOption}
|
onClick={handleAddOption}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import xIcon from '@tabler/icons/outline/x.svg';
|
import xIcon from '@tabler/icons/outline/x.svg';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
import { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
@ -21,7 +22,6 @@ import PlaceholderStatus from 'soapbox/features/placeholder/components/placehold
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||||
|
|
||||||
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
|
||||||
import type { VirtuosoHandle } from 'react-virtuoso';
|
import type { VirtuosoHandle } from 'react-virtuoso';
|
||||||
import type { SearchFilter } from 'soapbox/reducers/search.ts';
|
import type { SearchFilter } from 'soapbox/reducers/search.ts';
|
||||||
|
|
||||||
|
@ -198,7 +198,7 @@ const SearchResults = () => {
|
||||||
placeholderComponent = PlaceholderHashtag;
|
placeholderComponent = PlaceholderHashtag;
|
||||||
|
|
||||||
if (results.hashtags && results.hashtags.size > 0) {
|
if (results.hashtags && results.hashtags.size > 0) {
|
||||||
searchResults = results.hashtags.map(hashtag => <Hashtag key={hashtag.name} hashtag={hashtag} />);
|
searchResults = [...results.hashtags].map(hashtag => <Hashtag key={hashtag.name} hashtag={hashtag} />);
|
||||||
} else if (!submitted && suggestions && !suggestions.isEmpty()) {
|
} else if (!submitted && suggestions && !suggestions.isEmpty()) {
|
||||||
searchResults = trends.map(hashtag => <Hashtag key={hashtag.name} hashtag={hashtag} />);
|
searchResults = trends.map(hashtag => <Hashtag key={hashtag.name} hashtag={hashtag} />);
|
||||||
} else if (loaded) {
|
} else if (loaded) {
|
||||||
|
@ -236,7 +236,11 @@ const SearchResults = () => {
|
||||||
key={selectedFilter}
|
key={selectedFilter}
|
||||||
scrollKey={`${selectedFilter}:${value}`}
|
scrollKey={`${selectedFilter}:${value}`}
|
||||||
isLoading={submitted && !loaded}
|
isLoading={submitted && !loaded}
|
||||||
showLoading={submitted && !loaded && searchResults?.isEmpty()}
|
showLoading={submitted && !loaded && (
|
||||||
|
!searchResults ||
|
||||||
|
(Array.isArray(searchResults) && searchResults.length === 0) ||
|
||||||
|
(ImmutableOrderedSet.isOrderedSet(searchResults) && searchResults.size === 0)
|
||||||
|
)}
|
||||||
hasMore={hasMore}
|
hasMore={hasMore}
|
||||||
onLoadMore={handleLoadMore}
|
onLoadMore={handleLoadMore}
|
||||||
placeholderComponent={placeholderComponent}
|
placeholderComponent={placeholderComponent}
|
||||||
|
|
|
@ -42,7 +42,7 @@ const UploadForm: React.FC<IUploadForm> = ({ composeId, onSubmit }) => {
|
||||||
<div className='overflow-hidden'>
|
<div className='overflow-hidden'>
|
||||||
<UploadProgress composeId={composeId} />
|
<UploadProgress composeId={composeId} />
|
||||||
|
|
||||||
<HStack wrap className={clsx('overflow-hidden', mediaIds.size !== 0 && 'p-1')}>
|
<HStack wrap className={clsx('overflow-hidden', mediaIds.length !== 0 && 'p-1')}>
|
||||||
{mediaIds.map((id: string) => (
|
{mediaIds.map((id: string) => (
|
||||||
<Upload
|
<Upload
|
||||||
id={id}
|
id={id}
|
||||||
|
|
|
@ -15,7 +15,7 @@ const QuotedStatusContainer: React.FC<IQuotedStatusContainer> = ({ composeId })
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const getStatus = useCallback(makeGetStatus(), []);
|
const getStatus = useCallback(makeGetStatus(), []);
|
||||||
|
|
||||||
const status = useAppSelector(state => getStatus(state, { id: state.compose.get(composeId)?.quote! }));
|
const status = useAppSelector(state => getStatus(state, { id: state.compose[composeId]?.quote! }));
|
||||||
|
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
dispatch(cancelQuoteCompose());
|
dispatch(cancelQuoteCompose());
|
||||||
|
|
|
@ -14,8 +14,8 @@ const makeMapStateToProps = () => {
|
||||||
const getStatus = makeGetStatus();
|
const getStatus = makeGetStatus();
|
||||||
|
|
||||||
const mapStateToProps = (state: RootState, { composeId }: { composeId: string }) => {
|
const mapStateToProps = (state: RootState, { composeId }: { composeId: string }) => {
|
||||||
const statusId = state.compose.get(composeId)?.in_reply_to!;
|
const statusId = state.compose[composeId]?.in_reply_to!;
|
||||||
const editing = !!state.compose.get(composeId)?.id;
|
const editing = !!state.compose[composeId]?.id;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: (getStatus(state, { id: statusId }) as LegacyStatus)?.toJS() as StatusEntity,
|
status: (getStatus(state, { id: statusId }) as LegacyStatus)?.toJS() as StatusEntity,
|
||||||
|
|
|
@ -8,8 +8,8 @@ import type { IntlShape } from 'react-intl';
|
||||||
import type { AppDispatch, RootState } from 'soapbox/store.ts';
|
import type { AppDispatch, RootState } from 'soapbox/store.ts';
|
||||||
|
|
||||||
const mapStateToProps = (state: RootState, { composeId }: { composeId: string }) => ({
|
const mapStateToProps = (state: RootState, { composeId }: { composeId: string }) => ({
|
||||||
disabled: state.compose.get(composeId)?.is_uploading,
|
disabled: state.compose[composeId]?.is_uploading,
|
||||||
resetFileKey: state.compose.get(composeId)?.resetFileKey!,
|
resetFileKey: state.compose[composeId]?.resetFileKey!,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: AppDispatch, { composeId }: { composeId: string }) => ({
|
const mapDispatchToProps = (dispatch: AppDispatch, { composeId }: { composeId: string }) => ({
|
||||||
|
|
|
@ -94,7 +94,7 @@ const ComposeEditor = forwardRef<LexicalEditor, IComposeEditor>(({
|
||||||
theme,
|
theme,
|
||||||
editorState: dispatch((_, getState) => {
|
editorState: dispatch((_, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
const compose = state.compose.get(composeId);
|
const compose = state.compose[composeId];
|
||||||
|
|
||||||
if (!compose) return;
|
if (!compose) return;
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,7 @@ const AutosuggestPlugin = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSelectSuggestion = (index: number) => {
|
const onSelectSuggestion = (index: number) => {
|
||||||
const suggestion = suggestions.get(index) as AutoSuggestion;
|
const suggestion = suggestions[index] as AutoSuggestion;
|
||||||
|
|
||||||
editor.update(() => {
|
editor.update(() => {
|
||||||
dispatch((dispatch, getState) => {
|
dispatch((dispatch, getState) => {
|
||||||
|
@ -443,11 +443,11 @@ const AutosuggestPlugin = ({
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (suggestions && suggestions.size > 0) setSuggestionsHidden(false);
|
if (suggestions && suggestions.length > 0) setSuggestionsHidden(false);
|
||||||
}, [suggestions]);
|
}, [suggestions]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (resolution !== null && !suggestionsHidden && !suggestions.isEmpty()) {
|
if (resolution !== null && !suggestionsHidden && suggestions.length > 0) {
|
||||||
const handleClick = (event: MouseEvent) => {
|
const handleClick = (event: MouseEvent) => {
|
||||||
const target = event.target as HTMLElement;
|
const target = event.target as HTMLElement;
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ const AutosuggestPlugin = ({
|
||||||
|
|
||||||
return () => document.removeEventListener('click', handleClick);
|
return () => document.removeEventListener('click', handleClick);
|
||||||
}
|
}
|
||||||
}, [resolution, suggestionsHidden, suggestions.isEmpty()]);
|
}, [resolution, suggestionsHidden, suggestions.length === 0]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (resolution === null) return;
|
if (resolution === null) return;
|
||||||
|
@ -469,8 +469,8 @@ const AutosuggestPlugin = ({
|
||||||
KEY_ARROW_UP_COMMAND,
|
KEY_ARROW_UP_COMMAND,
|
||||||
(payload) => {
|
(payload) => {
|
||||||
const event = payload;
|
const event = payload;
|
||||||
if (suggestions !== null && suggestions.size && selectedSuggestion !== null) {
|
if (suggestions !== null && suggestions.length && selectedSuggestion !== null) {
|
||||||
const newSelectedSuggestion = selectedSuggestion !== 0 ? selectedSuggestion - 1 : suggestions.size - 1;
|
const newSelectedSuggestion = selectedSuggestion !== 0 ? selectedSuggestion - 1 : suggestions.length - 1;
|
||||||
setSelectedSuggestion(newSelectedSuggestion);
|
setSelectedSuggestion(newSelectedSuggestion);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
|
@ -483,8 +483,8 @@ const AutosuggestPlugin = ({
|
||||||
KEY_ARROW_DOWN_COMMAND,
|
KEY_ARROW_DOWN_COMMAND,
|
||||||
(payload) => {
|
(payload) => {
|
||||||
const event = payload;
|
const event = payload;
|
||||||
if (suggestions !== null && suggestions.size && selectedSuggestion !== null) {
|
if (suggestions !== null && suggestions.length && selectedSuggestion !== null) {
|
||||||
const newSelectedSuggestion = selectedSuggestion !== suggestions.size - 1 ? selectedSuggestion + 1 : 0;
|
const newSelectedSuggestion = selectedSuggestion !== suggestions.length - 1 ? selectedSuggestion + 1 : 0;
|
||||||
setSelectedSuggestion(newSelectedSuggestion);
|
setSelectedSuggestion(newSelectedSuggestion);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
|
@ -540,8 +540,8 @@ const AutosuggestPlugin = ({
|
||||||
<div
|
<div
|
||||||
className={clsx({
|
className={clsx({
|
||||||
'scroll-smooth snap-y snap-always will-change-scroll mt-6 overflow-y-auto max-h-56 relative w-max z-[1000] shadow bg-white dark:bg-gray-900 rounded-lg py-1 space-y-0 dark:ring-2 dark:ring-primary-700 focus:outline-none': true,
|
'scroll-smooth snap-y snap-always will-change-scroll mt-6 overflow-y-auto max-h-56 relative w-max z-[1000] shadow bg-white dark:bg-gray-900 rounded-lg py-1 space-y-0 dark:ring-2 dark:ring-primary-700 focus:outline-none': true,
|
||||||
hidden: suggestionsHidden || suggestions.isEmpty(),
|
hidden: suggestionsHidden || suggestions.length === 0,
|
||||||
block: !suggestionsHidden && !suggestions.isEmpty(),
|
block: !suggestionsHidden && suggestions.length > 0,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{suggestions.map(renderSuggestion)}
|
{suggestions.map(renderSuggestion)}
|
||||||
|
|
|
@ -42,7 +42,7 @@ const GroupTimeline: React.FC<IGroupTimeline> = (props) => {
|
||||||
|
|
||||||
const composeId = `group:${groupId}`;
|
const composeId = `group:${groupId}`;
|
||||||
const canComposeGroupStatus = !!account && group?.relationship?.member;
|
const canComposeGroupStatus = !!account && group?.relationship?.member;
|
||||||
const groupTimelineVisible = useAppSelector((state) => !!state.compose.get(composeId)?.group_timeline_visible);
|
const groupTimelineVisible = useAppSelector((state) => !!state.compose[composeId]?.group_timeline_visible);
|
||||||
const featuredStatusIds = useAppSelector((state) => getStatusIds(state, { type: `group:${group?.id}:pinned` }));
|
const featuredStatusIds = useAppSelector((state) => getStatusIds(state, { type: `group:${group?.id}:pinned` }));
|
||||||
|
|
||||||
const { isDragging, isDraggedOver } = useDraggedFiles(composer, (files) => {
|
const { isDragging, isDraggedOver } = useDraggedFiles(composer, (files) => {
|
||||||
|
|
|
@ -29,7 +29,7 @@ const Account: React.FC<IAccount> = ({ composeId, accountId, author }) => {
|
||||||
|
|
||||||
const compose = useCompose(composeId);
|
const compose = useCompose(composeId);
|
||||||
const { account } = useAccount(accountId);
|
const { account } = useAccount(accountId);
|
||||||
const added = !!account && compose.to?.includes(account.acct);
|
const added = !!account && Array.from(compose.to)?.includes(account.acct);
|
||||||
|
|
||||||
const onRemove = () => dispatch(removeFromMentions(composeId, accountId));
|
const onRemove = () => dispatch(removeFromMentions(composeId, accountId));
|
||||||
const onAdd = () => dispatch(addToMentions(composeId, accountId));
|
const onAdd = () => dispatch(addToMentions(composeId, accountId));
|
||||||
|
|
Ładowanie…
Reference in New Issue