diff --git a/extension/chrome/elements/subscribe.ts b/extension/chrome/elements/subscribe.ts
index 8e5cd63abdd..92261823a1c 100644
--- a/extension/chrome/elements/subscribe.ts
+++ b/extension/chrome/elements/subscribe.ts
@@ -9,40 +9,121 @@ import { Ui } from '../../js/common/browser/ui.js';
import { Lang } from '../../js/common/lang.js';
import { Api } from '../../js/common/api/api.js';
import { BrowserMsg, Bm } from '../../js/common/browser/browser-msg.js';
-import { Backend, ProductName, Product } from '../../js/common/api/backend.js';
+import { Backend, ProductName, Product, FcUuidAuth } from '../../js/common/api/backend.js';
import { Assert } from '../../js/common/assert.js';
import { XssSafeFactory } from '../../js/common/xss_safe_factory.js';
import { Xss } from '../../js/common/platform/xss.js';
import { Settings } from '../../js/common/settings.js';
+import { View } from '../../js/common/view.js';
-Catch.try(async () => {
+View.run(class SubscribeView extends View {
+ private readonly acctEmail: string;
+ private readonly parentTabId: string;
+ private readonly placement: string | undefined;
+ private authInfo: FcUuidAuth | undefined;
+ private tabId: string | undefined;
- Ui.event.protect();
-
- const uncheckedUrlParams = Url.parse(['acctEmail', 'placement', 'parentTabId']);
- const acctEmail = Assert.urlParamRequire.string(uncheckedUrlParams, 'acctEmail');
- const parentTabId = Assert.urlParamRequire.string(uncheckedUrlParams, 'parentTabId');
- const placement = Assert.urlParamRequire.oneof(uncheckedUrlParams, 'placement', ['settings', 'settings_compose', 'default', 'dialog', 'gmail', 'embedded', 'compose', undefined]);
-
- const authInfo = await Store.authInfo(acctEmail);
-
- const PRODUCTS: { [productName in ProductName]: Product } = {
+ private readonly PRODUCTS: { [productName in ProductName]: Product } = {
null: { id: null, method: null, name: null, level: null }, // tslint:disable-line:no-null-keyword
trial: { id: 'free_month', method: 'trial', name: 'trial', level: 'pro' },
advancedMonthly: { id: 'cu-adv-month', method: 'stripe', name: 'advanced_monthly', level: 'pro' },
};
- const stripeCcEnteredHandler: Bm.AsyncResponselessHandler = async ({ token }: Bm.StripeResult) => {
- $('.stripe_checkout').text('').css('display', 'none');
- await subscribeAndHandleResult(PRODUCTS.advancedMonthly, token);
- };
+ constructor() {
+ super();
+ const uncheckedUrlParams = Url.parse(['acctEmail', 'placement', 'parentTabId']);
+ this.acctEmail = Assert.urlParamRequire.string(uncheckedUrlParams, 'acctEmail');
+ this.parentTabId = Assert.urlParamRequire.string(uncheckedUrlParams, 'parentTabId');
+ this.placement = Assert.urlParamRequire.oneof(uncheckedUrlParams, 'placement', ['settings', 'settings_compose', 'default', 'dialog', 'gmail', 'embedded', 'compose', undefined]);
+ }
+
+ async render() {
+ Ui.event.protect();
+ if (this.placement === 'settings') {
+ $('#content').removeClass('dialog').css({ 'margin-top': 0, 'margin-bottom': 30 });
+ $('.line.button_padding').css('padding', 0);
+ } else {
+ $('body').css('overflow', 'hidden');
+ }
+ $('.list_table').css('display', 'block');
+ $('#content').css('display', 'block');
+ await this.renderSubscriptionDetails();
+ this.tabId = await BrowserMsg.requiredTabId();
+ $('.stripe_checkout')
+ .html(`${Lang.account.creditOrDebit}
${new XssSafeFactory(this.acctEmail, this.tabId).embeddedStripeCheckout()}
${Ui.retryLink('back')}`); // xss-safe-factory
+ }
+
+ setHandlers() {
+ $('.action_close').click(this.setHandler(() => this.closeDialog()));
+ $('.action_show_stripe').click(this.setHandler(() => this.showStripeHandler()));
+ $('.action_contact_page').click(this.setHandler(() => BrowserMsg.send.bg.settings({ page: '/chrome/settings/modules/contact_page.htm', acctEmail: this.acctEmail })));
+ $('.action_get_trial').click(this.setHandlerPrevent('parallel', async (target, done) => {
+ await this.subscribeAndHandleResult(this.PRODUCTS.trial, undefined);
+ done();
+ }));
+ BrowserMsg.addListener('stripe_result', (res) => this.stripeCcEnteredHandler(res as Bm.StripeResult));
+ BrowserMsg.listen(this.tabId!);
+ }
+
+ private async renderSubscriptionDetails() {
+ this.authInfo = await Store.authInfo(this.acctEmail);
+ try {
+ await Backend.accountGet(this.authInfo);
+ await Backend.getSubscriptionWithoutLogin(this.acctEmail);
+ } catch (e) {
+ if (Api.err.isAuthErr(e)) {
+ Xss.sanitizeRender('#content', `Not logged in. ${Ui.retryLink()}`);
+ Settings.offerToLoginWithPopupShowModalOnErr(this.acctEmail, () => window.location.reload());
+ } else if (Api.err.isNetErr(e)) {
+ Xss.sanitizeRender('#content', `Failed to load due to internet connection. ${Ui.retryLink()}`);
+ } else {
+ Catch.reportErr(e);
+ Xss.sanitizeRender('#content', `Unknown error happened when fetching account info. ${Ui.retryLink()}`);
+ }
+ }
+ const subscription = await Store.subscription(this.acctEmail); // updated in getSubscriptionWithoutLogin
+ if (!subscription.active) {
+ if (subscription.level && subscription.expire) {
+ if (subscription.method === 'trial') {
+ $('.status').text('Your trial has expired on ' + Str.datetimeToDate(subscription.expire) + '. Upgrade now to continue using FlowCrypt Advanced.');
+ } else if (subscription.method === 'group') {
+ $('.status').text('Your group licensing is due for renewal. Please check with company leadership.');
+ } else {
+ $('.status').text('Your subscription has ended on ' + subscription.expire + '. Renew now to continue using FlowCrypt Advanced.');
+ }
+ $('.action_get_trial').css('display', 'none');
+ $('.action_show_stripe').removeClass('gray').addClass('green');
+ } else {
+ $('.status').text('After the trial, your account will automatically switch to Free Forever.');
+ }
+ } else if (subscription.active && subscription.method === 'trial') {
+ Xss.sanitizeRender('.status',
+ 'After the trial, your account will automatically switch to Free Forever.
You can subscribe now to stay on FlowCrypt Advanced. It\'s $5 a month.');
+ }
+ if (subscription.active) {
+ if (subscription.method === 'trial') {
+ $('.list_table').css('display', 'none');
+ $('.action_get_trial').css('display', 'none');
+ $('.action_show_stripe').removeClass('gray').addClass('green');
+ } else {
+ Xss.sanitizeRender('#content', `