Skip to content
Snippets Groups Projects
Commit 2a84271e authored by Eugen Rochko's avatar Eugen Rochko
Browse files

Infinite scroll for account timelines

parent 4a670780
No related branches found
No related tags found
No related merge requests found
import api from '../api'
import api from '../api'
import axios from 'axios';
export const ACCOUNT_SET_SELF = 'ACCOUNT_SET_SELF';
......@@ -18,6 +19,10 @@ export const ACCOUNT_TIMELINE_FETCH_REQUEST = 'ACCOUNT_TIMELINE_FETCH_REQUEST';
export const ACCOUNT_TIMELINE_FETCH_SUCCESS = 'ACCOUNT_TIMELINE_FETCH_SUCCESS';
export const ACCOUNT_TIMELINE_FETCH_FAIL = 'ACCOUNT_TIMELINE_FETCH_FAIL';
export const ACCOUNT_TIMELINE_EXPAND_REQUEST = 'ACCOUNT_TIMELINE_EXPAND_REQUEST';
export const ACCOUNT_TIMELINE_EXPAND_SUCCESS = 'ACCOUNT_TIMELINE_EXPAND_SUCCESS';
export const ACCOUNT_TIMELINE_EXPAND_FAIL = 'ACCOUNT_TIMELINE_EXPAND_FAIL';
export function setAccountSelf(account) {
return {
type: ACCOUNT_SET_SELF,
......@@ -27,10 +32,12 @@ export function setAccountSelf(account) {
export function fetchAccount(id) {
return (dispatch, getState) => {
const boundApi = api(getState);
dispatch(fetchAccountRequest(id));
api(getState).get(`/api/accounts/${id}`).then(response => {
dispatch(fetchAccountSuccess(response.data));
axios.all([boundApi.get(`/api/accounts/${id}`), boundApi.get(`/api/accounts/relationships?id=${id}`)]).then(values => {
dispatch(fetchAccountSuccess(values[0].data, values[1].data[0]));
}).catch(error => {
dispatch(fetchAccountFail(id, error));
});
......@@ -49,6 +56,20 @@ export function fetchAccountTimeline(id) {
};
};
export function expandAccountTimeline(id) {
return (dispatch, getState) => {
const lastId = getState().getIn(['timelines', 'accounts_timelines', id]).last();
dispatch(expandAccountTimelineRequest(id));
api(getState).get(`/api/accounts/${id}/statuses?max_id=${lastId}`).then(response => {
dispatch(expandAccountTimelineSuccess(id, response.data));
}).catch(error => {
dispatch(expandAccountTimelineFail(id, error));
});
};
};
export function fetchAccountRequest(id) {
return {
type: ACCOUNT_FETCH_REQUEST,
......@@ -56,10 +77,11 @@ export function fetchAccountRequest(id) {
};
};
export function fetchAccountSuccess(account) {
export function fetchAccountSuccess(account, relationship) {
return {
type: ACCOUNT_FETCH_SUCCESS,
account: account
account: account,
relationship: relationship
};
};
......@@ -159,3 +181,26 @@ export function fetchAccountTimelineFail(id, error) {
error: error
};
};
export function expandAccountTimelineRequest(id) {
return {
type: ACCOUNT_TIMELINE_EXPAND_REQUEST,
id: id
};
};
export function expandAccountTimelineSuccess(id, statuses) {
return {
type: ACCOUNT_TIMELINE_EXPAND_SUCCESS,
id: id,
statuses: statuses
};
};
export function expandAccountTimelineFail(id, error) {
return {
type: ACCOUNT_TIMELINE_EXPAND_FAIL,
id: id,
error: error
};
};
import { connect } from 'react-redux';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { fetchAccount, followAccount, unfollowAccount, fetchAccountTimeline } from '../../actions/accounts';
import { replyCompose } from '../../actions/compose';
import { favourite, reblog } from '../../actions/interactions';
import Header from './components/header';
import { selectStatus } from '../../reducers/timelines';
import StatusList from '../../components/status_list';
import Immutable from 'immutable';
import { connect } from 'react-redux';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ImmutablePropTypes from 'react-immutable-proptypes';
import {
fetchAccount,
followAccount,
unfollowAccount,
fetchAccountTimeline,
expandAccountTimeline
} from '../../actions/accounts';
import { replyCompose } from '../../actions/compose';
import { favourite, reblog } from '../../actions/interactions';
import Header from './components/header';
import { selectStatus } from '../../reducers/timelines';
import StatusList from '../../components/status_list';
import Immutable from 'immutable';
function selectAccount(state, id) {
return state.getIn(['timelines', 'accounts', id], null);
......@@ -65,6 +71,10 @@ const Account = React.createClass({
this.props.dispatch(favourite(status));
},
handleScrollToBottom () {
this.props.dispatch(expandAccountTimeline(this.props.account.get('id')));
},
render () {
const { account, statuses } = this.props;
......@@ -75,7 +85,7 @@ const Account = React.createClass({
return (
<div style={{ display: 'flex', flexDirection: 'column', 'flex': '0 0 auto', height: '100%' }}>
<Header account={account} onFollow={this.handleFollow} onUnfollow={this.handleUnfollow} />
<StatusList statuses={statuses} onReply={this.handleReply} onReblog={this.handleReblog} onFavourite={this.handleFavourite} />
<StatusList statuses={statuses} onScrollToBottom={this.handleScrollToBottom} onReply={this.handleReply} onReblog={this.handleReblog} onFavourite={this.handleFavourite} />
</div>
);
}
......
......@@ -10,7 +10,8 @@ import {
ACCOUNT_FETCH_FAIL,
ACCOUNT_FOLLOW_FAIL,
ACCOUNT_UNFOLLOW_FAIL,
ACCOUNT_TIMELINE_FETCH_FAIL
ACCOUNT_TIMELINE_FETCH_FAIL,
ACCOUNT_TIMELINE_EXPAND_FAIL
} from '../actions/accounts';
import { STATUS_FETCH_FAIL } from '../actions/statuses';
import Immutable from 'immutable';
......@@ -48,6 +49,7 @@ export default function notifications(state = initialState, action) {
case ACCOUNT_FOLLOW_FAIL:
case ACCOUNT_UNFOLLOW_FAIL:
case ACCOUNT_TIMELINE_FETCH_FAIL:
case ACCOUNT_TIMELINE_EXPAND_FAIL:
case STATUS_FETCH_FAIL:
return notificationFromError(state, action.error);
case NOTIFICATION_DISMISS:
......
......@@ -13,7 +13,8 @@ import {
ACCOUNT_FETCH_SUCCESS,
ACCOUNT_FOLLOW_SUCCESS,
ACCOUNT_UNFOLLOW_SUCCESS,
ACCOUNT_TIMELINE_FETCH_SUCCESS
ACCOUNT_TIMELINE_FETCH_SUCCESS,
ACCOUNT_TIMELINE_EXPAND_SUCCESS
} from '../actions/accounts';
import { STATUS_FETCH_SUCCESS } from '../actions/statuses';
import { FOLLOW_SUBMIT_SUCCESS } from '../actions/follow';
......@@ -110,6 +111,17 @@ function normalizeAccountTimeline(state, accountId, statuses) {
return state;
};
function appendNormalizedAccountTimeline(state, accountId, statuses) {
let moreIds = Immutable.List();
statuses.forEach((status, i) => {
state = normalizeStatus(state, status);
moreIds = moreIds.set(i, status.get('id'));
});
return state.updateIn(['accounts_timelines', accountId], Immutable.List(), list => list.push(...moreIds));
};
function updateTimeline(state, timeline, status) {
state = normalizeStatus(state, status);
state = state.update(timeline, list => list.unshift(status.get('id')));
......@@ -176,6 +188,8 @@ export default function timelines(state = initialState, action) {
return normalizeContext(state, Immutable.fromJS(action.status), Immutable.fromJS(action.context.ancestors), Immutable.fromJS(action.context.descendants));
case ACCOUNT_TIMELINE_FETCH_SUCCESS:
return normalizeAccountTimeline(state, action.id, Immutable.fromJS(action.statuses));
case ACCOUNT_TIMELINE_EXPAND_SUCCESS:
return appendNormalizedAccountTimeline(state, action.id, Immutable.fromJS(action.statuses));
default:
return state;
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment