diff --git a/app/soapbox/features/compose/components/search_results.js b/app/soapbox/features/compose/components/search_results.js deleted file mode 100644 index 05cbe26639..0000000000 Binary files a/app/soapbox/features/compose/components/search_results.js and /dev/null differ diff --git a/app/soapbox/features/compose/components/search_results.tsx b/app/soapbox/features/compose/components/search_results.tsx new file mode 100644 index 0000000000..1dc244920e --- /dev/null +++ b/app/soapbox/features/compose/components/search_results.tsx @@ -0,0 +1,187 @@ +import classNames from 'classnames'; +import React, { useEffect } from 'react'; +import { FormattedMessage } from 'react-intl'; +import { defineMessages, useIntl } from 'react-intl'; + +import { fetchTrendingStatuses } from 'soapbox/actions/trending_statuses'; +import ScrollableList from 'soapbox/components/scrollable_list'; +import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder_account'; +import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder_hashtag'; +import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder_status'; +import { useAppDispatch } from 'soapbox/hooks'; + +import Hashtag from '../../../components/hashtag'; +import { Tabs } from '../../../components/ui'; +import AccountContainer from '../../../containers/account_container'; +import StatusContainer from '../../../containers/status_container'; + +import type { Map as ImmutableMap, List as ImmutableList } from 'immutable'; + +const messages = defineMessages({ + accounts: { id: 'search_results.accounts', defaultMessage: 'People' }, + statuses: { id: 'search_results.statuses', defaultMessage: 'Posts' }, + hashtags: { id: 'search_results.hashtags', defaultMessage: 'Hashtags' }, +}); + +type SearchFilter = 'accounts' | 'statuses' | 'hashtags'; + +interface ISearchResults { + value: string, + results: ImmutableMap, + submitted: boolean, + expandSearch: (filter: SearchFilter) => void, + selectedFilter: SearchFilter, + selectFilter: (filter: SearchFilter) => void, + suggestions: ImmutableList, + trendingStatuses: ImmutableList, + trends: ImmutableList, +} + +/** Displays search results depending on the active tab. */ +const SearchResults: React.FC = ({ + value, + results, + submitted, + expandSearch, + selectedFilter, + selectFilter, + suggestions, + trendingStatuses, + trends, +}) => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + const handleLoadMore = () => expandSearch(selectedFilter); + const handleSelectFilter = (newActiveFilter: SearchFilter) => selectFilter(newActiveFilter); + + useEffect(() => { + dispatch(fetchTrendingStatuses()); + }, []); + + const renderFilterBar = () => { + const items = [ + { + text: intl.formatMessage(messages.accounts), + action: () => handleSelectFilter('accounts'), + name: 'accounts', + }, + { + text: intl.formatMessage(messages.statuses), + action: () => handleSelectFilter('statuses'), + name: 'statuses', + }, + { + text: intl.formatMessage(messages.hashtags), + action: () => handleSelectFilter('hashtags'), + name: 'hashtags', + }, + ]; + + return ; + }; + + let searchResults; + let hasMore = false; + let loaded; + let noResultsMessage; + let placeholderComponent: React.ComponentType = PlaceholderStatus; + + if (selectedFilter === 'accounts') { + hasMore = results.get('accountsHasMore'); + loaded = results.get('accountsLoaded'); + placeholderComponent = PlaceholderAccount; + + if (results.get('accounts') && results.get('accounts').size > 0) { + searchResults = results.get('accounts').map((accountId: string) => ); + } else if (!submitted && suggestions && !suggestions.isEmpty()) { + searchResults = suggestions.map(suggestion => ); + } else if (loaded) { + noResultsMessage = ( +
+ +
+ ); + } + } + + if (selectedFilter === 'statuses') { + hasMore = results.get('statusesHasMore'); + loaded = results.get('statusesLoaded'); + + if (results.get('statuses') && results.get('statuses').size > 0) { + searchResults = results.get('statuses').map((statusId: string) => ( + // @ts-ignore + + )); + } else if (!submitted && trendingStatuses && !trendingStatuses.isEmpty()) { + searchResults = trendingStatuses.map(statusId => ( + // @ts-ignore + + )); + } else if (loaded) { + noResultsMessage = ( +
+ +
+ ); + } + } + + if (selectedFilter === 'hashtags') { + hasMore = results.get('hashtagsHasMore'); + loaded = results.get('hashtagsLoaded'); + placeholderComponent = PlaceholderHashtag; + + if (results.get('hashtags') && results.get('hashtags').size > 0) { + searchResults = results.get('hashtags').map((hashtag: ImmutableMap) => ); + } else if (!submitted && suggestions && !suggestions.isEmpty()) { + searchResults = trends.map(hashtag => ); + } else if (loaded) { + noResultsMessage = ( +
+ +
+ ); + } + } + + return ( + <> + {renderFilterBar()} + + {noResultsMessage || ( + + {searchResults} + + )} + + ); +}; + +export default SearchResults;