mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-21 22:54:11 +08:00
feat(tracking): sticky tracking state and consolidate component
This commit is contained in:
parent
73bc277d68
commit
9ad088f899
4 changed files with 160 additions and 90 deletions
|
@ -1,8 +1,8 @@
|
||||||
import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
|
// import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
|
||||||
import {RetinaImg} from 'nylas-component-kit'
|
import {React} from 'nylas-exports'
|
||||||
|
import {MetadataComposerToggleButton} from 'nylas-component-kit'
|
||||||
import {PLUGIN_ID, PLUGIN_NAME} from './link-tracking-constants'
|
import {PLUGIN_ID, PLUGIN_NAME} from './link-tracking-constants'
|
||||||
|
|
||||||
|
|
||||||
export default class LinkTrackingButton extends React.Component {
|
export default class LinkTrackingButton extends React.Component {
|
||||||
static displayName = 'LinkTrackingButton';
|
static displayName = 'LinkTrackingButton';
|
||||||
|
|
||||||
|
@ -10,55 +10,26 @@ export default class LinkTrackingButton extends React.Component {
|
||||||
draftClientId: React.PropTypes.string.isRequired,
|
draftClientId: React.PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
_title(enabled) {
|
||||||
super(props);
|
const dir = enabled ? "Disable" : "Enable";
|
||||||
this.state = {enabled: false};
|
return `${dir} link tracking`
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
_errorMessage(error) {
|
||||||
const query = DatabaseStore.findBy(Message, {clientId: this.props.draftClientId});
|
return `Sorry, we were unable to save your link tracking settings. ${error.message}`
|
||||||
this._subscription = Rx.Observable.fromQuery(query).subscribe(this.setStateFromDraft);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this._subscription.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
setStateFromDraft = (draft)=> {
|
|
||||||
if (!draft) return;
|
|
||||||
const metadata = draft.metadataForPluginId(PLUGIN_ID);
|
|
||||||
this.setState({enabled: metadata ? metadata.tracked : false});
|
|
||||||
};
|
|
||||||
|
|
||||||
_onClick = ()=> {
|
|
||||||
const currentlyEnabled = this.state.enabled;
|
|
||||||
|
|
||||||
// write metadata into the draft to indicate tracked state
|
|
||||||
DraftStore.sessionForClientId(this.props.draftClientId).then((session) => {
|
|
||||||
const draft = session.draft();
|
|
||||||
|
|
||||||
NylasAPI.authPlugin(PLUGIN_ID, PLUGIN_NAME, draft.accountId)
|
|
||||||
.then(() => {
|
|
||||||
Actions.setMetadata(draft, PLUGIN_ID, currentlyEnabled ? null : {tracked: true});
|
|
||||||
})
|
|
||||||
.catch((error)=> {
|
|
||||||
NylasEnv.reportError(error);
|
|
||||||
NylasEnv.showErrorDialog(`Sorry, we were unable to save your link tracking settings. ${error.message}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const title = this.state.enabled ? "Disable" : "Enable"
|
|
||||||
return (
|
return (
|
||||||
<button
|
<MetadataComposerToggleButton
|
||||||
title={`${title} link tracking`}
|
title={this._title}
|
||||||
className={`btn btn-toolbar ${this.state.enabled ? "btn-enabled" : ""}`}
|
iconName="icon-composer-linktracking.png"
|
||||||
onClick={this._onClick}>
|
pluginId={PLUGIN_ID}
|
||||||
<RetinaImg
|
pluginName={PLUGIN_NAME}
|
||||||
name="icon-composer-linktracking.png"
|
metadataKey="tracked"
|
||||||
mode={RetinaImg.Mode.ContentIsMask} />
|
stickyToggle
|
||||||
</button>
|
errorMessage={this._errorMessage}
|
||||||
|
draftClientId={this.props.draftClientId} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,60 +1,35 @@
|
||||||
import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
|
// import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
|
||||||
import {RetinaImg} from 'nylas-component-kit'
|
import {React} from 'nylas-exports'
|
||||||
|
import {MetadataComposerToggleButton} from 'nylas-component-kit'
|
||||||
import {PLUGIN_ID, PLUGIN_NAME} from './open-tracking-constants'
|
import {PLUGIN_ID, PLUGIN_NAME} from './open-tracking-constants'
|
||||||
|
|
||||||
export default class OpenTrackingButton extends React.Component {
|
export default class OpenTrackingButton extends React.Component {
|
||||||
|
|
||||||
static displayName = 'OpenTrackingButton';
|
static displayName = 'OpenTrackingButton';
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
draftClientId: React.PropTypes.string.isRequired,
|
draftClientId: React.PropTypes.string.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props) {
|
_title(enabled) {
|
||||||
super(props);
|
const dir = enabled ? "Disable" : "Enable";
|
||||||
this.state = {enabled: false};
|
return `${dir} read receipts`
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
_errorMessage(error) {
|
||||||
const query = DatabaseStore.findBy(Message, {clientId: this.props.draftClientId});
|
return `Sorry, we were unable to save your read receipt settings. ${error.message}`
|
||||||
this._subscription = Rx.Observable.fromQuery(query).subscribe(this.setStateFromDraft)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this._subscription.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
setStateFromDraft = (draft)=> {
|
|
||||||
if (!draft) return;
|
|
||||||
const metadata = draft.metadataForPluginId(PLUGIN_ID);
|
|
||||||
this.setState({enabled: metadata ? metadata.tracked : false});
|
|
||||||
};
|
|
||||||
|
|
||||||
_onClick=()=> {
|
|
||||||
const currentlyEnabled = this.state.enabled;
|
|
||||||
|
|
||||||
// write metadata into the draft to indicate tracked state
|
|
||||||
DraftStore.sessionForClientId(this.props.draftClientId).then((session)=> {
|
|
||||||
const draft = session.draft();
|
|
||||||
|
|
||||||
NylasAPI.authPlugin(PLUGIN_ID, PLUGIN_NAME, draft.accountId)
|
|
||||||
.then(() => {
|
|
||||||
Actions.setMetadata(draft, PLUGIN_ID, currentlyEnabled ? null : {tracked: true});
|
|
||||||
})
|
|
||||||
.catch((error)=> {
|
|
||||||
NylasEnv.reportError(error);
|
|
||||||
NylasEnv.showErrorDialog(`Sorry, we were unable to save your read receipt settings. ${error.message}`);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const title = this.state.enabled ? "Disable" : "Enable";
|
return (
|
||||||
return (<button className={`btn btn-toolbar ${this.state.enabled ? "btn-enabled" : ""}`}
|
<MetadataComposerToggleButton
|
||||||
onClick={this._onClick} title={`${title} read receipts`}>
|
title={this._title}
|
||||||
<RetinaImg url="nylas://open-tracking/assets/icon-composer-eye@2x.png"
|
iconUrl="nylas://open-tracking/assets/icon-composer-eye@2x.png"
|
||||||
mode={RetinaImg.Mode.ContentIsMask} />
|
pluginId={PLUGIN_ID}
|
||||||
</button>)
|
pluginName={PLUGIN_NAME}
|
||||||
|
metadataKey="tracked"
|
||||||
|
stickyToggle
|
||||||
|
errorMessage={this._errorMessage}
|
||||||
|
draftClientId={this.props.draftClientId} />
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
123
src/components/metadata-composer-toggle-button.jsx
Normal file
123
src/components/metadata-composer-toggle-button.jsx
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
|
||||||
|
import {RetinaImg} from 'nylas-component-kit'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
|
||||||
|
export default class MetadataComposerToggleButton extends React.Component {
|
||||||
|
|
||||||
|
static displayName = 'MetadataComposerToggleButton';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
title: React.PropTypes.func.isRequired,
|
||||||
|
iconUrl: React.PropTypes.string,
|
||||||
|
iconName: React.PropTypes.string,
|
||||||
|
pluginId: React.PropTypes.string.isRequired,
|
||||||
|
pluginName: React.PropTypes.string.isRequired,
|
||||||
|
metadataKey: React.PropTypes.string.isRequired,
|
||||||
|
stickyToggle: React.PropTypes.bool,
|
||||||
|
errorMessage: React.PropTypes.func.isRequired,
|
||||||
|
draftClientId: React.PropTypes.string.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
stickyToggle: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
enabled: false,
|
||||||
|
isSetup: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this._mounted = true;
|
||||||
|
const query = DatabaseStore.findBy(Message, {clientId: this.props.draftClientId});
|
||||||
|
this._subscription = Rx.Observable.fromQuery(query).subscribe(this._onDraftChange)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this._mounted = false
|
||||||
|
this._subscription.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_configKey() {
|
||||||
|
return `plugins.${this.props.pluginId}.defaultOn`
|
||||||
|
}
|
||||||
|
|
||||||
|
_isDefaultOn() {
|
||||||
|
return NylasEnv.config.get(this._configKey())
|
||||||
|
}
|
||||||
|
|
||||||
|
_onDraftChange = (draft)=> {
|
||||||
|
if (!this._mounted || !draft) { return; }
|
||||||
|
const metadata = draft.metadataForPluginId(this.props.pluginId);
|
||||||
|
if (!metadata) {
|
||||||
|
if (!this.state.isSetup) {
|
||||||
|
if (this._isDefaultOn()) {
|
||||||
|
this._setMetadataValueTo(true)
|
||||||
|
}
|
||||||
|
this.setState({isSetup: true})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.setState({enabled: metadata.tracked, isSetup: true});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_setMetadataValueTo(enabled) {
|
||||||
|
const newValue = {}
|
||||||
|
newValue[this.props.metadataKey] = enabled
|
||||||
|
this.setState({enabled, pending: true});
|
||||||
|
const metadataValue = enabled ? newValue : null
|
||||||
|
// write metadata into the draft to indicate tracked state
|
||||||
|
return DraftStore.sessionForClientId(this.props.draftClientId).then((session)=> {
|
||||||
|
const draft = session.draft();
|
||||||
|
|
||||||
|
return NylasAPI.authPlugin(this.props.pluginId, this.props.pluginName, draft.accountId)
|
||||||
|
.then(() => {
|
||||||
|
Actions.setMetadata(draft, this.props.pluginId, metadataValue);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({enabled: false});
|
||||||
|
NylasEnv.reportError(error);
|
||||||
|
NylasEnv.showErrorDialog(this.props.errorMessage(error));
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
this.setState({pending: false})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_onClick = () => {
|
||||||
|
// Toggle.
|
||||||
|
if (this.state.pending) { return; }
|
||||||
|
if (this.props.stickyToggle) {
|
||||||
|
NylasEnv.config.set(this._configKey(), !this.state.enabled)
|
||||||
|
}
|
||||||
|
this._setMetadataValueTo(!this.state.enabled)
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const title = this.props.title(this.state.enabled)
|
||||||
|
|
||||||
|
const className = classnames({
|
||||||
|
"btn": true,
|
||||||
|
"btn-toolbar": true,
|
||||||
|
"btn-pending": this.state.pending,
|
||||||
|
"btn-enabled": this.state.enabled,
|
||||||
|
});
|
||||||
|
|
||||||
|
const attrs = {}
|
||||||
|
if (this.props.iconUrl) {
|
||||||
|
attrs.url = this.props.iconUrl
|
||||||
|
} else if (this.props.iconName) {
|
||||||
|
attrs.name = this.props.iconName
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button className={className} onClick={this._onClick} title={title}>
|
||||||
|
<RetinaImg {...attrs} mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -32,6 +32,7 @@ class NylasComponentKit
|
||||||
@load "MultiselectActionBar", 'multiselect-action-bar'
|
@load "MultiselectActionBar", 'multiselect-action-bar'
|
||||||
@load "InjectedComponentSet", 'injected-component-set'
|
@load "InjectedComponentSet", 'injected-component-set'
|
||||||
@load "TimeoutTransitionGroup", 'timeout-transition-group'
|
@load "TimeoutTransitionGroup", 'timeout-transition-group'
|
||||||
|
@load "MetadataComposerToggleButton", 'metadata-composer-toggle-button'
|
||||||
@load "ConfigPropContainer", "config-prop-container"
|
@load "ConfigPropContainer", "config-prop-container"
|
||||||
@load "DisclosureTriangle", "disclosure-triangle"
|
@load "DisclosureTriangle", "disclosure-triangle"
|
||||||
@load "EditableList", "editable-list"
|
@load "EditableList", "editable-list"
|
||||||
|
|
Loading…
Reference in a new issue