* Add explore page to web UI * Fix not removing loaded statuses from trends on mute/block actionclosed-social-glitch-2
@ -1,31 +1,94 @@ | |||
import api from '../api'; | |||
import { importFetchedStatuses } from './importer'; | |||
export const TRENDS_FETCH_REQUEST = 'TRENDS_FETCH_REQUEST'; | |||
export const TRENDS_FETCH_SUCCESS = 'TRENDS_FETCH_SUCCESS'; | |||
export const TRENDS_FETCH_FAIL = 'TRENDS_FETCH_FAIL'; | |||
export const TRENDS_TAGS_FETCH_REQUEST = 'TRENDS_TAGS_FETCH_REQUEST'; | |||
export const TRENDS_TAGS_FETCH_SUCCESS = 'TRENDS_TAGS_FETCH_SUCCESS'; | |||
export const TRENDS_TAGS_FETCH_FAIL = 'TRENDS_TAGS_FETCH_FAIL'; | |||
export const fetchTrends = () => (dispatch, getState) => { | |||
dispatch(fetchTrendsRequest()); | |||
export const TRENDS_LINKS_FETCH_REQUEST = 'TRENDS_LINKS_FETCH_REQUEST'; | |||
export const TRENDS_LINKS_FETCH_SUCCESS = 'TRENDS_LINKS_FETCH_SUCCESS'; | |||
export const TRENDS_LINKS_FETCH_FAIL = 'TRENDS_LINKS_FETCH_FAIL'; | |||
export const TRENDS_STATUSES_FETCH_REQUEST = 'TRENDS_STATUSES_FETCH_REQUEST'; | |||
export const TRENDS_STATUSES_FETCH_SUCCESS = 'TRENDS_STATUSES_FETCH_SUCCESS'; | |||
export const TRENDS_STATUSES_FETCH_FAIL = 'TRENDS_STATUSES_FETCH_FAIL'; | |||
export const fetchTrendingHashtags = () => (dispatch, getState) => { | |||
dispatch(fetchTrendingHashtagsRequest()); | |||
api(getState) | |||
.get('/api/v1/trends/tags') | |||
.then(({ data }) => dispatch(fetchTrendingHashtagsSuccess(data))) | |||
.catch(err => dispatch(fetchTrendingHashtagsFail(err))); | |||
}; | |||
export const fetchTrendingHashtagsRequest = () => ({ | |||
type: TRENDS_TAGS_FETCH_REQUEST, | |||
skipLoading: true, | |||
}); | |||
export const fetchTrendingHashtagsSuccess = trends => ({ | |||
type: TRENDS_TAGS_FETCH_SUCCESS, | |||
trends, | |||
skipLoading: true, | |||
}); | |||
export const fetchTrendingHashtagsFail = error => ({ | |||
type: TRENDS_TAGS_FETCH_FAIL, | |||
error, | |||
skipLoading: true, | |||
skipAlert: true, | |||
}); | |||
export const fetchTrendingLinks = () => (dispatch, getState) => { | |||
dispatch(fetchTrendingLinksRequest()); | |||
api(getState) | |||
.get('/api/v1/trends') | |||
.then(({ data }) => dispatch(fetchTrendsSuccess(data))) | |||
.catch(err => dispatch(fetchTrendsFail(err))); | |||
.get('/api/v1/trends/links') | |||
.then(({ data }) => dispatch(fetchTrendingLinksSuccess(data))) | |||
.catch(err => dispatch(fetchTrendingLinksFail(err))); | |||
}; | |||
export const fetchTrendsRequest = () => ({ | |||
type: TRENDS_FETCH_REQUEST, | |||
export const fetchTrendingLinksRequest = () => ({ | |||
type: TRENDS_LINKS_FETCH_REQUEST, | |||
skipLoading: true, | |||
}); | |||
export const fetchTrendsSuccess = trends => ({ | |||
type: TRENDS_FETCH_SUCCESS, | |||
export const fetchTrendingLinksSuccess = trends => ({ | |||
type: TRENDS_LINKS_FETCH_SUCCESS, | |||
trends, | |||
skipLoading: true, | |||
}); | |||
export const fetchTrendsFail = error => ({ | |||
type: TRENDS_FETCH_FAIL, | |||
export const fetchTrendingLinksFail = error => ({ | |||
type: TRENDS_LINKS_FETCH_FAIL, | |||
error, | |||
skipLoading: true, | |||
skipAlert: true, | |||
}); | |||
export const fetchTrendingStatuses = () => (dispatch, getState) => { | |||
dispatch(fetchTrendingStatusesRequest()); | |||
api(getState).get('/api/v1/trends/statuses').then(({ data }) => { | |||
dispatch(importFetchedStatuses(data)); | |||
dispatch(fetchTrendingStatusesSuccess(data)); | |||
}).catch(err => dispatch(fetchTrendingStatusesFail(err))); | |||
}; | |||
export const fetchTrendingStatusesRequest = () => ({ | |||
type: TRENDS_STATUSES_FETCH_REQUEST, | |||
skipLoading: true, | |||
}); | |||
export const fetchTrendingStatusesSuccess = statuses => ({ | |||
type: TRENDS_STATUSES_FETCH_SUCCESS, | |||
statuses, | |||
skipLoading: true, | |||
}); | |||
export const fetchTrendingStatusesFail = error => ({ | |||
type: TRENDS_STATUSES_FETCH_FAIL, | |||
error, | |||
skipLoading: true, | |||
skipAlert: true, | |||
@ -0,0 +1,51 @@ | |||
import React from 'react'; | |||
import PropTypes from 'prop-types'; | |||
import Blurhash from 'mastodon/components/blurhash'; | |||
import { accountsCountRenderer } from 'mastodon/components/hashtag'; | |||
import ShortNumber from 'mastodon/components/short_number'; | |||
import Skeleton from 'mastodon/components/skeleton'; | |||
import classNames from 'classnames'; | |||
export default class Story extends React.PureComponent { | |||
static propTypes = { | |||
url: PropTypes.string, | |||
title: PropTypes.string, | |||
publisher: PropTypes.string, | |||
sharedTimes: PropTypes.number, | |||
thumbnail: PropTypes.string, | |||
blurhash: PropTypes.string, | |||
}; | |||
state = { | |||
thumbnailLoaded: false, | |||
}; | |||
handleImageLoad = () => this.setState({ thumbnailLoaded: true }); | |||
render () { | |||
const { url, title, publisher, sharedTimes, thumbnail, blurhash } = this.props; | |||
const { thumbnailLoaded } = this.state; | |||
return ( | |||
<a className='story' href={url} target='blank' rel='noopener'> | |||
<div className='story__details'> | |||
<div className='story__details__publisher'>{publisher ? publisher : <Skeleton width={50} />}</div> | |||
<div className='story__details__title'>{title ? title : <Skeleton />}</div> | |||
<div className='story__details__shared'>{typeof sharedTimes === 'number' ? <ShortNumber value={sharedTimes} renderer={accountsCountRenderer} /> : <Skeleton width={100} />}</div> | |||
</div> | |||
<div className='story__thumbnail'> | |||
{thumbnail ? ( | |||
<React.Fragment> | |||
<div className={classNames('story__thumbnail__preview', { 'story__thumbnail__preview--hidden': thumbnailLoaded })}><Blurhash hash={blurhash} /></div> | |||
<img src={thumbnail} onLoad={this.handleImageLoad} alt='' role='presentation' /> | |||
</React.Fragment> | |||
) : <Skeleton />} | |||
</div> | |||
</a> | |||
); | |||
} | |||
} |
@ -0,0 +1,91 @@ | |||
import React from 'react'; | |||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; | |||
import { connect } from 'react-redux'; | |||
import PropTypes from 'prop-types'; | |||
import Column from 'mastodon/components/column'; | |||
import ColumnHeader from 'mastodon/components/column_header'; | |||
import { NavLink, Switch, Route } from 'react-router-dom'; | |||
import Links from './links'; | |||
import Tags from './tags'; | |||
import Statuses from './statuses'; | |||
import Suggestions from './suggestions'; | |||
import Search from 'mastodon/features/compose/containers/search_container'; | |||
import SearchResults from './results'; | |||
const messages = defineMessages({ | |||
title: { id: 'explore.title', defaultMessage: 'Explore' }, | |||
searchResults: { id: 'explore.search_results', defaultMessage: 'Search results' }, | |||
}); | |||
const mapStateToProps = state => ({ | |||
layout: state.getIn(['meta', 'layout']), | |||
isSearching: state.getIn(['search', 'submitted']), | |||
}); | |||
export default @connect(mapStateToProps) | |||
@injectIntl | |||
class Explore extends React.PureComponent { | |||
static contextTypes = { | |||
router: PropTypes.object, | |||
}; | |||
static propTypes = { | |||
intl: PropTypes.object.isRequired, | |||
multiColumn: PropTypes.bool, | |||
isSearching: PropTypes.bool, | |||
layout: PropTypes.string, | |||
}; | |||
handleHeaderClick = () => { | |||
this.column.scrollTop(); | |||
} | |||
setRef = c => { | |||
this.column = c; | |||
} | |||
render () { | |||
const { intl, multiColumn, isSearching, layout } = this.props; | |||
return ( | |||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}> | |||
{layout === 'mobile' ? ( | |||
<div className='explore__search-header'> | |||
<Search /> | |||
</div> | |||
) : ( | |||
<ColumnHeader | |||
icon={isSearching ? 'search' : 'globe'} | |||
title={intl.formatMessage(isSearching ? messages.searchResults : messages.title)} | |||
onClick={this.handleHeaderClick} | |||
multiColumn={multiColumn} | |||
/> | |||
)} | |||
<div className='scrollable scrollable--flex'> | |||
{isSearching ? ( | |||
<SearchResults /> | |||
) : ( | |||
<React.Fragment> | |||
<div className='account__section-headline'> | |||
<NavLink exact to='/explore'><FormattedMessage id='explore.trending_statuses' defaultMessage='Posts' /></NavLink> | |||
<NavLink exact to='/explore/tags'><FormattedMessage id='explore.trending_tags' defaultMessage='Hashtags' /></NavLink> | |||
<NavLink exact to='/explore/links'><FormattedMessage id='explore.trending_links' defaultMessage='News' /></NavLink> | |||
<NavLink exact to='/explore/suggestions'><FormattedMessage id='explore.suggested_follows' defaultMessage='For you' /></NavLink> | |||
</div> | |||
<Switch> | |||
<Route path='/explore/tags' component={Tags} /> | |||
<Route path='/explore/links' component={Links} /> | |||
<Route path='/explore/suggestions' component={Suggestions} /> | |||
<Route exact path={['/explore', '/explore/posts', '/search']} component={Statuses} componentParams={{ multiColumn }} /> | |||
</Switch> | |||
</React.Fragment> | |||
)} | |||
</div> | |||
</Column> | |||
); | |||
} | |||
} |
@ -0,0 +1,48 @@ | |||
import React from 'react'; | |||
import PropTypes from 'prop-types'; | |||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||
import Story from './components/story'; | |||
import LoadingIndicator from 'mastodon/components/loading_indicator'; | |||
import { connect } from 'react-redux'; | |||
import { fetchTrendingLinks } from 'mastodon/actions/trends'; | |||
const mapStateToProps = state => ({ | |||
links: state.getIn(['trends', 'links', 'items']), | |||
isLoading: state.getIn(['trends', 'links', 'isLoading']), | |||
}); | |||
export default @connect(mapStateToProps) | |||
class Links extends React.PureComponent { | |||
static propTypes = { | |||
links: ImmutablePropTypes.list, | |||
isLoading: PropTypes.bool, | |||
dispatch: PropTypes.func.isRequired, | |||
}; | |||
componentDidMount () { | |||
const { dispatch } = this.props; | |||
dispatch(fetchTrendingLinks()); | |||
} | |||
render () { | |||
const { isLoading, links } = this.props; | |||
return ( | |||
<div className='explore__links'> | |||
{isLoading ? (<LoadingIndicator />) : links.map(link => ( | |||
<Story | |||
key={link.get('id')} | |||
url={link.get('url')} | |||
title={link.get('title')} | |||
publisher={link.get('provider_name')} | |||
sharedTimes={link.getIn(['history', 0, 'accounts']) * 1 + link.getIn(['history', 1, 'accounts']) * 1} | |||
thumbnail={link.get('image')} | |||
blurhash={link.get('blurhash')} | |||
/> | |||
))} | |||
</div> | |||
); | |||
} | |||
} |
@ -0,0 +1,113 @@ | |||
import React from 'react'; | |||
import PropTypes from 'prop-types'; | |||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { connect } from 'react-redux'; | |||
import { expandSearch } from 'mastodon/actions/search'; | |||
import Account from 'mastodon/containers/account_container'; | |||
import Status from 'mastodon/containers/status_container'; | |||
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag'; | |||
import { List as ImmutableList } from 'immutable'; | |||
import LoadMore from 'mastodon/components/load_more'; | |||
import LoadingIndicator from 'mastodon/components/loading_indicator'; | |||
const mapStateToProps = state => ({ | |||
isLoading: state.getIn(['search', 'isLoading']), | |||
results: state.getIn(['search', 'results']), | |||
}); | |||
const appendLoadMore = (id, list, onLoadMore) => { | |||
if (list.size >= 5) { | |||
return list.push(<LoadMore key={`${id}-load-more`} visible onClick={onLoadMore} />); | |||
} else { | |||
return list; | |||
} | |||
}; | |||
const renderAccounts = (results, onLoadMore) => appendLoadMore('accounts', results.get('accounts').map(item => ( | |||
<Account key={`account-${item}`} id={item} /> | |||
)), onLoadMore); | |||
const renderHashtags = (results, onLoadMore) => appendLoadMore('hashtags', results.get('hashtags').map(item => ( | |||
<Hashtag key={`tag-${item.get('name')}`} hashtag={item} /> | |||
)), onLoadMore); | |||
const renderStatuses = (results, onLoadMore) => appendLoadMore('statuses', results.get('statuses').map(item => ( | |||
<Status key={`status-${item}`} id={item} /> | |||
)), onLoadMore); | |||
export default @connect(mapStateToProps) | |||
class Results extends React.PureComponent { | |||
static propTypes = { | |||
results: ImmutablePropTypes.map, | |||
isLoading: PropTypes.bool, | |||
multiColumn: PropTypes.bool, | |||
dispatch: PropTypes.func.isRequired, | |||
}; | |||
state = { | |||
type: 'all', | |||
}; | |||
handleSelectAll = () => this.setState({ type: 'all' }); | |||
handleSelectAccounts = () => this.setState({ type: 'accounts' }); | |||
handleSelectHashtags = () => this.setState({ type: 'hashtags' }); | |||
handleSelectStatuses = () => this.setState({ type: 'statuses' }); | |||
handleLoadMoreAccounts = () => this.loadMore('accounts'); | |||
handleLoadMoreStatuses = () => this.loadMore('statuses'); | |||
handleLoadMoreHashtags = () => this.loadMore('hashtags'); | |||
loadMore (type) { | |||
const { dispatch } = this.props; | |||
dispatch(expandSearch(type)); | |||
} | |||
render () { | |||
const { isLoading, results } = this.props; | |||
const { type } = this.state; | |||
let filteredResults = ImmutableList(); | |||
if (!isLoading) { | |||
switch(type) { | |||
case 'all': | |||
filteredResults = filteredResults.concat(renderAccounts(results, this.handleLoadMoreAccounts), renderHashtags(results, this.handleLoadMoreHashtags), renderStatuses(results, this.handleLoadMoreStatuses)); | |||
break; | |||
case 'accounts': | |||
filteredResults = filteredResults.concat(renderAccounts(results, this.handleLoadMoreAccounts)); | |||
break; | |||
case 'hashtags': | |||
filteredResults = filteredResults.concat(renderHashtags(results, this.handleLoadMoreHashtags)); | |||
break; | |||
case 'statuses': | |||
filteredResults = filteredResults.concat(renderStatuses(results, this.handleLoadMoreStatuses)); | |||
break; | |||
} | |||
if (filteredResults.size === 0) { | |||
filteredResults = ( | |||
<div className='empty-column-indicator'> | |||
<FormattedMessage id='search_results.nothing_found' defaultMessage='Could not find anything for these search terms' /> | |||
</div> | |||
); | |||
} | |||
} | |||
return ( | |||
<React.Fragment> | |||
<div className='account__section-headline'> | |||
<button onClick={this.handleSelectAll} className={type === 'all' && 'active'}><FormattedMessage id='search_results.all' defaultMessage='All' /></button> | |||
<button onClick={this.handleSelectAccounts} className={type === 'accounts' && 'active'}><FormattedMessage id='search_results.accounts' defaultMessage='People' /></button> | |||
<button onClick={this.handleSelectHashtags} className={type === 'hashtags' && 'active'}><FormattedMessage id='search_results.hashtags' defaultMessage='Hashtags' /></button> | |||
<button onClick={this.handleSelectStatuses} className={type === 'statuses' && 'active'}><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></button> | |||
</div> | |||
<div className='explore__search-results'> | |||
{isLoading ? (<LoadingIndicator />) : filteredResults} | |||
</div> | |||
</React.Fragment> | |||
); | |||
} | |||
} |
@ -0,0 +1,48 @@ | |||
import React from 'react'; | |||
import PropTypes from 'prop-types'; | |||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||
import StatusList from 'mastodon/components/status_list'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { connect } from 'react-redux'; | |||
import { fetchTrendingStatuses } from 'mastodon/actions/trends'; | |||
const mapStateToProps = state => ({ | |||
statusIds: state.getIn(['status_lists', 'trending', 'items']), | |||
isLoading: state.getIn(['status_lists', 'trending', 'isLoading'], true), | |||
}); | |||
export default @connect(mapStateToProps) | |||
class Statuses extends React.PureComponent { | |||
static propTypes = { | |||
statusIds: ImmutablePropTypes.list, | |||
isLoading: PropTypes.bool, | |||
multiColumn: PropTypes.bool, | |||
dispatch: PropTypes.func.isRequired, | |||
}; | |||
componentDidMount () { | |||
const { dispatch } = this.props; | |||
dispatch(fetchTrendingStatuses()); | |||
} | |||
render () { | |||
const { isLoading, statusIds, multiColumn } = this.props; | |||
const emptyMessage = <FormattedMessage id='empty_column.explore_statuses' defaultMessage='Nothing is trending right now. Check back later!' />; | |||
return ( | |||
<StatusList | |||
trackScroll | |||
statusIds={statusIds} | |||
scrollKey='explore-statuses' | |||
hasMore={false} | |||
isLoading={isLoading} | |||
emptyMessage={emptyMessage} | |||
bindToDocument={!multiColumn} | |||
withCounters | |||
/> | |||
); | |||
} | |||
} |
@ -0,0 +1,40 @@ | |||
import React from 'react'; | |||
import PropTypes from 'prop-types'; | |||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||
import Account from 'mastodon/containers/account_container'; | |||
import LoadingIndicator from 'mastodon/components/loading_indicator'; | |||
import { connect } from 'react-redux'; | |||
import { fetchSuggestions } from 'mastodon/actions/suggestions'; | |||
const mapStateToProps = state => ({ | |||
suggestions: state.getIn(['suggestions', 'items']), | |||
isLoading: state.getIn(['suggestions', 'isLoading']), | |||
}); | |||
export default @connect(mapStateToProps) | |||
class Suggestions extends React.PureComponent { | |||
static propTypes = { | |||
isLoading: PropTypes.bool, | |||
suggestions: ImmutablePropTypes.list, | |||
dispatch: PropTypes.func.isRequired, | |||
}; | |||
componentDidMount () { | |||
const { dispatch } = this.props; | |||
dispatch(fetchSuggestions(true)); | |||
} | |||
render () { | |||
const { isLoading, suggestions } = this.props; | |||
return ( | |||
<div className='explore__links'> | |||
{isLoading ? (<LoadingIndicator />) : suggestions.map(suggestion => ( | |||
<Account key={suggestion.get('account')} id={suggestion.get('account')} /> | |||
))} | |||
</div> | |||
); | |||
} | |||
} |
@ -0,0 +1,40 @@ | |||
import React from 'react'; | |||
import PropTypes from 'prop-types'; | |||
import ImmutablePropTypes from 'react-immutable-proptypes'; | |||
import { ImmutableHashtag as Hashtag } from 'mastodon/components/hashtag'; | |||
import LoadingIndicator from 'mastodon/components/loading_indicator'; | |||
import { connect } from 'react-redux'; | |||
import { fetchTrendingHashtags } from 'mastodon/actions/trends'; | |||
const mapStateToProps = state => ({ | |||
hashtags: state.getIn(['trends', 'tags', 'items']), | |||
isLoadingHashtags: state.getIn(['trends', 'tags', 'isLoading']), | |||
}); | |||
export default @connect(mapStateToProps) | |||
class Tags extends React.PureComponent { | |||
static propTypes = { | |||
hashtags: ImmutablePropTypes.list, | |||
isLoading: PropTypes.bool, | |||
dispatch: PropTypes.func.isRequired, | |||
}; | |||
componentDidMount () { | |||
const { dispatch } = this.props; | |||
dispatch(fetchTrendingHashtags()); | |||
} | |||
render () { | |||
const { isLoading, hashtags } = this.props; | |||
return ( | |||
<div className='explore__links'> | |||
{isLoading ? (<LoadingIndicator />) : hashtags.map(hashtag => ( | |||
<Hashtag key={hashtag.get('name')} hashtag={hashtag} /> | |||
))} | |||
</div> | |||
); | |||
} | |||
} |
@ -1,13 +1,13 @@ | |||
import { connect } from 'react-redux'; | |||
import { fetchTrends } from 'mastodon/actions/trends'; | |||
import { fetchTrendingHashtags } from 'mastodon/actions/trends'; | |||
import Trends from '../components/trends'; | |||
const mapStateToProps = state => ({ | |||
trends: state.getIn(['trends', 'items']), | |||
trends: state.getIn(['trends', 'tags', 'items']), | |||
}); | |||
const mapDispatchToProps = dispatch => ({ | |||
fetchTrends: () => dispatch(fetchTrends()), | |||
fetchTrends: () => dispatch(fetchTrendingHashtags()), | |||
}); | |||
export default connect(mapStateToProps, mapDispatchToProps)(Trends); |
@ -1,17 +0,0 @@ | |||
import React from 'react'; | |||
import SearchContainer from 'mastodon/features/compose/containers/search_container'; | |||
import SearchResultsContainer from 'mastodon/features/compose/containers/search_results_container'; | |||
const Search = () => ( | |||
<div className='column search-page'> | |||
<SearchContainer /> | |||
<div className='drawer__pager'> | |||
<div className='drawer__inner darker'> | |||
<SearchResultsContainer /> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
export default Search; |
@ -1,22 +1,45 @@ | |||
import { TRENDS_FETCH_REQUEST, TRENDS_FETCH_SUCCESS, TRENDS_FETCH_FAIL } from '../actions/trends'; | |||
import { | |||
TRENDS_TAGS_FETCH_REQUEST, | |||
TRENDS_TAGS_FETCH_SUCCESS, | |||
TRENDS_TAGS_FETCH_FAIL, | |||
TRENDS_LINKS_FETCH_REQUEST, | |||
TRENDS_LINKS_FETCH_SUCCESS, | |||
TRENDS_LINKS_FETCH_FAIL, | |||
} from 'mastodon/actions/trends'; | |||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; | |||
const initialState = ImmutableMap({ | |||
items: ImmutableList(), | |||
isLoading: false, | |||
tags: ImmutableMap({ | |||
items: ImmutableList(), | |||
isLoading: false, | |||
}), | |||
links: ImmutableMap({ | |||
items: ImmutableList(), | |||
isLoading: false, | |||
}), | |||
}); | |||
export default function trendsReducer(state = initialState, action) { | |||
switch(action.type) { | |||
case TRENDS_FETCH_REQUEST: | |||
return state.set('isLoading', true); | |||
case TRENDS_FETCH_SUCCESS: | |||
case TRENDS_TAGS_FETCH_REQUEST: | |||
return state.setIn(['tags', 'isLoading'], true); | |||
case TRENDS_TAGS_FETCH_SUCCESS: | |||
return state.withMutations(map => { | |||
map.setIn(['tags', 'items'], fromJS(action.trends)); | |||
map.setIn(['tags', 'isLoading'], false); | |||
}); | |||
case TRENDS_TAGS_FETCH_FAIL: | |||
return state.setIn(['tags', 'isLoading'], false); | |||
case TRENDS_LINKS_FETCH_REQUEST: | |||
return state.setIn(['links', 'isLoading'], true); | |||
case TRENDS_LINKS_FETCH_SUCCESS: | |||
return state.withMutations(map => { | |||
map.set('items', fromJS(action.trends)); | |||
map.set('isLoading', false); | |||
map.setIn(['links', 'items'], fromJS(action.trends)); | |||
map.setIn(['links', 'isLoading'], false); | |||
}); | |||
case TRENDS_FETCH_FAIL: | |||
return state.set('isLoading', false); | |||
case TRENDS_LINKS_FETCH_FAIL: | |||
return state.setIn(['links', 'isLoading'], false); | |||
default: | |||
return state; | |||
} | |||