Add loading indicator for trending tags (#7693)
This commit is contained in:
		
							parent
							
								
									bfa12239e8
								
							
						
					
					
						commit
						69b45350fe
					
				@ -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 => ({
 | 
			
		||||
 | 
			
		||||
@ -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>
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -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));
 | 
			
		||||
@ -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' />}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1036,6 +1036,19 @@
 | 
			
		||||
    ],
 | 
			
		||||
    "path": "app/javascript/mastodon/features/follow_requests/index.json"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "descriptors": [
 | 
			
		||||
      {
 | 
			
		||||
        "defaultMessage": "Refresh",
 | 
			
		||||
        "id": "trends.refresh"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "defaultMessage": "Trending now",
 | 
			
		||||
        "id": "trends.header"
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    "path": "app/javascript/mastodon/features/getting_started/components/trends.json"
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    "descriptors": [
 | 
			
		||||
      {
 | 
			
		||||
@ -1094,10 +1107,6 @@
 | 
			
		||||
        "defaultMessage": "Lists",
 | 
			
		||||
        "id": "navigation_bar.lists"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "defaultMessage": "Refresh",
 | 
			
		||||
        "id": "trends.refresh"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "defaultMessage": "Discover",
 | 
			
		||||
        "id": "navigation_bar.discover"
 | 
			
		||||
@ -1114,10 +1123,6 @@
 | 
			
		||||
        "defaultMessage": "Getting started",
 | 
			
		||||
        "id": "getting_started.heading"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "defaultMessage": "Trending now",
 | 
			
		||||
        "id": "trends.header"
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
        "defaultMessage": "Hotkeys",
 | 
			
		||||
        "id": "navigation_bar.keyboard_shortcuts"
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user