diff --git a/app/assets/javascripts/components/actions/notifications.jsx b/app/assets/javascripts/components/actions/notifications.jsx
index 23bdcb5c7..1731c1857 100644
--- a/app/assets/javascripts/components/actions/notifications.jsx
+++ b/app/assets/javascripts/components/actions/notifications.jsx
@@ -96,13 +96,17 @@ export function expandNotifications() {
return (dispatch, getState) => {
const url = getState().getIn(['notifications', 'next'], null);
- if (url === null) {
+ if (url === null || getState().getIn(['notifications', 'isLoading'])) {
return;
}
dispatch(expandNotificationsRequest());
- api(getState).get(url).then(response => {
+ api(getState).get(url, {
+ params: {
+ limit: 5
+ }
+ }).then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null));
diff --git a/app/assets/javascripts/components/features/notifications/index.jsx b/app/assets/javascripts/components/features/notifications/index.jsx
index 366d8f5e9..b4593aaff 100644
--- a/app/assets/javascripts/components/features/notifications/index.jsx
+++ b/app/assets/javascripts/components/features/notifications/index.jsx
@@ -20,7 +20,8 @@ const getNotifications = createSelector([
], (excludedTypes, notifications) => notifications.filterNot(item => excludedTypes.includes(item.get('type'))));
const mapStateToProps = state => ({
- notifications: getNotifications(state)
+ notifications: getNotifications(state),
+ isLoading: state.getIn(['notifications', 'isLoading'], true)
});
const Notifications = React.createClass({
@@ -29,7 +30,8 @@ const Notifications = React.createClass({
notifications: ImmutablePropTypes.list.isRequired,
dispatch: React.PropTypes.func.isRequired,
trackScroll: React.PropTypes.bool,
- intl: React.PropTypes.object.isRequired
+ intl: React.PropTypes.object.isRequired,
+ isLoading: React.PropTypes.bool
},
getDefaultProps () {
@@ -42,8 +44,9 @@ const Notifications = React.createClass({
handleScroll (e) {
const { scrollTop, scrollHeight, clientHeight } = e.target;
+ const offset = scrollHeight - scrollTop - clientHeight;
- if (scrollTop === scrollHeight - clientHeight) {
+ if (250 > offset && !this.props.isLoading) {
this.props.dispatch(expandNotifications());
}
},
diff --git a/app/assets/javascripts/components/reducers/notifications.jsx b/app/assets/javascripts/components/reducers/notifications.jsx
index c85e7b460..482093c33 100644
--- a/app/assets/javascripts/components/reducers/notifications.jsx
+++ b/app/assets/javascripts/components/reducers/notifications.jsx
@@ -2,6 +2,10 @@ import {
NOTIFICATIONS_UPDATE,
NOTIFICATIONS_REFRESH_SUCCESS,
NOTIFICATIONS_EXPAND_SUCCESS,
+ NOTIFICATIONS_REFRESH_REQUEST,
+ NOTIFICATIONS_EXPAND_REQUEST,
+ NOTIFICATIONS_REFRESH_FAIL,
+ NOTIFICATIONS_EXPAND_FAIL
} from '../actions/notifications';
import { ACCOUNT_BLOCK_SUCCESS } from '../actions/accounts';
import Immutable from 'immutable';
@@ -9,7 +13,8 @@ import Immutable from 'immutable';
const initialState = Immutable.Map({
items: Immutable.List(),
next: null,
- loaded: false
+ loaded: false,
+ isLoading: true
});
const notificationToMap = notification => Immutable.Map({
@@ -31,7 +36,11 @@ const normalizeNotifications = (state, notifications, next) => {
items = items.set(i, notificationToMap(n));
});
- return state.update('items', list => loaded ? list.unshift(...items) : list.push(...items)).set('next', next).set('loaded', true);
+ return state
+ .update('items', list => loaded ? list.unshift(...items) : list.push(...items))
+ .set('next', next)
+ .set('loaded', true)
+ .set('isLoading', false);
};
const appendNormalizedNotifications = (state, notifications, next) => {
@@ -41,7 +50,10 @@ const appendNormalizedNotifications = (state, notifications, next) => {
items = items.set(i, notificationToMap(n));
});
- return state.update('items', list => list.push(...items)).set('next', next);
+ return state
+ .update('items', list => list.push(...items))
+ .set('next', next)
+ .set('isLoading', false);
};
const filterNotifications = (state, relationship) => {
@@ -50,6 +62,11 @@ const filterNotifications = (state, relationship) => {
export default function notifications(state = initialState, action) {
switch(action.type) {
+ case NOTIFICATIONS_REFRESH_REQUEST:
+ case NOTIFICATIONS_EXPAND_REQUEST:
+ case NOTIFICATIONS_REFRESH_FAIL:
+ case NOTIFICATIONS_EXPAND_FAIL:
+ return state.set('isLoading', true);
case NOTIFICATIONS_UPDATE:
return normalizeNotification(state, action.notification);
case NOTIFICATIONS_REFRESH_SUCCESS:
diff --git a/app/assets/stylesheets/about.scss b/app/assets/stylesheets/about.scss
index d92febced..b7d903ddf 100644
--- a/app/assets/stylesheets/about.scss
+++ b/app/assets/stylesheets/about.scss
@@ -1,5 +1,3 @@
-@import url(https://fonts.googleapis.com/css?family=Montserrat);
-
.about-body {
.wrapper {
max-width: 600px;
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index fc58c7463..649a0148b 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -1,6 +1,7 @@
@import 'variables';
@import url(https://fonts.googleapis.com/css?family=Roboto:400,500,400italic);
@import url(https://fonts.googleapis.com/css?family=Roboto+Mono:400,500);
+@import url(https://fonts.googleapis.com/css?family=Montserrat);
@import 'font-awesome';
/* http://meyerweb.com/eric/tools/css/reset/
diff --git a/app/assets/stylesheets/boost.scss b/app/assets/stylesheets/boost.scss
index c45d4ff8e..a2e6421f8 100644
--- a/app/assets/stylesheets/boost.scss
+++ b/app/assets/stylesheets/boost.scss
@@ -1,9 +1,7 @@
-@import 'variables';
-
@function url-friendly-colour($colour) {
- @return '%23' + str-slice('#{$colour}', 2, -1)
+ @return '%23' + str-slice('#{$colour}', 2, -1)
}
button i.fa-retweet {
-background-image: url("data:image/svg+xml;utf8,");
-}
\ No newline at end of file
+ background-image: url("data:image/svg+xml;utf8,");
+}
diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb
index 157a88e14..877356a75 100644
--- a/app/controllers/api/v1/notifications_controller.rb
+++ b/app/controllers/api/v1/notifications_controller.rb
@@ -6,8 +6,10 @@ class Api::V1::NotificationsController < ApiController
respond_to :json
+ DEFAULT_NOTIFICATIONS_LIMIT = 15
+
def index
- @notifications = Notification.where(account: current_account).browserable.paginate_by_max_id(limit_param(15), params[:max_id], params[:since_id])
+ @notifications = Notification.where(account: current_account).browserable.paginate_by_max_id(limit_param(DEFAULT_NOTIFICATIONS_LIMIT), params[:max_id], params[:since_id])
@notifications = cache_collection(@notifications, Notification)
statuses = @notifications.select { |n| !n.target_status.nil? }.map(&:target_status)
@@ -15,7 +17,7 @@ class Api::V1::NotificationsController < ApiController
set_counters_maps(statuses)
set_account_counters_maps(@notifications.map(&:from_account))
- next_path = api_v1_notifications_url(max_id: @notifications.last.id) if @notifications.size == limit_param(15)
+ next_path = api_v1_notifications_url(max_id: @notifications.last.id) if @notifications.size == limit_param(DEFAULT_NOTIFICATIONS_LIMIT)
prev_path = api_v1_notifications_url(since_id: @notifications.first.id) unless @notifications.empty?
set_pagination_headers(next_path, prev_path)