jitsi-meet/react/features/notifications/components/NotificationsContainer.web.js
Leonard Kim 7341c7bf84 ref(notifications): stop passing around Notifications component
Passing around of the component was used when there were two
independent Notification components. Now that there is only
one Notification component, it is not necessary to pass
around the component.
2018-02-12 17:53:29 -06:00

198 lines
5.6 KiB
JavaScript

import { FlagGroup } from '@atlaskit/flag';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { hideNotification } from '../actions';
import { Notification } from './';
/**
* Implements a React {@link Component} which displays notifications and handles
* automatic dismissmal after a notification is shown for a defined timeout
* period.
*
* @extends {Component}
*/
class NotificationsContainer extends Component {
/**
* {@code NotificationsContainer} component's property types.
*
* @static
*/
static propTypes = {
/**
* The notifications to be displayed, with the first index being the
* notification at the top and the rest shown below it in order.
*/
_notifications: PropTypes.array,
/**
* Whether or not notifications should be displayed at all. If not,
* notifications will be dismissed immediately.
*/
_showNotifications: PropTypes.bool,
/**
* Invoked to update the redux store in order to remove notifications.
*/
dispatch: PropTypes.func
};
/**
* Initializes a new {@code NotificationsContainer} instance.
*
* @param {Object} props - The read-only React Component props with which
* the new instance is to be initialized.
*/
constructor(props) {
super(props);
/**
* The timeout set for automatically dismissing a displayed
* notification. This value is set on the instance and not state to
* avoid additional re-renders.
*
* @type {number|null}
*/
this._notificationDismissTimeout = null;
// Bind event handlers so they are only bound once for every instance.
this._onDismissed = this._onDismissed.bind(this);
}
/**
* Sets a timeout if the currently displayed notification has changed.
*
* @inheritdoc
* returns {void}
*/
componentDidUpdate() {
const { _notifications, _showNotifications } = this.props;
if (_notifications.length) {
const notification = _notifications[0];
if (!_showNotifications || this._notificationDismissTimeout) {
// No-op because there should already be a notification that
// is waiting for dismissal.
} else {
const { timeout, uid } = notification;
this._notificationDismissTimeout = setTimeout(() => {
// Perform a no-op if a timeout is not specified.
if (Number.isInteger(timeout)) {
this._onDismissed(uid);
}
}, timeout);
}
}
}
/**
* Clear any dismissal timeout that is still active.
*
* @inheritdoc
* returns {void}
*/
componentWillUnmount() {
clearTimeout(this._notificationDismissTimeout);
}
/**
* Implements React's {@link Component#render()}.
*
* @inheritdoc
* @returns {ReactElement}
*/
render() {
return (
<FlagGroup onDismissed = { this._onDismissed }>
{ this._renderFlags() }
</FlagGroup>
);
}
/**
* Emits an action to remove the notification from the redux store so it
* stops displaying.
*
* @param {number} flagUid - The id of the notification to be removed.
* @private
* @returns {void}
*/
_onDismissed(flagUid) {
clearTimeout(this._notificationDismissTimeout);
this._notificationDismissTimeout = null;
this.props.dispatch(hideNotification(flagUid));
}
/**
* Renders notifications to display as ReactElements. An empty array will
* be returned if notifications are disabled.
*
* @private
* @returns {ReactElement[]}
*/
_renderFlags() {
const { _notifications, _showNotifications } = this.props;
if (!_showNotifications) {
return [];
}
return _notifications.map(notification => {
const { props, uid } = notification;
// The id attribute is necessary as {@code FlagGroup} looks for
// either id or key to set a key on notifications, but accessing
// props.key will cause React to print an error.
return (
<Notification
{ ...props }
id = { uid }
key = { uid }
uid = { uid } />
);
});
}
}
/**
* Maps (parts of) the Redux state to the associated NotificationsContainer's
* props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _notifications: Array
* }}
*/
function _mapStateToProps(state) {
// TODO: Per existing behavior, notifications should not display when an
// overlay is visible. This logic for checking overlay display can likely be
// simplified.
const {
connectionEstablished,
haveToReload,
isMediaPermissionPromptVisible,
suspendDetected
} = state['features/overlay'];
const isAnyOverlayVisible = (connectionEstablished && haveToReload)
|| isMediaPermissionPromptVisible
|| suspendDetected
|| state['features/base/jwt'].calleeInfoVisible;
const { enabled, notifications } = state['features/notifications'];
return {
_notifications: notifications,
_showNotifications: enabled && !isAnyOverlayVisible
};
}
export default connect(_mapStateToProps)(NotificationsContainer);