about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features
diff options
context:
space:
mode:
authorThibaut Girka <thib@sitedethib.com>2018-05-27 19:10:37 +0200
committerThibG <thib@sitedethib.com>2018-05-29 21:25:28 +0200
commit0ad3eedd4cf6d1d7f7ceacc2c4412dbd8ee79cef (patch)
tree9ce0301ec860e4ca5c3cf3ef2a03bcc471aa7e94 /app/javascript/flavours/glitch/features
parent532fb8e2150c70c627d57f9f72f8232606976a4a (diff)
[Glitch] Allow clients to fetch statuses made while they were offline
Port 9a1a55ce526c956ac6b35897d483c316b7ad4394 to glitch-soc
Diffstat (limited to 'app/javascript/flavours/glitch/features')
-rw-r--r--app/javascript/flavours/glitch/features/account_gallery/index.js57
-rw-r--r--app/javascript/flavours/glitch/features/account_timeline/index.js18
-rw-r--r--app/javascript/flavours/glitch/features/community_timeline/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/hashtag_timeline/index.js15
-rw-r--r--app/javascript/flavours/glitch/features/home_timeline/index.js12
-rw-r--r--app/javascript/flavours/glitch/features/list_timeline/index.js10
-rw-r--r--app/javascript/flavours/glitch/features/public_timeline/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/standalone/community_timeline/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/standalone/public_timeline/index.js13
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/report_modal.js6
-rw-r--r--app/javascript/flavours/glitch/features/ui/containers/status_list_container.js6
-rw-r--r--app/javascript/flavours/glitch/features/ui/index.js4
13 files changed, 101 insertions, 92 deletions
diff --git a/app/javascript/flavours/glitch/features/account_gallery/index.js b/app/javascript/flavours/glitch/features/account_gallery/index.js
index 63ff98deb..8f770eb9a 100644
--- a/app/javascript/flavours/glitch/features/account_gallery/index.js
+++ b/app/javascript/flavours/glitch/features/account_gallery/index.js
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { fetchAccount } from 'flavours/glitch/actions/accounts';
-import { refreshAccountMediaTimeline, expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines';
+import { expandAccountMediaTimeline } from 'flavours/glitch/actions/timelines';
 import LoadingIndicator from 'flavours/glitch/components/loading_indicator';
 import Column from 'flavours/glitch/features/ui/components/column';
 import ColumnBackButton from 'flavours/glitch/components/column_back_button';
@@ -17,9 +17,31 @@ import LoadMore from 'flavours/glitch/components/load_more';
 const mapStateToProps = (state, props) => ({
   medias: getAccountGallery(state, props.params.accountId),
   isLoading: state.getIn(['timelines', `account:${props.params.accountId}:media`, 'isLoading']),
-  hasMore: !!state.getIn(['timelines', `account:${props.params.accountId}:media`, 'next']),
+  hasMore:   state.getIn(['timelines', `account:${props.params.accountId}:media`, 'hasMore']),
 });
 
+class LoadMoreMedia extends ImmutablePureComponent {
+
+  static propTypes = {
+    maxId: PropTypes.string,
+    onLoadMore: PropTypes.func.isRequired,
+  };
+
+  handleLoadMore = () => {
+    this.props.onLoadMore(this.props.maxId);
+  }
+
+  render () {
+    return (
+      <LoadMore
+        disabled={this.props.disabled}
+        onLoadMore={this.handleLoadMore}
+      />
+    );
+  }
+
+}
+
 @connect(mapStateToProps)
 export default class AccountGallery extends ImmutablePureComponent {
 
@@ -33,19 +55,19 @@ export default class AccountGallery extends ImmutablePureComponent {
 
   componentDidMount () {
     this.props.dispatch(fetchAccount(this.props.params.accountId));
-    this.props.dispatch(refreshAccountMediaTimeline(this.props.params.accountId));
+    this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));
   }
 
   componentWillReceiveProps (nextProps) {
     if (nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) {
       this.props.dispatch(fetchAccount(nextProps.params.accountId));
-      this.props.dispatch(refreshAccountMediaTimeline(this.props.params.accountId));
+      this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));
     }
   }
 
   handleScrollToBottom = () => {
     if (this.props.hasMore) {
-      this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId));
+      this.handleLoadMore(this.props.medias.last().get('id'));
     }
   }
 
@@ -58,7 +80,11 @@ export default class AccountGallery extends ImmutablePureComponent {
     }
   }
 
