Infinite scroll for account timelines
This commit is contained in:
		
							parent
							
								
									4a670780f0
								
							
						
					
					
						commit
						2a84271e85
					
				| @ -1,4 +1,5 @@ | ||||
| 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 | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @ -1,13 +1,19 @@ | ||||
| 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; | ||||
|   } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user