diff --git a/.circleci/config.yml b/.circleci/config.yml
index 5f9e1a11fb2..99a022451d9 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -41,14 +41,15 @@ jobs:
- run: npm test
- run: reaction test
-
- save_cache:
name: Saving Meteor dev_bundle to cache
key: dev_bundle
paths:
- /home/reaction/.meteor/local
- - run: .circleci/build.sh
+ - run:
+ command: .circleci/build.sh
+ no_output_timeout: 30m
# deploy the build (if on a deployment branch)
- deploy:
diff --git a/.meteor/packages b/.meteor/packages
index 213943a56bc..22c3926c661 100644
--- a/.meteor/packages
+++ b/.meteor/packages
@@ -11,13 +11,13 @@ meteor-base@1.1.0 # Packages every Meteor app needs to have
mobile-experience@1.0.4 # Packages for a great mobile UX
blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers.
-ecmascript@0.8.0 # Enable ECMAScript2015+ syntax in app code
+ecmascript@0.8.1 # Enable ECMAScript2015+ syntax in app code
audit-argument-checks@1.0.7 # ensure meteor method argument validation
browser-policy@1.1.0 # security-related policies enforced by newer browsers
juliancwirko:postcss # CSS post-processing plugin (replaces standard-minifier-css)
session@1.1.7 # ReactiveDict whose contents are preserved across Hot Code Push
tracker@1.1.3 # Meteor transparent reactive programming library
-mongo@1.1.18
+mongo@1.1.19
random@1.0.10
reactive-var@1.0.11
reactive-dict@1.1.9
@@ -31,13 +31,13 @@ ejson@1.0.13
less@2.7.9
service-configuration@1.0.11
mdg:validated-method
-shell-server@0.2.3
-dynamic-import
+shell-server@0.2.4
+dynamic-import@0.1.1
# Meteor Auth Packages
-accounts-base@1.3.0
-accounts-password@1.3.6
-accounts-facebook@1.2.0
+accounts-base@1.3.1
+accounts-password@1.4.0
+accounts-facebook@1.2.1
accounts-google@1.2.0
accounts-twitter@1.3.0
oauth-encryption@1.2.1
@@ -93,3 +93,4 @@ johanbrook:publication-collector
# Custom Packages
abernix:standard-minifier-js@2.1.0-beta.0
+bozhao:accounts-instagram
diff --git a/.meteor/release b/.meteor/release
index 025f64e7073..1e7fc5b564c 100644
--- a/.meteor/release
+++ b/.meteor/release
@@ -1 +1 @@
-METEOR@1.5
+METEOR@1.5.1
diff --git a/.meteor/versions b/.meteor/versions
index 671a440f2dd..4fa112a0a02 100644
--- a/.meteor/versions
+++ b/.meteor/versions
@@ -1,10 +1,10 @@
-abernix:minifier-js@2.1.0-beta.0
-abernix:standard-minifier-js@2.1.0-beta.0
-accounts-base@1.3.0
-accounts-facebook@1.2.0
+abernix:minifier-js@2.1.0
+abernix:standard-minifier-js@2.1.0
+accounts-base@1.3.1
+accounts-facebook@1.2.1
accounts-google@1.2.0
accounts-oauth@1.1.15
-accounts-password@1.3.7
+accounts-password@1.4.0
accounts-twitter@1.3.0
alanning:roles@1.2.16
aldeed:autoform@5.8.1
@@ -15,17 +15,18 @@ aldeed:schema-deny@1.1.0
aldeed:schema-index@1.1.1
aldeed:simple-schema@1.5.3
aldeed:template-extension@4.1.0
-allow-deny@1.0.5
+allow-deny@1.0.6
audit-argument-checks@1.0.7
autoupdate@1.3.12
-babel-compiler@6.19.3
+babel-compiler@6.19.4
babel-runtime@1.0.1
base64@1.0.10
binary-heap@1.0.10
blaze@2.3.2
blaze-html-templates@1.1.2
blaze-tools@1.0.10
-boilerplate-generator@1.1.0
+boilerplate-generator@1.1.1
+bozhao:accounts-instagram@0.2.2
browser-policy@1.1.0
browser-policy-common@1.0.11
browser-policy-content@1.1.0
@@ -56,25 +57,25 @@ cfs:worker@0.1.4
check@1.2.5
coffeescript@1.12.6_1
dburles:factory@1.1.0
-ddp@1.2.5
-ddp-client@1.3.4
-ddp-common@1.2.8
+ddp@1.3.0
+ddp-client@2.0.0
+ddp-common@1.2.9
ddp-rate-limiter@1.0.7
-ddp-server@1.3.14
+ddp-server@2.0.0
deps@1.0.12
diff-sequence@1.0.7
dispatch:mocha@0.4.1
dispatch:run-as-user@1.1.1
dynamic-import@0.1.1
-ecmascript@0.8.1
+ecmascript@0.8.2
ecmascript-runtime@0.4.1
-ecmascript-runtime-client@0.4.2
+ecmascript-runtime-client@0.4.3
ecmascript-runtime-server@0.4.1
ejson@1.0.13
email@1.2.3
es5-shim@4.6.15
facebook-config-ui@1.0.0
-facebook-oauth@1.3.1
+facebook-oauth@1.3.2
fastclick@1.0.13
gadicc:blaze-react-component@1.4.0
geojson-utils@1.0.10
@@ -85,7 +86,7 @@ html-tools@1.0.11
htmljs@1.0.11
http@1.2.12
id-map@1.0.9
-johanbrook:publication-collector@1.0.8
+johanbrook:publication-collector@1.0.9
jparker:crypto-core@0.1.0
jparker:crypto-md5@0.1.1
jparker:gravatar@0.5.1
@@ -97,12 +98,12 @@ kadira:dochead@1.5.0
launch-screen@1.1.1
less@2.7.9
livedata@1.0.18
-localstorage@1.1.0
+localstorage@1.1.1
logging@1.1.17
matb33:collection-hooks@0.8.4
mdg:validated-method@1.1.0
mdg:validation-error@0.5.1
-meteor@1.6.1
+meteor@1.7.0
meteor-base@1.1.0
meteorhacks:ssr@2.2.0
meteorhacks:subs-manager@1.6.4
@@ -113,7 +114,7 @@ mobile-status-bar@1.0.14
modules@0.9.2
modules-runtime@0.8.0
momentjs:moment@2.18.1
-mongo@1.1.18
+mongo@1.1.19
mongo-id@1.0.6
mongo-livedata@1.0.12
mrt:later@1.6.1
@@ -145,7 +146,7 @@ routepolicy@1.0.12
service-configuration@1.0.11
session@1.1.7
sha@1.0.9
-shell-server@0.2.3
+shell-server@0.2.4
spacebars@1.0.15
spacebars-compiler@1.1.2
srp@1.0.10
@@ -162,5 +163,5 @@ ui@1.0.13
underscore@1.0.10
url@1.1.0
vsivsi:job-collection@1.4.0
-webapp@1.3.16
+webapp@1.3.17
webapp-hashing@1.0.9
diff --git a/client/modules/accounts/components/auth/loginButtons.js b/client/modules/accounts/components/auth/loginButtons.js
index a349cb76b67..f7800833f7d 100644
--- a/client/modules/accounts/components/auth/loginButtons.js
+++ b/client/modules/accounts/components/auth/loginButtons.js
@@ -33,6 +33,7 @@ class LoginButtons extends Component {
{this.props.currentView === "loginFormSignInView" &&
+
}
diff --git a/client/modules/accounts/containers/dropdown/mainDropdownContainer.js b/client/modules/accounts/containers/dropdown/mainDropdownContainer.js
index 258f0e79837..2865225a81c 100644
--- a/client/modules/accounts/containers/dropdown/mainDropdownContainer.js
+++ b/client/modules/accounts/containers/dropdown/mainDropdownContainer.js
@@ -70,18 +70,21 @@ class MainDropdownContainer extends Component {
function getCurrentUser() {
const shopId = Reaction.getShopId();
- const user = Accounts.user();
+ const user = Accounts.user() || {};
if (!shopId || typeof user !== "object") {
return null;
}
+
// shoppers should always be guests
const isGuest = Roles.userIsInRole(user, "guest", shopId);
// but if a user has never logged in then they are anonymous
const isAnonymous = Roles.userIsInRole(user, "anonymous", shopId);
- return isGuest && !isAnonymous ? user : null;
+ const account = Collections.Accounts.findOne(user._id);
+
+ return isGuest && !isAnonymous ? account : null;
}
function getUserGravatar(currentUser, size) {
diff --git a/client/modules/accounts/helpers/util.js b/client/modules/accounts/helpers/util.js
index fb47aab4fa5..3e2bcc7cffc 100644
--- a/client/modules/accounts/helpers/util.js
+++ b/client/modules/accounts/helpers/util.js
@@ -10,7 +10,8 @@ function capitalize(str) {
const providers = {
Facebook: {},
Google: {},
- Twitter: {}
+ Twitter: {},
+ Instagram: {}
};
providers.Facebook.fields = function () {
@@ -34,6 +35,13 @@ providers.Twitter.fields = function () {
];
};
+providers.Instagram.fields = function () {
+ return [
+ { property: "clientId", label: "Client ID" },
+ { property: "secret", label: "Client secret" }
+ ];
+};
+
export class ServiceConfigHelper {
availableServices() {
const services = Package["accounts-oauth"] ? Accounts.oauth.serviceNames() : [];
diff --git a/client/modules/accounts/templates/profile/profile.js b/client/modules/accounts/templates/profile/profile.js
index 952ab68b4a1..ea34baec851 100644
--- a/client/modules/accounts/templates/profile/profile.js
+++ b/client/modules/accounts/templates/profile/profile.js
@@ -1,7 +1,9 @@
import { Meteor } from "meteor/meteor";
import { Template } from "meteor/templating";
+import { Roles } from "meteor/alanning:roles";
import { ReactiveVar } from "meteor/reactive-var";
import { Reaction } from "/client/api";
+import { i18next } from "/client/api";
import * as Collections from "/lib/collections";
/**
@@ -58,6 +60,30 @@ Template.accountProfile.helpers({
return Collections.Accounts.findOne();
},
+ /**
+ * User's display name
+ * @return {String} display name
+ */
+ displayName() {
+ const userId = Meteor.userId() || {};
+ const user = Collections.Accounts.findOne(userId);
+
+ if (user) {
+ if (user.name) {
+ return user.name;
+ } else if (user.username) {
+ return user.username;
+ } else if (user.profile && user.profile.name) {
+ return user.profile.name;
+ }
+ }
+
+ if (Roles.userIsInRole(user._id || user.userId, "account/profile",
+ Reaction.getShopId())) {
+ return i18next.t("accountsUI.guest", { defaultValue: "Guest" });
+ }
+ },
+
/**
* Returns the address book default view
* @return {String} "addressBookGrid" || "addressBookAdd"
diff --git a/client/modules/core/helpers/utils.js b/client/modules/core/helpers/utils.js
index 447f54258e6..aa1d49d24b0 100644
--- a/client/modules/core/helpers/utils.js
+++ b/client/modules/core/helpers/utils.js
@@ -1,7 +1,4 @@
-/* global slugify */
-// client slugify only works when import minified version.
-import "transliteration/lib/browser/transliteration.js";
-
+import { slugify } from "transliteration";
/**
* getSlug - return a client slugified string using the "slugify"
* global from the transliteration package
diff --git a/client/modules/i18n/startup.js b/client/modules/i18n/startup.js
index 16a8409878e..7fbe8d5f0c3 100644
--- a/client/modules/i18n/startup.js
+++ b/client/modules/i18n/startup.js
@@ -51,11 +51,7 @@ Meteor.startup(() => {
//
return Meteor.subscribe("Translations", language, () => {
// fetch reaction translations
- const translations = Translations.find({}, {
- fields: {
- _id: 0
- }
- }).fetch();
+ const translations = Translations.find({}).fetch();
//
// reduce and merge translations
diff --git a/imports/plugins/core/collections/index.js b/imports/plugins/core/collections/index.js
new file mode 100644
index 00000000000..5bc57d78a9e
--- /dev/null
+++ b/imports/plugins/core/collections/index.js
@@ -0,0 +1 @@
+export { default as Validation } from "./lib/validation";
diff --git a/imports/plugins/core/collections/lib/validation.js b/imports/plugins/core/collections/lib/validation.js
new file mode 100644
index 00000000000..1011a3770bd
--- /dev/null
+++ b/imports/plugins/core/collections/lib/validation.js
@@ -0,0 +1,93 @@
+/**
+ * Validation class
+ * @summary Helper to streamline getting simple-schema validation in react components
+ */
+class Validation {
+ /**
+ * Instantiate with a schema to validate against
+ * @param {SimpleSchema} schema aldeed:simpleschema class
+ * @param {Object} options extra options such as { pick: ["fieldName"] }
+ */
+ constructor(schema, options) {
+ if (options && options.pick) {
+ this.validationContext = schema.pick(options.pick).newContext();
+ } else {
+ this.validationContext = schema.namedContext();
+ }
+
+ this.schema = schema;
+ this.options = options;
+ this.validationStatus = {
+ isValid: undefined,
+ fields: {},
+ messages: {},
+ isFieldValid: this.isFieldValid
+ };
+ }
+
+ get cleanOptions() {
+ return this.options && this.options.cleanOptions || { getAutoValues: false };
+ }
+
+ /**
+ * validate
+ * @param {Object} objectToValidate Object to validate against schema
+ * @return {Object} object containting {isValid: true|false, validationMessages: undefined|object}
+ */
+ validate(objectToValidate) {
+ const messages = {};
+ const fields = {};
+
+ // clean object, removing fields that aren't in the schema, and convert types
+ // based on schema
+ const cleanedObject = this.schema.clean(objectToValidate, this.cleanOptions);
+
+ // Validate the cleaned object
+ const isValid = this.validationContext.validate(cleanedObject);
+
+ // Avoiding the reactive-stuff built into simple-schema, grab invalid
+ // keys from the private var _invalidKeys, and create a new object with
+ // the validation error and message.
+ this.validationContext._invalidKeys
+ .forEach((validationError) => {
+ messages[validationError.name] = {
+ ...validationError,
+ isValid: false,
+ message: this.validationContext.keyErrorMessage(validationError.name)
+ };
+ });
+
+ for (const fieldName of Object.keys(cleanedObject)) {
+ const hasMessage = messages[fieldName];
+
+ fields[fieldName] = {
+ isValid: hasMessage ? false : true,
+ value: cleanedObject[fieldName]
+ };
+ }
+
+
+ // Set the current validation status of the validated object on class instance
+ this.validationStatus = {
+ isValid,
+ fields,
+ messages,
+ isFieldValid: this.isFieldValid
+ };
+
+ // Return object validation status, fields, and helpers
+ return this.validationStatus;
+ }
+
+ /**
+ * isFieldValid - get status of a field after running `validate`
+ * @param {String} fieldName Name of field to check status
+ * @return {Boolean} `true` if valid / `false` if not valid / `undefined` if unknown or not yet tested
+ */
+ isFieldValid = (fieldName) => {
+ const field = this.validationStatus.fields[fieldName];
+ return field && field.isValid;
+ }
+}
+
+export default Validation;
diff --git a/imports/plugins/core/ui/client/components/table/sortableTable.js b/imports/plugins/core/ui/client/components/table/sortableTable.js
index d0a90e855a0..50d798bc8e8 100644
--- a/imports/plugins/core/ui/client/components/table/sortableTable.js
+++ b/imports/plugins/core/ui/client/components/table/sortableTable.js
@@ -27,7 +27,7 @@ class SortableTable extends Component {
* @prop {String} matchingResultsCount - Send to Counts collection to get results count of sub
* @prop {String} publication - publication to subscribe to
* @prop {Object} collection - collection to get data from
- * Use props to get collection, EmailTableColumn
+ * Use props to get collection
* Use that info to call meteor and get subscription
* Output data for table
* @returns {Object} loading status (bool), results (object), and matchingResults (number)
diff --git a/imports/plugins/core/ui/client/components/textfield/textfield.js b/imports/plugins/core/ui/client/components/textfield/textfield.js
index 23af808a0bb..76aa6b6cdb8 100644
--- a/imports/plugins/core/ui/client/components/textfield/textfield.js
+++ b/imports/plugins/core/ui/client/components/textfield/textfield.js
@@ -14,6 +14,32 @@ class TextField extends Component {
return this.props.value || "";
}
+ /**
+ * Getter: isValid
+ * @return {Boolean} true/false if field is valid from props.isValid or props.valitation[this.props.name].isValid
+ */
+ get isValid() {
+ const { isValid } = this.props;
+
+ if (typeof isValid === "boolean") {
+ return isValid;
+ } else if (this.validationMessage) {
+ return false;
+ }
+
+ return undefined;
+ }
+
+ get validationMessage() {
+ const { name, validation } = this.props;
+
+ if (typeof validation === "object" && validation.messages && validation.messages[name]) {
+ return validation.messages[name];
+ }
+
+ return undefined;
+ }
+
/**
* onValueChange
* @summary set the state when the value of the input is changed
@@ -121,6 +147,10 @@ class TextField extends Component {
return this.renderSingleLineInput();
}
+ /**
+ * Render the label for the text field if one is provided in props
+ * @return {ReactNode|null} react node or null
+ */
renderLabel() {
if (this.props.label) {
return (
@@ -133,11 +163,24 @@ class TextField extends Component {
return null;
}
+ /**
+ * Render help text or validation message
+ * @return {ReactNode|null} react node or null
+ */
renderHelpText() {
- if (this.props.helpText) {
+ const message = this.validationMessage;
+ let helpText = this.props.helpText;
+ let i18nKey = this.props.i18nKeyHelpText;
+
+ if (this.isValid === false && message) {
+ helpText = message.message;
+ i18nKey = message.i18nKeyMessage;
+ }
+
+ if (helpText) {
return (
-
+
);
}
@@ -155,6 +198,8 @@ class TextField extends Component {
"rui": true,
"textfield": true,
"form-group": true,
+ "has-error": this.isValid === false,
+ "has-success": this.isValid === true,
// Alignment
"center": this.props.align === "center",
@@ -186,6 +231,7 @@ TextField.propTypes = {
i18nKeyLabel: PropTypes.string,
i18nKeyPlaceholder: PropTypes.string,
id: PropTypes.string,
+ isValid: PropTypes.bool,
label: PropTypes.string,
multiline: PropTypes.bool,
name: PropTypes.string,
@@ -197,6 +243,7 @@ TextField.propTypes = {
style: PropTypes.object,
textFieldStyle: PropTypes.object,
type: PropTypes.string,
+ validation: PropTypes.object,
value: PropTypes.any
};
diff --git a/imports/plugins/core/ui/server/i18n/ar.json b/imports/plugins/core/ui/server/i18n/ar.json
index 65b9404c5a1..6002b8d569e 100644
--- a/imports/plugins/core/ui/server/i18n/ar.json
+++ b/imports/plugins/core/ui/server/i18n/ar.json
@@ -17,7 +17,20 @@
"publishThemeError": "`لا يمكن نشر موضوع {{themeName}}",
"components": {
"navbar": "شريط التنقل",
- "button": "زر"
+ "button": "زر",
+ "sortableTable": {
+ "filterPlaceholder": "تصفية البيانات",
+ "tableText": {
+ "noDataMessage": "لا توجد نتائج",
+ "previousText": "سابق",
+ "nextText": "التالى",
+ "loadingText": "تحميل ...",
+ "noDataText": "لا توجد نتائج",
+ "pageText": "صفحة",
+ "ofText": "من",
+ "rowsText": "الصفوف"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/bg.json b/imports/plugins/core/ui/server/i18n/bg.json
index 4f6fda0ac9b..c179b74fb5c 100644
--- a/imports/plugins/core/ui/server/i18n/bg.json
+++ b/imports/plugins/core/ui/server/i18n/bg.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Не може да публикувате тема {{themeName}}",
"components": {
"navbar": "Navigation Bar",
- "button": "бутон"
+ "button": "бутон",
+ "sortableTable": {
+ "filterPlaceholder": "Филтриране на данни",
+ "tableText": {
+ "noDataMessage": "Няма намерени резултати",
+ "previousText": "Предишен",
+ "nextText": "Следващия",
+ "loadingText": "Зарежда се ...",
+ "noDataText": "Няма намерени резултати",
+ "pageText": "страница",
+ "ofText": "на",
+ "rowsText": "редове"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/cs.json b/imports/plugins/core/ui/server/i18n/cs.json
index 03c2609c7d9..2ce5f5b796b 100644
--- a/imports/plugins/core/ui/server/i18n/cs.json
+++ b/imports/plugins/core/ui/server/i18n/cs.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Nelze zveřejnit téma {{themeName}}",
"components": {
"navbar": "navigační lišta",
- "button": "Tlačítko"
+ "button": "Tlačítko",
+ "sortableTable": {
+ "filterPlaceholder": "Filtrování dat",
+ "tableText": {
+ "noDataMessage": "Nebyly nalezeny žádné výsledky",
+ "previousText": "Předchozí",
+ "nextText": "Další",
+ "loadingText": "Loading ...",
+ "noDataText": "Nebyly nalezeny žádné výsledky",
+ "pageText": "Strana",
+ "ofText": "z",
+ "rowsText": "Řádky"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/de.json b/imports/plugins/core/ui/server/i18n/de.json
index e51d8bcfc22..268e61ef159 100644
--- a/imports/plugins/core/ui/server/i18n/de.json
+++ b/imports/plugins/core/ui/server/i18n/de.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Konnte nicht Thema {{themeName}} veröffentlichen",
"components": {
"navbar": "Navigationsleiste",
- "button": "Taste"
+ "button": "Taste",
+ "sortableTable": {
+ "filterPlaceholder": "Filterdaten",
+ "tableText": {
+ "noDataMessage": "Keine Ergebnisse gefunden",
+ "previousText": "Früher",
+ "nextText": "Nächster",
+ "loadingText": "Wird geladen ...",
+ "noDataText": "Keine Ergebnisse gefunden",
+ "pageText": "Page",
+ "ofText": "von",
+ "rowsText": "Reihen"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/el.json b/imports/plugins/core/ui/server/i18n/el.json
index b90c2b996c3..e09da1b7d90 100644
--- a/imports/plugins/core/ui/server/i18n/el.json
+++ b/imports/plugins/core/ui/server/i18n/el.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Δεν ήταν δυνατή η δημοσίευση θέμα {{themeName}}",
"components": {
"navbar": "Μπάρα πλοήγησης",
- "button": "Κουμπί"
+ "button": "Κουμπί",
+ "sortableTable": {
+ "filterPlaceholder": "Φιλτράρετε δεδομένα",
+ "tableText": {
+ "noDataMessage": "Δεν βρέθηκαν αποτελέσματα",
+ "previousText": "Προηγούμενος",
+ "nextText": "Επόμενος",
+ "loadingText": "Φόρτωση ...",
+ "noDataText": "Δεν βρέθηκαν αποτελέσματα",
+ "pageText": "Σελίδα",
+ "ofText": "του",
+ "rowsText": "Σειρές"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/es.json b/imports/plugins/core/ui/server/i18n/es.json
index 27df297c454..ea87192f86b 100644
--- a/imports/plugins/core/ui/server/i18n/es.json
+++ b/imports/plugins/core/ui/server/i18n/es.json
@@ -17,7 +17,20 @@
"publishThemeError": "`No se pudo publicar {{themeName}} tema",
"components": {
"navbar": "Barra de navegación",
- "button": "Botón"
+ "button": "Botón",
+ "sortableTable": {
+ "filterPlaceholder": "Filtrar datos",
+ "tableText": {
+ "noDataMessage": "Sin resultados",
+ "previousText": "Anterior",
+ "nextText": "Siguiente",
+ "loadingText": "Cargando ...",
+ "noDataText": "Sin resultados",
+ "pageText": "Página",
+ "ofText": "de",
+ "rowsText": "Filas"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/fr.json b/imports/plugins/core/ui/server/i18n/fr.json
index 015ae7e4a93..3a21188fc56 100644
--- a/imports/plugins/core/ui/server/i18n/fr.json
+++ b/imports/plugins/core/ui/server/i18n/fr.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Impossible de publier le thème {{themeName}}",
"components": {
"navbar": "Barre de navigation",
- "button": "Bouton"
+ "button": "Bouton",
+ "sortableTable": {
+ "filterPlaceholder": "Données de filtrage",
+ "tableText": {
+ "noDataMessage": "Aucun résultat trouvé",
+ "previousText": "Précédent",
+ "nextText": "Suivant",
+ "loadingText": "Chargement ...",
+ "noDataText": "Aucun résultat trouvé",
+ "pageText": "Page",
+ "ofText": "de",
+ "rowsText": "Lignes"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/hr.json b/imports/plugins/core/ui/server/i18n/hr.json
index 810a3f264d0..1c05cdc9f64 100644
--- a/imports/plugins/core/ui/server/i18n/hr.json
+++ b/imports/plugins/core/ui/server/i18n/hr.json
@@ -17,7 +17,20 @@
"publishThemeError": "'Ne može se objaviti temu {{themeName}}",
"components": {
"navbar": "Nalazite se ovdje",
- "button": "Dugme"
+ "button": "Dugme",
+ "sortableTable": {
+ "filterPlaceholder": "Filtriranje podataka",
+ "tableText": {
+ "noDataMessage": "nisu pronađeni rezultati",
+ "previousText": "Prethodna",
+ "nextText": "Sljedeće",
+ "loadingText": "Učitavanje ...",
+ "noDataText": "nisu pronađeni rezultati",
+ "pageText": "Stranica",
+ "ofText": "od",
+ "rowsText": "redovi"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/hu.json b/imports/plugins/core/ui/server/i18n/hu.json
index e18d0d0f1be..db3eef746f7 100644
--- a/imports/plugins/core/ui/server/i18n/hu.json
+++ b/imports/plugins/core/ui/server/i18n/hu.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Nem sikerült a téma {{themeName}}",
"components": {
"navbar": "Navigációs sáv",
- "button": "Gomb"
+ "button": "Gomb",
+ "sortableTable": {
+ "filterPlaceholder": "adatok szűrése",
+ "tableText": {
+ "noDataMessage": "Nincs találat",
+ "previousText": "Előző",
+ "nextText": "Következő",
+ "loadingText": "Terhelés...",
+ "noDataText": "Nincs találat",
+ "pageText": "oldal",
+ "ofText": "nak,-nek",
+ "rowsText": "sorok"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/it.json b/imports/plugins/core/ui/server/i18n/it.json
index d2b7615c72e..0694d40f933 100644
--- a/imports/plugins/core/ui/server/i18n/it.json
+++ b/imports/plugins/core/ui/server/i18n/it.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Impossibile pubblicare tema {{themeName}}",
"components": {
"navbar": "Barra di navigazione",
- "button": "Pulsante"
+ "button": "Pulsante",
+ "sortableTable": {
+ "filterPlaceholder": "Filtro Dati",
+ "tableText": {
+ "noDataMessage": "nessun risultato trovato",
+ "previousText": "Precedente",
+ "nextText": "Il Prossimo",
+ "loadingText": "Caricamento in corso ...",
+ "noDataText": "nessun risultato trovato",
+ "pageText": "Pagina",
+ "ofText": "di",
+ "rowsText": "righe"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/my.json b/imports/plugins/core/ui/server/i18n/my.json
index 975d8abecab..3347f19259c 100644
--- a/imports/plugins/core/ui/server/i18n/my.json
+++ b/imports/plugins/core/ui/server/i18n/my.json
@@ -17,7 +17,20 @@
"publishThemeError": "`ဆောင်ပုဒ်ထုတ်ဝေရန်လို့မရပါ {{themeName}}",
"components": {
"navbar": "navigation ဘား",
- "button": "ကြယ်သီး"
+ "button": "ကြယ်သီး",
+ "sortableTable": {
+ "filterPlaceholder": "filter မှာ Data",
+ "tableText": {
+ "noDataMessage": "ရလဒ်များမတွေ့",
+ "previousText": "လွန်ခဲ့သော",
+ "nextText": "နောက်တစ်ခု",
+ "loadingText": "Loading ...",
+ "noDataText": "ရလဒ်များမတွေ့",
+ "pageText": "စာမျက်နှာ",
+ "ofText": "၏",
+ "rowsText": "အတန်း"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/nl.json b/imports/plugins/core/ui/server/i18n/nl.json
index 53c494afac2..cb96c21a3de 100644
--- a/imports/plugins/core/ui/server/i18n/nl.json
+++ b/imports/plugins/core/ui/server/i18n/nl.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Kon thema {{themeName}} niet publiceren",
"components": {
"navbar": "Navigatiebalk",
- "button": "Knop"
+ "button": "Knop",
+ "sortableTable": {
+ "filterPlaceholder": "Filter data",
+ "tableText": {
+ "noDataMessage": "geen resultaten gevonden",
+ "previousText": "Vorig",
+ "nextText": "Volgende",
+ "loadingText": "Laden ...",
+ "noDataText": "geen resultaten gevonden",
+ "pageText": "Pagina",
+ "ofText": "van",
+ "rowsText": "rijen"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/pl.json b/imports/plugins/core/ui/server/i18n/pl.json
index 7a5b3dee7be..5f135205ae8 100644
--- a/imports/plugins/core/ui/server/i18n/pl.json
+++ b/imports/plugins/core/ui/server/i18n/pl.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Nie można opublikować tematu {{themeName}}",
"components": {
"navbar": "Pasek nawigacyjny",
- "button": "Przycisk"
+ "button": "Przycisk",
+ "sortableTable": {
+ "filterPlaceholder": "Filtruj dane",
+ "tableText": {
+ "noDataMessage": "Nie znaleziono wyników",
+ "previousText": "Poprzedni",
+ "nextText": "Następny",
+ "loadingText": "Ładowanie ...",
+ "noDataText": "Nie znaleziono wyników",
+ "pageText": "Strona",
+ "ofText": "z",
+ "rowsText": "wydziwianie"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/pt.json b/imports/plugins/core/ui/server/i18n/pt.json
index 0fa8d872cfc..676673b966f 100644
--- a/imports/plugins/core/ui/server/i18n/pt.json
+++ b/imports/plugins/core/ui/server/i18n/pt.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Não foi possível publicar {{themeName}} tema",
"components": {
"navbar": "Barra de navegação",
- "button": "Botão"
+ "button": "Botão",
+ "sortableTable": {
+ "filterPlaceholder": "Dados do filtro",
+ "tableText": {
+ "noDataMessage": "Nenhum resultado encontrado",
+ "previousText": "Anterior",
+ "nextText": "Next",
+ "loadingText": "Carregando...",
+ "noDataText": "Nenhum resultado encontrado",
+ "pageText": "Página",
+ "ofText": "de",
+ "rowsText": "Linhas"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/ro.json b/imports/plugins/core/ui/server/i18n/ro.json
index 42e822c220b..3a0f04814cd 100644
--- a/imports/plugins/core/ui/server/i18n/ro.json
+++ b/imports/plugins/core/ui/server/i18n/ro.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Nu am putut publica tema {{themeName}}",
"components": {
"navbar": "Bară de navigare",
- "button": "Buton"
+ "button": "Buton",
+ "sortableTable": {
+ "filterPlaceholder": "Filtrați datele",
+ "tableText": {
+ "noDataMessage": "Nici un rezultat gasit",
+ "previousText": "Anterior",
+ "nextText": "Următorul",
+ "loadingText": "Loading ...",
+ "noDataText": "Nici un rezultat gasit",
+ "pageText": "Pagină",
+ "ofText": "de",
+ "rowsText": "rânduri"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/ru.json b/imports/plugins/core/ui/server/i18n/ru.json
index c182c9d8fdd..1c8dbb3cd4a 100644
--- a/imports/plugins/core/ui/server/i18n/ru.json
+++ b/imports/plugins/core/ui/server/i18n/ru.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Не удалось опубликовать тему {{themeName}}",
"components": {
"navbar": "Панель навигации",
- "button": "кнопка"
+ "button": "кнопка",
+ "sortableTable": {
+ "filterPlaceholder": "Данные фильтра",
+ "tableText": {
+ "noDataMessage": "результатов не найдено",
+ "previousText": "Предыдущий",
+ "nextText": "Следующий",
+ "loadingText": "Загрузка ...",
+ "noDataText": "результатов не найдено",
+ "pageText": "страница",
+ "ofText": "из",
+ "rowsText": "строки"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/sl.json b/imports/plugins/core/ui/server/i18n/sl.json
index 029f447f8dc..34fc3d21ef5 100644
--- a/imports/plugins/core/ui/server/i18n/sl.json
+++ b/imports/plugins/core/ui/server/i18n/sl.json
@@ -17,7 +17,20 @@
"publishThemeError": "'Ni bilo mogoče objaviti temo {{themeName}}",
"components": {
"navbar": "Navigation Bar",
- "button": "Button"
+ "button": "Button",
+ "sortableTable": {
+ "filterPlaceholder": "filter podatkov",
+ "tableText": {
+ "noDataMessage": "Ni zadetkov",
+ "previousText": "Prejšnja",
+ "nextText": "Naslednja",
+ "loadingText": "Nalaganje ...",
+ "noDataText": "Ni zadetkov",
+ "pageText": "stran",
+ "ofText": "za",
+ "rowsText": "vrstice"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/sv.json b/imports/plugins/core/ui/server/i18n/sv.json
index 8ed22864cea..3f6b167d4e4 100644
--- a/imports/plugins/core/ui/server/i18n/sv.json
+++ b/imports/plugins/core/ui/server/i18n/sv.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Det gick inte att publicera tema {{themeName}}",
"components": {
"navbar": "Navigeringsfält",
- "button": "Knapp"
+ "button": "Knapp",
+ "sortableTable": {
+ "filterPlaceholder": "Filtrera data",
+ "tableText": {
+ "noDataMessage": "Inga resultat funna",
+ "previousText": "Tidigare",
+ "nextText": "Nästa",
+ "loadingText": "Hämtar ...",
+ "noDataText": "Inga resultat funna",
+ "pageText": "Sida",
+ "ofText": "av",
+ "rowsText": "rader"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/tr.json b/imports/plugins/core/ui/server/i18n/tr.json
index e86e0a5e6f2..a1665fc5d45 100644
--- a/imports/plugins/core/ui/server/i18n/tr.json
+++ b/imports/plugins/core/ui/server/i18n/tr.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Tema {{themeName}} yayınlamak Could not",
"components": {
"navbar": "Gezinti çubuğu",
- "button": "düğme"
+ "button": "düğme",
+ "sortableTable": {
+ "filterPlaceholder": "Verileri Filtreleme",
+ "tableText": {
+ "noDataMessage": "Sonuç bulunamadı",
+ "previousText": "Önceki",
+ "nextText": "Sonraki",
+ "loadingText": "Yükleniyor ...",
+ "noDataText": "Sonuç bulunamadı",
+ "pageText": "Sayfa",
+ "ofText": "arasında",
+ "rowsText": "satırlar"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/vi.json b/imports/plugins/core/ui/server/i18n/vi.json
index 338d6a29d1a..3e568967b8b 100644
--- a/imports/plugins/core/ui/server/i18n/vi.json
+++ b/imports/plugins/core/ui/server/i18n/vi.json
@@ -17,7 +17,20 @@
"publishThemeError": "`Không thể xuất bản chủ đề {{themeName}}",
"components": {
"navbar": "Thanh điều hướng",
- "button": "nút"
+ "button": "nút",
+ "sortableTable": {
+ "filterPlaceholder": "Lọc dữ liệu",
+ "tableText": {
+ "noDataMessage": "không có kết quả nào được tìm thấy",
+ "previousText": "Trước",
+ "nextText": "Kế tiếp",
+ "loadingText": "Tải...",
+ "noDataText": "không có kết quả nào được tìm thấy",
+ "pageText": "Trang",
+ "ofText": "Của",
+ "rowsText": "Hàng"
+ }
+ }
}
}
}
diff --git a/imports/plugins/core/ui/server/i18n/zh.json b/imports/plugins/core/ui/server/i18n/zh.json
index 96818298180..c9988584b83 100644
--- a/imports/plugins/core/ui/server/i18n/zh.json
+++ b/imports/plugins/core/ui/server/i18n/zh.json
@@ -17,7 +17,20 @@
"publishThemeError": "`无法发布主题{{themeName}}",
"components": {
"navbar": "导航栏",
- "button": "按键"
+ "button": "按键",
+ "sortableTable": {
+ "filterPlaceholder": "过滤数据",
+ "tableText": {
+ "noDataMessage": "未找到结果",
+ "previousText": "上一页",
+ "nextText": "下一个",
+ "loadingText": "加载中...",
+ "noDataText": "未找到结果",
+ "pageText": "页",
+ "ofText": "的",
+ "rowsText": "行"
+ }
+ }
}
}
}
diff --git a/imports/plugins/included/default-theme/client/styles/tagNav.less b/imports/plugins/included/default-theme/client/styles/tagNav.less
index 1297aa589bc..404a6bd8522 100644
--- a/imports/plugins/included/default-theme/client/styles/tagNav.less
+++ b/imports/plugins/included/default-theme/client/styles/tagNav.less
@@ -294,7 +294,7 @@
}
.rui.tagnav .navbar-item {
- height: 100%;
+ height: @navbar-height;
}
.rui.tagnav.vertical .navbar-item {
diff --git a/imports/plugins/included/default-theme/client/styles/textfield.less b/imports/plugins/included/default-theme/client/styles/textfield.less
index 772efe661ef..54b7c8cbd56 100644
--- a/imports/plugins/included/default-theme/client/styles/textfield.less
+++ b/imports/plugins/included/default-theme/client/styles/textfield.less
@@ -40,3 +40,11 @@
border: 1px solid @border-color;
border-radius: @input-border-radius;
}
+
+.rui.textfield.has-error input {
+ border-color: @rui-danger;
+}
+
+.rui.textfield.help-text input {
+ border-color: @state-danger-border
+}
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/ar.json b/imports/plugins/included/product-detail-simple/server/i18n/ar.json
index 1970eff6745..ea18cf1a71d 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/ar.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/ar.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "تم تعديل كمية المنتج الخاص بك إلى الكمية القصوى في الأوراق المالية"
+ },
+ "mediaGallery": {
+ "deleteImage": "انقر لإزالة الصورة",
+ "addedImage": "هذه صورة جديدة. نشر لحفظ التغييرات.",
+ "removedImage": "تم حذف الصورة. نشر لحفظ التغييرات."
}
},
"availableOptions": "خيارات متاحة"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/bg.json b/imports/plugins/included/product-detail-simple/server/i18n/bg.json
index ed7e7d7504e..9fee484275f 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/bg.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/bg.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Вашият продукт количество бе коригиран до макс количество на склад"
+ },
+ "mediaGallery": {
+ "deleteImage": "Кликнете, за да премахнете изображението",
+ "addedImage": "Това е ново изображение. Публикуване, за да запазите промените.",
+ "removedImage": "Изображението бе изтрито. Публикуване, за да запазите промените."
}
},
"availableOptions": "Налични варианти"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/cs.json b/imports/plugins/included/product-detail-simple/server/i18n/cs.json
index 011a5bec26e..1f1389648c9 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/cs.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/cs.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Váš množství produktu byla upravena tak, aby max množství na skladě"
+ },
+ "mediaGallery": {
+ "deleteImage": "Klepnutím odeberete obrázek",
+ "addedImage": "Toto je nový obrázek. Publikujte, chcete-li uložit změny.",
+ "removedImage": "Obrázek byl smazán. Publikujte, chcete-li uložit změny."
}
},
"availableOptions": "dostupné možnosti"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/de.json b/imports/plugins/included/product-detail-simple/server/i18n/de.json
index b4e1332c113..8b2737e5f56 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/de.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/de.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Ihre Produktmenge wurde die Höchstmenge eingestellt auf Lager"
+ },
+ "mediaGallery": {
+ "deleteImage": "Klicken Sie, um das Bild zu entfernen",
+ "addedImage": "Dies ist ein neues Bild. Veröffentlichen, um Änderungen zu speichern.",
+ "removedImage": "Bild wurde gelöscht. Veröffentlichen, um Änderungen zu speichern."
}
},
"availableOptions": "Verfügbare Optionen"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/el.json b/imports/plugins/included/product-detail-simple/server/i18n/el.json
index bee39e538ed..7f6b0f10466 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/el.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/el.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "ποσότητα του προϊόντος σας έχει ρυθμιστεί στο μέγιστο ποσότητα στο απόθεμα"
+ },
+ "mediaGallery": {
+ "deleteImage": "Κάντε κλικ για να αφαιρέσετε την εικόνα",
+ "addedImage": "Αυτή είναι μια νέα εικόνα. Δημοσιεύστε για να αποθηκεύσετε τις αλλαγές.",
+ "removedImage": "Η εικόνα έχει διαγραφεί. Δημοσιεύστε για να αποθηκεύσετε τις αλλαγές."
}
},
"availableOptions": "διαθέσιμες Επιλογές"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/es.json b/imports/plugins/included/product-detail-simple/server/i18n/es.json
index d1ea84fd01b..b3a7234454c 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/es.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/es.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Su cantidad de producto se ha ajustado a la cantidad máxima en stock"
+ },
+ "mediaGallery": {
+ "deleteImage": "Haga clic para eliminar la imagen",
+ "addedImage": "Esta es una nueva imagen. Publicar para guardar los cambios.",
+ "removedImage": "Se ha eliminado la imagen. Publicar para guardar los cambios."
}
},
"availableOptions": "Opciones disponibles"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/fr.json b/imports/plugins/included/product-detail-simple/server/i18n/fr.json
index b97cf697df3..8c7562054c0 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/fr.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/fr.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Votre quantité de produit a été ajustée à la quantité maximale en stock"
+ },
+ "mediaGallery": {
+ "deleteImage": "Cliquez pour supprimer l'image",
+ "addedImage": "C'est une nouvelle image. Publiez pour enregistrer les modifications.",
+ "removedImage": "L'image a été supprimée. Publiez pour enregistrer les modifications."
}
},
"availableOptions": "Options disponibles"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/hr.json b/imports/plugins/included/product-detail-simple/server/i18n/hr.json
index 0a6bb2b5ccf..b88edbc0905 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/hr.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/hr.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Vaš proizvod količina je prilagođena max količini na lageru"
+ },
+ "mediaGallery": {
+ "deleteImage": "Kliknite da biste uklonili sliku",
+ "addedImage": "Ovo je nova slika. Objavi za spremanje promjena.",
+ "removedImage": "Slika je izbrisana. Objavi za spremanje promjena."
}
},
"availableOptions": "Dostupne opcije"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/hu.json b/imports/plugins/included/product-detail-simple/server/i18n/hu.json
index 5138b65f40e..8a1cdda3184 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/hu.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/hu.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "A termék mennyisége állították be a max mennyiség raktáron"
+ },
+ "mediaGallery": {
+ "deleteImage": "Kattintson a kép eltávolítása",
+ "addedImage": "Ez egy új képet. Adja változások mentéséhez.",
+ "removedImage": "Képet törölték. Adja változások mentéséhez."
}
},
"availableOptions": "elérhető opciók"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/it.json b/imports/plugins/included/product-detail-simple/server/i18n/it.json
index ab5e2bc5b4d..eaab691bad3 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/it.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/it.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "La vostra quantità di prodotto è stato adattato per la quantità massima in magazzino"
+ },
+ "mediaGallery": {
+ "deleteImage": "Fare clic per rimuovere l'immagine",
+ "addedImage": "Questa è una nuova immagine. Pubblica per salvare le modifiche.",
+ "removedImage": "L'immagine è stata cancellata. Pubblica per salvare le modifiche."
}
},
"availableOptions": "Opzioni disponibili"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/my.json b/imports/plugins/included/product-detail-simple/server/i18n/my.json
index fc0be4a08c8..64250adda5d 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/my.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/my.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "သင့်ရဲ့ကုန်ပစ္စည်းအရေအတွက်စတော့ရှယ်ယာအတွက် max ကိုအရေအတွက်မှချိန်ညှိထားပြီး"
+ },
+ "mediaGallery": {
+ "deleteImage": "image ကိုဖယ်ရှားပစ်ရန်ကလစ်နှိပ်ပါ",
+ "addedImage": "ဒါကအသစ်တခုပုံရိပ်ဖြစ်ပါတယ်။ အပြောင်းအလဲများကိုကယ်ဖို့ Publish ။",
+ "removedImage": "Image ကိုဖျက်ထားသည်။ အပြောင်းအလဲများကိုကယ်ဖို့ Publish ။"
}
},
"availableOptions": "ရရှိနိုင် Options ကို"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/nl.json b/imports/plugins/included/product-detail-simple/server/i18n/nl.json
index 6cd0fae4367..f5268831a2f 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/nl.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/nl.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Uw product hoeveelheid is aangepast aan de maximale hoeveelheid in voorraad"
+ },
+ "mediaGallery": {
+ "deleteImage": "Klik om de afbeelding te verwijderen",
+ "addedImage": "Dit is een nieuwe afbeelding. Publiceer om wijzigingen op te slaan.",
+ "removedImage": "Afbeelding is verwijderd. Publiceer om wijzigingen op te slaan."
}
},
"availableOptions": "Beschikbare opties"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/pl.json b/imports/plugins/included/product-detail-simple/server/i18n/pl.json
index 41f28553985..2be203cfd23 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/pl.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/pl.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Twoja ilość produktów została dostosowana do maksymalnej ilości w magazynie"
+ },
+ "mediaGallery": {
+ "deleteImage": "Kliknij, aby usunąć obraz",
+ "addedImage": "To jest nowy wizerunek. Opublikuj, aby zapisać zmiany.",
+ "removedImage": "Obraz został usunięty. Opublikuj, aby zapisać zmiany."
}
},
"availableOptions": "Dostępne opcje"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/pt.json b/imports/plugins/included/product-detail-simple/server/i18n/pt.json
index 40b5e6d8416..6c986074210 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/pt.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/pt.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Sua quantidade de produto foi ajustado para a quantidade máxima em estoque"
+ },
+ "mediaGallery": {
+ "deleteImage": "Clique para remover a imagem",
+ "addedImage": "Esta é uma nova imagem. Publique para salvar as alterações.",
+ "removedImage": "A imagem foi excluída. Publique para salvar as alterações."
}
},
"availableOptions": "Opções disponíveis"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/ro.json b/imports/plugins/included/product-detail-simple/server/i18n/ro.json
index ec1b6df3ad7..be649a3dd99 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/ro.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/ro.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Cantitatea dvs. de produs a fost ajustat la cantitatea maximă în stoc"
+ },
+ "mediaGallery": {
+ "deleteImage": "Faceți clic pentru a elimina imaginea",
+ "addedImage": "Aceasta este o imagine nouă. Publicați pentru a salva modificările.",
+ "removedImage": "Imaginea a fost ștearsă. Publicați pentru a salva modificările."
}
},
"availableOptions": "Opțiuni disponibile"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/ru.json b/imports/plugins/included/product-detail-simple/server/i18n/ru.json
index d3b9cd6ab35..40fa6ae4842 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/ru.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/ru.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Ваше количество продукта было скорректировано до максимального количества в наличии"
+ },
+ "mediaGallery": {
+ "deleteImage": "Нажмите, чтобы удалить изображение",
+ "addedImage": "Это новый образ. Публикация для сохранения изменений.",
+ "removedImage": "Изображение удалено. Публикация для сохранения изменений."
}
},
"availableOptions": "Доступные опции"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/sl.json b/imports/plugins/included/product-detail-simple/server/i18n/sl.json
index dfd476ef71f..8ce59648e04 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/sl.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/sl.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Vaš količina izdelka je bil prilagojen za maksimalno količino na zalogi"
+ },
+ "mediaGallery": {
+ "deleteImage": "Kliknite, da odstranite sliko",
+ "addedImage": "To je nova podoba. Objavi, da shranite spremembe.",
+ "removedImage": "Slika je bila izbrisana. Objavi, da shranite spremembe."
}
},
"availableOptions": "Opcije na voljo"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/sv.json b/imports/plugins/included/product-detail-simple/server/i18n/sv.json
index adc3b6b56a7..19014835935 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/sv.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/sv.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Din produkt mängd har justerats till max antal i lager"
+ },
+ "mediaGallery": {
+ "deleteImage": "Klicka för att ta bort bilden",
+ "addedImage": "Det här är en ny bild. Publicera för att spara ändringar.",
+ "removedImage": "Bilden har raderats. Publicera för att spara ändringar."
}
},
"availableOptions": "tillgängliga alternativ"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/tr.json b/imports/plugins/included/product-detail-simple/server/i18n/tr.json
index dc0994980de..4bae0ccd041 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/tr.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/tr.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "Ürününüz miktar stok maksimum miktara ayarlandı"
+ },
+ "mediaGallery": {
+ "deleteImage": "Resmi kaldırmak için tıklayın",
+ "addedImage": "Bu yeni bir görüntü. Değişiklikleri kaydetmek için yayınla.",
+ "removedImage": "Resim silindi. Değişiklikleri kaydetmek için yayınla."
}
},
"availableOptions": "mevcut seçenekler"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/vi.json b/imports/plugins/included/product-detail-simple/server/i18n/vi.json
index 58f24a293e2..ad240de63ee 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/vi.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/vi.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "số lượng sản phẩm của bạn đã được điều chỉnh theo số lượng tối đa trong kho"
+ },
+ "mediaGallery": {
+ "deleteImage": "Nhấp để xóa hình ảnh",
+ "addedImage": "Đây là hình ảnh mới. Xuất bản để lưu thay đổi.",
+ "removedImage": "Hình ảnh đã bị xóa. Xuất bản để lưu thay đổi."
}
},
"availableOptions": "Tùy chọn có sẵn"
diff --git a/imports/plugins/included/product-detail-simple/server/i18n/zh.json b/imports/plugins/included/product-detail-simple/server/i18n/zh.json
index 93074855a36..ea3475f5130 100644
--- a/imports/plugins/included/product-detail-simple/server/i18n/zh.json
+++ b/imports/plugins/included/product-detail-simple/server/i18n/zh.json
@@ -9,6 +9,11 @@
},
"inventoryAlerts": {
"adjustedQuantity": "您的产品数量进行了调整,在股票的最大数量"
+ },
+ "mediaGallery": {
+ "deleteImage": "点击删除图片",
+ "addedImage": "这是一个新的形象。发布以保存更改。",
+ "removedImage": "图片已被删除。发布以保存更改。"
}
},
"availableOptions": "可用选项"
diff --git a/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.html b/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.html
index 2b500ec10ac..f9a8ab9c1e1 100644
--- a/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.html
+++ b/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.html
@@ -73,7 +73,7 @@
-
-
-
diff --git a/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.js b/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.js
index 3fbfcb2973b..2ff2057a36c 100644
--- a/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.js
+++ b/imports/plugins/included/product-variant/client/templates/products/productDetail/variants/variantForm/childVariant.js
@@ -1,19 +1,37 @@
import { $ } from "meteor/jquery";
import { Template } from "meteor/templating";
import { Meteor } from "meteor/meteor";
+import { ReactiveDict } from "meteor/reactive-dict";
import { Reaction, i18next } from "/client/api";
import { ReactionProduct } from "/lib/api";
import { Media } from "/lib/collections";
import { Icon } from "/imports/plugins/core/ui/client/components";
+import { Validation } from "@reactioncommerce/reaction-collections";
+import { ProductVariant } from "/lib/collections/schemas/products";
function productHandle() {
const selectedProduct = ReactionProduct.selectedProduct();
return selectedProduct.__published && selectedProduct.__published.handle || selectedProduct.handle;
}
+
+Template.childVariantForm.onCreated(function () {
+ this.validation = new Validation(ProductVariant);
+ this.state = new ReactiveDict();
+ this.state.setDefault({
+ validationStatus: {}
+ });
+});
+
+
/**
* childVariantForm onRendered
*/
-Template.onRendered(function () {
+Template.childVariantForm.onRendered(function () {
+ const validationStatus = this.validation.validate(this.data);
+
+ this.state.set("validationStatus", validationStatus);
+ this.state.set("variant", this.data);
+
this.autorun(() => {
const selectedVariantId = Reaction.Router.getParam("variantId");
@@ -88,6 +106,26 @@ Template.childVariantForm.helpers({
}
return "panel-default";
+ },
+ hasValidationMessage(fieldName) {
+ const instance = Template.instance();
+ const validationStatus = instance.state.get("validationStatus");
+
+ if (validationStatus && validationStatus.messages && validationStatus.messages[fieldName]) {
+ return validationStatus.messages[fieldName];
+ }
+
+ return false;
+ },
+ hasErrorClassName(fieldName) {
+ const instance = Template.instance();
+ const validationStatus = instance.state.get("validationStatus");
+
+ if (validationStatus && validationStatus.messages && validationStatus.messages[fieldName]) {
+ return "has-error";
+ }
+
+ return false;
}
});
@@ -111,12 +149,25 @@ Template.childVariantForm.events({
const value = Template.instance().$(event.currentTarget).val();
const field = Template.instance().$(event.currentTarget).attr("name");
- Meteor.call("products/updateProductField", variant._id, field, value,
- error => {
- if (error) {
- Alerts.toast(error.message, "error");
- }
- });
+ const variantToValidate = template.state.get("variant") || variant;
+ const updated = {
+ ...variantToValidate,
+ [field]: value
+ };
+ const validationStatus = template.validation.validate(updated);
+
+ template.state.set("validationStatus", validationStatus);
+ template.state.set("variant", updated);
+
+ if (validationStatus.isValid === true) {
+ Meteor.call("products/updateProductField", variant._id, field, value,
+ error => {
+ if (error) {
+ Alerts.toast(error.message, "error");
+ }
+ });
+ }
+
return ReactionProduct.setCurrentVariant(variant._id);
},
"click .js-child-variant-heading": function (event, instance) {
diff --git a/imports/plugins/included/product-variant/client/templates/products/productGrid/controls.html b/imports/plugins/included/product-variant/client/templates/products/productGrid/controls.html
deleted file mode 100644
index 5b8635fa673..00000000000
--- a/imports/plugins/included/product-variant/client/templates/products/productGrid/controls.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
- {{#if hasControl }}
-
-
-
- {{#if product.isDeleted}}
-
- Archived
-
- {{/if}}
-
- {{#if hasChanges}}
-
{{> React VisibilityButton}}
- {{/if}}
-
-
- {{/if}}
-
diff --git a/imports/plugins/included/product-variant/client/templates/products/productGrid/controls.js b/imports/plugins/included/product-variant/client/templates/products/productGrid/controls.js
deleted file mode 100644
index 5fa3f16ce46..00000000000
--- a/imports/plugins/included/product-variant/client/templates/products/productGrid/controls.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import _ from "lodash";
-import { Session } from "meteor/session";
-import { Template } from "meteor/templating";
-import { ReactiveDict } from "meteor/reactive-dict";
-import { Reaction } from "/lib/api";
-import { IconButton } from "/imports/plugins/core/ui/client/components";
-
-Template.gridControls.onCreated(function () {
- this.state = new ReactiveDict();
-
- this.autorun(() => {
- if (this.data.product) {
- const selectedProducts = Session.get("productGrid/selectedProducts");
- const isSelected = _.isArray(selectedProducts) ? selectedProducts.indexOf(this.data.product._id) >= 0 : false;
-
- this.state.set("isSelected", isSelected);
- }
- });
-});
-
-Template.gridControls.onRendered(function () {
- return this.$("[data-toggle='tooltip']").tooltip({
- position: "top"
- });
-});
-
-
-Template.gridControls.helpers({
- checked: function () {
- return Template.instance().state.equals("isSelected", true);
- },
-
- isVisible() {
- const currentData = Template.currentData();
- return currentData && currentData.product && currentData.product.isVisible;
- },
-
- hasControl() {
- if (Reaction.hasOwnerAccess()) {
- return true;
- }
-
- const instance = Template.instance();
- const shopId = Reaction.getShopId();
-
- return (
- Reaction.hasPermission("createProduct") &&
- // does product belong to this shop seller
- shopId === instance.data.product.shopId
- );
- },
-
- hasChanges() {
- const { product } = Template.currentData();
- if (product.__draft) {
- return true;
- }
-
- return false;
- },
-
- VisibilityButton() {
- return {
- component: IconButton,
- icon: "",
- onIcon: "",
- status: "info"
- };
- }
-});
diff --git a/imports/plugins/included/product-variant/components/products.js b/imports/plugins/included/product-variant/components/products.js
index 8ebfdbe9dca..dc12d8b722d 100644
--- a/imports/plugins/included/product-variant/components/products.js
+++ b/imports/plugins/included/product-variant/components/products.js
@@ -69,7 +69,7 @@ class ProductsComponent extends Component {
render() {
if (this.props.ready()) {
return (
-
+
{this.renderProductGrid()}
{this.renderLoadMoreProductsButton()}
{this.renderSpinner()}
diff --git a/imports/plugins/included/product-variant/components/variantForm.js b/imports/plugins/included/product-variant/components/variantForm.js
index 3bff0a07544..09d01c36baf 100644
--- a/imports/plugins/included/product-variant/components/variantForm.js
+++ b/imports/plugins/included/product-variant/components/variantForm.js
@@ -3,7 +3,6 @@ import PropTypes from "prop-types";
import { isEqual } from "lodash";
import Velocity from "velocity-animate";
import "velocity-animate/velocity.ui";
-import update from "react/lib/update";
import { formatPriceString } from "/client/api";
import {
Button,
@@ -55,7 +54,7 @@ class VariantForm extends Component {
super(props);
this.state = {
- expandedCard: this.fieldGroupForFieldName(props.editFocus),
+ expandedCard: "variantDetails",
variant: props.variant,
inventoryPolicy: props.variant.inventoryPolicy,
taxable: props.variant.taxable,
@@ -74,10 +73,11 @@ class VariantForm extends Component {
}
}
}
- const cardGroupName = this.fieldGroupForFieldName(nextProps.editFocus);
this.setState({
- expandedCard: cardGroupName,
+ inventoryManagement: nextProps.variant.inventoryManagement,
+ inventoryPolicy: nextProps.variant.inventoryPolicy,
+ taxable: nextProps.variant.taxable,
variant: nextProps.variant
});
}
@@ -110,9 +110,11 @@ class VariantForm extends Component {
if (fieldRef) {
const input = fieldRef.refs.input;
+ const isFieldValid = this.props.validation.isFieldValid(fieldName);
+ const flashColor = isFieldValid ? "#f0fff4" : "#ffeeef";
Velocity.RunSequence([
- { e: input, p: { backgroundColor: "#e2f2e2" }, o: { duration: 200 } },
+ { e: input, p: { backgroundColor: flashColor }, o: { duration: 200 } },
{ e: input, p: { backgroundColor: "#fff" }, o: { duration: 100 } }
]);
}
@@ -123,51 +125,52 @@ class VariantForm extends Component {
}
handleFieldChange = (event, value, field) => {
- const newState = update(this.state, {
+ this.setState(({ variant }) => ({
variant: {
- $merge: {
- [field]: value
- }
+ ...variant,
+ [field]: value
}
- });
-
- this.setState(newState);
+ }));
}
handleFieldBlur = (event, value, field) => {
if (this.props.onVariantFieldSave) {
- this.props.onVariantFieldSave(this.variant._id, field, value);
+ this.props.onVariantFieldSave(this.variant._id, field, value, this.state.variant);
}
}
handleSelectChange = (value, field) => {
- this.handleFieldChange(event, value, field);
-
- if (this.props.onVariantFieldSave) {
- this.props.onVariantFieldSave(this.variant._id, field, value);
- }
+ this.setState(({ variant }) => ({
+ variant: {
+ ...variant,
+ [field]: value
+ }
+ }), () => {
+ if (this.props.onVariantFieldSave) {
+ this.props.onVariantFieldSave(this.variant._id, field, value, this.state.variant);
+ }
+ });
}
handleCheckboxChange = (event, value, field) => {
- this.setState({
- [field]: value
- });
+ this.setState(({ variant }) => ({
+ variant: {
+ ...variant,
+ [field]: value
+ }
+ }));
this.handleFieldBlur(event, value, field);
}
- handleCardExpand(cardName) {
- if (this.props.onCardExpand) {
- this.props.onCardExpand(cardName);
+ handleCardExpand = (event, card, cardName, isExpanded) => {
+ if (typeof this.props.onCardExpand === "function") {
+ this.props.onCardExpand(isExpanded ? cardName : undefined);
}
}
- isExpanded(groupName) {
- if (this.state.expandedCard && this.state.expandedCard === groupName) {
- return true;
- }
-
- return false;
+ isExpanded = (groupName) => {
+ return this.state.expandedCard === groupName;
}
renderTaxCodeField() {
@@ -198,6 +201,7 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
);
}
@@ -253,6 +257,7 @@ class VariantForm extends Component {
);
}
+
return (
);
@@ -275,8 +281,10 @@ class VariantForm extends Component {
return (
@@ -345,6 +355,7 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
@@ -362,6 +373,7 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
@@ -376,6 +388,7 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
@@ -393,6 +406,7 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
@@ -407,6 +421,7 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
@@ -416,12 +431,12 @@ class VariantForm extends Component {
{this.renderTaxCodeField()}
@@ -436,18 +451,19 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
@@ -464,6 +480,7 @@ class VariantForm extends Component {
onBlur={this.handleFieldBlur}
onChange={this.handleFieldChange}
onReturnKeyDown={this.handleFieldBlur}
+ validation={this.props.validation}
/>
@@ -477,6 +494,7 @@ class VariantForm extends Component {
onLabel={"Allow Backorder"}
checked={this.state.inventoryPolicy}
onChange={this.handleCheckboxChange}
+ validation={this.props.validation}
/>
@@ -501,6 +519,7 @@ VariantForm.propTypes = {
onVariantFieldSave: PropTypes.func,
removeVariant: PropTypes.func,
restoreVariant: PropTypes.func,
+ validation: PropTypes.object,
variant: PropTypes.object
};
diff --git a/imports/plugins/included/product-variant/containers/productsContainer.js b/imports/plugins/included/product-variant/containers/productsContainer.js
index 93448b4f7cf..6cf884ff02f 100644
--- a/imports/plugins/included/product-variant/containers/productsContainer.js
+++ b/imports/plugins/included/product-variant/containers/productsContainer.js
@@ -20,16 +20,15 @@ import ProductsComponent from "../components/products";
function loadMoreProducts() {
let threshold;
const target = document.querySelectorAll("#productScrollLimitLoader");
- let scrollContainer = document.querySelectorAll("#reactionAppContainer");
-
+ let scrollContainer = document.querySelectorAll("#container-main");
if (scrollContainer.length === 0) {
scrollContainer = window;
}
if (target.length) {
- threshold = scrollContainer[0].scrollTop + scrollContainer[0].offsetHeight - target[0].offsetHeight;
+ threshold = scrollContainer[0].scrollHeight - scrollContainer[0].scrollTop === scrollContainer[0].clientHeight;
- if (target[0].offsetTop <= threshold) {
+ if (threshold) {
if (!target[0].getAttribute("visible")) {
target[0].setAttribute("productScrollLimit", true);
Session.set("productScrollLimit", Session.get("productScrollLimit") + ITEMS_INCREMENT || 24);
@@ -115,24 +114,24 @@ function composer(props, onData) {
if (!tag && slug) {
return;
}
+ const currentTag = ReactionProduct.getTag();
+
+ const sort = {
+ [`positions.${currentTag}.position`]: 1,
+ [`positions.${currentTag}.createdAt`]: 1,
+ createdAt: 1
+ };
const queryParams = Object.assign({}, tags, Reaction.Router.current().queryParams);
- const productsSubscription = Meteor.subscribe("Products", scrollLimit, queryParams);
+ const productsSubscription = Meteor.subscribe("Products", scrollLimit, queryParams, sort);
if (productsSubscription.ready()) {
window.prerenderReady = true;
}
- const currentTag = ReactionProduct.getTag();
const productCursor = Products.find({
ancestors: [],
type: { $in: ["simple"] }
- }, {
- sort: {
- [`positions.${currentTag}.position`]: 1,
- [`positions.${currentTag}.createdAt`]: 1,
- createdAt: 1
- }
});
const products = productCursor.map((product) => {
diff --git a/imports/plugins/included/product-variant/containers/variantFormContainer.js b/imports/plugins/included/product-variant/containers/variantFormContainer.js
index c8273f13251..c044c377f10 100644
--- a/imports/plugins/included/product-variant/containers/variantFormContainer.js
+++ b/imports/plugins/included/product-variant/containers/variantFormContainer.js
@@ -10,25 +10,45 @@ import { Countries } from "/client/collections";
import { Reaction, i18next } from "/client/api";
import { TaxCodes } from "/imports/plugins/core/taxes/lib/collections";
import VariantForm from "../components/variantForm";
+import { ProductVariant } from "/lib/collections/schemas/products";
+import { Validation } from "@reactioncommerce/reaction-collections";
class VariantFormContainer extends Component {
constructor(props) {
super(props);
+ this.validation = new Validation(ProductVariant);
+
this.state = {
- isDeleted: props.variant.isDeleted
+ variant: props.variant,
+ validationStatus: this.validation.validationStatus,
+ isDeleted: props.variant && props.variant.isDeleted
};
+ }
- this.isProviderEnabled = this.isProviderEnabled.bind(this);
- this.fetchTaxCodes = this.fetchTaxCodes.bind(this);
- this.hasChildVariants = this.hasChildVariants.bind(this);
- this.greyDisabledFields = this.greyDisabledFields.bind(this);
- this.removeVariant = this.removeVariant.bind(this);
- this.restoreVariant = this.restoreVariant.bind(this);
- this.cloneVariant = this.cloneVariant.bind(this);
- this.handleVariantFieldSave = this.handleVariantFieldSave.bind(this);
- this.handleCardExpand = this.handleCardExpand.bind(this);
- this.updateQuantityIfChildVariants = this.updateQuantityIfChildVariants.bind(this);
+ componentDidMount() {
+ this.runVariantValidation(this.state.variant);
+ }
+
+ componentWillReceiveProps(nextProps) {
+ this.setState(() => ({
+ variant: nextProps.variant
+ }), () => {
+ this.runVariantValidation(this.state.variant);
+ });
+ }
+
+ runVariantValidation(variant) {
+ if (variant) {
+ const validationStatus = this.validation.validate(variant);
+
+ this.setState(() => ({
+ validationStatus,
+ variant
+ }));
+
+ return validationStatus;
+ }
}
isProviderEnabled = () => {
@@ -157,13 +177,17 @@ class VariantFormContainer extends Component {
});
}
- handleVariantFieldSave = (variantId, fieldName, value) => {
- Meteor.call("products/updateProductField", variantId, fieldName, value, (error) => {
- if (error) {
- Alerts.toast(error.message, "error");
- this.forceUpdate();
- }
- });
+ handleVariantFieldSave = (variantId, fieldName, value, variant) => {
+ const validationStatus = this.runVariantValidation(variant);
+
+ if (validationStatus.isFieldValid(fieldName)) {
+ Meteor.call("products/updateProductField", variantId, fieldName, value, (error) => {
+ if (error) {
+ Alerts.toast(error.message, "error");
+ this.forceUpdate();
+ }
+ });
+ }
}
handleCardExpand = (cardName) => {
@@ -178,40 +202,51 @@ class VariantFormContainer extends Component {
}
render() {
- return (
-
- );
+ if (this.state.variant) {
+ return (
+
+ );
+ }
+
+ return null;
}
}
function composer(props, onData) {
- const countries = Countries.find({}).fetch();
+ Meteor.subscribe("TaxCodes");
const productHandle = Reaction.Router.getParam("handle");
if (!productHandle) {
Reaction.clearActionView();
}
- Meteor.subscribe("TaxCodes");
+ const countries = Countries.find({}).fetch();
+ const variant = ReactionProduct.selectedTopVariant();
- onData(null, {
- countries,
- variant: props.variant,
- editFocus: Reaction.state.get("edit/focus")
- });
+ if (variant) {
+ onData(null, {
+ countries,
+ variant: ReactionProduct.selectedTopVariant(),
+ editFocus: Reaction.state.get("edit/focus")
+ });
+ } else {
+ onData(null, { countries });
+ }
}
VariantFormContainer.propTypes = {
diff --git a/imports/plugins/included/shippo/client/settings/shippoTableColumn.js b/imports/plugins/included/shippo/client/settings/shippoTableColumn.js
index b85748a62f3..7fb44858de3 100644
--- a/imports/plugins/included/shippo/client/settings/shippoTableColumn.js
+++ b/imports/plugins/included/shippo/client/settings/shippoTableColumn.js
@@ -2,7 +2,7 @@ import React, { Component } from "react";
import PropTypes from "prop-types";
import { Icon } from "/imports/plugins/core/ui/client/components";
-class EmailTableColumn extends Component {
+class ShippoTableColumn extends Component {
static propTypes = {
data: PropTypes.object,
row: PropTypes.object
@@ -33,4 +33,4 @@ class EmailTableColumn extends Component {
}
}
-export default EmailTableColumn;
+export default ShippoTableColumn;
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/ar.json b/imports/plugins/included/taxes-avalara/server/i18n/ar.json
index ddcb62354ff..03a586674c7 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/ar.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/ar.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "لا توجد سجلات",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "التاريخ",
+ "type": "نوع الوثيقة"
+ }
+ }
+ },
"date": "التاريخ",
"docType": "نوع الوثيقة"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/bg.json b/imports/plugins/included/taxes-avalara/server/i18n/bg.json
index e4224f6f2f4..9d758b13f3d 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/bg.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/bg.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Няма намерени трупи",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Дата",
+ "type": "тип на документа"
+ }
+ }
+ },
"date": "Дата",
"docType": "тип на документа"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/cs.json b/imports/plugins/included/taxes-avalara/server/i18n/cs.json
index 4281489aa58..454b4fa6ee9 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/cs.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/cs.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Nebyly nalezeny žádné protokoly",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Datum",
+ "type": "Typ dokumentu"
+ }
+ }
+ },
"date": "Datum",
"docType": "Typ dokumentu"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/de.json b/imports/plugins/included/taxes-avalara/server/i18n/de.json
index 33dd382275a..a0477f508b7 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/de.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/de.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Keine Protokolle gefunden",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Datum",
+ "type": "Dokumenttyp"
+ }
+ }
+ },
"date": "Datum",
"docType": "Dokumenttyp"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/el.json b/imports/plugins/included/taxes-avalara/server/i18n/el.json
index bf80930d69c..88b54ca5d27 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/el.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/el.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Δεν κούτσουρα που βρέθηκαν",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Ημερομηνία",
+ "type": "Είδος αρχείου"
+ }
+ }
+ },
"date": "Ημερομηνία",
"docType": "Είδος αρχείου"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/es.json b/imports/plugins/included/taxes-avalara/server/i18n/es.json
index 6ccaf027bf2..bd9fa1134cd 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/es.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/es.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "No se encontraron registros",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Fecha",
+ "type": "Tipo De Documento"
+ }
+ }
+ },
"date": "Fecha",
"docType": "Tipo De Documento"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/fr.json b/imports/plugins/included/taxes-avalara/server/i18n/fr.json
index f00bd8f96b2..d382f92595e 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/fr.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/fr.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Aucun journal trouvé",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Date",
+ "type": "Type de document"
+ }
+ }
+ },
"date": "Date",
"docType": "Type de document"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/he.json b/imports/plugins/included/taxes-avalara/server/i18n/he.json
index fd19ff15dfc..5824101fe82 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/he.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/he.json
@@ -10,6 +10,13 @@
},
"logGrid": {
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "תאריך"
+ }
+ }
+ },
"date": "תאריך"
}
},
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/hr.json b/imports/plugins/included/taxes-avalara/server/i18n/hr.json
index cbbc31a1241..890fcb5c7b6 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/hr.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/hr.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Zapisi nisu pronađeni",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Rok",
+ "type": "vrsta dokumenta"
+ }
+ }
+ },
"date": "Rok",
"docType": "vrsta dokumenta"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/hu.json b/imports/plugins/included/taxes-avalara/server/i18n/hu.json
index 8c462466b8d..1177b8d1132 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/hu.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/hu.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Nem találhatók naplók",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Dátum",
+ "type": "dokumentum típus"
+ }
+ }
+ },
"date": "Dátum",
"docType": "dokumentum típus"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/it.json b/imports/plugins/included/taxes-avalara/server/i18n/it.json
index 6a171e9da5d..2d453c92b52 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/it.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/it.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Nessun log trovato",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Data",
+ "type": "tipo di documento"
+ }
+ }
+ },
"date": "Data",
"docType": "tipo di documento"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/my.json b/imports/plugins/included/taxes-avalara/server/i18n/my.json
index 4bd8c3183d5..bc2b9f965b4 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/my.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/my.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "သစ်လုံးများမတွေ့ပါ",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "နေ့စှဲ",
+ "type": "စာရွက်စာတမ်းအမျိုးအစား"
+ }
+ }
+ },
"date": "နေ့စှဲ",
"docType": "စာရွက်စာတမ်းအမျိုးအစား"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/nl.json b/imports/plugins/included/taxes-avalara/server/i18n/nl.json
index 384ddf7991b..e918c7774f2 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/nl.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/nl.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Geen logs gevonden",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Datum",
+ "type": "type document"
+ }
+ }
+ },
"date": "Datum",
"docType": "type document"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/pl.json b/imports/plugins/included/taxes-avalara/server/i18n/pl.json
index ecd47e320e5..ce9b453b1a3 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/pl.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/pl.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Nie znaleziono dzienników",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Data",
+ "type": "typ dokumentu"
+ }
+ }
+ },
"date": "Data",
"docType": "typ dokumentu"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/pt.json b/imports/plugins/included/taxes-avalara/server/i18n/pt.json
index bf0f01c2141..f704808dc25 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/pt.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/pt.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Não foram encontrados registos",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Data",
+ "type": "tipo de documento"
+ }
+ }
+ },
"date": "Data",
"docType": "tipo de documento"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/ro.json b/imports/plugins/included/taxes-avalara/server/i18n/ro.json
index 56d4c7a2f6e..bd6478807d3 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/ro.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/ro.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Nu au fost găsite jurnale",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Data",
+ "type": "Tipul documentului"
+ }
+ }
+ },
"date": "Data",
"docType": "Tipul documentului"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/ru.json b/imports/plugins/included/taxes-avalara/server/i18n/ru.json
index 2dcc53f9b72..43573c76825 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/ru.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/ru.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Не найдено ни одного бревна",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Дата",
+ "type": "тип документа"
+ }
+ }
+ },
"date": "Дата",
"docType": "тип документа"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/sl.json b/imports/plugins/included/taxes-avalara/server/i18n/sl.json
index 76a15b2a2e1..788a78636a4 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/sl.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/sl.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Ni dnevniki",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Datum",
+ "type": "Vrsta dokumenta"
+ }
+ }
+ },
"date": "Datum",
"docType": "Vrsta dokumenta"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/sv.json b/imports/plugins/included/taxes-avalara/server/i18n/sv.json
index a4381769c42..9e2ec341c4f 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/sv.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/sv.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Inga loggar hittades",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Datum",
+ "type": "Dokumenttyp"
+ }
+ }
+ },
"date": "Datum",
"docType": "Dokumenttyp"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/tr.json b/imports/plugins/included/taxes-avalara/server/i18n/tr.json
index ffdd654d944..6a113dd2f8f 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/tr.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/tr.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Hiçbir günlükleri bulundu",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Tarih",
+ "type": "Belge Türü"
+ }
+ }
+ },
"date": "Tarih",
"docType": "Belge Türü"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/vi.json b/imports/plugins/included/taxes-avalara/server/i18n/vi.json
index fc3407e1a4f..9afd781931a 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/vi.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/vi.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "Không tìm thấy nhật ký",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "Ngày",
+ "type": "loại tài liệu"
+ }
+ }
+ },
"date": "Ngày",
"docType": "loại tài liệu"
}
diff --git a/imports/plugins/included/taxes-avalara/server/i18n/zh.json b/imports/plugins/included/taxes-avalara/server/i18n/zh.json
index 4f9a26ecc62..288d79e71f0 100644
--- a/imports/plugins/included/taxes-avalara/server/i18n/zh.json
+++ b/imports/plugins/included/taxes-avalara/server/i18n/zh.json
@@ -26,6 +26,14 @@
"logGrid": {
"noLogsFound": "没有找到记录",
"columns": {
+ "data": {
+ "request": {
+ "data": {
+ "date": "日期",
+ "type": "文件类型"
+ }
+ }
+ },
"date": "日期",
"docType": "文件类型"
}
diff --git a/lib/api/products.js b/lib/api/products.js
index c2dbd5c101e..d4dfc49cc6e 100644
--- a/lib/api/products.js
+++ b/lib/api/products.js
@@ -53,6 +53,15 @@ export function applyProductRevision(product) {
return null;
}
+export function variantIsSelected(variantId) {
+ const current = ReactionProduct.selectedVariant();
+ if (current && typeof current === "object" && (variantId === current._id || ~current.ancestors.indexOf(variantId))) {
+ return true;
+ }
+
+ return false;
+}
+
ReactionProduct.sortProducts = (products, tag) => {
let sorted = [];
@@ -176,6 +185,18 @@ ReactionProduct.selectedVariant = function () {
return [];
};
+/**
+ * selectedTopVariant
+ * @summary get the currently active TOP variant object
+ * @return {Object} currently selected TOP variant object
+ */
+ReactionProduct.selectedTopVariant = function () {
+ const topVariants = ReactionProduct.getTopVariants();
+ const topVariant = topVariants.find((variant) => variantIsSelected(variant._id));
+
+ return topVariant;
+};
+
/**
* selectedProduct
* @summary get the currently active/requested product object
diff --git a/package.json b/package.json
index 85e01f8e87a..a367db8fe24 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "reaction",
"description": "Reaction is a modern reactive, real-time event driven ecommerce platform.",
- "version": "1.3.0",
+ "version": "1.4.0",
"main": "main.js",
"directories": {
"test": "tests"
@@ -103,7 +103,7 @@
"swiper": "^3.4.2",
"tether-drop": "^1.4.2",
"tether-tooltip": "^1.2.0",
- "transliteration": "1.6.2",
+ "transliteration": "github:reactioncommerce/transliteration",
"twilio": "^3.4.0",
"url": "^0.11.0",
"velocity-animate": "^1.5.0",
@@ -151,8 +151,7 @@
},
"babel": {
"plugins": [
- "lodash",
- [
+ "lodash", [
"module-resolver",
{
"root": [
@@ -161,7 +160,8 @@
"alias": {
"underscore": "lodash",
"@reactioncommerce/reaction-ui": "./imports/plugins/core/ui/client/components",
- "@reactioncommerce/reaction-router": "./imports/plugins/core/router/lib"
+ "@reactioncommerce/reaction-router": "./imports/plugins/core/router/lib",
+ "@reactioncommerce/reaction-collections": "./imports/plugins/core/collections"
}
}
]
diff --git a/private/data/i18n/ar.json b/private/data/i18n/ar.json
index bb862b340a0..eb63398ddab 100644
--- a/private/data/i18n/ar.json
+++ b/private/data/i18n/ar.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "تفاصيل الطلب",
"invoice": "فاتورة",
+ "lineItems": "بنود الخط",
"shipmentTracking": "تتبع الشحنة"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "تعديل هذا العنوان ",
"addressValidation": "عنوان التحقق من صحة",
- "somethingWentWrong": "حدث خطأ ما: {{err}}"
+ "reviewAddress": "للحصول على أفضل توافق، يرجى التحقق من صحة عنوانك",
+ "somethingWentWrong": "حدث خطأ ما: {{err}}",
+ "enteredAddress": "أدخل عنوان",
+ "validatedAddress": "التحقق من العنوان"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "البريد الالكترونى لا يتوافق مع الشروط",
"errorSendingEmail": ".خطأ في إرسال رسالة الكترونية، من المحتمل أن تكون مشكلة في التهيئة",
"unableToSendInvitationEmail": "لا يمكن ارسال دعوات إلكترونية",
+ "userWithEmailAlreadyExists": "يوجد مستخدم لديه عنوان البريد الإلكتروني هذا بالفعل",
"failedToLogout": "فشل في تسجيل الخروج",
"invalidLoginToken": "رمز الدخول غير صالح",
"loginForbidden": "تسجيل الدخول غير مسموح",
diff --git a/private/data/i18n/bg.json b/private/data/i18n/bg.json
index 2b0af042f01..96aaec0f50a 100644
--- a/private/data/i18n/bg.json
+++ b/private/data/i18n/bg.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "подробности за поръчката",
"invoice": "фактура",
+ "lineItems": "Редните елементи",
"shipmentTracking": "пратка проследяване"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Редактирайте адреса",
"addressValidation": "Адрес за потвърждаване",
- "somethingWentWrong": "Нещо се обърка: {{err}}"
+ "reviewAddress": "За най-добро съответствие, моля, потвърдете адреса си",
+ "somethingWentWrong": "Нещо се обърка: {{err}}",
+ "enteredAddress": "Въведеният адрес",
+ "validatedAddress": "Потвърдете адреса"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Имейл адресът не покрива критериите.",
"errorSendingEmail": "Грешка при изпращане на имейл, възможно въпрос конфигурация.",
"unableToSendInvitationEmail": "Не може да се изпрати покана по имейл.",
+ "userWithEmailAlreadyExists": "Потребител с този имейл адрес вече съществува",
"failedToLogout": "Неуспех да излезете.",
"invalidLoginToken": "Невалиден вход",
"loginForbidden": "Входът е забранен",
diff --git a/private/data/i18n/cs.json b/private/data/i18n/cs.json
index 8561cff1d67..9965b8ac6f4 100644
--- a/private/data/i18n/cs.json
+++ b/private/data/i18n/cs.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Podrobnosti o objednávce",
"invoice": "Faktura",
+ "lineItems": "Řádkové položky",
"shipmentTracking": "Sledování zásilky"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Úpravou tohoto zadání adresy",
"addressValidation": "Ověření adresy",
- "somethingWentWrong": "Něco se pokazilo: {{err}}"
+ "reviewAddress": "Pro dosažení nejlepšího souladu ověřte svou adresu",
+ "somethingWentWrong": "Něco se pokazilo: {{err}}",
+ "enteredAddress": "Zadaná adresa",
+ "validatedAddress": "Ověřte adresu"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Email nesplňuje požadavky.",
"errorSendingEmail": "Chyba při odesílání e-mailu, možnost konfigurace problém.",
"unableToSendInvitationEmail": "Nelze odeslat e-mailem pozvánku.",
+ "userWithEmailAlreadyExists": "Uživatel s touto e-mailovou adresou již existuje",
"failedToLogout": "Nepodařilo se odhlásit.",
"invalidLoginToken": "Neplatný přihlašovací token",
"loginForbidden": "Přihlášení je zakázáno",
diff --git a/private/data/i18n/de.json b/private/data/i18n/de.json
index 7869a242341..22ba2100af8 100644
--- a/private/data/i18n/de.json
+++ b/private/data/i18n/de.json
@@ -673,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Das Format der E-Mail-Adresse ist falsch.",
"errorSendingEmail": "Fehler beim Senden der E-Mail, möglicherweise infolge eines Konfigurationsproblems.",
"unableToSendInvitationEmail": "Die Einladungs-E-Mail konnte nicht gesendet werden.",
+ "userWithEmailAlreadyExists": "Ein Benutzer mit dieser E-Mail-Adresse existiert bereits",
"failedToLogout": "Die Abmeldung ist fehlgeschlagen.",
"invalidLoginToken": "Ungültiges Login-Token",
"loginForbidden": "Login nicht zulässig",
diff --git a/private/data/i18n/el.json b/private/data/i18n/el.json
index aaccd856159..ba86cd30e06 100644
--- a/private/data/i18n/el.json
+++ b/private/data/i18n/el.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Λεπτομέρειες Παραγγελίας",
"invoice": "Τιμολόγιο",
+ "lineItems": "Στοιχεία γραμμής",
"shipmentTracking": "Παρακολούθηση αποστολής"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Επεξεργασία διεύθυνσης",
"addressValidation": "διεύθυνση Επικύρωση",
- "somethingWentWrong": "Κάτι πήγε στραβά: {{err}}"
+ "reviewAddress": "Για καλύτερη συμμόρφωση, επικυρώστε τη διεύθυνσή σας",
+ "somethingWentWrong": "Κάτι πήγε στραβά: {{err}}",
+ "enteredAddress": "Εισαγωγή Διεύθυνσης",
+ "validatedAddress": "Επικύρωση διεύθυνσης"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Το email δεν είναι συμβατό.",
"errorSendingEmail": "Σφάλμα κατά την αποστολή e-mail, είναι δυνατόν το ζήτημα διαμόρφωσης.",
"unableToSendInvitationEmail": "Δεν μπορεί να στείλει email πρόσκλησης.",
+ "userWithEmailAlreadyExists": "Ένας χρήστης με αυτήν τη διεύθυνση ηλεκτρονικού ταχυδρομείου υπάρχει ήδη",
"failedToLogout": "Αποτυχία να αποσυνδεθείτε.",
"invalidLoginToken": "Λάθος token σύνδεσης",
"loginForbidden": "Η σύνδεση απαγορεύεται",
diff --git a/private/data/i18n/en.json b/private/data/i18n/en.json
index 251e4640709..ca8757a8785 100644
--- a/private/data/i18n/en.json
+++ b/private/data/i18n/en.json
@@ -549,6 +549,7 @@
"facebook": "Facebook",
"google": "Google",
"github": "GitHub",
+ "instagram": "Instagram",
"meetup": "Meetup",
"ok": "Ok",
"twitter": "Twitter",
diff --git a/private/data/i18n/es.json b/private/data/i18n/es.json
index 658cffbf7c0..3df99ed2087 100644
--- a/private/data/i18n/es.json
+++ b/private/data/i18n/es.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Información de envío",
"invoice": "Factura",
+ "lineItems": "Artículos de línea",
"shipmentTracking": "Seguimiento de envío"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Editar esta dirección",
"addressValidation": "La validación de direcciones",
- "somethingWentWrong": "Algo ha salido mal: {{err}}"
+ "reviewAddress": "Para obtener el mejor cumplimiento, valide su dirección",
+ "somethingWentWrong": "Algo ha salido mal: {{err}}",
+ "enteredAddress": "Dirección introducida",
+ "validatedAddress": "Validar dirección"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "El correo electrónico no se ajusta a los criterios.",
"errorSendingEmail": "Error al enviar el correo electrónico, posible fallo de configuración.",
"unableToSendInvitationEmail": "No se ha podido enviar la invitación por correo electrónico.",
+ "userWithEmailAlreadyExists": "Ya existe un usuario con esta dirección de correo electrónico.",
"failedToLogout": "No se pudo cerrar la sesión.",
"invalidLoginToken": "Token de inicio de sesión no válido",
"loginForbidden": "Se ha impedido el inicio de sesión",
diff --git a/private/data/i18n/fr.json b/private/data/i18n/fr.json
index 856d9ec6381..9e7c9a78c40 100644
--- a/private/data/i18n/fr.json
+++ b/private/data/i18n/fr.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Détails de la commande",
"invoice": "Facture",
+ "lineItems": "Ligne Articles",
"shipmentTracking": "Suivi de l'expédition"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Editer cette adresse",
"addressValidation": "Adresse validation",
- "somethingWentWrong": "Quelque chose ne s'est pas passé comme prévu : {{err}}"
+ "reviewAddress": "Pour une meilleure conformité, validez votre adresse",
+ "somethingWentWrong": "Quelque chose ne s'est pas passé comme prévu : {{err}}",
+ "enteredAddress": "Adresse saisie",
+ "validatedAddress": "Valider l'adresse"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "L'e-mail ne remplit pas les critères.",
"errorSendingEmail": "Erreur lors de l'envoi de l'e-mail, possible problème de configuration.",
"unableToSendInvitationEmail": "Impossible d'envoyer l'e-mail d'invitation.",
+ "userWithEmailAlreadyExists": "Un utilisateur avec cette adresse email existe déjà",
"failedToLogout": "Echec de la déconnexion.",
"invalidLoginToken": "Jeton d'identification invalide",
"loginForbidden": "Connexion impossible",
diff --git a/private/data/i18n/hr.json b/private/data/i18n/hr.json
index d8d97f9ccea..cdda01d223f 100644
--- a/private/data/i18n/hr.json
+++ b/private/data/i18n/hr.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Detalji narudžbe",
"invoice": "Dostavnica",
+ "lineItems": "Stavke retka",
"shipmentTracking": "praćenje pošiljke"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Uređivanje adrese",
"addressValidation": "Adresa valjanosti",
- "somethingWentWrong": "Nešto je pošlo po zlu: {{err}}"
+ "reviewAddress": "Za najbolju sukladnost, potvrdite svoju adresu",
+ "somethingWentWrong": "Nešto je pošlo po zlu: {{err}}",
+ "enteredAddress": "Unesena adresa",
+ "validatedAddress": "Potvrdite adresu"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Netočna Email adresa.",
"errorSendingEmail": "Pogreška prilikom slanja e-mail, mogući problem s konfiguracijom.",
"unableToSendInvitationEmail": "Ne mogu poslati pozivnicu e-pošte.",
+ "userWithEmailAlreadyExists": "Korisnik s ovom adresom e-pošte već postoji",
"failedToLogout": "Neuspješno logout.",
"invalidLoginToken": "Nevaljan token za prijavu",
"loginForbidden": "Prijava zabranjena",
diff --git a/private/data/i18n/hu.json b/private/data/i18n/hu.json
index 912941306f0..ab7195b267f 100644
--- a/private/data/i18n/hu.json
+++ b/private/data/i18n/hu.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Rendelési információk",
"invoice": "Számla",
+ "lineItems": "Sorok",
"shipmentTracking": "szállítmány követés"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Cím szerkesztése",
"addressValidation": "cím érvényesítése",
- "somethingWentWrong": "Valami elromlott: {{err}}"
+ "reviewAddress": "A legjobb szabálynak megfelelően, érvényesítse a címet",
+ "somethingWentWrong": "Valami elromlott: {{err}}",
+ "enteredAddress": "Lépett Cím",
+ "validatedAddress": "érvényesítse Cím"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Email nem felel meg a szabálynak.",
"errorSendingEmail": "Hiba történt az e-mail, a lehetséges konfigurációs probléma.",
"unableToSendInvitationEmail": "Nem sikerült elküldeni a meghívót e-mailben.",
+ "userWithEmailAlreadyExists": "A felhasználó e-mail cím már létezik",
"failedToLogout": "Nem sikerült a logout.",
"invalidLoginToken": "Érvénytelen login token",
"loginForbidden": "Belépés megtagadva",
diff --git a/private/data/i18n/it.json b/private/data/i18n/it.json
index b42fe82002e..cdc8610490b 100644
--- a/private/data/i18n/it.json
+++ b/private/data/i18n/it.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Dettagli ordine",
"invoice": "Fattura",
+ "lineItems": "Partite singole",
"shipmentTracking": "monitoraggio delle spedizioni"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Modificare questa voce indirizzo",
"addressValidation": "Validazione indirizzo",
- "somethingWentWrong": "Qualcosa è andato storto: {{err}}"
+ "reviewAddress": "Per la migliore conformità, convalidate il tuo indirizzo",
+ "somethingWentWrong": "Qualcosa è andato storto: {{err}}",
+ "enteredAddress": "Indirizzo immesso",
+ "validatedAddress": "Convalida l'indirizzo"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "L'indirizzo email non soddisfa i requisiti.",
"errorSendingEmail": "Errore durante l'invio e-mail, eventuale problema di configurazione.",
"unableToSendInvitationEmail": "Impossibile inviare e-mail di invito.",
+ "userWithEmailAlreadyExists": "Un utente con questo indirizzo email esiste già",
"failedToLogout": "Impossibile il logout.",
"invalidLoginToken": "Codice di accesso non valido",
"loginForbidden": "Accesso non consentito",
diff --git a/private/data/i18n/my.json b/private/data/i18n/my.json
index a74a7ab19ac..08ad6be813c 100644
--- a/private/data/i18n/my.json
+++ b/private/data/i18n/my.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "အမိန့်အသေးစိတ်",
"invoice": "ဝယ်ကုန်စာရင်း",
+ "lineItems": "လိုင်းအကြောင်းအရာများ",
"shipmentTracking": "တင်ပို့ခြေရာကောက်"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "ဒီလိပ်စာ entry ကိုတည်းဖြတ်ခြင်း",
"addressValidation": "လိပ်စာ Validation",
- "somethingWentWrong": "တစ်ခုခုမှားသွား: {{err}}"
+ "reviewAddress": "အကောင်းဆုံးလိုက်နာမှုများအတွက်သင့်လိပ်စာမှန်ကန်ကြောင်းသက်သေပြကျေးဇူးပြုပြီး",
+ "somethingWentWrong": "တစ်ခုခုမှားသွား: {{err}}",
+ "enteredAddress": "သို့ ဝင်. လိပ်စာ",
+ "validatedAddress": "လိပ်စာမှန်ကန်ကြောင်းသက်သေပြ"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "ဤအီးမေးလ်မှာ သတ်မှတ်ချက်နှင့် မပြည့်စုံပါ",
"errorSendingEmail": "အီးမေးလ်, ဖြစ်နိုင်သမျှ configuration ကိုပြဿနာမပို့အမှား။",
"unableToSendInvitationEmail": "ဖိတ်ကြားချက်ကိုအီးမေးလ်ပေးပို့မရနိုင်ပါ။",
+ "userWithEmailAlreadyExists": "ဒီအီးမေးလ်လိပ်စာနှင့်အတူအသုံးပြုသူတစ်ဦးရှိထားပြီးသား",
"failedToLogout": "ထွက်ပြီးရန်မအောင်မြင်ခဲ့ပါ။",
"invalidLoginToken": "မမှန်ကန်သော အကောင့်တိုကင်",
"loginForbidden": "အကောင့်ဝင်ခွင့် ပိတ်ထားပါသည်",
diff --git a/private/data/i18n/nl.json b/private/data/i18n/nl.json
index 46f98bac875..4e855e56080 100644
--- a/private/data/i18n/nl.json
+++ b/private/data/i18n/nl.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Bestel Details",
"invoice": "Factuur",
+ "lineItems": "Line Items",
"shipmentTracking": "Verzending volgen"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Dit adres bewerken",
"addressValidation": "Address Validation",
- "somethingWentWrong": "Er is iets misgegaan: {{err}}"
+ "reviewAddress": "Bevestig uw adres voor de beste naleving",
+ "somethingWentWrong": "Er is iets misgegaan: {{err}}",
+ "enteredAddress": "Ingevoerd adres",
+ "validatedAddress": "Validate Address"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "E-mailadres komt niet overeen met de criteria.",
"errorSendingEmail": "Fout bij het verzenden van e-mail, mogelijke configuratie probleem.",
"unableToSendInvitationEmail": "Kan geen uitnodiging e-mail.",
+ "userWithEmailAlreadyExists": "Een gebruiker met dit e-mailadres bestaat al",
"failedToLogout": "Nagelaten om uit te loggen.",
"invalidLoginToken": "Ongeldig inlog-token",
"loginForbidden": "Login verboden",
diff --git a/private/data/i18n/pl.json b/private/data/i18n/pl.json
index 5691f322b9e..8f3b8642122 100644
--- a/private/data/i18n/pl.json
+++ b/private/data/i18n/pl.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Szczegóły zamówienia",
"invoice": "Faktura",
+ "lineItems": "Elementy zamówienia",
"shipmentTracking": "Śledzenie przesyłek"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Montaż tego wpisu adresu",
"addressValidation": "adres Validation",
- "somethingWentWrong": "Coś poszło nie tak: {{err}}"
+ "reviewAddress": "Aby uzyskać najlepszą zgodność, sprawdź swój adres",
+ "somethingWentWrong": "Coś poszło nie tak: {{err}}",
+ "enteredAddress": "Wprowadzony adres",
+ "validatedAddress": "Sprawdź poprawność adresu"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Adres email nie spełnia kryteriów.",
"errorSendingEmail": "Błąd wysyłania poczty elektronicznej, możliwej problem z konfiguracją.",
"unableToSendInvitationEmail": "Nie udało się wysłać e-maila z zaproszeniem.",
+ "userWithEmailAlreadyExists": "Użytkownik z tym adresem e-mail już istnieje",
"failedToLogout": "Nie udało się wylogować.",
"invalidLoginToken": "Błędny token logowania",
"loginForbidden": "Logowanie zabronione",
diff --git a/private/data/i18n/pt.json b/private/data/i18n/pt.json
index 1d8f2df0f46..ab500875d2e 100644
--- a/private/data/i18n/pt.json
+++ b/private/data/i18n/pt.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Detalhes da encomenda",
"invoice": "Fatura",
+ "lineItems": "Itens de linha",
"shipmentTracking": "Monitorização de transporte"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Editar esta entrada de endereço",
"addressValidation": "Validação de endereço",
- "somethingWentWrong": "Ocorreu um erro: {{err}}"
+ "reviewAddress": "Para melhor conformidade, valide seu endereço",
+ "somethingWentWrong": "Ocorreu um erro: {{err}}",
+ "enteredAddress": "Endereço inserido",
+ "validatedAddress": "Validar endereço"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "O email não corresponde aos critérios.",
"errorSendingEmail": "Erro ao enviar o email. Possível problema de configuração.",
"unableToSendInvitationEmail": "Não é possível enviar email de convite.",
+ "userWithEmailAlreadyExists": "Um usuário com este endereço de e-mail já existe",
"failedToLogout": "Falha ao terminar sessão.",
"invalidLoginToken": "Token de início de sessão inválido",
"loginForbidden": "Início de sessão proibido",
diff --git a/private/data/i18n/ro.json b/private/data/i18n/ro.json
index 9a42a6bae76..31122cdb198 100644
--- a/private/data/i18n/ro.json
+++ b/private/data/i18n/ro.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Detalii Comandă",
"invoice": "Factură",
+ "lineItems": "Elemente rând",
"shipmentTracking": "Urmărirea pachetului"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Editează această adresă",
"addressValidation": "adrese de validare",
- "somethingWentWrong": "Ceva nu a mers bine: {{err}}"
+ "reviewAddress": "Pentru cea mai bună conformitate, vă rugăm să vă validați adresa",
+ "somethingWentWrong": "Ceva nu a mers bine: {{err}}",
+ "enteredAddress": "Adresa introdusă",
+ "validatedAddress": "Validați adresa"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Adresa de e-mail nu corespunde criteriilor.",
"errorSendingEmail": "Eroare la trimiterea de e-mail-ului, verificați configurarea.",
"unableToSendInvitationEmail": "Nu se poate trimite e-mail-ul de invitație.",
+ "userWithEmailAlreadyExists": "Un utilizator cu această adresă de e-mail există deja",
"failedToLogout": "Conectarea a eșuat.",
"invalidLoginToken": "Jeton de conectare nevalid",
"loginForbidden": "Intrarea interzisă",
diff --git a/private/data/i18n/ru.json b/private/data/i18n/ru.json
index b3d00025d4a..1f6d306a7b8 100644
--- a/private/data/i18n/ru.json
+++ b/private/data/i18n/ru.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Детали заказа",
"invoice": "Счёт",
+ "lineItems": "Позиции",
"shipmentTracking": "Отслеживание посылки"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Редактирование адреса",
"addressValidation": "Адрес Validation",
- "somethingWentWrong": "Что-то пошло не так: {{err}}"
+ "reviewAddress": "Для обеспечения наилучшего соответствия, пожалуйста, подтвердите свой адрес",
+ "somethingWentWrong": "Что-то пошло не так: {{err}}",
+ "enteredAddress": "Введенный адрес",
+ "validatedAddress": "Проверить адрес"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Email не соответствует критериям.",
"errorSendingEmail": "Ошибка при отправке письма. Возможно проблемы с настройками.",
"unableToSendInvitationEmail": "Не удалось отправить приглашение.",
+ "userWithEmailAlreadyExists": "Пользователь с этим адресом электронной почты уже существует",
"failedToLogout": "Не удалось выйти",
"invalidLoginToken": "Неверный токен для входа",
"loginForbidden": "Вход запрещен",
diff --git a/private/data/i18n/sl.json b/private/data/i18n/sl.json
index 340efb2bf27..6cdf5381f02 100644
--- a/private/data/i18n/sl.json
+++ b/private/data/i18n/sl.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "podrobnosti naročila",
"invoice": "Račun",
+ "lineItems": "Line Izdelki",
"shipmentTracking": "pošiljka sledenje"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Urejanje ta vnos naslova",
"addressValidation": "naslov Validation",
- "somethingWentWrong": "Nekaj je šlo narobe: {{err}}"
+ "reviewAddress": "Za najboljšo skladnosti, potrdi svoj naslov",
+ "somethingWentWrong": "Nekaj je šlo narobe: {{err}}",
+ "enteredAddress": "vpisana Naslov",
+ "validatedAddress": "Potrdite naslov"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Email ne odgovarja kriterijem.",
"errorSendingEmail": "Napaka pri pošiljanju e-pošte, morebitno težavo konfiguracijo.",
"unableToSendInvitationEmail": "Mogli poslati povabilo e-pošto.",
+ "userWithEmailAlreadyExists": "Uporabnik s tem e-poštnim naslovom že obstaja",
"failedToLogout": "Ni odjaviti.",
"invalidLoginToken": "Napačen prijavni žeton",
"loginForbidden": "Prijava ni dovoljena",
diff --git a/private/data/i18n/sv.json b/private/data/i18n/sv.json
index 8f6585859fe..247e5bdcf7f 100644
--- a/private/data/i18n/sv.json
+++ b/private/data/i18n/sv.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Orderdetaljer",
"invoice": "Faktura",
+ "lineItems": "Linjeposter",
"shipmentTracking": "Leveransspårning"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Redigera den här adressen inträde",
"addressValidation": "adress Validering",
- "somethingWentWrong": "Något gick fel: {{err}}"
+ "reviewAddress": "För bästa överensstämmelse, bekräfta din adress",
+ "somethingWentWrong": "Något gick fel: {{err}}",
+ "enteredAddress": "Inmatad adress",
+ "validatedAddress": "Validera adress"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "E-postadressen uppfyller inte kriterierna.",
"errorSendingEmail": "Fel att skicka e-post, kan konfigurationsproblem.",
"unableToSendInvitationEmail": "Det går inte att skicka inbjudan e-post.",
+ "userWithEmailAlreadyExists": "En användare med den här e-postadressen finns redan",
"failedToLogout": "Det gick inte att logga ut.",
"invalidLoginToken": "Felaktig login-token",
"loginForbidden": "Inloggning tillåts ej",
diff --git a/private/data/i18n/tr.json b/private/data/i18n/tr.json
index 1b94ed6cd02..7b49ebf74b7 100644
--- a/private/data/i18n/tr.json
+++ b/private/data/i18n/tr.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "sipariş detayları",
"invoice": "Fatura",
+ "lineItems": "Satır Öğeleri",
"shipmentTracking": "Sevk Takibi"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Bu adresi düzenleyin",
"addressValidation": "Adres Doğrulama",
- "somethingWentWrong": "Bir şeyler ters gitti: {{err}}"
+ "reviewAddress": "En iyi uyum için lütfen adresinizi onaylayın",
+ "somethingWentWrong": "Bir şeyler ters gitti: {{err}}",
+ "enteredAddress": "Girilen Adres",
+ "validatedAddress": "Adres Doğrulayın"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "E-posta kriterlere uygun değil.",
"errorSendingEmail": "E-posta, olası yapılandırma sorunu gönderme hatası.",
"unableToSendInvitationEmail": "davetiye e-posta göndermek için açılamıyor.",
+ "userWithEmailAlreadyExists": "Bu e-posta adresine sahip bir kullanıcı zaten mevcut",
"failedToLogout": "çıkış için başarısız oldu.",
"invalidLoginToken": "Geçersiz giriş anahtarı",
"loginForbidden": "Giriş engellenmiş",
diff --git a/private/data/i18n/vi.json b/private/data/i18n/vi.json
index b36a45ce5d1..fe4f3de8f1d 100644
--- a/private/data/i18n/vi.json
+++ b/private/data/i18n/vi.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "Đặt hàng Chi tiết",
"invoice": "Hóa đơn",
+ "lineItems": "Mục hàng",
"shipmentTracking": "Theo dõi lô hàng"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "Chỉnh sửa mục nhập địa chỉ này",
"addressValidation": "địa chỉ Validation",
- "somethingWentWrong": "Một cái gì đó đã đi sai: {{err}}"
+ "reviewAddress": "Để tuân thủ tốt nhất, hãy xác minh địa chỉ của bạn",
+ "somethingWentWrong": "Một cái gì đó đã đi sai: {{err}}",
+ "enteredAddress": "Địa chỉ đã nhập",
+ "validatedAddress": "Xác nhận Địa chỉ"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "Email không phù hợp.",
"errorSendingEmail": "Lỗi gửi email, vấn đề cấu hình tốt.",
"unableToSendInvitationEmail": "Không thể gửi email mời.",
+ "userWithEmailAlreadyExists": "Người dùng có địa chỉ email này đã tồn tại",
"failedToLogout": "Không thể đăng xuất.",
"invalidLoginToken": "Mã đăng nhập không đúng",
"loginForbidden": "Đăng nhập bị cấm",
diff --git a/private/data/i18n/zh.json b/private/data/i18n/zh.json
index 026d0373729..5f73009e837 100644
--- a/private/data/i18n/zh.json
+++ b/private/data/i18n/zh.json
@@ -387,6 +387,7 @@
"orderWorkflow": {
"orderDetails": "订单详细信息",
"invoice": "账单",
+ "lineItems": "行项目",
"shipmentTracking": "发货跟踪"
},
"cartCheckout": {
@@ -433,7 +434,10 @@
"addressBookEdit": {
"editAddress": "编辑地址",
"addressValidation": "地址验证",
- "somethingWentWrong": "出现了错误:{{err}}"
+ "reviewAddress": "为了达到最佳效果,请验证您的地址",
+ "somethingWentWrong": "出现了错误:{{err}}",
+ "enteredAddress": "输入地址",
+ "validatedAddress": "验证地址"
},
"corePackageConfig": {
"settings": {
@@ -669,6 +673,7 @@
"emailDoesntMatchTheCriteria": "邮箱不合格。",
"errorSendingEmail": "发送电子邮件时出错,配置可能有问题。",
"unableToSendInvitationEmail": "无法发送邀请电子邮件。",
+ "userWithEmailAlreadyExists": "具有此电子邮件地址的用户已存在",
"failedToLogout": "退出失败。",
"invalidLoginToken": "登录令牌无效。",
"loginForbidden": "登录被禁止。",
diff --git a/server/publications/collections/products.js b/server/publications/collections/products.js
index 12d7a639b13..1c061cc5385 100644
--- a/server/publications/collections/products.js
+++ b/server/publications/collections/products.js
@@ -242,6 +242,7 @@ Meteor.publish("Products", function (productScrollLimit = 24, productFilters, so
selector.isVisible = {
$in: [true, false, undefined]
};
+ selector.ancestors = [];
// Get _ids of top-level products
const productIds = Products.find(selector, {
@@ -253,7 +254,7 @@ Meteor.publish("Products", function (productScrollLimit = 24, productFilters, so
// Remove hashtag filter from selector (hashtags are not applied to variants, we need to get variants)
if (productFilters && productFilters.tags) {
- newSelector = _.omit(selector, ["hashtags"]);
+ newSelector = _.omit(selector, ["hashtags", "ancestors"]);
// Re-configure selector to pick either Variants of one of the top-level products, or the top-level products in the filter
_.extend(newSelector, {
@@ -262,9 +263,32 @@ Meteor.publish("Products", function (productScrollLimit = 24, productFilters, so
ancestors: {
$in: productIds
}
- }, {
- hashtags: {
- $in: productFilters.tags
+ }, { $and: [
+ {
+ hashtags: {
+ $in: productFilters.tags
+ }
+ }, {
+ _id: {
+ $in: productIds
+ }
+ }
+ ]
+ }
+ ]
+ });
+ } else {
+ newSelector = _.omit(selector, ["hashtags", "ancestors"]);
+ _.extend(newSelector, {
+ $or: [
+ {
+ ancestors: {
+ $in: productIds
+ }
+ },
+ {
+ _id: {
+ $in: productIds
}
}
]
diff --git a/server/security/policy.js b/server/security/policy.js
index 4d122a29533..edad2494053 100644
--- a/server/security/policy.js
+++ b/server/security/policy.js
@@ -37,6 +37,7 @@ BrowserPolicy.content.allowOriginForAll("*.facebook.com");
BrowserPolicy.content.allowOriginForAll("*.fbcdn.net");
BrowserPolicy.content.allowOriginForAll("connect.facebook.net");
BrowserPolicy.content.allowOriginForAll("*.googleusercontent.com");
+BrowserPolicy.content.allowOriginForAll("*.cdninstagram.com");
BrowserPolicy.content.allowImageOrigin("fbcdn-profile-a.akamaihd.net");
BrowserPolicy.content.allowImageOrigin("secure.gravatar.com");