From 742b1f2b58b50e6dc48c70a9907ef9357fa4b436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 24 Oct 2021 19:54:51 +0200 Subject: [PATCH] Use ScrollableList for search results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/actions/search.js | 5 +- .../compose/components/search_results.js | 124 ++++++++++-------- .../components/placeholder_hashtag.js | 20 +++ app/soapbox/reducers/search.js | 8 +- app/styles/placeholder.scss | 1 + 5 files changed, 100 insertions(+), 58 deletions(-) create mode 100644 app/soapbox/features/placeholder/components/placeholder_hashtag.js diff --git a/app/soapbox/actions/search.js b/app/soapbox/actions/search.js index 194f54e05..6f1621ad4 100644 --- a/app/soapbox/actions/search.js +++ b/app/soapbox/actions/search.js @@ -95,7 +95,7 @@ export const expandSearch = type => (dispatch, getState) => { const value = getState().getIn(['search', 'value']); const offset = getState().getIn(['search', 'results', type]).size; - dispatch(expandSearchRequest()); + dispatch(expandSearchRequest(type)); api(getState).get('/api/v2/search', { params: { @@ -119,8 +119,9 @@ export const expandSearch = type => (dispatch, getState) => { }); }; -export const expandSearchRequest = () => ({ +export const expandSearchRequest = (searchType) => ({ type: SEARCH_EXPAND_REQUEST, + searchType, }); export const expandSearchSuccess = (results, searchTerm, searchType) => ({ diff --git a/app/soapbox/features/compose/components/search_results.js b/app/soapbox/features/compose/components/search_results.js index 25dd43c7b..6e144d55d 100644 --- a/app/soapbox/features/compose/components/search_results.js +++ b/app/soapbox/features/compose/components/search_results.js @@ -6,12 +6,13 @@ import AccountContainer from '../../../containers/account_container'; import StatusContainer from '../../../containers/status_container'; import ImmutablePureComponent from 'react-immutable-pure-component'; import Hashtag from '../../../components/hashtag'; -import LoadingIndicator from 'soapbox/components/loading_indicator'; import FilterBar from '../../search/components/filter_bar'; -import LoadMore from '../../../components/load_more'; import BundleContainer from 'soapbox/features/ui/containers/bundle_container'; import { WhoToFollowPanel } from 'soapbox/features/ui/util/async-components'; -import classNames from 'classnames'; +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'; export default class SearchResults extends ImmutablePureComponent { @@ -32,13 +33,7 @@ export default class SearchResults extends ImmutablePureComponent { render() { const { value, results, submitted, selectedFilter, features } = this.props; - if (submitted && results.isEmpty()) { - return ( -
- -
- ); - } else if (features.suggestions && results.isEmpty()) { + if (!submitted && features.suggestions && results.isEmpty()) { return ( {Component => } @@ -48,68 +43,87 @@ export default class SearchResults extends ImmutablePureComponent { let searchResults; let hasMore = false; + let loaded; + let noResultsMessage; + let placeholderComponent = PlaceholderStatus; if (selectedFilter === 'accounts' && results.get('accounts')) { hasMore = results.get('accountsHasMore'); - - searchResults = results.get('accounts').size > 0 ? ( -
- {results.get('accounts').map(accountId => )} -
- ) : ( -
- -
- ); + loaded = results.get('accountsLoaded'); + placeholderComponent = PlaceholderAccount; + + if (results.get('accounts').size > 0) { + searchResults = results.get('accounts').map(accountId => ); + } else { + noResultsMessage = ( +
+ +
+ ); + } } if (selectedFilter === 'statuses' && results.get('statuses')) { hasMore = results.get('statusesHasMore'); - - searchResults = results.get('statuses').size > 0 ? ( -
- {results.get('statuses').map(statusId => )} -
- ) : ( -
- -
- ); + loaded = results.get('statusesLoaded'); + + if (results.get('statuses').size > 0) { + searchResults = results.get('statuses').map(statusId => ); + } else { + noResultsMessage = ( +
+ +
+ ); + } } if (selectedFilter === 'hashtags' && results.get('hashtags')) { hasMore = results.get('hashtagsHasMore'); - - searchResults = results.get('hashtags').size > 0 ? ( -
- {results.get('hashtags').map(hashtag => )} -
- ) : ( -
- -
- ); + loaded = results.get('hashtagsLoaded'); + placeholderComponent = PlaceholderHashtag; + + if (results.get('hashtags').size > 0) { + searchResults = results.get('hashtags').map(hashtag => ); + } else { + noResultsMessage = ( +
+ +
+ ); + } } return ( <> {submitted && } - {searchResults} - - {hasMore && } + {noResultsMessage || ( + + {searchResults} + + )} ); } diff --git a/app/soapbox/features/placeholder/components/placeholder_hashtag.js b/app/soapbox/features/placeholder/components/placeholder_hashtag.js new file mode 100644 index 000000000..66f11a479 --- /dev/null +++ b/app/soapbox/features/placeholder/components/placeholder_hashtag.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { generateText, randomIntFromInterval } from '../utils'; + +export default class PlaceholderHashtag extends React.Component { + + render() { + const length = randomIntFromInterval(15, 30); + + return ( +
+
+
+ {generateText(length)} +
+
+
+ ); + } + +} \ No newline at end of file diff --git a/app/soapbox/reducers/search.js b/app/soapbox/reducers/search.js index 104f7dc2d..d4c3f1a59 100644 --- a/app/soapbox/reducers/search.js +++ b/app/soapbox/reducers/search.js @@ -5,6 +5,7 @@ import { SEARCH_FETCH_SUCCESS, SEARCH_SHOW, SEARCH_FILTER_SET, + SEARCH_EXPAND_REQUEST, SEARCH_EXPAND_SUCCESS, } from '../actions/search'; import { @@ -28,7 +29,6 @@ export default function search(state = initialState, action) { case SEARCH_CHANGE: return state.withMutations(map => { map.set('value', action.value); - map.set('submitted', false); }); case SEARCH_CLEAR: return state.withMutations(map => { @@ -58,6 +58,9 @@ export default function search(state = initialState, action) { accountsHasMore: action.results.accounts.length >= 20, statusesHasMore: action.results.statuses.length >= 20, hashtagsHasMore: action.results.hashtags.length >= 20, + accountsLoaded: true, + statusesLoaded: true, + hashtagsLoaded: true, })).set('submitted', true).set('filter', action.results.accounts.length > 0 ? 'accounts' : action.results.statuses.length > 0 @@ -67,9 +70,12 @@ export default function search(state = initialState, action) { : 'accounts'); case SEARCH_FILTER_SET: return state.set('filter', action.value); + case SEARCH_EXPAND_REQUEST: + return state.setIn(['results', `${action.searchType}Loaded`], false); case SEARCH_EXPAND_SUCCESS: return state.withMutations((state) => { state.setIn(['results', `${action.searchType}HasMore`], action.results[action.searchType].length >= 20); + state.setIn(['results', `${action.searchType}Loaded`], true); state.updateIn(['results', action.searchType], list => list.concat(action.results[action.searchType].map(item => item.id))); }); default: diff --git a/app/styles/placeholder.scss b/app/styles/placeholder.scss index 3b5a3a4aa..0427e9463 100644 --- a/app/styles/placeholder.scss +++ b/app/styles/placeholder.scss @@ -1,4 +1,5 @@ .placeholder-status, +.placeholder-hashtag, .notification--placeholder { position: relative;