From 38dd85daab8e8342ec608d24cf81254c0dfde95c Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Sun, 20 Nov 2016 19:39:18 +0100 Subject: Adding notifications column --- .../javascripts/components/reducers/accounts.jsx | 8 +++ .../javascripts/components/reducers/alerts.jsx | 25 +++++++++ .../javascripts/components/reducers/index.jsx | 28 +++++----- .../components/reducers/notifications.jsx | 60 +++++++++++++++++----- .../javascripts/components/reducers/statuses.jsx | 12 +++++ 5 files changed, 106 insertions(+), 27 deletions(-) create mode 100644 app/assets/javascripts/components/reducers/alerts.jsx (limited to 'app/assets/javascripts/components/reducers') diff --git a/app/assets/javascripts/components/reducers/accounts.jsx b/app/assets/javascripts/components/reducers/accounts.jsx index c0ea961b7..68247a98c 100644 --- a/app/assets/javascripts/components/reducers/accounts.jsx +++ b/app/assets/javascripts/components/reducers/accounts.jsx @@ -28,6 +28,11 @@ import { CONTEXT_FETCH_SUCCESS } from '../actions/statuses'; import { SEARCH_SUGGESTIONS_READY } from '../actions/search'; +import { + NOTIFICATIONS_UPDATE, + NOTIFICATIONS_REFRESH_SUCCESS, + NOTIFICATIONS_EXPAND_SUCCESS +} from '../actions/notifications'; import Immutable from 'immutable'; const normalizeAccount = (state, account) => state.set(account.id, Immutable.fromJS(account)); @@ -64,6 +69,7 @@ export default function accounts(state = initialState, action) { switch(action.type) { case ACCOUNT_SET_SELF: case ACCOUNT_FETCH_SUCCESS: + case NOTIFICATIONS_UPDATE: return normalizeAccount(state, action.account); case SUGGESTIONS_FETCH_SUCCESS: case FOLLOWERS_FETCH_SUCCESS: @@ -74,6 +80,8 @@ export default function accounts(state = initialState, action) { case FAVOURITES_FETCH_SUCCESS: case COMPOSE_SUGGESTIONS_READY: case SEARCH_SUGGESTIONS_READY: + case NOTIFICATIONS_REFRESH_SUCCESS: + case NOTIFICATIONS_EXPAND_SUCCESS: return normalizeAccounts(state, action.accounts); case TIMELINE_REFRESH_SUCCESS: case TIMELINE_EXPAND_SUCCESS: diff --git a/app/assets/javascripts/components/reducers/alerts.jsx b/app/assets/javascripts/components/reducers/alerts.jsx new file mode 100644 index 000000000..42987f649 --- /dev/null +++ b/app/assets/javascripts/components/reducers/alerts.jsx @@ -0,0 +1,25 @@ +import { + ALERT_SHOW, + ALERT_DISMISS, + ALERT_CLEAR +} from '../actions/alerts'; +import Immutable from 'immutable'; + +const initialState = Immutable.List([]); + +export default function alerts(state = initialState, action) { + switch(action.type) { + case ALERT_SHOW: + return state.push(Immutable.Map({ + key: state.size > 0 ? state.last().get('key') + 1 : 0, + title: action.title, + message: action.message + })); + case ALERT_DISMISS: + return state.filterNot(item => item.get('key') === action.alert.key); + case ALERT_CLEAR: + return state.clear(); + default: + return state; + } +}; diff --git a/app/assets/javascripts/components/reducers/index.jsx b/app/assets/javascripts/components/reducers/index.jsx index 1e015cf74..aea9239f8 100644 --- a/app/assets/javascripts/components/reducers/index.jsx +++ b/app/assets/javascripts/components/reducers/index.jsx @@ -1,26 +1,28 @@ -import { combineReducers } from 'redux-immutable'; -import timelines from './timelines'; -import meta from './meta'; -import compose from './compose'; -import notifications from './notifications'; +import { combineReducers } from 'redux-immutable'; +import timelines from './timelines'; +import meta from './meta'; +import compose from './compose'; +import alerts from './alerts'; import { loadingBarReducer } from 'react-redux-loading-bar'; -import modal from './modal'; -import user_lists from './user_lists'; -import accounts from './accounts'; -import statuses from './statuses'; -import relationships from './relationships'; -import search from './search'; +import modal from './modal'; +import user_lists from './user_lists'; +import accounts from './accounts'; +import statuses from './statuses'; +import relationships from './relationships'; +import search from './search'; +import notifications from './notifications'; export default combineReducers({ timelines, meta, compose, - notifications, + alerts, loadingBar: loadingBarReducer, modal, user_lists, accounts, statuses, relationships, - search + search, + notifications }); diff --git a/app/assets/javascripts/components/reducers/notifications.jsx b/app/assets/javascripts/components/reducers/notifications.jsx index efe8d9739..0e67e732a 100644 --- a/app/assets/javascripts/components/reducers/notifications.jsx +++ b/app/assets/javascripts/components/reducers/notifications.jsx @@ -1,24 +1,56 @@ import { - NOTIFICATION_SHOW, - NOTIFICATION_DISMISS, - NOTIFICATION_CLEAR + NOTIFICATIONS_UPDATE, + NOTIFICATIONS_REFRESH_SUCCESS, + NOTIFICATIONS_EXPAND_SUCCESS } from '../actions/notifications'; import Immutable from 'immutable'; -const initialState = Immutable.List([]); +const initialState = Immutable.Map({ + items: Immutable.List(), + next: null, + loaded: false +}); + +const notificationToMap = notification => Immutable.Map({ + id: notification.id, + type: notification.type, + account: notification.account.id, + status: notification.status ? notification.status.id : null +}); + +const normalizeNotification = (state, notification) => { + return state.update('items', list => list.unshift(notificationToMap(notification))); +}; + +const normalizeNotifications = (state, notifications, next) => { + let items = Immutable.List(); + const loaded = state.get('loaded'); + + notifications.forEach((n, i) => { + items = items.set(i, notificationToMap(n)); + }); + + return state.update('items', list => loaded ? list.unshift(...items) : list.push(...items)).set('next', next).set('loaded', true); +}; + +const appendNormalizedNotifications = (state, notifications, next) => { + let items = Immutable.List(); + + notifications.forEach((n, i) => { + items = items.set(i, notificationToMap(n)); + }); + + return state.update('items', list => list.push(...items)).set('next', next); +}; export default function notifications(state = initialState, action) { switch(action.type) { - case NOTIFICATION_SHOW: - return state.push(Immutable.Map({ - key: state.size > 0 ? state.last().get('key') + 1 : 0, - title: action.title, - message: action.message - })); - case NOTIFICATION_DISMISS: - return state.filterNot(item => item.get('key') === action.notification.key); - case NOTIFICATION_CLEAR: - return state.clear(); + case NOTIFICATIONS_UPDATE: + return normalizeNotification(state, action.notification); + case NOTIFICATIONS_REFRESH_SUCCESS: + return normalizeNotifications(state, action.notifications, action.next); + case NOTIFICATIONS_EXPAND_SUCCESS: + return appendNormalizedNotifications(state, action.notifications, action.next); default: return state; } diff --git a/app/assets/javascripts/components/reducers/statuses.jsx b/app/assets/javascripts/components/reducers/statuses.jsx index 69c0e6193..2a24a75e4 100644 --- a/app/assets/javascripts/components/reducers/statuses.jsx +++ b/app/assets/javascripts/components/reducers/statuses.jsx @@ -18,9 +18,18 @@ import { ACCOUNT_TIMELINE_FETCH_SUCCESS, ACCOUNT_TIMELINE_EXPAND_SUCCESS } from '../actions/accounts'; +import { + NOTIFICATIONS_UPDATE, + NOTIFICATIONS_REFRESH_SUCCESS, + NOTIFICATIONS_EXPAND_SUCCESS +} from '../actions/notifications'; import Immutable from 'immutable'; const normalizeStatus = (state, status) => { + if (!status) { + return state; + } + status.account = status.account.id; if (status.reblog && status.reblog.id) { @@ -53,6 +62,7 @@ export default function statuses(state = initialState, action) { switch(action.type) { case TIMELINE_UPDATE: case STATUS_FETCH_SUCCESS: + case NOTIFICATIONS_UPDATE: return normalizeStatus(state, action.status); case REBLOG_SUCCESS: case UNREBLOG_SUCCESS: @@ -64,6 +74,8 @@ export default function statuses(state = initialState, action) { case ACCOUNT_TIMELINE_FETCH_SUCCESS: case ACCOUNT_TIMELINE_EXPAND_SUCCESS: case CONTEXT_FETCH_SUCCESS: + case NOTIFICATIONS_REFRESH_SUCCESS: + case NOTIFICATIONS_EXPAND_SUCCESS: return normalizeStatuses(state, action.statuses); case TIMELINE_DELETE: return deleteStatus(state, action.id, action.references); -- cgit