import React from 'react'; import PropTypes from 'prop-types'; import { observer } from 'mobx-react'; import { autorun, action, observable, computed } from 'mobx'; import Spinning from 'grommet/components/icons/Spinning'; import CircleInformationIcon from 'grommet/components/icons/base/CircleInformation'; import { delay, isEmpty, includes, get } from 'lodash'; import classnames from 'classnames'; import './network-activity-overlay.scss'; function Indicator({ error }) { return error ? : ; } @observer export default class NetworkActivityOverlay extends React.Component { static defaultProps = { timeout: 30000, errorTimeout: 2000, } static propTypes = { model: PropTypes.object, message: PropTypes.string, timeout: PropTypes.number, visible: PropTypes.bool, method: PropTypes.string, errorTimeout: PropTypes.number, } @computed get isRequesting() { const { syncInProgress } = this.props.model || {}; if (this.props.method) { return !!(syncInProgress && syncInProgress.method === this.props.method); } return !!syncInProgress; } @computed get hasError() { return this.props.model && !isEmpty(this.props.model.errors); } @computed get isVisible() { return this.props.visible || this.isPending; } @observable isPending = false; removeHandler = null; @action.bound removeMessage() { this.isPending = false; } clearTimeout() { if (this.removeHandler) { clearTimeout(this.removeHandler); this.removeHandler = null; } } installRemoval() { this.clearTimeout(); this.removeHandler = delay( this.removeMessage, (this.hasError ? this.props.errorTimeout : this.props.timeout), ); } componentWillMount() { this.loadingObserverDisposer = autorun(() => { if (this.hasError || this.isRequesting) { this.isPending = true; this.installRemoval(); } else if (!this.hasError) { this.isPending = false; } }); } componentWillUnMount() { this.loadingObserverDisposer(); this.clearTimeout(); } get message() { const { props: { model } } = this; let { message } = this.props; if (!message) { if (this.hasError) { message = get(model, 'errorMessage', 'Error'); } else { const method = get(model, 'syncInProgress.method'); if ('GET' === method) { message = 'Loading…'; } else if (includes(['PATCH', 'POST', 'PUT'], method)) { message = 'Saving…'; } else if ('DELETE' === method) { message = 'Deleting…'; } } } return message || 'Pending…'; } render() { if (!this.isVisible) { return null; } const classes = classnames('network-activity-overlay', this.props.className, { rounded: this.props.roundedCorners, }); return (
{this.message}
); } }