Add emoji reaction api pagination support
This commit is contained in:
parent
5fd2a57502
commit
2667e478d3
4 changed files with 104 additions and 15 deletions
|
@ -33,7 +33,7 @@ class Api::V1::Statuses::EmojiReactionedByAccountsController < Api::BaseControll
|
||||||
|
|
||||||
def paginated_emoji_reactions
|
def paginated_emoji_reactions
|
||||||
EmojiReaction.paginate_by_max_id(
|
EmojiReaction.paginate_by_max_id(
|
||||||
limit_param(1000), # limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
limit_param(DEFAULT_ACCOUNTS_LIMIT),
|
||||||
params[:max_id],
|
params[:max_id],
|
||||||
params[:since_id]
|
params[:since_id]
|
||||||
)
|
)
|
||||||
|
|
|
@ -51,6 +51,10 @@ export const EMOJI_REACTIONS_FETCH_REQUEST = 'EMOJI_REACTIONS_FETCH_REQUEST';
|
||||||
export const EMOJI_REACTIONS_FETCH_SUCCESS = 'EMOJI_REACTIONS_FETCH_SUCCESS';
|
export const EMOJI_REACTIONS_FETCH_SUCCESS = 'EMOJI_REACTIONS_FETCH_SUCCESS';
|
||||||
export const EMOJI_REACTIONS_FETCH_FAIL = 'EMOJI_REACTIONS_FETCH_FAIL';
|
export const EMOJI_REACTIONS_FETCH_FAIL = 'EMOJI_REACTIONS_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const EMOJI_REACTIONS_EXPAND_REQUEST = 'EMOJI_REACTIONS_EXPAND_REQUEST';
|
||||||
|
export const EMOJI_REACTIONS_EXPAND_SUCCESS = 'EMOJI_REACTIONS_EXPAND_SUCCESS';
|
||||||
|
export const EMOJI_REACTIONS_EXPAND_FAIL = 'EMOJI_REACTIONS_EXPAND_FAIL';
|
||||||
|
|
||||||
export const PIN_REQUEST = 'PIN_REQUEST';
|
export const PIN_REQUEST = 'PIN_REQUEST';
|
||||||
export const PIN_SUCCESS = 'PIN_SUCCESS';
|
export const PIN_SUCCESS = 'PIN_SUCCESS';
|
||||||
export const PIN_FAIL = 'PIN_FAIL';
|
export const PIN_FAIL = 'PIN_FAIL';
|
||||||
|
@ -547,8 +551,9 @@ export function fetchEmojiReactions(id) {
|
||||||
dispatch(fetchEmojiReactionsRequest(id));
|
dispatch(fetchEmojiReactionsRequest(id));
|
||||||
|
|
||||||
api(getState).get(`/api/v1/statuses/${id}/emoji_reactioned_by`).then(response => {
|
api(getState).get(`/api/v1/statuses/${id}/emoji_reactioned_by`).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
dispatch(importFetchedAccounts(response.data.map((er) => er.account)));
|
dispatch(importFetchedAccounts(response.data.map((er) => er.account)));
|
||||||
dispatch(fetchEmojiReactionsSuccess(id, response.data));
|
dispatch(fetchEmojiReactionsSuccess(id, response.data, next ? next.uri : null));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchEmojiReactionsFail(id, error));
|
dispatch(fetchEmojiReactionsFail(id, error));
|
||||||
});
|
});
|
||||||
|
@ -562,11 +567,12 @@ export function fetchEmojiReactionsRequest(id) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchEmojiReactionsSuccess(id, accounts) {
|
export function fetchEmojiReactionsSuccess(id, accounts, next) {
|
||||||
return {
|
return {
|
||||||
type: EMOJI_REACTIONS_FETCH_SUCCESS,
|
type: EMOJI_REACTIONS_FETCH_SUCCESS,
|
||||||
id,
|
id,
|
||||||
accounts,
|
accounts,
|
||||||
|
next,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,6 +583,48 @@ export function fetchEmojiReactionsFail(id, error) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function expandEmojiReactions(id) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const url = getState().getIn(['user_lists', 'emoji_reactioned_by', id, 'next']);
|
||||||
|
if (url === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(expandEmojiReactionsRequest(id));
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||||
|
|
||||||
|
dispatch(importFetchedAccounts(response.data.map((er) => er.account)));
|
||||||
|
dispatch(expandEmojiReactionsSuccess(id, response.data, next ? next.uri : null));
|
||||||
|
}).catch(error => dispatch(expandEmojiReactionsFail(id, error)));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandEmojiReactionsRequest(id) {
|
||||||
|
return {
|
||||||
|
type: EMOJI_REACTIONS_EXPAND_REQUEST,
|
||||||
|
id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandEmojiReactionsSuccess(id, accounts, next) {
|
||||||
|
return {
|
||||||
|
type: EMOJI_REACTIONS_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
next,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandEmojiReactionsFail(id, error) {
|
||||||
|
return {
|
||||||
|
type: EMOJI_REACTIONS_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchStatusReferences(id) {
|
export function fetchStatusReferences(id) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(fetchStatusReferencesRequest(id));
|
dispatch(fetchStatusReferencesRequest(id));
|
||||||
|
|
|
@ -8,7 +8,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { fetchEmojiReactions } from 'mastodon/actions/interactions';
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
|
import { fetchEmojiReactions, expandEmojiReactions } from 'mastodon/actions/interactions';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||||
|
@ -25,7 +27,9 @@ const messages = defineMessages({
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => {
|
const mapStateToProps = (state, props) => {
|
||||||
return {
|
return {
|
||||||
accountIds: state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId]),
|
accountIds: state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId, 'items']),
|
||||||
|
hasMore: !!state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId, 'next']),
|
||||||
|
isLoading: state.getIn(['user_lists', 'emoji_reactioned_by', props.params.statusId, 'isLoading'], true),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,6 +39,8 @@ class EmojiReactions extends ImmutablePureComponent {
|
||||||
params: PropTypes.object.isRequired,
|
params: PropTypes.object.isRequired,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
accountIds: ImmutablePropTypes.list,
|
accountIds: ImmutablePropTypes.list,
|
||||||
|
hasMore: PropTypes.bool,
|
||||||
|
isLoading: PropTypes.bool,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
@ -45,18 +51,16 @@ class EmojiReactions extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
|
||||||
if (nextProps.params.statusId !== this.props.params.statusId && nextProps.params.statusId) {
|
|
||||||
this.props.dispatch(fetchEmojiReactions(nextProps.params.statusId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleRefresh = () => {
|
handleRefresh = () => {
|
||||||
this.props.dispatch(fetchEmojiReactions(this.props.params.statusId));
|
this.props.dispatch(fetchEmojiReactions(this.props.params.statusId));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleLoadMore = debounce(() => {
|
||||||
|
this.props.dispatch(expandEmojiReactions(this.props.params.statusId));
|
||||||
|
}, 300, { leading: true });
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, accountIds, multiColumn } = this.props;
|
const { intl, accountIds, hasMore, isLoading, multiColumn } = this.props;
|
||||||
|
|
||||||
if (!accountIds) {
|
if (!accountIds) {
|
||||||
return (
|
return (
|
||||||
|
@ -68,7 +72,7 @@ class EmojiReactions extends ImmutablePureComponent {
|
||||||
|
|
||||||
let groups = {};
|
let groups = {};
|
||||||
for (const emoji_reaction of accountIds) {
|
for (const emoji_reaction of accountIds) {
|
||||||
const key = emoji_reaction.account.id;
|
const key = emoji_reaction.account_id;
|
||||||
const value = emoji_reaction;
|
const value = emoji_reaction;
|
||||||
if (!groups[key]) groups[key] = [value];
|
if (!groups[key]) groups[key] = [value];
|
||||||
else groups[key].push(value);
|
else groups[key].push(value);
|
||||||
|
@ -82,12 +86,15 @@ class EmojiReactions extends ImmutablePureComponent {
|
||||||
showBackButton
|
showBackButton
|
||||||
multiColumn={multiColumn}
|
multiColumn={multiColumn}
|
||||||
extraButton={(
|
extraButton={(
|
||||||
<button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleRefresh}><Icon id='refresh' /></button>
|
<button type='button' className='column-header__button' title={intl.formatMessage(messages.refresh)} aria-label={intl.formatMessage(messages.refresh)} onClick={this.handleLoadMore}><Icon id='refresh' /></button>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
scrollKey='emoji_reactions'
|
scrollKey='emoji_reactions'
|
||||||
|
onLoadMore={this.handleLoadMore}
|
||||||
|
hasMore={hasMore}
|
||||||
|
isLoading={isLoading}
|
||||||
emptyMessage={emptyMessage}
|
emptyMessage={emptyMessage}
|
||||||
bindToDocument={!multiColumn}
|
bindToDocument={!multiColumn}
|
||||||
>
|
>
|
||||||
|
|
|
@ -57,7 +57,12 @@ import {
|
||||||
FAVOURITES_EXPAND_REQUEST,
|
FAVOURITES_EXPAND_REQUEST,
|
||||||
FAVOURITES_EXPAND_SUCCESS,
|
FAVOURITES_EXPAND_SUCCESS,
|
||||||
FAVOURITES_EXPAND_FAIL,
|
FAVOURITES_EXPAND_FAIL,
|
||||||
|
EMOJI_REACTIONS_FETCH_REQUEST,
|
||||||
EMOJI_REACTIONS_FETCH_SUCCESS,
|
EMOJI_REACTIONS_FETCH_SUCCESS,
|
||||||
|
EMOJI_REACTIONS_FETCH_FAIL,
|
||||||
|
EMOJI_REACTIONS_EXPAND_REQUEST,
|
||||||
|
EMOJI_REACTIONS_EXPAND_SUCCESS,
|
||||||
|
EMOJI_REACTIONS_EXPAND_FAIL,
|
||||||
STATUS_REFERENCES_FETCH_SUCCESS,
|
STATUS_REFERENCES_FETCH_SUCCESS,
|
||||||
} from '../actions/interactions';
|
} from '../actions/interactions';
|
||||||
import {
|
import {
|
||||||
|
@ -101,12 +106,33 @@ const normalizeList = (state, path, accounts, next) => {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const normalizeEmojiReactionList = (state, path, rows, next) => {
|
||||||
|
return state.setIn(path, ImmutableMap({
|
||||||
|
next,
|
||||||
|
items: ImmutableList(rows.map(normalizeEmojiReactionRow)),
|
||||||
|
isLoading: false,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
const appendToList = (state, path, accounts, next) => {
|
const appendToList = (state, path, accounts, next) => {
|
||||||
return state.updateIn(path, map => {
|
return state.updateIn(path, map => {
|
||||||
return map.set('next', next).set('isLoading', false).update('items', list => list.concat(accounts.map(item => item.id)));
|
return map.set('next', next).set('isLoading', false).update('items', list => list.concat(accounts.map(item => item.id)));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const appendToEmojiReactionList = (state, path, rows, next) => {
|
||||||
|
return state.updateIn(path, map => {
|
||||||
|
return map.set('next', next).set('isLoading', false).update('items', list => list.concat(rows.map(normalizeEmojiReactionRow)));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeEmojiReactionRow = (row) => {
|
||||||
|
const accountId = row.account ? row.account.id : 0;
|
||||||
|
delete row.account;
|
||||||
|
row.account_id = accountId;
|
||||||
|
return row;
|
||||||
|
};
|
||||||
|
|
||||||
const normalizeFollowRequest = (state, notification) => {
|
const normalizeFollowRequest = (state, notification) => {
|
||||||
return state.updateIn(['follow_requests', 'items'], list => {
|
return state.updateIn(['follow_requests', 'items'], list => {
|
||||||
return list.filterNot(item => item === notification.account.id).unshift(notification.account.id);
|
return list.filterNot(item => item === notification.account.id).unshift(notification.account.id);
|
||||||
|
@ -167,8 +193,16 @@ export default function userLists(state = initialState, action) {
|
||||||
case FAVOURITES_FETCH_FAIL:
|
case FAVOURITES_FETCH_FAIL:
|
||||||
case FAVOURITES_EXPAND_FAIL:
|
case FAVOURITES_EXPAND_FAIL:
|
||||||
return state.setIn(['favourited_by', action.id, 'isLoading'], false);
|
return state.setIn(['favourited_by', action.id, 'isLoading'], false);
|
||||||
|
case EMOJI_REACTIONS_FETCH_REQUEST:
|
||||||
|
case EMOJI_REACTIONS_EXPAND_REQUEST:
|
||||||
|
return state.setIn(['emoji_reactioned_by', action.id, 'isLoading'], true);
|
||||||
|
case EMOJI_REACTIONS_FETCH_FAIL:
|
||||||
|
case EMOJI_REACTIONS_EXPAND_FAIL:
|
||||||
|
return state.setIn(['emoji_reactioned_by', action.id, 'isLoading'], false);
|
||||||
case EMOJI_REACTIONS_FETCH_SUCCESS:
|
case EMOJI_REACTIONS_FETCH_SUCCESS:
|
||||||
return state.setIn(['emoji_reactioned_by', action.id], ImmutableList(action.accounts));
|
return normalizeEmojiReactionList(state, ['emoji_reactioned_by', action.id], action.accounts, action.next);
|
||||||
|
case EMOJI_REACTIONS_EXPAND_SUCCESS:
|
||||||
|
return appendToEmojiReactionList(state, ['emoji_reactioned_by', action.id], action.accounts, action.next);
|
||||||
case STATUS_REFERENCES_FETCH_SUCCESS:
|
case STATUS_REFERENCES_FETCH_SUCCESS:
|
||||||
return state.setIn(['referred_by', action.id], ImmutableList(action.statuses.map(item => item.id)));
|
return state.setIn(['referred_by', action.id], ImmutableList(action.statuses.map(item => item.id)));
|
||||||
case NOTIFICATIONS_UPDATE:
|
case NOTIFICATIONS_UPDATE:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue