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.

reducer.ts 3.9KB

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