0
Fork 0
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:
Rishabh 2021-10-19 13:05:18 +05:30
parent 54f5f659f7
commit eddeb07a52
3 changed files with 68 additions and 17 deletions

View file

@ -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

View file

@ -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>

View file

@ -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();
}
} }
}); });