diff --git a/src/attributes/fixtures.ts b/src/attributes/fixtures.ts index 7b8d420bc..6c342966a 100644 --- a/src/attributes/fixtures.ts +++ b/src/attributes/fixtures.ts @@ -90,6 +90,7 @@ export const attributes: Array ({ id: attribute.id, + valueRequired: attribute.valueRequired, values: attribute.choices.edges .map(value => ({ slug: value.node.slug, diff --git a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx index 0767b9b75..f9c7a5c6b 100644 --- a/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx +++ b/src/products/components/ProductVariantCreatorPage/ProductVariantCreatorPage.tsx @@ -47,7 +47,9 @@ function canHitNext( switch (step) { case ProductVariantCreatorStep.values: return ( - data.attributes.every(attribute => attribute.values.length > 0) && + data.attributes.every( + attribute => !attribute.valueRequired || attribute.values.length > 0 + ) && (variantsLeft === null || getVariantsNumber(data) <= variantsLeft) ); case ProductVariantCreatorStep.prices: diff --git a/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap b/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap index 1851e3361..e7f274770 100644 --- a/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap +++ b/src/products/components/ProductVariantCreatorPage/__snapshots__/reducer.test.ts.snap @@ -5,6 +5,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -42,6 +43,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -79,6 +81,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", @@ -650,6 +653,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -687,6 +691,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -724,6 +729,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", @@ -1295,6 +1301,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -1332,6 +1339,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -1369,6 +1377,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", @@ -1440,6 +1449,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -1477,6 +1487,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -1514,6 +1525,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", @@ -2036,6 +2048,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -2073,6 +2086,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -2110,6 +2124,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", @@ -2587,6 +2602,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -2624,6 +2640,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -2661,6 +2678,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", @@ -3183,6 +3201,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -3220,6 +3239,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -3257,6 +3277,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", @@ -3696,6 +3717,7 @@ Object { "attributes": Array [ Object { "id": "attr-1", + "valueRequired": false, "values": Array [ Object { "slug": "val-1-1", @@ -3733,6 +3755,7 @@ Object { }, Object { "id": "attr-2", + "valueRequired": false, "values": Array [ Object { "slug": "val-2-2", @@ -3770,6 +3793,7 @@ Object { }, Object { "id": "attr-4", + "valueRequired": false, "values": Array [ Object { "slug": "val-4-1", diff --git a/src/products/components/ProductVariantCreatorPage/createVariants.ts b/src/products/components/ProductVariantCreatorPage/createVariants.ts index a4fbaaa35..d78f15cb5 100644 --- a/src/products/components/ProductVariantCreatorPage/createVariants.ts +++ b/src/products/components/ProductVariantCreatorPage/createVariants.ts @@ -1,4 +1,7 @@ -import { ProductVariantBulkCreateInput } from "@saleor/types/globalTypes"; +import { + BulkAttributeValueInput, + ProductVariantBulkCreateInput +} from "@saleor/types/globalTypes"; import { Attribute, @@ -10,7 +13,7 @@ import { interface CreateVariantAttributeValueInput { attributeId: string; - attributeValueSlug: string; + attributeValueSlug: string | null; attributeBooleanValue: boolean | null; } @@ -81,6 +84,23 @@ function getPriceFromMode( } } +function getAttributeFromAttributeValueInput({ + attributeId, + attributeBooleanValue, + attributeValueSlug +}: CreateVariantAttributeValueInput): BulkAttributeValueInput { + if (attributeBooleanValue === null) { + return { + id: attributeId, + values: attributeValueSlug === null ? [] : [attributeValueSlug] + }; + } + return { + id: attributeId, + boolean: attributeBooleanValue + }; +} + function createVariant( data: ProductVariantCreateFormData, attributes: CreateVariantInput @@ -97,12 +117,7 @@ function createVariant( ); return { - attributes: attributes.map(attribute => ({ - id: attribute.attributeId, - ...(attribute.attributeBooleanValue === null - ? { values: [attribute.attributeValueSlug] } - : { boolean: attribute.attributeBooleanValue }) - })), + attributes: attributes.map(getAttributeFromAttributeValueInput), channelListings: price, sku: "", stocks: stocks.map((quantity, stockIndex) => ({ @@ -116,6 +131,18 @@ function addAttributeToVariant( attribute: Attribute, variant: CreateVariantInput ): CreateVariantInput[] { + if (attribute.values.length === 0) { + return [ + [ + ...variant, + { + attributeId: attribute.id, + attributeValueSlug: null, + attributeBooleanValue: null + } + ] + ]; + } return attribute.values.map(attributeValue => [ ...variant, { diff --git a/src/products/components/ProductVariantCreatorPage/fixtures.ts b/src/products/components/ProductVariantCreatorPage/fixtures.ts index 8ff374428..ea8783a66 100644 --- a/src/products/components/ProductVariantCreatorPage/fixtures.ts +++ b/src/products/components/ProductVariantCreatorPage/fixtures.ts @@ -18,6 +18,7 @@ export const channels: ChannelPriceData[] = [ export const attributes = [ { id: "attr-1", + valueRequired: false, values: Array(9) .fill(0) .map((_, index) => ({ @@ -39,6 +40,7 @@ export const attributes = [ }, { id: "attr-2", + valueRequired: false, values: Array(6) .fill(0) .map((_, index) => ({ @@ -60,6 +62,7 @@ export const attributes = [ }, { id: "attr-3", + valueRequired: false, values: Array(4) .fill(0) .map((_, index) => ({ @@ -81,6 +84,7 @@ export const attributes = [ }, { id: "attr-4", + valueRequired: false, values: Array(11) .fill(0) .map((_, index) => ({ @@ -130,14 +134,17 @@ export const secondStep: ProductVariantCreateFormData = { attributes: [ { id: attributes[0].id, + valueRequired: attributes[0].valueRequired, values: [] }, { id: attributes[1].id, + valueRequired: attributes[1].valueRequired, values: [] }, { id: attributes[3].id, + valueRequired: attributes[3].valueRequired, values: [] } ] @@ -148,14 +155,17 @@ export const thirdStep: ProductVariantCreateFormData = { attributes: [ { id: attributes[0].id, + valueRequired: attributes[0].valueRequired, values: [0, 6].map(index => attributes[0].values[index]) }, { id: attributes[1].id, + valueRequired: attributes[1].valueRequired, values: [1, 3].map(index => attributes[1].values[index]) }, { id: attributes[3].id, + valueRequired: attributes[3].valueRequired, values: [0, 4].map(index => attributes[3].values[index]) } ], diff --git a/src/products/components/ProductVariantCreatorPage/form.ts b/src/products/components/ProductVariantCreatorPage/form.ts index 5afe0eb9c..7216d3f87 100644 --- a/src/products/components/ProductVariantCreatorPage/form.ts +++ b/src/products/components/ProductVariantCreatorPage/form.ts @@ -29,6 +29,7 @@ export interface Stock { } export interface Attribute { id: string; + valueRequired: boolean; values: Array>>; } export interface ProductVariantCreateFormData { @@ -52,6 +53,7 @@ export const createInitialForm = ( return { attributes: attributes.map(attribute => ({ id: attribute.id, + valueRequired: attribute.valueRequired, values: [] })), price: { diff --git a/src/products/components/ProductVariantCreatorPage/reducer.ts b/src/products/components/ProductVariantCreatorPage/reducer.ts index 5e5a33968..09d7d791b 100644 --- a/src/products/components/ProductVariantCreatorPage/reducer.ts +++ b/src/products/components/ProductVariantCreatorPage/reducer.ts @@ -94,6 +94,7 @@ function selectValue( const updatedAttributes = add( { id: attributeId, + valueRequired: attribute.valueRequired, values }, remove(attribute, prevState.attributes, (a, b) => a.id === b.id) @@ -417,9 +418,21 @@ function deleteVariant( state: ProductVariantCreateFormData, variantIndex: number ): ProductVariantCreateFormData { + const variants = removeAtIndex(state.variants, variantIndex); + return { ...state, - variants: removeAtIndex(state.variants, variantIndex) + variants: variants.length + ? variants + : createVariants({ + ...state, + attributes: state.attributes.map(attribute => ({ + id: attribute.id, + valueRequired: attribute.valueRequired, + values: [] + })), + variants + }) }; } diff --git a/src/products/fixtures.ts b/src/products/fixtures.ts index f0ef3260b..540392811 100644 --- a/src/products/fixtures.ts +++ b/src/products/fixtures.ts @@ -472,6 +472,7 @@ export const product: ( id: "isdugfhud", name: "Attachment", inputType: AttributeInputTypeEnum.DROPDOWN, + valueRequired: false, unit: null, choices: { __typename: "AttributeValueCountableConnection", @@ -512,6 +513,7 @@ export const product: ( id: "pta18161", name: "Color", inputType: AttributeInputTypeEnum.DROPDOWN, + valueRequired: false, unit: null, choices: { __typename: "AttributeValueCountableConnection", diff --git a/src/products/types/CreateMultipleVariantsData.ts b/src/products/types/CreateMultipleVariantsData.ts index 5b41efbe2..2e4115de9 100644 --- a/src/products/types/CreateMultipleVariantsData.ts +++ b/src/products/types/CreateMultipleVariantsData.ts @@ -132,6 +132,7 @@ export interface CreateMultipleVariantsData_product_productType_variantAttribute id: string; name: string | null; inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; unit: MeasurementUnitsEnum | null; choices: CreateMultipleVariantsData_product_productType_variantAttributes_choices | null; } diff --git a/src/products/types/ProductDetails.ts b/src/products/types/ProductDetails.ts index 1eaff44a9..220e80de9 100644 --- a/src/products/types/ProductDetails.ts +++ b/src/products/types/ProductDetails.ts @@ -132,6 +132,7 @@ export interface ProductDetails_product_productType_variantAttributes { id: string; name: string | null; inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; unit: MeasurementUnitsEnum | null; choices: ProductDetails_product_productType_variantAttributes_choices | null; } diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index 2909e0309..c0a3da6f1 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -139,6 +139,7 @@ export interface ProductUpdate_productUpdate_product_productType_variantAttribut id: string; name: string | null; inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; unit: MeasurementUnitsEnum | null; choices: ProductUpdate_productUpdate_product_productType_variantAttributes_choices | null; } diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index c0bbe46ef..11108605c 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -139,6 +139,7 @@ export interface SimpleProductUpdate_productUpdate_product_productType_variantAt id: string; name: string | null; inputType: AttributeInputTypeEnum | null; + valueRequired: boolean; unit: MeasurementUnitsEnum | null; choices: SimpleProductUpdate_productUpdate_product_productType_variantAttributes_choices | null; } diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index aae46639c..55227b57c 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -180484,10 +180484,9 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`] class="PageHeader-root-id" >