diff --git a/app/soapbox/features/compose/components/search_results.js b/app/soapbox/features/compose/components/search_results.js new file mode 100644 index 000000000..05cbe2663 --- /dev/null +++ b/app/soapbox/features/compose/components/search_results.js @@ -0,0 +1,174 @@ +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { FormattedMessage } from 'react-intl'; +import { defineMessages, injectIntl } from 'react-intl'; + +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 Hashtag from '../../../components/hashtag'; +import { Tabs } from '../../../components/ui'; +import AccountContainer from '../../../containers/account_container'; +import StatusContainer from '../../../containers/status_container'; + +const messages = defineMessages({ + accounts: { id: 'search_results.accounts', defaultMessage: 'People' }, + statuses: { id: 'search_results.statuses', defaultMessage: 'Posts' }, + hashtags: { id: 'search_results.hashtags', defaultMessage: 'Hashtags' }, +}); + +export default @injectIntl +class SearchResults extends ImmutablePureComponent { + + static propTypes = { + value: PropTypes.string, + results: ImmutablePropTypes.map.isRequired, + submitted: PropTypes.bool, + expandSearch: PropTypes.func.isRequired, + selectedFilter: PropTypes.string.isRequired, + selectFilter: PropTypes.func.isRequired, + features: PropTypes.object.isRequired, + suggestions: ImmutablePropTypes.list, + trendingStatuses: ImmutablePropTypes.list, + trends: ImmutablePropTypes.list, + intl: PropTypes.object.isRequired, + }; + + handleLoadMore = () => this.props.expandSearch(this.props.selectedFilter); + + handleSelectFilter = newActiveFilter => this.props.selectFilter(newActiveFilter); + + componentDidMount() { + this.props.fetchTrendingStatuses(); + } + + renderFilterBar() { + const { intl, selectedFilter } = this.props; + + const items = [ + { + text: intl.formatMessage(messages.accounts), + action: () => this.handleSelectFilter('accounts'), + name: 'accounts', + }, + { + text: intl.formatMessage(messages.statuses), + action: () => this.handleSelectFilter('statuses'), + name: 'statuses', + }, + { + text: intl.formatMessage(messages.hashtags), + action: () => this.handleSelectFilter('hashtags'), + name: 'hashtags', + }, + ]; + + return ; + } + + render() { + const { value, results, submitted, selectedFilter, suggestions, trendingStatuses, trends } = this.props; + + let searchResults; + let hasMore = false; + let loaded; + let noResultsMessage; + let placeholderComponent = 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 => ); + } 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 => ); + } else if (!submitted && trendingStatuses && !trendingStatuses.isEmpty()) { + searchResults = trendingStatuses.map(statusId => ); + } 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 => ); + } else if (!submitted && suggestions && !suggestions.isEmpty()) { + searchResults = trends.map(hashtag => ); + } else if (loaded) { + noResultsMessage = ( +
+ +
+ ); + } + } + + return ( + <> + {this.renderFilterBar()} + + {noResultsMessage || ( + + {searchResults} + + )} + + ); + } + +} diff --git a/app/soapbox/features/compose/components/search_results.tsx b/app/soapbox/features/compose/components/search_results.tsx deleted file mode 100644 index 66d8f2062..000000000 --- a/app/soapbox/features/compose/components/search_results.tsx +++ /dev/null @@ -1,174 +0,0 @@ -import classNames from 'classnames'; -import React, { useEffect } from 'react'; -import { FormattedMessage } from 'react-intl'; -import { defineMessages, useIntl } from 'react-intl'; - -import { expandSearch, setFilter } from 'soapbox/actions/search'; -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 { useAppSelector, 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 } 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'; - -/** Displays search results depending on the active tab. */ -const SearchResults: React.FC = () => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - - const value = useAppSelector(state => state.search.submittedValue); - const results = useAppSelector(state => state.search.results); - const suggestions = useAppSelector(state => state.suggestions.items); - const trendingStatuses = useAppSelector(state => state.trending_statuses.items); - const trends = useAppSelector(state => state.trends.items); - const submitted = useAppSelector(state => state.search.submitted); - const selectedFilter = useAppSelector(state => state.search.filter); - - const handleLoadMore = () => dispatch(expandSearch(selectedFilter)); - const handleSelectFilter = (newActiveFilter: SearchFilter) => dispatch(setFilter(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; diff --git a/app/soapbox/features/compose/containers/search_results_container.js b/app/soapbox/features/compose/containers/search_results_container.js new file mode 100644 index 000000000..4ab9b712f --- /dev/null +++ b/app/soapbox/features/compose/containers/search_results_container.js @@ -0,0 +1,33 @@ +import { connect } from 'react-redux'; + +import { fetchTrendingStatuses } from 'soapbox/actions/trending_statuses'; +import { getFeatures } from 'soapbox/utils/features'; + +import { expandSearch, setFilter } from '../../../actions/search'; +import { fetchSuggestions, dismissSuggestion } from '../../../actions/suggestions'; +import SearchResults from '../components/search_results'; + +const mapStateToProps = state => { + const instance = state.get('instance'); + + return { + value: state.getIn(['search', 'submittedValue']), + results: state.getIn(['search', 'results']), + suggestions: state.getIn(['suggestions', 'items']), + trendingStatuses: state.getIn(['trending_statuses', 'items']), + trends: state.getIn(['trends', 'items']), + submitted: state.getIn(['search', 'submitted']), + selectedFilter: state.getIn(['search', 'filter']), + features: getFeatures(instance), + }; +}; + +const mapDispatchToProps = dispatch => ({ + fetchSuggestions: () => dispatch(fetchSuggestions()), + fetchTrendingStatuses: () => dispatch(fetchTrendingStatuses()), + expandSearch: type => dispatch(expandSearch(type)), + dismissSuggestion: account => dispatch(dismissSuggestion(account.get('id'))), + selectFilter: newActiveFilter => dispatch(setFilter(newActiveFilter)), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(SearchResults); diff --git a/app/soapbox/features/follow_recommendations/components/follow_recommendations_list.tsx b/app/soapbox/features/follow_recommendations/components/follow_recommendations_list.tsx index 109febdf4..4ca838072 100644 --- a/app/soapbox/features/follow_recommendations/components/follow_recommendations_list.tsx +++ b/app/soapbox/features/follow_recommendations/components/follow_recommendations_list.tsx @@ -31,8 +31,8 @@ const FollowRecommendationsList: React.FC = () => { return (
- {suggestions.size > 0 ? suggestions.map(suggestion => ( - + {suggestions.size > 0 ? suggestions.map((suggestion: { account: string }) => ( + )) : (
diff --git a/app/soapbox/features/search/index.tsx b/app/soapbox/features/search/index.tsx index c17691c37..3fdf625f6 100644 --- a/app/soapbox/features/search/index.tsx +++ b/app/soapbox/features/search/index.tsx @@ -3,7 +3,7 @@ import { defineMessages, useIntl } from 'react-intl'; import { Column } from 'soapbox/components/ui'; import Search from 'soapbox/features/compose/components/search'; -import SearchResults from 'soapbox/features/compose/components/search_results'; +import SearchResultsContainer from 'soapbox/features/compose/containers/search_results_container'; const messages = defineMessages({ heading: { id: 'column.search', defaultMessage: 'Search' }, @@ -16,7 +16,7 @@ const SearchPage = () => {
- +
); diff --git a/app/soapbox/reducers/__tests__/search-test.js b/app/soapbox/reducers/__tests__/search-test.js index c3b8d1ea0..b1138b663 100644 --- a/app/soapbox/reducers/__tests__/search-test.js +++ b/app/soapbox/reducers/__tests__/search-test.js @@ -6,11 +6,11 @@ import { SEARCH_EXPAND_SUCCESS, } from 'soapbox/actions/search'; -import reducer, { ReducerRecord } from '../search'; +import reducer from '../search'; describe('search reducer', () => { it('should return the initial state', () => { - expect(reducer(undefined, {})).toEqual(ReducerRecord({ + expect(reducer(undefined, {})).toEqual(ImmutableMap({ value: '', submitted: false, submittedValue: '', @@ -22,7 +22,7 @@ describe('search reducer', () => { describe('SEARCH_CHANGE', () => { it('sets the value', () => { - const state = ReducerRecord({ value: 'hell' }); + const state = ImmutableMap({ value: 'hell' }); const action = { type: SEARCH_CHANGE, value: 'hello' }; expect(reducer(state, action).get('value')).toEqual('hello'); }); @@ -30,7 +30,7 @@ describe('search reducer', () => { describe('SEARCH_CLEAR', () => { it('resets the state', () => { - const state = ReducerRecord({ + const state = ImmutableMap({ value: 'hello world', submitted: true, submittedValue: 'hello world', @@ -41,7 +41,7 @@ describe('search reducer', () => { const action = { type: SEARCH_CLEAR }; - const expected = ReducerRecord({ + const expected = ImmutableMap({ value: '', submitted: false, submittedValue: '', @@ -56,7 +56,7 @@ describe('search reducer', () => { describe(SEARCH_EXPAND_SUCCESS, () => { it('imports hashtags as maps', () => { - const state = ReducerRecord({ + const state = ImmutableMap({ value: 'artist', submitted: true, submittedValue: 'artist', @@ -82,7 +82,7 @@ describe('search reducer', () => { searchType: 'hashtags', }; - const expected = ReducerRecord({ + const expected = ImmutableMap({ value: 'artist', submitted: true, submittedValue: 'artist', diff --git a/app/soapbox/reducers/__tests__/suggestions-test.js b/app/soapbox/reducers/__tests__/suggestions-test.js index 3a11b5b56..7da0b7f75 100644 --- a/app/soapbox/reducers/__tests__/suggestions-test.js +++ b/app/soapbox/reducers/__tests__/suggestions-test.js @@ -1,7 +1,4 @@ -import { - Record as ImmutableRecord, - fromJS, -} from 'immutable'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; import { SUGGESTIONS_DISMISS } from 'soapbox/actions/suggestions'; @@ -9,10 +6,10 @@ import reducer from '../suggestions'; describe('suggestions reducer', () => { it('should return the initial state', () => { - const result = reducer(undefined, {}); - expect(ImmutableRecord.isRecord(result)).toBe(true); - expect(result.items.isEmpty()).toBe(true); - expect(result.isLoading).toBe(false); + expect(reducer(undefined, {})).toEqual(ImmutableMap({ + items: ImmutableList(), + isLoading: false, + })); }); describe('SUGGESTIONS_DISMISS', () => { diff --git a/app/soapbox/reducers/__tests__/trends-test.js b/app/soapbox/reducers/__tests__/trends-test.js index 22d7d34e4..5ebeabb31 100644 --- a/app/soapbox/reducers/__tests__/trends-test.js +++ b/app/soapbox/reducers/__tests__/trends-test.js @@ -1,12 +1,12 @@ -import { Record as ImmutableRecord } from 'immutable'; +import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; import reducer from '../trends'; describe('trends reducer', () => { it('should return the initial state', () => { - const result = reducer(undefined, {}); - expect(ImmutableRecord.isRecord(result)).toBe(true); - expect(result.items.isEmpty()).toBe(true); - expect(result.isLoading).toBe(false); + expect(reducer(undefined, {})).toEqual(ImmutableMap({ + items: ImmutableList(), + isLoading: false, + })); }); }); diff --git a/app/soapbox/reducers/search.ts b/app/soapbox/reducers/search.js similarity index 69% rename from app/soapbox/reducers/search.ts rename to app/soapbox/reducers/search.js index 64d2a6a8c..e086ef4a0 100644 --- a/app/soapbox/reducers/search.ts +++ b/app/soapbox/reducers/search.js @@ -1,10 +1,4 @@ -import { - Map as ImmutableMap, - Record as ImmutableRecord, - List as ImmutableList, - OrderedSet as ImmutableOrderedSet, - fromJS, -} from 'immutable'; +import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable'; import { COMPOSE_MENTION, @@ -23,39 +17,26 @@ import { SEARCH_EXPAND_SUCCESS, } from '../actions/search'; -import type { AnyAction } from 'redux'; - -export const ReducerRecord = ImmutableRecord({ +const initialState = ImmutableMap({ value: '', submitted: false, submittedValue: '', hidden: false, - results: ImmutableMap(), + results: ImmutableMap(), filter: 'accounts', }); -type State = ReturnType; - -type IdEntity = { id: string }; -type SearchType = 'accounts' | 'statuses' | 'hashtags'; - -type Results = { - accounts: IdEntity[], - statuses: IdEntity[], - hashtags: Record[], -} - -const toIds = (items: IdEntity[]) => { +const toIds = items => { return ImmutableOrderedSet(items.map(item => item.id)); }; -const importResults = (state: State, results: Results, searchTerm: string, searchType: SearchType): State => { +const importResults = (state, results, searchTerm, searchType) => { return state.withMutations(state => { if (state.get('value') === searchTerm && state.get('filter') === searchType) { state.set('results', ImmutableMap({ accounts: toIds(results.accounts), statuses: toIds(results.statuses), - hashtags: ImmutableList(results.hashtags.map(ImmutableMap)), // it's a list of maps + hashtags: fromJS(results.hashtags), // it's a list of maps accountsHasMore: results.accounts.length >= 20, statusesHasMore: results.statuses.length >= 20, hashtagsHasMore: results.hashtags.length >= 20, @@ -69,19 +50,17 @@ const importResults = (state: State, results: Results, searchTerm: string, searc }); }; -const paginateResults = (state: State, searchType: SearchType, results: Results, searchTerm: string): State => { +const paginateResults = (state, searchType, results, searchTerm) => { return state.withMutations(state => { - if (state.value === searchTerm) { + if (state.get('value') === searchTerm) { state.setIn(['results', `${searchType}HasMore`], results[searchType].length >= 20); state.setIn(['results', `${searchType}Loaded`], true); state.updateIn(['results', searchType], items => { const data = results[searchType]; // Hashtags are a list of maps. Others are IDs. if (searchType === 'hashtags') { - // @ts-ignore return items.concat(fromJS(data)); } else { - // @ts-ignore return items.concat(toIds(data)); } }); @@ -89,7 +68,7 @@ const paginateResults = (state: State, searchType: SearchType, results: Results, }); }; -const handleSubmitted = (state: State, value: string): State => { +const handleSubmitted = (state, value) => { return state.withMutations(state => { state.set('results', ImmutableMap()); state.set('submitted', true); @@ -97,12 +76,12 @@ const handleSubmitted = (state: State, value: string): State => { }); }; -export default function search(state = ReducerRecord(), action: AnyAction) { +export default function search(state = initialState, action) { switch (action.type) { case SEARCH_CHANGE: return state.set('value', action.value); case SEARCH_CLEAR: - return ReducerRecord(); + return initialState; case SEARCH_SHOW: return state.set('hidden', false); case COMPOSE_REPLY: diff --git a/app/soapbox/reducers/suggestions.ts b/app/soapbox/reducers/suggestions.js similarity index 54% rename from app/soapbox/reducers/suggestions.ts rename to app/soapbox/reducers/suggestions.js index bca64c9e2..ac00eecf1 100644 --- a/app/soapbox/reducers/suggestions.ts +++ b/app/soapbox/reducers/suggestions.js @@ -1,8 +1,4 @@ -import { - Map as ImmutableMap, - List as ImmutableList, - Record as ImmutableRecord, -} from 'immutable'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from 'soapbox/actions/accounts'; import { DOMAIN_BLOCK_SUCCESS } from 'soapbox/actions/domain_blocks'; @@ -17,64 +13,42 @@ import { SUGGESTIONS_V2_FETCH_FAIL, } from '../actions/suggestions'; -import type { AnyAction } from 'redux'; - -type SuggestionSource = 'past_interactions' | 'staff' | 'global'; - -type ReducerSuggestion = { - source: SuggestionSource, - account: string, -} - -type SuggestionAccount = { - id: string, -} - -type Suggestion = { - source: SuggestionSource, - account: SuggestionAccount, -} - -const ReducerRecord = ImmutableRecord({ - items: ImmutableList>(), +const initialState = ImmutableMap({ + items: ImmutableList(), isLoading: false, }); -type State = ReturnType; - -/** Convert a v1 account into a v2 suggestion. */ -const accountToSuggestion = (account: SuggestionAccount): ReducerSuggestion => { +// Convert a v1 account into a v2 suggestion +const accountToSuggestion = account => { return { source: 'past_interactions', account: account.id, }; }; -/** Import plain accounts into the reducer (legacy). */ -const importAccounts = (state: State, accounts: SuggestionAccount[]): State => { +const importAccounts = (state, accounts) => { return state.withMutations(state => { - state.set('items', ImmutableList(accounts.map(account => ImmutableMap(accountToSuggestion(account))))); + state.set('items', fromJS(accounts.map(accountToSuggestion))); state.set('isLoading', false); }); }; -/** Import full suggestion objects. */ -const importSuggestions = (state: State, suggestions: Suggestion[]): State => { +const importSuggestions = (state, suggestions) => { return state.withMutations(state => { - state.set('items', ImmutableList(suggestions.map(x => ImmutableMap({ ...x, account: x.account.id })))); + state.set('items', fromJS(suggestions.map(x => ({ ...x, account: x.account.id })))); state.set('isLoading', false); }); }; -const dismissAccount = (state: State, accountId: string): State => { +const dismissAccount = (state, accountId) => { return state.update('items', items => items.filterNot(item => item.get('account') === accountId)); }; -const dismissAccounts = (state: State, accountIds: string[]): State => { +const dismissAccounts = (state, accountIds) => { return state.update('items', items => items.filterNot(item => accountIds.includes(item.get('account')))); }; -export default function suggestionsReducer(state = ReducerRecord(), action: AnyAction) { +export default function suggestionsReducer(state = initialState, action) { switch (action.type) { case SUGGESTIONS_FETCH_REQUEST: case SUGGESTIONS_V2_FETCH_REQUEST: diff --git a/app/soapbox/reducers/trending_statuses.js b/app/soapbox/reducers/trending_statuses.js new file mode 100644 index 000000000..ee4fa234b --- /dev/null +++ b/app/soapbox/reducers/trending_statuses.js @@ -0,0 +1,31 @@ +import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable'; + +import { + TRENDING_STATUSES_FETCH_REQUEST, + TRENDING_STATUSES_FETCH_SUCCESS, +} from 'soapbox/actions/trending_statuses'; + +const initialState = ImmutableMap({ + items: ImmutableOrderedSet(), + isLoading: false, +}); + +const toIds = items => ImmutableOrderedSet(items.map(item => item.id)); + +const importStatuses = (state, statuses) => { + return state.withMutations(state => { + state.set('items', toIds(statuses)); + state.set('isLoading', false); + }); +}; + +export default function trending_statuses(state = initialState, action) { + switch (action.type) { + case TRENDING_STATUSES_FETCH_REQUEST: + return state.set('isLoading', true); + case TRENDING_STATUSES_FETCH_SUCCESS: + return importStatuses(state, action.statuses); + default: + return state; + } +} diff --git a/app/soapbox/reducers/trending_statuses.ts b/app/soapbox/reducers/trending_statuses.ts deleted file mode 100644 index afaf5d9af..000000000 --- a/app/soapbox/reducers/trending_statuses.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Record as ImmutableRecord, OrderedSet as ImmutableOrderedSet } from 'immutable'; - -import { - TRENDING_STATUSES_FETCH_REQUEST, - TRENDING_STATUSES_FETCH_SUCCESS, -} from 'soapbox/actions/trending_statuses'; - -import type { AnyAction } from 'redux'; - -const ReducerRecord = ImmutableRecord({ - items: ImmutableOrderedSet(), - isLoading: false, -}); - -type State = ReturnType; - -type IdEntity = { id: string }; - -const toIds = (items: IdEntity[]) => ImmutableOrderedSet(items.map(item => item.id)); - -const importStatuses = (state: State, statuses: IdEntity[]): State => { - return state.withMutations(state => { - state.set('items', toIds(statuses)); - state.set('isLoading', false); - }); -}; - -export default function trending_statuses(state = ReducerRecord(), action: AnyAction) { - switch (action.type) { - case TRENDING_STATUSES_FETCH_REQUEST: - return state.set('isLoading', true); - case TRENDING_STATUSES_FETCH_SUCCESS: - return importStatuses(state, action.statuses); - default: - return state; - } -} diff --git a/app/soapbox/reducers/trends.ts b/app/soapbox/reducers/trends.js similarity index 53% rename from app/soapbox/reducers/trends.ts rename to app/soapbox/reducers/trends.js index cb061c7b7..eb7df59bf 100644 --- a/app/soapbox/reducers/trends.ts +++ b/app/soapbox/reducers/trends.js @@ -1,8 +1,4 @@ -import { - Map as ImmutableMap, - Record as ImmutableRecord, - List as ImmutableList, -} from 'immutable'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; import { TRENDS_FETCH_REQUEST, @@ -10,20 +6,18 @@ import { TRENDS_FETCH_FAIL, } from '../actions/trends'; -import type { AnyAction } from 'redux'; - -const ReducerRecord = ImmutableRecord({ - items: ImmutableList>(), +const initialState = ImmutableMap({ + items: ImmutableList(), isLoading: false, }); -export default function trendsReducer(state = ReducerRecord(), action: AnyAction) { +export default function trendsReducer(state = initialState, action) { switch (action.type) { case TRENDS_FETCH_REQUEST: return state.set('isLoading', true); case TRENDS_FETCH_SUCCESS: return state.withMutations(map => { - map.set('items', ImmutableList(action.tags.map(ImmutableMap))); + map.set('items', fromJS(action.tags.map((x => x)))); map.set('isLoading', false); }); case TRENDS_FETCH_FAIL: