From e41a79fe78956de6a66c1b3124b3ba6d0c8914f7 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Wed, 1 Apr 2020 18:28:47 +0200 Subject: [PATCH] Make variant creator view instead of dialog --- .../ProductVariantCreateContent.tsx | 147 -------- .../ProductVariantCreatePrices.tsx | 315 ----------------- .../ProductVariantCreateValues.tsx | 81 ----- .../ProductVariantCreateDialog/index.ts | 0 .../ProductVariantCreateDialog/types.ts | 5 - .../ProductVariantCreator.stories.tsx} | 63 ++-- .../ProductVariantCreatorContent.tsx | 122 +++++++ .../ProductVariantCreatorPage.tsx} | 136 ++++--- .../ProductVariantCreatorPrices.tsx | 331 ++++++++++++++++++ .../ProductVariantCreatorSummary.tsx} | 29 +- .../ProductVariantCreatorTabs.tsx} | 24 +- .../ProductVariantCreatorValues.tsx | 75 ++++ .../__snapshots__/reducer.test.ts.snap | 0 .../createVariants.test.ts | 0 .../createVariants.ts | 7 +- .../fixtures.ts | 0 .../form.ts | 0 .../ProductVariantCreatorPage/index.ts | 2 + .../reducer.test.ts | 0 .../reducer.ts | 0 .../ProductVariantCreatorPage/types.ts | 5 + .../containers/ProductUpdateOperations.tsx | 70 ++-- src/products/index.tsx | 14 +- src/products/mutations.ts | 2 +- src/products/queries.ts | 91 +++-- .../types/CreateMultipleVariantsData.ts | 80 +++++ src/products/types/Product.ts | 93 ++--- src/products/types/ProductCreate.ts | 93 ++--- src/products/types/ProductDetails.ts | 108 +++--- src/products/types/ProductImageCreate.ts | 93 ++--- src/products/types/ProductImageUpdate.ts | 93 ++--- src/products/types/ProductUpdate.ts | 93 ++--- .../types/ProductVariantAttributesFragment.ts | 65 ++++ src/products/types/SimpleProductUpdate.ts | 93 ++--- src/products/urls.ts | 11 +- .../ProductMultipleVariantCreate.tsx | 0 .../ProductMultipleVariantCreate/index.ts | 0 .../ProductMultipleVariantCreate/paginate.ts | 0 .../views/ProductUpdate/ProductUpdate.tsx | 42 +-- .../ProductVariantCreator.tsx | 71 ++++ .../views/ProductVariantCreator/index.ts | 2 + 41 files changed, 1352 insertions(+), 1104 deletions(-) delete mode 100644 src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx delete mode 100644 src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx delete mode 100644 src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx delete mode 100644 src/products/components/ProductVariantCreateDialog/index.ts delete mode 100644 src/products/components/ProductVariantCreateDialog/types.ts rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreate.stories.tsx => ProductVariantCreatorPage/ProductVariantCreator.stories.tsx} (66%) create mode 100644 src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreateDialog.tsx => ProductVariantCreatorPage/ProductVariantCreatorPage.tsx} (54%) create mode 100644 src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreateSummary.tsx => ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx} (92%) rename src/products/components/{ProductVariantCreateDialog/ProductVariantCreateTabs.tsx => ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx} (78%) create mode 100644 src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/__snapshots__/reducer.test.ts.snap (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/createVariants.test.ts (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/createVariants.ts (94%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/fixtures.ts (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/form.ts (100%) create mode 100644 src/products/components/ProductVariantCreatorPage/index.ts rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/reducer.test.ts (100%) rename src/products/components/{ProductVariantCreateDialog => ProductVariantCreatorPage}/reducer.ts (100%) create mode 100644 src/products/components/ProductVariantCreatorPage/types.ts create mode 100644 src/products/types/CreateMultipleVariantsData.ts create mode 100644 src/products/types/ProductVariantAttributesFragment.ts delete mode 100644 src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx delete mode 100644 src/products/views/ProductMultipleVariantCreate/index.ts delete mode 100644 src/products/views/ProductMultipleVariantCreate/paginate.ts create mode 100644 src/products/views/ProductVariantCreator/ProductVariantCreator.tsx create mode 100644 src/products/views/ProductVariantCreator/index.ts diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx deleted file mode 100644 index 2b0fae0b1..000000000 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateContent.tsx +++ /dev/null @@ -1,147 +0,0 @@ -import { makeStyles } from "@material-ui/core/styles"; -import React from "react"; - -import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; -import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; -import { isSelected } from "@saleor/utils/lists"; -import { ProductVariantCreateFormData } from "./form"; -import ProductVariantCreatePrices from "./ProductVariantCreatePrices"; -import ProductVariantCreateSummary from "./ProductVariantCreateSummary"; -import ProductVariantCreateTabs from "./ProductVariantCreateTabs"; -import ProductVariantCreateValues from "./ProductVariantCreateValues"; -import { ProductVariantCreateReducerAction } from "./reducer"; -import { ProductVariantCreateStep } from "./types"; - -const useStyles = makeStyles( - theme => ({ - root: { - maxHeight: 400, - overflowX: "hidden", - overflowY: "scroll", - paddingLeft: theme.spacing(3), - paddingRight: theme.spacing(2), - position: "relative", - right: theme.spacing(3), - width: `calc(100% + ${theme.spacing(3)}px)` - } - }), - { name: "ProductVariantCreateContent" } -); - -export interface ProductVariantCreateContentProps { - attributes: ProductDetails_product_productType_variantAttributes[]; - currencySymbol: string; - data: ProductVariantCreateFormData; - dispatchFormDataAction: React.Dispatch; - errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[]; - step: ProductVariantCreateStep; - onStepClick: (step: ProductVariantCreateStep) => void; -} - -const ProductVariantCreateContent: React.FC = props => { - const { - attributes, - currencySymbol, - data, - dispatchFormDataAction, - errors, - step, - onStepClick - } = props; - const classes = useStyles(props); - - const selectedAttributes = attributes.filter(attribute => - isSelected( - attribute.id, - data.attributes.map(dataAttribute => dataAttribute.id), - (a, b) => a === b - ) - ); - - return ( -
- -
- {step === ProductVariantCreateStep.values && ( - - dispatchFormDataAction({ - attributeId, - type: "selectValue", - valueId - }) - } - /> - )} - {step === ProductVariantCreateStep.prices && ( - - dispatchFormDataAction({ - all, - type: type === "price" ? "applyPriceToAll" : "applyStockToAll" - }) - } - onApplyToAllChange={(value, type) => - dispatchFormDataAction({ - type: - type === "price" - ? "changeApplyPriceToAllValue" - : "changeApplyStockToAllValue", - value - }) - } - onAttributeSelect={(attributeId, type) => - dispatchFormDataAction({ - attributeId, - type: - type === "price" - ? "changeApplyPriceToAttributeId" - : "changeApplyStockToAttributeId" - }) - } - onAttributeValueChange={(valueId, value, type) => - dispatchFormDataAction({ - type: - type === "price" - ? "changeAttributeValuePrice" - : "changeAttributeValueStock", - value, - valueId - }) - } - /> - )} - {step === ProductVariantCreateStep.summary && ( - - dispatchFormDataAction({ - field, - type: "changeVariantData", - value, - variantIndex - }) - } - onVariantDelete={variantIndex => - dispatchFormDataAction({ - type: "deleteVariant", - variantIndex - }) - } - /> - )} -
-
- ); -}; - -ProductVariantCreateContent.displayName = "ProductVariantCreateContent"; -export default ProductVariantCreateContent; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx deleted file mode 100644 index d4ef692f9..000000000 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreatePrices.tsx +++ /dev/null @@ -1,315 +0,0 @@ -import FormControlLabel from "@material-ui/core/FormControlLabel"; -import Radio from "@material-ui/core/Radio"; -import RadioGroup from "@material-ui/core/RadioGroup"; -import { makeStyles } from "@material-ui/core/styles"; -import TextField from "@material-ui/core/TextField"; -import Typography from "@material-ui/core/Typography"; -import React from "react"; -import { FormattedMessage, useIntl } from "react-intl"; - -import FormSpacer from "@saleor/components/FormSpacer"; -import Grid from "@saleor/components/Grid"; -import Hr from "@saleor/components/Hr"; -import SingleSelectField from "@saleor/components/SingleSelectField"; -import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; -import { ProductVariantCreateFormData } from "./form"; - -const useStyles = makeStyles( - theme => ({ - hr: { - marginBottom: theme.spacing(), - marginTop: theme.spacing(0.5) - }, - hrAttribute: { - marginTop: theme.spacing(2) - }, - label: { - alignSelf: "center" - }, - shortInput: { - width: "50%" - } - }), - { name: "ProductVariantCreatePrices" } -); - -export type PriceOrStock = "price" | "stock"; -export interface ProductVariantCreatePricesProps { - attributes: ProductDetails_product_productType_variantAttributes[]; - currencySymbol: string; - data: ProductVariantCreateFormData; - onApplyPriceOrStockChange: (applyToAll: boolean, type: PriceOrStock) => void; - onApplyToAllChange: (value: string, type: PriceOrStock) => void; - onAttributeSelect: (id: string, type: PriceOrStock) => void; - onAttributeValueChange: ( - id: string, - value: string, - type: PriceOrStock - ) => void; -} - -const ProductVariantCreatePrices: React.FC< - ProductVariantCreatePricesProps -> = props => { - const { - attributes, - currencySymbol, - data, - onApplyPriceOrStockChange, - onApplyToAllChange, - onAttributeSelect, - onAttributeValueChange - } = props; - const classes = useStyles(props); - const intl = useIntl(); - - const attributeChoices = attributes.map(attribute => ({ - label: attribute.name, - value: attribute.id - })); - const priceAttributeValues = data.price.all - ? null - : data.price.attribute - ? attributes - .find(attribute => attribute.id === data.price.attribute) - .values.filter(value => - data.attributes - .find(attribute => attribute.id === data.price.attribute) - .values.includes(value.slug) - ) - : []; - const stockAttributeValues = data.stock.all - ? null - : data.stock.attribute - ? attributes - .find(attribute => attribute.id === data.stock.attribute) - .values.filter(value => - data.attributes - .find(attribute => attribute.id === data.stock.attribute) - .values.includes(value.slug) - ) - : []; - - return ( - <> - - - -
- - } - label={intl.formatMessage({ - defaultMessage: "Apply single price to all SKUs" - })} - onChange={() => onApplyPriceOrStockChange(true, "price")} - /> - - onApplyToAllChange(event.target.value, "price")} - /> - - } - label={intl.formatMessage({ - defaultMessage: "Apply unique prices by attribute to each SKU" - })} - onChange={() => onApplyPriceOrStockChange(false, "price")} - /> - - {!data.price.all && ( - <> - - -
- - - -
-
- - onAttributeSelect(event.target.value, "price") - } - /> -
-
-
- {priceAttributeValues && - priceAttributeValues.map(attributeValue => ( - - - -
- {attributeValue.name} -
-
- value.slug === attributeValue.slug - ).value - } - onChange={event => - onAttributeValueChange( - attributeValue.slug, - event.target.value, - "price" - ) - } - /> -
-
-
- ))} - - )} - - - - -
- - } - label={intl.formatMessage({ - defaultMessage: "Apply single stock to all SKUs" - })} - onChange={() => onApplyPriceOrStockChange(true, "stock")} - /> - - onApplyToAllChange(event.target.value, "stock")} - /> - - } - label={intl.formatMessage({ - defaultMessage: "Apply unique stock by attribute to each SKU" - })} - onChange={() => onApplyPriceOrStockChange(false, "stock")} - /> - - {!data.stock.all && ( - <> - - -
- - - -
-
- - onAttributeSelect(event.target.value, "stock") - } - /> -
-
-
- {stockAttributeValues && - stockAttributeValues.map(attributeValue => ( - - - -
- {attributeValue.name} -
-
- value.slug === attributeValue.slug - ).value - } - onChange={event => - onAttributeValueChange( - attributeValue.slug, - event.target.value, - "stock" - ) - } - /> -
-
-
- ))} - - )} - - ); -}; - -ProductVariantCreatePrices.displayName = "ProductVariantCreatePrices"; -export default ProductVariantCreatePrices; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx b/src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx deleted file mode 100644 index 212f7dcbd..000000000 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateValues.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import makeStyles from "@material-ui/core/styles/makeStyles"; -import Typography from "@material-ui/core/Typography"; -import React from "react"; - -import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; -import Debounce from "@saleor/components/Debounce"; -import Hr from "@saleor/components/Hr"; -import Skeleton from "@saleor/components/Skeleton"; -import { maybe } from "@saleor/misc"; -import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; -import { isSelected } from "@saleor/utils/lists"; -import { ProductVariantCreateFormData } from "./form"; - -export interface ProductVariantCreateValuesProps { - attributes: ProductDetails_product_productType_variantAttributes[]; - data: ProductVariantCreateFormData; - onValueClick: (attributeId: string, valueId: string) => void; -} - -const useStyles = makeStyles( - theme => ({ - hr: { - marginBottom: theme.spacing(), - marginTop: theme.spacing(0.5) - }, - valueContainer: { - display: "grid", - gridColumnGap: theme.spacing(3), - gridTemplateColumns: "repeat(3, 1fr)", - marginBottom: theme.spacing(3) - } - }), - { name: "ProductVariantCreateValues" } -); - -const ProductVariantCreateValues: React.FC< - ProductVariantCreateValuesProps -> = props => { - const { attributes, data, onValueClick } = props; - const classes = useStyles(props); - - return ( - <> - {attributes.map(attribute => ( - - - {maybe(() => attribute.name, )} - -
-
- {attribute.values.map(value => ( - onValueClick(attribute.id, value.slug)} - time={100} - key={value.slug} - > - {change => ( - attribute.id === dataAttribute.id - ).values, - (a, b) => a === b - )} - name={`value:${value.slug}`} - label={value.name} - onChange={change} - /> - )} - - ))} -
-
- ))} - - ); -}; - -ProductVariantCreateValues.displayName = "ProductVariantCreateValues"; -export default ProductVariantCreateValues; diff --git a/src/products/components/ProductVariantCreateDialog/index.ts b/src/products/components/ProductVariantCreateDialog/index.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/components/ProductVariantCreateDialog/types.ts b/src/products/components/ProductVariantCreateDialog/types.ts deleted file mode 100644 index f8b088f0a..000000000 --- a/src/products/components/ProductVariantCreateDialog/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum ProductVariantCreateStep { - values, - prices, - summary -} diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreate.stories.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx similarity index 66% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreate.stories.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx index b735d3f0f..3305d853f 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreate.stories.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreator.stories.tsx @@ -1,18 +1,18 @@ -import Card from "@material-ui/core/Card"; -import CardContent from "@material-ui/core/CardContent"; import { storiesOf } from "@storybook/react"; import React from "react"; import { attributes } from "@saleor/attributes/fixtures"; import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; import { ProductErrorCode } from "@saleor/types/globalTypes"; +import Container from "@saleor/components/Container"; import Decorator from "../../../storybook/Decorator"; import { createVariants } from "./createVariants"; import { AllOrAttribute } from "./form"; -import ProductVariantCreateContent, { - ProductVariantCreateContentProps -} from "./ProductVariantCreateContent"; -import ProductVariantCreateDialog from "./ProductVariantCreateDialog"; +import ProductVariantCreatorContent, { + ProductVariantCreatorContentProps +} from "./ProductVariantCreatorContent"; +import ProductVariantCreatorPage from "./ProductVariantCreatorPage"; +import { ProductVariantCreatorStep } from "./types"; const selectedAttributes = [1, 4, 5].map(index => attributes[index]); @@ -52,7 +52,7 @@ const errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[] = [ } ]; -const props: ProductVariantCreateContentProps = { +const props: ProductVariantCreatorContentProps = { attributes, currencySymbol: "USD", data: { @@ -68,56 +68,43 @@ const props: ProductVariantCreateContentProps = { }, dispatchFormDataAction: () => undefined, errors: [], - onStepClick: () => undefined, - step: "values" + step: ProductVariantCreatorStep.values }; storiesOf("Views / Products / Create multiple variants", module) - .addDecorator(storyFn => ( - - {storyFn()} - - )) + .addDecorator(storyFn => {storyFn()}) .addDecorator(Decorator) - .add("choose values", () => ) + .add("choose values", () => ) .add("prices and SKU", () => ( - + )); storiesOf("Views / Products / Create multiple variants / summary", module) - .addDecorator(storyFn => ( - - {storyFn()} - - )) + .addDecorator(storyFn => {storyFn()}) .addDecorator(Decorator) .add("default", () => ( - + )) .add("errors", () => ( - + )); storiesOf("Views / Products / Create multiple variants", module) .addDecorator(Decorator) .add("interactive", () => ( - undefined} onSubmit={() => undefined} /> )); diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx new file mode 100644 index 000000000..4316c2df5 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorContent.tsx @@ -0,0 +1,122 @@ +import React from "react"; + +import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; +import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; +import { isSelected } from "@saleor/utils/lists"; +import { ProductVariantCreateFormData } from "./form"; +import ProductVariantCreatePrices from "./ProductVariantCreatorPrices"; +import ProductVariantCreateSummary from "./ProductVariantCreatorSummary"; +import ProductVariantCreateValues from "./ProductVariantCreatorValues"; +import { ProductVariantCreateReducerAction } from "./reducer"; +import { ProductVariantCreatorStep } from "./types"; + +export interface ProductVariantCreatorContentProps { + attributes: ProductDetails_product_productType_variantAttributes[]; + currencySymbol: string; + data: ProductVariantCreateFormData; + dispatchFormDataAction: React.Dispatch; + errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[]; + step: ProductVariantCreatorStep; +} + +const ProductVariantCreatorContent: React.FC = props => { + const { + attributes, + currencySymbol, + data, + dispatchFormDataAction, + errors, + step + } = props; + const selectedAttributes = attributes.filter(attribute => + isSelected( + attribute.id, + data.attributes.map(dataAttribute => dataAttribute.id), + (a, b) => a === b + ) + ); + + return ( + <> + {step === ProductVariantCreatorStep.values && ( + + dispatchFormDataAction({ + attributeId, + type: "selectValue", + valueId + }) + } + /> + )} + {step === ProductVariantCreatorStep.prices && ( + + dispatchFormDataAction({ + all, + type: type === "price" ? "applyPriceToAll" : "applyStockToAll" + }) + } + onApplyToAllChange={(value, type) => + dispatchFormDataAction({ + type: + type === "price" + ? "changeApplyPriceToAllValue" + : "changeApplyStockToAllValue", + value + }) + } + onAttributeSelect={(attributeId, type) => + dispatchFormDataAction({ + attributeId, + type: + type === "price" + ? "changeApplyPriceToAttributeId" + : "changeApplyStockToAttributeId" + }) + } + onAttributeValueChange={(valueId, value, type) => + dispatchFormDataAction({ + type: + type === "price" + ? "changeAttributeValuePrice" + : "changeAttributeValueStock", + value, + valueId + }) + } + /> + )} + {step === ProductVariantCreatorStep.summary && ( + + dispatchFormDataAction({ + field, + type: "changeVariantData", + value, + variantIndex + }) + } + onVariantDelete={variantIndex => + dispatchFormDataAction({ + type: "deleteVariant", + variantIndex + }) + } + /> + )} + + ); +}; + +ProductVariantCreatorContent.displayName = "ProductVariantCreatorContent"; +export default ProductVariantCreatorContent; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx similarity index 54% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx index b2fcfed6c..aaf03a9b2 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx @@ -1,22 +1,19 @@ import Button from "@material-ui/core/Button"; -import Dialog from "@material-ui/core/Dialog"; -import DialogActions from "@material-ui/core/DialogActions"; -import DialogContent from "@material-ui/core/DialogContent"; -import DialogTitle from "@material-ui/core/DialogTitle"; import { makeStyles } from "@material-ui/core/styles"; import React from "react"; -import { FormattedMessage } from "react-intl"; +import { FormattedMessage, useIntl, IntlShape } from "react-intl"; -import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; -import useModalDialogOpen from "@saleor/hooks/useModalDialogOpen"; import useWizard from "@saleor/hooks/useWizard"; +import PageHeader from "@saleor/components/PageHeader"; +import Container from "@saleor/components/Container"; import { ProductVariantBulkCreateInput } from "../../../types/globalTypes"; import { createInitialForm, ProductVariantCreateFormData } from "./form"; -import ProductVariantCreateContent, { - ProductVariantCreateContentProps -} from "./ProductVariantCreateContent"; +import ProductVariantCreatorContent, { + ProductVariantCreatorContentProps +} from "./ProductVariantCreatorContent"; import reduceProductVariantCreateFormData from "./reducer"; -import { ProductVariantCreateStep } from "./types"; +import { ProductVariantCreatorStep } from "./types"; +import ProductVariantCreateTabs from "./ProductVariantCreatorTabs"; const useStyles = makeStyles( theme => ({ @@ -27,22 +24,19 @@ const useStyles = makeStyles( overflowX: "visible", overflowY: "hidden", width: 800 - }, - spacer: { - flex: 1 } }), - { name: "ProductVariantCreateDialog" } + { name: "ProductVariantCreatePage" } ); function canHitNext( - step: ProductVariantCreateStep, + step: ProductVariantCreatorStep, data: ProductVariantCreateFormData ): boolean { switch (step) { - case ProductVariantCreateStep.values: + case ProductVariantCreatorStep.values: return data.attributes.every(attribute => attribute.values.length > 0); - case ProductVariantCreateStep.prices: + case ProductVariantCreatorStep.prices: if (data.price.all) { if (data.price.value === "") { return false; @@ -70,7 +64,7 @@ function canHitNext( } return true; - case ProductVariantCreateStep.summary: + case ProductVariantCreatorStep.summary: return data.variants.every(variant => variant.sku !== ""); default: @@ -78,34 +72,45 @@ function canHitNext( } } -export interface ProductVariantCreateDialogProps +export interface ProductVariantCreatePageProps extends Omit< - ProductVariantCreateContentProps, + ProductVariantCreatorContentProps, "data" | "dispatchFormDataAction" | "step" | "onStepClick" > { defaultPrice: string; - open: boolean; - onClose: () => void; onSubmit: (data: ProductVariantBulkCreateInput[]) => void; } -const ProductVariantCreateDialog: React.FC = props => { - const { - attributes, - defaultPrice, - errors: apiErrors, - open, - onClose, - onSubmit, - ...contentProps - } = props; +function getTitle(step: ProductVariantCreatorStep, intl: IntlShape): string { + switch (step) { + case ProductVariantCreatorStep.values: + return intl.formatMessage({ + defaultMessage: "Choose Values", + description: "product attribute values, page title" + }); + case ProductVariantCreatorStep.prices: + return intl.formatMessage({ + defaultMessage: "Price and SKUs", + description: "page title" + }); + case ProductVariantCreatorStep.summary: + return intl.formatMessage({ + defaultMessage: "Summary", + description: "page title" + }); + } +} + +const ProductVariantCreatePage: React.FC = props => { + const { attributes, defaultPrice, errors, onSubmit, ...contentProps } = props; const classes = useStyles(props); + const intl = useIntl(); const [step, { next, prev, set: setStep }] = useWizard< - ProductVariantCreateStep - >(ProductVariantCreateStep.values, [ - ProductVariantCreateStep.values, - ProductVariantCreateStep.prices, - ProductVariantCreateStep.summary + ProductVariantCreatorStep + >(ProductVariantCreatorStep.values, [ + ProductVariantCreatorStep.values, + ProductVariantCreatorStep.prices, + ProductVariantCreatorStep.summary ]); const [data, dispatchFormDataAction] = React.useReducer( @@ -121,40 +126,11 @@ const ProductVariantCreateDialog: React.FC = pr React.useEffect(reloadForm, [attributes.length]); - useModalDialogOpen(open, { - onClose: () => { - reloadForm(); - setStep(ProductVariantCreateStep.values); - } - }); - - const errors = useModalDialogErrors(apiErrors, open); - return ( - - - - - - setStep(step)} - /> - - - -
- {step !== ProductVariantCreateStep.values && ( + + + + {step !== ProductVariantCreatorStep.values && ( )} - {step !== ProductVariantCreateStep.summary ? ( + {step !== ProductVariantCreatorStep.summary ? ( )} - -
+ + + ); }; -ProductVariantCreateDialog.displayName = "ProductVariantCreateDialog"; -export default ProductVariantCreateDialog; +ProductVariantCreatePage.displayName = "ProductVariantCreatePage"; +export default ProductVariantCreatePage; diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx new file mode 100644 index 000000000..e63ac92dc --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPrices.tsx @@ -0,0 +1,331 @@ +import FormControlLabel from "@material-ui/core/FormControlLabel"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import Radio from "@material-ui/core/Radio"; +import RadioGroup from "@material-ui/core/RadioGroup"; +import { makeStyles } from "@material-ui/core/styles"; +import TextField from "@material-ui/core/TextField"; +import Typography from "@material-ui/core/Typography"; +import React from "react"; +import { FormattedMessage, useIntl } from "react-intl"; + +import FormSpacer from "@saleor/components/FormSpacer"; +import Grid from "@saleor/components/Grid"; +import Hr from "@saleor/components/Hr"; +import SingleSelectField from "@saleor/components/SingleSelectField"; +import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; +import CardTitle from "@saleor/components/CardTitle"; +import CardSpacer from "@saleor/components/CardSpacer"; +import { ProductVariantCreateFormData } from "./form"; + +const useStyles = makeStyles( + theme => ({ + hr: { + marginBottom: theme.spacing(), + marginTop: theme.spacing(0.5) + }, + hrAttribute: { + marginTop: theme.spacing(2) + }, + label: { + alignSelf: "center" + }, + shortInput: { + width: "33%" + } + }), + { name: "ProductVariantCreatorPrices" } +); + +export type PriceOrStock = "price" | "stock"; +export interface ProductVariantCreatorPricesProps { + attributes: ProductDetails_product_productType_variantAttributes[]; + currencySymbol: string; + data: ProductVariantCreateFormData; + onApplyPriceOrStockChange: (applyToAll: boolean, type: PriceOrStock) => void; + onApplyToAllChange: (value: string, type: PriceOrStock) => void; + onAttributeSelect: (id: string, type: PriceOrStock) => void; + onAttributeValueChange: ( + id: string, + value: string, + type: PriceOrStock + ) => void; +} + +const ProductVariantCreatorPrices: React.FC = props => { + const { + attributes, + currencySymbol, + data, + onApplyPriceOrStockChange, + onApplyToAllChange, + onAttributeSelect, + onAttributeValueChange + } = props; + const classes = useStyles(props); + const intl = useIntl(); + + const attributeChoices = attributes.map(attribute => ({ + label: attribute.name, + value: attribute.id + })); + const priceAttributeValues = data.price.all + ? null + : data.price.attribute + ? attributes + .find(attribute => attribute.id === data.price.attribute) + .values.filter(value => + data.attributes + .find(attribute => attribute.id === data.price.attribute) + .values.includes(value.slug) + ) + : []; + const stockAttributeValues = data.stock.all + ? null + : data.stock.attribute + ? attributes + .find(attribute => attribute.id === data.stock.attribute) + .values.filter(value => + data.attributes + .find(attribute => attribute.id === data.stock.attribute) + .values.includes(value.slug) + ) + : []; + + return ( + <> + + + + + } + label={intl.formatMessage({ + defaultMessage: "Apply single price to all SKUs" + })} + onChange={() => onApplyPriceOrStockChange(true, "price")} + /> + + + onApplyToAllChange(event.target.value, "price") + } + /> + + } + label={intl.formatMessage({ + defaultMessage: "Apply unique prices by attribute to each SKU" + })} + onChange={() => onApplyPriceOrStockChange(false, "price")} + /> + + {!data.price.all && ( + <> + + +
+ + + +
+
+ + onAttributeSelect(event.target.value, "price") + } + /> +
+
+ {priceAttributeValues && + priceAttributeValues.map(attributeValue => ( + +
+ + +
+ {attributeValue.name} +
+
+ value.slug === attributeValue.slug + ).value + } + onChange={event => + onAttributeValueChange( + attributeValue.slug, + event.target.value, + "price" + ) + } + /> +
+
+
+ ))} + + )} +
+
+ + + + + + } + label={intl.formatMessage({ + defaultMessage: "Apply single stock to all SKUs" + })} + onChange={() => onApplyPriceOrStockChange(true, "stock")} + /> + + + onApplyToAllChange(event.target.value, "stock") + } + /> + + } + label={intl.formatMessage({ + defaultMessage: "Apply unique stock by attribute to each SKU" + })} + onChange={() => onApplyPriceOrStockChange(false, "stock")} + /> + + {!data.stock.all && ( + <> + + +
+ + + +
+
+ + onAttributeSelect(event.target.value, "stock") + } + /> +
+
+ {stockAttributeValues && + stockAttributeValues.map(attributeValue => ( + +
+ + +
+ {attributeValue.name} +
+
+ value.slug === attributeValue.slug + ).value + } + onChange={event => + onAttributeValueChange( + attributeValue.slug, + event.target.value, + "stock" + ) + } + /> +
+
+
+ ))} + + )} +
+
+ + ); +}; + +ProductVariantCreatorPrices.displayName = "ProductVariantCreatorPrices"; +export default ProductVariantCreatorPrices; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateSummary.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx similarity index 92% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreateSummary.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx index 01e370e9e..aab3db002 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateSummary.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorSummary.tsx @@ -3,25 +3,26 @@ import cyan from "@material-ui/core/colors/cyan"; import green from "@material-ui/core/colors/green"; import purple from "@material-ui/core/colors/purple"; import yellow from "@material-ui/core/colors/yellow"; +import Card from "@material-ui/core/Card"; import IconButton from "@material-ui/core/IconButton"; import { makeStyles } from "@material-ui/core/styles"; import TextField from "@material-ui/core/TextField"; -import Typography from "@material-ui/core/Typography"; import DeleteIcon from "@material-ui/icons/Delete"; import classNames from "classnames"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import Hr from "@saleor/components/Hr"; import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate"; import { ProductVariantBulkCreateInput } from "@saleor/types/globalTypes"; import { getFormErrors } from "@saleor/utils/errors"; import { getBulkProductErrorMessage } from "@saleor/utils/errors/product"; +import CardTitle from "@saleor/components/CardTitle"; +import { commonMessages } from "@saleor/intl"; import { ProductDetails_product_productType_variantAttributes } from "../../types/ProductDetails"; import { ProductVariantCreateFormData } from "./form"; import { VariantField } from "./reducer"; -export interface ProductVariantCreateSummaryProps { +export interface ProductVariantCreatorSummaryProps { attributes: ProductDetails_product_productType_variantAttributes[]; currencySymbol: string; data: ProductVariantCreateFormData; @@ -81,11 +82,11 @@ const useStyles = makeStyles( borderBottom: `1px solid ${theme.palette.divider}`, display: "grid", gridTemplateColumns: "1fr 180px 120px 180px 64px", - padding: theme.spacing(1, 0) + padding: theme.spacing(1, 1, 1, 3) } }), { - name: "ProductVariantCreateSummary" + name: "ProductVariantCreatorSummary" } ); @@ -108,7 +109,7 @@ function getVariantName( ); } -const ProductVariantCreateSummary: React.FC = props => { +const ProductVariantCreatorSummary: React.FC = props => { const { attributes, currencySymbol, @@ -121,14 +122,8 @@ const ProductVariantCreateSummary: React.FC = const intl = useIntl(); return ( - <> - - - -
+ +
= ); })}
- + ); }; -ProductVariantCreateSummary.displayName = "ProductVariantCreateSummary"; -export default ProductVariantCreateSummary; +ProductVariantCreatorSummary.displayName = "ProductVariantCreatorSummary"; +export default ProductVariantCreatorSummary; diff --git a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx similarity index 78% rename from src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx rename to src/products/components/ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx index 039c5b8e0..49c4ab52a 100644 --- a/src/products/components/ProductVariantCreateDialog/ProductVariantCreateTabs.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorTabs.tsx @@ -4,11 +4,11 @@ import classNames from "classnames"; import React from "react"; import { IntlShape, useIntl } from "react-intl"; -import { ProductVariantCreateStep } from "./types"; +import { ProductVariantCreatorStep } from "./types"; interface Step { label: string; - value: ProductVariantCreateStep; + value: ProductVariantCreatorStep; } function getSteps(intl: IntlShape): Step[] { return [ @@ -17,21 +17,21 @@ function getSteps(intl: IntlShape): Step[] { defaultMessage: "Select Values", description: "attribute values, variant creation step" }), - value: ProductVariantCreateStep.values + value: ProductVariantCreatorStep.values }, { label: intl.formatMessage({ defaultMessage: "Prices and SKU", description: "variant creation step" }), - value: ProductVariantCreateStep.prices + value: ProductVariantCreatorStep.prices }, { label: intl.formatMessage({ defaultMessage: "Summary", description: "variant creation step" }), - value: ProductVariantCreateStep.summary + value: ProductVariantCreatorStep.summary } ]; } @@ -62,16 +62,16 @@ const useStyles = makeStyles( } }), { - name: "ProductVariantCreateTabs" + name: "ProductVariantCreatorTabs" } ); -export interface ProductVariantCreateTabsProps { - step: ProductVariantCreateStep; - onStepClick: (step: ProductVariantCreateStep) => void; +export interface ProductVariantCreatorTabsProps { + step: ProductVariantCreatorStep; + onStepClick: (step: ProductVariantCreatorStep) => void; } -const ProductVariantCreateTabs: React.FC = props => { +const ProductVariantCreatorTabs: React.FC = props => { const { step: currentStep, onStepClick } = props; const classes = useStyles(props); const intl = useIntl(); @@ -102,5 +102,5 @@ const ProductVariantCreateTabs: React.FC = props ); }; -ProductVariantCreateTabs.displayName = "ProductVariantCreateTabs"; -export default ProductVariantCreateTabs; +ProductVariantCreatorTabs.displayName = "ProductVariantCreatorTabs"; +export default ProductVariantCreatorTabs; diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx new file mode 100644 index 000000000..19acb45d8 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorValues.tsx @@ -0,0 +1,75 @@ +import makeStyles from "@material-ui/core/styles/makeStyles"; +import Card from "@material-ui/core/Card"; +import CardContent from "@material-ui/core/CardContent"; +import React from "react"; + +import ControlledCheckbox from "@saleor/components/ControlledCheckbox"; +import Debounce from "@saleor/components/Debounce"; +import Skeleton from "@saleor/components/Skeleton"; +import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails"; +import { isSelected } from "@saleor/utils/lists"; +import CardTitle from "@saleor/components/CardTitle"; +import CardSpacer from "@saleor/components/CardSpacer"; +import { ProductVariantCreateFormData } from "./form"; + +export interface ProductVariantCreatorValuesProps { + attributes: ProductDetails_product_productType_variantAttributes[]; + data: ProductVariantCreateFormData; + onValueClick: (attributeId: string, valueId: string) => void; +} + +const useStyles = makeStyles( + theme => ({ + valueContainer: { + display: "grid", + gridColumnGap: theme.spacing(3), + gridTemplateColumns: "repeat(5, 1fr)" + } + }), + { name: "ProductVariantCreatorValues" } +); + +const ProductVariantCreatorValues: React.FC = props => { + const { attributes, data, onValueClick } = props; + const classes = useStyles(props); + + return ( + <> + {attributes.map(attribute => ( + <> + + } /> + + {attribute.values.map(value => ( + onValueClick(attribute.id, value.slug)} + time={100} + key={value.slug} + > + {change => ( + attribute.id === dataAttribute.id + ).values, + (a, b) => a === b + )} + name={`value:${value.slug}`} + label={value.name} + onChange={change} + /> + )} + + ))} + + + + + ))} + + ); +}; + +ProductVariantCreatorValues.displayName = "ProductVariantCreatorValues"; +export default ProductVariantCreatorValues; diff --git a/src/products/components/ProductVariantCreateDialog/__snapshots__/reducer.test.ts.snap b/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap similarity index 100% rename from src/products/components/ProductVariantCreateDialog/__snapshots__/reducer.test.ts.snap rename to src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap diff --git a/src/products/components/ProductVariantCreateDialog/createVariants.test.ts b/src/products/components/ProductVariantCreatorPage/createVariants.test.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/createVariants.test.ts rename to src/products/components/ProductVariantCreatorPage/createVariants.test.ts diff --git a/src/products/components/ProductVariantCreateDialog/createVariants.ts b/src/products/components/ProductVariantCreatorPage/createVariants.ts similarity index 94% rename from src/products/components/ProductVariantCreateDialog/createVariants.ts rename to src/products/components/ProductVariantCreatorPage/createVariants.ts index 6239832e2..186972c60 100644 --- a/src/products/components/ProductVariantCreateDialog/createVariants.ts +++ b/src/products/components/ProductVariantCreatorPage/createVariants.ts @@ -97,9 +97,10 @@ export function createVariants( ) { return []; } - const variants = createVariantFlatMatrixDimension([[]], data.attributes).map( - variant => createVariant(data, variant) - ); + const variants = createVariantFlatMatrixDimension( + [[]], + data.attributes + ).map(variant => createVariant(data, variant)); return variants; } diff --git a/src/products/components/ProductVariantCreateDialog/fixtures.ts b/src/products/components/ProductVariantCreatorPage/fixtures.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/fixtures.ts rename to src/products/components/ProductVariantCreatorPage/fixtures.ts diff --git a/src/products/components/ProductVariantCreateDialog/form.ts b/src/products/components/ProductVariantCreatorPage/form.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/form.ts rename to src/products/components/ProductVariantCreatorPage/form.ts diff --git a/src/products/components/ProductVariantCreatorPage/index.ts b/src/products/components/ProductVariantCreatorPage/index.ts new file mode 100644 index 000000000..5e4e6b074 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/index.ts @@ -0,0 +1,2 @@ +export * from "./ProductVariantCreatorPage"; +export { default } from "./ProductVariantCreatorPage"; diff --git a/src/products/components/ProductVariantCreateDialog/reducer.test.ts b/src/products/components/ProductVariantCreatorPage/reducer.test.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/reducer.test.ts rename to src/products/components/ProductVariantCreatorPage/reducer.test.ts diff --git a/src/products/components/ProductVariantCreateDialog/reducer.ts b/src/products/components/ProductVariantCreatorPage/reducer.ts similarity index 100% rename from src/products/components/ProductVariantCreateDialog/reducer.ts rename to src/products/components/ProductVariantCreatorPage/reducer.ts diff --git a/src/products/components/ProductVariantCreatorPage/types.ts b/src/products/components/ProductVariantCreatorPage/types.ts new file mode 100644 index 000000000..baab8f3e7 --- /dev/null +++ b/src/products/components/ProductVariantCreatorPage/types.ts @@ -0,0 +1,5 @@ +export enum ProductVariantCreatorStep { + values, + prices, + summary +} diff --git a/src/products/containers/ProductUpdateOperations.tsx b/src/products/containers/ProductUpdateOperations.tsx index d07c6561b..a2e79a952 100644 --- a/src/products/containers/ProductUpdateOperations.tsx +++ b/src/products/containers/ProductUpdateOperations.tsx @@ -7,7 +7,6 @@ import { TypedProductImageCreateMutation, TypedProductImageDeleteMutation, TypedProductUpdateMutation, - TypedProductVariantBulkCreateMutation, TypedProductVariantBulkDeleteMutation, TypedSimpleProductUpdateMutation } from "../mutations"; @@ -26,10 +25,6 @@ import { ProductImageReorderVariables } from "../types/ProductImageReorder"; import { ProductUpdate, ProductUpdateVariables } from "../types/ProductUpdate"; -import { - ProductVariantBulkCreate, - ProductVariantBulkCreateVariables -} from "../types/ProductVariantBulkCreate"; import { ProductVariantBulkDelete, ProductVariantBulkDeleteVariables @@ -43,10 +38,6 @@ import ProductImagesReorderProvider from "./ProductImagesReorder"; interface ProductUpdateOperationsProps { product: ProductDetails_product; children: (props: { - bulkProductVariantCreate: PartialMutationProviderOutput< - ProductVariantBulkCreate, - ProductVariantBulkCreateVariables - >; bulkProductVariantDelete: PartialMutationProviderOutput< ProductVariantBulkDelete, ProductVariantBulkDeleteVariables @@ -76,7 +67,6 @@ interface ProductUpdateOperationsProps { SimpleProductUpdateVariables >; }) => React.ReactNode; - onBulkProductVariantCreate?: (data: ProductVariantBulkCreate) => void; onBulkProductVariantDelete?: (data: ProductVariantBulkDelete) => void; onDelete?: (data: ProductDelete) => void; onImageCreate?: (data: ProductImageCreate) => void; @@ -88,7 +78,6 @@ interface ProductUpdateOperationsProps { const ProductUpdateOperations: React.FC = ({ product, children, - onBulkProductVariantCreate, onBulkProductVariantDelete, onDelete, onImageDelete, @@ -121,40 +110,31 @@ const ProductUpdateOperations: React.FC = ({ - {(...bulkProductVariantDelete) => ( - - {(...bulkProductVariantCreate) => - children({ - bulkProductVariantCreate: getMutationProviderData( - ...bulkProductVariantCreate - ), - bulkProductVariantDelete: getMutationProviderData( - ...bulkProductVariantDelete - ), - createProductImage: getMutationProviderData( - ...createProductImage - ), - deleteProduct: getMutationProviderData( - ...deleteProduct - ), - deleteProductImage: getMutationProviderData( - ...deleteProductImage - ), - reorderProductImages: getMutationProviderData( - ...reorderProductImages - ), - updateProduct: getMutationProviderData( - ...updateProduct - ), - updateSimpleProduct: getMutationProviderData( - ...updateSimpleProduct - ) - }) - } - - )} + {(...bulkProductVariantDelete) => + children({ + bulkProductVariantDelete: getMutationProviderData( + ...bulkProductVariantDelete + ), + createProductImage: getMutationProviderData( + ...createProductImage + ), + deleteProduct: getMutationProviderData( + ...deleteProduct + ), + deleteProductImage: getMutationProviderData( + ...deleteProductImage + ), + reorderProductImages: getMutationProviderData( + ...reorderProductImages + ), + updateProduct: getMutationProviderData( + ...updateProduct + ), + updateSimpleProduct: getMutationProviderData( + ...updateSimpleProduct + ) + }) + } )} diff --git a/src/products/index.tsx b/src/products/index.tsx index dfd75cd77..624a50346 100644 --- a/src/products/index.tsx +++ b/src/products/index.tsx @@ -20,7 +20,8 @@ import { productVariantEditPath, ProductVariantEditUrlQueryParams, ProductAddUrlQueryParams, - ProductVariantAddUrlQueryParams + ProductVariantAddUrlQueryParams, + productVariantCreatorPath } from "./urls"; import ProductCreateComponent from "./views/ProductCreate"; import ProductImageComponent from "./views/ProductImage"; @@ -28,6 +29,7 @@ import ProductListComponent from "./views/ProductList"; import ProductUpdateComponent from "./views/ProductUpdate"; import ProductVariantComponent from "./views/ProductVariant"; import ProductVariantCreateComponent from "./views/ProductVariantCreate"; +import ProductVariantCreatorComponent from "./views/ProductVariantCreator"; const ProductList: React.FC> = ({ location }) => { const qs = parseQs(location.search.substr(1)); @@ -100,6 +102,12 @@ const ProductVariantCreate: React.FC> = ({ ); }; +const ProductVariantCreator: React.FC> = ({ match }) => ( + +); + const ProductCreate: React.FC = ({ location }) => { const qs = parseQs(location.search.substr(1)); const params: ProductAddUrlQueryParams = qs; @@ -116,6 +124,10 @@ const Component = () => { + (ProductVariantBulkCreateMutation); diff --git a/src/products/queries.ts b/src/products/queries.ts index a14d917ca..2749cf718 100644 --- a/src/products/queries.ts +++ b/src/products/queries.ts @@ -27,6 +27,10 @@ import { InitialProductFilterData, InitialProductFilterDataVariables } from "./types/InitialProductFilterData"; +import { + CreateMultipleVariantsData, + CreateMultipleVariantsDataVariables +} from "./types/CreateMultipleVariantsData"; export const stockFragment = gql` fragment StockFragment on Stock { @@ -74,12 +78,50 @@ export const productFragment = gql` } } `; + +const productVariantAttributesFragment = gql` + fragment ProductVariantAttributesFragment on Product { + id + attributes { + attribute { + id + slug + name + inputType + valueRequired + values { + id + name + slug + } + } + values { + id + name + slug + } + } + productType { + variantAttributes { + id + name + values { + id + name + slug + } + } + } + } +`; + export const productFragmentDetails = gql` ${fragmentProductImage} ${fragmentMoney} + ${productVariantAttributesFragment} ${stockFragment} fragment Product on Product { - id + ...ProductVariantAttributesFragment name descriptionJson seoTitle @@ -111,25 +153,6 @@ export const productFragmentDetails = gql` isPublished chargeTaxes publicationDate - attributes { - attribute { - id - slug - name - inputType - valueRequired - values { - id - name - slug - } - } - values { - id - name - slug - } - } pricing { priceRange { start { @@ -332,17 +355,6 @@ const productDetailsQuery = gql` query ProductDetails($id: ID!) { product(id: $id) { ...Product - productType { - variantAttributes { - id - name - values { - id - name - slug - } - } - } } } `; @@ -464,3 +476,20 @@ export const AvailableInGridAttributesQuery = TypedQuery< AvailableInGridAttributes, AvailableInGridAttributesVariables >(availableInGridAttributes); + +const createMultipleVariantsData = gql` + ${fragmentMoney} + ${productVariantAttributesFragment} + query CreateMultipleVariantsData($id: ID!) { + product(id: $id) { + ...ProductVariantAttributesFragment + basePrice { + ...Money + } + } + } +`; +export const useCreateMultipleVariantsData = makeQuery< + CreateMultipleVariantsData, + CreateMultipleVariantsDataVariables +>(createMultipleVariantsData); diff --git a/src/products/types/CreateMultipleVariantsData.ts b/src/products/types/CreateMultipleVariantsData.ts new file mode 100644 index 000000000..d73feae44 --- /dev/null +++ b/src/products/types/CreateMultipleVariantsData.ts @@ -0,0 +1,80 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { AttributeInputTypeEnum } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL query operation: CreateMultipleVariantsData +// ==================================================== + +export interface CreateMultipleVariantsData_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface CreateMultipleVariantsData_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (CreateMultipleVariantsData_product_attributes_attribute_values | null)[] | null; +} + +export interface CreateMultipleVariantsData_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface CreateMultipleVariantsData_product_attributes { + __typename: "SelectedAttribute"; + attribute: CreateMultipleVariantsData_product_attributes_attribute; + values: (CreateMultipleVariantsData_product_attributes_values | null)[]; +} + +export interface CreateMultipleVariantsData_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface CreateMultipleVariantsData_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (CreateMultipleVariantsData_product_productType_variantAttributes_values | null)[] | null; +} + +export interface CreateMultipleVariantsData_product_productType { + __typename: "ProductType"; + variantAttributes: (CreateMultipleVariantsData_product_productType_variantAttributes | null)[] | null; +} + +export interface CreateMultipleVariantsData_product_basePrice { + __typename: "Money"; + amount: number; + currency: string; +} + +export interface CreateMultipleVariantsData_product { + __typename: "Product"; + id: string; + attributes: CreateMultipleVariantsData_product_attributes[]; + productType: CreateMultipleVariantsData_product_productType; + basePrice: CreateMultipleVariantsData_product_basePrice | null; +} + +export interface CreateMultipleVariantsData { + product: CreateMultipleVariantsData_product | null; +} + +export interface CreateMultipleVariantsDataVariables { + id: string; +} diff --git a/src/products/types/Product.ts b/src/products/types/Product.ts index 7b1ce054e..bf6d5b287 100644 --- a/src/products/types/Product.ts +++ b/src/products/types/Product.ts @@ -8,6 +8,58 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes"; // GraphQL fragment: Product // ==================================================== +export interface Product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface Product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (Product_attributes_attribute_values | null)[] | null; +} + +export interface Product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface Product_attributes { + __typename: "SelectedAttribute"; + attribute: Product_attributes_attribute; + values: (Product_attributes_values | null)[]; +} + +export interface Product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface Product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (Product_productType_variantAttributes_values | null)[] | null; +} + +export interface Product_productType { + __typename: "ProductType"; + variantAttributes: (Product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface Product_category { __typename: "Category"; id: string; @@ -50,36 +102,6 @@ export interface Product_purchaseCost { stop: Product_purchaseCost_stop | null; } -export interface Product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface Product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (Product_attributes_attribute_values | null)[] | null; -} - -export interface Product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface Product_attributes { - __typename: "SelectedAttribute"; - attribute: Product_attributes_attribute; - values: (Product_attributes_values | null)[]; -} - export interface Product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -151,16 +173,11 @@ export interface Product_variants { trackInventory: boolean; } -export interface Product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface Product { __typename: "Product"; id: string; + attributes: Product_attributes[]; + productType: Product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -174,9 +191,7 @@ export interface Product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: Product_attributes[]; pricing: Product_pricing | null; images: (Product_images | null)[] | null; variants: (Product_variants | null)[] | null; - productType: Product_productType; } diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index 710f81e8f..07e21aa5a 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -14,6 +14,58 @@ export interface ProductCreate_productCreate_errors { field: string | null; } +export interface ProductCreate_productCreate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductCreate_productCreate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductCreate_productCreate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductCreate_productCreate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductCreate_productCreate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductCreate_productCreate_product_attributes_attribute; + values: (ProductCreate_productCreate_product_attributes_values | null)[]; +} + +export interface ProductCreate_productCreate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductCreate_productCreate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductCreate_productCreate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductCreate_productCreate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductCreate_productCreate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductCreate_productCreate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductCreate_productCreate_product_purchaseCost { stop: ProductCreate_productCreate_product_purchaseCost_stop | null; } -export interface ProductCreate_productCreate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductCreate_productCreate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductCreate_productCreate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductCreate_productCreate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductCreate_productCreate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductCreate_productCreate_product_attributes_attribute; - values: (ProductCreate_productCreate_product_attributes_values | null)[]; -} - export interface ProductCreate_productCreate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductCreate_productCreate_product_variants { trackInventory: boolean; } -export interface ProductCreate_productCreate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductCreate_productCreate_product { __typename: "Product"; id: string; + attributes: ProductCreate_productCreate_product_attributes[]; + productType: ProductCreate_productCreate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductCreate_productCreate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductCreate_productCreate_product_attributes[]; pricing: ProductCreate_productCreate_product_pricing | null; images: (ProductCreate_productCreate_product_images | null)[] | null; variants: (ProductCreate_productCreate_product_variants | null)[] | null; - productType: ProductCreate_productCreate_product_productType; } export interface ProductCreate_productCreate { diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index c426f408a..19b2b3e40 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -8,6 +8,58 @@ import { AttributeInputTypeEnum } from "./../../types/globalTypes"; // GraphQL query operation: ProductDetails // ==================================================== +export interface ProductDetails_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductDetails_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductDetails_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductDetails_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductDetails_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductDetails_product_attributes_attribute; + values: (ProductDetails_product_attributes_values | null)[]; +} + +export interface ProductDetails_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductDetails_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductDetails_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductDetails_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductDetails_product_category { __typename: "Category"; id: string; @@ -50,36 +102,6 @@ export interface ProductDetails_product_purchaseCost { stop: ProductDetails_product_purchaseCost_stop | null; } -export interface ProductDetails_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductDetails_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductDetails_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductDetails_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductDetails_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductDetails_product_attributes_attribute; - values: (ProductDetails_product_attributes_values | null)[]; -} - export interface ProductDetails_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -151,31 +173,11 @@ export interface ProductDetails_product_variants { trackInventory: boolean; } -export interface ProductDetails_product_productType_variantAttributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductDetails_product_productType_variantAttributes { - __typename: "Attribute"; - id: string; - name: string | null; - values: (ProductDetails_product_productType_variantAttributes_values | null)[] | null; -} - -export interface ProductDetails_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; - variantAttributes: (ProductDetails_product_productType_variantAttributes | null)[] | null; -} - export interface ProductDetails_product { __typename: "Product"; id: string; + attributes: ProductDetails_product_attributes[]; + productType: ProductDetails_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -189,11 +191,9 @@ export interface ProductDetails_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductDetails_product_attributes[]; pricing: ProductDetails_product_pricing | null; images: (ProductDetails_product_images | null)[] | null; variants: (ProductDetails_product_variants | null)[] | null; - productType: ProductDetails_product_productType; } export interface ProductDetails { diff --git a/src/products/types/ProductImageCreate.ts b/src/products/types/ProductImageCreate.ts index fcbb37415..6c6d583a9 100644 --- a/src/products/types/ProductImageCreate.ts +++ b/src/products/types/ProductImageCreate.ts @@ -14,6 +14,58 @@ export interface ProductImageCreate_productImageCreate_errors { field: string | null; } +export interface ProductImageCreate_productImageCreate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageCreate_productImageCreate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductImageCreate_productImageCreate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductImageCreate_productImageCreate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageCreate_productImageCreate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductImageCreate_productImageCreate_product_attributes_attribute; + values: (ProductImageCreate_productImageCreate_product_attributes_values | null)[]; +} + +export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageCreate_productImageCreate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductImageCreate_productImageCreate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductImageCreate_productImageCreate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductImageCreate_productImageCreate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductImageCreate_productImageCreate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductImageCreate_productImageCreate_product_purchaseCost { stop: ProductImageCreate_productImageCreate_product_purchaseCost_stop | null; } -export interface ProductImageCreate_productImageCreate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageCreate_productImageCreate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductImageCreate_productImageCreate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductImageCreate_productImageCreate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageCreate_productImageCreate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductImageCreate_productImageCreate_product_attributes_attribute; - values: (ProductImageCreate_productImageCreate_product_attributes_values | null)[]; -} - export interface ProductImageCreate_productImageCreate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductImageCreate_productImageCreate_product_variants { trackInventory: boolean; } -export interface ProductImageCreate_productImageCreate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductImageCreate_productImageCreate_product { __typename: "Product"; id: string; + attributes: ProductImageCreate_productImageCreate_product_attributes[]; + productType: ProductImageCreate_productImageCreate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductImageCreate_productImageCreate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductImageCreate_productImageCreate_product_attributes[]; pricing: ProductImageCreate_productImageCreate_product_pricing | null; images: (ProductImageCreate_productImageCreate_product_images | null)[] | null; variants: (ProductImageCreate_productImageCreate_product_variants | null)[] | null; - productType: ProductImageCreate_productImageCreate_product_productType; } export interface ProductImageCreate_productImageCreate { diff --git a/src/products/types/ProductImageUpdate.ts b/src/products/types/ProductImageUpdate.ts index 0bca7c7c9..5bb8acfea 100644 --- a/src/products/types/ProductImageUpdate.ts +++ b/src/products/types/ProductImageUpdate.ts @@ -14,6 +14,58 @@ export interface ProductImageUpdate_productImageUpdate_errors { field: string | null; } +export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductImageUpdate_productImageUpdate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductImageUpdate_productImageUpdate_product_attributes_attribute; + values: (ProductImageUpdate_productImageUpdate_product_attributes_values | null)[]; +} + +export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductImageUpdate_productImageUpdate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductImageUpdate_productImageUpdate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductImageUpdate_productImageUpdate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductImageUpdate_productImageUpdate_product_purchaseCost { stop: ProductImageUpdate_productImageUpdate_product_purchaseCost_stop | null; } -export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageUpdate_productImageUpdate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductImageUpdate_productImageUpdate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductImageUpdate_productImageUpdate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductImageUpdate_productImageUpdate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductImageUpdate_productImageUpdate_product_attributes_attribute; - values: (ProductImageUpdate_productImageUpdate_product_attributes_values | null)[]; -} - export interface ProductImageUpdate_productImageUpdate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductImageUpdate_productImageUpdate_product_variants { trackInventory: boolean; } -export interface ProductImageUpdate_productImageUpdate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductImageUpdate_productImageUpdate_product { __typename: "Product"; id: string; + attributes: ProductImageUpdate_productImageUpdate_product_attributes[]; + productType: ProductImageUpdate_productImageUpdate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductImageUpdate_productImageUpdate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductImageUpdate_productImageUpdate_product_attributes[]; pricing: ProductImageUpdate_productImageUpdate_product_pricing | null; images: (ProductImageUpdate_productImageUpdate_product_images | null)[] | null; variants: (ProductImageUpdate_productImageUpdate_product_variants | null)[] | null; - productType: ProductImageUpdate_productImageUpdate_product_productType; } export interface ProductImageUpdate_productImageUpdate { diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index 90b5615c1..f0b15d703 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -14,6 +14,58 @@ export interface ProductUpdate_productUpdate_errors { field: string | null; } +export interface ProductUpdate_productUpdate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductUpdate_productUpdate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; +} + +export interface ProductUpdate_productUpdate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductUpdate_productUpdate_product_attributes { + __typename: "SelectedAttribute"; + attribute: ProductUpdate_productUpdate_product_attributes_attribute; + values: (ProductUpdate_productUpdate_product_attributes_values | null)[]; +} + +export interface ProductUpdate_productUpdate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductUpdate_productUpdate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductUpdate_productUpdate_product_productType { + __typename: "ProductType"; + variantAttributes: (ProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface ProductUpdate_productUpdate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface ProductUpdate_productUpdate_product_purchaseCost { stop: ProductUpdate_productUpdate_product_purchaseCost_stop | null; } -export interface ProductUpdate_productUpdate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductUpdate_productUpdate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (ProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; -} - -export interface ProductUpdate_productUpdate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface ProductUpdate_productUpdate_product_attributes { - __typename: "SelectedAttribute"; - attribute: ProductUpdate_productUpdate_product_attributes_attribute; - values: (ProductUpdate_productUpdate_product_attributes_values | null)[]; -} - export interface ProductUpdate_productUpdate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface ProductUpdate_productUpdate_product_variants { trackInventory: boolean; } -export interface ProductUpdate_productUpdate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface ProductUpdate_productUpdate_product { __typename: "Product"; id: string; + attributes: ProductUpdate_productUpdate_product_attributes[]; + productType: ProductUpdate_productUpdate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface ProductUpdate_productUpdate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: ProductUpdate_productUpdate_product_attributes[]; pricing: ProductUpdate_productUpdate_product_pricing | null; images: (ProductUpdate_productUpdate_product_images | null)[] | null; variants: (ProductUpdate_productUpdate_product_variants | null)[] | null; - productType: ProductUpdate_productUpdate_product_productType; } export interface ProductUpdate_productUpdate { diff --git a/src/products/types/ProductVariantAttributesFragment.ts b/src/products/types/ProductVariantAttributesFragment.ts new file mode 100644 index 000000000..462cbd1e6 --- /dev/null +++ b/src/products/types/ProductVariantAttributesFragment.ts @@ -0,0 +1,65 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { AttributeInputTypeEnum } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: ProductVariantAttributesFragment +// ==================================================== + +export interface ProductVariantAttributesFragment_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductVariantAttributesFragment_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (ProductVariantAttributesFragment_attributes_attribute_values | null)[] | null; +} + +export interface ProductVariantAttributesFragment_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductVariantAttributesFragment_attributes { + __typename: "SelectedAttribute"; + attribute: ProductVariantAttributesFragment_attributes_attribute; + values: (ProductVariantAttributesFragment_attributes_values | null)[]; +} + +export interface ProductVariantAttributesFragment_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface ProductVariantAttributesFragment_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (ProductVariantAttributesFragment_productType_variantAttributes_values | null)[] | null; +} + +export interface ProductVariantAttributesFragment_productType { + __typename: "ProductType"; + variantAttributes: (ProductVariantAttributesFragment_productType_variantAttributes | null)[] | null; +} + +export interface ProductVariantAttributesFragment { + __typename: "Product"; + id: string; + attributes: ProductVariantAttributesFragment_attributes[]; + productType: ProductVariantAttributesFragment_productType; +} diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index c54d9ea19..adfa2075b 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -14,6 +14,58 @@ export interface SimpleProductUpdate_productUpdate_errors { field: string | null; } +export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productUpdate_product_attributes_attribute { + __typename: "Attribute"; + id: string; + slug: string | null; + name: string | null; + inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; + values: (SimpleProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; +} + +export interface SimpleProductUpdate_productUpdate_product_attributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productUpdate_product_attributes { + __typename: "SelectedAttribute"; + attribute: SimpleProductUpdate_productUpdate_product_attributes_attribute; + values: (SimpleProductUpdate_productUpdate_product_attributes_values | null)[]; +} + +export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values { + __typename: "AttributeValue"; + id: string; + name: string | null; + slug: string | null; +} + +export interface SimpleProductUpdate_productUpdate_product_productType_variantAttributes { + __typename: "Attribute"; + id: string; + name: string | null; + values: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes_values | null)[] | null; +} + +export interface SimpleProductUpdate_productUpdate_product_productType { + __typename: "ProductType"; + variantAttributes: (SimpleProductUpdate_productUpdate_product_productType_variantAttributes | null)[] | null; + id: string; + name: string; + hasVariants: boolean; +} + export interface SimpleProductUpdate_productUpdate_product_category { __typename: "Category"; id: string; @@ -56,36 +108,6 @@ export interface SimpleProductUpdate_productUpdate_product_purchaseCost { stop: SimpleProductUpdate_productUpdate_product_purchaseCost_stop | null; } -export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface SimpleProductUpdate_productUpdate_product_attributes_attribute { - __typename: "Attribute"; - id: string; - slug: string | null; - name: string | null; - inputType: AttributeInputTypeEnum | null; - valueRequired: boolean; - values: (SimpleProductUpdate_productUpdate_product_attributes_attribute_values | null)[] | null; -} - -export interface SimpleProductUpdate_productUpdate_product_attributes_values { - __typename: "AttributeValue"; - id: string; - name: string | null; - slug: string | null; -} - -export interface SimpleProductUpdate_productUpdate_product_attributes { - __typename: "SelectedAttribute"; - attribute: SimpleProductUpdate_productUpdate_product_attributes_attribute; - values: (SimpleProductUpdate_productUpdate_product_attributes_values | null)[]; -} - export interface SimpleProductUpdate_productUpdate_product_pricing_priceRange_start_net { __typename: "Money"; amount: number; @@ -157,16 +179,11 @@ export interface SimpleProductUpdate_productUpdate_product_variants { trackInventory: boolean; } -export interface SimpleProductUpdate_productUpdate_product_productType { - __typename: "ProductType"; - id: string; - name: string; - hasVariants: boolean; -} - export interface SimpleProductUpdate_productUpdate_product { __typename: "Product"; id: string; + attributes: SimpleProductUpdate_productUpdate_product_attributes[]; + productType: SimpleProductUpdate_productUpdate_product_productType; name: string; descriptionJson: any; seoTitle: string | null; @@ -180,11 +197,9 @@ export interface SimpleProductUpdate_productUpdate_product { isPublished: boolean; chargeTaxes: boolean; publicationDate: any | null; - attributes: SimpleProductUpdate_productUpdate_product_attributes[]; pricing: SimpleProductUpdate_productUpdate_product_pricing | null; images: (SimpleProductUpdate_productUpdate_product_images | null)[] | null; variants: (SimpleProductUpdate_productUpdate_product_variants | null)[] | null; - productType: SimpleProductUpdate_productUpdate_product_productType; } export interface SimpleProductUpdate_productUpdate { diff --git a/src/products/urls.ts b/src/products/urls.ts index 08b8aeb7a..5160034a8 100644 --- a/src/products/urls.ts +++ b/src/products/urls.ts @@ -69,11 +69,7 @@ export const productListUrl = (params?: ProductListUrlQueryParams): string => productListPath + "?" + stringifyQs(params); export const productPath = (id: string) => urlJoin(productSection + id); -export type ProductUrlDialog = - | "create-variants" - | "edit-stocks" - | "remove" - | "remove-variants"; +export type ProductUrlDialog = "edit-stocks" | "remove" | "remove-variants"; export type ProductUrlQueryParams = BulkAction & Dialog; export const productUrl = (id: string, params?: ProductUrlQueryParams) => productPath(encodeURIComponent(id)) + "?" + stringifyQs(params); @@ -96,6 +92,11 @@ export const productVariantEditUrl = ( "?" + stringifyQs(params); +export const productVariantCreatorPath = (productId: string) => + urlJoin(productSection, productId, "variant-creator"); +export const productVariantCreatorUrl = (productId: string) => + productVariantCreatorPath(encodeURIComponent(productId)); + export const productVariantAddPath = (productId: string) => urlJoin(productSection, productId, "variant/add"); export type ProductVariantAddUrlDialog = "edit-stocks"; diff --git a/src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx b/src/products/views/ProductMultipleVariantCreate/ProductMultipleVariantCreate.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/views/ProductMultipleVariantCreate/index.ts b/src/products/views/ProductMultipleVariantCreate/index.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/views/ProductMultipleVariantCreate/paginate.ts b/src/products/views/ProductMultipleVariantCreate/paginate.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/products/views/ProductUpdate/ProductUpdate.tsx b/src/products/views/ProductUpdate/ProductUpdate.tsx index 899d14dd1..c0c35acf8 100644 --- a/src/products/views/ProductUpdate/ProductUpdate.tsx +++ b/src/products/views/ProductUpdate/ProductUpdate.tsx @@ -11,10 +11,7 @@ import { DEFAULT_INITIAL_SEARCH_DATA } from "@saleor/config"; import useBulkActions from "@saleor/hooks/useBulkActions"; import useNavigator from "@saleor/hooks/useNavigator"; import useNotifier from "@saleor/hooks/useNotifier"; -import useShop from "@saleor/hooks/useShop"; import { commonMessages } from "@saleor/intl"; -import ProductVariantCreateDialog from "@saleor/products/components/ProductVariantCreateDialog/ProductVariantCreateDialog"; -import { ProductVariantBulkCreate } from "@saleor/products/types/ProductVariantBulkCreate"; import useCategorySearch from "@saleor/searches/useCategorySearch"; import useCollectionSearch from "@saleor/searches/useCollectionSearch"; import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers"; @@ -39,7 +36,8 @@ import { ProductUrlQueryParams, productVariantAddUrl, productVariantEditUrl, - ProductUrlDialog + ProductUrlDialog, + productVariantCreatorUrl } from "../../urls"; import { createImageReorderHandler, @@ -59,7 +57,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { params.ids ); const intl = useIntl(); - const shop = useShop(); const { loadMore: loadMoreCategories, search: searchCategories, @@ -144,15 +141,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { }); const handleVariantAdd = () => navigate(productVariantAddUrl(id)); - const handleBulkProductVariantCreate = ( - data: ProductVariantBulkCreate - ) => { - if (data.productVariantBulkCreate.errors.length === 0) { - closeModal(); - refetch(); - } - }; - const handleBulkProductVariantDelete = ( data: ProductVariantBulkDelete ) => { @@ -166,7 +154,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { return ( = ({ id, params }) => { onUpdate={handleUpdate} > {({ - bulkProductVariantCreate, bulkProductVariantDelete, createProductImage, deleteProduct, @@ -258,7 +244,7 @@ export const ProductUpdate: React.FC = ({ id, params }) => { onImageReorder={handleImageReorder} onSubmit={handleSubmit} onVariantAdd={handleVariantAdd} - onVariantsAdd={() => openModal("create-variants")} + onVariantsAdd={() => navigate(productVariantCreatorUrl(id))} onVariantShow={variantId => () => navigate(productVariantEditUrl(product.id, variantId))} onImageUpload={handleImageUpload} @@ -347,28 +333,6 @@ export const ProductUpdate: React.FC = ({ id, params }) => { /> - - data.product.basePrice.amount.toFixed(2) - )} - errors={ - bulkProductVariantCreate.opts.data - ?.productVariantBulkCreate.errors || [] - } - open={params.action === "create-variants"} - attributes={maybe( - () => data.product.productType.variantAttributes, - [] - )} - currencySymbol={maybe(() => shop.defaultCurrency)} - onClose={closeModal} - onSubmit={inputs => - bulkProductVariantCreate.mutate({ - id, - inputs - }) - } - /> {!product?.productType?.hasVariants && ( = ({ + id +}) => { + const navigate = useNavigator(); + const notify = useNotifier(); + const intl = useIntl(); + const { data } = useCreateMultipleVariantsData({ + displayLoader: true, + variables: { id } + }); + const [ + bulkProductVariantCreate, + bulkProductVariantCreateOpts + ] = useProductVariantBulkCreateMutation({ + onCompleted: data => { + if (data.productVariantBulkCreate.errors.length === 0) { + notify({ + text: intl.formatMessage({ + defaultMessage: "Successfully created variants", + description: "success message" + }) + }); + navigate(productUrl(id)); + } + } + }); + const shop = useShop(); + + return ( + <> + + + bulkProductVariantCreate({ + variables: { id, inputs } + }) + } + /> + + ); +}; +ProductVariantCreator.displayName = "ProductVariantCreator"; +export default ProductVariantCreator; diff --git a/src/products/views/ProductVariantCreator/index.ts b/src/products/views/ProductVariantCreator/index.ts new file mode 100644 index 000000000..033e63894 --- /dev/null +++ b/src/products/views/ProductVariantCreator/index.ts @@ -0,0 +1,2 @@ +export * from "./ProductVariantCreator"; +export { default } from "./ProductVariantCreator";