0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-24 23:48:13 -05:00

Added error handling for price modal

refs https://github.com/TryGhost/Team/issues/678

Covers error handling for missing name/amount/billing period for a price modal when adding a new price or editing existing price.
This commit is contained in:
Rishabh 2021-05-10 20:59:05 +05:30
parent 42463e4fdd
commit d3efc29f08
3 changed files with 52 additions and 26 deletions

View file

@ -9,7 +9,7 @@
<div class="modal-body"> <div class="modal-body">
<div class="gh-main-section-block"> <div class="gh-main-section-block">
<div class="gh-main-section-content grey gh-product-priceform-block"> <div class="gh-main-section-content grey gh-product-priceform-block">
<GhFormGroup @errors={{this.price.errors}} @hasValidated={{this.price.hasValidated}} @property="name"> <GhFormGroup @errors={{this.errors}} @property="name">
<label for="name" class="fw6">Name</label> <label for="name" class="fw6">Name</label>
<GhTextInput <GhTextInput
@value={{readonly this.price.nickname}} @value={{readonly this.price.nickname}}
@ -17,9 +17,9 @@
@name="name" @name="name"
@id="name" @id="name"
@class="gh-input" /> @class="gh-input" />
<GhErrorMessage @errors={{this.price.errors}} @property="name" /> <GhErrorMessage @errors={{this.errors}} @property="name" />
</GhFormGroup> </GhFormGroup>
<GhFormGroup @errors={{this.price.errors}} @hasValidated={{this.price.hasValidated}} @property="description"> <GhFormGroup @errors={{this.errors}} @property="description">
<label for="description" class="fw6">Description</label> <label for="description" class="fw6">Description</label>
<GhTextInput <GhTextInput
@value={{readonly this.price.description}} @value={{readonly this.price.description}}
@ -27,20 +27,21 @@
@name="description" @name="description"
@id="description" @id="description"
@class="gh-input" /> @class="gh-input" />
<GhErrorMessage @errors={{this.price.errors}} @property="description" /> <GhErrorMessage @errors={{this.errors}} @property="description" />
</GhFormGroup> </GhFormGroup>
<div class="gh-product-priceform-pricecurrency"> <div class="gh-product-priceform-pricecurrency">
<GhFormGroup @errors={{this.price.errors}} @hasValidated={{this.price.hasValidated}} @property="price"> <GhFormGroup @errors={{this.errors}} @property="amount">
<label for="price" class="fw6">Price</label> <label for="amount" class="fw6">Price</label>
<div class="flex items-center justify-center gh-labs-price-label"> <div class="flex items-center justify-center gh-labs-price-label">
<GhTextInput <GhTextInput
@id="amount"
@value={{this.price.amount}} @value={{this.price.amount}}
@type="number" @type="number"
@disabled={{this.isExistingPrice}} @disabled={{this.isExistingPrice}}
@input={{action "setAmount" value="target.value"}} @input={{action "setAmount" value="target.value"}}
/> />
</div> </div>
<GhErrorMessage @errors={{this.price.errors}} @property="price" /> <GhErrorMessage @errors={{this.errors}} @property="amount" />
</GhFormGroup> </GhFormGroup>
<GhFormGroup @class="for-select"> <GhFormGroup @class="for-select">
<label class="fw6 f8"for="currency">Plan currency</label> <label class="fw6 f8"for="currency">Plan currency</label>
@ -65,6 +66,7 @@
@triggerId="period-input" @triggerId="period-input"
@value={{this.price.interval}} @disabled={{this.isExistingPrice}} @value={{this.price.interval}} @disabled={{this.isExistingPrice}}
/> />
<GhErrorMessage @errors={{this.errors}} @property="interval" />
</GhFormGroup> </GhFormGroup>
</div> </div>
</div> </div>

View file

@ -1,7 +1,8 @@
import EmberObject, {action} from '@ember/object';
import ModalBase from 'ghost-admin/components/modal-base'; import ModalBase from 'ghost-admin/components/modal-base';
import classic from 'ember-classic-decorator'; import classic from 'ember-classic-decorator';
import {action} from '@ember/object';
import {currencies} from 'ghost-admin/utils/currency'; import {currencies} from 'ghost-admin/utils/currency';
import {isEmpty} from '@ember/utils';
import {task} from 'ember-concurrency-decorators'; import {task} from 'ember-concurrency-decorators';
import {tracked} from '@glimmer/tracking'; import {tracked} from '@glimmer/tracking';
@ -12,6 +13,7 @@ export default class ModalProductPrice extends ModalBase {
@tracked price; @tracked price;
@tracked currencyVal; @tracked currencyVal;
@tracked periodVal; @tracked periodVal;
@tracked errors = EmberObject.create();
init() { init() {
super.init(...arguments); super.init(...arguments);
@ -80,22 +82,40 @@ export default class ModalProductPrice extends ModalBase {
@task({drop: true}) @task({drop: true})
*savePrice() { *savePrice() {
try { this.validatePriceData();
const priceObj = { if (!isEmpty(this.errors) && Object.keys(this.errors).length > 0) {
...this.price, return;
amount: (this.price.amount || 0) * 100 }
}; const priceObj = {
if (!priceObj.id) { ...this.price,
priceObj.active = 1; amount: (this.price.amount || 0) * 100
priceObj.currency = priceObj.currency || 'usd'; };
priceObj.interval = priceObj.interval || 'month'; if (!priceObj.id) {
priceObj.type = 'recurring'; priceObj.active = 1;
} priceObj.currency = priceObj.currency || 'usd';
yield this.confirm(priceObj); priceObj.interval = priceObj.interval || 'month';
} catch (error) { priceObj.type = 'recurring';
this.notifications.showAPIError(error, {key: 'price.save.failed'}); }
} finally { yield this.confirm(priceObj);
this.send('closeModal'); this.send('closeModal');
}
validatePriceData() {
this.errors = EmberObject.create();
if (!this.price.nickname) {
this.errors.set('name', [{
message: 'Please enter name'
}]);
}
if (isNaN(this.price.amount)) {
this.errors.set('amount', [{
message: 'Please enter amount'
}]);
}
if (!this.price.interval || !['month', 'year'].includes(this.price.interval)) {
this.errors.set('interval', [{
message: 'Please enter billing interval'
}]);
} }
} }

View file

@ -168,7 +168,11 @@ export default class ProductController extends Controller {
return; return;
} }
yield this.settings.save(); yield this.settings.save();
return yield this.product.save(); const response = yield this.product.save();
if (this.showPriceModal) {
this.closePriceModal();
}
return response;
} }
_validateSignupRedirect(url, type) { _validateSignupRedirect(url, type) {