diff --git a/app/javascript/flavours/glitch/actions/notifications.js b/app/javascript/flavours/glitch/actions/notifications.js index e88eda78f7..ee148e4ef2 100644 --- a/app/javascript/flavours/glitch/actions/notifications.js +++ b/app/javascript/flavours/glitch/actions/notifications.js @@ -25,6 +25,9 @@ export const NOTIFICATIONS_EXPAND_FAIL = 'NOTIFICATIONS_EXPAND_FAIL'; export const NOTIFICATIONS_CLEAR = 'NOTIFICATIONS_CLEAR'; export const NOTIFICATIONS_SCROLL_TOP = 'NOTIFICATIONS_SCROLL_TOP'; +export const NOTIFICATIONS_MOUNT = 'NOTIFICATIONS_MOUNT'; +export const NOTIFICATIONS_UNMOUNT = 'NOTIFICATIONS_UNMOUNT'; + defineMessages({ mention: { id: 'notification.mention', defaultMessage: '{name} mentioned you' }, }); @@ -216,3 +219,15 @@ export function deleteMarkedNotificationsSuccess() { type: NOTIFICATIONS_DELETE_MARKED_SUCCESS, }; }; + +export function mountNotifications() { + return { + type: NOTIFICATIONS_MOUNT, + }; +}; + +export function unmountNotifications() { + return { + type: NOTIFICATIONS_UNMOUNT, + }; +}; diff --git a/app/javascript/flavours/glitch/features/notifications/index.js b/app/javascript/flavours/glitch/features/notifications/index.js index 266d6807d9..ee711bd8ae 100644 --- a/app/javascript/flavours/glitch/features/notifications/index.js +++ b/app/javascript/flavours/glitch/features/notifications/index.js @@ -8,6 +8,8 @@ import { enterNotificationClearingMode, expandNotifications, scrollTopNotifications, + mountNotifications, + unmountNotifications, } from 'flavours/glitch/actions/notifications'; import { addColumn, removeColumn, moveColumn } from 'flavours/glitch/actions/columns'; import NotificationContainer from './containers/notification_container'; @@ -42,6 +44,12 @@ const mapDispatchToProps = dispatch => ({ onEnterCleaningMode(yes) { dispatch(enterNotificationClearingMode(yes)); }, + onMount() { + dispatch(mountNotifications()); + }, + onUnmount() { + dispatch(unmountNotifications()); + }, dispatch, }); @@ -62,6 +70,8 @@ export default class Notifications extends React.PureComponent { localSettings: ImmutablePropTypes.map, notifCleaningActive: PropTypes.bool, onEnterCleaningMode: PropTypes.func, + onMount: PropTypes.func, + onUnmount: PropTypes.func, }; static defaultProps = { @@ -126,6 +136,20 @@ export default class Notifications extends React.PureComponent { } } + componentDidMount () { + const { onMount } = this.props; + if (onMount) { + onMount(); + } + } + + componentWillUnmount () { + const { onUnmount } = this.props; + if (onUnmount) { + onUnmount(); + } + } + render () { const { intl, notifications, shouldUpdateScroll, isLoading, isUnread, columnId, multiColumn, hasMore } = this.props; const pinned = !!columnId; diff --git a/app/javascript/flavours/glitch/reducers/notifications.js b/app/javascript/flavours/glitch/reducers/notifications.js index b712aaa67f..9087e226ca 100644 --- a/app/javascript/flavours/glitch/reducers/notifications.js +++ b/app/javascript/flavours/glitch/reducers/notifications.js @@ -1,4 +1,6 @@ import { + NOTIFICATIONS_MOUNT, + NOTIFICATIONS_UNMOUNT, NOTIFICATIONS_UPDATE, NOTIFICATIONS_EXPAND_SUCCESS, NOTIFICATIONS_EXPAND_REQUEST, @@ -24,6 +26,7 @@ const initialState = ImmutableMap({ items: ImmutableList(), hasMore: true, top: true, + mounted: 0, unread: 0, lastReadId: '0', isLoading: false, @@ -41,7 +44,7 @@ const notificationToMap = (state, notification) => ImmutableMap({ }); const normalizeNotification = (state, notification) => { - const top = state.get('top'); + const top = state.get('top') && state.get('mounted') > 0; if (top) { state = state.set('lastReadId', notification.id); @@ -59,7 +62,7 @@ const normalizeNotification = (state, notification) => { }; const expandNormalizedNotifications = (state, notifications, next) => { - const top = state.get('top'); + const top = state.get('top') && state.get('mounted') > 0; const lastReadId = state.get('lastReadId'); let items = ImmutableList(); @@ -102,18 +105,23 @@ const filterNotifications = (state, relationship) => { return state.update('items', list => list.filterNot(item => item !== null && item.get('account') === relationship.id)); }; +const clearUnread = (state) => { + state = state.set('unread', 0); + const lastNotification = state.get('items').find(item => item !== null); + return state.set('lastReadId', lastNotification ? lastNotification.get('id') : '0'); +} + const updateTop = (state, top) => { - if (top) { - state = state.set('unread', 0); - const lastNotification = state.get('items').find(item => item !== null); - state = state.set('lastReadId', lastNotification ? lastNotification.get('id') : '0'); + if (top && state.get('mounted') > 0) { + state = clearUnread(state); } return state.set('top', top); }; const deleteByStatus = (state, statusId) => { - if (!state.get('top')) { + const top = state.get('top') && state.get('mounted') > 0; + if (!top) { const lastReadId = state.get('lastReadId'); const deletedUnread = state.get('items').filter(item => item !== null && item.get('status') === statusId && compareId(item.get('id'), lastReadId) > 0); state = state.update('unread', unread => unread - deletedUnread.size); @@ -153,6 +161,10 @@ export default function notifications(state = initialState, action) { let st; switch(action.type) { + case NOTIFICATIONS_MOUNT: + return (state.get('top') ? clearUnread(state) : state).update('mounted', count => count + 1); + case NOTIFICATIONS_UNMOUNT: + return state.update('mounted', count => count - 1); case NOTIFICATIONS_EXPAND_REQUEST: case NOTIFICATIONS_DELETE_MARKED_REQUEST: return state.set('isLoading', true);