mirror of https://github.com/mastodon/mastodon
Add listing of followed hashtags (#21773)
* Add followed_tags route. This at least gets us to the point where the page can actually be rendered, although it doesn't display any hashtags (yet?). Attempting to implement #20763. * Fix minor issues. * I've got the followed tags data partially working But the Hashtag component errors for some reason. Something about the value of the history attribute being invalid. * Fix a mistake in the code * Minor change. * Get the followed hashtags list fully working. Still need to add the Follow/Unfollow buttons, though. * Resolve JS linter issues. * Add pagination logic to followed tags list view. However, it currently loads further pages immediately on page load, so that's not ideal. Need to figure that one out. * Appease the linter. * Apply suggestions from code review Co-authored-by: Claire <claire.github-309c@sitedethib.com> * Fixes and resolve some other feedback. * Use set/update instead of setIn/updateIn. Co-authored-by: Claire <claire.github-309c@sitedethib.com>pull/23156/head
parent
3970a6f433
commit
30e895299c
@ -0,0 +1,89 @@
|
||||
import { debounce } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import { connect } from 'react-redux';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import Column from 'mastodon/features/ui/components/column';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import Hashtag from 'mastodon/components/hashtag';
|
||||
import { expandFollowedHashtags, fetchFollowedHashtags } from 'mastodon/actions/tags';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'followed_tags', defaultMessage: 'Followed hashtags' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
hashtags: state.getIn(['followed_tags', 'items']),
|
||||
isLoading: state.getIn(['followed_tags', 'isLoading'], true),
|
||||
hasMore: !!state.getIn(['followed_tags', 'next']),
|
||||
});
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
@injectIntl
|
||||
class FollowedTags extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hashtags: ImmutablePropTypes.list,
|
||||
isLoading: PropTypes.bool,
|
||||
hasMore: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(fetchFollowedHashtags());
|
||||
};
|
||||
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.dispatch(expandFollowedHashtags());
|
||||
}, 300, { leading: true });
|
||||
|
||||
render () {
|
||||
const { intl, hashtags, isLoading, hasMore, multiColumn } = this.props;
|
||||
|
||||
const emptyMessage = <FormattedMessage id='empty_column.followed_tags' defaultMessage='You have not followed any hashtags yet. When you do, they will show up here.' />;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn}>
|
||||
<ColumnHeader
|
||||
icon='hashtag'
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
showBackButton
|
||||
multiColumn={multiColumn}
|
||||
/>
|
||||
|
||||
<ScrollableList
|
||||
scrollKey='followed_tags'
|
||||
emptyMessage={emptyMessage}
|
||||
hasMore={hasMore}
|
||||
isLoading={isLoading}
|
||||
onLoadMore={this.handleLoadMore}
|
||||
bindToDocument={!multiColumn}
|
||||
>
|
||||
{hashtags.map((hashtag) => (
|
||||
<Hashtag
|
||||
key={hashtag.get('name')}
|
||||
name={hashtag.get('name')}
|
||||
to={`/tags/${hashtag.get('name')}`}
|
||||
withGraph={false}
|
||||
// Taken from ImmutableHashtag. Should maybe refactor ImmutableHashtag to accept more options?
|
||||
people={hashtag.getIn(['history', 0, 'accounts']) * 1 + hashtag.getIn(['history', 1, 'accounts']) * 1}
|
||||
history={hashtag.get('history').reverse().map((day) => day.get('uses')).toArray()}
|
||||
/>
|
||||
))}
|
||||
</ScrollableList>
|
||||
|
||||
<Helmet>
|
||||
<meta name='robots' content='noindex' />
|
||||
</Helmet>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
import {
|
||||
FOLLOWED_HASHTAGS_FETCH_REQUEST,
|
||||
FOLLOWED_HASHTAGS_FETCH_SUCCESS,
|
||||
FOLLOWED_HASHTAGS_FETCH_FAIL,
|
||||
FOLLOWED_HASHTAGS_EXPAND_REQUEST,
|
||||
FOLLOWED_HASHTAGS_EXPAND_SUCCESS,
|
||||
FOLLOWED_HASHTAGS_EXPAND_FAIL,
|
||||
} from 'mastodon/actions/tags';
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
isLoading: false,
|
||||
next: null,
|
||||
});
|
||||
|
||||
export default function followed_tags(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case FOLLOWED_HASHTAGS_FETCH_REQUEST:
|
||||
return state.set('isLoading', true);
|
||||
case FOLLOWED_HASHTAGS_FETCH_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.set('items', fromJS(action.followed_tags));
|
||||
map.set('isLoading', false);
|
||||
map.set('next', action.next);
|
||||
});
|
||||
case FOLLOWED_HASHTAGS_FETCH_FAIL:
|
||||
return state.set('isLoading', false);
|
||||
case FOLLOWED_HASHTAGS_EXPAND_REQUEST:
|
||||
return state.set('isLoading', true);
|
||||
case FOLLOWED_HASHTAGS_EXPAND_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
map.update('items', set => set.concat(fromJS(action.followed_tags)));
|
||||
map.set('isLoading', false);
|
||||
map.set('next', action.next);
|
||||
});
|
||||
case FOLLOWED_HASHTAGS_EXPAND_FAIL:
|
||||
return state.set('isLoading', false);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
Loading…
Reference in New Issue