import React from 'react';
import { localized, UndoRedoStore, SyncbackMetadataTask } from 'mailspring-exports';
import { RetinaImg } from 'mailspring-component-kit';
import { CSSTransitionGroup } from 'react-transition-group';
function isUndoSend(block) {
return (
block.tasks.length === 1 &&
block.tasks[0] instanceof SyncbackMetadataTask &&
block.tasks[0].value.isUndoSend
);
}
function getUndoSendExpiration(block) {
return block.tasks[0].value.expiration * 1000;
}
function getDisplayDuration(block) {
return isUndoSend(block) ? Math.max(400, getUndoSendExpiration(block) - Date.now()) : 3000;
}
class Countdown extends React.Component<{ expiration: number }, { x: number }> {
animationDuration: string;
_tickStart: NodeJS.Timeout;
_tick: NodeJS.Timeout;
constructor(props) {
super(props);
this.animationDuration = `${props.expiration - Date.now()}ms`;
this.state = { x: 0 };
}
componentWillReceiveProps(nextProps) {
if (nextProps.expiration !== this.props.expiration) {
this.animationDuration = `${nextProps.expiration - Date.now()}ms`;
}
}
componentDidMount() {
this._tickStart = setTimeout(() => {
this.setState({ x: this.state.x + 1 });
this._tick = setInterval(() => {
this.setState({ x: this.state.x + 1 });
}, 1000);
}, this.props.expiration % 1000);
}
componentWillUnmount() {
clearTimeout(this._tickStart);
clearInterval(this._tick);
}
render() {
// subtract a few ms so we never round up to start time + 1 by accident
let diff = Math.min(
Math.max(0, this.props.expiration - Date.now()),
AppEnv.config.get('core.sending.undoSend')
);
return (
{Math.ceil(diff / 1000)}
{diff > 0 && (
)}
);
}
}
const UndoSendContent = ({ block, onMouseEnter, onMouseLeave }) => {
return (
{localized('Sending soon...')}
AppEnv.commands.dispatch('core:undo')}>
{localized('Undo')}
);
};
const BasicContent = ({ block, onMouseEnter, onMouseLeave }) => {
return (
{block.description}
AppEnv.commands.dispatch('core:undo')}>
{localized('Undo')}
);
};
export default class UndoRedoToast extends React.Component<{}, { block: any }> {
static displayName = 'UndoRedoToast';
static containerRequired = false;
_timeout: NodeJS.Timeout;
_unlisten?: () => void;
constructor(props) {
super(props);
this._timeout = null;
this._unlisten = null;
// Note: we explicitly do /not/ set initial state to the state of
// the UndoRedoStore here because "getMostRecent" might be more
// than 3000ms old.
this.state = {
block: null,
};
}
componentDidMount() {
this._unlisten = UndoRedoStore.listen(() => {
this.setState({
block: UndoRedoStore.getMostRecent(),
});
});
}
componentDidUpdate() {
this._ensureTimeout();
}
componentWillUnmount() {
this._clearTimeout();
if (this._unlisten) {
this._unlisten();
}
}
_clearTimeout() {
clearTimeout(this._timeout);
this._timeout = null;
}
_ensureTimeout() {
this._clearTimeout();
if (this.state.block) {
this._timeout = setTimeout(() => {
this.setState({ block: null });
}, getDisplayDuration(this.state.block));
}
}
_onMouseEnter = () => {
this._clearTimeout();
};
_onMouseLeave = () => {
this._ensureTimeout();
};
render() {
const { block } = this.state;
const Component = block && (isUndoSend(block) ? UndoSendContent : BasicContent);
return (
{block ? (
) : null}
);
}
}