jiti-meet/react/features/notifications/components/AbstractNotificationsContai...

147 lines
4.0 KiB
JavaScript

// @flow
import { Component } from 'react';
import { getOverlayToRender } from '../../overlay';
import { hideNotification } from '../actions';
export type Props = {
/**
* The notifications to be displayed, with the first index being the
* notification at the top and the rest shown below it in order.
*/
_notifications: Array<Object>,
/**
* Invoked to update the redux store in order to remove notifications.
*/
dispatch: Function
};
/**
* Abstract class for {@code NotificationsContainer} component.
*/
export default class AbstractNotificationsContainer<P: Props>
extends Component<P> {
/**
* A timeout id returned by setTimeout.
*/
_notificationDismissTimeout: ?TimeoutID;
/**
* Initializes a new {@code AbstractNotificationsContainer} instance.
*
* @inheritdoc
*/
constructor(props: P) {
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
*/
componentDidUpdate(prevProps: P) {
const { _notifications } = this.props;
if (_notifications.length) {
const notification = _notifications[0];
const previousNotification
= prevProps._notifications.length
? prevProps._notifications[0]
: undefined;
if (notification !== previousNotification) {
this._clearNotificationDismissTimeout();
if (notification) {
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);
}
}
} else if (this._notificationDismissTimeout) {
// Clear timeout when all notifications are cleared (e.g external
// call to clear them)
this._clearNotificationDismissTimeout();
}
}
/**
* Clear any dismissal timeout that is still active.
*
* @inheritdoc
* returns {void}
*/
componentWillUnmount() {
this._clearNotificationDismissTimeout();
}
_onDismissed: number => void;
/**
* Clears the running notification dismiss timeout, if any.
*
* @returns {void}
*/
_clearNotificationDismissTimeout() {
this._notificationDismissTimeout
&& clearTimeout(this._notificationDismissTimeout);
this._notificationDismissTimeout = null;
}
/**
* Emits an action to remove the notification from the redux store so it
* stops displaying.
*
* @param {number} uid - The id of the notification to be removed.
* @private
* @returns {void}
*/
_onDismissed(uid) {
this._clearNotificationDismissTimeout();
this.props.dispatch(hideNotification(uid));
}
}
/**
* Maps (parts of) the Redux state to the associated NotificationsContainer's
* props.
*
* @param {Object} state - The Redux state.
* @private
* @returns {{
* _notifications: Array
* }}
*/
export function _abstractMapStateToProps(state: Object) {
const isAnyOverlayVisible = Boolean(getOverlayToRender(state));
const { enabled, notifications } = state['features/notifications'];
return {
_notifications: enabled && !isAnyOverlayVisible ? notifications : []
};
}