mirror of
https://github.com/mastodon/mastodon.git
synced 2024-11-25 07:05:20 +00:00
Infinite scroll for followers/following lists
This commit is contained in:
parent
49b7896953
commit
dbfe1e4be6
|
@ -1,4 +1,4 @@
|
||||||
import api from '../api'
|
import api, { getLinks } from '../api'
|
||||||
import Immutable from 'immutable';
|
import Immutable from 'immutable';
|
||||||
|
|
||||||
export const ACCOUNT_SET_SELF = 'ACCOUNT_SET_SELF';
|
export const ACCOUNT_SET_SELF = 'ACCOUNT_SET_SELF';
|
||||||
|
@ -35,10 +35,18 @@ export const FOLLOWERS_FETCH_REQUEST = 'FOLLOWERS_FETCH_REQUEST';
|
||||||
export const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS';
|
export const FOLLOWERS_FETCH_SUCCESS = 'FOLLOWERS_FETCH_SUCCESS';
|
||||||
export const FOLLOWERS_FETCH_FAIL = 'FOLLOWERS_FETCH_FAIL';
|
export const FOLLOWERS_FETCH_FAIL = 'FOLLOWERS_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const FOLLOWERS_EXPAND_REQUEST = 'FOLLOWERS_EXPAND_REQUEST';
|
||||||
|
export const FOLLOWERS_EXPAND_SUCCESS = 'FOLLOWERS_EXPAND_SUCCESS';
|
||||||
|
export const FOLLOWERS_EXPAND_FAIL = 'FOLLOWERS_EXPAND_FAIL';
|
||||||
|
|
||||||
export const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST';
|
export const FOLLOWING_FETCH_REQUEST = 'FOLLOWING_FETCH_REQUEST';
|
||||||
export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS';
|
export const FOLLOWING_FETCH_SUCCESS = 'FOLLOWING_FETCH_SUCCESS';
|
||||||
export const FOLLOWING_FETCH_FAIL = 'FOLLOWING_FETCH_FAIL';
|
export const FOLLOWING_FETCH_FAIL = 'FOLLOWING_FETCH_FAIL';
|
||||||
|
|
||||||
|
export const FOLLOWING_EXPAND_REQUEST = 'FOLLOWING_EXPAND_REQUEST';
|
||||||
|
export const FOLLOWING_EXPAND_SUCCESS = 'FOLLOWING_EXPAND_SUCCESS';
|
||||||
|
export const FOLLOWING_EXPAND_FAIL = 'FOLLOWING_EXPAND_FAIL';
|
||||||
|
|
||||||
export const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST';
|
export const RELATIONSHIPS_FETCH_REQUEST = 'RELATIONSHIPS_FETCH_REQUEST';
|
||||||
export const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS';
|
export const RELATIONSHIPS_FETCH_SUCCESS = 'RELATIONSHIPS_FETCH_SUCCESS';
|
||||||
export const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL';
|
export const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL';
|
||||||
|
@ -46,7 +54,7 @@ export const RELATIONSHIPS_FETCH_FAIL = 'RELATIONSHIPS_FETCH_FAIL';
|
||||||
export function setAccountSelf(account) {
|
export function setAccountSelf(account) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_SET_SELF,
|
type: ACCOUNT_SET_SELF,
|
||||||
account: account
|
account
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,22 +109,22 @@ export function expandAccountTimeline(id) {
|
||||||
export function fetchAccountRequest(id) {
|
export function fetchAccountRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_FETCH_REQUEST,
|
type: ACCOUNT_FETCH_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchAccountSuccess(account) {
|
export function fetchAccountSuccess(account) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_FETCH_SUCCESS,
|
type: ACCOUNT_FETCH_SUCCESS,
|
||||||
account: account
|
account
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchAccountFail(id, error) {
|
export function fetchAccountFail(id, error) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_FETCH_FAIL,
|
type: ACCOUNT_FETCH_FAIL,
|
||||||
id: id,
|
id,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -147,89 +155,89 @@ export function unfollowAccount(id) {
|
||||||
export function followAccountRequest(id) {
|
export function followAccountRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_FOLLOW_REQUEST,
|
type: ACCOUNT_FOLLOW_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function followAccountSuccess(relationship) {
|
export function followAccountSuccess(relationship) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_FOLLOW_SUCCESS,
|
type: ACCOUNT_FOLLOW_SUCCESS,
|
||||||
relationship: relationship
|
relationship
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function followAccountFail(error) {
|
export function followAccountFail(error) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_FOLLOW_FAIL,
|
type: ACCOUNT_FOLLOW_FAIL,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function unfollowAccountRequest(id) {
|
export function unfollowAccountRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_UNFOLLOW_REQUEST,
|
type: ACCOUNT_UNFOLLOW_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function unfollowAccountSuccess(relationship) {
|
export function unfollowAccountSuccess(relationship) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_UNFOLLOW_SUCCESS,
|
type: ACCOUNT_UNFOLLOW_SUCCESS,
|
||||||
relationship: relationship
|
relationship
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function unfollowAccountFail(error) {
|
export function unfollowAccountFail(error) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_UNFOLLOW_FAIL,
|
type: ACCOUNT_UNFOLLOW_FAIL,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchAccountTimelineRequest(id) {
|
export function fetchAccountTimelineRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_TIMELINE_FETCH_REQUEST,
|
type: ACCOUNT_TIMELINE_FETCH_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchAccountTimelineSuccess(id, statuses, replace) {
|
export function fetchAccountTimelineSuccess(id, statuses, replace) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_TIMELINE_FETCH_SUCCESS,
|
type: ACCOUNT_TIMELINE_FETCH_SUCCESS,
|
||||||
id: id,
|
id,
|
||||||
statuses: statuses,
|
statuses,
|
||||||
replace: replace
|
replace
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchAccountTimelineFail(id, error) {
|
export function fetchAccountTimelineFail(id, error) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_TIMELINE_FETCH_FAIL,
|
type: ACCOUNT_TIMELINE_FETCH_FAIL,
|
||||||
id: id,
|
id,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function expandAccountTimelineRequest(id) {
|
export function expandAccountTimelineRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_TIMELINE_EXPAND_REQUEST,
|
type: ACCOUNT_TIMELINE_EXPAND_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function expandAccountTimelineSuccess(id, statuses) {
|
export function expandAccountTimelineSuccess(id, statuses) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_TIMELINE_EXPAND_SUCCESS,
|
type: ACCOUNT_TIMELINE_EXPAND_SUCCESS,
|
||||||
id: id,
|
id,
|
||||||
statuses: statuses
|
statuses
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function expandAccountTimelineFail(id, error) {
|
export function expandAccountTimelineFail(id, error) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_TIMELINE_EXPAND_FAIL,
|
type: ACCOUNT_TIMELINE_EXPAND_FAIL,
|
||||||
id: id,
|
id,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -260,42 +268,42 @@ export function unblockAccount(id) {
|
||||||
export function blockAccountRequest(id) {
|
export function blockAccountRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_BLOCK_REQUEST,
|
type: ACCOUNT_BLOCK_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function blockAccountSuccess(relationship) {
|
export function blockAccountSuccess(relationship) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_BLOCK_SUCCESS,
|
type: ACCOUNT_BLOCK_SUCCESS,
|
||||||
relationship: relationship
|
relationship
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function blockAccountFail(error) {
|
export function blockAccountFail(error) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_BLOCK_FAIL,
|
type: ACCOUNT_BLOCK_FAIL,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function unblockAccountRequest(id) {
|
export function unblockAccountRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_UNBLOCK_REQUEST,
|
type: ACCOUNT_UNBLOCK_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function unblockAccountSuccess(relationship) {
|
export function unblockAccountSuccess(relationship) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_UNBLOCK_SUCCESS,
|
type: ACCOUNT_UNBLOCK_SUCCESS,
|
||||||
relationship: relationship
|
relationship
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function unblockAccountFail(error) {
|
export function unblockAccountFail(error) {
|
||||||
return {
|
return {
|
||||||
type: ACCOUNT_UNBLOCK_FAIL,
|
type: ACCOUNT_UNBLOCK_FAIL,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -304,7 +312,9 @@ export function fetchFollowers(id) {
|
||||||
dispatch(fetchFollowersRequest(id));
|
dispatch(fetchFollowersRequest(id));
|
||||||
|
|
||||||
api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => {
|
api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => {
|
||||||
dispatch(fetchFollowersSuccess(id, response.data));
|
const prev = getLinks(response).refs.find(link => link.rel === 'prev').uri;
|
||||||
|
|
||||||
|
dispatch(fetchFollowersSuccess(id, response.data, prev));
|
||||||
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchFollowersFail(id, error));
|
dispatch(fetchFollowersFail(id, error));
|
||||||
|
@ -315,23 +325,65 @@ export function fetchFollowers(id) {
|
||||||
export function fetchFollowersRequest(id) {
|
export function fetchFollowersRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOWERS_FETCH_REQUEST,
|
type: FOLLOWERS_FETCH_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchFollowersSuccess(id, accounts) {
|
export function fetchFollowersSuccess(id, accounts, prev) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOWERS_FETCH_SUCCESS,
|
type: FOLLOWERS_FETCH_SUCCESS,
|
||||||
id: id,
|
id,
|
||||||
accounts: accounts
|
accounts,
|
||||||
|
prev
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchFollowersFail(id, error) {
|
export function fetchFollowersFail(id, error) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOWERS_FETCH_FAIL,
|
type: FOLLOWERS_FETCH_FAIL,
|
||||||
id: id,
|
id,
|
||||||
error: error
|
error
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowers(id) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const url = getState().getIn(['user_lists', 'followers', id, 'prev']);
|
||||||
|
|
||||||
|
dispatch(expandFollowersRequest(id));
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const prev = getLinks(response).refs.find(link => link.rel === 'prev').uri;
|
||||||
|
|
||||||
|
dispatch(expandFollowersSuccess(id, response.data, prev));
|
||||||
|
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandFollowersFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowersRequest(id) {
|
||||||
|
return {
|
||||||
|
type: FOLLOWERS_EXPAND_REQUEST,
|
||||||
|
id
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowersSuccess(id, accounts, prev) {
|
||||||
|
return {
|
||||||
|
type: FOLLOWERS_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
prev
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowersFail(id, error) {
|
||||||
|
return {
|
||||||
|
type: FOLLOWERS_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -351,23 +403,64 @@ export function fetchFollowing(id) {
|
||||||
export function fetchFollowingRequest(id) {
|
export function fetchFollowingRequest(id) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOWING_FETCH_REQUEST,
|
type: FOLLOWING_FETCH_REQUEST,
|
||||||
id: id
|
id
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchFollowingSuccess(id, accounts) {
|
export function fetchFollowingSuccess(id, accounts) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOWING_FETCH_SUCCESS,
|
type: FOLLOWING_FETCH_SUCCESS,
|
||||||
id: id,
|
id,
|
||||||
accounts: accounts
|
accounts
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchFollowingFail(id, error) {
|
export function fetchFollowingFail(id, error) {
|
||||||
return {
|
return {
|
||||||
type: FOLLOWING_FETCH_FAIL,
|
type: FOLLOWING_FETCH_FAIL,
|
||||||
id: id,
|
id,
|
||||||
error: error
|
error
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowing(id) {
|
||||||
|
return (dispatch, getState) => {
|
||||||
|
const url = getState().getIn(['user_lists', 'following', id, 'prev']);
|
||||||
|
|
||||||
|
dispatch(expandFollowingRequest(id));
|
||||||
|
|
||||||
|
api(getState).get(url).then(response => {
|
||||||
|
const prev = getLinks(response).refs.find(link => link.rel === 'prev').uri;
|
||||||
|
|
||||||
|
dispatch(expandFollowingSuccess(id, response.data, prev));
|
||||||
|
dispatch(fetchRelationships(response.data.map(item => item.id)));
|
||||||
|
}).catch(error => {
|
||||||
|
dispatch(expandFollowingFail(id, error));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowingRequest(id) {
|
||||||
|
return {
|
||||||
|
type: FOLLOWING_EXPAND_REQUEST,
|
||||||
|
id
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowingSuccess(id, accounts, prev) {
|
||||||
|
return {
|
||||||
|
type: FOLLOWING_EXPAND_SUCCESS,
|
||||||
|
id,
|
||||||
|
accounts,
|
||||||
|
prev
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export function expandFollowingFail(id, error) {
|
||||||
|
return {
|
||||||
|
type: FOLLOWING_EXPAND_FAIL,
|
||||||
|
id,
|
||||||
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -386,20 +479,20 @@ export function fetchRelationships(account_ids) {
|
||||||
export function fetchRelationshipsRequest(ids) {
|
export function fetchRelationshipsRequest(ids) {
|
||||||
return {
|
return {
|
||||||
type: RELATIONSHIPS_FETCH_REQUEST,
|
type: RELATIONSHIPS_FETCH_REQUEST,
|
||||||
ids: ids
|
ids
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchRelationshipsSuccess(relationships) {
|
export function fetchRelationshipsSuccess(relationships) {
|
||||||
return {
|
return {
|
||||||
type: RELATIONSHIPS_FETCH_SUCCESS,
|
type: RELATIONSHIPS_FETCH_SUCCESS,
|
||||||
relationships: relationships
|
relationships
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function fetchRelationshipsFail(error) {
|
export function fetchRelationshipsFail(error) {
|
||||||
return {
|
return {
|
||||||
type: RELATIONSHIPS_FETCH_FAIL,
|
type: RELATIONSHIPS_FETCH_FAIL,
|
||||||
error: error
|
error
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import LinkHeader from 'http-link-header';
|
||||||
|
|
||||||
|
export const getLinks = response => {
|
||||||
|
return LinkHeader.parse(response.headers.link);
|
||||||
|
};
|
||||||
|
|
||||||
export default getState => axios.create({
|
export default getState => axios.create({
|
||||||
headers: {
|
headers: {
|
||||||
|
|
|
@ -7,7 +7,6 @@ const UploadForm = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
media: ImmutablePropTypes.list.isRequired,
|
media: ImmutablePropTypes.list.isRequired,
|
||||||
is_uploading: React.PropTypes.bool,
|
is_uploading: React.PropTypes.bool,
|
||||||
onSelectFile: React.PropTypes.func.isRequired,
|
|
||||||
onRemoveFile: React.PropTypes.func.isRequired
|
onRemoveFile: React.PropTypes.func.isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import LoadingIndicator from '../../components/loading_indicator';
|
||||||
import { fetchFollowers } from '../../actions/accounts';
|
import {
|
||||||
import { ScrollContainer } from 'react-router-scroll';
|
fetchFollowers,
|
||||||
import AccountContainer from './containers/account_container';
|
expandFollowers
|
||||||
|
} from '../../actions/accounts';
|
||||||
|
import { ScrollContainer } from 'react-router-scroll';
|
||||||
|
import AccountContainer from './containers/account_container';
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
accountIds: state.getIn(['user_lists', 'followers', Number(props.params.accountId)])
|
accountIds: state.getIn(['user_lists', 'followers', Number(props.params.accountId), 'items'])
|
||||||
});
|
});
|
||||||
|
|
||||||
const Followers = React.createClass({
|
const Followers = React.createClass({
|
||||||
|
@ -30,6 +33,14 @@ const Followers = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleScroll (e) {
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = e.target;
|
||||||
|
|
||||||
|
if (scrollTop === scrollHeight - clientHeight) {
|
||||||
|
this.props.dispatch(expandFollowers(Number(this.props.params.accountId)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { accountIds } = this.props;
|
const { accountIds } = this.props;
|
||||||
|
|
||||||
|
@ -39,8 +50,10 @@ const Followers = React.createClass({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollContainer scrollKey='followers'>
|
<ScrollContainer scrollKey='followers'>
|
||||||
<div className='scrollable'>
|
<div className='scrollable' onScroll={this.handleScroll}>
|
||||||
{accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)}
|
<div>
|
||||||
|
{accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ScrollContainer>
|
</ScrollContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
import PureRenderMixin from 'react-addons-pure-render-mixin';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import LoadingIndicator from '../../components/loading_indicator';
|
import LoadingIndicator from '../../components/loading_indicator';
|
||||||
import { fetchFollowing } from '../../actions/accounts';
|
import {
|
||||||
import { ScrollContainer } from 'react-router-scroll';
|
fetchFollowing,
|
||||||
import AccountContainer from '../followers/containers/account_container';
|
expandFollowing
|
||||||
|
} from '../../actions/accounts';
|
||||||
|
import { ScrollContainer } from 'react-router-scroll';
|
||||||
|
import AccountContainer from '../followers/containers/account_container';
|
||||||
|
|
||||||
const mapStateToProps = (state, props) => ({
|
const mapStateToProps = (state, props) => ({
|
||||||
accountIds: state.getIn(['user_lists', 'following', Number(props.params.accountId)])
|
accountIds: state.getIn(['user_lists', 'following', Number(props.params.accountId), 'items'])
|
||||||
});
|
});
|
||||||
|
|
||||||
const Following = React.createClass({
|
const Following = React.createClass({
|
||||||
|
@ -30,6 +33,14 @@ const Following = React.createClass({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
handleScroll (e) {
|
||||||
|
const { scrollTop, scrollHeight, clientHeight } = e.target;
|
||||||
|
|
||||||
|
if (scrollTop === scrollHeight - clientHeight) {
|
||||||
|
this.props.dispatch(expandFollowing(Number(this.props.params.accountId)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { accountIds } = this.props;
|
const { accountIds } = this.props;
|
||||||
|
|
||||||
|
@ -39,8 +50,10 @@ const Following = React.createClass({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollContainer scrollKey='following'>
|
<ScrollContainer scrollKey='following'>
|
||||||
<div className='scrollable'>
|
<div className='scrollable' onScroll={this.handleScroll}>
|
||||||
{accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)}
|
<div>
|
||||||
|
{accountIds.map(id => <AccountContainer key={id} id={id} withNote={false} />)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ScrollContainer>
|
</ScrollContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,9 @@ import {
|
||||||
ACCOUNT_SET_SELF,
|
ACCOUNT_SET_SELF,
|
||||||
ACCOUNT_FETCH_SUCCESS,
|
ACCOUNT_FETCH_SUCCESS,
|
||||||
FOLLOWERS_FETCH_SUCCESS,
|
FOLLOWERS_FETCH_SUCCESS,
|
||||||
|
FOLLOWERS_EXPAND_SUCCESS,
|
||||||
FOLLOWING_FETCH_SUCCESS,
|
FOLLOWING_FETCH_SUCCESS,
|
||||||
|
FOLLOWING_EXPAND_SUCCESS,
|
||||||
ACCOUNT_TIMELINE_FETCH_SUCCESS,
|
ACCOUNT_TIMELINE_FETCH_SUCCESS,
|
||||||
ACCOUNT_TIMELINE_EXPAND_SUCCESS
|
ACCOUNT_TIMELINE_EXPAND_SUCCESS
|
||||||
} from '../actions/accounts';
|
} from '../actions/accounts';
|
||||||
|
@ -65,7 +67,9 @@ export default function accounts(state = initialState, action) {
|
||||||
return normalizeAccount(state, action.account);
|
return normalizeAccount(state, action.account);
|
||||||
case SUGGESTIONS_FETCH_SUCCESS:
|
case SUGGESTIONS_FETCH_SUCCESS:
|
||||||
case FOLLOWERS_FETCH_SUCCESS:
|
case FOLLOWERS_FETCH_SUCCESS:
|
||||||
|
case FOLLOWERS_EXPAND_SUCCESS:
|
||||||
case FOLLOWING_FETCH_SUCCESS:
|
case FOLLOWING_FETCH_SUCCESS:
|
||||||
|
case FOLLOWING_EXPAND_SUCCESS:
|
||||||
case REBLOGS_FETCH_SUCCESS:
|
case REBLOGS_FETCH_SUCCESS:
|
||||||
case FAVOURITES_FETCH_SUCCESS:
|
case FAVOURITES_FETCH_SUCCESS:
|
||||||
case COMPOSE_SUGGESTIONS_READY:
|
case COMPOSE_SUGGESTIONS_READY:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import {
|
import {
|
||||||
FOLLOWERS_FETCH_SUCCESS,
|
FOLLOWERS_FETCH_SUCCESS,
|
||||||
FOLLOWING_FETCH_SUCCESS
|
FOLLOWERS_EXPAND_SUCCESS,
|
||||||
|
FOLLOWING_FETCH_SUCCESS,
|
||||||
|
FOLLOWING_EXPAND_SUCCESS
|
||||||
} from '../actions/accounts';
|
} from '../actions/accounts';
|
||||||
import { SUGGESTIONS_FETCH_SUCCESS } from '../actions/suggestions';
|
import { SUGGESTIONS_FETCH_SUCCESS } from '../actions/suggestions';
|
||||||
import {
|
import {
|
||||||
|
@ -17,12 +19,29 @@ const initialState = Immutable.Map({
|
||||||
favourited_by: Immutable.Map()
|
favourited_by: Immutable.Map()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const normalizeList = (state, type, id, accounts, prev) => {
|
||||||
|
return state.setIn([type, id], Immutable.Map({
|
||||||
|
prev,
|
||||||
|
items: Immutable.List(accounts.map(item => item.id))
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const appendToList = (state, type, id, accounts, prev) => {
|
||||||
|
return state.updateIn([type, id], map => {
|
||||||
|
return map.set('prev', prev).update('items', list => list.push(...accounts.map(item => item.id)));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export default function userLists(state = initialState, action) {
|
export default function userLists(state = initialState, action) {
|
||||||
switch(action.type) {
|
switch(action.type) {
|
||||||
case FOLLOWERS_FETCH_SUCCESS:
|
case FOLLOWERS_FETCH_SUCCESS:
|
||||||
return state.setIn(['followers', action.id], Immutable.List(action.accounts.map(item => item.id)));
|
return normalizeList(state, 'followers', action.id, action.accounts, action.prev);
|
||||||
|
case FOLLOWERS_EXPAND_SUCCESS:
|
||||||
|
return appendToList(state, 'followers', action.id, action.accounts, action.prev);
|
||||||
case FOLLOWING_FETCH_SUCCESS:
|
case FOLLOWING_FETCH_SUCCESS:
|
||||||
return state.setIn(['following', action.id], Immutable.List(action.accounts.map(item => item.id)));
|
return normalizeList(state, 'following', action.id, action.accounts, action.prev);
|
||||||
|
case FOLLOWING_EXPAND_SUCCESS:
|
||||||
|
return appendToList(state, 'following', action.id, action.accounts, action.prev);
|
||||||
case SUGGESTIONS_FETCH_SUCCESS:
|
case SUGGESTIONS_FETCH_SUCCESS:
|
||||||
return state.set('suggestions', Immutable.List(action.accounts.map(item => item.id)));
|
return state.set('suggestions', Immutable.List(action.accounts.map(item => item.id)));
|
||||||
case REBLOGS_FETCH_SUCCESS:
|
case REBLOGS_FETCH_SUCCESS:
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||||
"emojione": "^2.2.6",
|
"emojione": "^2.2.6",
|
||||||
|
"http-link-header": "^0.5.0",
|
||||||
"react-autosuggest": "^7.0.1",
|
"react-autosuggest": "^7.0.1",
|
||||||
"react-decoration": "^1.4.0",
|
"react-decoration": "^1.4.0",
|
||||||
"react-motion": "^0.4.5",
|
"react-motion": "^0.4.5",
|
||||||
|
|
|
@ -2399,6 +2399,10 @@ http-errors@~1.5.0:
|
||||||
setprototypeof "1.0.1"
|
setprototypeof "1.0.1"
|
||||||
statuses ">= 1.3.0 < 2"
|
statuses ">= 1.3.0 < 2"
|
||||||
|
|
||||||
|
http-link-header:
|
||||||
|
version "0.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/http-link-header/-/http-link-header-0.5.0.tgz#68598d92c55d3dac7d3e6ae405142fecf7bd3303"
|
||||||
|
|
||||||
http-signature@~1.1.0:
|
http-signature@~1.1.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
|
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf"
|
||||||
|
|
Loading…
Reference in a new issue