Mailspring/app/internal_packages/send-later/lib/send-later-button.jsx
Ben Gotow 1a3cca8d0a
Totally overhauled composer based on Slate (#524)
* Remove the composer contenteditable, replace with basic <textarea>

* Beginning broader cleanup of draft session

* DraftJS composer with color, style support

* Serialization/unserialization of basic styles, toolbar working

* WIP

* Switch to draft-js-plugins approach, need to revisit HTML

* Move HTML conversion functionality into plugins

* Add spellcheck context menu to editor

* Initial work on quoted text

* Further work on quoted text

* BLOCK approach

* Entity approach - better, does not bump out to top level

* Hiding and showing quoted text via CSS

* Get rid of ability to inject another subject line component

* Clean up specs, DraftFactory to ES6

* Remove old initial focus hack

* Fix focusing, initial text selection

* Remove participant “collapsing” support, it can be confusing

* Correctly terminate links on carriage returns

* Initial signature support, allow removal of uneditable blocks

* Sync body string with body editorstate

* Simplify draft editor session, finish signatures

* Templates

* Minor fixes

* Simplify link/open tracking, ensure it works

* Reorg composer, rework template editor

* Omg the slowness is all the stupid emoji button

* Polish and small fixes

* Performance improvements, new templates UI

* Don’t assume nodes are elements

* Fix for sending drafts twice due to back-to-back saves

* Fix order of operations on app quit to save drafts reliably

* Improve DraftJS-Convert whitespace handling

* Use contentID throughout attachment lifecycle

* Try to fix images

* Switch to Slate instead of DraftJS… much better

* Fix newline handling

* Bug fixes

* Cleanup

* Finish templates plugin

* Clean up text editing / support for Gmail email styles

* Support for color + size on the same node, clean trailing whitespace

* Restore emoji typeahead / emoji picker

* Fix scrolling in template editor

* Fix specs

* Fix newlines

* Re-implement spellcheck to be faster

* Make spellcheck decorator changes invisible to the undo/redo stack

* Remove comment

* Polish themplates panel

* Fix #521
2018-01-11 15:55:56 -08:00

168 lines
4.3 KiB
JavaScript

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import moment from 'moment';
import { Actions, FeatureUsageStore } from 'mailspring-exports';
import { RetinaImg } from 'mailspring-component-kit';
import SendLaterPopover from './send-later-popover';
import { PLUGIN_ID } from './send-later-constants';
function sendLaterDateForDraft(draft) {
return ((draft && draft.metadataForPluginId(PLUGIN_ID)) || {}).expiration;
}
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;
}
if (sendLaterDateForDraft(nextProps.draft) !== sendLaterDateForDraft(this.props.draft)) {
return true;
}
return false;
}
componentDidUpdate(prevProps) {
if (
this.state.saving &&
sendLaterDateForDraft(prevProps.draft) !== sendLaterDateForDraft(this.props.draft)
) {
this.setState({ saving: false });
}
}
componentWillUnmount() {
this.mounted = false;
}
onAssignSendLaterDate = async (sendLaterDate, dateLabel) => {
if (!this.props.isValidDraft()) {
return;
}
Actions.closePopover();
const currentSendLaterDate = sendLaterDateForDraft(this.props.draft);
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 {
await FeatureUsageStore.markUsedOrUpgrade('send-later', {
usedUpHeader: 'All Scheduled Sends Used',
usagePhrase: 'schedule sending of',
iconUrl: 'mailspring://send-later/assets/ic-send-later-modal@2x.png',
});
} catch (error) {
if (error instanceof FeatureUsageStore.NoProAccessError) {
return;
}
}
this.setState({ saving: true });
}
this.props.session.changes.addPluginMetadata(PLUGIN_ID, {
expiration: sendLaterDate,
});
if (AppEnv.isComposerWindow()) {
AppEnv.close();
}
};
onCancelSendLater = () => {
Actions.closePopover();
this.props.session.changes.addPluginMetadata(PLUGIN_ID, {
expiration: null,
});
};
onClick = () => {
const buttonRect = ReactDOM.findDOMNode(this).getBoundingClientRect();
Actions.openPopover(
<SendLaterPopover
sendLaterDate={sendLaterDateForDraft(this.props.draft)}
onAssignSendLaterDate={this.onAssignSendLaterDate}
onCancelSendLater={this.onCancelSendLater}
/>,
{ originRect: buttonRect, direction: 'up' }
);
};
render() {
let className = 'btn btn-toolbar btn-send-later';
if (this.state.saving) {
return (
<button
className={className}
title="Saving send date..."
tabIndex={-1}
style={{ order: -99 }}
>
<RetinaImg
name="inline-loading-spinner.gif"
mode={RetinaImg.Mode.ContentDark}
style={{ width: 14, height: 14 }}
/>
</button>
);
}
let sendLaterLabel = false;
const sendLaterDate = sendLaterDateForDraft(this.props.draft);
if (sendLaterDate) {
className += ' btn-enabled';
if (sendLaterDate > new Date()) {
sendLaterLabel = (
<span className="at">Sending in {moment(sendLaterDate).fromNow(true)}</span>
);
} else {
sendLaterLabel = <span className="at">Sending now</span>;
}
}
return (
<button
className={className}
title="Send later…"
onClick={this.onClick}
tabIndex={-1}
style={{ order: -99 }}
>
<RetinaImg name="icon-composer-sendlater.png" mode={RetinaImg.Mode.ContentIsMask} />
{sendLaterLabel}
<span>&nbsp;</span>
<RetinaImg name="icon-composer-dropdown.png" mode={RetinaImg.Mode.ContentIsMask} />
</button>
);
}
}
export default SendLaterButton;