-  handleLoadMore = (e) => {
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandAccountMediaTimeline(this.props.params.accountId, { maxId }));
+  };
+
+  handleLoadOlder = (e) => {
     e.preventDefault();
     this.handleScrollToBottom();
   }
@@ -66,7 +92,7 @@ export default class AccountGallery extends ImmutablePureComponent {
   render () {
     const { medias, isLoading, hasMore } = this.props;
 
-    let loadMore = null;
+    let loadOlder = null;
 
     if (!medias && isLoading) {
       return (
@@ -77,7 +103,7 @@ export default class AccountGallery extends ImmutablePureComponent {
     }
 
     if (!isLoading && medias.size > 0 && hasMore) {
-      loadMore = <LoadMore onClick={this.handleLoadMore} />;
+      loadOlder = <LoadMore onClick={this.handleLoadOlder} />;
     }
 
     return (
@@ -89,13 +115,18 @@ export default class AccountGallery extends ImmutablePureComponent {
             <HeaderContainer accountId={this.props.params.accountId} />
 
             <div className='account-gallery__container'>
-              {medias.map(media =>
-                (<MediaItem
+              {medias.map((media, index) => media === null ? (
+                <LoadMoreMedia
+                  key={'more:' + medias.getIn(index + 1, 'id')}
+                  maxId={index > 0 ? medias.getIn(index - 1, 'id') : null}
+                />
+              ) : (
+                <MediaItem
                   key={media.get('id')}
                   media={media}
-                />)
-              )}
-              {loadMore}
+                />
+              ))}
+              {loadOlder}
             </div>
           </div>
         </ScrollContainer>
diff --git a/app/javascript/flavours/glitch/features/account_timeline/index.js b/app/javascript/flavours/glitch/features/account_timeline/index.js
index dd70d1ee2..2216f9153 100644
--- a/app/javascript/flavours/glitch/features/account_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/account_timeline/index.js
@@ -3,7 +3,7 @@ import { connect } from 'react-redux';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { fetchAccount } from 'flavours/glitch/actions/accounts';
-import { refreshAccountTimeline, refreshAccountFeaturedTimeline, expandAccountTimeline } from 'flavours/glitch/actions/timelines';
+import { expandAccountFeaturedTimeline, expandAccountTimeline } from 'flavours/glitch/actions/timelines';
 import StatusList from '../../components/status_list';
 import LoadingIndicator from '../../components/loading_indicator';
 import Column from '../ui/components/column';
@@ -19,7 +19,7 @@ const mapStateToProps = (state, { params: { accountId }, withReplies = false })
     statusIds: state.getIn(['timelines', `account:${path}`, 'items'], ImmutableList()),
     featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned`, 'items'], ImmutableList()),
     isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
-    hasMore: !!state.getIn(['timelines', `account:${path}`, 'next']),
+    hasMore:   state.getIn(['timelines', `account:${path}`, 'hasMore']),
   };
 };
 
@@ -41,25 +41,23 @@ export default class AccountTimeline extends ImmutablePureComponent {
 
     this.props.dispatch(fetchAccount(accountId));
     if (!withReplies) {
-      this.props.dispatch(refreshAccountFeaturedTimeline(accountId));
+      this.props.dispatch(expandAccountFeaturedTimeline(accountId));
     }
-    this.props.dispatch(refreshAccountTimeline(accountId, withReplies));
+    this.props.dispatch(expandAccountTimeline(accountId, { withReplies }));
   }
 
   componentWillReceiveProps (nextProps) {
     if ((nextProps.params.accountId !== this.props.params.accountId && nextProps.params.accountId) || nextProps.withReplies !== this.props.withReplies) {
       this.props.dispatch(fetchAccount(nextProps.params.accountId));
       if (!nextProps.withReplies) {
-        this.props.dispatch(refreshAccountFeaturedTimeline(nextProps.params.accountId));
+        this.props.dispatch(expandAccountFeaturedTimeline(nextProps.params.accountId));
       }
-      this.props.dispatch(refreshAccountTimeline(nextProps.params.accountId, nextProps.params.withReplies));
+      this.props.dispatch(expandAccountTimeline(nextProps.params.accountId, { withReplies: nextProps.params.withReplies }));
     }
   }
 
-  handleLoadMore = () => {
-    if (!this.props.isLoading && this.props.hasMore) {
-      this.props.dispatch(expandAccountTimeline(this.props.params.accountId, this.props.withReplies));
-    }
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandAccountTimeline(this.props.params.accountId, { maxId, withReplies: this.props.withReplies }));
   }
 
   render () {
diff --git a/app/javascript/flavours/glitch/features/community_timeline/index.js b/app/javascript/flavours/glitch/features/community_timeline/index.js
index 55355414f..b5843ca16 100644
--- a/app/javascript/flavours/glitch/features/community_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/community_timeline/index.js
@@ -4,10 +4,7 @@ import PropTypes from 'prop-types';
 import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
 import Column from 'flavours/glitch/components/column';
 import ColumnHeader from 'flavours/glitch/components/column_header';
-import {
-  refreshCommunityTimeline,
-  expandCommunityTimeline,
-} from 'flavours/glitch/actions/timelines';
+import { expandCommunityTimeline } from 'flavours/glitch/actions/timelines';
 import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import ColumnSettingsContainer from './containers/column_settings_container';
@@ -55,7 +52,7 @@ export default class CommunityTimeline extends React.PureComponent {
   componentDidMount () {
     const { dispatch } = this.props;
 
-    dispatch(refreshCommunityTimeline());
+    dispatch(expandCommunityTimeline());
     this.disconnect = dispatch(connectCommunityStream());
   }
 
@@ -70,8 +67,8 @@ export default class CommunityTimeline extends React.PureComponent {
     this.column = c;
   }
 
-  handleLoadMore = () => {
-    this.props.dispatch(expandCommunityTimeline());
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandCommunityTimeline({ maxId }));
   }
 
   render () {
@@ -97,7 +94,7 @@ export default class CommunityTimeline extends React.PureComponent {
           trackScroll={!pinned}
           scrollKey={`community_timeline-${columnId}`}
           timelineId='community'
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
           emptyMessage={<FormattedMessage id='empty_column.community' defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!' />}
         />
       </Column>
diff --git a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
index 9f3c9bec7..8f77ed42b 100644
--- a/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/hashtag_timeline/index.js
@@ -4,10 +4,7 @@ import PropTypes from 'prop-types';
 import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
 import Column from 'flavours/glitch/components/column';
 import ColumnHeader from 'flavours/glitch/components/column_header';
-import {
-  refreshHashtagTimeline,
-  expandHashtagTimeline,
-} from 'flavours/glitch/actions/timelines';
+import { expandHashtagTimeline } from 'flavours/glitch/actions/timelines';
 import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
 import { FormattedMessage } from 'react-intl';
 import { connectHashtagStream } from 'flavours/glitch/actions/streaming';
@@ -61,13 +58,13 @@ export default class HashtagTimeline extends React.PureComponent {
     const { dispatch } = this.props;
     const { id } = this.props.params;
 
-    dispatch(refreshHashtagTimeline(id));
+    dispatch(expandHashtagTimeline(id));
     this._subscribe(dispatch, id);
   }
 
   componentWillReceiveProps (nextProps) {
     if (nextProps.params.id !== this.props.params.id) {
-      this.props.dispatch(refreshHashtagTimeline(nextProps.params.id));
+      this.props.dispatch(expandHashtagTimeline(nextProps.params.id));
       this._unsubscribe();
       this._subscribe(this.props.dispatch, nextProps.params.id);
     }
@@ -81,8 +78,8 @@ export default class HashtagTimeline extends React.PureComponent {
     this.column = c;
   }
 
-  handleLoadMore = () => {
-    this.props.dispatch(expandHashtagTimeline(this.props.params.id));
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandHashtagTimeline(this.props.params.id, { maxId }));
   }
 
   render () {
@@ -108,7 +105,7 @@ export default class HashtagTimeline extends React.PureComponent {
           trackScroll={!pinned}
           scrollKey={`hashtag_timeline-${columnId}`}
           timelineId={`hashtag:${id}`}
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
           emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
         />
       </Column>
diff --git a/app/javascript/flavours/glitch/features/home_timeline/index.js b/app/javascript/flavours/glitch/features/home_timeline/index.js
index c20c0244a..3650ffc6d 100644
--- a/app/javascript/flavours/glitch/features/home_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/home_timeline/index.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import { connect } from 'react-redux';
-import { expandHomeTimeline, refreshHomeTimeline } from 'flavours/glitch/actions/timelines';
+import { expandHomeTimeline } from 'flavours/glitch/actions/timelines';
 import PropTypes from 'prop-types';
 import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
 import Column from 'flavours/glitch/components/column';
@@ -16,7 +16,7 @@ const messages = defineMessages({
 
 const mapStateToProps = state => ({
   hasUnread: state.getIn(['timelines', 'home', 'unread']) > 0,
-  isPartial: state.getIn(['timelines', 'home', 'isPartial'], false),
+  isPartial: state.getIn(['timelines', 'home', 'items', 0], null) === null,
 });
 
 @connect(mapStateToProps)
@@ -55,8 +55,8 @@ export default class HomeTimeline extends React.PureComponent {
     this.column = c;
   }
 
-  handleLoadMore = () => {
-    this.props.dispatch(expandHomeTimeline());
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandHomeTimeline({ maxId }));
   }
 
   componentDidMount () {
@@ -78,7 +78,7 @@ export default class HomeTimeline extends React.PureComponent {
       return;
     } else if (!wasPartial && isPartial) {
       this.polling = setInterval(() => {
-        dispatch(refreshHomeTimeline());
+        dispatch(expandHomeTimeline());
       }, 3000);
     } else if (wasPartial && !isPartial) {
       this._stopPolling();
@@ -114,7 +114,7 @@ export default class HomeTimeline extends React.PureComponent {
         <StatusListContainer
           trackScroll={!pinned}
           scrollKey={`home_timeline-${columnId}`}
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
           timelineId='home'
           emptyMessage={<FormattedMessage id='empty_column.home' defaultMessage='Your home timeline is empty! Visit {public} or use search to get started and meet other users.' values={{ public: <Link to='/timelines/public'><FormattedMessage id='empty_column.home.public_timeline' defaultMessage='the public timeline' /></Link> }} />}
         />
diff --git a/app/javascript/flavours/glitch/features/list_timeline/index.js b/app/javascript/flavours/glitch/features/list_timeline/index.js
index f9476d92d..07edf45aa 100644
--- a/app/javascript/flavours/glitch/features/list_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/list_timeline/index.js
@@ -8,7 +8,7 @@ import ColumnHeader from 'flavours/glitch/components/column_header';
 import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
 import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 import { connectListStream } from 'flavours/glitch/actions/streaming';
-import { refreshListTimeline, expandListTimeline } from 'flavours/glitch/actions/timelines';
+import { expandListTimeline } from 'flavours/glitch/actions/timelines';
 import { fetchList, deleteList } from 'flavours/glitch/actions/lists';
 import { openModal } from 'flavours/glitch/actions/modal';
 import MissingIndicator from 'flavours/glitch/components/missing_indicator';
@@ -67,7 +67,7 @@ export default class ListTimeline extends React.PureComponent {
     const { id } = this.props.params;
 
     dispatch(fetchList(id));
-    dispatch(refreshListTimeline(id));
+    dispatch(expandListTimeline(id));
 
     this.disconnect = dispatch(connectListStream(id));
   }
@@ -83,9 +83,9 @@ export default class ListTimeline extends React.PureComponent {
     this.column = c;
   }
 
-  handleLoadMore = () => {
+  handleLoadMore = maxId => {
     const { id } = this.props.params;
-    this.props.dispatch(expandListTimeline(id));
+    this.props.dispatch(expandListTimeline(id, { maxId }));
   }
 
   handleEditClick = () => {
@@ -164,7 +164,7 @@ export default class ListTimeline extends React.PureComponent {
           trackScroll={!pinned}
           scrollKey={`list_timeline-${columnId}`}
           timelineId={`list:${id}`}
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
           emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet.' />}
         />
       </Column>
diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js
index bbdd4612e..a6c0b1688 100644
--- a/app/javascript/flavours/glitch/features/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/public_timeline/index.js
@@ -4,10 +4,7 @@ import PropTypes from 'prop-types';
 import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
 import Column from 'flavours/glitch/components/column';
 import ColumnHeader from 'flavours/glitch/components/column_header';
-import {
-  refreshPublicTimeline,
-  expandPublicTimeline,
-} from 'flavours/glitch/actions/timelines';
+import { expandPublicTimeline } from 'flavours/glitch/actions/timelines';
 import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import ColumnSettingsContainer from './containers/column_settings_container';
@@ -55,7 +52,7 @@ export default class PublicTimeline extends React.PureComponent {
   componentDidMount () {
     const { dispatch } = this.props;
 
-    dispatch(refreshPublicTimeline());
+    dispatch(expandPublicTimeline());
     this.disconnect = dispatch(connectPublicStream());
   }
 
@@ -70,8 +67,8 @@ export default class PublicTimeline extends React.PureComponent {
     this.column = c;
   }
 
-  handleLoadMore = () => {
-    this.props.dispatch(expandPublicTimeline());
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandPublicTimeline({ maxId }));
   }
 
   render () {
@@ -95,7 +92,7 @@ export default class PublicTimeline extends React.PureComponent {
 
         <StatusListContainer
           timelineId='public'
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
           trackScroll={!pinned}
           scrollKey={`public_timeline-${columnId}`}
           emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />}
diff --git a/app/javascript/flavours/glitch/features/standalone/community_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/community_timeline/index.js
index ff464b390..c488f9541 100644
--- a/app/javascript/flavours/glitch/features/standalone/community_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/standalone/community_timeline/index.js
@@ -2,10 +2,7 @@ import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
-import {
-  refreshCommunityTimeline,
-  expandCommunityTimeline,
-} from 'flavours/glitch/actions/timelines';
+import { expandCommunityTimeline } from 'flavours/glitch/actions/timelines';
 import Column from 'flavours/glitch/components/column';
 import ColumnHeader from 'flavours/glitch/components/column_header';
 import { defineMessages, injectIntl } from 'react-intl';
@@ -35,7 +32,7 @@ export default class CommunityTimeline extends React.PureComponent {
   componentDidMount () {
     const { dispatch } = this.props;
 
-    dispatch(refreshCommunityTimeline());
+    dispatch(expandCommunityTimeline());
     this.disconnect = dispatch(connectCommunityStream());
   }
 
@@ -46,8 +43,8 @@ export default class CommunityTimeline extends React.PureComponent {
     }
   }
 
-  handleLoadMore = () => {
-    this.props.dispatch(expandCommunityTimeline());
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandCommunityTimeline({ maxId }));
   }
 
   render () {
@@ -63,7 +60,7 @@ export default class CommunityTimeline extends React.PureComponent {
 
         <StatusListContainer
           timelineId='community'
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
           scrollKey='standalone_public_timeline'
           trackScroll={false}
         />
diff --git a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
index 39053bcc9..dc02f1c91 100644
--- a/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/standalone/hashtag_timeline/index.js
@@ -2,10 +2,7 @@ import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
-import {
-  refreshHashtagTimeline,
-  expandHashtagTimeline,
-} from 'flavours/glitch/actions/timelines';
+import { expandHashtagTimeline } from 'flavours/glitch/actions/timelines';
 import Column from 'flavours/glitch/components/column';
 import ColumnHeader from 'flavours/glitch/components/column_header';
 import { connectHashtagStream } from 'flavours/glitch/actions/streaming';
@@ -29,7 +26,7 @@ export default class HashtagTimeline extends React.PureComponent {
   componentDidMount () {
     const { dispatch, hashtag } = this.props;
 
-    dispatch(refreshHashtagTimeline(hashtag));
+    dispatch(expandHashtagTimeline(hashtag));
     this.disconnect = dispatch(connectHashtagStream(hashtag));
   }
 
@@ -40,8 +37,8 @@ export default class HashtagTimeline extends React.PureComponent {
     }
   }
 
-  handleLoadMore = () => {
-    this.props.dispatch(expandHashtagTimeline(this.props.hashtag));
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandHashtagTimeline(this.props.hashtag, { maxId }));
   }
 
   render () {
@@ -59,7 +56,7 @@ export default class HashtagTimeline extends React.PureComponent {
           trackScroll={false}
           scrollKey='standalone_hashtag_timeline'
           timelineId={`hashtag:${hashtag}`}
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
         />
       </Column>
     );
diff --git a/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js b/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
index 8e1ad4e52..0b4238485 100644
--- a/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/standalone/public_timeline/index.js
@@ -2,10 +2,7 @@ import React from 'react';
 import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import StatusListContainer from 'flavours/glitch/features/ui/containers/status_list_container';
-import {
-  refreshPublicTimeline,
-  expandPublicTimeline,
-} from 'flavours/glitch/actions/timelines';
+import { expandPublicTimeline } from 'flavours/glitch/actions/timelines';
 import Column from 'flavours/glitch/components/column';
 import ColumnHeader from 'flavours/glitch/components/column_header';
 import { defineMessages, injectIntl } from 'react-intl';
@@ -35,7 +32,7 @@ export default class PublicTimeline extends React.PureComponent {
   componentDidMount () {
     const { dispatch } = this.props;
 
-    dispatch(refreshPublicTimeline());
+    dispatch(expandPublicTimeline());
     this.disconnect = dispatch(connectPublicStream());
   }
 
@@ -46,8 +43,8 @@ export default class PublicTimeline extends React.PureComponent {
     }
   }
 
-  handleLoadMore = () => {
-    this.props.dispatch(expandPublicTimeline());
+  handleLoadMore = maxId => {
+    this.props.dispatch(expandPublicTimeline({ maxId }));
   }
 
   render () {
@@ -63,7 +60,7 @@ export default class PublicTimeline extends React.PureComponent {
 
         <StatusListContainer
           timelineId='public'
-          loadMore={this.handleLoadMore}
+          onLoadMore={this.handleLoadMore}
           scrollKey='standalone_public_timeline'
           trackScroll={false}
         />
diff --git a/app/javascript/flavours/glitch/features/ui/components/report_modal.js b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
index 3b7a5ff20..ff81522a8 100644
--- a/app/javascript/flavours/glitch/features/ui/components/report_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
@@ -1,7 +1,7 @@
 import React from 'react';
 import { connect } from 'react-redux';
 import { changeReportComment, changeReportForward, submitReport } from 'flavours/glitch/actions/reports';
-import { refreshAccountTimeline } from 'flavours/glitch/actions/timelines';
+import { expandAccountTimeline } from 'flavours/glitch/actions/timelines';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { makeGetAccount } from 'flavours/glitch/selectors';
@@ -64,12 +64,12 @@ export default class ReportModal extends ImmutablePureComponent {
   }
 
   componentDidMount () {
-    this.props.dispatch(refreshAccountTimeline(this.props.account.get('id'), true));
+    this.props.dispatch(expandAccountTimeline(this.props.account.get('id'), { withReplies: true }));
   }
 
   componentWillReceiveProps (nextProps) {
     if (this.props.account !== nextProps.account && nextProps.account) {
-      this.props.dispatch(refreshAccountTimeline(nextProps.account.get('id'), true));
+      this.props.dispatch(expandAccountTimeline(nextProps.account.get('id'), { withReplies: true }));
     }
   }
 
diff --git a/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js b/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
index 33932e95d..9047752f5 100644
--- a/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
+++ b/app/javascript/flavours/glitch/features/ui/containers/status_list_container.js
@@ -52,15 +52,13 @@ const makeMapStateToProps = () => {
     statusIds: getStatusIds(state, { type: timelineId }),
     isLoading: state.getIn(['timelines', timelineId, 'isLoading'], true),
     isPartial: state.getIn(['timelines', timelineId, 'isPartial'], false),
-    hasMore: !!state.getIn(['timelines', timelineId, 'next']),
+    hasMore:   state.getIn(['timelines', timelineId, 'hasMore']),
   });
 
   return mapStateToProps;
 };
 
-const mapDispatchToProps = (dispatch, { timelineId, loadMore }) => ({
-
-  onLoadMore: debounce(loadMore, 300, { leading: true }),
+const mapDispatchToProps = (dispatch, { timelineId }) => ({
 
   onScrollToTop: debounce(() => {
     dispatch(scrollTopTimeline(timelineId, true));
diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js
index e4b69cb3b..ef3c3ffe4 100644
--- a/app/javascript/flavours/glitch/features/ui/index.js
+++ b/app/javascript/flavours/glitch/features/ui/index.js
@@ -9,7 +9,7 @@ import { Redirect, withRouter } from 'react-router-dom';
 import { isMobile } from 'flavours/glitch/util/is_mobile';
 import { debounce } from 'lodash';
 import { uploadCompose, resetCompose } from 'flavours/glitch/actions/compose';
-import { refreshHomeTimeline } from 'flavours/glitch/actions/timelines';
+import { expandHomeTimeline } from 'flavours/glitch/actions/timelines';
 import { refreshNotifications } from 'flavours/glitch/actions/notifications';
 import { clearHeight } from 'flavours/glitch/actions/height_cache';
 import { WrappedSwitch, WrappedRoute } from 'flavours/glitch/util/react_router_helpers';
@@ -219,7 +219,7 @@ export default class UI extends React.Component {
       navigator.serviceWorker.addEventListener('message', this.handleServiceWorkerPostMessage);
     }
 
-    this.props.dispatch(refreshHomeTimeline());
+    this.props.dispatch(expandHomeTimeline());
     this.props.dispatch(refreshNotifications());
   }