2017-09-07 07:19:48 +08:00
|
|
|
import React, {Component} from 'react'
|
|
|
|
import PropTypes from 'prop-types'
|
|
|
|
import ReactDOM from 'react-dom'
|
2017-09-26 06:44:20 +08:00
|
|
|
import {Actions, DateUtils, NylasAPIHelpers, FeatureUsageStore} from 'nylas-exports'
|
2017-09-07 07:19:48 +08:00
|
|
|
import {RetinaImg} from 'nylas-component-kit'
|
2017-09-26 06:44:20 +08:00
|
|
|
|
2017-09-07 07:19:48 +08:00
|
|
|
import SendLaterPopover from './send-later-popover'
|
|
|
|
import {PLUGIN_ID, PLUGIN_NAME} from './send-later-constants'
|
|
|
|
|
2017-09-26 06:44:20 +08:00
|
|
|
function sendLaterDateForDraft(draft) {
|
|
|
|
if (!draft) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const messageMetadata = draft.metadataForPluginId(PLUGIN_ID) || {};
|
|
|
|
return messageMetadata.expiration;
|
|
|
|
}
|
2017-09-07 07:19:48 +08:00
|
|
|
|
|
|
|
class SendLaterButton extends Component {
|
|
|
|
static displayName = 'SendLaterButton';
|
|
|
|
|
|
|
|
static containerRequired = false;
|
|
|
|
|
|
|
|
static propTypes = {
|
|
|
|
draft: PropTypes.object.isRequired,
|
|
|
|
session: PropTypes.object.isRequired,
|
|
|
|
isValidDraft: PropTypes.func,
|
|
|
|
};
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
this.state = {
|
|
|
|
saving: false,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
this.mounted = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
shouldComponentUpdate(nextProps, nextState) {
|
|
|
|
if (nextState.saving !== this.state.saving) {
|
|
|
|
return true;
|
|
|
|
}
|
2017-09-26 06:44:20 +08:00
|
|
|
if (sendLaterDateForDraft(nextProps.draft) !== sendLaterDateForDraft(this.props.draft)) {
|
2017-09-07 07:19:48 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this.mounted = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
onAssignSendLaterDate = async (sendLaterDate, dateLabel) => {
|
|
|
|
if (!this.props.isValidDraft()) { return }
|
|
|
|
Actions.closePopover();
|
|
|
|
|
2017-09-26 06:44:20 +08:00
|
|
|
const currentSendLaterDate = sendLaterDateForDraft(this.props.draft)
|
2017-09-07 07:19:48 +08:00
|
|
|
if (currentSendLaterDate === sendLaterDate) { return }
|
|
|
|
|
|
|
|
// Only check for feature usage and record metrics if this draft is not
|
|
|
|
// already set to send later.
|
|
|
|
if (!currentSendLaterDate) {
|
|
|
|
try {
|
2017-09-26 06:44:20 +08:00
|
|
|
await FeatureUsageStore.asyncUseFeature('send-later', {
|
|
|
|
usedUpHeader: "All Scheduled Sends Used",
|
|
|
|
usagePhrase: "schedule sending of",
|
|
|
|
iconUrl: "mailspring://send-later/assets/ic-send-later-modal@2x.png",
|
|
|
|
})
|
2017-09-07 07:19:48 +08:00
|
|
|
} catch (error) {
|
|
|
|
if (error instanceof FeatureUsageStore.NoProAccessError) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.setState({saving: true});
|
|
|
|
const sendInSec = Math.round(((new Date(sendLaterDate)).valueOf() - Date.now()) / 1000)
|
|
|
|
Actions.recordUserEvent("Draft Send Later", {
|
|
|
|
timeInSec: sendInSec,
|
|
|
|
timeInLog10Sec: Math.log10(sendInSec),
|
|
|
|
label: dateLabel,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
this.onSetMetadata({expiration: sendLaterDate});
|
|
|
|
};
|
|
|
|
|
|
|
|
onCancelSendLater = () => {
|
|
|
|
Actions.closePopover();
|
2017-09-26 06:44:20 +08:00
|
|
|
this.onSetMetadata({expiration: null});
|
2017-09-07 07:19:48 +08:00
|
|
|
};
|
|
|
|
|
2017-09-26 06:44:20 +08:00
|
|
|
onSetMetadata = async ({expiration}) => {
|
2017-09-07 07:19:48 +08:00
|
|
|
const {draft, session} = this.props;
|
2017-09-26 06:44:20 +08:00
|
|
|
|
|
|
|
if (!this.mounted) { return; }
|
2017-09-07 07:19:48 +08:00
|
|
|
this.setState({saving: true});
|
|
|
|
|
|
|
|
try {
|
|
|
|
await NylasAPIHelpers.authPlugin(PLUGIN_ID, PLUGIN_NAME, draft.accountId);
|
|
|
|
if (!this.mounted) { return; }
|
|
|
|
|
2017-09-26 06:44:20 +08:00
|
|
|
session.changes.addPluginMetadata(PLUGIN_ID, {expiration});
|
2017-09-07 07:19:48 +08:00
|
|
|
|
|
|
|
if (expiration && NylasEnv.isComposerWindow()) {
|
|
|
|
NylasEnv.close();
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
NylasEnv.reportError(error);
|
|
|
|
NylasEnv.showErrorDialog(`Sorry, we were unable to schedule this message. ${error.message}`);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.mounted) { return }
|
|
|
|
this.setState({saving: false})
|
|
|
|
}
|
|
|
|
|
|
|
|
onClick = () => {
|
|
|
|
const buttonRect = ReactDOM.findDOMNode(this).getBoundingClientRect()
|
|
|
|
Actions.openPopover(
|
|
|
|
<SendLaterPopover
|
2017-09-26 06:44:20 +08:00
|
|
|
sendLaterDate={sendLaterDateForDraft(this.props.draft)}
|
2017-09-07 07:19:48 +08:00
|
|
|
onAssignSendLaterDate={this.onAssignSendLaterDate}
|
|
|
|
onCancelSendLater={this.onCancelSendLater}
|
|
|
|
/>,
|
|
|
|
{originRect: buttonRect, direction: 'up'}
|
|
|
|
)
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
let className = 'btn btn-toolbar btn-send-later';
|
|
|
|
|
|
|
|
if (this.state.saving) {
|
|
|
|
return (
|
2017-09-26 06:44:20 +08:00
|
|
|
<button
|
|
|
|
className={className}
|
|
|
|
title="Saving send date..."
|
|
|
|
tabIndex={-1}
|
|
|
|
style={{order: -99}}
|
|
|
|
>
|
2017-09-07 07:19:48 +08:00
|
|
|
<RetinaImg
|
|
|
|
name="inline-loading-spinner.gif"
|
|
|
|
mode={RetinaImg.Mode.ContentDark}
|
|
|
|
style={{width: 14, height: 14}}
|
|
|
|
/>
|
|
|
|
</button>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let sendLaterLabel = false;
|
2017-09-26 06:44:20 +08:00
|
|
|
const sendLaterDate = sendLaterDateForDraft(this.props.draft);
|
2017-09-07 07:19:48 +08:00
|
|
|
|
|
|
|
if (sendLaterDate) {
|
|
|
|
className += ' btn-enabled';
|
|
|
|
const momentDate = DateUtils.futureDateFromString(sendLaterDate);
|
|
|
|
if (momentDate) {
|
|
|
|
sendLaterLabel = <span className="at">Sending in {momentDate.fromNow(true)}</span>;
|
|
|
|
} else {
|
|
|
|
sendLaterLabel = <span className="at">Sending now</span>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (
|
2017-09-26 06:44:20 +08:00
|
|
|
<button
|
|
|
|
className={className}
|
|
|
|
title="Send later…"
|
|
|
|
onClick={this.onClick}
|
|
|
|
tabIndex={-1}
|
|
|
|
style={{order: -99}}
|
|
|
|
>
|
2017-09-07 07:19:48 +08:00
|
|
|
<RetinaImg name="icon-composer-sendlater.png" mode={RetinaImg.Mode.ContentIsMask} />
|
|
|
|
{sendLaterLabel}
|
|
|
|
<span> </span>
|
|
|
|
<RetinaImg name="icon-composer-dropdown.png" mode={RetinaImg.Mode.ContentIsMask} />
|
|
|
|
</button>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default SendLaterButton
|