Skip to content

Commit

Permalink
feat(storefront): BCTHEME-187 improve localization and add default an…
Browse files Browse the repository at this point in the history
…d fallback messages
  • Loading branch information
bc-alexsaiannyi committed Oct 21, 2020
1 parent a244865 commit 521ed00
Show file tree
Hide file tree
Showing 17 changed files with 248 additions and 53 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- Quick search query param needs to be fixed while navigating to search page. [#230](https://jira.bigcommerce.com/browse/BCTHEME-230)

## Draft
- Move phrases and static strings to en.json for improving translation customizing. [#1850](https://github.com/bigcommerce/cornerstone/pull/1850)
- Create unified focus styling in Cornerstone. [#1812](https://github.com/bigcommerce/cornerstone/pull/1812)
- Review link in quick modal focused twice. [#1797](https://github.com/bigcommerce/cornerstone/pull/1797)
- Fixed product image doesn't change on click when viewing a product with multiple images in IE11 [#1748](https://github.com/bigcommerce/cornerstone/pull/1748)
Expand Down
16 changes: 13 additions & 3 deletions assets/js/test-unit/theme/common/faceted-search.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('FacetedSearch', () => {
let onSearchSuccess;
let html;
let $element;
let options;

beforeEach(() => {
onSearchSuccess = jest.fn();
Expand All @@ -26,6 +27,16 @@ describe('FacetedSearch', () => {
},
};

options = {
validationErrorMessages: {
onMinPriceError: jasmine.any(String),
onMaxPriceError: jasmine.any(String),
minPriceNotEntered: jasmine.any(String),
maxPriceNotEntered: jasmine.any(String),
onInvalidPrice: jasmine.any(String),
},
};

html =
'<div id="facetedSearch">' +
'<a class="facetedSearch-clearLink">Clear</a>' +
Expand Down Expand Up @@ -57,8 +68,7 @@ describe('FacetedSearch', () => {

$element = $(html);
$element.appendTo(document.body);

facetedSearch = new FacetedSearch(requestOptions, onSearchSuccess);
facetedSearch = new FacetedSearch(requestOptions, onSearchSuccess, options);
});

afterEach(() => {
Expand Down Expand Up @@ -99,7 +109,7 @@ describe('FacetedSearch', () => {
it('should re-init price range validator', function() {
facetedSearch.refreshView(content);

expect(Validators.setMinMaxPriceValidation).toHaveBeenCalledWith(facetedSearch.priceRangeValidator, jasmine.any(Object));
expect(Validators.setMinMaxPriceValidation).toHaveBeenCalledWith(facetedSearch.priceRangeValidator, jasmine.any(Object), options.validationErrorMessages);
});
});

Expand Down
15 changes: 11 additions & 4 deletions assets/js/test-unit/theme/common/form-utils.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ describe('Validators', () => {

describe('setMinMaxPriceValidation', () => {
let selectors;
const priceValidationErrorTexts = {
onMinPriceError: jasmine.any(String),
onMaxPriceError: jasmine.any(String),
minPriceNotEntered: jasmine.any(String),
maxPriceNotEntered: jasmine.any(String),
onInvalidPrice: jasmine.any(String),
};

beforeEach(() => {
selectors = {
Expand All @@ -25,7 +32,7 @@ describe('Validators', () => {
});

it('should add min-max validator to min price input', () => {
Validators.setMinMaxPriceValidation(validator, selectors);
Validators.setMinMaxPriceValidation(validator, selectors, priceValidationErrorTexts);

expect(validator.add).toHaveBeenCalledWith({
errorMessage: jasmine.any(String),
Expand All @@ -35,7 +42,7 @@ describe('Validators', () => {
});

it('should add presence validator to max price input', () => {
Validators.setMinMaxPriceValidation(validator, selectors);
Validators.setMinMaxPriceValidation(validator, selectors, priceValidationErrorTexts);

expect(validator.add).toHaveBeenCalledWith({
errorMessage: jasmine.any(String),
Expand All @@ -45,7 +52,7 @@ describe('Validators', () => {
});

it('should add presence validator to max price input', () => {
Validators.setMinMaxPriceValidation(validator, selectors);
Validators.setMinMaxPriceValidation(validator, selectors, priceValidationErrorTexts);

expect(validator.add).toHaveBeenCalledWith({
errorMessage: jasmine.any(String),
Expand All @@ -55,7 +62,7 @@ describe('Validators', () => {
});

it('should add min-number validator to max/min price inputs', () => {
Validators.setMinMaxPriceValidation(validator, selectors);
Validators.setMinMaxPriceValidation(validator, selectors, priceValidationErrorTexts);

expect(validator.add).toHaveBeenCalledWith({
errorMessage: jasmine.any(String),
Expand Down
19 changes: 11 additions & 8 deletions assets/js/theme/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import nod from './common/nod';
import Wishlist from './wishlist';
import validation from './common/form-validation';
import stateCountry from './common/state-country';
import { classifyForm, Validators, insertStateHiddenField } from './common/utils/form-utils';
import { classifyForm, Validators, insertStateHiddenField, createPasswordValidationErrorTextObject } from './common/utils/form-utils';
import { createTranslationDictionary } from './common/utils/translations-utils';
import { creditCardType, storeInstrument, Validators as CCValidators, Formatters as CCFormatters } from './common/payment-method';
import swal from './global/sweet-alert';

export default class Account extends PageManager {
constructor(context) {
super(context);

this.validationDictionary = createTranslationDictionary(context);
this.$state = $('[data-field-type="State"]');
this.$body = $('body');
}
Expand Down Expand Up @@ -130,7 +131,7 @@ export default class Account extends PageManager {
}

initAddressFormValidation($addressForm) {
const validationModel = validation($addressForm);
const validationModel = validation($addressForm, this.context);
const stateSelector = 'form[data-address-form] [data-field-type="State"]';
const $stateElement = $(stateSelector);
const addressValidator = nod({
Expand Down Expand Up @@ -160,7 +161,7 @@ export default class Account extends PageManager {

if ($field.is('select')) {
$last = field;
Validators.setStateCountryValidation(addressValidator, field);
Validators.setStateCountryValidation(addressValidator, field, this.validationDictionary.field_not_blank);
} else {
Validators.cleanUpStateValidation(field);
}
Expand Down Expand Up @@ -220,7 +221,7 @@ export default class Account extends PageManager {
$paymentMethodForm.find('#state.form-field').attr('data-validation', `{ "type": "singleline", "label": "${this.context.stateLabel}", "required": true, "maxlength": 0 }`);
$paymentMethodForm.find('#postal_code.form-field').attr('data-validation', `{ "type": "singleline", "label": "${this.context.postalCodeLabel}", "required": true, "maxlength": 0 }`);

const validationModel = validation($paymentMethodForm);
const validationModel = validation($paymentMethodForm, this.context);
const paymentMethodSelector = 'form[data-payment-method-form]';
const paymentMethodValidator = nod({ submit: `${paymentMethodSelector} input[type="submit"]` });
const $stateElement = $(`${paymentMethodSelector} [data-field-type="State"]`);
Expand All @@ -244,7 +245,7 @@ export default class Account extends PageManager {

if ($field.is('select')) {
$last = field;
Validators.setStateCountryValidation(paymentMethodValidator, field);
Validators.setStateCountryValidation(paymentMethodValidator, field, this.validationDictionary.field_not_blank);
} else {
Validators.cleanUpStateValidation(field);
}
Expand Down Expand Up @@ -309,7 +310,7 @@ export default class Account extends PageManager {
}

registerEditAccountValidation($editAccountForm) {
const validationModel = validation($editAccountForm);
const validationModel = validation($editAccountForm, this.context);
const formEditSelector = 'form[data-edit-account-form]';
const editValidator = nod({
submit: '${formEditSelector} input[type="submit"]',
Expand All @@ -328,17 +329,19 @@ export default class Account extends PageManager {

if ($emailElement) {
editValidator.remove(emailSelector);
Validators.setEmailValidation(editValidator, emailSelector);
Validators.setEmailValidation(editValidator, emailSelector, this.validationDictionary.valid_email);
}

if ($passwordElement && $password2Element) {
const { password: enterPassword, password_match: matchPassword, invalid_password: invalidPassword } = this.validationDictionary;
editValidator.remove(passwordSelector);
editValidator.remove(password2Selector);
Validators.setPasswordValidation(
editValidator,
passwordSelector,
password2Selector,
this.passwordRequirements,
createPasswordValidationErrorTextObject(enterPassword, enterPassword, matchPassword, invalidPassword),
true,
);
}
Expand Down
17 changes: 12 additions & 5 deletions assets/js/theme/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import stateCountry from './common/state-country';
import nod from './common/nod';
import validation from './common/form-validation';
import forms from './common/models/forms';
import { classifyForm, Validators } from './common/utils/form-utils';
import { classifyForm, Validators, createPasswordValidationErrorTextObject } from './common/utils/form-utils';
import { createTranslationDictionary } from './common/utils/translations-utils';

export default class Auth extends PageManager {
constructor(context) {
super(context);
this.validationDictionary = createTranslationDictionary(context);
this.formCreateSelector = 'form[data-create-account-form]';
}

Expand Down Expand Up @@ -79,23 +81,25 @@ export default class Auth extends PageManager {
}

registerNewPasswordValidation() {
const { password: enterPassword, password_match: matchPassword, invalid_password: invalidPassword } = this.validationDictionary;
const newPasswordForm = '.new-password-form';
const newPasswordValidator = nod({
submit: $(`${newPasswordForm} input[type="submit"]`),
});
const passwordSelector = $(`${newPasswordForm} input[name="password"]`);
const password2Selector = $(`${newPasswordForm} input[name="password_confirm"]`);

const errorTextMessages = createPasswordValidationErrorTextObject(enterPassword, enterPassword, matchPassword, invalidPassword);
Validators.setPasswordValidation(
newPasswordValidator,
passwordSelector,
password2Selector,
this.passwordRequirements,
errorTextMessages,
);
}

registerCreateAccountValidator($createAccountForm) {
const validationModel = validation($createAccountForm);
const validationModel = validation($createAccountForm, this.context);
const createAccountValidator = nod({
submit: `${this.formCreateSelector} input[type='submit']`,
});
Expand Down Expand Up @@ -130,7 +134,7 @@ export default class Auth extends PageManager {

if ($field.is('select')) {
$last = field;
Validators.setStateCountryValidation(createAccountValidator, field);
Validators.setStateCountryValidation(createAccountValidator, field, this.validationDictionary.field_not_blank);
} else {
Validators.cleanUpStateValidation(field);
}
Expand All @@ -139,17 +143,20 @@ export default class Auth extends PageManager {

if ($emailElement) {
createAccountValidator.remove(emailSelector);
Validators.setEmailValidation(createAccountValidator, emailSelector);
Validators.setEmailValidation(createAccountValidator, emailSelector, this.validationDictionary.valid_email);
}

if ($passwordElement && $password2Element) {
const { password: enterPassword, password_match: matchPassword, invalid_password: invalidPassword } = this.validationDictionary;

createAccountValidator.remove(passwordSelector);
createAccountValidator.remove(password2Selector);
Validators.setPasswordValidation(
createAccountValidator,
passwordSelector,
password2Selector,
this.passwordRequirements,
createPasswordValidationErrorTextObject(enterPassword, enterPassword, matchPassword, invalidPassword),
);
}

Expand Down
21 changes: 21 additions & 0 deletions assets/js/theme/brand.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import { hooks } from '@bigcommerce/stencil-utils';
import CatalogPage from './catalog';
import compareProducts from './global/compare-products';
import FacetedSearch from './common/faceted-search';
import { createTranslationDictionary } from '../theme/common/utils/translations-utils';

export default class Brand extends CatalogPage {
constructor(context) {
super(context);
this.validationDictionary = createTranslationDictionary(context);
}

onReady() {
compareProducts(this.context.urls);

Expand All @@ -16,6 +22,13 @@ export default class Brand extends CatalogPage {
}

initFacetedSearch() {
const {
price_min_evaluation: onMinPriceError,
price_max_evaluation: onMaxPriceError,
price_min_not_entered: minPriceNotEntered,
price_max_not_entered: maxPriceNotEntered,
price_invalid_value: onInvalidPrice,
} = this.validationDictionary;
const $productListingContainer = $('#product-listing-container');
const $facetedSearchContainer = $('#faceted-search-container');
const productsPerPage = this.context.brandProductsPerPage;
Expand Down Expand Up @@ -44,6 +57,14 @@ export default class Brand extends CatalogPage {
$('html, body').animate({
scrollTop: 0,
}, 100);
}, {
validationErrorMessages: {
onMinPriceError,
onMaxPriceError,
minPriceNotEntered,
maxPriceNotEntered,
onInvalidPrice,
},
});
}
}
21 changes: 21 additions & 0 deletions assets/js/theme/category.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@ import { hooks } from '@bigcommerce/stencil-utils';
import CatalogPage from './catalog';
import compareProducts from './global/compare-products';
import FacetedSearch from './common/faceted-search';
import { createTranslationDictionary } from '../theme/common/utils/translations-utils';

export default class Category extends CatalogPage {
constructor(context) {
super(context);
this.validationDictionary = createTranslationDictionary(context);
}

onReady() {
compareProducts(this.context.urls);

Expand All @@ -16,6 +22,13 @@ export default class Category extends CatalogPage {
}

initFacetedSearch() {
const {
price_min_evaluation: onMinPriceError,
price_max_evaluation: onMaxPriceError,
price_min_not_entered: minPriceNotEntered,
price_max_not_entered: maxPriceNotEntered,
price_invalid_value: onInvalidPrice,
} = this.validationDictionary;
const $productListingContainer = $('#product-listing-container');
const $facetedSearchContainer = $('#faceted-search-container');
const productsPerPage = this.context.categoryProductsPerPage;
Expand Down Expand Up @@ -44,6 +57,14 @@ export default class Category extends CatalogPage {
$('html, body').animate({
scrollTop: 0,
}, 100);
}, {
validationErrorMessages: {
onMinPriceError,
onMaxPriceError,
minPriceNotEntered,
maxPriceNotEntered,
onInvalidPrice,
},
});
}
}
2 changes: 1 addition & 1 deletion assets/js/theme/common/faceted-search.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ class FacetedSearch {
minPriceSelector: this.options.priceRangeMinPriceSelector,
};

Validators.setMinMaxPriceValidation(validator, selectors);
Validators.setMinMaxPriceValidation(validator, selectors, this.options.validationErrorMessages);

this.priceRangeValidator = validator;
}
Expand Down
Loading

0 comments on commit 521ed00

Please sign in to comment.