You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. import ReducerRegistry from '../base/redux/ReducerRegistry';
  2. import {
  3. CLEAR_NOTIFICATIONS,
  4. HIDE_NOTIFICATION,
  5. SET_NOTIFICATIONS_ENABLED,
  6. SHOW_NOTIFICATION
  7. } from './actionTypes';
  8. import { NOTIFICATION_TYPE_PRIORITIES } from './constants';
  9. /**
  10. * The initial state of the feature notifications.
  11. *
  12. * @type {array}
  13. */
  14. const DEFAULT_STATE = {
  15. enabled: true,
  16. notifications: []
  17. };
  18. interface INotification {
  19. component: Object;
  20. props: {
  21. appearance?: string;
  22. descriptionKey?: string;
  23. titleKey: string;
  24. };
  25. timeout: number;
  26. uid: string;
  27. }
  28. export interface INotificationsState {
  29. enabled: boolean;
  30. notifications: INotification[];
  31. }
  32. /**
  33. * Reduces redux actions which affect the display of notifications.
  34. *
  35. * @param {Object} state - The current redux state.
  36. * @param {Object} action - The redux action to reduce.
  37. * @returns {Object} The next redux state which is the result of reducing the
  38. * specified {@code action}.
  39. */
  40. ReducerRegistry.register<INotificationsState>('features/notifications',
  41. (state = DEFAULT_STATE, action): INotificationsState => {
  42. switch (action.type) {
  43. case CLEAR_NOTIFICATIONS:
  44. return {
  45. ...state,
  46. notifications: []
  47. };
  48. case HIDE_NOTIFICATION:
  49. return {
  50. ...state,
  51. notifications: state.notifications.filter(
  52. notification => notification.uid !== action.uid)
  53. };
  54. case SET_NOTIFICATIONS_ENABLED:
  55. return {
  56. ...state,
  57. enabled: action.enabled
  58. };
  59. case SHOW_NOTIFICATION:
  60. return {
  61. ...state,
  62. notifications:
  63. _insertNotificationByPriority(state.notifications, {
  64. component: action.component,
  65. props: action.props,
  66. timeout: action.timeout,
  67. uid: action.uid
  68. })
  69. };
  70. }
  71. return state;
  72. });
  73. /**
  74. * Creates a new notification queue with the passed in notification placed at
  75. * the end of other notifications with higher or the same priority.
  76. *
  77. * @param {Object[]} notifications - The queue of notifications to be displayed.
  78. * @param {Object} notification - The new notification to add to the queue.
  79. * @private
  80. * @returns {Object[]} A new array with an updated order of the notification
  81. * queue.
  82. */
  83. function _insertNotificationByPriority(notifications: INotification[], notification: INotification) {
  84. // Create a copy to avoid mutation.
  85. const copyOfNotifications = notifications.slice();
  86. // Get the index of any queued notification that has the same id as the new notification
  87. let insertAtLocation = copyOfNotifications.findIndex(
  88. (queuedNotification: INotification) =>
  89. queuedNotification?.uid === notification?.uid
  90. );
  91. if (insertAtLocation !== -1) {
  92. copyOfNotifications.splice(insertAtLocation, 1, notification);
  93. return copyOfNotifications;
  94. }
  95. const newNotificationPriority
  96. = NOTIFICATION_TYPE_PRIORITIES[notification.props.appearance ?? ''] || 0;
  97. // Find where to insert the new notification based on priority. Do not
  98. // insert at the front of the queue so that the user can finish acting on
  99. // any notification currently being read.
  100. for (let i = 1; i < notifications.length; i++) {
  101. const queuedNotification = notifications[i];
  102. const queuedNotificationPriority
  103. = NOTIFICATION_TYPE_PRIORITIES[queuedNotification.props.appearance ?? '']
  104. || 0;
  105. if (queuedNotificationPriority < newNotificationPriority) {
  106. insertAtLocation = i;
  107. break;
  108. }
  109. }
  110. copyOfNotifications.splice(insertAtLocation, 0, notification);
  111. return copyOfNotifications;
  112. }