mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
Added error handling and validation for offer
closes https://github.com/TryGhost/Team/issues/1159 - validates offer fields before save client-side
This commit is contained in:
parent
54f5f659f7
commit
eddeb07a52
3 changed files with 68 additions and 17 deletions
|
@ -160,6 +160,7 @@ export default class OffersController extends Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
yield this.offer.validate();
|
||||||
yield offer.save();
|
yield offer.save();
|
||||||
|
|
||||||
// replace 'offer.new' route with 'offer' route
|
// replace 'offer.new' route with 'offer' route
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<div class="gh-main-section-block no-margin">
|
<div class="gh-main-section-block no-margin">
|
||||||
<h4 class="gh-main-section-header small bn">Basic</h4>
|
<h4 class="gh-main-section-header small bn">Basic</h4>
|
||||||
<div class="gh-main-section-content grey">
|
<div class="gh-main-section-content grey">
|
||||||
<GhFormGroup @errors={{this.errors}} @property="name" class="no-margin">
|
<GhFormGroup @errors={{this.offer.errors}} @property="name" @hasValidated={{this.offer.hasValidated}} class="no-margin">
|
||||||
<label for="name" class="fw6">Name</label>
|
<label for="name" class="fw6">Name</label>
|
||||||
<GhTextInput
|
<GhTextInput
|
||||||
@name="name"
|
@name="name"
|
||||||
|
@ -34,8 +34,10 @@
|
||||||
@input={{this.setOfferName}}
|
@input={{this.setOfferName}}
|
||||||
data-test-input="offer-name"
|
data-test-input="offer-name"
|
||||||
@class="gh-input" />
|
@class="gh-input" />
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="name" />
|
<span class="error">
|
||||||
<p>Will be shown to members on the Stripe Checkout page</p>
|
<GhErrorMessage @errors={{this.offer.errors}} @property="name" />
|
||||||
|
</span>
|
||||||
|
<p>Visible to members on Stripe Checkout page.</p>
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -58,7 +60,7 @@
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="product-cadence" />
|
<GhErrorMessage @errors={{this.errors}} @property="product-cadence" />
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
<div class="gh-offer-discount">
|
<div class="gh-offer-discount">
|
||||||
<GhFormGroup @errors={{this.errors}} @property="amount">
|
<GhFormGroup @errors={{this.offer.errors}} @property="amount" @hasValidated={{this.offer.hasValidated}}>
|
||||||
<label for="amount" class="fw6">Amount off</label>
|
<label for="amount" class="fw6">Amount off</label>
|
||||||
<div class="gh-offer-value percentage">
|
<div class="gh-offer-value percentage">
|
||||||
{{#if (eq this.offer.type 'fixed')}}
|
{{#if (eq this.offer.type 'fixed')}}
|
||||||
|
@ -84,11 +86,13 @@
|
||||||
@class="gh-input"
|
@class="gh-input"
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="amount" />
|
|
||||||
</div>
|
</div>
|
||||||
|
<span class="error">
|
||||||
|
<GhErrorMessage @errors={{this.offer.errors}} @property="amount" />
|
||||||
|
</span>
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
<div class="gh-offer-type">
|
<div class="gh-offer-type">
|
||||||
<GhFormGroup @errors={{this.errors}} @property="offer-type" class="no-margin">
|
<GhFormGroup @errors={{this.offer.errors}} @property="type" @hasValidated={{this.offer.hasValidated}} class="no-margin">
|
||||||
<span class="gh-select">
|
<span class="gh-select">
|
||||||
<OneWaySelect
|
<OneWaySelect
|
||||||
@value={{this.offer.type}}
|
@value={{this.offer.type}}
|
||||||
|
@ -101,7 +105,7 @@
|
||||||
/>
|
/>
|
||||||
{{svg-jar "arrow-down-small"}}
|
{{svg-jar "arrow-down-small"}}
|
||||||
</span>
|
</span>
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="duration" />
|
<GhErrorMessage @errors={{this.offer.errors}} @property="type" />
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -120,10 +124,12 @@
|
||||||
/>
|
/>
|
||||||
{{svg-jar "arrow-down-small"}}
|
{{svg-jar "arrow-down-small"}}
|
||||||
</span>
|
</span>
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="duration" />
|
<span class="error">
|
||||||
|
<GhErrorMessage @errors={{this.errors}} @property="duration" />
|
||||||
|
</span>
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
{{#if (eq this.offer.duration "repeating")}}
|
{{#if (eq this.offer.duration "repeating")}}
|
||||||
<GhFormGroup @errors={{this.errors}} @property="duration-months" @class="duration-months">
|
<GhFormGroup @errors={{this.offer.errors}} @property="durationInMonths" @class="duration-months">
|
||||||
<label for="duration-months" class="fw6">Number of months</label>
|
<label for="duration-months" class="fw6">Number of months</label>
|
||||||
<GhTextInput
|
<GhTextInput
|
||||||
@name="duration-months"
|
@name="duration-months"
|
||||||
|
@ -132,7 +138,9 @@
|
||||||
@disabled={{this.isDiscountSectionDisabled}}
|
@disabled={{this.isDiscountSectionDisabled}}
|
||||||
@id="duration-months"
|
@id="duration-months"
|
||||||
@class="gh-input" />
|
@class="gh-input" />
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="duration-months" />
|
<span class="error">
|
||||||
|
<GhErrorMessage @errors={{this.offer.errors}} @property="durationInMonths" />
|
||||||
|
</span>
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -141,7 +149,7 @@
|
||||||
<h4 class="gh-main-section-header small bn">Portal settings</h4>
|
<h4 class="gh-main-section-header small bn">Portal settings</h4>
|
||||||
<div class="gh-main-section-content grey">
|
<div class="gh-main-section-content grey">
|
||||||
<div class="form-col2">
|
<div class="form-col2">
|
||||||
<GhFormGroup @errors={{this.errors}} @property="display-title">
|
<GhFormGroup @errors={{this.offer.errors}} @property="displayTitle" @hasValidated={{this.offer.hasValidated}}>
|
||||||
<label for="display-title" class="fw6">Display title</label>
|
<label for="display-title" class="fw6">Display title</label>
|
||||||
<GhTextInput
|
<GhTextInput
|
||||||
@name="display-title"
|
@name="display-title"
|
||||||
|
@ -150,9 +158,11 @@
|
||||||
@placeholder="Black Friday Special"
|
@placeholder="Black Friday Special"
|
||||||
@id="display-title"
|
@id="display-title"
|
||||||
@class="gh-input" />
|
@class="gh-input" />
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="display-title" />
|
<span class="error">
|
||||||
|
<GhErrorMessage @errors={{this.offer.errors}} @property="displayTitle" />
|
||||||
|
</span>
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
<GhFormGroup @errors={{this.errors}} @property="code">
|
<GhFormGroup @errors={{this.offer.errors}} @property="code" @hasValidated={{this.offer.hasValidated}}>
|
||||||
<label for="code" class="fw6">Offer code</label>
|
<label for="code" class="fw6">Offer code</label>
|
||||||
<GhTextInput
|
<GhTextInput
|
||||||
@name="code"
|
@name="code"
|
||||||
|
@ -161,7 +171,9 @@
|
||||||
@input={{this.setOfferCode}}
|
@input={{this.setOfferCode}}
|
||||||
@id="code"
|
@id="code"
|
||||||
@class="gh-input" />
|
@class="gh-input" />
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="code" />
|
<span class="error">
|
||||||
|
<GhErrorMessage @errors={{this.offer.errors}} @property="code" />
|
||||||
|
</span>
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
</div>
|
</div>
|
||||||
<GhFormGroup @errors={{this.errors}} @property="url" @class="gh-offer-url">
|
<GhFormGroup @errors={{this.errors}} @property="url" @class="gh-offer-url">
|
||||||
|
@ -182,16 +194,19 @@
|
||||||
</div>
|
</div>
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="url" />
|
<GhErrorMessage @errors={{this.errors}} @property="url" />
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
<GhFormGroup @errors={{this.errors}} @property="description" class="no-margin">
|
<GhFormGroup @errors={{this.offer.errors}} @property="displayDescription" class="no-margin">
|
||||||
<label for="description" class="fw6">Description</label>
|
<label for="description" class="fw6">Description</label>
|
||||||
<GhTextarea
|
<GhTextarea
|
||||||
@id="description"
|
@id="description"
|
||||||
@name="description"
|
@name="description"
|
||||||
|
@placeholder="Take advantage of this limited-time offer."
|
||||||
@value={{this.offer.displayDescription}}
|
@value={{this.offer.displayDescription}}
|
||||||
@input={{this.setPortalDescription}}
|
@input={{this.setPortalDescription}}
|
||||||
@stopEnterKeyDownPropagation="true"
|
@stopEnterKeyDownPropagation="true"
|
||||||
/>
|
/>
|
||||||
<GhErrorMessage @errors={{this.errors}} @property="description" />
|
<span class="error">
|
||||||
|
<GhErrorMessage @errors={{this.offer.errors}} @property="displayDescription" />
|
||||||
|
</span>
|
||||||
</GhFormGroup>
|
</GhFormGroup>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import BaseValidator from './base';
|
||||||
import validator from 'validator';
|
import validator from 'validator';
|
||||||
|
|
||||||
export default BaseValidator.create({
|
export default BaseValidator.create({
|
||||||
properties: ['name'],
|
properties: ['name', 'amount', 'displayTitle', 'displayDescription', 'code', 'durationInMonths'],
|
||||||
|
|
||||||
name(model) {
|
name(model) {
|
||||||
if (!model.name) {
|
if (!model.name) {
|
||||||
|
@ -13,5 +13,40 @@ export default BaseValidator.create({
|
||||||
model.errors.add('name', 'Name cannot be longer than 191 characters.');
|
model.errors.add('name', 'Name cannot be longer than 191 characters.');
|
||||||
this.invalidate();
|
this.invalidate();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
amount(model) {
|
||||||
|
if (!model.amount) {
|
||||||
|
model.errors.add('amount', 'Please enter Amount.');
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displayTitle(model) {
|
||||||
|
if (!model.displayTitle) {
|
||||||
|
model.errors.add('displayTitle', 'Please enter Display title.');
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
displayDescription(model) {
|
||||||
|
if (!validator.isLength(model.displayDescription || '', 0, 191)) {
|
||||||
|
model.errors.add('displayDescription', 'Display description cannot be longer than 191 characters.');
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
durationInMonths(model) {
|
||||||
|
if (model.duration === 'repeating' && !model.durationInMonths) {
|
||||||
|
model.errors.add('durationInMonths', 'Please enter duration in months.');
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
code(model) {
|
||||||
|
if (!model.code) {
|
||||||
|
model.errors.add('code', 'Please enter code.');
|
||||||
|
this.invalidate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue