Make it work
This commit is contained in:
parent
4d9171faa4
commit
fcfdd432b4
7 changed files with 488 additions and 158 deletions
|
@ -112,6 +112,7 @@ const ProductVariantCreatePrices: React.FC<
|
|||
})}
|
||||
onChange={() => onApplyPriceOrStockChange(false, "price")}
|
||||
/>
|
||||
</RadioGroup>
|
||||
{!data.price.all && (
|
||||
<>
|
||||
<FormSpacer />
|
||||
|
@ -139,8 +140,7 @@ const ProductVariantCreatePrices: React.FC<
|
|||
</div>
|
||||
</Grid>
|
||||
{priceAttributeValues &&
|
||||
priceAttributeValues.map(
|
||||
(attributeValue, attributeValueIndex) => (
|
||||
priceAttributeValues.map((attributeValue, attributeValueIndex) => (
|
||||
<>
|
||||
<FormSpacer />
|
||||
<Grid variant="inverted">
|
||||
|
@ -167,11 +167,9 @@ const ProductVariantCreatePrices: React.FC<
|
|||
</div>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</RadioGroup>
|
||||
<FormSpacer />
|
||||
<Typography color="textSecondary" variant="headline">
|
||||
<FormattedMessage
|
||||
|
@ -212,6 +210,7 @@ const ProductVariantCreatePrices: React.FC<
|
|||
})}
|
||||
onChange={() => onApplyPriceOrStockChange(false, "stock")}
|
||||
/>
|
||||
</RadioGroup>
|
||||
{!data.stock.all && (
|
||||
<>
|
||||
<FormSpacer />
|
||||
|
@ -239,8 +238,7 @@ const ProductVariantCreatePrices: React.FC<
|
|||
</div>
|
||||
</Grid>
|
||||
{stockAttributeValues &&
|
||||
stockAttributeValues.map(
|
||||
(attributeValue, attributeValueIndex) => (
|
||||
stockAttributeValues.map((attributeValue, attributeValueIndex) => (
|
||||
<>
|
||||
<FormSpacer />
|
||||
<Grid variant="inverted">
|
||||
|
@ -267,11 +265,9 @@ const ProductVariantCreatePrices: React.FC<
|
|||
</div>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</RadioGroup>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -125,7 +125,9 @@ const ProductVariantCreateSummary: React.FC<
|
|||
<TableBody>
|
||||
{data.variants.map(variant => (
|
||||
<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)}>
|
||||
{getVariantName(variant, attributes).map(
|
||||
|
|
|
@ -2,7 +2,7 @@ import {
|
|||
createVariantFlatMatrixDimension,
|
||||
createVariants
|
||||
} from "./createVariants";
|
||||
import { thirdStep } from "./fixtures";
|
||||
import { attributes, thirdStep } from "./fixtures";
|
||||
import { ProductVariantCreateFormData } from "./form";
|
||||
|
||||
describe("Creates variant matrix", () => {
|
||||
|
@ -35,9 +35,186 @@ describe("Creates variant matrix", () => {
|
|||
};
|
||||
|
||||
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);
|
||||
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 { Attribute, ProductVariantCreateFormData } from "./form";
|
||||
import {
|
||||
AllOrAttribute,
|
||||
Attribute,
|
||||
ProductVariantCreateFormData
|
||||
} from "./form";
|
||||
|
||||
interface CreateVariantAttributeValueInput {
|
||||
attributeId: string;
|
||||
attributeValueId: string;
|
||||
}
|
||||
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(
|
||||
data: ProductVariantCreateFormData,
|
||||
attributes: CreateVariantInput
|
||||
): ProductVariantCreateInput {
|
||||
const priceOverride = data.price.all
|
||||
? data.price.value
|
||||
: data.price.values.find(
|
||||
value =>
|
||||
attributes.find(
|
||||
attribute => attribute.attributeId === data.price.attribute
|
||||
).attributeValueId === value.id
|
||||
).value;
|
||||
: getAttributeValuePriceOrStock(attributes, data.price);
|
||||
const quantity = parseInt(
|
||||
data.stock.all
|
||||
? data.stock.value
|
||||
: data.stock.values.find(
|
||||
value =>
|
||||
attributes.find(
|
||||
attribute => attribute.attributeId === data.stock.attribute
|
||||
).attributeValueId === value.id
|
||||
).value,
|
||||
: getAttributeValuePriceOrStock(attributes, data.stock),
|
||||
10
|
||||
);
|
||||
|
||||
|
@ -81,6 +91,12 @@ export function createVariantFlatMatrixDimension(
|
|||
export function createVariants(
|
||||
data: ProductVariantCreateFormData
|
||||
): ProductVariantCreateInput[] {
|
||||
if (
|
||||
(!data.price.all && !data.price.attribute) ||
|
||||
(!data.stock.all && !data.stock.attribute)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
const variants = createVariantFlatMatrixDimension([[]], data.attributes).map(
|
||||
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 = [
|
||||
{
|
||||
|
@ -44,6 +49,7 @@ export const secondStep: ProductVariantCreateFormData = {
|
|||
}
|
||||
]
|
||||
};
|
||||
|
||||
export const thirdStep: ProductVariantCreateFormData = {
|
||||
...secondStep,
|
||||
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 reducer from "./reducer";
|
||||
import reducer, { VariantField } from "./reducer";
|
||||
|
||||
function execActions<TState, TAction>(
|
||||
initialState: TState,
|
||||
|
@ -108,6 +108,7 @@ describe("Reducer is able to", () => {
|
|||
});
|
||||
|
||||
it("select price to each attribute value", () => {
|
||||
const attribute = thirdStep.attributes[0];
|
||||
const value = 45.99;
|
||||
const state = execActions(thirdStep, reducer, [
|
||||
{
|
||||
|
@ -115,18 +116,18 @@ describe("Reducer is able to", () => {
|
|||
type: "applyPriceToAll"
|
||||
},
|
||||
{
|
||||
attributeId: attributes[0].id,
|
||||
attributeId: attribute.id,
|
||||
type: "changeApplyPriceToAttributeId"
|
||||
},
|
||||
{
|
||||
type: "changeAttributeValuePrice",
|
||||
value: value.toString(),
|
||||
valueId: attributes[0].values[0]
|
||||
valueId: attribute.values[0]
|
||||
},
|
||||
{
|
||||
type: "changeAttributeValuePrice",
|
||||
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", () => {
|
||||
const attribute = thirdStep.attributes[0];
|
||||
const value = 13;
|
||||
const state = execActions(thirdStep, reducer, [
|
||||
{
|
||||
|
@ -146,18 +148,18 @@ describe("Reducer is able to", () => {
|
|||
type: "applyStockToAll"
|
||||
},
|
||||
{
|
||||
attributeId: attributes[0].id,
|
||||
attributeId: attribute.id,
|
||||
type: "changeApplyStockToAttributeId"
|
||||
},
|
||||
{
|
||||
type: "changeAttributeValueStock",
|
||||
value: value.toString(),
|
||||
valueId: attributes[0].values[0]
|
||||
valueId: attribute.values[0]
|
||||
},
|
||||
{
|
||||
type: "changeAttributeValueStock",
|
||||
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();
|
||||
});
|
||||
|
||||
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"
|
||||
| "changeAttributeValuePrice"
|
||||
| "changeAttributeValueStock"
|
||||
| "changeVariantData"
|
||||
| "selectAttribute"
|
||||
| "selectValue";
|
||||
|
||||
export type VariantField = "stock" | "price" | "sku";
|
||||
export interface ProductVariantCreateReducerAction {
|
||||
all?: boolean;
|
||||
attributeId?: string;
|
||||
field?: VariantField;
|
||||
type: ProductVariantCreateReducerActionType;
|
||||
value?: string;
|
||||
valueId?: string;
|
||||
variantIndex?: number;
|
||||
}
|
||||
|
||||
function selectAttribute(
|
||||
|
@ -69,26 +74,36 @@ function applyPriceToAll(
|
|||
state: ProductVariantCreateFormData,
|
||||
value: boolean
|
||||
): ProductVariantCreateFormData {
|
||||
return {
|
||||
const data = {
|
||||
...state,
|
||||
price: {
|
||||
...state.price,
|
||||
all: value
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...data,
|
||||
variants: createVariants(data)
|
||||
};
|
||||
}
|
||||
|
||||
function applyStockToAll(
|
||||
state: ProductVariantCreateFormData,
|
||||
value: boolean
|
||||
): ProductVariantCreateFormData {
|
||||
return {
|
||||
const data = {
|
||||
...state,
|
||||
stock: {
|
||||
...state.stock,
|
||||
all: value
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...data,
|
||||
variants: createVariants(data)
|
||||
};
|
||||
}
|
||||
|
||||
function changeAttributeValuePrice(
|
||||
|
@ -113,13 +128,18 @@ function changeAttributeValuePrice(
|
|||
index
|
||||
);
|
||||
|
||||
return {
|
||||
const data = {
|
||||
...state,
|
||||
price: {
|
||||
...state.price,
|
||||
values
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...data,
|
||||
variants: createVariants(data)
|
||||
};
|
||||
}
|
||||
|
||||
function changeAttributeValueStock(
|
||||
|
@ -144,13 +164,18 @@ function changeAttributeValueStock(
|
|||
index
|
||||
);
|
||||
|
||||
return {
|
||||
const data = {
|
||||
...state,
|
||||
stock: {
|
||||
...state.stock,
|
||||
values
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...data,
|
||||
variants: createVariants(data)
|
||||
};
|
||||
}
|
||||
|
||||
function changeApplyPriceToAttributeId(
|
||||
|
@ -164,8 +189,7 @@ function changeApplyPriceToAttributeId(
|
|||
id,
|
||||
value: ""
|
||||
}));
|
||||
|
||||
return {
|
||||
const data = {
|
||||
...state,
|
||||
price: {
|
||||
...state.price,
|
||||
|
@ -173,38 +197,56 @@ function changeApplyPriceToAttributeId(
|
|||
values
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...data,
|
||||
variants: createVariants(data)
|
||||
};
|
||||
}
|
||||
|
||||
function changeApplyStockToAttributeId(
|
||||
state: ProductVariantCreateFormData,
|
||||
attribute: string
|
||||
attributeId: string
|
||||
): ProductVariantCreateFormData {
|
||||
return {
|
||||
const attribute = state.attributes.find(
|
||||
attribute => attribute.id === attributeId
|
||||
);
|
||||
const values = attribute.values.map(id => ({
|
||||
id,
|
||||
value: ""
|
||||
}));
|
||||
|
||||
const data = {
|
||||
...state,
|
||||
stock: {
|
||||
...state.stock,
|
||||
attribute,
|
||||
values: state.attributes
|
||||
.find(stateAttribute => stateAttribute.id === attribute)
|
||||
.values.map(attributeValue => ({
|
||||
id: attributeValue,
|
||||
value: ""
|
||||
}))
|
||||
attribute: attributeId,
|
||||
values
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...data,
|
||||
variants: createVariants(data)
|
||||
};
|
||||
}
|
||||
|
||||
function changeApplyPriceToAllValue(
|
||||
state: ProductVariantCreateFormData,
|
||||
value: string
|
||||
): ProductVariantCreateFormData {
|
||||
return {
|
||||
const data = {
|
||||
...state,
|
||||
price: {
|
||||
...state.price,
|
||||
value
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
...data,
|
||||
variants: createVariants(data)
|
||||
};
|
||||
}
|
||||
|
||||
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(
|
||||
prevState: ProductVariantCreateFormData,
|
||||
action: ProductVariantCreateReducerAction
|
||||
|
@ -252,6 +315,13 @@ function reduceProductVariantCreateFormData(
|
|||
return changeApplyPriceToAllValue(prevState, action.value);
|
||||
case "changeApplyStockToAllValue":
|
||||
return changeApplyStockToAllValue(prevState, action.value);
|
||||
case "changeVariantData":
|
||||
return changeVariantData(
|
||||
prevState,
|
||||
action.field,
|
||||
action.value,
|
||||
action.variantIndex
|
||||
);
|
||||
default:
|
||||
return prevState;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue