mirror of
https://github.com/TryGhost/Ghost-Admin.git
synced 2023-12-14 02:33:04 +01:00
Updated members lab settings design
no issue - Extracts members lab settings from `Beta Features` section to its own section - Adds new `fromAddress` field to members settings
This commit is contained in:
parent
47e125b3f1
commit
677de7f317
6 changed files with 252 additions and 177 deletions
107
app/components/gh-members-lab-setting.js
Normal file
107
app/components/gh-members-lab-setting.js
Normal file
|
@ -0,0 +1,107 @@
|
|||
import Component from '@ember/component';
|
||||
import {computed} from '@ember/object';
|
||||
import {inject as service} from '@ember/service';
|
||||
|
||||
export default Component.extend({
|
||||
feature: service(),
|
||||
config: service(),
|
||||
mediaQueries: service(),
|
||||
|
||||
subscriptionSettings: computed('settings.membersSubscriptionSettings', function () {
|
||||
let subscriptionSettings = this.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');
|
||||
monthlyPlan.dollarAmount = parseInt(monthlyPlan.amount) ? (monthlyPlan.amount / 100) : 0;
|
||||
yearlyPlan.dollarAmount = parseInt(yearlyPlan.amount) ? (yearlyPlan.amount / 100) : 0;
|
||||
stripeProcessor.config.plans = {
|
||||
monthly: monthlyPlan,
|
||||
yearly: yearlyPlan
|
||||
};
|
||||
subscriptionSettings.stripeConfig = stripeProcessor.config;
|
||||
subscriptionSettings.requirePaymentForSetup = !!subscriptionSettings.requirePaymentForSetup;
|
||||
subscriptionSettings.fromAddress = subscriptionSettings.fromAddress || 'noreply';
|
||||
return subscriptionSettings;
|
||||
}),
|
||||
|
||||
defaultContentVisibility: computed('settings.defaultContentVisibility', function () {
|
||||
return this.get('settings.defaultContentVisibility');
|
||||
}),
|
||||
|
||||
actions: {
|
||||
setDefaultContentVisibility(value) {
|
||||
this.setDefaultContentVisibility(value);
|
||||
},
|
||||
setSubscriptionSettings(key, event) {
|
||||
let subscriptionSettings = this.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')
|
||||
};
|
||||
// TODO: this flag has to be removed as it doesn't serve any purpose
|
||||
if (key === 'isPaid') {
|
||||
subscriptionSettings.isPaid = event;
|
||||
}
|
||||
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.amount = parseInt(event.target.value) ? (event.target.value * 100) : 0;
|
||||
}
|
||||
return plan;
|
||||
});
|
||||
}
|
||||
if (key === 'requirePaymentForSignup') {
|
||||
subscriptionSettings.requirePaymentForSignup = !subscriptionSettings.requirePaymentForSignup;
|
||||
}
|
||||
if (key === 'fromAddress') {
|
||||
subscriptionSettings.fromAddress = event.target.value;
|
||||
}
|
||||
this.setMembersSubscriptionSettings(subscriptionSettings);
|
||||
}
|
||||
},
|
||||
|
||||
parseSubscriptionSettings(settingsString) {
|
||||
try {
|
||||
return JSON.parse(settingsString);
|
||||
} catch (e) {
|
||||
return {
|
||||
isPaid: false,
|
||||
requirePaymentForSignup: false,
|
||||
fromAddress: 'noreply',
|
||||
paymentProcessors: [{
|
||||
adapter: 'stripe',
|
||||
config: {
|
||||
secret_token: '',
|
||||
public_token: '',
|
||||
product: {
|
||||
name: this.settings.get('title')
|
||||
},
|
||||
plans: [
|
||||
{
|
||||
name: 'Monthly',
|
||||
currency: 'usd',
|
||||
interval: 'month',
|
||||
amount: ''
|
||||
},
|
||||
{
|
||||
name: 'Yearly',
|
||||
currency: 'usd',
|
||||
interval: 'year',
|
||||
amount: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
});
|
|
@ -78,6 +78,7 @@ export default Controller.extend({
|
|||
};
|
||||
subscriptionSettings.stripeConfig = stripeProcessor.config;
|
||||
subscriptionSettings.requirePaymentForSetup = !!subscriptionSettings.requirePaymentForSetup;
|
||||
subscriptionSettings.fromAddress = subscriptionSettings.fromAddress || 'noreply';
|
||||
return subscriptionSettings;
|
||||
}),
|
||||
|
||||
|
@ -180,71 +181,11 @@ export default Controller.extend({
|
|||
this.set('settings.defaultContentVisibility', value);
|
||||
},
|
||||
|
||||
setSubscriptionSettings(key, event) {
|
||||
let subscriptionSettings = this.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')
|
||||
};
|
||||
// TODO: this flag has to be removed as it doesn't serve any purpose
|
||||
if (key === 'isPaid') {
|
||||
subscriptionSettings.isPaid = event;
|
||||
}
|
||||
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.amount = parseInt(event.target.value) ? (event.target.value * 100) : 0;
|
||||
}
|
||||
return plan;
|
||||
});
|
||||
}
|
||||
if (key === 'requirePaymentForSignup') {
|
||||
subscriptionSettings.requirePaymentForSignup = !subscriptionSettings.requirePaymentForSignup;
|
||||
}
|
||||
setMembersSubscriptionSettings(subscriptionSettings) {
|
||||
this.set('settings.membersSubscriptionSettings', JSON.stringify(subscriptionSettings));
|
||||
}
|
||||
},
|
||||
|
||||
parseSubscriptionSettings(settingsString) {
|
||||
try {
|
||||
return JSON.parse(settingsString);
|
||||
} catch (e) {
|
||||
return {
|
||||
isPaid: false,
|
||||
paymentProcessors: [{
|
||||
adapter: 'stripe',
|
||||
config: {
|
||||
secret_token: '',
|
||||
public_token: '',
|
||||
product: {
|
||||
name: this.settings.get('title')
|
||||
},
|
||||
plans: [
|
||||
{
|
||||
name: 'Monthly',
|
||||
currency: 'usd',
|
||||
interval: 'month',
|
||||
amount: ''
|
||||
},
|
||||
{
|
||||
name: 'Yearly',
|
||||
currency: 'usd',
|
||||
interval: 'year',
|
||||
amount: ''
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: convert to ember-concurrency task
|
||||
_validate(file) {
|
||||
// Windows doesn't have mime-types for json files by default, so we
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
margin: 0 50px 0 0;
|
||||
}
|
||||
|
||||
.gh-members-setting-content {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.gh-setting-content--no-action {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
106
app/templates/components/gh-members-lab-setting.hbs
Normal file
106
app/templates/components/gh-members-lab-setting.hbs
Normal file
|
@ -0,0 +1,106 @@
|
|||
<div class="flex flex-column b--whitegrey bt">
|
||||
<section class="flex flex-column bb b--whitegrey pa5">
|
||||
<div class="w-50 mb4">
|
||||
<label class="fw6 f6">Stripe publishable API key</label>
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.public_token)
|
||||
input=(action "setSubscriptionSettings" "public_token")
|
||||
class="mt1"
|
||||
}}
|
||||
</div>
|
||||
<div class="w-50 mb4">
|
||||
<label class="fw6 f6 mt4">Stripe secret API key</label>
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.secret_token)
|
||||
input=(action "setSubscriptionSettings" "secret_token")
|
||||
class="mt1"
|
||||
}}
|
||||
<a href="https://dashboard.stripe.com/account/apikeys" target="_blank" class="mt1 fw4 f8">
|
||||
Where to find Stripe API keys
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="w-50 flex nb5">
|
||||
<div class="w-50 mr3">
|
||||
{{#gh-form-group}}
|
||||
<label class="fw6 f6">Monthly price</label>
|
||||
<div class="mt1 relative gh-labs-price-label gh-labs-monthly-price">
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.plans.monthly.dollarAmount)
|
||||
type="number"
|
||||
input=(action "setSubscriptionSettings" "month")
|
||||
}}
|
||||
</div>
|
||||
{{/gh-form-group}}
|
||||
</div>
|
||||
<div class="w-50 ml2">
|
||||
{{#gh-form-group class="description-container"}}
|
||||
<label class="fw6 f6">Yearly price</label>
|
||||
<div class="mt1 relative gh-labs-price-label gh-labs-yearly-price">
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.plans.yearly.dollarAmount)
|
||||
type="number"
|
||||
input=(action "setSubscriptionSettings" "year")
|
||||
}}
|
||||
</div>
|
||||
{{/gh-form-group}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="flex flex-column bb b--whitegrey pa5">
|
||||
<label class="dib f6 fw6 mb4">Default post access</label>
|
||||
|
||||
<div class="gh-radio {{if (eq settings.defaultContentVisibility "public") "active"}}"
|
||||
{{action "setDefaultContentVisibility" "public" on="click"}}>
|
||||
<div class="gh-radio-button" data-test-publishmenu-unpublished-option></div>
|
||||
<div class="gh-radio-content">
|
||||
<div class="gh-radio-label">Public</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gh-radio {{if (eq settings.defaultContentVisibility "members") "active"}}"
|
||||
{{action "setDefaultContentVisibility" "members" on="click"}}>
|
||||
<div class="gh-radio-button" data-test-publishmenu-published-option></div>
|
||||
<div class="gh-radio-content">
|
||||
<div class="gh-radio-label">Members only</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gh-radio {{if (eq settings.defaultContentVisibility "paid") "active"}}"
|
||||
{{action "setDefaultContentVisibility" "paid" on="click"}}>
|
||||
<div class="gh-radio-button" data-test-publishmenu-published-option></div>
|
||||
<div class="gh-radio-content">
|
||||
<div class="gh-radio-label">Paid-members only</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="flex flex-column bb b--whitegrey pa5">
|
||||
<div class="for-checkbox">
|
||||
<label class="checkbox flex items-center" for="members-require-payment"
|
||||
{{action "setSubscriptionSettings" "requirePaymentForSignup" bubbles="false"}}>
|
||||
<span class="f6 fw6"> Require payment for signups</span>
|
||||
<input type="checkbox" checked={{subscriptionSettings.requirePaymentForSignup}} class="gh-input"
|
||||
onclick={{action "setSubscriptionSettings" "requirePaymentForSignup"}}
|
||||
data-test-checkbox="members-require-payment">
|
||||
<span class="input-toggle-component mt1"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-column pl5 pr5 pt5">
|
||||
<div class="w-50 mr3">
|
||||
{{#gh-form-group}}
|
||||
<label class="dib f6 fw6 mb4">Email</label>
|
||||
<div class="flex items-center justify-center">
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.fromAddress)
|
||||
input=(action "setSubscriptionSettings" "fromAddress")
|
||||
}}
|
||||
<span class="ml3"> @{{config.blogDomain}}</span>
|
||||
</div>
|
||||
<div class="f6 fw4"> "From" address for sending sign up and sign in emails</div>
|
||||
{{/gh-form-group}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -86,126 +86,42 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gh-setting-header">Members</div>
|
||||
<div class="flex flex-column br3 shadow-1 bg-grouped-table pa5 mt2">
|
||||
{{#if config.enableDeveloperExperiments}}
|
||||
<div class="gh-setting-first gh-setting-last">
|
||||
<div class="gh-setting-content">
|
||||
<div class="gh-setting-title">Members</div>
|
||||
<div class="gh-setting-desc">Enable free or paid member registration.</div>
|
||||
|
||||
{{#liquid-if feature.labs.members class="nr25"}}
|
||||
|
||||
<div class="flex ba br4 b--whitegrey pa5 pt4 mt5">
|
||||
<section class="flex flex-column">
|
||||
<label class="fw6 f8">Stripe publishable API key</label>
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.public_token)
|
||||
input=(action "setSubscriptionSettings" "public_token")
|
||||
class="mt1"
|
||||
}}
|
||||
|
||||
<label class="fw6 f8 mt4">Stripe secret API key</label>
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.secret_token)
|
||||
input=(action "setSubscriptionSettings" "secret_token")
|
||||
class="mt1"
|
||||
}}
|
||||
<a href="https://dashboard.stripe.com/account/apikeys" target="_blank" class="mt1 fw4 f8">Where to find Stripe
|
||||
API keys</a>
|
||||
|
||||
<div class="mt5 flex nb5">
|
||||
<div class="w-50 mr3">
|
||||
{{#gh-form-group}}
|
||||
<label class="fw6 f8">Monthly price</label>
|
||||
<div class="mt1 relative gh-labs-price-label gh-labs-monthly-price">
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.plans.monthly.dollarAmount)
|
||||
type="number"
|
||||
input=(action "setSubscriptionSettings" "month")
|
||||
}}
|
||||
</div>
|
||||
{{/gh-form-group}}
|
||||
</div>
|
||||
<div class="w-50 ml2">
|
||||
{{#gh-form-group class="description-container"}}
|
||||
<label class="fw6 f8">Yearly price</label>
|
||||
<div class="mt1 relative gh-labs-price-label gh-labs-yearly-price">
|
||||
{{gh-text-input
|
||||
value=(readonly subscriptionSettings.stripeConfig.plans.yearly.dollarAmount)
|
||||
type="number"
|
||||
input=(action "setSubscriptionSettings" "year")
|
||||
}}
|
||||
</div>
|
||||
{{/gh-form-group}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt5 flex nb5">
|
||||
{{#gh-form-group class="require-payment-container"}}
|
||||
<div class="form-group for-checkbox">
|
||||
<label class="checkbox" for="members-require-payment" {{action "setSubscriptionSettings" "requirePaymentForSignup" bubbles="false"}}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={{subscriptionSettings.requirePaymentForSignup}}
|
||||
class="gh-input"
|
||||
onclick={{action "setSubscriptionSettings" "requirePaymentForSignup"}}
|
||||
data-test-checkbox="members-require-payment"
|
||||
>
|
||||
<span class="input-toggle-component"></span>
|
||||
<p> Require payment before signing up members</p>
|
||||
</label>
|
||||
</div>
|
||||
{{/gh-form-group}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="gh-visibility-menu-content w-50 ml10">
|
||||
<label class="dib f8 fw6 mb4">Default post access</label>
|
||||
|
||||
<div class="gh-radio {{if (eq settings.defaultContentVisibility "public") "active"}}"
|
||||
{{action "setDefaultContentVisibility" "public" on="click"}}>
|
||||
<div class="gh-radio-button" data-test-publishmenu-unpublished-option></div>
|
||||
<div class="gh-radio-content">
|
||||
<div class="gh-radio-label">Public</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gh-radio {{if (eq settings.defaultContentVisibility "members") "active"}}"
|
||||
{{action "setDefaultContentVisibility" "members" on="click"}}>
|
||||
<div class="gh-radio-button" data-test-publishmenu-published-option></div>
|
||||
<div class="gh-radio-content">
|
||||
<div class="gh-radio-label">Members only</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gh-radio {{if (eq settings.defaultContentVisibility "paid") "active"}}"
|
||||
{{action "setDefaultContentVisibility" "paid" on="click"}}>
|
||||
<div class="gh-radio-button" data-test-publishmenu-published-option></div>
|
||||
<div class="gh-radio-content">
|
||||
<div class="gh-radio-label">Paid-members only</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{{#if config.enableDeveloperExperiments}}
|
||||
<div class="gh-setting-header">Members (BETA) </div>
|
||||
<div class="flex flex-column br3 shadow-1 bg-grouped-table mt2">
|
||||
<div class="gh-setting-first gh-setting-last">
|
||||
<div class="gh-members-setting-content">
|
||||
<div class="flex">
|
||||
<div class="flex flex-column flex-grow-1">
|
||||
<div class="gh-setting-title pl5 pt5">Members</div>
|
||||
<div class="gh-setting-desc pl5 pb5">Enable free or paid member registration.</div>
|
||||
</div>
|
||||
<div class="gh-setting-action">
|
||||
<div class="for-switch pa5">{{gh-feature-flag "members"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb2 mt5">
|
||||
{{gh-task-button "Save members settings"
|
||||
task=saveSettings
|
||||
successText="Saved"
|
||||
runningText="Saving"
|
||||
class="gh-btn gh-btn-blue gh-btn-icon"
|
||||
{{#liquid-if feature.labs.members}}
|
||||
{{gh-members-lab-setting
|
||||
settings=settings
|
||||
setDefaultContentVisibility=(action "setDefaultContentVisibility")
|
||||
setMembersSubscriptionSettings=(action "setMembersSubscriptionSettings")
|
||||
}}
|
||||
</div>
|
||||
|
||||
{{/liquid-if}}
|
||||
<div class="mb2 mt5 pl5 pr5 pb5">
|
||||
{{gh-task-button "Save members settings"
|
||||
task=saveSettings
|
||||
successText="Saved"
|
||||
runningText="Saving"
|
||||
class="gh-btn gh-btn-blue gh-btn-icon"
|
||||
}}
|
||||
</div>
|
||||
{{/liquid-if}}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="gh-setting-action">
|
||||
<div class="for-switch">{{gh-feature-flag "members"}}</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="gh-setting-header">Beta features</div>
|
||||
<div class="flex flex-column br3 shadow-1 bg-grouped-table pa5 mt2">
|
||||
|
|
|
@ -177,7 +177,7 @@ export default [
|
|||
id: 23,
|
||||
type: 'members',
|
||||
key: 'members_subscription_settings',
|
||||
value: '{"isPaid":false,"paymentProcessors":[{"adapter":"stripe","config":{"secret_token":"","public_token":"","product":{"name":"Ghost Subscription"},"plans":[{"name":"Monthly","currency":"usd","interval":"month","amount":""},{"name":"Yearly","currency":"usd","interval":"year","amount":""}]}}]}',
|
||||
value: '{"isPaid":false,"requirePaymentForSignup":false,"fromAddress":"noreply","paymentProcessors":[{"adapter":"stripe","config":{"secret_token":"","public_token":"","product":{"name":"Ghost Subscription"},"plans":[{"name":"Monthly","currency":"usd","interval":"month","amount":""},{"name":"Yearly","currency":"usd","interval":"year","amount":""}]}}]}',
|
||||
created_at: '2019-10-09T09:49:00.000Z',
|
||||
created_by: 1,
|
||||
updated_at: '2019-10-09T09:49:00.000Z',
|
||||
|
|
Loading…
Reference in a new issue