mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-25 09:46:07 +08:00
e638e94084
Summary: This is a WIP Depends on D3799 on billing.nylas.com This adds a `FeatureUsageStore` which determines whether a feature can be used or not. It also allows us to record "using" a feature. Feature Usage is ultimately backed by the Nylas Identity and cached locally in the Identity object. Since feature usage is attached to the Nylas Identity, we move the whole Identity object (except for the ID) to the database. This includes a migration (with tests!) to move the Nylas Identity from the config into the Database. We still, however, need the Nylas ID to stay in the config so it can be synchronously accessed by the /browser process on bootup when determining what windows to show. It's also convenient to know what the Nylas ID is by looking at the config. There's logic (with tests!) to make sure these stay in sync. If you delete the Nylas ID from the config, it'll be the same as logging you out. The schema for the feature usage can be found in more detail on D3799. By the time it reaches Nylas Mail, the Nylas ID object has a `feature_usage` attribute that has each feature (keyed by the feature name) and information about the plans attached to it. The schema Nylas Mail sees looks like: ``` "feature_usage": { "snooze": { quota: 10, peroid: 'monthly', used_in_period: 8, feature_limit_name: 'Snooze Group A', }, } ``` See D3799 for more info about how these are generated. One final change that's in here is how Stores are loaded. Most of our core stores are loaded at require time, but now things like the IdentityStore need to do asynchronous things on activation. In reality most of our stores do this and it's a miracle it hasn't caused more problems! Now when stores activate we optionally look for an `activate` method and `await` for it. This was necessary so downstream classes (like the Onboarding Store), see a fully initialized IdentityStore by the time it's time to use them Test Plan: New tests! Reviewers: khamidou, juan, halla Reviewed By: juan Differential Revision: https://phab.nylas.com/D3808
204 lines
6.3 KiB
JavaScript
204 lines
6.3 KiB
JavaScript
import {AccountStore, Actions, IdentityStore, NylasSyncStatusStore} from 'nylas-exports';
|
|
import {ipcRenderer} from 'electron';
|
|
import NylasStore from 'nylas-store';
|
|
|
|
import OnboardingActions from './onboarding-actions';
|
|
|
|
function accountTypeForProvider(provider) {
|
|
if (provider === 'eas') {
|
|
return 'exchange';
|
|
}
|
|
if (provider === 'custom') {
|
|
return 'imap';
|
|
}
|
|
return provider;
|
|
}
|
|
|
|
class OnboardingStore extends NylasStore {
|
|
constructor() {
|
|
super();
|
|
|
|
NylasEnv.config.onDidChange('env', this._onEnvChanged);
|
|
this._onEnvChanged();
|
|
|
|
this.listenTo(OnboardingActions.moveToPreviousPage, this._onMoveToPreviousPage)
|
|
this.listenTo(OnboardingActions.moveToPage, this._onMoveToPage)
|
|
this.listenTo(OnboardingActions.accountJSONReceived, this._onAccountJSONReceived)
|
|
this.listenTo(OnboardingActions.authenticationJSONReceived, this._onAuthenticationJSONReceived)
|
|
this.listenTo(OnboardingActions.setAccountInfo, this._onSetAccountInfo);
|
|
this.listenTo(OnboardingActions.setAccountType, this._onSetAccountType);
|
|
ipcRenderer.on('set-account-type', (e, type) => {
|
|
if (type) {
|
|
this._onSetAccountType(type)
|
|
} else {
|
|
this._pageStack = ['account-choose']
|
|
this.trigger()
|
|
}
|
|
})
|
|
|
|
const {existingAccount, addingAccount, accountType} = NylasEnv.getWindowProps();
|
|
|
|
const hasAccounts = (AccountStore.accounts().length > 0)
|
|
const identity = IdentityStore.identity();
|
|
|
|
if (identity) {
|
|
this._accountInfo = {
|
|
name: `${identity.firstname || ""} ${identity.lastname || ""}`,
|
|
};
|
|
} else {
|
|
this._accountInfo = {};
|
|
}
|
|
|
|
if (existingAccount) {
|
|
// Used when re-adding an account after re-connecting
|
|
const existingAccountType = accountTypeForProvider(existingAccount.provider);
|
|
this._pageStack = ['account-choose']
|
|
this._accountInfo = {
|
|
name: existingAccount.name,
|
|
email: existingAccount.emailAddress,
|
|
};
|
|
this._onSetAccountType(existingAccountType);
|
|
} else if (addingAccount) {
|
|
// Adding a new, unknown account
|
|
this._pageStack = ['account-choose'];
|
|
if (accountType) {
|
|
this._onSetAccountType(accountType);
|
|
}
|
|
} else if (identity) {
|
|
// Should only happen if config was edited to remove all accounts,
|
|
// but don't want to re-login to Nylas account. Very useful when
|
|
// switching environments.
|
|
this._pageStack = ['account-choose'];
|
|
} else if (hasAccounts) {
|
|
// Should only happen when the user has "signed out" of their Nylas ID,
|
|
// but already has accounts synced. Or is upgrading from a very old build.
|
|
// We used to show "Welcome Back", but now just jump to sign in.
|
|
this._pageStack = ['authenticate'];
|
|
} else {
|
|
// Standard new user onboarding flow.
|
|
this._pageStack = ['welcome'];
|
|
}
|
|
}
|
|
|
|
_onEnvChanged = () => {
|
|
const env = NylasEnv.config.get('env')
|
|
if (['development', 'local'].includes(env)) {
|
|
this.welcomeRoot = "http://0.0.0.0:5555";
|
|
} else if (env === 'experimental') {
|
|
this.welcomeRoot = "https://www-experimental.nylas.com";
|
|
} else if (env === 'staging') {
|
|
this.welcomeRoot = "https://www-staging.nylas.com";
|
|
} else {
|
|
this.welcomeRoot = "https://nylas.com";
|
|
}
|
|
}
|
|
|
|
_onOnboardingComplete = () => {
|
|
// When account JSON is received, we want to notify external services
|
|
// that it succeeded. Unfortunately in this case we're likely to
|
|
// close the window before those requests can be made. We add a short
|
|
// delay here to ensure that any pending requests have a chance to
|
|
// clear before the window closes.
|
|
setTimeout(() => {
|
|
ipcRenderer.send('account-setup-successful');
|
|
}, 100);
|
|
}
|
|
|
|
_onSetAccountType = (type) => {
|
|
let nextPage = "account-settings";
|
|
if (type === 'gmail') {
|
|
nextPage = "account-settings-gmail";
|
|
} else if (type === 'exchange') {
|
|
nextPage = "account-settings-exchange";
|
|
}
|
|
|
|
Actions.recordUserEvent('Selected Account Type', {
|
|
provider: type,
|
|
});
|
|
|
|
// Don't carry over any type-specific account information
|
|
const {email, name, password} = this._accountInfo;
|
|
this._onSetAccountInfo({email, name, password, type});
|
|
this._onMoveToPage(nextPage);
|
|
}
|
|
|
|
_onSetAccountInfo = (info) => {
|
|
this._accountInfo = info;
|
|
this.trigger();
|
|
}
|
|
|
|
_onMoveToPreviousPage = () => {
|
|
this._pageStack.pop();
|
|
this.trigger();
|
|
}
|
|
|
|
_onMoveToPage = (page) => {
|
|
this._pageStack.push(page)
|
|
this.trigger();
|
|
}
|
|
|
|
_onAuthenticationJSONReceived = async (json) => {
|
|
const isFirstAccount = AccountStore.accounts().length === 0;
|
|
|
|
await IdentityStore.saveIdentity(json);
|
|
|
|
setTimeout(() => {
|
|
if (isFirstAccount) {
|
|
this._onSetAccountInfo(Object.assign({}, this._accountInfo, {
|
|
name: `${json.firstname || ""} ${json.lastname || ""}`,
|
|
email: json.email,
|
|
}));
|
|
OnboardingActions.moveToPage('account-choose');
|
|
} else {
|
|
this._onOnboardingComplete();
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
_onAccountJSONReceived = async (json, localToken, cloudToken) => {
|
|
try {
|
|
const isFirstAccount = AccountStore.accounts().length === 0;
|
|
|
|
AccountStore.addAccountFromJSON(json, localToken, cloudToken);
|
|
this._accountFromAuth = AccountStore.accountForEmail(json.email_address);
|
|
|
|
Actions.recordUserEvent('Email Account Auth Succeeded', {
|
|
provider: this._accountFromAuth.provider,
|
|
});
|
|
ipcRenderer.send('new-account-added');
|
|
NylasEnv.displayWindow();
|
|
|
|
if (isFirstAccount) {
|
|
this._onMoveToPage('initial-preferences');
|
|
Actions.recordUserEvent('First Account Linked', {
|
|
provider: this._accountFromAuth.provider,
|
|
});
|
|
} else {
|
|
await NylasSyncStatusStore.whenCategoryListSynced(json.id)
|
|
this._onOnboardingComplete();
|
|
}
|
|
} catch (e) {
|
|
NylasEnv.reportError(e);
|
|
NylasEnv.showErrorDialog("Unable to Connect Account", "Sorry, something went wrong on the Nylas server. Please try again. If you're still having issues, contact us at support@nylas.com.");
|
|
}
|
|
}
|
|
|
|
page() {
|
|
return this._pageStack[this._pageStack.length - 1];
|
|
}
|
|
|
|
pageDepth() {
|
|
return this._pageStack.length;
|
|
}
|
|
|
|
accountInfo() {
|
|
return this._accountInfo;
|
|
}
|
|
|
|
accountFromAuth() {
|
|
return this._accountFromAuth;
|
|
}
|
|
}
|
|
|
|
export default new OnboardingStore();
|