Skip to content
This repository has been archived by the owner on Nov 28, 2022. It is now read-only.

Commit

Permalink
Refactored to use updated members and stripe settings (#1621)
Browse files Browse the repository at this point in the history
refs #10318

* Updated settings model with new settings

* Removed parseSubscriptionSettings from settings service

* Updated members-utils to use new settings

* Updated labs controller to use new settings

* Fixed dependency for member-settings-form

* Updated members-lab-setting component to use new settings

* Updated disconnect modal to use new settings

* Updated members portal modal to use new settings

* Removed Direct from settings

* Renamed members_allow_signup -> members_allow_free_signup

* Allowed for null fromAddress
  • Loading branch information
allouis committed Jun 29, 2020
1 parent fa3dce7 commit eea4396
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 162 deletions.
2 changes: 1 addition & 1 deletion app/components/gh-member-settings-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export default Component.extend({

hasMultipleSubscriptions: gt('member.stripe', 1),

canShowStripeInfo: computed('member.isNew', 'settings.membersSubscriptionSettings', function () {
canShowStripeInfo: computed('member.isNew', 'membersUtils.isStripeEnabled', function () {
let stripeEnabled = this.membersUtils.isStripeEnabled;

if (this.member.get('isNew') || !stripeEnabled) {
Expand Down
39 changes: 19 additions & 20 deletions app/components/gh-members-lab-setting.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@
<label class="fw6 f8">Stripe Publishable key</label>
<GhTextInput
@type="password"
@value={{readonly this.subscriptionSettings.stripeConfig.public_token}}
@input={{action "setSubscriptionSettings" "public_token"}}
@value={{readonly this.stripeDirectPublicKey}}
@input={{action "setStripeDirectPublicKey"}}
@class="mt1 password"
/>
</div>
<div class="nudge-top--3">
<label class="fw6 f8 mt4">Stripe Secret key</label>
<GhTextInput
@type="password"
@value={{readonly this.subscriptionSettings.stripeConfig.secret_token}}
@input={{action "setSubscriptionSettings" "secret_token"}}
@value={{readonly this.stripeDirectSecretKey}}
@input={{action "setStripeDirectSecretKey"}}
@class="mt1 password"
/>
<a href="https://dashboard.stripe.com/account/apikeys" target="_blank" class="mt1 fw4 f8">
Expand Down Expand Up @@ -58,12 +58,12 @@
{{#if this.stripeConnectIntegration}}
<p class="gh-setting-desc pa0 ma0">
{{#if this.stripeConnectSuccess}}
{{svg-jar "check-circle" class="stroke-green w4 h4 nudge-top--3"}} <span class="green-d1">Successfully connected to {{this.stripeConnectIntegration.name}}</span>
{{svg-jar "check-circle" class="stroke-green w4 h4 nudge-top--3"}} <span class="green-d1">Successfully connected to {{this.stripeConnectAccountName}}</span>
{{else}}
Connected to <a href="https://dashboard.stripe.com/{{this.stripeConnectIntegration.id}}" target="_blank">{{this.stripeConnectIntegration.name}}</a>
Connected to <a href="https://dashboard.stripe.com/{{this.stripeConnectAccountId}}" target="_blank">{{this.stripeConnectAccountName}}</a>
{{/if}}

{{#unless this.stripeConnectIntegration.livemode}}
{{#unless this.stripeConnectLivemode}}
<span class="gh-members-connect-testmodelabel">Test mode</span>
{{/unless}}
</p>
Expand Down Expand Up @@ -106,7 +106,7 @@
<GhTextarea
@class="gh-members-stripe-connect-token"
@placeholder="Paste your secure key here"
@input={{action "setStripeConnectIntegrationToken" "stripe_connect_integration_token"}}
@input={{action "setStripeConnectIntegrationToken"}}
/>
{{#if this.stripeConnectError}}<p class="mb0 mt2 f8 red">{{this.stripeConnectError}}</p>{{/if}}
</div>
Expand Down Expand Up @@ -162,7 +162,7 @@
options=(readonly this.currencies)
optionValuePath="value"
optionLabelPath="label"
update=(action "setSubscriptionSettings" "currency")
update=(action "setStripePlansCurrency")
}}
{{svg-jar "arrow-down-small"}}
</span>
Expand All @@ -176,11 +176,11 @@

<div class="flex items-center justify-center mt1 gh-input-group gh-labs-price-label">
<GhTextInput
@value={{readonly this.subscriptionSettings.stripeConfig.plans.monthly.amount}}
@value={{readonly this.stripePlans.monthly.amount}}
@type="number"
@input={{action "setSubscriptionSettings" "month"}}
@input={{action "setStripePlan" "month"}}
/>
<span class="gh-input-append"><span class="ttu">{{this.subscriptionSettings.stripeConfig.plans.monthly.currency}}</span>/month</span>
<span class="gh-input-append"><span class="ttu">{{this.stripePlans.monthly.currency}}</span>/month</span>
</div>
</GhFormGroup>
</div>
Expand All @@ -189,11 +189,11 @@
<label class="fw6 f8">Yearly price</label>
<div class="flex items-center justify-center mt1 gh-input-group gh-labs-price-label">
<GhTextInput
@value={{readonly this.subscriptionSettings.stripeConfig.plans.yearly.amount}}
@value={{readonly this.stripePlans.yearly.amount}}
@type="number"
@input={{action "setSubscriptionSettings" "year"}}
@input={{action "setStripePlan" "year"}}
/>
<span class="gh-input-append"><span class="ttu">{{this.subscriptionSettings.stripeConfig.plans.yearly.currency}}</span>/year</span>
<span class="gh-input-append"><span class="ttu">{{this.stripePlans.yearly.currency}}</span>/year</span>
</div>
</GhFormGroup>
</div>
Expand All @@ -209,8 +209,8 @@
</div>
<div>
<div class="for-switch">
<label class="switch" for="members-allow-self-signup" {{action "setSubscriptionSettings" "allowSelfSignup" bubbles="false"}}>
<input type="checkbox" checked={{this.subscriptionSettings.allowSelfSignup}} class="gh-input" onclick={{action "setSubscriptionSettings" "allowSelfSignup"}} data-test-checkbox="members-allow-self-signup">
<label class="switch" for="members-allow-self-signup" {{action "toggleSelfSignup" bubbles="false"}}>
<input type="checkbox" checked={{this.allowSelfSignup}} class="gh-input" onclick={{action "toggleSelfSignup"}} data-test-checkbox="members-allow-self-signup">
<span class="input-toggle-component mt1"></span>
</label>
</div>
Expand Down Expand Up @@ -380,7 +380,7 @@
{{#if this.showDisconnectStripeConnectModal}}
<GhFullscreenModal @modal="disconnect-stripe"
@model={{hash
stripeConnectIntegration=this.stripeConnectIntegration
stripeConnectAccountName=this.stripeConnectAccountName
}}
@confirm={{action "disconnectStripeConnectIntegration"}}
@close={{action "closeDisconnectStripeModal"}}
Expand All @@ -390,8 +390,7 @@
{{#if this.showMembersModalSettings}}
<GhFullscreenModal @modal="members-modal-settings"
@model={{hash
subscriptionSettings=this.subscriptionSettings
stripeConnectIntegration=this.stripeConnectIntegration
allowSelfSignup=this.allowSelfSignup
}}
@close={{action "closeMembersModalSettings"}}
@modifier="full-overlay portal-settings" />
Expand Down
143 changes: 74 additions & 69 deletions app/components/gh-members-lab-setting.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,22 @@ export default Component.extend({
showMembersModalSettings: false,

// passed in actions
setMembersSubscriptionSettings() {},
setStripeConnectIntegrationTokenSetting() {},

defaultContentVisibility: reads('settings.defaultContentVisibility'),

stripeDirect: reads('config.stripeDirect'),

allowSelfSignup: reads('settings.membersAllowFreeSignup'),

/** OLD **/
stripeDirectPublicKey: reads('settings.stripePublishableKey'),
stripeDirectSecretKey: reads('settings.stripeSecretKey'),

stripeConnectAccountId: reads('settings.stripeConnectAccountId'),
stripeConnectAccountName: reads('settings.stripeConnectAccountName'),
stripeConnectLivemode: reads('settings.stripeConnectLivemode'),

stripeConnectIntegration: computed('settings.stripeConnectIntegration', function () {
try {
const integration = JSON.parse(this.get('settings.stripeConnectIntegration'));
Expand All @@ -66,13 +75,13 @@ export default Component.extend({
}
}),

selectedCurrency: computed('subscriptionSettings.stripeConfig.plans.monthly.currency', function () {
return CURRENCIES.findBy('value', this.get('subscriptionSettings.stripeConfig.plans.monthly.currency'));
selectedCurrency: computed('stripePlans.monthly.currency', function () {
return CURRENCIES.findBy('value', this.get('stripePlans.monthly.currency'));
}),

disableUpdateFromAddressButton: computed('fromAddress', function () {
const savedFromAddress = this.get('subscriptionSettings.fromAddress');
if (savedFromAddress.indexOf('@') < 0 && this.blogDomain) {
const savedFromAddress = this.get('settings.membersFromAddress') || '';
if (savedFromAddress.includes('@') && this.blogDomain) {
return (this.fromAddress === `${savedFromAddress}@${this.blogDomain}`);
}
return (this.fromAddress === savedFromAddress);
Expand All @@ -94,28 +103,21 @@ export default Component.extend({
});
}),

subscriptionSettings: computed('settings.membersSubscriptionSettings', function () {
let subscriptionSettings = this.settings.parseSubscriptionSettings(this.get('settings.membersSubscriptionSettings'));
let stripeProcessor = subscriptionSettings.paymentProcessors.find((proc) => {
return (proc.adapter === 'stripe');
});
let monthlyPlan = stripeProcessor.config.plans.find(plan => plan.interval === 'month');
let yearlyPlan = stripeProcessor.config.plans.find(plan => plan.interval === 'year' && plan.name !== 'Complimentary');

// NOTE: need to be careful about division by zero if we introduce zero decimal currencies
// ref.: https://stripe.com/docs/currencies#zero-decimal
monthlyPlan.amount = parseInt(monthlyPlan.amount) ? (monthlyPlan.amount / 100) : 0;
yearlyPlan.amount = parseInt(yearlyPlan.amount) ? (yearlyPlan.amount / 100) : 0;

stripeProcessor.config.plans = {
monthly: monthlyPlan,
yearly: yearlyPlan
stripePlans: computed('settings.stripePlans', function () {
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) / 100 || 0,
currency: monthly.currency
},
yearly: {
amount: parseInt(yearly.amount) / 100 || 0,
yearly: yearly.currency
}
};
subscriptionSettings.stripeConfig = stripeProcessor.config;
subscriptionSettings.allowSelfSignup = !!subscriptionSettings.allowSelfSignup;
subscriptionSettings.fromAddress = subscriptionSettings.fromAddress || '';

return subscriptionSettings;
}),

bulkEmailSettings: computed('settings.bulkEmailSettings', function () {
Expand Down Expand Up @@ -167,60 +169,63 @@ export default Component.extend({
this.setFromAddress(fromAddress);
},

setSubscriptionSettings(key, event) {
let subscriptionSettings = this.settings.parseSubscriptionSettings(this.get('settings.membersSubscriptionSettings'));
let stripeProcessor = subscriptionSettings.paymentProcessors.find((proc) => {
return (proc.adapter === 'stripe');
});
let stripeConfig = stripeProcessor.config;
stripeConfig.product = {
name: this.settings.get('title')
};
toggleSelfSignup() {
this.set('settings.membersAllowFreeSignup', !this.get('allowSelfSignup'));
},

if (key === 'secret_token' || key === 'public_token') {
stripeConfig[key] = event.target.value;
}
if (key === 'month' || key === 'year') {
stripeConfig.plans = stripeConfig.plans.map((plan) => {
if (key === plan.interval && plan.name !== 'Complimentary') {
plan.amount = parseInt(event.target.value) ? (event.target.value * 100) : 0;
}
return plan;
});
}
if (key === 'allowSelfSignup') {
subscriptionSettings.allowSelfSignup = !subscriptionSettings.allowSelfSignup;
}
setStripeDirectPublicKey(event) {
this.set('settings.stripeProductName', this.get('settings.title'));
this.set('settings.stripePublishableKey', event.target.value);
},

if (key === 'currency') {
stripeProcessor.config.plans.forEach((plan) => {
if (plan.name !== 'Complimentary') {
plan.currency = event.value;
}
});
setStripeDirectSecretKey(event) {
this.set('settings.stripeProductName', this.get('settings.title'));
this.set('settings.stripeSecretKey', event.target.value);
},

// NOTE: need to keep Complimentary plans with all available currencies so they don't conflict
// when applied to members with existing subscriptions in different currencies (ref. https://stripe.com/docs/billing/customer#currency)
let currentCurrencyComplimentary = stripeProcessor.config.plans.filter(plan => (plan.currency === event.value && plan.name === 'Complimentary'));
setStripePlan(type, event) {
const updatedPlans = this.get('settings.stripePlans').map((plan) => {
if (plan.interval === type && plan.name !== 'Complimentary') {
const newAmount = parseInt(event.target.value) * 100 || 0;
return Object.assign({}, plan, {
amount: newAmount
});
}
return plan;
});

if (!currentCurrencyComplimentary.length) {
let complimentary = {
name: 'Complimentary',
currency: event.value,
interval: 'year',
amount: '0'
};
this.set('settings.stripePlans', updatedPlans);
},

stripeProcessor.config.plans.push(complimentary);
setStripePlansCurrency(event) {
const newCurrency = event.value;
const updatedPlans = this.get('settings.stripePlans').map((plan) => {
if (plan.name !== 'Complimentary') {
return Object.assign({}, plan, {
currency: newCurrency
});
}
return plan;
});

stripeProcessor.config.currency = event.value;
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.setMembersSubscriptionSettings(subscriptionSettings);
this.set('settings.stripePlans', updatedPlans);
},

setStripeConnectIntegrationToken(key, event) {
setStripeConnectIntegrationToken(event) {
this.set('settings.stripeProductName', this.get('settings.title'));
this.setStripeConnectIntegrationTokenSetting(event.target.value);
},

Expand Down
2 changes: 1 addition & 1 deletion app/components/modal-disconnect-stripe.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<a class="close" href="" role="button" title="Close" {{action "closeModal"}}>{{svg-jar "close"}}<span class="hidden">Close</span></a>

<div class="modal-body">
You're about to disconnect your Stripe account ({{this.stripeConnectIntegration.name}}) from this site. This will automatically turn off paid memberships on this site.
You're about to disconnect your Stripe account ({{this.stripeConnectAccountName}}) from this site. This will automatically turn off paid memberships on this site.
</div>

<div class="modal-footer">
Expand Down
2 changes: 1 addition & 1 deletion app/components/modal-disconnect-stripe.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export default ModalComponent.extend({
// Allowed actions
confirm: () => {},

stripeConnectIntegration: alias('model.stripeConnectIntegration'),
stripeConnectAccountName: alias('model.stripeConnectAccountName'),

actions: {
confirm() {
Expand Down
20 changes: 8 additions & 12 deletions app/components/modal-members-modal-settings.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import ModalComponent from 'ghost-admin/components/modal-base';
import {alias} from '@ember/object/computed';
import {alias, reads} from '@ember/object/computed';
import {computed} from '@ember/object';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';

export default ModalComponent.extend({
settings: service(),
membersUtils: service(),
config: service(),
page: 'signup',

confirm() {},
subscriptionSettings: alias('model.subscriptionSettings'),
stripeConnectIntegration: alias('model.stripeConnectIntegration'),

allowSelfSignup: alias('model.allowSelfSignup'),

isStripeConfigured: reads('membersUtils.isStripeEnabled'),

portalPreviewUrl: computed('page', 'isFreeChecked', 'isMonthlyChecked', 'isYearlyChecked', 'settings.{portalName,portalButton}', function () {
const baseUrl = this.config.get('blogUrl');
Expand All @@ -26,16 +29,9 @@ export default ModalComponent.extend({
return `${baseUrl}${portalBase}?${settingsParam.toString()}`;
}),

isFreeChecked: computed('settings.{portalPlans.[],membersSubscriptionSettings}', function () {
const allowSelfSignup = this.subscriptionSettings.allowSelfSignup;
isFreeChecked: computed('settings.portalPlans.[]', 'allowSelfSignup', function () {
const allowedPlans = this.settings.get('portalPlans') || [];
return (allowSelfSignup && allowedPlans.includes('free'));
}),

isStripeConfigured: computed('settings.{stripeConnectIntegration,membersSubscriptionSettings}', function () {
const stripeConfig = this.subscriptionSettings.stripeConfig;
const stripeIntegration = this.stripeConnectIntegration;
return (!!stripeConfig.public_token && !!stripeConfig.secret_token) || stripeIntegration;
return (this.allowSelfSignup && allowedPlans.includes('free'));
}),

isMonthlyChecked: computed('settings.portalPlans.[]', 'isStripeConfigured', function () {
Expand Down
Loading

0 comments on commit eea4396

Please sign in to comment.