diff --git a/react/features/notifications/constants.js b/react/features/notifications/constants.js index 7d01cd10f..f1a070648 100644 --- a/react/features/notifications/constants.js +++ b/react/features/notifications/constants.js @@ -10,3 +10,16 @@ export const NOTIFICATION_TYPE = { SUCCESS: 'success', WARNING: 'warning' }; + +/** + * A mapping of notification type to priority of display. + * + * @enum {number} + */ +export const NOTIFICATION_TYPE_PRIORITIES = { + [NOTIFICATION_TYPE.ERROR]: 5, + [NOTIFICATION_TYPE.INFO]: 3, + [NOTIFICATION_TYPE.NORMAL]: 3, + [NOTIFICATION_TYPE.SUCCESS]: 3, + [NOTIFICATION_TYPE.WARNING]: 4 +}; diff --git a/react/features/notifications/reducer.js b/react/features/notifications/reducer.js index 105d4eb18..0a9c4a389 100644 --- a/react/features/notifications/reducer.js +++ b/react/features/notifications/reducer.js @@ -5,6 +5,7 @@ import { SET_NOTIFICATIONS_ENABLED, SHOW_NOTIFICATION } from './actionTypes'; +import { NOTIFICATION_TYPE_PRIORITIES } from './constants'; /** * The initial state of the feature notifications. @@ -43,17 +44,55 @@ ReducerRegistry.register('features/notifications', case SHOW_NOTIFICATION: return { ...state, - notifications: [ - ...state.notifications, - { + notifications: + _insertNotificationByPriority(state.notifications, { component: action.component, props: action.props, timeout: action.timeout, uid: action.uid - } - ] + }) }; } return state; }); + +/** + * Creates a new notification queue with the passed in notification placed at + * the end of other notifications with higher or the same priority. + * + * @param {Object[]} notifications - The queue of notifications to be displayed. + * @param {Object} notification - The new notification to add to the queue. + * @private + * @returns {Object[]} A new array with an updated order of the notification + * queue. + */ +function _insertNotificationByPriority(notifications, notification) { + const newNotificationPriority + = NOTIFICATION_TYPE_PRIORITIES[notification.props.appearance] || 0; + + // Default to putting the new notification at the end of the queue. + let insertAtLocation = notifications.length; + + // Find where to insert the new notification based on priority. Do not + // insert at the front of the queue so that the user can finish acting on + // any notification currently being read. + for (let i = 1; i < notifications.length; i++) { + const queuedNotification = notifications[i]; + const queuedNotificationPriority + = NOTIFICATION_TYPE_PRIORITIES[queuedNotification.props.appearance] + || 0; + + if (queuedNotificationPriority < newNotificationPriority) { + insertAtLocation = i; + break; + } + } + + // Create a copy to avoid mutation and insert the notification. + const copyOfNotifications = notifications.slice(); + + copyOfNotifications.splice(insertAtLocation, 0, notification); + + return copyOfNotifications; +}