From f6a82b0099bf4058b0caaafc69432b68fdda3a5a Mon Sep 17 00:00:00 2001 From: Kevin Ansfield Date: Wed, 20 Jan 2021 15:49:14 +0000 Subject: [PATCH] Added pricing setup to launch site wizard refs https://github.com/TryGhost/Team/issues/450 - duplicated and refactored/updated members pricing settings UI from labs to the "set pricing" step of the launch site wizard --- .../gh-launch-wizard/set-pricing.hbs | 83 +++++++++++- .../gh-launch-wizard/set-pricing.js | 126 ++++++++++++++++++ .../app/components/gh-members-lab-setting.js | 2 +- 3 files changed, 209 insertions(+), 2 deletions(-) diff --git a/ghost/admin/app/components/gh-launch-wizard/set-pricing.hbs b/ghost/admin/app/components/gh-launch-wizard/set-pricing.hbs index bbe3f5123f..3b499ff1bb 100644 --- a/ghost/admin/app/components/gh-launch-wizard/set-pricing.hbs +++ b/ghost/admin/app/components/gh-launch-wizard/set-pricing.hbs @@ -1,2 +1,83 @@

Set subscription pricing

- \ No newline at end of file + +
+
+
+
+ + + + + {{svg-jar "arrow-down-small"}} + + +
+
+
+
+ + + +
+ + {{this.stripePlans.monthly.currency}}/month +
+
+
+
+ + +
+ + {{this.stripePlans.yearly.currency}}/year +
+
+
+
+
+ +
+ +
+
+

Allow free member signup

+

If disabled, members can only be signed up via payment checkout or API integration

+
+
+
+ +
+
+
+
+
+ +{{!-- TODO: reset "failed" state automatically --}} + \ No newline at end of file diff --git a/ghost/admin/app/components/gh-launch-wizard/set-pricing.js b/ghost/admin/app/components/gh-launch-wizard/set-pricing.js index 482c3c4a8f..37a3392b34 100644 --- a/ghost/admin/app/components/gh-launch-wizard/set-pricing.js +++ b/ghost/admin/app/components/gh-launch-wizard/set-pricing.js @@ -1,4 +1,130 @@ import Component from '@glimmer/component'; +import {CURRENCIES} from 'ghost-admin/components/gh-members-lab-setting'; +import {action} from '@ember/object'; +import {inject as service} from '@ember/service'; +import {task} from 'ember-concurrency-decorators'; +import {tracked} from '@glimmer/tracking'; export default class GhLaunchWizardSetPricingComponent extends Component { + @service settings; + + currencies = CURRENCIES; + + @tracked stripeMonthlyAmount = null; + @tracked stripeYearlyAmount = null; + + get stripePlans() { + const plans = this.settings.get('stripePlans') || []; + const monthly = plans.find(plan => plan.interval === 'month'); + const yearly = plans.find(plan => plan.interval === 'year' && plan.name !== 'Complimentary'); + + return { + monthly: { + amount: (parseInt(monthly?.amount) || 0) / 100 || 5, + currency: monthly?.currency || this.currencies[0].value + }, + yearly: { + amount: (parseInt(yearly?.amount) || 0) / 100 || 50, + currency: yearly?.currency || this.currencies[0].value + } + }; + } + + get selectedCurrency() { + return this.currencies.findBy('value', this.stripePlans.monthly.currency); + } + + willDestroy() { + // clear any unsaved settings changes when going back/forward/closing + this.settings.rollbackAttributes(); + } + + @action + setStripePlansCurrency(event) { + const newCurrency = event.value; + + const updatedPlans = this.settings.get('stripePlans').map((plan) => { + if (plan.name !== 'Complimentary') { + return Object.assign({}, plan, { + currency: newCurrency + }); + } + return plan; + }); + + const currentComplimentaryPlan = updatedPlans.find((plan) => { + return plan.name === 'Complimentary' && plan.currency === event.value; + }); + + if (!currentComplimentaryPlan) { + updatedPlans.push({ + name: 'Complimentary', + currency: event.value, + interval: 'year', + amount: 0 + }); + } + + this.settings.set('stripePlans', updatedPlans); + } + + @action + toggleSelfSignup() { + this.settings.set('membersAllowFreeSignup', !this.settings.get('membersAllowFreeSignup')); + } + + @action + validateStripePlans() { + this.settings.errors.remove('stripePlans'); + this.settings.hasValidated.removeObject('stripePlans'); + + if (this.stripeYearlyAmount === null) { + this.stripeYearlyAmount = this.stripePlans.yearly.amount; + } + if (this.stripeMonthlyAmount === null) { + this.stripeMonthlyAmount = this.stripePlans.monthly.amount; + } + + try { + const selectedCurrency = this.selectedCurrency; + const yearlyAmount = parseInt(this.stripeYearlyAmount); + const monthlyAmount = parseInt(this.stripeMonthlyAmount); + if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) { + throw new TypeError(`Subscription amount must be at least ${selectedCurrency.symbol}1.00`); + } + + const updatedPlans = this.settings.get('stripePlans').map((plan) => { + if (plan.name !== 'Complimentary') { + let newAmount; + if (plan.interval === 'year') { + newAmount = yearlyAmount * 100; + } else if (plan.interval === 'month') { + newAmount = monthlyAmount * 100; + } + return Object.assign({}, plan, { + amount: newAmount + }); + } + return plan; + }); + + this.settings.set('stripePlans', updatedPlans); + } catch (err) { + this.settings.errors.add('stripePlans', err.message); + } finally { + this.settings.hasValidated.pushObject('stripePlans'); + } + } + + @task + *saveAndContinue() { + yield this.validateStripePlans(); + + if (this.settings.errors.length > 0) { + return false; + } + + yield this.settings.save(); + this.args.afterComplete(); + } } diff --git a/ghost/admin/app/components/gh-members-lab-setting.js b/ghost/admin/app/components/gh-members-lab-setting.js index 6c6ccda443..a7e4f5bf1a 100644 --- a/ghost/admin/app/components/gh-members-lab-setting.js +++ b/ghost/admin/app/components/gh-members-lab-setting.js @@ -7,7 +7,7 @@ import {task} from 'ember-concurrency'; const US = {flag: 'πŸ‡ΊπŸ‡Έ', name: 'US', baseUrl: 'https://api.mailgun.net/v3'}; const EU = {flag: 'πŸ‡ͺπŸ‡Ί', name: 'EU', baseUrl: 'https://api.eu.mailgun.net/v3'}; -const CURRENCIES = [ +export const CURRENCIES = [ { label: 'USD - US Dollar', value: 'usd', symbol: '$' },