From 0a9de4a2cb6c975c51a238278b818045d9a06aca Mon Sep 17 00:00:00 2001
From: alxd <github@alxd.org>
Date: Wed, 12 Dec 2018 16:35:58 +0100
Subject: [PATCH] make each filter flush notifications and load new ones,
 fixing pagination

---
 .../mastodon/actions/notifications.js         | 24 ++++++++++++++++++-
 .../containers/filter_bar_container.js        |  4 ++--
 .../mastodon/features/notifications/index.js  |  3 +++
 .../mastodon/reducers/notifications.js        |  3 +++
 app/javascript/mastodon/reducers/settings.js  |  2 ++
 5 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/app/javascript/mastodon/actions/notifications.js b/app/javascript/mastodon/actions/notifications.js
index 92c70e1555..0aa4589881 100644
--- a/app/javascript/mastodon/actions/notifications.js
+++ b/app/javascript/mastodon/actions/notifications.js
@@ -8,6 +8,7 @@ import {
   importFetchedStatuses,
 } from './importer';
 import { defineMessages } from 'react-intl';
+import { List as ImmutableList } from 'immutable';
 import { unescapeHTML } from '../utils/html';
 import { getFilters, regexFromFilters } from '../selectors';
 
@@ -18,6 +19,8 @@ export const NOTIFICATIONS_EXPAND_REQUEST = 'NOTIFICATIONS_EXPAND_REQUEST';
 export const NOTIFICATIONS_EXPAND_SUCCESS = 'NOTIFICATIONS_EXPAND_SUCCESS';
 export const NOTIFICATIONS_EXPAND_FAIL    = 'NOTIFICATIONS_EXPAND_FAIL';
 
+export const NOTIFICATIONS_FILTER_SET = 'NOTIFICATIONS_FILTER_SET'
+
 export const NOTIFICATIONS_CLEAR      = 'NOTIFICATIONS_CLEAR';
 export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP';
 
@@ -88,10 +91,16 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
 
 const excludeTypesFromSettings = state => state.getIn(['settings', 'notifications', 'shows']).filter(enabled => !enabled).keySeq().toJS();
 
