Add stock to variant matrix
This commit is contained in:
parent
422ede89a8
commit
e153b59bc3
18 changed files with 395 additions and 252 deletions
|
@ -4643,7 +4643,7 @@ input ProductVariantBulkCreateInput {
|
||||||
costPrice: Decimal
|
costPrice: Decimal
|
||||||
priceOverride: Decimal
|
priceOverride: Decimal
|
||||||
sku: String!
|
sku: String!
|
||||||
quantity: Int
|
stocks: [StockInput!]!
|
||||||
trackInventory: Boolean
|
trackInventory: Boolean
|
||||||
weight: WeightScalar
|
weight: WeightScalar
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,33 @@
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
export interface UseWizardOpts<T> {
|
export interface UseWizardActions<T> {
|
||||||
next: () => void;
|
next: () => void;
|
||||||
prev: () => void;
|
prev: () => void;
|
||||||
set: (step: T) => void;
|
set: (step: T) => void;
|
||||||
}
|
}
|
||||||
export type UseWizard<T> = [T, UseWizardOpts<T>];
|
export interface UseWizardOpts<T> {
|
||||||
function useWizard<T>(initial: T, steps: T[]): UseWizard<T> {
|
onTransition: (prevStep: T, nextStep: T) => void;
|
||||||
|
}
|
||||||
|
export type UseWizard<T> = [T, UseWizardActions<T>];
|
||||||
|
function useWizard<T>(
|
||||||
|
initial: T,
|
||||||
|
steps: T[],
|
||||||
|
opts?: UseWizardOpts<T>
|
||||||
|
): UseWizard<T> {
|
||||||
const [stepIndex, setStepIndex] = useState(steps.indexOf(initial));
|
const [stepIndex, setStepIndex] = useState(steps.indexOf(initial));
|
||||||
|
|
||||||
|
function goToStep(nextStepIndex) {
|
||||||
|
if (typeof opts?.onTransition === "function") {
|
||||||
|
opts.onTransition(steps[stepIndex], steps[nextStepIndex]);
|
||||||
|
}
|
||||||
|
setStepIndex(nextStepIndex);
|
||||||
|
}
|
||||||
|
|
||||||
function next() {
|
function next() {
|
||||||
if (stepIndex === steps.length - 1) {
|
if (stepIndex === steps.length - 1) {
|
||||||
console.error("This is the last step");
|
console.error("This is the last step");
|
||||||
} else {
|
} else {
|
||||||
setStepIndex(stepIndex + 1);
|
goToStep(stepIndex + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +35,7 @@ function useWizard<T>(initial: T, steps: T[]): UseWizard<T> {
|
||||||
if (stepIndex === 0) {
|
if (stepIndex === 0) {
|
||||||
console.error("This is the first step");
|
console.error("This is the first step");
|
||||||
} else {
|
} else {
|
||||||
setStepIndex(stepIndex - 1);
|
goToStep(stepIndex - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +44,7 @@ function useWizard<T>(initial: T, steps: T[]): UseWizard<T> {
|
||||||
if (newStepIndex === -1) {
|
if (newStepIndex === -1) {
|
||||||
console.error("Step does not exist");
|
console.error("Step does not exist");
|
||||||
} else {
|
} else {
|
||||||
setStepIndex(newStepIndex);
|
goToStep(newStepIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,10 @@ import { attributes } from "@saleor/attributes/fixtures";
|
||||||
import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate";
|
import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate";
|
||||||
import { ProductErrorCode } from "@saleor/types/globalTypes";
|
import { ProductErrorCode } from "@saleor/types/globalTypes";
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
|
import { warehouseList } from "@saleor/warehouses/fixtures";
|
||||||
import Decorator from "../../../storybook/Decorator";
|
import Decorator from "../../../storybook/Decorator";
|
||||||
import { createVariants } from "./createVariants";
|
import { createVariants } from "./createVariants";
|
||||||
import { AllOrAttribute } from "./form";
|
import { AllOrAttribute, ProductVariantCreateFormData } from "./form";
|
||||||
import ProductVariantCreatorContent, {
|
import ProductVariantCreatorContent, {
|
||||||
ProductVariantCreatorContentProps
|
ProductVariantCreatorContentProps
|
||||||
} from "./ProductVariantCreatorContent";
|
} from "./ProductVariantCreatorContent";
|
||||||
|
@ -15,24 +16,33 @@ import ProductVariantCreatorPage from "./ProductVariantCreatorPage";
|
||||||
import { ProductVariantCreatorStep } from "./types";
|
import { ProductVariantCreatorStep } from "./types";
|
||||||
|
|
||||||
const selectedAttributes = [1, 4, 5].map(index => attributes[index]);
|
const selectedAttributes = [1, 4, 5].map(index => attributes[index]);
|
||||||
|
const selectedWarehouses = [0, 1, 3].map(index => warehouseList[index]);
|
||||||
|
|
||||||
const price: AllOrAttribute = {
|
const price: AllOrAttribute<string> = {
|
||||||
all: false,
|
all: false,
|
||||||
attribute: selectedAttributes[1].id,
|
attribute: selectedAttributes[0].id,
|
||||||
value: "2.79",
|
value: "2.79",
|
||||||
values: selectedAttributes[1].values.map((attribute, attributeIndex) => ({
|
values: selectedAttributes[0].values.map((attribute, attributeIndex) => ({
|
||||||
slug: attribute.slug,
|
slug: attribute.slug,
|
||||||
value: (attributeIndex + 4).toFixed(2)
|
value: (attributeIndex + 4).toFixed(2)
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
const stock: AllOrAttribute = {
|
const stock: AllOrAttribute<string[]> = {
|
||||||
all: false,
|
all: false,
|
||||||
attribute: selectedAttributes[1].id,
|
attribute: selectedAttributes[0].id,
|
||||||
value: "8",
|
value: selectedWarehouses.map((_, warehouseIndex) =>
|
||||||
values: selectedAttributes[1].values.map((attribute, attributeIndex) => ({
|
((warehouseIndex + 2) * 3).toString()
|
||||||
|
),
|
||||||
|
values: selectedAttributes[0].values.map((attribute, attributeIndex) => ({
|
||||||
slug: attribute.slug,
|
slug: attribute.slug,
|
||||||
value: (selectedAttributes.length * 10 - attributeIndex).toString()
|
value: selectedWarehouses.map((_, warehouseIndex) =>
|
||||||
|
(
|
||||||
|
selectedAttributes.length * 10 -
|
||||||
|
attributeIndex -
|
||||||
|
warehouseIndex * 3
|
||||||
|
).toString()
|
||||||
|
)
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,23 +62,30 @@ const errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[] = [
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const data: ProductVariantCreateFormData = {
|
||||||
|
attributes: dataAttributes,
|
||||||
|
price,
|
||||||
|
stock,
|
||||||
|
variants: createVariants({
|
||||||
|
attributes: dataAttributes,
|
||||||
|
price,
|
||||||
|
stock,
|
||||||
|
variants: [],
|
||||||
|
warehouses: selectedWarehouses.map(warehouse => warehouse.id)
|
||||||
|
}),
|
||||||
|
warehouses: selectedWarehouses.map(warehouse => warehouse.id)
|
||||||
|
};
|
||||||
const props: ProductVariantCreatorContentProps = {
|
const props: ProductVariantCreatorContentProps = {
|
||||||
attributes,
|
attributes,
|
||||||
currencySymbol: "USD",
|
currencySymbol: "USD",
|
||||||
data: {
|
data: {
|
||||||
attributes: dataAttributes,
|
...data,
|
||||||
price,
|
variants: createVariants(data)
|
||||||
stock,
|
|
||||||
variants: createVariants({
|
|
||||||
attributes: dataAttributes,
|
|
||||||
price,
|
|
||||||
stock,
|
|
||||||
variants: []
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
dispatchFormDataAction: () => undefined,
|
dispatchFormDataAction: () => undefined,
|
||||||
errors: [],
|
errors: [],
|
||||||
step: ProductVariantCreatorStep.values
|
step: ProductVariantCreatorStep.values,
|
||||||
|
warehouses: warehouseList
|
||||||
};
|
};
|
||||||
|
|
||||||
storiesOf("Views / Products / Create multiple variants", module)
|
storiesOf("Views / Products / Create multiple variants", module)
|
||||||
|
|
|
@ -3,6 +3,7 @@ import React from "react";
|
||||||
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
|
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
|
||||||
import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate";
|
import { ProductVariantBulkCreate_productVariantBulkCreate_errors } from "@saleor/products/types/ProductVariantBulkCreate";
|
||||||
import { isSelected } from "@saleor/utils/lists";
|
import { isSelected } from "@saleor/utils/lists";
|
||||||
|
import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment";
|
||||||
import { ProductVariantCreateFormData } from "./form";
|
import { ProductVariantCreateFormData } from "./form";
|
||||||
import ProductVariantCreatePrices from "./ProductVariantCreatorPrices";
|
import ProductVariantCreatePrices from "./ProductVariantCreatorPrices";
|
||||||
import ProductVariantCreateSummary from "./ProductVariantCreatorSummary";
|
import ProductVariantCreateSummary from "./ProductVariantCreatorSummary";
|
||||||
|
@ -17,6 +18,7 @@ export interface ProductVariantCreatorContentProps {
|
||||||
dispatchFormDataAction: React.Dispatch<ProductVariantCreateReducerAction>;
|
dispatchFormDataAction: React.Dispatch<ProductVariantCreateReducerAction>;
|
||||||
errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[];
|
errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[];
|
||||||
step: ProductVariantCreatorStep;
|
step: ProductVariantCreatorStep;
|
||||||
|
warehouses: WarehouseFragment[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps> = props => {
|
const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps> = props => {
|
||||||
|
@ -26,7 +28,8 @@ const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps>
|
||||||
data,
|
data,
|
||||||
dispatchFormDataAction,
|
dispatchFormDataAction,
|
||||||
errors,
|
errors,
|
||||||
step
|
step,
|
||||||
|
warehouses
|
||||||
} = props;
|
} = props;
|
||||||
const selectedAttributes = attributes.filter(attribute =>
|
const selectedAttributes = attributes.filter(attribute =>
|
||||||
isSelected(
|
isSelected(
|
||||||
|
@ -106,12 +109,23 @@ const ProductVariantCreatorContent: React.FC<ProductVariantCreatorContentProps>
|
||||||
variantIndex
|
variantIndex
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
onVariantStockDataChange={(variantIndex, warehouse, value) =>
|
||||||
|
dispatchFormDataAction({
|
||||||
|
stock: {
|
||||||
|
quantity: parseInt(value, 10),
|
||||||
|
warehouse
|
||||||
|
},
|
||||||
|
type: "changeVariantStockData",
|
||||||
|
variantIndex
|
||||||
|
})
|
||||||
|
}
|
||||||
onVariantDelete={variantIndex =>
|
onVariantDelete={variantIndex =>
|
||||||
dispatchFormDataAction({
|
dispatchFormDataAction({
|
||||||
type: "deleteVariant",
|
type: "deleteVariant",
|
||||||
variantIndex
|
variantIndex
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
warehouses={warehouses}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -50,17 +50,8 @@ function canHitNext(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.stock.all) {
|
if (!data.stock.all || data.stock.attribute) {
|
||||||
if (data.stock.value === "") {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
data.stock.attribute === "" ||
|
|
||||||
data.stock.values.some(attributeValue => attributeValue.value === "")
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -102,25 +93,42 @@ function getTitle(step: ProductVariantCreatorStep, intl: IntlShape): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = props => {
|
const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = props => {
|
||||||
const { attributes, defaultPrice, errors, onSubmit, ...contentProps } = props;
|
const {
|
||||||
|
attributes,
|
||||||
|
defaultPrice,
|
||||||
|
errors,
|
||||||
|
onSubmit,
|
||||||
|
warehouses,
|
||||||
|
...contentProps
|
||||||
|
} = props;
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [step, { next: nextStep, prev: prevStep, set: setStep }] = useWizard<
|
|
||||||
ProductVariantCreatorStep
|
|
||||||
>(ProductVariantCreatorStep.values, [
|
|
||||||
ProductVariantCreatorStep.values,
|
|
||||||
ProductVariantCreatorStep.prices,
|
|
||||||
ProductVariantCreatorStep.summary
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [wizardData, dispatchFormDataAction] = React.useReducer(
|
const [wizardData, dispatchFormDataAction] = React.useReducer(
|
||||||
reduceProductVariantCreateFormData,
|
reduceProductVariantCreateFormData,
|
||||||
createInitialForm(attributes, defaultPrice)
|
createInitialForm(attributes, defaultPrice, warehouses)
|
||||||
|
);
|
||||||
|
const [step, { next: nextStep, prev: prevStep, set: setStep }] = useWizard<
|
||||||
|
ProductVariantCreatorStep
|
||||||
|
>(
|
||||||
|
ProductVariantCreatorStep.values,
|
||||||
|
[
|
||||||
|
ProductVariantCreatorStep.values,
|
||||||
|
ProductVariantCreatorStep.prices,
|
||||||
|
ProductVariantCreatorStep.summary
|
||||||
|
],
|
||||||
|
{
|
||||||
|
onTransition: (_, nextStep) => {
|
||||||
|
if (nextStep === ProductVariantCreatorStep.summary) {
|
||||||
|
dispatchFormDataAction({
|
||||||
|
type: "reload"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const reloadForm = () =>
|
const reloadForm = () =>
|
||||||
dispatchFormDataAction({
|
dispatchFormDataAction({
|
||||||
data: createInitialForm(attributes, defaultPrice),
|
data: createInitialForm(attributes, defaultPrice, warehouses),
|
||||||
type: "reload"
|
type: "reload"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -170,6 +178,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = props
|
||||||
dispatchFormDataAction={dispatchFormDataAction}
|
dispatchFormDataAction={dispatchFormDataAction}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
step={step}
|
step={step}
|
||||||
|
warehouses={warehouses}
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import purple from "@material-ui/core/colors/purple";
|
||||||
import yellow from "@material-ui/core/colors/yellow";
|
import yellow from "@material-ui/core/colors/yellow";
|
||||||
import Card from "@material-ui/core/Card";
|
import Card from "@material-ui/core/Card";
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
import IconButton from "@material-ui/core/IconButton";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles, Theme } from "@material-ui/core/styles";
|
||||||
import TextField from "@material-ui/core/TextField";
|
import TextField from "@material-ui/core/TextField";
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
@ -17,7 +17,8 @@ import { ProductVariantBulkCreateInput } from "@saleor/types/globalTypes";
|
||||||
import { getFormErrors } from "@saleor/utils/errors";
|
import { getFormErrors } from "@saleor/utils/errors";
|
||||||
import { getBulkProductErrorMessage } from "@saleor/utils/errors/product";
|
import { getBulkProductErrorMessage } from "@saleor/utils/errors/product";
|
||||||
import CardTitle from "@saleor/components/CardTitle";
|
import CardTitle from "@saleor/components/CardTitle";
|
||||||
import { commonMessages } from "@saleor/intl";
|
import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment";
|
||||||
|
import Hr from "@saleor/components/Hr";
|
||||||
import { ProductDetails_product_productType_variantAttributes } from "../../types/ProductDetails";
|
import { ProductDetails_product_productType_variantAttributes } from "../../types/ProductDetails";
|
||||||
import { ProductVariantCreateFormData } from "./form";
|
import { ProductVariantCreateFormData } from "./form";
|
||||||
import { VariantField } from "./reducer";
|
import { VariantField } from "./reducer";
|
||||||
|
@ -27,39 +28,62 @@ export interface ProductVariantCreatorSummaryProps {
|
||||||
currencySymbol: string;
|
currencySymbol: string;
|
||||||
data: ProductVariantCreateFormData;
|
data: ProductVariantCreateFormData;
|
||||||
errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[];
|
errors: ProductVariantBulkCreate_productVariantBulkCreate_errors[];
|
||||||
|
warehouses: WarehouseFragment[];
|
||||||
onVariantDataChange: (
|
onVariantDataChange: (
|
||||||
variantIndex: number,
|
variantIndex: number,
|
||||||
field: VariantField,
|
field: VariantField,
|
||||||
value: string
|
value: string
|
||||||
) => void;
|
) => void;
|
||||||
|
onVariantStockDataChange: (
|
||||||
|
variantIndex: number,
|
||||||
|
warehouseId: string,
|
||||||
|
value: string
|
||||||
|
) => void;
|
||||||
onVariantDelete: (variantIndex: number) => void;
|
onVariantDelete: (variantIndex: number) => void;
|
||||||
}
|
}
|
||||||
|
type ClassKey =
|
||||||
|
| "attributeValue"
|
||||||
|
| "card"
|
||||||
|
| "col"
|
||||||
|
| "colHeader"
|
||||||
|
| "colName"
|
||||||
|
| "colPrice"
|
||||||
|
| "colSku"
|
||||||
|
| "colStock"
|
||||||
|
| "delete"
|
||||||
|
| "hr"
|
||||||
|
| "input"
|
||||||
|
| "summary";
|
||||||
|
|
||||||
const colors = [blue, cyan, green, purple, yellow].map(color => color[800]);
|
const colors = [blue, cyan, green, purple, yellow].map(color => color[800]);
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles<
|
||||||
|
Theme,
|
||||||
|
ProductVariantCreatorSummaryProps,
|
||||||
|
ClassKey
|
||||||
|
>(
|
||||||
theme => ({
|
theme => ({
|
||||||
attributeValue: {
|
attributeValue: {
|
||||||
display: "inline-block",
|
display: "inline-block",
|
||||||
marginRight: theme.spacing(1)
|
marginRight: theme.spacing(1)
|
||||||
},
|
},
|
||||||
col: {
|
card: {
|
||||||
...theme.typography.body1,
|
paddingBottom: theme.spacing()
|
||||||
fontSize: 14,
|
|
||||||
paddingLeft: theme.spacing(),
|
|
||||||
paddingRight: theme.spacing(1)
|
|
||||||
},
|
},
|
||||||
colHeader: {
|
col: {
|
||||||
...theme.typography.body1,
|
...theme.typography.body1,
|
||||||
fontSize: 14
|
fontSize: 14
|
||||||
},
|
},
|
||||||
|
colHeader: {
|
||||||
|
...theme.typography.body1,
|
||||||
|
fontSize: 14,
|
||||||
|
paddingTop: theme.spacing(3)
|
||||||
|
},
|
||||||
colName: {
|
colName: {
|
||||||
"&&": {
|
|
||||||
paddingLeft: "0 !important"
|
|
||||||
},
|
|
||||||
"&:not($colHeader)": {
|
"&:not($colHeader)": {
|
||||||
paddingTop: theme.spacing(2)
|
paddingTop: theme.spacing(2)
|
||||||
}
|
},
|
||||||
|
paddingLeft: theme.spacing(3)
|
||||||
},
|
},
|
||||||
colPrice: {},
|
colPrice: {},
|
||||||
colSku: {},
|
colSku: {},
|
||||||
|
@ -67,22 +91,21 @@ const useStyles = makeStyles(
|
||||||
delete: {
|
delete: {
|
||||||
marginTop: theme.spacing(0.5)
|
marginTop: theme.spacing(0.5)
|
||||||
},
|
},
|
||||||
errorRow: {},
|
|
||||||
hr: {
|
hr: {
|
||||||
marginBottom: theme.spacing(),
|
gridColumn: props => `span ${4 + props.data.stock.value.length}`
|
||||||
marginTop: theme.spacing(0.5)
|
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
"& input": {
|
"& input": {
|
||||||
padding: "16px 12px 17px"
|
padding: "16px 12px 17px"
|
||||||
},
|
}
|
||||||
marginTop: theme.spacing(0.5)
|
|
||||||
},
|
},
|
||||||
row: {
|
summary: {
|
||||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
columnGap: theme.spacing(3),
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "1fr 180px 120px 180px 64px",
|
gridTemplateColumns: props =>
|
||||||
padding: theme.spacing(1, 1, 1, 3)
|
`minmax(240px, auto) 170px repeat(${props.data.stock.value.length}, 140px) 140px 64px`,
|
||||||
|
overflowX: "scroll",
|
||||||
|
rowGap: theme.spacing() + "px"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
@ -115,63 +138,66 @@ const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps>
|
||||||
currencySymbol,
|
currencySymbol,
|
||||||
data,
|
data,
|
||||||
errors,
|
errors,
|
||||||
|
warehouses,
|
||||||
onVariantDataChange,
|
onVariantDataChange,
|
||||||
onVariantDelete
|
onVariantDelete,
|
||||||
|
onVariantStockDataChange
|
||||||
} = props;
|
} = props;
|
||||||
const classes = useStyles(props);
|
const classes = useStyles(props);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card className={classes.card}>
|
||||||
<CardTitle title={intl.formatMessage(commonMessages.summary)} />
|
<CardTitle
|
||||||
<div>
|
title={intl.formatMessage({
|
||||||
<div className={classes.row}>
|
defaultMessage: "Created Variants",
|
||||||
<div
|
description: "variant creator summary card header"
|
||||||
className={classNames(
|
})}
|
||||||
classes.col,
|
/>
|
||||||
classes.colHeader,
|
<div className={classes.summary}>
|
||||||
classes.colName
|
<div
|
||||||
)}
|
className={classNames(
|
||||||
>
|
classes.col,
|
||||||
<FormattedMessage
|
classes.colHeader,
|
||||||
defaultMessage="Variant"
|
classes.colName
|
||||||
description="variant name"
|
)}
|
||||||
/>
|
>
|
||||||
</div>
|
<FormattedMessage
|
||||||
<div
|
defaultMessage="Variant"
|
||||||
className={classNames(
|
description="variant name"
|
||||||
classes.col,
|
/>
|
||||||
classes.colHeader,
|
</div>
|
||||||
classes.colPrice
|
<div
|
||||||
)}
|
className={classNames(
|
||||||
>
|
classes.col,
|
||||||
<FormattedMessage
|
classes.colHeader,
|
||||||
defaultMessage="Price"
|
classes.colPrice
|
||||||
description="variant price"
|
)}
|
||||||
/>
|
>
|
||||||
</div>
|
<FormattedMessage
|
||||||
|
defaultMessage="Price"
|
||||||
|
description="variant price"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{data.warehouses.map(warehouseId => (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
classes.col,
|
classes.col,
|
||||||
classes.colHeader,
|
classes.colHeader,
|
||||||
classes.colStock
|
classes.colStock
|
||||||
)}
|
)}
|
||||||
|
key={warehouseId}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
{warehouses.find(warehouse => warehouse.id === warehouseId).name}
|
||||||
defaultMessage="Inventory"
|
|
||||||
description="variant stock amount"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.col,
|
|
||||||
classes.colHeader,
|
|
||||||
classes.colSku
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<FormattedMessage defaultMessage="SKU" />
|
|
||||||
</div>
|
</div>
|
||||||
|
))}
|
||||||
|
<div
|
||||||
|
className={classNames(classes.col, classes.colHeader, classes.colSku)}
|
||||||
|
>
|
||||||
|
<FormattedMessage defaultMessage="SKU" />
|
||||||
</div>
|
</div>
|
||||||
|
<div className={classNames(classes.col, classes.colHeader)} />
|
||||||
|
<Hr className={classes.hr} />
|
||||||
{data.variants.map((variant, variantIndex) => {
|
{data.variants.map((variant, variantIndex) => {
|
||||||
const variantErrors = errors.filter(
|
const variantErrors = errors.filter(
|
||||||
error => error.index === variantIndex
|
error => error.index === variantIndex
|
||||||
|
@ -182,10 +208,7 @@ const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<React.Fragment
|
||||||
className={classNames(classes.row, {
|
|
||||||
[classes.errorRow]: variantErrors.length > 0
|
|
||||||
})}
|
|
||||||
key={variant.attributes
|
key={variant.attributes
|
||||||
.map(attribute => attribute.values[0])
|
.map(attribute => attribute.values[0])
|
||||||
.join(":")}
|
.join(":")}
|
||||||
|
@ -198,7 +221,7 @@ const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps>
|
||||||
style={{
|
style={{
|
||||||
color: colors[valueIndex % colors.length]
|
color: colors[valueIndex % colors.length]
|
||||||
}}
|
}}
|
||||||
key={value}
|
key={`${value}:${valueIndex}`}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</span>
|
</span>
|
||||||
|
@ -231,29 +254,34 @@ const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classNames(classes.col, classes.colStock)}>
|
{variant.stocks.map(stock => (
|
||||||
<TextField
|
<div
|
||||||
className={classes.input}
|
className={classNames(classes.col, classes.colStock)}
|
||||||
error={!!variantFormErrors.quantity}
|
key={stock.warehouse}
|
||||||
helperText={getBulkProductErrorMessage(
|
>
|
||||||
variantFormErrors.quantity,
|
<TextField
|
||||||
intl
|
className={classes.input}
|
||||||
)}
|
error={!!variantFormErrors.quantity}
|
||||||
inputProps={{
|
helperText={getBulkProductErrorMessage(
|
||||||
min: 0,
|
variantFormErrors.quantity,
|
||||||
type: "number"
|
intl
|
||||||
}}
|
)}
|
||||||
fullWidth
|
inputProps={{
|
||||||
value={variant.quantity}
|
min: 0,
|
||||||
onChange={event =>
|
type: "number"
|
||||||
onVariantDataChange(
|
}}
|
||||||
variantIndex,
|
fullWidth
|
||||||
"stock",
|
value={stock.quantity}
|
||||||
event.target.value
|
onChange={event =>
|
||||||
)
|
onVariantStockDataChange(
|
||||||
}
|
variantIndex,
|
||||||
/>
|
stock.warehouse,
|
||||||
</div>
|
event.target.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
<div className={classNames(classes.col, classes.colSku)}>
|
<div className={classNames(classes.col, classes.colSku)}>
|
||||||
<TextField
|
<TextField
|
||||||
className={classes.input}
|
className={classes.input}
|
||||||
|
@ -278,7 +306,10 @@ const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps>
|
||||||
<DeleteIcon />
|
<DeleteIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{variantIndex !== data.variants.length - 1 && (
|
||||||
|
<Hr className={classes.hr} />
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -11,10 +11,10 @@ interface CreateVariantAttributeValueInput {
|
||||||
}
|
}
|
||||||
type CreateVariantInput = CreateVariantAttributeValueInput[];
|
type CreateVariantInput = CreateVariantAttributeValueInput[];
|
||||||
|
|
||||||
function getAttributeValuePriceOrStock(
|
function getAttributeValuePriceOrStock<T>(
|
||||||
attributes: CreateVariantInput,
|
attributes: CreateVariantInput,
|
||||||
priceOrStock: AllOrAttribute
|
priceOrStock: AllOrAttribute<T>
|
||||||
): string {
|
): T {
|
||||||
const attribute = attributes.find(
|
const attribute = attributes.find(
|
||||||
attribute => attribute.attributeId === priceOrStock.attribute
|
attribute => attribute.attributeId === priceOrStock.attribute
|
||||||
);
|
);
|
||||||
|
@ -33,12 +33,9 @@ function createVariant(
|
||||||
const priceOverride = data.price.all
|
const priceOverride = data.price.all
|
||||||
? data.price.value
|
? data.price.value
|
||||||
: getAttributeValuePriceOrStock(attributes, data.price);
|
: getAttributeValuePriceOrStock(attributes, data.price);
|
||||||
const quantity = parseInt(
|
const stocks = data.stock.all
|
||||||
data.stock.all
|
? data.stock.value
|
||||||
? data.stock.value
|
: getAttributeValuePriceOrStock(attributes, data.stock);
|
||||||
: getAttributeValuePriceOrStock(attributes, data.stock),
|
|
||||||
10
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
attributes: attributes.map(attribute => ({
|
attributes: attributes.map(attribute => ({
|
||||||
|
@ -46,8 +43,11 @@ function createVariant(
|
||||||
values: [attribute.attributeValueSlug]
|
values: [attribute.attributeValueSlug]
|
||||||
})),
|
})),
|
||||||
priceOverride,
|
priceOverride,
|
||||||
quantity,
|
sku: "",
|
||||||
sku: ""
|
stocks: stocks.map((quantity, stockIndex) => ({
|
||||||
|
quantity: parseInt(quantity, 10),
|
||||||
|
warehouse: data.warehouses[stockIndex]
|
||||||
|
}))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
|
import { ProductDetails_product_productType_variantAttributes } from "@saleor/products/types/ProductDetails";
|
||||||
|
import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment";
|
||||||
import { ProductVariantBulkCreateInput } from "../../../types/globalTypes";
|
import { ProductVariantBulkCreateInput } from "../../../types/globalTypes";
|
||||||
|
|
||||||
export interface AttributeValue {
|
export interface AttributeValue<T> {
|
||||||
slug: string;
|
slug: string;
|
||||||
value: string;
|
value: T;
|
||||||
}
|
}
|
||||||
export interface AllOrAttribute {
|
export interface AllOrAttribute<T> {
|
||||||
all: boolean;
|
all: boolean;
|
||||||
attribute: string;
|
attribute: string;
|
||||||
value: string;
|
value: T;
|
||||||
values: AttributeValue[];
|
values: Array<AttributeValue<T>>;
|
||||||
}
|
}
|
||||||
export interface Attribute {
|
export interface Attribute {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -17,14 +18,16 @@ export interface Attribute {
|
||||||
}
|
}
|
||||||
export interface ProductVariantCreateFormData {
|
export interface ProductVariantCreateFormData {
|
||||||
attributes: Attribute[];
|
attributes: Attribute[];
|
||||||
price: AllOrAttribute;
|
price: AllOrAttribute<string>;
|
||||||
stock: AllOrAttribute;
|
stock: AllOrAttribute<number[]>;
|
||||||
variants: ProductVariantBulkCreateInput[];
|
variants: ProductVariantBulkCreateInput[];
|
||||||
|
warehouses: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const createInitialForm = (
|
export const createInitialForm = (
|
||||||
attributes: ProductDetails_product_productType_variantAttributes[],
|
attributes: ProductDetails_product_productType_variantAttributes[],
|
||||||
price: string
|
price: string,
|
||||||
|
warehouses: WarehouseFragment[]
|
||||||
): ProductVariantCreateFormData => ({
|
): ProductVariantCreateFormData => ({
|
||||||
attributes: attributes.map(attribute => ({
|
attributes: attributes.map(attribute => ({
|
||||||
id: attribute.id,
|
id: attribute.id,
|
||||||
|
@ -39,8 +42,9 @@ export const createInitialForm = (
|
||||||
stock: {
|
stock: {
|
||||||
all: true,
|
all: true,
|
||||||
attribute: undefined,
|
attribute: undefined,
|
||||||
value: "",
|
value: warehouses.length === 1 ? [0] : [],
|
||||||
values: []
|
values: []
|
||||||
},
|
},
|
||||||
variants: []
|
variants: [],
|
||||||
|
warehouses: warehouses.length === 1 ? [warehouses[0].id] : []
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,8 +3,10 @@ import {
|
||||||
remove,
|
remove,
|
||||||
removeAtIndex,
|
removeAtIndex,
|
||||||
toggle,
|
toggle,
|
||||||
updateAtIndex
|
updateAtIndex,
|
||||||
|
update
|
||||||
} from "@saleor/utils/lists";
|
} from "@saleor/utils/lists";
|
||||||
|
import { StockInput } from "@saleor/types/globalTypes";
|
||||||
import { createVariants } from "./createVariants";
|
import { createVariants } from "./createVariants";
|
||||||
import { ProductVariantCreateFormData } from "./form";
|
import { ProductVariantCreateFormData } from "./form";
|
||||||
|
|
||||||
|
@ -20,20 +22,24 @@ export type ProductVariantCreateReducerActionType =
|
||||||
| "changeAttributeValuePrice"
|
| "changeAttributeValuePrice"
|
||||||
| "changeAttributeValueStock"
|
| "changeAttributeValueStock"
|
||||||
| "changeVariantData"
|
| "changeVariantData"
|
||||||
|
| "changeVariantStockData"
|
||||||
| "deleteVariant"
|
| "deleteVariant"
|
||||||
| "reload"
|
| "reload"
|
||||||
| "selectValue";
|
| "selectValue";
|
||||||
|
|
||||||
export type VariantField = "stock" | "price" | "sku";
|
export type VariantField = "price" | "sku";
|
||||||
export interface ProductVariantCreateReducerAction {
|
export interface ProductVariantCreateReducerAction {
|
||||||
all?: boolean;
|
all?: boolean;
|
||||||
attributeId?: string;
|
attributeId?: string;
|
||||||
data?: ProductVariantCreateFormData;
|
data?: ProductVariantCreateFormData;
|
||||||
field?: VariantField;
|
field?: VariantField;
|
||||||
|
quantity?: number;
|
||||||
|
stock?: StockInput;
|
||||||
type: ProductVariantCreateReducerActionType;
|
type: ProductVariantCreateReducerActionType;
|
||||||
value?: string;
|
value?: string;
|
||||||
valueId?: string;
|
valueId?: string;
|
||||||
variantIndex?: number;
|
variantIndex?: number;
|
||||||
|
warehouseIndex?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectValue(
|
function selectValue(
|
||||||
|
@ -70,7 +76,7 @@ function selectValue(
|
||||||
? toggle(
|
? toggle(
|
||||||
{
|
{
|
||||||
slug: valueSlug,
|
slug: valueSlug,
|
||||||
value: ""
|
value: []
|
||||||
},
|
},
|
||||||
prevState.stock.values,
|
prevState.stock.values,
|
||||||
(a, b) => a.slug === b.slug
|
(a, b) => a.slug === b.slug
|
||||||
|
@ -95,36 +101,26 @@ function applyPriceToAll(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
value: boolean
|
value: boolean
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
const data = {
|
return {
|
||||||
...state,
|
...state,
|
||||||
price: {
|
price: {
|
||||||
...state.price,
|
...state.price,
|
||||||
all: value
|
all: value
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyStockToAll(
|
function applyStockToAll(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
value: boolean
|
value: boolean
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
const data = {
|
return {
|
||||||
...state,
|
...state,
|
||||||
stock: {
|
stock: {
|
||||||
...state.stock,
|
...state.stock,
|
||||||
all: value
|
all: value
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeAttributeValuePrice(
|
function changeAttributeValuePrice(
|
||||||
|
@ -149,24 +145,20 @@ function changeAttributeValuePrice(
|
||||||
index
|
index
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = {
|
return {
|
||||||
...state,
|
...state,
|
||||||
price: {
|
price: {
|
||||||
...state.price,
|
...state.price,
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeAttributeValueStock(
|
function changeAttributeValueStock(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
attributeValueSlug: string,
|
attributeValueSlug: string,
|
||||||
stock: string
|
warehouseIndex: number,
|
||||||
|
quantity: number
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
const index = state.stock.values.findIndex(
|
const index = state.stock.values.findIndex(
|
||||||
value => value.slug === attributeValueSlug
|
value => value.slug === attributeValueSlug
|
||||||
|
@ -179,24 +171,19 @@ function changeAttributeValueStock(
|
||||||
const values = updateAtIndex(
|
const values = updateAtIndex(
|
||||||
{
|
{
|
||||||
slug: attributeValueSlug,
|
slug: attributeValueSlug,
|
||||||
value: stock
|
value: updateAtIndex(quantity, state.stock.value, warehouseIndex)
|
||||||
},
|
},
|
||||||
state.stock.values,
|
state.stock.values,
|
||||||
index
|
index
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = {
|
return {
|
||||||
...state,
|
...state,
|
||||||
stock: {
|
stock: {
|
||||||
...state.stock,
|
...state.stock,
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyPriceToAttributeId(
|
function changeApplyPriceToAttributeId(
|
||||||
|
@ -210,7 +197,8 @@ function changeApplyPriceToAttributeId(
|
||||||
slug,
|
slug,
|
||||||
value: ""
|
value: ""
|
||||||
}));
|
}));
|
||||||
const data = {
|
|
||||||
|
return {
|
||||||
...state,
|
...state,
|
||||||
price: {
|
price: {
|
||||||
...state.price,
|
...state.price,
|
||||||
|
@ -218,11 +206,6 @@ function changeApplyPriceToAttributeId(
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyStockToAttributeId(
|
function changeApplyStockToAttributeId(
|
||||||
|
@ -234,10 +217,10 @@ function changeApplyStockToAttributeId(
|
||||||
);
|
);
|
||||||
const values = attribute.values.map(slug => ({
|
const values = attribute.values.map(slug => ({
|
||||||
slug,
|
slug,
|
||||||
value: ""
|
value: []
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const data = {
|
return {
|
||||||
...state,
|
...state,
|
||||||
stock: {
|
stock: {
|
||||||
...state.stock,
|
...state.stock,
|
||||||
|
@ -245,47 +228,33 @@ function changeApplyStockToAttributeId(
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyPriceToAllValue(
|
function changeApplyPriceToAllValue(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
value: string
|
value: string
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
const data = {
|
return {
|
||||||
...state,
|
...state,
|
||||||
price: {
|
price: {
|
||||||
...state.price,
|
...state.price,
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyStockToAllValue(
|
function changeApplyStockToAllValue(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
value: string
|
warehouseIndex: number,
|
||||||
|
quantity: number
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
const data = {
|
return {
|
||||||
...state,
|
...state,
|
||||||
stock: {
|
stock: {
|
||||||
...state.stock,
|
...state.stock,
|
||||||
value
|
value: updateAtIndex(quantity, state.stock.value, warehouseIndex)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
|
||||||
...data,
|
|
||||||
variants: createVariants(data)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeVariantData(
|
function changeVariantData(
|
||||||
|
@ -299,8 +268,6 @@ function changeVariantData(
|
||||||
variant.priceOverride = value;
|
variant.priceOverride = value;
|
||||||
} else if (field === "sku") {
|
} else if (field === "sku") {
|
||||||
variant.sku = value;
|
variant.sku = value;
|
||||||
} else {
|
|
||||||
variant.quantity = parseInt(value, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -309,6 +276,24 @@ function changeVariantData(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeVariantStockData(
|
||||||
|
state: ProductVariantCreateFormData,
|
||||||
|
stock: StockInput,
|
||||||
|
variantIndex: number
|
||||||
|
): ProductVariantCreateFormData {
|
||||||
|
const variant = state.variants[variantIndex];
|
||||||
|
variant.stocks = update(
|
||||||
|
stock,
|
||||||
|
variant.stocks,
|
||||||
|
(a, b) => a.warehouse === b.warehouse
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
variants: updateAtIndex(variant, state.variants, variantIndex)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function deleteVariant(
|
function deleteVariant(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
variantIndex: number
|
variantIndex: number
|
||||||
|
@ -319,6 +304,15 @@ function deleteVariant(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createVariantMatrix(
|
||||||
|
state: ProductVariantCreateFormData
|
||||||
|
): ProductVariantCreateFormData {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
variants: createVariants(state)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function reduceProductVariantCreateFormData(
|
function reduceProductVariantCreateFormData(
|
||||||
prevState: ProductVariantCreateFormData,
|
prevState: ProductVariantCreateFormData,
|
||||||
action: ProductVariantCreateReducerAction
|
action: ProductVariantCreateReducerAction
|
||||||
|
@ -326,7 +320,6 @@ function reduceProductVariantCreateFormData(
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "selectValue":
|
case "selectValue":
|
||||||
return selectValue(prevState, action.attributeId, action.valueId);
|
return selectValue(prevState, action.attributeId, action.valueId);
|
||||||
|
|
||||||
case "applyPriceToAll":
|
case "applyPriceToAll":
|
||||||
return applyPriceToAll(prevState, action.all);
|
return applyPriceToAll(prevState, action.all);
|
||||||
case "applyStockToAll":
|
case "applyStockToAll":
|
||||||
|
@ -334,7 +327,12 @@ function reduceProductVariantCreateFormData(
|
||||||
case "changeAttributeValuePrice":
|
case "changeAttributeValuePrice":
|
||||||
return changeAttributeValuePrice(prevState, action.valueId, action.value);
|
return changeAttributeValuePrice(prevState, action.valueId, action.value);
|
||||||
case "changeAttributeValueStock":
|
case "changeAttributeValueStock":
|
||||||
return changeAttributeValueStock(prevState, action.valueId, action.value);
|
return changeAttributeValueStock(
|
||||||
|
prevState,
|
||||||
|
action.valueId,
|
||||||
|
action.quantity,
|
||||||
|
action.warehouseIndex
|
||||||
|
);
|
||||||
case "changeApplyPriceToAttributeId":
|
case "changeApplyPriceToAttributeId":
|
||||||
return changeApplyPriceToAttributeId(prevState, action.attributeId);
|
return changeApplyPriceToAttributeId(prevState, action.attributeId);
|
||||||
case "changeApplyStockToAttributeId":
|
case "changeApplyStockToAttributeId":
|
||||||
|
@ -342,7 +340,11 @@ function reduceProductVariantCreateFormData(
|
||||||
case "changeApplyPriceToAllValue":
|
case "changeApplyPriceToAllValue":
|
||||||
return changeApplyPriceToAllValue(prevState, action.value);
|
return changeApplyPriceToAllValue(prevState, action.value);
|
||||||
case "changeApplyStockToAllValue":
|
case "changeApplyStockToAllValue":
|
||||||
return changeApplyStockToAllValue(prevState, action.value);
|
return changeApplyStockToAllValue(
|
||||||
|
prevState,
|
||||||
|
action.quantity,
|
||||||
|
action.warehouseIndex
|
||||||
|
);
|
||||||
case "changeVariantData":
|
case "changeVariantData":
|
||||||
return changeVariantData(
|
return changeVariantData(
|
||||||
prevState,
|
prevState,
|
||||||
|
@ -350,10 +352,16 @@ function reduceProductVariantCreateFormData(
|
||||||
action.value,
|
action.value,
|
||||||
action.variantIndex
|
action.variantIndex
|
||||||
);
|
);
|
||||||
|
case "changeVariantStockData":
|
||||||
|
return changeVariantStockData(
|
||||||
|
prevState,
|
||||||
|
action.stock,
|
||||||
|
action.variantIndex
|
||||||
|
);
|
||||||
case "deleteVariant":
|
case "deleteVariant":
|
||||||
return deleteVariant(prevState, action.variantIndex);
|
return deleteVariant(prevState, action.variantIndex);
|
||||||
case "reload":
|
case "reload":
|
||||||
return action.data;
|
return action.data ? action.data : createVariantMatrix(prevState);
|
||||||
default:
|
default:
|
||||||
return prevState;
|
return prevState;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import gql from "graphql-tag";
|
import gql from "graphql-tag";
|
||||||
|
|
||||||
import makeQuery from "@saleor/hooks/makeQuery";
|
import makeQuery from "@saleor/hooks/makeQuery";
|
||||||
|
import { warehouseFragment } from "@saleor/warehouses/queries";
|
||||||
import { pageInfoFragment, TypedQuery } from "../queries";
|
import { pageInfoFragment, TypedQuery } from "../queries";
|
||||||
import {
|
import {
|
||||||
AvailableInGridAttributes,
|
AvailableInGridAttributes,
|
||||||
|
@ -480,6 +481,7 @@ export const AvailableInGridAttributesQuery = TypedQuery<
|
||||||
const createMultipleVariantsData = gql`
|
const createMultipleVariantsData = gql`
|
||||||
${fragmentMoney}
|
${fragmentMoney}
|
||||||
${productVariantAttributesFragment}
|
${productVariantAttributesFragment}
|
||||||
|
${warehouseFragment}
|
||||||
query CreateMultipleVariantsData($id: ID!) {
|
query CreateMultipleVariantsData($id: ID!) {
|
||||||
product(id: $id) {
|
product(id: $id) {
|
||||||
...ProductVariantAttributesFragment
|
...ProductVariantAttributesFragment
|
||||||
|
@ -487,6 +489,13 @@ const createMultipleVariantsData = gql`
|
||||||
...Money
|
...Money
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
warehouses(first: 20) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
...WarehouseFragment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const useCreateMultipleVariantsData = makeQuery<
|
export const useCreateMultipleVariantsData = makeQuery<
|
||||||
|
|
|
@ -71,8 +71,25 @@ export interface CreateMultipleVariantsData_product {
|
||||||
basePrice: CreateMultipleVariantsData_product_basePrice | null;
|
basePrice: CreateMultipleVariantsData_product_basePrice | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CreateMultipleVariantsData_warehouses_edges_node {
|
||||||
|
__typename: "Warehouse";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateMultipleVariantsData_warehouses_edges {
|
||||||
|
__typename: "WarehouseCountableEdge";
|
||||||
|
node: CreateMultipleVariantsData_warehouses_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateMultipleVariantsData_warehouses {
|
||||||
|
__typename: "WarehouseCountableConnection";
|
||||||
|
edges: CreateMultipleVariantsData_warehouses_edges[];
|
||||||
|
}
|
||||||
|
|
||||||
export interface CreateMultipleVariantsData {
|
export interface CreateMultipleVariantsData {
|
||||||
product: CreateMultipleVariantsData_product | null;
|
product: CreateMultipleVariantsData_product | null;
|
||||||
|
warehouses: CreateMultipleVariantsData_warehouses | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateMultipleVariantsDataVariables {
|
export interface CreateMultipleVariantsDataVariables {
|
||||||
|
|
|
@ -63,6 +63,7 @@ const ProductVariantCreator: React.FC<ProductVariantCreatorProps> = ({
|
||||||
variables: { id, inputs }
|
variables: { id, inputs }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
warehouses={data?.warehouses.edges.map(edge => edge.node)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1223,7 +1223,7 @@ export interface ProductVariantBulkCreateInput {
|
||||||
costPrice?: any | null;
|
costPrice?: any | null;
|
||||||
priceOverride?: any | null;
|
priceOverride?: any | null;
|
||||||
sku: string;
|
sku: string;
|
||||||
quantity?: number | null;
|
stocks: StockInput[];
|
||||||
trackInventory?: boolean | null;
|
trackInventory?: boolean | null;
|
||||||
weight?: any | null;
|
weight?: any | null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import IconButton from "@material-ui/core/IconButton";
|
||||||
import DeleteIcon from "@material-ui/icons/Delete";
|
import DeleteIcon from "@material-ui/icons/Delete";
|
||||||
import EditIcon from "@material-ui/icons/Edit";
|
import EditIcon from "@material-ui/icons/Edit";
|
||||||
|
|
||||||
import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment";
|
|
||||||
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
import ResponsiveTable from "@saleor/components/ResponsiveTable";
|
||||||
import Skeleton from "@saleor/components/Skeleton";
|
import Skeleton from "@saleor/components/Skeleton";
|
||||||
import TablePagination from "@saleor/components/TablePagination";
|
import TablePagination from "@saleor/components/TablePagination";
|
||||||
|
@ -19,6 +18,7 @@ import { ListProps, SortPage } from "@saleor/types";
|
||||||
import { WarehouseListUrlSortField } from "@saleor/warehouses/urls";
|
import { WarehouseListUrlSortField } from "@saleor/warehouses/urls";
|
||||||
import TableCellHeader from "@saleor/components/TableCellHeader";
|
import TableCellHeader from "@saleor/components/TableCellHeader";
|
||||||
import { getArrowDirection } from "@saleor/utils/sort";
|
import { getArrowDirection } from "@saleor/utils/sort";
|
||||||
|
import { WarehouseWithShippingFragment } from "@saleor/warehouses/types/WarehouseWithShippingFragment";
|
||||||
|
|
||||||
const useStyles = makeStyles(
|
const useStyles = makeStyles(
|
||||||
theme => ({
|
theme => ({
|
||||||
|
@ -59,7 +59,7 @@ const useStyles = makeStyles(
|
||||||
interface WarehouseListProps
|
interface WarehouseListProps
|
||||||
extends ListProps,
|
extends ListProps,
|
||||||
SortPage<WarehouseListUrlSortField> {
|
SortPage<WarehouseListUrlSortField> {
|
||||||
warehouses: WarehouseFragment[];
|
warehouses: WarehouseWithShippingFragment[];
|
||||||
onAdd: () => void;
|
onAdd: () => void;
|
||||||
onRemove: (id: string) => void;
|
onRemove: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import Card from "@material-ui/core/Card";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
|
||||||
import { WarehouseFragment } from "@saleor/warehouses/types/WarehouseFragment";
|
|
||||||
import Container from "@saleor/components/Container";
|
import Container from "@saleor/components/Container";
|
||||||
import PageHeader from "@saleor/components/PageHeader";
|
import PageHeader from "@saleor/components/PageHeader";
|
||||||
import SearchBar from "@saleor/components/SearchBar";
|
import SearchBar from "@saleor/components/SearchBar";
|
||||||
|
@ -16,6 +15,7 @@ import {
|
||||||
} from "@saleor/types";
|
} from "@saleor/types";
|
||||||
import { WarehouseListUrlSortField } from "@saleor/warehouses/urls";
|
import { WarehouseListUrlSortField } from "@saleor/warehouses/urls";
|
||||||
import AppHeader from "@saleor/components/AppHeader";
|
import AppHeader from "@saleor/components/AppHeader";
|
||||||
|
import { WarehouseWithShippingFragment } from "@saleor/warehouses/types/WarehouseWithShippingFragment";
|
||||||
import WarehouseList from "../WarehouseList";
|
import WarehouseList from "../WarehouseList";
|
||||||
|
|
||||||
export interface WarehouseListPageProps
|
export interface WarehouseListPageProps
|
||||||
|
@ -23,7 +23,7 @@ export interface WarehouseListPageProps
|
||||||
SearchPageProps,
|
SearchPageProps,
|
||||||
SortPage<WarehouseListUrlSortField>,
|
SortPage<WarehouseListUrlSortField>,
|
||||||
TabPageProps {
|
TabPageProps {
|
||||||
warehouses: WarehouseFragment[];
|
warehouses: WarehouseWithShippingFragment[];
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
onRemove: (id: string) => void;
|
onRemove: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,12 @@ export const warehouseFragment = gql`
|
||||||
fragment WarehouseFragment on Warehouse {
|
fragment WarehouseFragment on Warehouse {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const warehouseWithShippingFragment = gql`
|
||||||
|
${warehouseFragment}
|
||||||
|
fragment WarehouseWithShippingFragment on Warehouse {
|
||||||
|
...WarehouseFragment
|
||||||
shippingZones(first: 100) {
|
shippingZones(first: 100) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
@ -26,9 +32,9 @@ export const warehouseFragment = gql`
|
||||||
|
|
||||||
export const warehouseDetailsFragment = gql`
|
export const warehouseDetailsFragment = gql`
|
||||||
${fragmentAddress}
|
${fragmentAddress}
|
||||||
${warehouseFragment}
|
${warehouseWithShippingFragment}
|
||||||
fragment WarehouseDetailsFragment on Warehouse {
|
fragment WarehouseDetailsFragment on Warehouse {
|
||||||
...WarehouseFragment
|
...WarehouseWithShippingFragment
|
||||||
address {
|
address {
|
||||||
...AddressFragment
|
...AddressFragment
|
||||||
}
|
}
|
||||||
|
@ -36,7 +42,7 @@ export const warehouseDetailsFragment = gql`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const warehouseList = gql`
|
const warehouseList = gql`
|
||||||
${warehouseFragment}
|
${warehouseWithShippingFragment}
|
||||||
${pageInfoFragment}
|
${pageInfoFragment}
|
||||||
query WarehouseList(
|
query WarehouseList(
|
||||||
$first: Int
|
$first: Int
|
||||||
|
@ -56,7 +62,7 @@ const warehouseList = gql`
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
...WarehouseFragment
|
...WarehouseWithShippingFragment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pageInfo {
|
pageInfo {
|
||||||
|
|
|
@ -6,25 +6,8 @@
|
||||||
// GraphQL fragment: WarehouseFragment
|
// GraphQL fragment: WarehouseFragment
|
||||||
// ====================================================
|
// ====================================================
|
||||||
|
|
||||||
export interface WarehouseFragment_shippingZones_edges_node {
|
|
||||||
__typename: "ShippingZone";
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WarehouseFragment_shippingZones_edges {
|
|
||||||
__typename: "ShippingZoneCountableEdge";
|
|
||||||
node: WarehouseFragment_shippingZones_edges_node;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WarehouseFragment_shippingZones {
|
|
||||||
__typename: "ShippingZoneCountableConnection";
|
|
||||||
edges: WarehouseFragment_shippingZones_edges[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WarehouseFragment {
|
export interface WarehouseFragment {
|
||||||
__typename: "Warehouse";
|
__typename: "Warehouse";
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
shippingZones: WarehouseFragment_shippingZones;
|
|
||||||
}
|
}
|
||||||
|
|
30
src/warehouses/types/WarehouseWithShippingFragment.ts
Normal file
30
src/warehouses/types/WarehouseWithShippingFragment.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/* tslint:disable */
|
||||||
|
/* eslint-disable */
|
||||||
|
// This file was automatically generated and should not be edited.
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// GraphQL fragment: WarehouseWithShippingFragment
|
||||||
|
// ====================================================
|
||||||
|
|
||||||
|
export interface WarehouseWithShippingFragment_shippingZones_edges_node {
|
||||||
|
__typename: "ShippingZone";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WarehouseWithShippingFragment_shippingZones_edges {
|
||||||
|
__typename: "ShippingZoneCountableEdge";
|
||||||
|
node: WarehouseWithShippingFragment_shippingZones_edges_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WarehouseWithShippingFragment_shippingZones {
|
||||||
|
__typename: "ShippingZoneCountableConnection";
|
||||||
|
edges: WarehouseWithShippingFragment_shippingZones_edges[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WarehouseWithShippingFragment {
|
||||||
|
__typename: "Warehouse";
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
shippingZones: WarehouseWithShippingFragment_shippingZones;
|
||||||
|
}
|
Loading…
Reference in a new issue