feat(tracking): sticky tracking state and consolidate component

This commit is contained in:
Evan Morikawa 2016-02-24 14:45:47 -08:00
parent bb321f4bd2
commit 1c5869c867
4 changed files with 160 additions and 90 deletions

View file

@ -1,8 +1,8 @@
import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
import {RetinaImg} from 'nylas-component-kit'
// import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
import {React} from 'nylas-exports'
import {MetadataComposerToggleButton} from 'nylas-component-kit'
import {PLUGIN_ID, PLUGIN_NAME} from './link-tracking-constants'
export default class LinkTrackingButton extends React.Component {
static displayName = 'LinkTrackingButton';
@ -10,55 +10,26 @@ export default class LinkTrackingButton extends React.Component {
draftClientId: React.PropTypes.string.isRequired,
};
constructor(props) {
super(props);
this.state = {enabled: false};
_title(enabled) {
const dir = enabled ? "Disable" : "Enable";
return `${dir} link tracking`
}
componentDidMount() {
const query = DatabaseStore.findBy(Message, {clientId: this.props.draftClientId});
this._subscription = Rx.Observable.fromQuery(query).subscribe(this.setStateFromDraft);
_errorMessage(error) {
return `Sorry, we were unable to save your link tracking settings. ${error.message}`
}
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() {
const title = this.state.enabled ? "Disable" : "Enable"
return (
<button
title={`${title} link tracking`}
className={`btn btn-toolbar ${this.state.enabled ? "btn-enabled" : ""}`}
onClick={this._onClick}>
<RetinaImg
name="icon-composer-linktracking.png"
mode={RetinaImg.Mode.ContentIsMask} />
</button>
<MetadataComposerToggleButton
title={this._title}
iconName="icon-composer-linktracking.png"
pluginId={PLUGIN_ID}
pluginName={PLUGIN_NAME}
metadataKey="tracked"
stickyToggle
errorMessage={this._errorMessage}
draftClientId={this.props.draftClientId} />
)
}
}

View file

@ -1,60 +1,35 @@
import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
import {RetinaImg} from 'nylas-component-kit'
// import {DraftStore, React, Actions, NylasAPI, DatabaseStore, Message, Rx} from 'nylas-exports'
import {React} from 'nylas-exports'
import {MetadataComposerToggleButton} from 'nylas-component-kit'
import {PLUGIN_ID, PLUGIN_NAME} from './open-tracking-constants'
export default class OpenTrackingButton extends React.Component {
static displayName = 'OpenTrackingButton';
static propTypes = {
draftClientId: React.PropTypes.string.isRequired,
};
constructor(props) {
super(props);
this.state = {enabled: false};
_title(enabled) {
const dir = enabled ? "Disable" : "Enable";
return `${dir} read receipts`
}
componentDidMount() {
const query = DatabaseStore.findBy(Message, {clientId: this.props.draftClientId});
this._subscription = Rx.Observable.fromQuery(query).subscribe(this.setStateFromDraft)
_errorMessage(error) {
return `Sorry, we were unable to save your read receipt settings. ${error.message}`
}
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() {
const title = this.state.enabled ? "Disable" : "Enable";
return (<button className={`btn btn-toolbar ${this.state.enabled ? "btn-enabled" : ""}`}
onClick={this._onClick} title={`${title} read receipts`}>
<RetinaImg url="nylas://open-tracking/assets/icon-composer-eye@2x.png"
mode={RetinaImg.Mode.ContentIsMask} />
</button>)
return (
<MetadataComposerToggleButton
title={this._title}
iconUrl="nylas://open-tracking/assets/icon-composer-eye@2x.png"
pluginId={PLUGIN_ID}
pluginName={PLUGIN_NAME}
metadataKey="tracked"
stickyToggle
errorMessage={this._errorMessage}
draftClientId={this.props.draftClientId} />
)
}
}

View 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>
);
}
}

View file

@ -32,6 +32,7 @@ class NylasComponentKit
@load "MultiselectActionBar", 'multiselect-action-bar'
@load "InjectedComponentSet", 'injected-component-set'
@load "TimeoutTransitionGroup", 'timeout-transition-group'
@load "MetadataComposerToggleButton", 'metadata-composer-toggle-button'
@load "ConfigPropContainer", "config-prop-container"
@load "DisclosureTriangle", "disclosure-triangle"
@load "EditableList", "editable-list"