diff options
6 files changed, 104 insertions, 41 deletions
diff --git a/app/javascript/mastodon/features/compose/containers/search_results_container.js b/app/javascript/mastodon/features/compose/containers/search_results_container.js index 7273460e2..2f879f9d9 100644 --- a/app/javascript/mastodon/features/compose/containers/search_results_container.js +++ b/app/javascript/mastodon/features/compose/containers/search_results_container.js @@ -4,7 +4,7 @@ import { fetchTrends } from '../../../actions/trends'; const mapStateToProps = state => ({ results: state.getIn(['search', 'results']), - trends: state.get('trends'), + trends: state.getIn(['trends', 'items']), }); const mapDispatchToProps = dispatch => ({ diff --git a/app/javascript/mastodon/features/getting_started/components/trends.js b/app/javascript/mastodon/features/getting_started/components/trends.js new file mode 100644 index 000000000..5d6b7ed8c --- /dev/null +++ b/app/javascript/mastodon/features/getting_started/components/trends.js @@ -0,0 +1,58 @@ +import classNames from 'classnames'; +import React from 'react'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import PropTypes from 'prop-types'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { FormattedMessage, defineMessages } from 'react-intl'; +import Hashtag from '../../../components/hashtag'; + +const messages = defineMessages({ + refresh_trends: { id: 'trends.refresh', defaultMessage: 'Refresh' }, +}); + +export default class Trends extends ImmutablePureComponent { + + static defaultProps = { + loading: false, + }; + + static propTypes = { + trends: ImmutablePropTypes.list, + loading: PropTypes.bool.isRequired, + }; + + componentDidMount () { + setTimeout(() => this.props.fetchTrends(), 5000); + } + + handleRefreshTrends = () => { + this.props.fetchTrends(); + } + + render () { + const { intl, trends, loading } = this.props; + + if (!trends || trends.size < 1) { + return null; + } + + return ( + <div className='getting-started__trends'> + <div className='column-header__wrapper'> + <h1 className='column-header'> + <button> + <i className='fa fa-fire fa-fw' /> + <FormattedMessage id='trends.header' defaultMessage='Trending now' /> + </button> + <div className='column-header__buttons'> + <button onClick={this.handleRefreshTrends} className='column-header__button' title={intl.formatMessage(messages.refresh_trends)} aria-label={intl.formatMessage(messages.refresh_trends)} disabled={loading}><i className={classNames('fa', 'fa-refresh', { 'fa-spin': loading })} /></button> + </div> + </h1> + </div> + + <div className='getting-started__scrollable'>{trends.take(3).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}</div> + </div> + ); + } + +} diff --git a/app/javascript/mastodon/features/getting_started/containers/trends_container.js b/app/javascript/mastodon/features/getting_started/containers/trends_container.js new file mode 100644 index 000000000..549556b76 --- /dev/null +++ b/app/javascript/mastodon/features/getting_started/containers/trends_container.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import { injectIntl } from 'react-intl'; +import { fetchTrends } from '../../../actions/trends'; +import Trends from '../components/trends'; + +const mapStateToProps = state => ({ + trends: state.getIn(['trends', 'items']), + loading: state.getIn(['trends', 'isLoading']), +}); + +const mapDispatchToProps = dispatch => ({ + fetchTrends: () => dispatch(fetchTrends()), +}); + +export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(Trends)); diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index da1909653..9575afd7a 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -11,9 +11,8 @@ import { me } from '../../initial_state'; import { fetchFollowRequests } from '../../actions/accounts'; import { List as ImmutableList } from 'immutable'; import { Link } from 'react-router-dom'; -import { fetchTrends } from '../../actions/trends'; -import Hashtag from '../../components/hashtag'; import NavigationBar from '../compose/components/navigation_bar'; +import TrendsContainer from './containers/trends_container'; const messages = defineMessages({ home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' }, @@ -30,7 +29,6 @@ const messages = defineMessages({ mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' }, lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, - refresh_trends: { id: 'trends.refresh', defaultMessage: 'Refresh' }, discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' }, personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' }, security: { id: 'navigation_bar.security', defaultMessage: 'Security' }, @@ -39,12 +37,10 @@ const messages = defineMessages({ const mapStateToProps = state => ({ myAccount: state.getIn(['accounts', me]), unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size, - trends: state.get('trends'), }); const mapDispatchToProps = dispatch => ({ fetchFollowRequests: () => dispatch(fetchFollowRequests()), - fetchTrends: () => dispatch(fetchTrends()), }); const badgeDisplay = (number, limit) => { @@ -69,7 +65,6 @@ export default class GettingStarted extends ImmutablePureComponent { fetchFollowRequests: PropTypes.func.isRequired, unreadFollowRequests: PropTypes.number, unreadNotifications: PropTypes.number, - trends: ImmutablePropTypes.list, }; componentDidMount () { @@ -78,16 +73,10 @@ export default class GettingStarted extends ImmutablePureComponent { if (myAccount.get('locked')) { fetchFollowRequests(); } - - setTimeout(() => this.props.fetchTrends(), 5000); - } - - handleRefreshTrends = () => { - this.props.fetchTrends(); } render () { - const { intl, myAccount, multiColumn, unreadFollowRequests, trends } = this.props; + const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props; const navItems = []; let i = 1; @@ -135,21 +124,7 @@ export default class GettingStarted extends ImmutablePureComponent { {navItems} </div> - {multiColumn && trends && <div className='getting-started__trends'> - <div className='column-header__wrapper'> - <h1 className='column-header'> - <button> - <i className='fa fa-fire fa-fw' /> - <FormattedMessage id='trends.header' defaultMessage='Trending now' /> - </button> - <div className='column-header__buttons'> - <button onClick={this.handleRefreshTrends} className='column-header__button' title={intl.formatMessage(messages.refresh_trends)} aria-label={intl.formatMessage(messages.refresh_trends)}><i className='fa fa-refresh' /></button> - </div> - </h1> - </div> - - <div className='getting-started__scrollable'>{trends.take(3).map(hashtag => <Hashtag key={hashtag.get('name')} hashtag={hashtag} />)}</div> - </div>} + {multiColumn && <TrendsContainer />} {!multiColumn && <div className='flex-spacer' />} diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index d8a115a76..c710e1270 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -1039,6 +1039,19 @@ { "descriptors": [ { + "defaultMessage": "Refresh", + "id": "trends.refresh" + }, + { + "defaultMessage": "Trending now", + "id": "trends.header" + } + ], + "path": "app/javascript/mastodon/features/getting_started/components/trends.json" + }, + { + "descriptors": [ + { "defaultMessage": "Home", "id": "tabs_bar.home" }, @@ -1095,10 +1108,6 @@ "id": "navigation_bar.lists" }, { - "defaultMessage": "Refresh", - "id": "trends.refresh" - }, - { "defaultMessage": "Discover", "id": "navigation_bar.discover" }, @@ -1115,10 +1124,6 @@ "id": "getting_started.heading" }, { - "defaultMessage": "Trending now", - "id": "trends.header" - }, - { "defaultMessage": "Hotkeys", "id": "navigation_bar.keyboard_shortcuts" }, diff --git a/app/javascript/mastodon/reducers/trends.js b/app/javascript/mastodon/reducers/trends.js index 95cf8f284..5cecc8fca 100644 --- a/app/javascript/mastodon/reducers/trends.js +++ b/app/javascript/mastodon/reducers/trends.js @@ -1,12 +1,22 @@ -import { TRENDS_FETCH_SUCCESS } from '../actions/trends'; -import { fromJS } from 'immutable'; +import { TRENDS_FETCH_REQUEST, TRENDS_FETCH_SUCCESS, TRENDS_FETCH_FAIL } from '../actions/trends'; +import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable'; -const initialState = null; +const initialState = 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: - return fromJS(action.trends); + return state.withMutations(map => { + map.set('items', fromJS(action.trends)); + map.set('isLoading', false); + }); + case TRENDS_FETCH_FAIL: + return state.set('isLoading', false); default: return state; } |