Make it work
This commit is contained in:
parent
4d9171faa4
commit
fcfdd432b4
7 changed files with 488 additions and 158 deletions
|
@ -112,66 +112,64 @@ const ProductVariantCreatePrices: React.FC<
|
||||||
})}
|
})}
|
||||||
onChange={() => onApplyPriceOrStockChange(false, "price")}
|
onChange={() => onApplyPriceOrStockChange(false, "price")}
|
||||||
/>
|
/>
|
||||||
{!data.price.all && (
|
|
||||||
<>
|
|
||||||
<FormSpacer />
|
|
||||||
<Grid variant="inverted">
|
|
||||||
<div className={classes.label}>
|
|
||||||
<Typography>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Choose attribute"
|
|
||||||
description="variant attribute"
|
|
||||||
/>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<SingleSelectField
|
|
||||||
choices={attributeChoices}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Attribute",
|
|
||||||
description: "variant attribute"
|
|
||||||
})}
|
|
||||||
value={data.price.attribute}
|
|
||||||
onChange={event =>
|
|
||||||
onAttributeSelect(event.target.value, "price")
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
{priceAttributeValues &&
|
|
||||||
priceAttributeValues.map(
|
|
||||||
(attributeValue, attributeValueIndex) => (
|
|
||||||
<>
|
|
||||||
<FormSpacer />
|
|
||||||
<Grid variant="inverted">
|
|
||||||
<div className={classes.label}>
|
|
||||||
<Typography>{attributeValue.name}</Typography>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Price",
|
|
||||||
description: "variant price",
|
|
||||||
id: "productVariantCreatePricesSetPricePlaceholder"
|
|
||||||
})}
|
|
||||||
fullWidth
|
|
||||||
value={data.price.values[attributeValueIndex].value}
|
|
||||||
onChange={event =>
|
|
||||||
onAttributeValueChange(
|
|
||||||
attributeValue.id,
|
|
||||||
event.target.value,
|
|
||||||
"price"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
{!data.price.all && (
|
||||||
|
<>
|
||||||
|
<FormSpacer />
|
||||||
|
<Grid variant="inverted">
|
||||||
|
<div className={classes.label}>
|
||||||
|
<Typography>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Choose attribute"
|
||||||
|
description="variant attribute"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<SingleSelectField
|
||||||
|
choices={attributeChoices}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Attribute",
|
||||||
|
description: "variant attribute"
|
||||||
|
})}
|
||||||
|
value={data.price.attribute}
|
||||||
|
onChange={event =>
|
||||||
|
onAttributeSelect(event.target.value, "price")
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
{priceAttributeValues &&
|
||||||
|
priceAttributeValues.map((attributeValue, attributeValueIndex) => (
|
||||||
|
<>
|
||||||
|
<FormSpacer />
|
||||||
|
<Grid variant="inverted">
|
||||||
|
<div className={classes.label}>
|
||||||
|
<Typography>{attributeValue.name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Price",
|
||||||
|
description: "variant price",
|
||||||
|
id: "productVariantCreatePricesSetPricePlaceholder"
|
||||||
|
})}
|
||||||
|
fullWidth
|
||||||
|
value={data.price.values[attributeValueIndex].value}
|
||||||
|
onChange={event =>
|
||||||
|
onAttributeValueChange(
|
||||||
|
attributeValue.id,
|
||||||
|
event.target.value,
|
||||||
|
"price"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<FormSpacer />
|
<FormSpacer />
|
||||||
<Typography color="textSecondary" variant="headline">
|
<Typography color="textSecondary" variant="headline">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
|
@ -212,66 +210,64 @@ const ProductVariantCreatePrices: React.FC<
|
||||||
})}
|
})}
|
||||||
onChange={() => onApplyPriceOrStockChange(false, "stock")}
|
onChange={() => onApplyPriceOrStockChange(false, "stock")}
|
||||||
/>
|
/>
|
||||||
{!data.stock.all && (
|
|
||||||
<>
|
|
||||||
<FormSpacer />
|
|
||||||
<Grid variant="inverted">
|
|
||||||
<div className={classes.label}>
|
|
||||||
<Typography>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Choose attribute"
|
|
||||||
description="variant attribute"
|
|
||||||
/>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<SingleSelectField
|
|
||||||
choices={attributeChoices}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Attribute",
|
|
||||||
description: "variant attribute"
|
|
||||||
})}
|
|
||||||
value={data.stock.attribute}
|
|
||||||
onChange={event =>
|
|
||||||
onAttributeSelect(event.target.value, "stock")
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
{stockAttributeValues &&
|
|
||||||
stockAttributeValues.map(
|
|
||||||
(attributeValue, attributeValueIndex) => (
|
|
||||||
<>
|
|
||||||
<FormSpacer />
|
|
||||||
<Grid variant="inverted">
|
|
||||||
<div className={classes.label}>
|
|
||||||
<Typography>{attributeValue.name}</Typography>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
label={intl.formatMessage({
|
|
||||||
defaultMessage: "Stock",
|
|
||||||
description: "variant stock",
|
|
||||||
id: "productVariantCreatePricesSetStockPlaceholder"
|
|
||||||
})}
|
|
||||||
fullWidth
|
|
||||||
value={data.stock.values[attributeValueIndex].value}
|
|
||||||
onChange={event =>
|
|
||||||
onAttributeValueChange(
|
|
||||||
attributeValue.id,
|
|
||||||
event.target.value,
|
|
||||||
"stock"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
{!data.stock.all && (
|
||||||
|
<>
|
||||||
|
<FormSpacer />
|
||||||
|
<Grid variant="inverted">
|
||||||
|
<div className={classes.label}>
|
||||||
|
<Typography>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="Choose attribute"
|
||||||
|
description="variant attribute"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<SingleSelectField
|
||||||
|
choices={attributeChoices}
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Attribute",
|
||||||
|
description: "variant attribute"
|
||||||
|
})}
|
||||||
|
value={data.stock.attribute}
|
||||||
|
onChange={event =>
|
||||||
|
onAttributeSelect(event.target.value, "stock")
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
{stockAttributeValues &&
|
||||||
|
stockAttributeValues.map((attributeValue, attributeValueIndex) => (
|
||||||
|
<>
|
||||||
|
<FormSpacer />
|
||||||
|
<Grid variant="inverted">
|
||||||
|
<div className={classes.label}>
|
||||||
|
<Typography>{attributeValue.name}</Typography>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<TextField
|
||||||
|
label={intl.formatMessage({
|
||||||
|
defaultMessage: "Stock",
|
||||||
|
description: "variant stock",
|
||||||
|
id: "productVariantCreatePricesSetStockPlaceholder"
|
||||||
|
})}
|
||||||
|
fullWidth
|
||||||
|
value={data.stock.values[attributeValueIndex].value}
|
||||||
|
onChange={event =>
|
||||||
|
onAttributeValueChange(
|
||||||
|
attributeValue.id,
|
||||||
|
event.target.value,
|
||||||
|
"stock"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -125,7 +125,9 @@ const ProductVariantCreateSummary: React.FC<
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{data.variants.map(variant => (
|
{data.variants.map(variant => (
|
||||||
<TableRow
|
<TableRow
|
||||||
key={variant.attributes.map(attribute => attribute.id).join(":")}
|
key={variant.attributes
|
||||||
|
.map(attribute => attribute.values[0])
|
||||||
|
.join(":")}
|
||||||
>
|
>
|
||||||
<TableCell className={classNames(classes.col, classes.colName)}>
|
<TableCell className={classNames(classes.col, classes.colName)}>
|
||||||
{getVariantName(variant, attributes).map(
|
{getVariantName(variant, attributes).map(
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {
|
||||||
createVariantFlatMatrixDimension,
|
createVariantFlatMatrixDimension,
|
||||||
createVariants
|
createVariants
|
||||||
} from "./createVariants";
|
} from "./createVariants";
|
||||||
import { thirdStep } from "./fixtures";
|
import { attributes, thirdStep } from "./fixtures";
|
||||||
import { ProductVariantCreateFormData } from "./form";
|
import { ProductVariantCreateFormData } from "./form";
|
||||||
|
|
||||||
describe("Creates variant matrix", () => {
|
describe("Creates variant matrix", () => {
|
||||||
|
@ -35,9 +35,186 @@ describe("Creates variant matrix", () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const variants = createVariants(data);
|
const variants = createVariants(data);
|
||||||
|
expect(variants).toHaveLength(
|
||||||
|
thirdStep.attributes.reduce(
|
||||||
|
(acc, attribute) => acc * attribute.values.length,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
variants.forEach(variant => {
|
variants.forEach(variant => {
|
||||||
expect(variant.priceOverride).toBe(price);
|
expect(variant.priceOverride).toBe(price);
|
||||||
expect(variant.quantity).toBe(stock);
|
expect(variant.quantity).toBe(stock);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("with constant stock and attribute dependent price", () => {
|
||||||
|
const price = 49.99;
|
||||||
|
const stock = 80;
|
||||||
|
const attribute = attributes.find(
|
||||||
|
attribute => attribute.id === thirdStep.attributes[0].id
|
||||||
|
);
|
||||||
|
|
||||||
|
const data: ProductVariantCreateFormData = {
|
||||||
|
...thirdStep,
|
||||||
|
price: {
|
||||||
|
...thirdStep.price,
|
||||||
|
all: false,
|
||||||
|
attribute: attribute.id,
|
||||||
|
values: attribute.values.map((attributeValue, attributeValueIndex) => ({
|
||||||
|
id: attributeValue,
|
||||||
|
value: (price * (attributeValueIndex + 1)).toString()
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
stock: {
|
||||||
|
...thirdStep.stock,
|
||||||
|
all: true,
|
||||||
|
value: stock.toString()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const variants = createVariants(data);
|
||||||
|
expect(variants).toHaveLength(
|
||||||
|
thirdStep.attributes.reduce(
|
||||||
|
(acc, attribute) => acc * attribute.values.length,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
variants.forEach(variant => {
|
||||||
|
expect(variant.quantity).toBe(stock);
|
||||||
|
});
|
||||||
|
|
||||||
|
attribute.values.forEach((attributeValue, attributeValueIndex) => {
|
||||||
|
variants
|
||||||
|
.filter(
|
||||||
|
variant =>
|
||||||
|
variant.attributes.find(
|
||||||
|
variantAttribute => variantAttribute.id === attribute.id
|
||||||
|
).values[0] === attributeValue
|
||||||
|
)
|
||||||
|
.forEach(variant => {
|
||||||
|
expect(variant.priceOverride).toBe(
|
||||||
|
(price * (attributeValueIndex + 1)).toString()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("with constant price and attribute dependent stock", () => {
|
||||||
|
const price = "49.99";
|
||||||
|
const stock = 80;
|
||||||
|
const attribute = attributes.find(
|
||||||
|
attribute => attribute.id === thirdStep.attributes[0].id
|
||||||
|
);
|
||||||
|
|
||||||
|
const data: ProductVariantCreateFormData = {
|
||||||
|
...thirdStep,
|
||||||
|
price: {
|
||||||
|
...thirdStep.price,
|
||||||
|
all: true,
|
||||||
|
value: price
|
||||||
|
},
|
||||||
|
stock: {
|
||||||
|
...thirdStep.stock,
|
||||||
|
all: false,
|
||||||
|
attribute: attribute.id,
|
||||||
|
values: attribute.values.map((attributeValue, attributeValueIndex) => ({
|
||||||
|
id: attributeValue,
|
||||||
|
value: (stock * (attributeValueIndex + 1)).toString()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const variants = createVariants(data);
|
||||||
|
expect(variants).toHaveLength(
|
||||||
|
thirdStep.attributes.reduce(
|
||||||
|
(acc, attribute) => acc * attribute.values.length,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
variants.forEach(variant => {
|
||||||
|
expect(variant.priceOverride).toBe(price);
|
||||||
|
});
|
||||||
|
|
||||||
|
attribute.values.forEach((attributeValue, attributeValueIndex) => {
|
||||||
|
variants
|
||||||
|
.filter(
|
||||||
|
variant =>
|
||||||
|
variant.attributes.find(
|
||||||
|
variantAttribute => variantAttribute.id === attribute.id
|
||||||
|
).values[0] === attributeValue
|
||||||
|
)
|
||||||
|
.forEach(variant => {
|
||||||
|
expect(variant.quantity).toBe(stock * (attributeValueIndex + 1));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("with attribute dependent price and stock", () => {
|
||||||
|
const price = 49.99;
|
||||||
|
const stock = 80;
|
||||||
|
const attribute = attributes.find(
|
||||||
|
attribute => attribute.id === thirdStep.attributes[0].id
|
||||||
|
);
|
||||||
|
|
||||||
|
const data: ProductVariantCreateFormData = {
|
||||||
|
...thirdStep,
|
||||||
|
price: {
|
||||||
|
...thirdStep.price,
|
||||||
|
all: false,
|
||||||
|
attribute: attribute.id,
|
||||||
|
values: attribute.values.map((attributeValue, attributeValueIndex) => ({
|
||||||
|
id: attributeValue,
|
||||||
|
value: (price * (attributeValueIndex + 1)).toString()
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
stock: {
|
||||||
|
...thirdStep.stock,
|
||||||
|
all: false,
|
||||||
|
attribute: attribute.id,
|
||||||
|
values: attribute.values.map((attributeValue, attributeValueIndex) => ({
|
||||||
|
id: attributeValue,
|
||||||
|
value: (stock * (attributeValueIndex + 1)).toString()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const variants = createVariants(data);
|
||||||
|
expect(variants).toHaveLength(
|
||||||
|
thirdStep.attributes.reduce(
|
||||||
|
(acc, attribute) => acc * attribute.values.length,
|
||||||
|
1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
attribute.values.forEach((attributeValue, attributeValueIndex) => {
|
||||||
|
variants
|
||||||
|
.filter(
|
||||||
|
variant =>
|
||||||
|
variant.attributes.find(
|
||||||
|
variantAttribute => variantAttribute.id === attribute.id
|
||||||
|
).values[0] === attributeValue
|
||||||
|
)
|
||||||
|
.forEach(variant => {
|
||||||
|
expect(variant.priceOverride).toBe(
|
||||||
|
(price * (attributeValueIndex + 1)).toString()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
attribute.values.forEach((attributeValue, attributeValueIndex) => {
|
||||||
|
variants
|
||||||
|
.filter(
|
||||||
|
variant =>
|
||||||
|
variant.attributes.find(
|
||||||
|
variantAttribute => variantAttribute.id === attribute.id
|
||||||
|
).values[0] === attributeValue
|
||||||
|
)
|
||||||
|
.forEach(variant => {
|
||||||
|
expect(variant.quantity).toBe(stock * (attributeValueIndex + 1));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,32 +1,42 @@
|
||||||
import { ProductVariantCreateInput } from "@saleor/types/globalTypes";
|
import { ProductVariantCreateInput } from "@saleor/types/globalTypes";
|
||||||
import { Attribute, ProductVariantCreateFormData } from "./form";
|
import {
|
||||||
|
AllOrAttribute,
|
||||||
|
Attribute,
|
||||||
|
ProductVariantCreateFormData
|
||||||
|
} from "./form";
|
||||||
|
|
||||||
interface CreateVariantAttributeValueInput {
|
interface CreateVariantAttributeValueInput {
|
||||||
attributeId: string;
|
attributeId: string;
|
||||||
attributeValueId: string;
|
attributeValueId: string;
|
||||||
}
|
}
|
||||||
type CreateVariantInput = CreateVariantAttributeValueInput[];
|
type CreateVariantInput = CreateVariantAttributeValueInput[];
|
||||||
|
|
||||||
|
function getAttributeValuePriceOrStock(
|
||||||
|
attributes: CreateVariantInput,
|
||||||
|
priceOrStock: AllOrAttribute
|
||||||
|
): string {
|
||||||
|
const attribute = attributes.find(
|
||||||
|
attribute => attribute.attributeId === priceOrStock.attribute
|
||||||
|
);
|
||||||
|
|
||||||
|
const attributeValue = priceOrStock.values.find(
|
||||||
|
attributeValue => attribute.attributeValueId === attributeValue.id
|
||||||
|
);
|
||||||
|
|
||||||
|
return attributeValue.value;
|
||||||
|
}
|
||||||
|
|
||||||
function createVariant(
|
function createVariant(
|
||||||
data: ProductVariantCreateFormData,
|
data: ProductVariantCreateFormData,
|
||||||
attributes: CreateVariantInput
|
attributes: CreateVariantInput
|
||||||
): ProductVariantCreateInput {
|
): ProductVariantCreateInput {
|
||||||
const priceOverride = data.price.all
|
const priceOverride = data.price.all
|
||||||
? data.price.value
|
? data.price.value
|
||||||
: data.price.values.find(
|
: getAttributeValuePriceOrStock(attributes, data.price);
|
||||||
value =>
|
|
||||||
attributes.find(
|
|
||||||
attribute => attribute.attributeId === data.price.attribute
|
|
||||||
).attributeValueId === value.id
|
|
||||||
).value;
|
|
||||||
const quantity = parseInt(
|
const quantity = parseInt(
|
||||||
data.stock.all
|
data.stock.all
|
||||||
? data.stock.value
|
? data.stock.value
|
||||||
: data.stock.values.find(
|
: getAttributeValuePriceOrStock(attributes, data.stock),
|
||||||
value =>
|
|
||||||
attributes.find(
|
|
||||||
attribute => attribute.attributeId === data.stock.attribute
|
|
||||||
).attributeValueId === value.id
|
|
||||||
).value,
|
|
||||||
10
|
10
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -81,6 +91,12 @@ export function createVariantFlatMatrixDimension(
|
||||||
export function createVariants(
|
export function createVariants(
|
||||||
data: ProductVariantCreateFormData
|
data: ProductVariantCreateFormData
|
||||||
): ProductVariantCreateInput[] {
|
): ProductVariantCreateInput[] {
|
||||||
|
if (
|
||||||
|
(!data.price.all && !data.price.attribute) ||
|
||||||
|
(!data.stock.all && !data.stock.attribute)
|
||||||
|
) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
const variants = createVariantFlatMatrixDimension([[]], data.attributes).map(
|
const variants = createVariantFlatMatrixDimension([[]], data.attributes).map(
|
||||||
variant => createVariant(data, variant)
|
variant => createVariant(data, variant)
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
import { initialForm, ProductVariantCreateFormData } from "./form";
|
import { createVariants } from "./createVariants";
|
||||||
|
import {
|
||||||
|
AllOrAttribute,
|
||||||
|
initialForm,
|
||||||
|
ProductVariantCreateFormData
|
||||||
|
} from "./form";
|
||||||
|
|
||||||
export const attributes = [
|
export const attributes = [
|
||||||
{
|
{
|
||||||
|
@ -44,6 +49,7 @@ export const secondStep: ProductVariantCreateFormData = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export const thirdStep: ProductVariantCreateFormData = {
|
export const thirdStep: ProductVariantCreateFormData = {
|
||||||
...secondStep,
|
...secondStep,
|
||||||
attributes: [
|
attributes: [
|
||||||
|
@ -61,3 +67,44 @@ export const thirdStep: ProductVariantCreateFormData = {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const price: AllOrAttribute = {
|
||||||
|
all: false,
|
||||||
|
attribute: thirdStep.attributes[1].id,
|
||||||
|
value: "",
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
id: thirdStep.attributes[1].values[0],
|
||||||
|
value: "24.99"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: thirdStep.attributes[1].values[1],
|
||||||
|
value: "26.99"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
const stock: AllOrAttribute = {
|
||||||
|
all: false,
|
||||||
|
attribute: thirdStep.attributes[2].id,
|
||||||
|
value: "",
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
id: thirdStep.attributes[2].values[0],
|
||||||
|
value: "50"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: thirdStep.attributes[2].values[1],
|
||||||
|
value: "35"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
export const fourthStep: ProductVariantCreateFormData = {
|
||||||
|
...thirdStep,
|
||||||
|
price,
|
||||||
|
stock,
|
||||||
|
variants: createVariants({
|
||||||
|
...thirdStep,
|
||||||
|
price,
|
||||||
|
stock
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { attributes, secondStep, thirdStep } from "./fixtures";
|
import { attributes, fourthStep, secondStep, thirdStep } from "./fixtures";
|
||||||
import { initialForm } from "./form";
|
import { initialForm } from "./form";
|
||||||
import reducer from "./reducer";
|
import reducer, { VariantField } from "./reducer";
|
||||||
|
|
||||||
function execActions<TState, TAction>(
|
function execActions<TState, TAction>(
|
||||||
initialState: TState,
|
initialState: TState,
|
||||||
|
@ -108,6 +108,7 @@ describe("Reducer is able to", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("select price to each attribute value", () => {
|
it("select price to each attribute value", () => {
|
||||||
|
const attribute = thirdStep.attributes[0];
|
||||||
const value = 45.99;
|
const value = 45.99;
|
||||||
const state = execActions(thirdStep, reducer, [
|
const state = execActions(thirdStep, reducer, [
|
||||||
{
|
{
|
||||||
|
@ -115,18 +116,18 @@ describe("Reducer is able to", () => {
|
||||||
type: "applyPriceToAll"
|
type: "applyPriceToAll"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeId: attributes[0].id,
|
attributeId: attribute.id,
|
||||||
type: "changeApplyPriceToAttributeId"
|
type: "changeApplyPriceToAttributeId"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "changeAttributeValuePrice",
|
type: "changeAttributeValuePrice",
|
||||||
value: value.toString(),
|
value: value.toString(),
|
||||||
valueId: attributes[0].values[0]
|
valueId: attribute.values[0]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "changeAttributeValuePrice",
|
type: "changeAttributeValuePrice",
|
||||||
value: (value + 6).toString(),
|
value: (value + 6).toString(),
|
||||||
valueId: attributes[0].values[6]
|
valueId: attribute.values[1]
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -139,6 +140,7 @@ describe("Reducer is able to", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("select stock to each attribute value", () => {
|
it("select stock to each attribute value", () => {
|
||||||
|
const attribute = thirdStep.attributes[0];
|
||||||
const value = 13;
|
const value = 13;
|
||||||
const state = execActions(thirdStep, reducer, [
|
const state = execActions(thirdStep, reducer, [
|
||||||
{
|
{
|
||||||
|
@ -146,18 +148,18 @@ describe("Reducer is able to", () => {
|
||||||
type: "applyStockToAll"
|
type: "applyStockToAll"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeId: attributes[0].id,
|
attributeId: attribute.id,
|
||||||
type: "changeApplyStockToAttributeId"
|
type: "changeApplyStockToAttributeId"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "changeAttributeValueStock",
|
type: "changeAttributeValueStock",
|
||||||
value: value.toString(),
|
value: value.toString(),
|
||||||
valueId: attributes[0].values[0]
|
valueId: attribute.values[0]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "changeAttributeValueStock",
|
type: "changeAttributeValueStock",
|
||||||
value: (value + 6).toString(),
|
value: (value + 6).toString(),
|
||||||
valueId: attributes[0].values[6]
|
valueId: attribute.values[1]
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -168,4 +170,24 @@ describe("Reducer is able to", () => {
|
||||||
);
|
);
|
||||||
expect(state).toMatchSnapshot();
|
expect(state).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("modify individual variant price", () => {
|
||||||
|
const field: VariantField = "price";
|
||||||
|
const value = "49.99";
|
||||||
|
const variantIndex = 3;
|
||||||
|
|
||||||
|
const state = execActions(fourthStep, reducer, [
|
||||||
|
{
|
||||||
|
field,
|
||||||
|
type: "changeVariantData",
|
||||||
|
value,
|
||||||
|
variantIndex
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect(state.variants[variantIndex].priceOverride).toBe(value);
|
||||||
|
expect(state.variants[variantIndex - 1].priceOverride).toBe(
|
||||||
|
fourthStep.variants[variantIndex - 1].priceOverride
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,14 +13,19 @@ export type ProductVariantCreateReducerActionType =
|
||||||
| "changeApplyStockToAttributeId"
|
| "changeApplyStockToAttributeId"
|
||||||
| "changeAttributeValuePrice"
|
| "changeAttributeValuePrice"
|
||||||
| "changeAttributeValueStock"
|
| "changeAttributeValueStock"
|
||||||
|
| "changeVariantData"
|
||||||
| "selectAttribute"
|
| "selectAttribute"
|
||||||
| "selectValue";
|
| "selectValue";
|
||||||
|
|
||||||
|
export type VariantField = "stock" | "price" | "sku";
|
||||||
export interface ProductVariantCreateReducerAction {
|
export interface ProductVariantCreateReducerAction {
|
||||||
all?: boolean;
|
all?: boolean;
|
||||||
attributeId?: string;
|
attributeId?: string;
|
||||||
|
field?: VariantField;
|
||||||
type: ProductVariantCreateReducerActionType;
|
type: ProductVariantCreateReducerActionType;
|
||||||
value?: string;
|
value?: string;
|
||||||
valueId?: string;
|
valueId?: string;
|
||||||
|
variantIndex?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectAttribute(
|
function selectAttribute(
|
||||||
|
@ -69,26 +74,36 @@ function applyPriceToAll(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
value: boolean
|
value: boolean
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
return {
|
const data = {
|
||||||
...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 {
|
||||||
return {
|
const data = {
|
||||||
...state,
|
...state,
|
||||||
stock: {
|
stock: {
|
||||||
...state.stock,
|
...state.stock,
|
||||||
all: value
|
all: value
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
variants: createVariants(data)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeAttributeValuePrice(
|
function changeAttributeValuePrice(
|
||||||
|
@ -113,13 +128,18 @@ function changeAttributeValuePrice(
|
||||||
index
|
index
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
const data = {
|
||||||
...state,
|
...state,
|
||||||
price: {
|
price: {
|
||||||
...state.price,
|
...state.price,
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
variants: createVariants(data)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeAttributeValueStock(
|
function changeAttributeValueStock(
|
||||||
|
@ -144,13 +164,18 @@ function changeAttributeValueStock(
|
||||||
index
|
index
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
const data = {
|
||||||
...state,
|
...state,
|
||||||
stock: {
|
stock: {
|
||||||
...state.stock,
|
...state.stock,
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
variants: createVariants(data)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyPriceToAttributeId(
|
function changeApplyPriceToAttributeId(
|
||||||
|
@ -164,8 +189,7 @@ function changeApplyPriceToAttributeId(
|
||||||
id,
|
id,
|
||||||
value: ""
|
value: ""
|
||||||
}));
|
}));
|
||||||
|
const data = {
|
||||||
return {
|
|
||||||
...state,
|
...state,
|
||||||
price: {
|
price: {
|
||||||
...state.price,
|
...state.price,
|
||||||
|
@ -173,38 +197,56 @@ function changeApplyPriceToAttributeId(
|
||||||
values
|
values
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
variants: createVariants(data)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyStockToAttributeId(
|
function changeApplyStockToAttributeId(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
attribute: string
|
attributeId: string
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
return {
|
const attribute = state.attributes.find(
|
||||||
|
attribute => attribute.id === attributeId
|
||||||
|
);
|
||||||
|
const values = attribute.values.map(id => ({
|
||||||
|
id,
|
||||||
|
value: ""
|
||||||
|
}));
|
||||||
|
|
||||||
|
const data = {
|
||||||
...state,
|
...state,
|
||||||
stock: {
|
stock: {
|
||||||
...state.stock,
|
...state.stock,
|
||||||
attribute,
|
attribute: attributeId,
|
||||||
values: state.attributes
|
values
|
||||||
.find(stateAttribute => stateAttribute.id === attribute)
|
|
||||||
.values.map(attributeValue => ({
|
|
||||||
id: attributeValue,
|
|
||||||
value: ""
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
variants: createVariants(data)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyPriceToAllValue(
|
function changeApplyPriceToAllValue(
|
||||||
state: ProductVariantCreateFormData,
|
state: ProductVariantCreateFormData,
|
||||||
value: string
|
value: string
|
||||||
): ProductVariantCreateFormData {
|
): ProductVariantCreateFormData {
|
||||||
return {
|
const data = {
|
||||||
...state,
|
...state,
|
||||||
price: {
|
price: {
|
||||||
...state.price,
|
...state.price,
|
||||||
value
|
value
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...data,
|
||||||
|
variants: createVariants(data)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeApplyStockToAllValue(
|
function changeApplyStockToAllValue(
|
||||||
|
@ -225,6 +267,27 @@ function changeApplyStockToAllValue(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeVariantData(
|
||||||
|
state: ProductVariantCreateFormData,
|
||||||
|
field: VariantField,
|
||||||
|
value: string,
|
||||||
|
variantIndex: number
|
||||||
|
): ProductVariantCreateFormData {
|
||||||
|
const variant = state.variants[variantIndex];
|
||||||
|
if (field === "price") {
|
||||||
|
variant.priceOverride = value;
|
||||||
|
} else if (field === "sku") {
|
||||||
|
variant.sku = value;
|
||||||
|
} else {
|
||||||
|
variant.quantity = parseInt(value, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
variants: updateAtIndex(variant, state.variants, variantIndex)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function reduceProductVariantCreateFormData(
|
function reduceProductVariantCreateFormData(
|
||||||
prevState: ProductVariantCreateFormData,
|
prevState: ProductVariantCreateFormData,
|
||||||
action: ProductVariantCreateReducerAction
|
action: ProductVariantCreateReducerAction
|
||||||
|
@ -252,6 +315,13 @@ function reduceProductVariantCreateFormData(
|
||||||
return changeApplyPriceToAllValue(prevState, action.value);
|
return changeApplyPriceToAllValue(prevState, action.value);
|
||||||
case "changeApplyStockToAllValue":
|
case "changeApplyStockToAllValue":
|
||||||
return changeApplyStockToAllValue(prevState, action.value);
|
return changeApplyStockToAllValue(prevState, action.value);
|
||||||
|
case "changeVariantData":
|
||||||
|
return changeVariantData(
|
||||||
|
prevState,
|
||||||
|
action.field,
|
||||||
|
action.value,
|
||||||
|
action.variantIndex
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
return prevState;
|
return prevState;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue