Added basic handling for invalid plan amount (#1625)

refs https://github.com/TryGhost/Ghost/issues/11765

Adds handling to disallow plans of less than 1

Co-authored-by: Matt Hanley <3798302+matthanley@users.noreply.github.com>
This commit is contained in:
Fabien 'egg' O'Carroll 2020-07-03 10:36:59 +02:00 committed by GitHub
parent ba34621564
commit 7517373176
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 61 additions and 24 deletions

View File

@ -171,33 +171,38 @@
</div>
<div class="w-100 w-50-l flex flex-column flex-row-ns">
<div class="w-100 w-50-ns mr3-ns">
<GhFormGroup>
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{settings.hasValidated}} @property="stripePlans">
<label class="fw6 f8">Monthly price</label>
<div class="flex items-center justify-center mt1 gh-input-group gh-labs-price-label">
<GhTextInput
@value={{readonly this.stripePlans.monthly.amount}}
@type="number"
@input={{action "setStripePlan" "month"}}
@input={{action (mut this._scratchStripeMonthlyAmount) value="target.value"}}
@focus-out={{action "validateStripePlans"}}
/>
<span class="gh-input-append"><span class="ttu">{{this.stripePlans.monthly.currency}}</span>/month</span>
</div>
</GhFormGroup>
</div>
<div class="w-100 w-50-ns ml2-ns">
<GhFormGroup @class="description-container">
<GhFormGroup @errors={{this.settings.errors}} @hasValidated={{settings.hasValidated}} @property="stripePlans">
<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.stripePlans.yearly.amount}}
@type="number"
@input={{action "setStripePlan" "year"}}
@input={{action (mut this._scratchStripeYearlyAmount) value="target.value"}}
@focus-out={{action "validateStripePlans"}}
/>
<span class="gh-input-append"><span class="ttu">{{this.stripePlans.yearly.currency}}</span>/year</span>
</div>
</GhFormGroup>
</div>
</div>
<div class="w-100 w-50-l flex flex-column flex-row-ns">
<GhErrorMessage @errors={{settings.errors}} @property="stripePlans" class="w-100 red"/>
</div>
{{/liquid-if}}
</section>
@ -394,4 +399,4 @@
}}
@close={{action "closeMembersModalSettings"}}
@modifier="full-overlay portal-settings" />
{{/if}}
{{/if}}

View File

@ -10,22 +10,22 @@ const EU = {flag: '🇪🇺', name: 'EU', baseUrl: 'https://api.eu.mailgun.net/v
const CURRENCIES = [
{
label: 'USD - US Dollar', value: 'usd'
label: 'USD - US Dollar', value: 'usd', symbol: '$'
},
{
label: 'AUD - Australian Dollar', value: 'aud'
label: 'AUD - Australian Dollar', value: 'aud', symbol: '$'
},
{
label: 'CAD - Canadian Dollar', value: 'cad'
label: 'CAD - Canadian Dollar', value: 'cad', symbol: '$'
},
{
label: 'EUR - Euro', value: 'eur'
label: 'EUR - Euro', value: 'eur', symbol: '€'
},
{
label: 'GBP - British Pound', value: 'gbp'
label: 'GBP - British Pound', value: 'gbp', symbol: '£'
},
{
label: 'INR - Indian Rupee', value: 'inr'
label: 'INR - Indian Rupee', value: 'inr', symbol: '₹'
}
];
@ -40,6 +40,9 @@ export default Component.extend({
currencies: null,
showFromAddressConfirmation: false,
showMembersModalSettings: false,
stripePlanInvalidAmount: false,
_scratchStripeYearlyAmount: null,
_scratchStripeMonthlyAmount: null,
// passed in actions
setStripeConnectIntegrationTokenSetting() {},
@ -93,11 +96,11 @@ export default Component.extend({
return {
monthly: {
amount: parseInt(monthly.amount) / 100 || 0,
amount: parseInt(monthly.amount) / 100 || 5,
currency: monthly.currency
},
yearly: {
amount: parseInt(yearly.amount) / 100 || 0,
amount: parseInt(yearly.amount) / 100 || 50,
currency: yearly.currency
}
};
@ -166,18 +169,46 @@ export default Component.extend({
this.set('settings.stripeSecretKey', event.target.value);
},
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;
});
validateStripePlans() {
this.get('settings.errors').remove('stripePlans');
this.get('settings.hasValidated').removeObject('stripePlans');
this.set('settings.stripePlans', updatedPlans);
if (this._scratchStripeYearlyAmount === null) {
this._scratchStripeYearlyAmount = this.get('stripePlans').yearly.amount;
}
if (this._scratchStripeMonthlyAmount === null) {
this._scratchStripeMonthlyAmount = this.get('stripePlans').monthly.amount;
}
try {
const selectedCurrency = this.selectedCurrency;
const yearlyAmount = parseInt(this._scratchStripeYearlyAmount);
const monthlyAmount = parseInt(this._scratchStripeMonthlyAmount);
if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) {
throw new TypeError(`Subscription amount must be at least ${selectedCurrency.symbol}1.00`);
}
const updatedPlans = this.get('settings.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.set('settings.stripePlans', updatedPlans);
} catch (err) {
this.get('settings.errors').add('stripePlans', err.message);
} finally {
this.get('settings.hasValidated').pushObject('stripePlans');
}
},
setStripePlansCurrency(event) {

View File

@ -158,6 +158,7 @@ select {
.error .gh-select select,
.error .ember-power-select-multiple-trigger,
.gh-select.error,
.error .gh-input-append,
select.error {
border-color: var(--red);
}