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.

NotificationsContainer.web.js 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import { FlagGroup } from '@atlaskit/flag';
  2. import React, { Component } from 'react';
  3. import { connect } from 'react-redux';
  4. import { hideNotification } from '../actions';
  5. /**
  6. * The duration for which a notification should be displayed before being
  7. * dismissed automatically.
  8. *
  9. * @type {number}
  10. */
  11. const DEFAULT_NOTIFICATION_TIMEOUT = 2500;
  12. /**
  13. * Implements a React {@link Component} which displays notifications and handles
  14. * automatic dismissmal after a notification is shown for a defined timeout
  15. * period.
  16. *
  17. * @extends {Component}
  18. */
  19. class NotificationsContainer extends Component {
  20. /**
  21. * {@code NotificationsContainer} component's property types.
  22. *
  23. * @static
  24. */
  25. static propTypes = {
  26. /**
  27. * The notifications to be displayed, with the first index being the
  28. * notification at the top and the rest shown below it in order.
  29. */
  30. _notifications: React.PropTypes.array,
  31. /**
  32. * Invoked to update the redux store in order to remove notifications.
  33. */
  34. dispatch: React.PropTypes.func
  35. };
  36. /**
  37. * Initializes a new {@code NotificationsContainer} instance.
  38. *
  39. * @param {Object} props - The read-only React Component props with which
  40. * the new instance is to be initialized.
  41. */
  42. constructor(props) {
  43. super(props);
  44. /**
  45. * The timeout set for automatically dismissing a displayed
  46. * notification. This value is set on the instance and not state to
  47. * avoid additional re-renders.
  48. *
  49. * @type {number|null}
  50. */
  51. this._notificationDismissTimeout = null;
  52. // Bind event handlers so they are only bound once for every instance.
  53. this._onDismissed = this._onDismissed.bind(this);
  54. }
  55. /**
  56. * Sets a timeout if the currently displayed notification has changed.
  57. *
  58. * @inheritdoc
  59. * returns {void}
  60. */
  61. componentDidUpdate() {
  62. const { _notifications } = this.props;
  63. if (_notifications.length && !this._notificationDismissTimeout) {
  64. const notification = _notifications[0];
  65. const { timeout, uid } = notification;
  66. this._notificationDismissTimeout = setTimeout(() => {
  67. this._onDismissed(uid);
  68. }, timeout || DEFAULT_NOTIFICATION_TIMEOUT);
  69. }
  70. }
  71. /**
  72. * Clear any dismissal timeout that is still active.
  73. *
  74. * @inheritdoc
  75. * returns {void}
  76. */
  77. componentWillUnmount() {
  78. clearTimeout(this._notificationDismissTimeout);
  79. }
  80. /**
  81. * Implements React's {@link Component#render()}.
  82. *
  83. * @inheritdoc
  84. * @returns {ReactElement}
  85. */
  86. render() {
  87. const { _notifications } = this.props;
  88. const flags = _notifications.map(notification => {
  89. const Notification = notification.component;
  90. const { props, uid } = notification;
  91. // The id attribute is necessary as {@code FlagGroup} looks for
  92. // either id or key to set a key on notifications, but accessing
  93. // props.key will cause React to print an error.
  94. return (
  95. <Notification
  96. { ...props }
  97. id = { uid }
  98. key = { uid }
  99. uid = { uid } />
  100. );
  101. });
  102. return (
  103. <FlagGroup onDismissed = { this._onDismissed }>
  104. { flags }
  105. </FlagGroup>
  106. );
  107. }
  108. /**
  109. * Emits an action to remove the notification from the redux store so it
  110. * stops displaying.
  111. *
  112. * @param {number} flagUid - The id of the notification to be removed.
  113. * @private
  114. * @returns {void}
  115. */
  116. _onDismissed(flagUid) {
  117. clearTimeout(this._notificationDismissTimeout);
  118. this._notificationDismissTimeout = null;
  119. this.props.dispatch(hideNotification(flagUid));
  120. }
  121. }
  122. /**
  123. * Maps (parts of) the Redux state to the associated NotificationsContainer's
  124. * props.
  125. *
  126. * @param {Object} state - The Redux state.
  127. * @private
  128. * @returns {{
  129. * _notifications: React.PropTypes.array
  130. * }}
  131. */
  132. function _mapStateToProps(state) {
  133. return {
  134. _notifications: state['features/notifications']
  135. };
  136. }
  137. export default connect(_mapStateToProps)(NotificationsContainer);