From 52b243b315073c53c9a5d1168012fb2d9001b378 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Thu, 23 Jan 2020 11:24:24 -0800 Subject: [PATCH 001/220] feat: add product query definition Signed-off-by: Mike Murray --- .../client/hooks/ProductQuery.js | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 imports/plugins/included/product-admin/client/hooks/ProductQuery.js diff --git a/imports/plugins/included/product-admin/client/hooks/ProductQuery.js b/imports/plugins/included/product-admin/client/hooks/ProductQuery.js new file mode 100644 index 0000000000..3529edde43 --- /dev/null +++ b/imports/plugins/included/product-admin/client/hooks/ProductQuery.js @@ -0,0 +1,86 @@ +import gql from "graphql-tag"; + +export default gql` + query product($productId: ID!, $shopId: ID!) { + product(productId: $productId, shopId: $shopId) { + _id + currentProductHash + description + isDeleted + isVisible + metaDescription + metafields { + key + value + } + originCountry + pageTitle + productType + publishedAt + publishedProductHash + shop { + _id + } + slug + socialMetadata { + message + service + } + supportedFulfillmentTypes + tagIds + title + updatedAt + vendor + variants { + _id + attributeLabel + barcode + height + index + isDeleted + isVisible + length + metafields { + key + value + } + minOrderQuantity + optionTitle + originCountry + shop { + _id + } + sku + title + updatedAt + weight + width + options { + _id + attributeLabel + barcode + height + index + isDeleted + isVisible + length + metafields { + key + value + } + minOrderQuantity + optionTitle + originCountry + shop { + _id + } + sku + title + updatedAt + weight + width + } + } + } + } +`; From f94aab60396b29ab01cc983760b9f34872748518 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Thu, 23 Jan 2020 11:24:39 -0800 Subject: [PATCH 002/220] feat: add product hook Signed-off-by: Mike Murray --- .../product-admin/client/hooks/useProduct.js | 318 ++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 imports/plugins/included/product-admin/client/hooks/useProduct.js diff --git a/imports/plugins/included/product-admin/client/hooks/useProduct.js b/imports/plugins/included/product-admin/client/hooks/useProduct.js new file mode 100644 index 0000000000..ef9fd36f9d --- /dev/null +++ b/imports/plugins/included/product-admin/client/hooks/useProduct.js @@ -0,0 +1,318 @@ +import { useState, useCallback, useMemo } from "react"; +import gql from "graphql-tag"; +import _ from "lodash"; +import { useHistory, useParams } from "react-router-dom"; +import { useMutation, useQuery } from "@apollo/react-hooks"; +import CountryOptions from "@reactioncommerce/api-utils/CountryOptions.js"; +import { Media } from "/imports/plugins/core/files/client"; +import { Meteor } from "meteor/meteor"; +import { Reaction, formatPriceString, i18next } from "/client/api"; +import { getPrimaryMediaForItem, ReactionProduct, Catalog } from "/lib/api"; +import { Tags, Templates } from "/lib/collections"; +import getOpaqueIds from "/imports/plugins/core/core/client/util/getOpaqueIds"; +import useCurrentShopId from "/imports/client/ui/hooks/useCurrentShopId"; +import encodeOpaqueId from "@reactioncommerce/api-utils/encodeOpaqueId.js"; + +import PRODUCT_QUERY from "./ProductQuery"; + +const encodeProductOpaqueId = encodeOpaqueId("reaction/product"); + +const getVariantIds = (variants) => Array.isArray(variants) && variants.map((variant) => variant._id); + +const ARCHIVE_PRODUCTS = gql` + mutation archiveProducts($input: ArchiveProductsInput!) { + archiveProducts(input: $input) { + products { + _id + } + } + } +`; + +const CLONE_PRODUCTS = gql` + mutation cloneProducts($input: CloneProductsInput!) { + cloneProducts(input: $input) { + products { + _id + } + } + } +`; + +const CREATE_VARIANT = gql` +mutation createProductVariant($input: CreateProductVariantInput!) { + createProductVariant(input: $input) { + variant { + _id + } + } +} +`; + +const UPDATE_PRODUCT = gql` +mutation updateProduct($input: UpdateProductInput!) { + updateProduct(input: $input) { + product { + _id + title + isVisible + } + } +} +`; + + +/** + * Metafield to remove + * @param {String} productId Product ID + * @param {Object} metafield Metafield object + * @param {String} metafield.key Key + * @param {String} metafield.value Value + * @returns {undefined} No return + */ +export function handleMetaRemove(productId, metafield) { + Meteor.call("products/removeMetaFields", productId, metafield); +} + +/** + * Restore an archived product + * @param {Object} product Product object + * @returns {undefined} No return + */ +export function handleProductRestore(product) { + Meteor.call("products/updateProductField", product._id, "isDeleted", false); +} + +/** + * Save a product field + * @param {String} productId Product ID + * @param {String} fieldName Field name to save + * @param {Any} value Value for that field + * @returns {undefined} No return + */ +export function handleProductFieldSave(productId, fieldName, value) { + Meteor.call("products/updateProductField", productId, fieldName, value, (error) => { + if (error) { + Alerts.toast(error.message, "error"); + this.forceUpdate(); + } + }); +} + +/** + * Handle save of a product variant field + * @param {String} variantId Variant id + * @param {String} fieldName Field name + * @param {Any} value Any value supported by the variant schema + * @returns {undefined} No return + */ +export function handleProductVariantFieldSave(variantId, fieldName, value) { + Meteor.call("products/updateProductField", variantId, fieldName, value, (error) => { + if (error) { + Alerts.toast(error.message, "error"); + } + }); +} + + +/** + * Toggle product visibility + * @param {String} product Product + * @returns {undefined} No return + */ +function handleToggleProductVisibility(product) { + Meteor.call("products/updateProductField", product._id, "isVisible", !product.isVisible); +} + +/** + * @method useProduct + * @summary useProduct hook + * @param {Object} args input arguments + * @param {String} args.productId Product Id to load product data for + * @param {String} args.variantId Variant Id to load product data for + * @param {String} args.optionId Option Id to load product data for + * @returns {Object} Result containing the product and other helpers for managing that product + */ +function useProduct(args = {}) { + const { + productId: productIdProp, + variantId: variantIdProp, + optionId: optionIdProp + } = args; + const [newMetaField, setNewMetaField] = useState({ key: "", value: "" }); + const history = useHistory(); + const routeParams = useParams(); + const [updateProduct] = useMutation(UPDATE_PRODUCT); + const [archiveProducts] = useMutation(ARCHIVE_PRODUCTS); + const [cloneProducts] = useMutation(CLONE_PRODUCTS); + const [createProductVariant] = useMutation(CREATE_VARIANT); + const [currentShopId] = useCurrentShopId(); + + const productId = encodeProductOpaqueId(routeParams.handle) || productIdProp; + const variantId = encodeProductOpaqueId(routeParams.variantId) || variantIdProp; + const optionId = encodeProductOpaqueId(routeParams.optionId) || optionIdProp; + const shopId = routeParams.shopId || currentShopId; + + const { data: productQueryResult, isLoading } = useQuery(PRODUCT_QUERY, { + variables: { + productId, + shopId + } + }); + + const { product } = productQueryResult || {}; + + let variant; + let option; + // let parentVariant; + + if (product && variantId) { + variant = product.variants.find(({ _id }) => _id === variantId); + } + + if (product && variantId && optionId) { + option = variant.options.find(({ _id }) => _id === optionId); + } + + const onArchiveProduct = useCallback(async (product, redirectUrl) => { + const opaqueProductIds = await getOpaqueIds([{ namespace: "Product", id: product._id }]); + + try { + await archiveProducts({ variables: { input: { shopId, productIds: opaqueProductIds } } }); + Alerts.toast(i18next.t("productDetailEdit.archiveProductsSuccess"), "success"); + history.push(redirectUrl); + } catch (error) { + Alerts.toast(i18next.t("productDetailEdit.archiveProductsFail", { err: error }), "error"); + } + }, [ + history, + archiveProducts, + shopId + ]); + + + const onCloneProduct = useCallback(async (product) => { + const opaqueProductIds = await getOpaqueIds([{ namespace: "Product", id: product }]); + + try { + await cloneProducts({ variables: { input: { shopId, productIds: opaqueProductIds } } }); + Alerts.toast(i18next.t("productDetailEdit.cloneProductSuccess"), "success"); + } catch (error) { + Alerts.toast(i18next.t("productDetailEdit.cloneProductFail", { err: error }), "error"); + } + }, [ + cloneProducts, + shopId + ]); + + const onCreateVariant = useCallback(async (product) => { + const [opaqueProductId] = await getOpaqueIds([ + { namespace: "Product", id: product._id }, + { namespace: "Shop", id: product.shopId } + ]); + + try { + await createProductVariant({ variables: { input: { productId: opaqueProductId, shopId } } }); + // Because of the way GraphQL and meteor interact when creating a new variant, + // we can't immediately redirect a user to the new variant as GraphQL is too quick + // and the meteor subscription isn't yet updated. Once this page has been updated + // to use GraphQL for data fetching, add a redirect to the new variant when it's created + Alerts.toast(i18next.t("productDetailEdit.addVariant"), "success"); + } catch (error) { + Alerts.toast(i18next.t("productDetailEdit.addVariantFail", { err: error }), "error"); + } + }, [ + createProductVariant, + shopId + ]); + + const onToggleProductVisibility = useCallback(async () => { + try { + await updateProduct({ + variables: { + input: { + productId: product._id, + shopId, + product: { + isVisible: !product.isVisible + } + } + } + }); + + Alerts.toast(i18next.t("productDetailEdit.updateProductFieldSuccess"), "success"); + } catch (error) { + Alerts.toast(i18next.t("productDetailEdit.updateProductFieldFail", { err: error }), "error"); + } + }, [ + product, + shopId, + updateProduct + ]); + + const onUpdateProduct = useCallback(async ({ + product: productLocal + }) => { + try { + await updateProduct({ + variables: { + input: { + productId: product._id, + shopId, + product: productLocal + } + } + }); + + Alerts.toast(i18next.t("productDetailEdit.updateProductFieldSuccess"), "success"); + } catch (error) { + Alerts.toast(i18next.t("productDetailEdit.updateProductFieldFail", { err: error }), "error"); + } + }, [ + product, + shopId, + updateProduct + ]); + + // const onUpdateProductVariant = useCallback(async (productLocal) => { + // try { + // await updateProductVariant({ + // variables: { + // input: { + // productVariantId: product._id, + // shopId, + // product: productLocal + // } + // } + // }); + + // Alerts.toast(i18next.t("productDetailEdit.updateProductFieldSuccess"), "success"); + // } catch (error) { + // Alerts.toast(i18next.t("productDetailEdit.updateProductFieldFail", { err: error }), "error"); + // } + // }, [ + // product, + // shopId, + // updateProduct + // ]); + + + return { + newMetaField, + isLoading, + onArchiveProduct, + onCloneProduct, + onCreateVariant, + onUpdateProduct, + onProductVariantFieldSave: handleProductVariantFieldSave, + option, + onRestoreProduct: handleProductRestore, + onToggleProductVisibility, + product: productQueryResult && productQueryResult.product, + setNewMetaField, + shopId, + variant + }; +} + +export default useProduct; From 69f7d5afa02d0a25e35bb21a37d42f75aefa5a19 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Thu, 23 Jan 2020 11:25:12 -0800 Subject: [PATCH 003/220] refactor: use `useProduct` hook Signed-off-by: Mike Murray --- .../product-admin/client/blocks/ProductHeader.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/imports/plugins/included/product-admin/client/blocks/ProductHeader.js b/imports/plugins/included/product-admin/client/blocks/ProductHeader.js index 391b2db015..8a43868cd1 100644 --- a/imports/plugins/included/product-admin/client/blocks/ProductHeader.js +++ b/imports/plugins/included/product-admin/client/blocks/ProductHeader.js @@ -1,19 +1,18 @@ import React from "react"; -import PropTypes from "prop-types"; import ProductHeaderComponent from "../components/ProductHeader"; +import useProduct from "../hooks/useProduct"; /** * Product header block component - * @param {Object} props Component props * @returns {Node} React node */ -function ProductHeader(props) { +function ProductHeader() { const { onArchiveProduct, onCloneProduct, onToggleProductVisibility, product - } = props; + } = useProduct(); return ( Date: Thu, 23 Jan 2020 11:27:12 -0800 Subject: [PATCH 004/220] refactor: initial updated to `useProduct` hook Signed-off-by: Mike Murray --- .../client/blocks/ProductDetailForm.js | 824 ++++++++++++------ 1 file changed, 539 insertions(+), 285 deletions(-) diff --git a/imports/plugins/included/product-admin/client/blocks/ProductDetailForm.js b/imports/plugins/included/product-admin/client/blocks/ProductDetailForm.js index 2a46edfd54..5964ce8a18 100644 --- a/imports/plugins/included/product-admin/client/blocks/ProductDetailForm.js +++ b/imports/plugins/included/product-admin/client/blocks/ProductDetailForm.js @@ -1,8 +1,8 @@ import { isEqual } from "lodash"; -import React, { Component } from "react"; +import React, { Component, useState } from "react"; import PropTypes from "prop-types"; import Alert from "sweetalert2"; -import { Components } from "@reactioncommerce/reaction-components"; +// import { Components } from "@reactioncommerce/reaction-components"; import { i18next } from "/client/api"; import update from "immutability-helper"; import { highlightInput } from "/imports/plugins/core/ui/client/helpers/animations"; @@ -10,14 +10,34 @@ import withGenerateSitemaps from "/imports/plugins/included/sitemap-generator/cl import Card from "@material-ui/core/Card"; import CardHeader from "@material-ui/core/CardHeader"; import CardContent from "@material-ui/core/CardContent"; -import withStyles from "@material-ui/core/styles/withStyles"; +import { + makeStyles, + TextField, + Grid, + Button, + Box, + Checkbox +} from "@material-ui/core"; import { compose } from "recompose"; +import useProduct from "../hooks/useProduct"; +// import TextField from "@reactioncommerce/reaction-ui"; +import useReactoForm from "reacto-form/cjs/useReactoForm"; +import SimpleSchema from "simpl-schema"; +import { useSnackbar } from "notistack"; +import muiOptions from "reacto-form/cjs/muiOptions"; +import { useCallback } from "react"; +import TextInput from "@reactioncommerce/components/TextInput/v1" -const styles = (theme) => ({ + +const useStyles = makeStyles((theme) => ({ card: { marginBottom: theme.spacing(2) + }, + textField: { + marginBottom: theme.spacing(4), + minWidth: 350 } -}); +})); const fieldNames = [ "title", @@ -46,289 +66,523 @@ const fieldGroups = { metafields: { group: "metafields" } }; -class DetailForm extends Component { - constructor(props) { - super(props); - - this.state = { - expandedCard: this.fieldGroupForFieldName(props.editFocus), - product: props.product, - viewProps: props.viewProps - }; - } - - UNSAFE_componentWillReceiveProps(nextProps) { // eslint-disable-line camelcase - if (nextProps.product === undefined || this.props.product === undefined) { - return; - } - const nextProduct = nextProps.product; - const currentProduct = this.props.product; - - if (!isEqual(nextProduct, currentProduct)) { - for (const fieldName of fieldNames) { - if (nextProduct[fieldName] !== currentProduct[fieldName]) { - this.animateFieldFlash(fieldName); - } - } - } - - const cardGroupName = this.fieldGroupForFieldName(nextProps.editFocus); - - this.setState({ - expandedCard: cardGroupName, - viewProps: nextProps.viewProps - }); - - this.setState({ - product: nextProps.product - }); - } - - fieldGroupForFieldName(field) { - // Other wise, if a field was passed - // const fieldName = this.state.viewProps.field; - - let fieldName; - - // If the field is an array of field name - if (Array.isArray(field) && field.length) { - // Use the first field name - [fieldName] = field; - } else { - fieldName = field; - } - - const fieldData = fieldGroups[fieldName]; - - if (fieldData && fieldData.group) { - return fieldData.group; - } - - return fieldName; +const formSchema = new SimpleSchema({ + title: { + type: String, + optional: true + }, + permalink: { + type: String, + optional: true + }, + pageTitle: { + type: String, + optional: true + }, + vendor: { + type: String, + optional: true + }, + description: { + type: String, + optional: true } - - animateFieldFlash(fieldName) { - const fieldRef = this.refs[`${fieldName}Input`]; - - if (fieldRef) { - const { input } = fieldRef.refs; - highlightInput(input); - } - } - - handleDeleteProduct = () => { - if (this.props.onDeleteProduct) { - this.props.onDeleteProduct(this.props.product); - } - } - - handleRestoreProduct = () => { - if (this.props.onRestoreProduct) { - this.props.onRestoreProduct(this.props.product); - } - } - - handleFieldChange = (event, value, field) => { - const newState = update(this.state, { - product: { - $merge: { - [field]: value - } - } - }); - - this.setState(newState, () => { - if (this.props.onFieldChange) { - this.props.onFieldChange(field, value); - } - }); - } - - handleSelectChange = (value, field) => { - if (this.props.onProductFieldSave) { - this.props.onProductFieldSave(this.product._id, field, value); - } - } - - handleSitemapCheckboxChange = (event) => { - const { checked: isChecked } = event.target; - const { shouldAppearInSitemap } = this.product; - if (typeof shouldAppearInSitemap === "undefined" || isChecked === shouldAppearInSitemap) { - // onChange for checkbox runs when field is first displayed - return; - } - - if (this.props.onProductFieldSave) { - this.props.onProductFieldSave(this.product._id, "shouldAppearInSitemap", isChecked); - } - - const { isVisible, isDeleted } = this.product; - if (isVisible && !isDeleted) { - // If product is published, ask whether to regenerate sitemap - Alert({ - title: i18next.t("productDetailEdit.refreshSitemap", { defaultValue: "Refresh sitemap now?" }), - type: "warning", - showCancelButton: true, - cancelButtonText: i18next.t("productDetailEdit.refreshSitemapNo", { defaultValue: "No, don't refresh" }), - confirmButtonText: i18next.t("productDetailEdit.refreshSitemapYes", { defaultValue: "Yes, refresh" }) - }) - .then(({ value }) => { - if (value) { - this.props.generateSitemaps(); - Alerts.toast(i18next.t("shopSettings.sitemapRefreshInitiated", { - defaultValue: "Refreshing the sitemap can take up to 5 minutes. You will be notified when it is completed." - }), "success"); - } - return false; - }) - .catch(() => false); - } - }; - - handleFieldBlur = (event, value, field) => { - if (this.props.onProductFieldSave) { - this.props.onProductFieldSave(this.product._id, field, value); - } +}); +const validator = formSchema.getFormValidator(); + + +/** + * + * @param {*} props + */ +const ProductDetailForm = React.forwardRef((props, ref) => { + const classes = useStyles(); + const [isSubmitting, setIsSubmitting] = useState(false); + const { enqueueSnackbar } = useSnackbar(); + const { + onUpdateProduct, + product, + shopId + } = useProduct(); + + let content; + console.log("Product from hook", product); + + const { + getFirstErrorMessage, + getInputProps, + hasErrors, + resetValue, + formData, + submitForm + } = useReactoForm({ + async onSubmit(formData) { + setIsSubmitting(true); + + await onUpdateProduct({ + product: formSchema.clean(formData) + }); + + resetValue(); + setIsSubmitting(false); + }, + validator(formData) { + return validator(formSchema.clean(formData)); + }, + value: product + }); + + console.log("FORM DATA", formData); + + + if (product) { + content = ( +
{ + event.preventDefault(); + submitForm(); + }} + > + {product.title} + + + + + + {/* + + + + + {/* */} {/* - */} + { + if (event.key === "Enter") submitForm(); + }} + select + {...originCountryInputProps} + // Avoid "value must be an array" error + value={originCountryInputProps.value || []} + > + {CountryOptions.map((option) => ( + + {option.label} + + ))} + + } + /> + + ); } - isExpanded = (groupName) => this.state.expandedCard === groupName - - render() { - const { classes } = this.props; - - return ( - - - - - - - - - - ); - } -} - -ProductAdmin.propTypes = { - classes: PropTypes.object, - countries: PropTypes.arrayOf(PropTypes.object), - editFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]), - editable: PropTypes.bool, // eslint-disable-line react/boolean-prop-naming - generateSitemaps: PropTypes.func, - handleFieldBlur: PropTypes.func, - handleFieldChange: PropTypes.func, - handleProductFieldChange: PropTypes.func, - newMetafield: PropTypes.object, - onCardExpand: PropTypes.func, - onDeleteProduct: PropTypes.func, - onFieldChange: PropTypes.func, - onMetaChange: PropTypes.func, - onMetaRemove: PropTypes.func, - onMetaSave: PropTypes.func, - onProductFieldSave: PropTypes.func, - onRestoreProduct: PropTypes.func, - product: PropTypes.object, - templates: PropTypes.arrayOf(PropTypes.shape({ - label: PropTypes.string, - value: PropTypes.any - })), - viewProps: PropTypes.object -}; - + return ( + + + + {content} + + + ); +}); -export default compose( - withGenerateSitemaps, - withStyles(styles) -)(ProductAdmin); +export default ProductSocialForm; From 89872cbc824156880eac6a4bdab8e40612652dd1 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Fri, 24 Jan 2020 16:02:04 -0800 Subject: [PATCH 016/220] refactor: include social form Signed-off-by: Mike Murray --- .../included/product-admin/client/blocks/index.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/imports/plugins/included/product-admin/client/blocks/index.js b/imports/plugins/included/product-admin/client/blocks/index.js index e855bfdd6f..f13efe6e2c 100644 --- a/imports/plugins/included/product-admin/client/blocks/index.js +++ b/imports/plugins/included/product-admin/client/blocks/index.js @@ -50,13 +50,12 @@ registerBlock({ // priority: 20 // }); -// registerBlock({ -// region: "ProductDetailMain", -// name: "ProductSocialForm", -// component: ProductSocialForm, -// hocs: [withProductForm], -// priority: 30 -// }); +registerBlock({ + region: "ProductDetailMain", + name: "ProductSocialForm", + component: ProductSocialForm, + priority: 30 +}); // registerBlock({ // region: "ProductDetailMain", From ae96ebc37aba04b946fa6c56e27716da1b1da1cc Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 29 Jan 2020 13:53:02 -0800 Subject: [PATCH 017/220] feat: update catalyst and peer dependencies Signed-off-by: Mike Murray --- package-lock.json | 314 ++++++++++++++++++++++++++++++++-------------- package.json | 5 +- 2 files changed, 223 insertions(+), 96 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0f384b62a..27cb83ece7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2487,108 +2487,248 @@ } }, "@material-ui/core": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.3.3.tgz", - "integrity": "sha512-wUQjoJEbtVWYi+R9gBWCPGy0O+c0oY8cAp2TugyB70f89ahq/cnfnTbMZl6O2arKe2xQlfAMzY8rOOy8UMzJoQ==", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.9.0.tgz", + "integrity": "sha512-zrrr8mPU5DDBYaVil4uJYauW41PjSn5otn7cqGsmWOY0t90fypr9nNgM7rRJaPz2AP6oRSDx1kBQt2igf5uelg==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/styles": "^4.3.3", - "@material-ui/system": "^4.3.3", - "@material-ui/types": "^4.1.1", - "@material-ui/utils": "^4.3.0", + "@material-ui/styles": "^4.9.0", + "@material-ui/system": "^4.7.1", + "@material-ui/types": "^5.0.0", + "@material-ui/utils": "^4.7.1", "@types/react-transition-group": "^4.2.0", "clsx": "^1.0.2", "convert-css-length": "^2.0.1", - "deepmerge": "^4.0.0", "hoist-non-react-statics": "^3.2.1", - "is-plain-object": "^3.0.0", "normalize-scroll-left": "^0.2.0", "popper.js": "^1.14.1", "prop-types": "^15.7.2", - "react-transition-group": "^4.0.0", - "warning": "^4.0.1" + "react-is": "^16.8.0", + "react-transition-group": "^4.3.0" }, "dependencies": { + "@emotion/hash": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.7.4.tgz", + "integrity": "sha512-fxfMSBMX3tlIbKUdtGKxqB1fyrH6gVrX39Gsv3y8lRYKUqlgDt3UMqQyGnR1bQMa2B8aGnhLZokZgg8vT0Le+A==" + }, + "@material-ui/styles": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.0.tgz", + "integrity": "sha512-nJHum4RqYBPWsjL/9JET8Z02FZ9gSizlg/7LWVFpIthNzpK6OQ5OSRR4T4x9/p+wK3t1qNn3b1uI4XpnZaPxOA==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.7.4", + "@material-ui/types": "^5.0.0", + "@material-ui/utils": "^4.7.1", + "clsx": "^1.0.2", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.2.1", + "jss": "^10.0.3", + "jss-plugin-camel-case": "^10.0.3", + "jss-plugin-default-unit": "^10.0.3", + "jss-plugin-global": "^10.0.3", + "jss-plugin-nested": "^10.0.3", + "jss-plugin-props-sort": "^10.0.3", + "jss-plugin-rule-value-function": "^10.0.3", + "jss-plugin-vendor-prefixer": "^10.0.3", + "prop-types": "^15.7.2" + } + }, + "@material-ui/types": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.0.0.tgz", + "integrity": "sha512-UeH2BuKkwDndtMSS0qgx1kCzSMw+ydtj0xx/XbFtxNSTlXydKwzs5gVW5ZKsFlAkwoOOQ9TIsyoCC8hq18tOwg==" + }, + "@material-ui/utils": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.7.1.tgz", + "integrity": "sha512-+ux0SlLdlehvzCk2zdQ3KiS3/ylWvuo/JwAGhvb8dFVvwR21K28z0PU9OQW2PGogrMEdvX3miEI5tGxTwwWiwQ==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + } + }, "@types/react-transition-group": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.2.tgz", - "integrity": "sha512-YfoaTNqBwbIqpiJ5NNfxfgg5kyFP1Hqf/jqBtSWNv0E+EkkxmN+3VD6U2fu86tlQvdAc1o0SdWhnWFwcRMTn9A==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.2.3.tgz", + "integrity": "sha512-Hk8jiuT7iLOHrcjKP/ZVSyCNXK73wJAUz60xm0mVhiRujrdiI++j4duLiL282VGxwAgxetHQFfqA29LgEeSkFA==", "requires": { "@types/react": "*" } }, - "deepmerge": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.0.0.tgz", - "integrity": "sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww==" + "css-vendor": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.7.tgz", + "integrity": "sha512-VS9Rjt79+p7M0WkPqcAza4Yq1ZHrsHrwf7hPL/bjQB+c1lwmAI+1FXxYTYt818D/50fFVflw0XKleiBN5RITkg==", + "requires": { + "@babel/runtime": "^7.6.2", + "is-in-browser": "^1.0.2" + } }, "dom-helpers": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", - "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.3.tgz", + "integrity": "sha512-nZD1OtwfWGRBWlpANxacBEZrEuLa16o1nh7YopFWeoF68Zt8GGEmzHu6Xv4F3XaFIC+YXtTLrzgqKxFgLEe4jw==", "requires": { - "@babel/runtime": "^7.1.2" + "@babel/runtime": "^7.6.3", + "csstype": "^2.6.7" + }, + "dependencies": { + "csstype": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.8.tgz", + "integrity": "sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA==" + } } }, "hoist-non-react-statics": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz", - "integrity": "sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", "requires": { "react-is": "^16.7.0" } }, - "is-plain-object": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.0.tgz", - "integrity": "sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg==", + "hyphenate-style-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz", + "integrity": "sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==" + }, + "jss": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.0.4.tgz", + "integrity": "sha512-GqHmeDK83qbqMAVjxyPfN1qJVTKZne533a9bdCrllZukUM8npG/k+JumEPI86IIB5ifaZAHG2HAsUziyxOiooQ==", "requires": { - "isobject": "^4.0.0" + "@babel/runtime": "^7.3.1", + "csstype": "^2.6.5", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.8.tgz", + "integrity": "sha512-msVS9qTuMT5zwAGCVm4mxfrZ18BNc6Csd0oJAtiFMZ1FAx1CCvy2+5MDmYoix63LM/6NDbNtodCiGYGmFgO0dA==" + } } }, - "isobject": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==" + "jss-plugin-camel-case": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.0.4.tgz", + "integrity": "sha512-+wnqxJsyfUnOn0LxVg3GgZBSjfBCrjxwx7LFxwVTUih0ceGaXKZoieheNOaTo5EM4w8bt1nbb8XonpQCj67C6A==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.0.4" + } + }, + "jss-plugin-default-unit": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.0.4.tgz", + "integrity": "sha512-T0mhL/Ogp/quvod/jAHEqKvptLDxq7Cj3a+7zRuqK8HxUYkftptN89wJElZC3rshhNKiogkEYhCWenpJdFvTBg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.4" + } + }, + "jss-plugin-global": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.0.4.tgz", + "integrity": "sha512-N8n9/GHENZce+sqE4UYiZiJtI+t+erT/BypHOrNYAfIoNEj7OYsOEKfIo2P0GpLB3QyDAYf5eo9XNdZ8veEkUA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.4" + } + }, + "jss-plugin-nested": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.0.4.tgz", + "integrity": "sha512-QM21BKVt8LDeoRfowvAMh/s+/89VYrreIIE6ch4pvw0oAXDWw1iorUPlqLZ7uCO3UL0uFtQhJq3QMLN6Lr1v0A==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.4", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.0.4.tgz", + "integrity": "sha512-WoETdOCjGskuin/OMt2uEdDPLZF3vfQuHXF+XUHGJrq0BAapoyGQDcv37SeReDlkRAbVXkEZPsIMvYrgHSHFiA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.4" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.0.4.tgz", + "integrity": "sha512-0hrzOSWRF5ABJGaHrlnHbYZjU877Ofzfh2id3uLtBvemGQLHI+ldoL8/+6iPSRa7M8z8Ngfg2vfYhKjUA5gA0g==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.0.4" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.0.4.tgz", + "integrity": "sha512-4JgEbcrdeMda1qvxTm1CnxFJAWVV++VLpP46HNTrfH7VhVlvUpihnUNs2gAlKuRT/XSBuiWeLAkrTqF4NVrPig==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.7", + "jss": "10.0.4" + } }, "normalize-scroll-left": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/normalize-scroll-left/-/normalize-scroll-left-0.2.0.tgz", "integrity": "sha512-t5oCENZJl8TGusJKoCJm7+asaSsPuNmK6+iEjrZ5TyBj2f02brCRsd4c83hwtu+e5d4LCSBZ0uoDlMjBo+A8yA==" }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", - "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" - } - }, "react-is": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==" + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" }, "react-transition-group": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.2.2.tgz", - "integrity": "sha512-uP0tjqewtvjb7kGZFpZYPoD/NlVZmIgts9eTt1w35pAaEApPxQGv94lD3VkqyXf2aMqrSGwhs6EV/DLaoKbLSw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.3.0.tgz", + "integrity": "sha512-1qRV1ZuVSdxPlPf4O8t7inxUGpdyO5zG9IoNfJxSO0ImU2A1YWkEQvFPuIPZmMLkg5hYs7vv5mMOyfgSkvAwvw==", "requires": { - "@babel/runtime": "^7.4.5", - "dom-helpers": "^3.4.0", + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", "loose-envify": "^1.4.0", "prop-types": "^15.6.2" } - }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + } + } + }, + "@material-ui/lab": { + "version": "4.0.0-alpha.40", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.40.tgz", + "integrity": "sha512-VwXCNFJKfctu9Ot9XP5u2SSzXpm2Fn7F/o08bUfrJDkMCuRc8MCGVnNhT+guZRZa35rR97uWKc3SGQ/LAv8yEg==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.7.1", + "clsx": "^1.0.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" + }, + "dependencies": { + "@material-ui/utils": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.7.1.tgz", + "integrity": "sha512-+ux0SlLdlehvzCk2zdQ3KiS3/ylWvuo/JwAGhvb8dFVvwR21K28z0PU9OQW2PGogrMEdvX3miEI5tGxTwwWiwQ==", "requires": { - "loose-envify": "^1.0.0" + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" } + }, + "react-is": { + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" } } }, @@ -2660,43 +2800,29 @@ } }, "@material-ui/system": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.3.3.tgz", - "integrity": "sha512-j7JyvlhcTdc1wV6HzrDTU7XXlarxYXEUyzyHawOA0kCGmYVN2uFHENQRARLUdl+mEmuXO4TsAhNAiqiKakkFMg==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.7.1.tgz", + "integrity": "sha512-zH02p+FOimXLSKOW/OT2laYkl9bB3dD1AvnZqsHYoseUaq0aVrpbl2BGjQi+vJ5lg8w73uYlt9zOWzb3+1UdMQ==", "requires": { "@babel/runtime": "^7.4.4", - "deepmerge": "^4.0.0", - "prop-types": "^15.7.2", - "warning": "^4.0.1" + "@material-ui/utils": "^4.7.1", + "prop-types": "^15.7.2" }, "dependencies": { - "deepmerge": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.0.0.tgz", - "integrity": "sha512-YZ1rOP5+kHor4hMAH+HRQnBQHg+wvS1un1hAOuIcxcBy0hzcUf6Jg2a1w65kpoOUnurOfZbERwjI1TfZxNjcww==" - }, - "prop-types": { - "version": "15.7.2", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", - "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "@material-ui/utils": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.7.1.tgz", + "integrity": "sha512-+ux0SlLdlehvzCk2zdQ3KiS3/ylWvuo/JwAGhvb8dFVvwR21K28z0PU9OQW2PGogrMEdvX3miEI5tGxTwwWiwQ==", "requires": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.8.1" + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0" } }, "react-is": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.9.0.tgz", - "integrity": "sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw==" - }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "requires": { - "loose-envify": "^1.0.0" - } + "version": "16.12.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.12.0.tgz", + "integrity": "sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==" } } }, @@ -2736,9 +2862,9 @@ } }, "@reactioncommerce/catalyst": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@reactioncommerce/catalyst/-/catalyst-1.14.1.tgz", - "integrity": "sha512-E95PmlsgCr8rcasQmpDMSkfJCZF6ew3fbtq7vVLnRvgLIn5zKhlxkqwdRFgmBgfLKIZ9yI69xBGeymS4Zdhadg==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@reactioncommerce/catalyst/-/catalyst-1.18.0.tgz", + "integrity": "sha512-jSL1w/ZeRxJEnHFsVgTRJEtRXXi9kg27jRzXHN09kW78qU9LntZXisBOxe8l9sEfadKG3cUeMkH/FNnTiJAHcA==", "requires": { "@babel/runtime": "~7.3.1", "accounting-js": "~1.1.1", @@ -2751,7 +2877,7 @@ "mdi-material-ui": "~5.8.0", "react-is": "~16.4.1", "react-select": "^3.0.4", - "react-table": "7.0.0-beta.0" + "react-table": "7.0.0-rc.15" }, "dependencies": { "@babel/runtime": { @@ -2768,9 +2894,9 @@ "integrity": "sha512-KixZVfNg0ejURv9CIliB1M3kl4Soe6f6yAFjFNsoYPMvGGw1AhnQKGZ3EOEKOIdp2X9YeZFOaO+i9e4ZHUrpNA==" }, "react-table": { - "version": "7.0.0-beta.0", - "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.0.0-beta.0.tgz", - "integrity": "sha512-ddPDtsGMAq1m4Mh/pIn1uUaGAUikS52YMAfOhduKQkz+3UuQVqcUU44C6e8/9S7GZrMB+Vp1MwqmHJwR5ciW/g==" + "version": "7.0.0-rc.15", + "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.0.0-rc.15.tgz", + "integrity": "sha512-ofMOlgrioHhhvHjvjsQkxvfQzU98cqwy6BjPGNwhLN1vhgXeWi0mUGreaCPvRenEbTiXsQbMl4k3Xmx3Mut8Rw==" }, "regenerator-runtime": { "version": "0.12.1", diff --git a/package.json b/package.json index 9e13cfa3ba..7f4368373a 100644 --- a/package.json +++ b/package.json @@ -25,9 +25,10 @@ "@fortawesome/fontawesome-svg-core": "^1.2.25", "@fortawesome/free-solid-svg-icons": "^5.7.1", "@fortawesome/react-fontawesome": "^0.1.4", - "@material-ui/core": "^4.3.2", + "@material-ui/core": "^4.9.0", + "@material-ui/lab": "^4.0.0-alpha.40", "@material-ui/styles": "^4.5.0", - "@reactioncommerce/catalyst": "~1.14.1", + "@reactioncommerce/catalyst": "^1.18.0", "@reactioncommerce/components": "^0.69.0", "@reactioncommerce/components-context": "1.2.0", "@reactioncommerce/file-collections": "^0.7.3", From db15fe55abe8dd583f4f3df502e6c47ea23a3b2f Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 29 Jan 2020 13:53:49 -0800 Subject: [PATCH 018/220] fix: use named import Signed-off-by: Mike Murray --- imports/client/ui/startup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imports/client/ui/startup.js b/imports/client/ui/startup.js index 9ff38de235..0659150c97 100644 --- a/imports/client/ui/startup.js +++ b/imports/client/ui/startup.js @@ -5,7 +5,7 @@ import { AuthenticationProvider, oidcLog } from "@axa-fr/react-oidc-context"; import { Meteor } from "meteor/meteor"; import { Tracker } from "meteor/tracker"; import { ThemeProvider } from "styled-components"; -import MuiThemeProvider from "@material-ui/core/styles/MuiThemeProvider"; +import { ThemeProvider as MuiThemeProvider } from "@material-ui/core/styles"; import { ApolloProvider } from "react-apollo"; import { ComponentsProvider } from "@reactioncommerce/components-context"; import { TranslationProvider } from "/imports/plugins/core/ui/client/providers"; From e16db182485844685806692d0b06527b256f55d6 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 29 Jan 2020 13:55:10 -0800 Subject: [PATCH 019/220] fix: import from material-ui/core Signed-off-by: Mike Murray --- .../core/dashboard/client/components/CreateFirstShopForm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imports/plugins/core/dashboard/client/components/CreateFirstShopForm.js b/imports/plugins/core/dashboard/client/components/CreateFirstShopForm.js index 1216f72004..57d030d500 100644 --- a/imports/plugins/core/dashboard/client/components/CreateFirstShopForm.js +++ b/imports/plugins/core/dashboard/client/components/CreateFirstShopForm.js @@ -3,7 +3,7 @@ import PropTypes from "prop-types"; import SimpleSchema from "simpl-schema"; import Button from "@reactioncommerce/catalyst/Button"; import TextField from "@material-ui/core/TextField"; -import { makeStyles } from "@material-ui/styles"; +import { makeStyles } from "@material-ui/core"; import muiOptions from "reacto-form/cjs/muiOptions"; import useReactoForm from "reacto-form/cjs/useReactoForm"; From a0403eb4caaf61d6e0db026a307c32df881a1d24 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 29 Jan 2020 13:55:16 -0800 Subject: [PATCH 020/220] fix: use named import Signed-off-by: Mike Murray --- imports/plugins/core/router/client/browserRouter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imports/plugins/core/router/client/browserRouter.js b/imports/plugins/core/router/client/browserRouter.js index 713b39b041..dbebd3a3a0 100644 --- a/imports/plugins/core/router/client/browserRouter.js +++ b/imports/plugins/core/router/client/browserRouter.js @@ -2,7 +2,7 @@ import React, { Component } from "react"; import PropTypes from "prop-types"; import ReactDOM from "react-dom"; import { ThemeProvider } from "styled-components"; -import MuiThemeProvider from "@material-ui/core/styles/MuiThemeProvider"; +import { ThemeProvider as MuiThemeProvider } from "@material-ui/core/styles"; import { matchPath } from "react-router"; import { Router as ReactRouter } from "react-router-dom"; import { ApolloProvider } from "react-apollo"; From 8e664a5b9a2b59966fef5ad397bfc3734c2a37fd Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 29 Jan 2020 13:55:22 -0800 Subject: [PATCH 021/220] fix: use named import Signed-off-by: Mike Murray --- imports/plugins/core/ui/client/helpers/react-template-helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imports/plugins/core/ui/client/helpers/react-template-helper.js b/imports/plugins/core/ui/client/helpers/react-template-helper.js index 027aac7c0f..bc4a2b623e 100644 --- a/imports/plugins/core/ui/client/helpers/react-template-helper.js +++ b/imports/plugins/core/ui/client/helpers/react-template-helper.js @@ -4,7 +4,7 @@ import ReactDOM from "react-dom"; import { ApolloProvider } from "react-apollo"; import { ComponentsProvider } from "@reactioncommerce/components-context"; import { ThemeProvider } from "styled-components"; -import MuiThemeProvider from "@material-ui/core/styles/MuiThemeProvider"; +import { ThemeProvider as MuiThemeProvider } from "@material-ui/core/styles"; import _ from "lodash"; import { Template } from "meteor/templating"; import { Blaze } from "meteor/blaze"; From ca5bb61d5df0cc9678113d63f8a43d3ec5f5ee33 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 29 Jan 2020 13:55:43 -0800 Subject: [PATCH 022/220] refactor: reintroduce the tag form block Signed-off-by: Mike Murray --- .../included/product-admin/client/blocks/index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/imports/plugins/included/product-admin/client/blocks/index.js b/imports/plugins/included/product-admin/client/blocks/index.js index f13efe6e2c..8a492aa603 100644 --- a/imports/plugins/included/product-admin/client/blocks/index.js +++ b/imports/plugins/included/product-admin/client/blocks/index.js @@ -57,12 +57,12 @@ registerBlock({ priority: 30 }); -// registerBlock({ -// region: "ProductDetailMain", -// name: "ProductTagForm", -// component: ProductTagForm, -// priority: 40 -// }); +registerBlock({ + region: "ProductDetailMain", + name: "ProductTagForm", + component: ProductTagForm, + priority: 40 +}); // registerBlock({ // region: "ProductDetailMain", From f5d1e6dd5c5930cd9b922d9a49ae5213503b2479 Mon Sep 17 00:00:00 2001 From: Mike Murray Date: Wed, 29 Jan 2020 13:56:41 -0800 Subject: [PATCH 023/220] feat: add bulk tag dialog Signed-off-by: Mike Murray --- .../TagSelector/TagSelectorDialog.js | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 imports/plugins/included/product-admin/client/components/TagSelector/TagSelectorDialog.js diff --git a/imports/plugins/included/product-admin/client/components/TagSelector/TagSelectorDialog.js b/imports/plugins/included/product-admin/client/components/TagSelector/TagSelectorDialog.js new file mode 100644 index 0000000000..4b870648ef --- /dev/null +++ b/imports/plugins/included/product-admin/client/components/TagSelector/TagSelectorDialog.js @@ -0,0 +1,188 @@ +import React, { useState } from "react"; +import PropTypes from "prop-types"; +import i18next from "i18next"; +import CloseIcon from "mdi-material-ui/Close"; +import Button from "@reactioncommerce/catalyst/Button"; +import Select from "@reactioncommerce/catalyst/Select"; +import SplitButton from "@reactioncommerce/catalyst/SplitButton"; +import { useApolloClient } from "@apollo/react-hooks"; +import { useSnackbar } from "notistack"; +import { + Box, + Grid, + CardActions, + CardHeader, + CardContent, + Dialog, + IconButton, + makeStyles +} from "@material-ui/core"; +import { getTags } from "./helpers"; +import { ADD_TAGS_TO_PRODUCTS, REMOVE_TAGS_FROM_PRODUCTS } from "./mutations"; + +const ACTION_OPTIONS = [{ + label: "Add tags to products", + type: "ADD" +}, { + label: "Remove tags from products", + isDestructive: true, + type: "REMOVE" +}]; + +const useStyles = makeStyles((theme) => ({ + cardRoot: { + overflow: "visible", + padding: theme.spacing(2) + }, + cardContainer: { + alignItems: "center" + }, + cardActions: { + padding: theme.spacing(2), + justifyContent: "flex-end" + }, + hidden: { + display: "none" + }, + visible: { + display: "block" + } +})); + +/** + * TagSelector component + * @param {Object} props Component props + * @returns {React.Component} A React component + */ +function TagSelector({ isOpen, onClose, onSuccess, productIds, shopId }) { + const apolloClient = useApolloClient(); + const [selectedTags, setSelectedTags] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const classes = useStyles(); + const { enqueueSnackbar } = useSnackbar(); + + // eslint-disable-next-line consistent-return + const handleTagsAction = async (option) => { + const tagIds = selectedTags && selectedTags.map(({ value }) => (value)); + + // Prevent user from executing action if he/she has not // yet selected at least one tag + if (!tagIds.length) { + return enqueueSnackbar(i18next.t("admin.addRemoveTags.invalidSelection"), { variant: "warning" }); + } + + let mutationName; + let data; let loading; let error; + setIsLoading(true); + switch (option.type) { + case "ADD": + mutationName = "addTagsToProducts"; + ({ data, loading, error } = await apolloClient.mutate({ + mutation: ADD_TAGS_TO_PRODUCTS, + variables: { + input: { + productIds, + shopId, + tagIds + } + } + })); + + setIsLoading(loading); + break; + case "REMOVE": + mutationName = "removeTagsFromProducts"; + ({ data, loading, error } = await apolloClient.mutate({ + mutation: REMOVE_TAGS_FROM_PRODUCTS, + variables: { + input: { + productIds, + shopId, + tagIds + } + } + })); + + setIsLoading(loading); + break; + + default: + break; + } + + if (data && data[mutationName]) { + // Notify user of performed action + if (mutationName.startsWith("add")) { + enqueueSnackbar(i18next.t("admin.addRemoveTags.addConfirmation")); + } else { + enqueueSnackbar(i18next.t("admin.addRemoveTags.removeConfirmation")); + } + onSuccess && onSuccess(); + } + + if (error) { + enqueueSnackbar(i18next.t("admin.addRemoveTags.errorMessage"), { variant: "error" }); + } + + onClose(); + setSelectedTags([]); + }; + + return ( + + + + + } + title={i18next.t("admin.addRemoveTags.title")} + /> + + + + getTags(apolloClient, query)} - onSelection={(tags) => setSelectedTags(tags)} - placeholder={i18next.t("admin.addRemoveTags.inputPlaceholder")} - /> - - - - - + + setVisibility(false)}> + + + } + title={i18next.t("admin.productTable.bulkActions.addRemoveTags")} /> - - + + + +