+const excludeTypesFromFilter = filter => {
+  const allTypes = ImmutableList(['follow', 'favourite', 'reblog', 'mention']);
+  return allTypes.filterNot(item => item === filter).toJS();
+};
+
 const noOp = () => {};
 
 export function expandNotifications({ maxId } = {}, done = noOp) {
   return (dispatch, getState) => {
+    const activeFilter = getState().getIn(['settings', 'notifications', 'quickFilter', 'active']);
     const notifications = getState().get('notifications');
     const isLoadingMore = !!maxId;
 
@@ -102,7 +111,9 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
 
     const params = {
       max_id: maxId,
-      exclude_types: excludeTypesFromSettings(getState()),
+      exclude_types: activeFilter === 'all'
+        ? excludeTypesFromSettings(getState())
+        : excludeTypesFromFilter(activeFilter),
     };
 
     if (!maxId && notifications.get('items').size > 0) {
@@ -167,3 +178,14 @@ export function scrollTopNotifications(top) {
     top,
   };
 };
+
+export function setFilter (filterType) {
+  return dispatch => {
+    dispatch({
+      type: NOTIFICATIONS_FILTER_SET,
+      path: ['notifications', 'quickFilter', 'active'],
+      value: filterType,
+    });
+    dispatch(expandNotifications());
+  };
+};
diff --git a/app/javascript/mastodon/features/notifications/containers/filter_bar_container.js b/app/javascript/mastodon/features/notifications/containers/filter_bar_container.js
index a5492bcc66..4d495c2908 100644
--- a/app/javascript/mastodon/features/notifications/containers/filter_bar_container.js
+++ b/app/javascript/mastodon/features/notifications/containers/filter_bar_container.js
@@ -1,6 +1,6 @@
 import { connect } from 'react-redux';
 import FilterBar from '../components/filter_bar';
-import { changeSetting } from '../../../actions/settings';
+import { setFilter } from '../../../actions/notifications';
 
 const makeMapStateToProps = state => ({
   selectedFilter: state.getIn(['settings', 'notifications', 'quickFilter', 'active']),
@@ -9,7 +9,7 @@ const makeMapStateToProps = state => ({
 
 const mapDispatchToProps = (dispatch) => ({
   selectFilter (newActiveFilter) {
-    dispatch(changeSetting(['notifications', 'quickFilter', 'active'], newActiveFilter));
+    dispatch(setFilter(newActiveFilter));
   },
 });
 
diff --git a/app/javascript/mastodon/features/notifications/index.js b/app/javascript/mastodon/features/notifications/index.js
index 80688e3327..c49d48f012 100644
--- a/app/javascript/mastodon/features/notifications/index.js
+++ b/app/javascript/mastodon/features/notifications/index.js
@@ -21,12 +21,15 @@ const messages = defineMessages({
 });
 
 const getNotifications = createSelector([
+  // TODO: Remove the first two arguments and simplify
   state => state.getIn(['settings', 'notifications', 'quickFilter', 'show']),
   state => state.getIn(['settings', 'notifications', 'quickFilter', 'active']),
   state => ImmutableList(state.getIn(['settings', 'notifications', 'shows']).filter(item => !item).keys()),
   state => state.getIn(['notifications', 'items']),
 ], (showFilterBar, allowedType, excludedTypes, notifications) => {
   if (!showFilterBar || allowedType === 'all') {
+    // used if user changed the notification settings after loading the notifications from the server
+    // otherwise a list of notifications will come pre-filtered from the backend
     return notifications.filterNot(item => item !== null && excludedTypes.includes(item.get('type')));
   }
   return notifications.filter(item => item !== null && allowedType === item.get('type'));
diff --git a/app/javascript/mastodon/reducers/notifications.js b/app/javascript/mastodon/reducers/notifications.js
index d71ae00aec..19a02f5b15 100644
--- a/app/javascript/mastodon/reducers/notifications.js
+++ b/app/javascript/mastodon/reducers/notifications.js
@@ -3,6 +3,7 @@ import {
   NOTIFICATIONS_EXPAND_SUCCESS,
   NOTIFICATIONS_EXPAND_REQUEST,
   NOTIFICATIONS_EXPAND_FAIL,
+  NOTIFICATIONS_FILTER_SET,
   NOTIFICATIONS_CLEAR,
   NOTIFICATIONS_SCROLL_TOP,
 } from '../actions/notifications';
@@ -98,6 +99,8 @@ export default function notifications(state = initialState, action) {
     return state.set('isLoading', true);
   case NOTIFICATIONS_EXPAND_FAIL:
     return state.set('isLoading', false);
+  case NOTIFICATIONS_FILTER_SET:
+    return state.set('items', ImmutableList()).set('hasMore', true);
   case NOTIFICATIONS_SCROLL_TOP:
     return updateTop(state, action.top);
   case NOTIFICATIONS_UPDATE:
diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js
index de1a4216c4..2e1878cf78 100644
--- a/app/javascript/mastodon/reducers/settings.js
+++ b/app/javascript/mastodon/reducers/settings.js
@@ -1,4 +1,5 @@
 import { SETTING_CHANGE, SETTING_SAVE } from '../actions/settings';
+import { NOTIFICATIONS_FILTER_SET } from '../actions/notifications';
 import { COLUMN_ADD, COLUMN_REMOVE, COLUMN_MOVE, COLUMN_PARAMS_CHANGE } from '../actions/columns';
 import { STORE_HYDRATE } from '../actions/store';
 import { EMOJI_USE } from '../actions/emojis';
@@ -118,6 +119,7 @@ export default function settings(state = initialState, action) {
   switch(action.type) {
   case STORE_HYDRATE:
     return hydrate(state, action.state.get('settings'));
+  case NOTIFICATIONS_FILTER_SET:
   case SETTING_CHANGE:
     return state
       .setIn(action.path, action.value)