From d9022884c6c4e066b1e6ee8d9c07c220c031454e Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Jan 2017 04:12:10 +0100 Subject: Smarter infinite scroll --- app/assets/javascripts/components/actions/accounts.jsx | 11 ++++++++--- app/assets/javascripts/components/actions/cards.jsx | 2 +- app/assets/javascripts/components/actions/timelines.jsx | 7 ++++++- 3 files changed, 15 insertions(+), 5 deletions(-) (limited to 'app/assets/javascripts/components/actions') diff --git a/app/assets/javascripts/components/actions/accounts.jsx b/app/assets/javascripts/components/actions/accounts.jsx index 235f29194..0be05034e 100644 --- a/app/assets/javascripts/components/actions/accounts.jsx +++ b/app/assets/javascripts/components/actions/accounts.jsx @@ -80,7 +80,7 @@ export function fetchAccount(id) { export function fetchAccountTimeline(id, replace = false) { return (dispatch, getState) => { - const ids = getState().getIn(['timelines', 'accounts_timelines', id], Immutable.List()); + const ids = getState().getIn(['timelines', 'accounts_timelines', id, 'items'], Immutable.List()); const newestId = ids.size > 0 ? ids.first() : null; let params = ''; @@ -103,11 +103,16 @@ export function fetchAccountTimeline(id, replace = false) { export function expandAccountTimeline(id) { return (dispatch, getState) => { - const lastId = getState().getIn(['timelines', 'accounts_timelines', id], Immutable.List()).last(); + const lastId = getState().getIn(['timelines', 'accounts_timelines', id, 'items'], Immutable.List()).last(); dispatch(expandAccountTimelineRequest(id)); - api(getState).get(`/api/v1/accounts/${id}/statuses?max_id=${lastId}`).then(response => { + api(getState).get(`/api/v1/accounts/${id}/statuses`, { + params: { + limit: 10, + max_id: lastId + } + }).then(response => { dispatch(expandAccountTimelineSuccess(id, response.data)); }).catch(error => { dispatch(expandAccountTimelineFail(id, error)); diff --git a/app/assets/javascripts/components/actions/cards.jsx b/app/assets/javascripts/components/actions/cards.jsx index 845d15e93..503c2bfeb 100644 --- a/app/assets/javascripts/components/actions/cards.jsx +++ b/app/assets/javascripts/components/actions/cards.jsx @@ -9,7 +9,7 @@ export function fetchStatusCard(id) { dispatch(fetchStatusCardRequest(id)); api(getState).get(`/api/v1/statuses/${id}/card`).then(response => { - if (!response.data.url) { + if (!response.data.url || !response.data.title || !response.data.description) { return; } diff --git a/app/assets/javascripts/components/actions/timelines.jsx b/app/assets/javascripts/components/actions/timelines.jsx index 72e949e87..1d7e0547c 100644 --- a/app/assets/javascripts/components/actions/timelines.jsx +++ b/app/assets/javascripts/components/actions/timelines.jsx @@ -115,7 +115,12 @@ export function expandTimeline(timeline, id = null) { path = `${path}/${id}` } - api(getState).get(`/api/v1/timelines/${path}?max_id=${lastId}`).then(response => { + api(getState).get(`/api/v1/timelines/${path}`, { + params: { + limit: 10, + max_id: lastId + } + }).then(response => { dispatch(expandTimelineSuccess(timeline, response.data)); }).catch(error => { dispatch(expandTimelineFail(timeline, error)); -- cgit From 21c209636d12ea601379e7abd3d370ad0d22ea18 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Tue, 24 Jan 2017 13:04:12 +0100 Subject: Set isLoading false on timelines when request fails --- .../javascripts/components/actions/timelines.jsx | 7 ++- .../components/features/notifications/index.jsx | 1 + .../javascripts/components/reducers/timelines.jsx | 62 +++++++++++++--------- 3 files changed, 43 insertions(+), 27 deletions(-) (limited to 'app/assets/javascripts/components/actions') diff --git a/app/assets/javascripts/components/actions/timelines.jsx b/app/assets/javascripts/components/actions/timelines.jsx index 1d7e0547c..29a060e87 100644 --- a/app/assets/javascripts/components/actions/timelines.jsx +++ b/app/assets/javascripts/components/actions/timelines.jsx @@ -63,6 +63,10 @@ export function refreshTimelineRequest(timeline, id, skipLoading) { export function refreshTimeline(timeline, id = null) { return function (dispatch, getState) { + if (getState().getIn(['timelines', timeline, 'isLoading'])) { + return; + } + const ids = getState().getIn(['timelines', timeline, 'items'], Immutable.List()); const newestId = ids.size > 0 ? ids.first() : null; @@ -102,8 +106,9 @@ export function expandTimeline(timeline, id = null) { return (dispatch, getState) => { const lastId = getState().getIn(['timelines', timeline, 'items'], Immutable.List()).last(); - if (!lastId) { + if (!lastId || getState().getIn(['timelines', timeline, 'isLoading'])) { // If timeline is empty, don't try to load older posts since there are none + // Also if already loading return; } diff --git a/app/assets/javascripts/components/features/notifications/index.jsx b/app/assets/javascripts/components/features/notifications/index.jsx index d243f178f..366d8f5e9 100644 --- a/app/assets/javascripts/components/features/notifications/index.jsx +++ b/app/assets/javascripts/components/features/notifications/index.jsx @@ -62,6 +62,7 @@ const Notifications = React.createClass({ if (trackScroll) { return ( + {scrollableArea} diff --git a/app/assets/javascripts/components/reducers/timelines.jsx b/app/assets/javascripts/components/reducers/timelines.jsx index 6b1093651..6f2d26dcb 100644 --- a/app/assets/javascripts/components/reducers/timelines.jsx +++ b/app/assets/javascripts/components/reducers/timelines.jsx @@ -1,10 +1,12 @@ import { TIMELINE_REFRESH_REQUEST, TIMELINE_REFRESH_SUCCESS, + TIMELINE_REFRESH_FAIL, TIMELINE_UPDATE, TIMELINE_DELETE, TIMELINE_EXPAND_SUCCESS, TIMELINE_EXPAND_REQUEST, + TIMELINE_EXPAND_FAIL, TIMELINE_SCROLL_TOP } from '../actions/timelines'; import { @@ -16,8 +18,10 @@ import { import { ACCOUNT_TIMELINE_FETCH_REQUEST, ACCOUNT_TIMELINE_FETCH_SUCCESS, + ACCOUNT_TIMELINE_FETCH_FAIL, ACCOUNT_TIMELINE_EXPAND_REQUEST, ACCOUNT_TIMELINE_EXPAND_SUCCESS, + ACCOUNT_TIMELINE_EXPAND_FAIL, ACCOUNT_BLOCK_SUCCESS } from '../actions/accounts'; import { @@ -232,31 +236,37 @@ const resetTimeline = (state, timeline, id) => { export default function timelines(state = initialState, action) { switch(action.type) { - case TIMELINE_REFRESH_REQUEST: - case TIMELINE_EXPAND_REQUEST: - return resetTimeline(state, action.timeline, action.id); - case TIMELINE_REFRESH_SUCCESS: - return normalizeTimeline(state, action.timeline, Immutable.fromJS(action.statuses)); - case TIMELINE_EXPAND_SUCCESS: - return appendNormalizedTimeline(state, action.timeline, Immutable.fromJS(action.statuses)); - case TIMELINE_UPDATE: - return updateTimeline(state, action.timeline, Immutable.fromJS(action.status), action.references); - case TIMELINE_DELETE: - return deleteStatus(state, action.id, action.accountId, action.references, action.reblogOf); - case CONTEXT_FETCH_SUCCESS: - return normalizeContext(state, action.id, Immutable.fromJS(action.ancestors), Immutable.fromJS(action.descendants)); - case ACCOUNT_TIMELINE_FETCH_REQUEST: - case ACCOUNT_TIMELINE_EXPAND_REQUEST: - return state.updateIn(['accounts_timelines', action.id], Immutable.Map(), map => map.set('isLoading', true)); - case ACCOUNT_TIMELINE_FETCH_SUCCESS: - return normalizeAccountTimeline(state, action.id, Immutable.fromJS(action.statuses), action.replace); - case ACCOUNT_TIMELINE_EXPAND_SUCCESS: - return appendNormalizedAccountTimeline(state, action.id, Immutable.fromJS(action.statuses)); - case ACCOUNT_BLOCK_SUCCESS: - return filterTimelines(state, action.relationship, action.statuses); - case TIMELINE_SCROLL_TOP: - return state.setIn([action.timeline, 'top'], action.top); - default: - return state; + case TIMELINE_REFRESH_REQUEST: + case TIMELINE_EXPAND_REQUEST: + return resetTimeline(state, action.timeline, action.id); + case TIMELINE_REFRESH_FAIL: + case TIMELINE_EXPAND_FAIL: + return state.setIn([action.timeline, 'isLoading'], false); + case TIMELINE_REFRESH_SUCCESS: + return normalizeTimeline(state, action.timeline, Immutable.fromJS(action.statuses)); + case TIMELINE_EXPAND_SUCCESS: + return appendNormalizedTimeline(state, action.timeline, Immutable.fromJS(action.statuses)); + case TIMELINE_UPDATE: + return updateTimeline(state, action.timeline, Immutable.fromJS(action.status), action.references); + case TIMELINE_DELETE: + return deleteStatus(state, action.id, action.accountId, action.references, action.reblogOf); + case CONTEXT_FETCH_SUCCESS: + return normalizeContext(state, action.id, Immutable.fromJS(action.ancestors), Immutable.fromJS(action.descendants)); + case ACCOUNT_TIMELINE_FETCH_REQUEST: + case ACCOUNT_TIMELINE_EXPAND_REQUEST: + return state.updateIn(['accounts_timelines', action.id], Immutable.Map(), map => map.set('isLoading', true)); + case ACCOUNT_TIMELINE_FETCH_FAIL: + case ACCOUNT_TIMELINE_EXPAND_FAIL: + return state.updateIn(['accounts_timelines', action.id], Immutable.Map(), map => map.set('isLoading', false)); + case ACCOUNT_TIMELINE_FETCH_SUCCESS: + return normalizeAccountTimeline(state, action.id, Immutable.fromJS(action.statuses), action.replace); + case ACCOUNT_TIMELINE_EXPAND_SUCCESS: + return appendNormalizedAccountTimeline(state, action.id, Immutable.fromJS(action.statuses)); + case ACCOUNT_BLOCK_SUCCESS: + return filterTimelines(state, action.relationship, action.statuses); + case TIMELINE_SCROLL_TOP: + return state.setIn([action.timeline, 'top'], action.top); + default: + return state; } }; -- cgit