From 82ec38471e6903915579a4a14f638543cbdd0c56 Mon Sep 17 00:00:00 2001 From: Will Lopez Date: Tue, 10 Mar 2020 16:50:42 -0700 Subject: [PATCH 1/6] refactor: start work on de-meteorizing localization settings form Signed-off-by: Will Lopez --- .../client/graphql/fragments/shopCommon.js | 7 + .../components/LocalizationSettingsForm.js | 228 ++++++++++++++++++ imports/plugins/core/i18n/client/index.js | 10 +- 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js diff --git a/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js b/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js index e0a4706827..ee5de88d28 100644 --- a/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js +++ b/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js @@ -16,13 +16,20 @@ export default gql` phone isCommercial } + baseUOL + baseUOM + currency { + code + } description emails { address } keywords + language name slug + timezone } `; diff --git a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js new file mode 100644 index 0000000000..6237f540cc --- /dev/null +++ b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js @@ -0,0 +1,228 @@ +import React, { useState } from "react"; +import i18next from "i18next"; +import SimpleSchema from "simpl-schema"; +import { Button, TextField } from "@reactioncommerce/catalyst"; +import useReactoForm from "reacto-form/cjs/useReactoForm"; +import muiOptions from "reacto-form/cjs/muiOptions"; +import { + Box, + Card, + CardContent, + CardHeader, + CardActions, + CircularProgress, + Grid, + makeStyles, + MenuItem +} from "@material-ui/core"; +import useShopSettings from "/imports/plugins/core/dashboard/client/hooks/useShopSettings"; +import CountryOptions from "@reactioncommerce/api-utils/CountryOptions.js"; +import CurrencyOptions from "@reactioncommerce/api-utils/CurrencyOptions.js"; +import LanguageOptions from "@reactioncommerce/api-utils/LanguageOptions.js"; +import { convertWeight, convertLength } from "/lib/api"; + +const unitsOfMeasure = []; +const unitsOfLength = []; +const TimezoneOptions = []; + +const useStyles = makeStyles((theme) => ({ + card: { + overflow: "visible" + }, + cardActions: { + justifyContent: "flex-end", + marginRight: theme.spacing(1) + } +})); + +const localizationSettings = new SimpleSchema({ + "currency": Object, + "currency.symbol": { + type: String, + optional: true + }, + "baseUOL": { + type: String, + optional: true + }, + "baseUOM": { + type: String, + optional: true + }, + "language": { + type: String, + optional: true + }, + "timezone": { + type: String, + optional: true + } +}); + +const validator = localizationSettings.getFormValidator(); + +/** + * Shop settings form block component + * @returns {Node} React node + */ +export default function ShopSettings() { + const [isSubmitting, setIsSubmitting] = useState(false); + const { loading, onUpdateShop, shop } = useShopSettings(); + const classes = useStyles(); + const { + getFirstErrorMessage, + getInputProps, + hasErrors, + isDirty, + submitForm + } = useReactoForm({ + async onSubmit(formData) { + setIsSubmitting(true); + await onUpdateShop(localizationSettings.clean(formData)); + setIsSubmitting(false); + }, + validator(formData) { + return validator(localizationSettings.clean(formData)); + }, + value: shop + }); + + if (loading) { + return ( + + + + ); + } + + const handleSubmit = (event) => { + event.preventDefault(); + submitForm(); + }; + + const currencyInputProps = getInputProps("currency.code", muiOptions); + const baseUOLInputProps = getInputProps("baseUOL", muiOptions); + const baseUOMInputProps = getInputProps("baseUOM", muiOptions); + const languageInputProps = getInputProps("language", muiOptions); + const timezoneInputProps = getInputProps("timezone", muiOptions); + + return ( + + + + + + { + if (event.key === "Enter") submitForm(); + }} + select + {...currencyInputProps} + > + {CurrencyOptions.map((option) => ( + + {option.label} + + ))} + + + + { + if (event.key === "Enter") submitForm(); + }} + select + {...baseUOLInputProps} + value={baseUOLInputProps.value} + > + {unitsOfLength.map((option) => ( + + {option.label} + + ))} + + + + { + if (event.key === "Enter") submitForm(); + }} + select + {...baseUOMInputProps} + > + {unitsOfMeasure.map((option) => ( + + {option.label} + + ))} + + + + { + if (event.key === "Enter") submitForm(); + }} + select + {...languageInputProps} + value={languageInputProps.value} + > + {LanguageOptions.map((option) => ( + + {option.label} + + ))} + + + + { + if (event.key === "Enter") submitForm(); + }} + select + {...timezoneInputProps} + value={timezoneInputProps.value} + > + {TimezoneOptions.map((option) => ( + + {option.label} + + ))} + + + + + + + + + ); +} diff --git a/imports/plugins/core/i18n/client/index.js b/imports/plugins/core/i18n/client/index.js index 09584494aa..06b35849c9 100644 --- a/imports/plugins/core/i18n/client/index.js +++ b/imports/plugins/core/i18n/client/index.js @@ -2,6 +2,7 @@ import { registerOperatorRoute } from "/imports/client/ui"; import { registerBlock } from "@reactioncommerce/reaction-components"; import LocalizationSettingsRegion from "./components/LocalizationSettingsRegion"; import Localization from "./containers/localizationSettings"; +import LocalizationSettingsForm from "./components/LocalizationSettingsForm"; export { default as LocalizationSettings } from "./containers/localizationSettings"; @@ -13,9 +14,16 @@ registerOperatorRoute({ priority: 160 }); +registerBlock({ + component: LocalizationSettingsForm, + name: "LocalizationSettings", + priority: 1, + region: "LocalizationSettings" +}); + registerBlock({ component: Localization, name: "LocalizationSettingsGeneral", - priority: 1, + priority: 2, region: "LocalizationSettings" }); From 011c79456c66f6c4d5743e400ec1fe7eb77caed3 Mon Sep 17 00:00:00 2001 From: Will Lopez Date: Wed, 11 Mar 2020 12:17:45 -0700 Subject: [PATCH 2/6] refactor: wire up timezone and units of measure/length selects Signed-off-by: Will Lopez --- .../client/graphql/fragments/shopCommon.js | 8 +++ .../components/LocalizationSettingsForm.js | 70 ++++++++++++------- .../i18n/client/helpers/getUnitOptions.js | 21 ++++++ 3 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 imports/plugins/core/i18n/client/helpers/getUnitOptions.js diff --git a/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js b/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js index ee5de88d28..94b56d1eee 100644 --- a/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js +++ b/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js @@ -30,6 +30,14 @@ export default gql` name slug timezone + unitsOfLength { + uol + label + } + unitsOfMeasure { + uom + label + } } `; diff --git a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js index 6237f540cc..2118c0a1e0 100644 --- a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js +++ b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js @@ -4,6 +4,8 @@ import SimpleSchema from "simpl-schema"; import { Button, TextField } from "@reactioncommerce/catalyst"; import useReactoForm from "reacto-form/cjs/useReactoForm"; import muiOptions from "reacto-form/cjs/muiOptions"; +import moment from "moment-timezone"; +import _ from "lodash"; import { Box, Card, @@ -16,14 +18,18 @@ import { MenuItem } from "@material-ui/core"; import useShopSettings from "/imports/plugins/core/dashboard/client/hooks/useShopSettings"; -import CountryOptions from "@reactioncommerce/api-utils/CountryOptions.js"; import CurrencyOptions from "@reactioncommerce/api-utils/CurrencyOptions.js"; import LanguageOptions from "@reactioncommerce/api-utils/LanguageOptions.js"; -import { convertWeight, convertLength } from "/lib/api"; +import getUnitOptions from "../helpers/getUnitOptions"; -const unitsOfMeasure = []; -const unitsOfLength = []; -const TimezoneOptions = []; +const timezoneOptions = []; +const timezones = moment.tz.names(); +for (const timezone of timezones) { + timezoneOptions.push({ + value: timezone, + label: timezone + }); +} const useStyles = makeStyles((theme) => ({ card: { @@ -37,7 +43,7 @@ const useStyles = makeStyles((theme) => ({ const localizationSettings = new SimpleSchema({ "currency": Object, - "currency.symbol": { + "currency.code": { type: String, optional: true }, @@ -68,6 +74,10 @@ const validator = localizationSettings.getFormValidator(); export default function ShopSettings() { const [isSubmitting, setIsSubmitting] = useState(false); const { loading, onUpdateShop, shop } = useShopSettings(); + + const unitsOfLength = getUnitOptions("uol", shop.unitsOfLength); + const unitsOfMeasure = getUnitOptions("uom", shop.unitsOfMeasure); + const classes = useStyles(); const { getFirstErrorMessage, @@ -78,7 +88,11 @@ export default function ShopSettings() { } = useReactoForm({ async onSubmit(formData) { setIsSubmitting(true); - await onUpdateShop(localizationSettings.clean(formData)); + // Flatten currency object + const cleanedFormData = _.clone(localizationSettings.clean(formData)); + const { currency: { code } } = cleanedFormData; + cleanedFormData.currency = code; + await onUpdateShop(cleanedFormData); setIsSubmitting(false); }, validator(formData) { @@ -111,6 +125,26 @@ export default function ShopSettings() { + + { + if (event.key === "Enter") submitForm(); + }} + select + {...timezoneInputProps} + value={timezoneInputProps.value} + > + {timezoneOptions.map((option) => ( + + {option.label} + + ))} + + {CurrencyOptions.map((option) => ( @@ -161,6 +196,7 @@ export default function ShopSettings() { }} select {...baseUOMInputProps} + value={baseUOMInputProps.value} > {unitsOfMeasure.map((option) => ( @@ -189,26 +225,6 @@ export default function ShopSettings() { ))} - - { - if (event.key === "Enter") submitForm(); - }} - select - {...timezoneInputProps} - value={timezoneInputProps.value} - > - {TimezoneOptions.map((option) => ( - - {option.label} - - ))} - - diff --git a/imports/plugins/core/i18n/client/helpers/getUnitOptions.js b/imports/plugins/core/i18n/client/helpers/getUnitOptions.js new file mode 100644 index 0000000000..817abfc23e --- /dev/null +++ b/imports/plugins/core/i18n/client/helpers/getUnitOptions.js @@ -0,0 +1,21 @@ +import i18next from "i18next"; + +/** + * + * @param {String} type the type of unit, either length or measure + * @param {Array} rawOptions - an array af of unformatted units + * @returns {Array} An array of formatted options to be used in a select + */ +export default function getUnitOptions(type, rawOptions) { + const options = []; + if (Array.isArray(rawOptions)) { + for (const option of rawOptions) { + options.push({ + label: i18next.t(`admin.${type}.${option.label}`, { defaultValue: option.label }), + value: option[type] + }); + } + } + + return options; +} From f41043e295a2c1576ad5190272314fe5490ac83c Mon Sep 17 00:00:00 2001 From: Will Lopez Date: Wed, 11 Mar 2020 12:44:24 -0700 Subject: [PATCH 3/6] refactor: update default parcel size when UOL/UOM are updated Signed-off-by: Will Lopez --- .../client/graphql/fragments/shopCommon.js | 6 ++ .../components/LocalizationSettingsForm.js | 28 ++++-- .../client/components/localizationSettings.js | 94 ------------------- imports/plugins/core/i18n/client/index.js | 10 -- 4 files changed, 26 insertions(+), 112 deletions(-) delete mode 100644 imports/plugins/core/i18n/client/components/localizationSettings.js diff --git a/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js b/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js index 94b56d1eee..368e34bf58 100644 --- a/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js +++ b/imports/plugins/core/dashboard/client/graphql/fragments/shopCommon.js @@ -21,6 +21,12 @@ export default gql` currency { code } + defaultParcelSize { + width + weight + height + length + } description emails { address diff --git a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js index 2118c0a1e0..5c4411c350 100644 --- a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js +++ b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js @@ -21,6 +21,7 @@ import useShopSettings from "/imports/plugins/core/dashboard/client/hooks/useSho import CurrencyOptions from "@reactioncommerce/api-utils/CurrencyOptions.js"; import LanguageOptions from "@reactioncommerce/api-utils/LanguageOptions.js"; import getUnitOptions from "../helpers/getUnitOptions"; +import { convertWeight, convertLength } from "/lib/api"; const timezoneOptions = []; const timezones = moment.tz.names(); @@ -74,11 +75,11 @@ const validator = localizationSettings.getFormValidator(); export default function ShopSettings() { const [isSubmitting, setIsSubmitting] = useState(false); const { loading, onUpdateShop, shop } = useShopSettings(); + const classes = useStyles(); const unitsOfLength = getUnitOptions("uol", shop.unitsOfLength); const unitsOfMeasure = getUnitOptions("uom", shop.unitsOfMeasure); - const classes = useStyles(); const { getFirstErrorMessage, getInputProps, @@ -86,17 +87,28 @@ export default function ShopSettings() { isDirty, submitForm } = useReactoForm({ - async onSubmit(formData) { + async onSubmit(userInput) { setIsSubmitting(true); + // Flatten currency object - const cleanedFormData = _.clone(localizationSettings.clean(formData)); - const { currency: { code } } = cleanedFormData; - cleanedFormData.currency = code; - await onUpdateShop(cleanedFormData); + const cleanedUserInput = _.clone(localizationSettings.clean(userInput)); + const { currency: { code } } = cleanedUserInput; + cleanedUserInput.currency = code; + + // Update default parcel size when UOL/UOM are updated + const parcelSize = { + weight: convertWeight(shop.baseUOM, userInput.baseUOM, shop.defaultParcelSize.weight), + height: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.height), + length: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.length), + width: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.width) + }; + cleanedUserInput.defaultParcelSize = parcelSize; + + await onUpdateShop(cleanedUserInput); setIsSubmitting(false); }, - validator(formData) { - return validator(localizationSettings.clean(formData)); + validator(userInput) { + return validator(localizationSettings.clean(userInput)); }, value: shop }); diff --git a/imports/plugins/core/i18n/client/components/localizationSettings.js b/imports/plugins/core/i18n/client/components/localizationSettings.js deleted file mode 100644 index 50bd83c552..0000000000 --- a/imports/plugins/core/i18n/client/components/localizationSettings.js +++ /dev/null @@ -1,94 +0,0 @@ -import React, { Component } from "react"; -import PropTypes from "prop-types"; -import { Components } from "@reactioncommerce/reaction-components"; -import { Shop as ShopSchema } from "/lib/collections/schemas"; - -const PACKAGE_NAME = "reaction-i18n"; - -class LocalizationSettings extends Component { - static propTypes = { - currencyOptions: PropTypes.array, - languages: PropTypes.array, - onUpdateLocalization: PropTypes.func, - shop: PropTypes.object, // Shop data - timezoneOptions: PropTypes.array, - uolOptions: PropTypes.array, - uomOptions: PropTypes.array - } - - handleSubmit = (event, formData) => { - if (typeof this.props.onUpdateLocalization === "function") { - this.props.onUpdateLocalization(formData.doc); - } - } - - renderListControls(name) { - return ( - - - { "|" } - - - ); - } - - render() { - return ( - - - - - - ); - } -} - -export default LocalizationSettings; diff --git a/imports/plugins/core/i18n/client/index.js b/imports/plugins/core/i18n/client/index.js index 06b35849c9..6957154796 100644 --- a/imports/plugins/core/i18n/client/index.js +++ b/imports/plugins/core/i18n/client/index.js @@ -1,11 +1,8 @@ import { registerOperatorRoute } from "/imports/client/ui"; import { registerBlock } from "@reactioncommerce/reaction-components"; import LocalizationSettingsRegion from "./components/LocalizationSettingsRegion"; -import Localization from "./containers/localizationSettings"; import LocalizationSettingsForm from "./components/LocalizationSettingsForm"; -export { default as LocalizationSettings } from "./containers/localizationSettings"; - registerOperatorRoute({ group: "settings", MainComponent: LocalizationSettingsRegion, @@ -20,10 +17,3 @@ registerBlock({ priority: 1, region: "LocalizationSettings" }); - -registerBlock({ - component: Localization, - name: "LocalizationSettingsGeneral", - priority: 2, - region: "LocalizationSettings" -}); From 5defc9a3a252b61b47165f195cb3893ba5f29a22 Mon Sep 17 00:00:00 2001 From: Will Lopez Date: Wed, 11 Mar 2020 12:51:53 -0700 Subject: [PATCH 4/6] refactor: bye Meteor madness Signed-off-by: Will Lopez --- .../core/core/server/methods/shop/index.js | 8 +- .../shop/updateCurrencyConfiguration.js | 63 -------- .../methods/shop/updateDefaultParcelSize.js | 41 ------ .../shop/updateLanguageConfiguration.js | 63 -------- .../client/containers/localizationSettings.js | 134 ------------------ 5 files changed, 1 insertion(+), 308 deletions(-) delete mode 100644 imports/plugins/core/core/server/methods/shop/updateCurrencyConfiguration.js delete mode 100644 imports/plugins/core/core/server/methods/shop/updateDefaultParcelSize.js delete mode 100644 imports/plugins/core/core/server/methods/shop/updateLanguageConfiguration.js delete mode 100644 imports/plugins/core/i18n/client/containers/localizationSettings.js diff --git a/imports/plugins/core/core/server/methods/shop/index.js b/imports/plugins/core/core/server/methods/shop/index.js index 8704589937..62b1fd385a 100644 --- a/imports/plugins/core/core/server/methods/shop/index.js +++ b/imports/plugins/core/core/server/methods/shop/index.js @@ -1,9 +1,6 @@ import createTag from "./createTag"; import updateBrandAssets from "./updateBrandAssets"; -import updateCurrencyConfiguration from "./updateCurrencyConfiguration"; -import updateDefaultParcelSize from "./updateDefaultParcelSize"; import updateHeaderTags from "./updateHeaderTags"; -import updateLanguageConfiguration from "./updateLanguageConfiguration"; /** * @file Meteor methods for Shop @@ -15,8 +12,5 @@ import updateLanguageConfiguration from "./updateLanguageConfiguration"; export default { "shop/createTag": createTag, "shop/updateBrandAssets": updateBrandAssets, - "shop/updateCurrencyConfiguration": updateCurrencyConfiguration, - "shop/updateDefaultParcelSize": updateDefaultParcelSize, - "shop/updateHeaderTags": updateHeaderTags, - "shop/updateLanguageConfiguration": updateLanguageConfiguration + "shop/updateHeaderTags": updateHeaderTags }; diff --git a/imports/plugins/core/core/server/methods/shop/updateCurrencyConfiguration.js b/imports/plugins/core/core/server/methods/shop/updateCurrencyConfiguration.js deleted file mode 100644 index b2c6154a78..0000000000 --- a/imports/plugins/core/core/server/methods/shop/updateCurrencyConfiguration.js +++ /dev/null @@ -1,63 +0,0 @@ -import { check } from "meteor/check"; -import { Reaction } from "/lib/api"; -import ReactionError from "@reactioncommerce/reaction-error"; -import { Shops } from "/lib/collections"; - -/** - * @name shop/updateCurrencyConfiguration - * @method - * @memberof Shop/Methods - * @summary enable / disable a currency - * @param {String} currency - currency name | "all" to bulk enable / disable - * @param {Boolean} enabled - true / false - * @returns {Number} returns mongo update result - */ -export default function updateCurrencyConfiguration(currency, enabled) { - check(currency, String); - check(enabled, Boolean); - - // must have core permissions - if (!Reaction.hasPermission("reaction:legacy:shops/update")) { - throw new ReactionError("access-denied", "Access Denied"); - } - this.unblock(); - - const shopId = Reaction.getShopId(); - - const shop = Shops.findOne({ - _id: shopId - }); - - const defaultCurrency = shop.currency; - - if (currency === defaultCurrency && !enabled) { - throw new ReactionError("invalid-param", "Cannot disable the shop default currency"); - } - - if (currency === "all") { - const updateObject = {}; - for (const currencyName in shop.currencies) { - if ({}.hasOwnProperty.call(shop.currencies, currencyName) && currencyName !== "updatedAt") { - if (currencyName === defaultCurrency) { - updateObject[`currencies.${currencyName}.enabled`] = true; - } else { - updateObject[`currencies.${currencyName}.enabled`] = enabled; - } - } - } - - return Shops.update({ - _id: shopId - }, { - $set: updateObject - }); - } - - return Shops.update({ - _id: shopId - }, { - $set: { - [`currencies.${currency}.enabled`]: enabled - } - }); -} diff --git a/imports/plugins/core/core/server/methods/shop/updateDefaultParcelSize.js b/imports/plugins/core/core/server/methods/shop/updateDefaultParcelSize.js deleted file mode 100644 index 4396ab92bc..0000000000 --- a/imports/plugins/core/core/server/methods/shop/updateDefaultParcelSize.js +++ /dev/null @@ -1,41 +0,0 @@ -import { check, Match } from "meteor/check"; -import { Shops } from "/lib/collections"; -import Reaction from "/imports/plugins/core/core/server/Reaction"; -import ReactionError from "@reactioncommerce/reaction-error"; - -const shippingRoles = ["reaction:legacy:shippingMethods/update"]; - -/** - * @method shop/updateDefaultParcelSize - * @summary update defaultParcelSize for a shop - * @param {Object} parcel - size to be updated - * @since 1.1.12 - * @returns {Object} The update call result -*/ -export default function updateDefaultParcelSize(parcel) { - check(parcel, { - weight: Match.Optional(Number), - height: Match.Optional(Number), - length: Match.Optional(Number), - width: Match.Optional(Number) - }); - - if (!Reaction.hasPermission(shippingRoles)) { - throw new ReactionError("access-denied", "Access Denied"); - } - - const modifier = Object.keys(parcel).reduce((mod, key) => { - mod[`defaultParcelSize.${key}`] = parcel[key]; - return mod; - }, {}); - - return Shops.update({ - _id: Reaction.getShopId() - }, { - $set: modifier - }, (error) => { - if (error) { - throw new ReactionError("server-error", error.message); - } - }); -} diff --git a/imports/plugins/core/core/server/methods/shop/updateLanguageConfiguration.js b/imports/plugins/core/core/server/methods/shop/updateLanguageConfiguration.js deleted file mode 100644 index 62f44f59a4..0000000000 --- a/imports/plugins/core/core/server/methods/shop/updateLanguageConfiguration.js +++ /dev/null @@ -1,63 +0,0 @@ -import { check } from "meteor/check"; -import { Reaction } from "/lib/api"; -import ReactionError from "@reactioncommerce/reaction-error"; -import { Shops } from "/lib/collections"; - -/** - * @name shop/updateLanguageConfiguration - * @method - * @memberof Shop/Methods - * @summary enable / disable a language - * @param {String} language - language name | "all" to bulk enable / disable - * @param {Boolean} enabled - true / false - * @returns {Array} returns workflow array - */ -export default function updateLanguageConfiguration(language, enabled) { - check(language, String); - check(enabled, Boolean); - - // must have reaction:legacy:shops/update permissions - if (!Reaction.hasPermission("reaction:legacy:shops/update")) { - throw new ReactionError("access-denied", "Access Denied"); - } - this.unblock(); - - const shopId = Reaction.getShopId(); - - const shop = Shops.findOne({ _id: shopId }); - - const defaultLanguage = shop.language; - - if (language === defaultLanguage && !enabled) { - throw new ReactionError("invalid-param", "Cannot disable the shop default language"); - } - - if (language === "all") { - const updateObject = {}; - - if (Array.isArray(shop.languages)) { - shop.languages.forEach((languageData, index) => { - if (languageData.i18n === defaultLanguage) { - updateObject[`languages.${index}.enabled`] = true; - } else { - updateObject[`languages.${index}.enabled`] = enabled; - } - }); - } - - return Shops.update({ - _id: shopId - }, { - $set: updateObject - }); - } - - return Shops.update({ - "_id": shopId, - "languages.i18n": language - }, { - $set: { - "languages.$.enabled": enabled - } - }); -} diff --git a/imports/plugins/core/i18n/client/containers/localizationSettings.js b/imports/plugins/core/i18n/client/containers/localizationSettings.js deleted file mode 100644 index 4b161d9591..0000000000 --- a/imports/plugins/core/i18n/client/containers/localizationSettings.js +++ /dev/null @@ -1,134 +0,0 @@ -import React, { Component } from "react"; -import { compose } from "recompose"; -import CountryOptions from "@reactioncommerce/api-utils/CountryOptions.js"; -import CurrencyOptions from "@reactioncommerce/api-utils/CurrencyOptions.js"; -import LanguageOptions from "@reactioncommerce/api-utils/LanguageOptions.js"; -import { registerComponent, composeWithTracker, withMomentTimezone } from "@reactioncommerce/reaction-components"; -import { Meteor } from "meteor/meteor"; -import { Reaction, i18next } from "/client/api"; -import { Shops } from "/lib/collections"; -import { convertWeight, convertLength } from "/lib/api"; -import LocalizationSettings from "../components/localizationSettings"; - -/** - * @summary Use this as a Meteor.call callback to show a toast alert - * with the error reason/message. - * @param {Error|null} [error] Error - * @return {undefined} - */ -function methodAlertCallback(error) { - if (error) Alerts.toast(error.reason || error.message || "There was an unknown error", "error"); -} - -const wrapComponent = (Comp) => ( - class LocalizationSettingsContainer extends Component { - static propTypes = LocalizationSettings.propTypes - - handleSubmit = (doc) => { - const shop = Shops.findOne({ - _id: Reaction.getShopId() - }, { defaultParcelSize: 1, baseUOM: 1, baseUOL: 1 }); - if (shop && shop.defaultParcelSize) { - const parcelSize = { - weight: convertWeight(shop.baseUOM, doc.baseUOM, shop.defaultParcelSize.weight), - height: convertLength(shop.baseUOL, doc.baseUOL, shop.defaultParcelSize.height), - length: convertLength(shop.baseUOL, doc.baseUOL, shop.defaultParcelSize.length), - width: convertLength(shop.baseUOL, doc.baseUOL, shop.defaultParcelSize.width) - }; - Meteor.call("shop/updateDefaultParcelSize", parcelSize, methodAlertCallback); - } - Shops.update({ - _id: doc._id - }, { - $set: { - timezone: doc.timezone, - currency: doc.currency, - baseUOM: doc.baseUOM, - baseUOL: doc.baseUOL, - language: doc.language, - allowCustomUserLocale: doc.allowCustomUserLocale - } - }); - } - - render() { - return ( - - ); - } - } -); - -/** - * @private - * @param {Object} props Props - * @param {Function} onData Call this to update props - * @returns {undefined} - */ -function composer(props, onData) { - const shop = Shops.findOne(); - - const { unitsOfMeasure } = shop; - const uomOptions = []; - if (Array.isArray(unitsOfMeasure)) { - for (const measure of unitsOfMeasure) { - uomOptions.push({ - label: i18next.t(`uom.${measure.uom}`, { defaultValue: measure.uom }), - value: measure.uom - }); - } - } - - const { unitsOfLength } = Shops.findOne(); - const uolOptions = []; - if (Array.isArray(unitsOfLength)) { - for (const length of unitsOfLength) { - uolOptions.push({ - label: i18next.t(`uol.${length.uol}`, { defaultValue: length.uol }), - value: length.uol - }); - } - } - - const label = i18next.t("app.timezoneOptions", "Choose timezone"); - const timezoneOptions = [{ - value: "", - label - }]; - const moment = props.momentTimezone; - if (moment) { - const timezones = moment.names(); - for (const timezone of timezones) { - timezoneOptions.push({ - value: timezone, - label: timezone - }); - } - } - - onData(null, { - preferences: {}, - shop, - languages: LanguageOptions, - countryOptions: CountryOptions, - currencyOptions: CurrencyOptions, - uomOptions, - uolOptions, - timezoneOptions - }); -} - -registerComponent("i18nSettings", LocalizationSettings, [ - withMomentTimezone, - composeWithTracker(composer), - wrapComponent -]); - -export default compose( - withMomentTimezone, - composeWithTracker(composer), - wrapComponent -)(LocalizationSettings); From 623d923eff7817b7e77afa4d42cc1029c8aa15a2 Mon Sep 17 00:00:00 2001 From: Will Lopez Date: Fri, 13 Mar 2020 10:27:43 -0700 Subject: [PATCH 5/6] refactor: update parcel size only when neccessary Signed-off-by: Will Lopez --- .../components/LocalizationSettingsForm.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js index 5c4411c350..9ab9a0a359 100644 --- a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js +++ b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js @@ -95,14 +95,17 @@ export default function ShopSettings() { const { currency: { code } } = cleanedUserInput; cleanedUserInput.currency = code; - // Update default parcel size when UOL/UOM are updated - const parcelSize = { - weight: convertWeight(shop.baseUOM, userInput.baseUOM, shop.defaultParcelSize.weight), - height: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.height), - length: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.length), - width: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.width) - }; - cleanedUserInput.defaultParcelSize = parcelSize; + // Only update default parcel size when UOL/UOM are changed by the user + if (userInput.baseUOL !== shop.baseUOL || userInput.baseUOM !== shop.baseUOM) { + const parcelSize = { + weight: convertWeight(shop.baseUOM, userInput.baseUOM, shop.defaultParcelSize.weight), + height: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.height), + length: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.length), + width: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.width) + }; + cleanedUserInput.defaultParcelSize = parcelSize; + console.log("updating parcel Size"); + } await onUpdateShop(cleanedUserInput); setIsSubmitting(false); From 7bca8a3280001b58ecf91dc28ffbfc2a77c25bb2 Mon Sep 17 00:00:00 2001 From: Will Lopez Date: Fri, 13 Mar 2020 11:06:10 -0700 Subject: [PATCH 6/6] chore: clean up Signed-off-by: Will Lopez --- .../core/i18n/client/components/LocalizationSettingsForm.js | 1 - 1 file changed, 1 deletion(-) diff --git a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js index 9ab9a0a359..c7b0fc6f99 100644 --- a/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js +++ b/imports/plugins/core/i18n/client/components/LocalizationSettingsForm.js @@ -104,7 +104,6 @@ export default function ShopSettings() { width: convertLength(shop.baseUOL, userInput.baseUOL, shop.defaultParcelSize.width) }; cleanedUserInput.defaultParcelSize = parcelSize; - console.log("updating parcel Size"); } await onUpdateShop(cleanedUserInput);