diff --git a/schema.graphql b/schema.graphql index bb01cb372..ae15c713c 100644 --- a/schema.graphql +++ b/schema.graphql @@ -688,6 +688,7 @@ type BulkProductError { field: String message: String code: ProductErrorCode! + attributes: [ID!] index: Int warehouses: [ID!] } @@ -696,6 +697,7 @@ type BulkStockError { field: String message: String code: ProductErrorCode! + attributes: [ID!] index: Int } @@ -3744,6 +3746,7 @@ type ProductError { field: String message: String code: ProductErrorCode! + attributes: [ID!] } enum ProductErrorCode { @@ -3755,6 +3758,7 @@ enum ProductErrorCode { GRAPHQL_ERROR INVALID NOT_PRODUCTS_IMAGE + NOT_PRODUCTS_VARIANT NOT_FOUND REQUIRED UNIQUE diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx index a7913a898..c8d537d11 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectField.tsx @@ -4,7 +4,7 @@ import TextField from "@material-ui/core/TextField"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { FetchMoreProps } from "@saleor/types"; import classNames from "classnames"; -import Downshift from "downshift"; +import Downshift, { ControllerStateAndHelpers } from "downshift"; import { filter } from "fuzzaldrin"; import React from "react"; @@ -76,20 +76,27 @@ const SingleAutocompleteSelectFieldComponent: React.FC + const handleChange = ( + item: string, + stateAndHelpers: ControllerStateAndHelpers + ) => { onChange({ target: { name, value: item } } as any); + stateAndHelpers.reset({ + inputValue: item + }); + }; return ( {debounceFn => ( displayValue} + itemToString={() => displayValue || ""} onInputValueChange={value => debounceFn(value)} onSelect={handleChange} selectedItem={value} @@ -190,6 +197,7 @@ const SingleAutocompleteSelectField: React.FC { const [query, setQuery] = React.useState(""); + if (fetchChoices) { return ( diff --git a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx index 0b7075d13..0b3999b88 100644 --- a/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx +++ b/src/components/SingleAutocompleteSelectField/SingleAutocompleteSelectFieldContent.tsx @@ -35,7 +35,7 @@ export interface SingleAutocompleteSelectFieldContentProps choices: SingleAutocompleteChoiceType[]; displayCustomValue: boolean; emptyOption: boolean; - getItemProps: (options: GetItemPropsOptions) => void; + getItemProps: (options: GetItemPropsOptions) => any; highlightedIndex: number; inputValue: string; isCustomValueSelected: boolean; @@ -164,9 +164,11 @@ const SingleAutocompleteSelectFieldContent: React.FC { setSlice(sliceSize); - anchor.current.scrollTo({ - top: 0 - }); + if (anchor.current?.scrollTo) { + anchor.current.scrollTo({ + top: 0 + }); + } }, [choices?.length]); React.useEffect(() => { @@ -175,6 +177,10 @@ const SingleAutocompleteSelectFieldContent: React.FC
@@ -206,6 +211,7 @@ const SingleAutocompleteSelectFieldContent: React.FC @@ -222,6 +228,7 @@ const SingleAutocompleteSelectFieldContent: React.FC {suggestion.label} diff --git a/src/fragments/errors.ts b/src/fragments/errors.ts index f4bd5d788..2670f2d6f 100644 --- a/src/fragments/errors.ts +++ b/src/fragments/errors.ts @@ -7,6 +7,14 @@ export const productErrorFragment = gql` } `; +export const productErrorWithAttributesFragment = gql` + ${productErrorFragment} + fragment ProductErrorWithAttributesFragment on ProductError { + ...ProductErrorFragment + attributes + } +`; + export const accountErrorFragment = gql` fragment AccountErrorFragment on AccountError { code diff --git a/src/fragments/types/ProductErrorWithAttributesFragment.ts b/src/fragments/types/ProductErrorWithAttributesFragment.ts new file mode 100644 index 000000000..46c737efa --- /dev/null +++ b/src/fragments/types/ProductErrorWithAttributesFragment.ts @@ -0,0 +1,16 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { ProductErrorCode } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: ProductErrorWithAttributesFragment +// ==================================================== + +export interface ProductErrorWithAttributesFragment { + __typename: "ProductError"; + code: ProductErrorCode; + field: string | null; + attributes: string[] | null; +} diff --git a/src/products/components/ProductAttributes/ProductAttributes.tsx b/src/products/components/ProductAttributes/ProductAttributes.tsx index c6018c2ef..1f50a4daa 100644 --- a/src/products/components/ProductAttributes/ProductAttributes.tsx +++ b/src/products/components/ProductAttributes/ProductAttributes.tsx @@ -13,10 +13,11 @@ import MultiAutocompleteSelectField, { import SingleAutocompleteSelectField, { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; +import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; -import { maybe } from "@saleor/misc"; import { ProductDetails_product_attributes_attribute_values } from "@saleor/products/types/ProductDetails"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; +import { getProductErrorMessage } from "@saleor/utils/errors"; import classNames from "classnames"; import React from "react"; import { FormattedMessage, useIntl } from "react-intl"; @@ -33,6 +34,7 @@ export type ProductAttributeInput = FormsetAtomicData< export interface ProductAttributesProps { attributes: ProductAttributeInput[]; disabled: boolean; + errors: ProductErrorWithAttributesFragment[]; onChange: FormsetChange; onMultiChange: FormsetChange; } @@ -125,6 +127,7 @@ function getSingleChoices( const ProductAttributes: React.FC = ({ attributes, disabled, + errors, onChange, onMultiChange }) => { @@ -169,61 +172,69 @@ const ProductAttributes: React.FC = ({ {expanded && attributes.length > 0 && ( <>
- {attributes.map((attribute, attributeIndex) => ( - - {attributeIndex > 0 &&
} - -
- {attribute.label} -
-
- {attribute.data.inputType === - AttributeInputTypeEnum.DROPDOWN ? ( - + {attributes.map((attribute, attributeIndex) => { + const error = errors.find(err => + err.attributes?.includes(attribute.id) + ); + + return ( + + {attributeIndex > 0 &&
} + +
+ {attribute.label} +
+
+ {attribute.data.inputType === + AttributeInputTypeEnum.DROPDOWN ? ( + value.slug === attribute.value[0] - ).name, - attribute.value[0] - )} - emptyOption - name={`attribute:${attribute.label}`} - label={intl.formatMessage({ - defaultMessage: "Value", - description: "attribute value" - })} - value={attribute.value[0]} - onChange={event => - onChange(attribute.id, event.target.value) - } - allowCustomValues={!attribute.data.isRequired} - /> - ) : ( - - onMultiChange(attribute.id, event.target.value) - } - allowCustomValues={!attribute.data.isRequired} - /> - )} -
-
-
- ))} + )?.name || "" + } + emptyOption={!attribute.data.isRequired} + error={!!error} + helperText={getProductErrorMessage(error, intl)} + name={`attribute:${attribute.label}`} + label={intl.formatMessage({ + defaultMessage: "Value", + description: "attribute value" + })} + value={attribute.value[0]} + onChange={event => + onChange(attribute.id, event.target.value) + } + allowCustomValues={!attribute.data.isRequired} + /> + ) : ( + + onMultiChange(attribute.id, event.target.value) + } + allowCustomValues={!attribute.data.isRequired} + /> + )} +
+
+
+ ); + })} )} diff --git a/src/products/components/ProductCreatePage/ProductCreatePage.tsx b/src/products/components/ProductCreatePage/ProductCreatePage.tsx index 21464797b..88377434d 100644 --- a/src/products/components/ProductCreatePage/ProductCreatePage.tsx +++ b/src/products/components/ProductCreatePage/ProductCreatePage.tsx @@ -10,13 +10,14 @@ import { MultiAutocompleteChoiceType } from "@saleor/components/MultiAutocomplet import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; -import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; +import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment"; import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; import useFormset from "@saleor/hooks/useFormset"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { sectionNames } from "@saleor/intl"; import { + getAttributeInputFromProductType, getChoices, ProductAttributeValueChoices, ProductType @@ -79,7 +80,7 @@ export interface ProductCreatePageSubmitData extends FormData { } interface ProductCreatePageProps { - errors: ProductErrorFragment[]; + errors: ProductErrorWithAttributesFragment[]; collections: SearchCollections_search_edges_node[]; categories: SearchCategories_search_edges_node[]; currency: string; @@ -87,6 +88,7 @@ interface ProductCreatePageProps { fetchMoreCategories: FetchMoreProps; fetchMoreCollections: FetchMoreProps; fetchMoreProductTypes: FetchMoreProps; + initial?: Partial; productTypes?: Array<{ id: string; name: string; @@ -118,6 +120,7 @@ export const ProductCreatePage: React.FC = ({ fetchMoreCollections, fetchMoreProductTypes, header, + initial, productTypes: productTypeChoiceList, saveButtonBarState, warehouses, @@ -130,12 +133,21 @@ export const ProductCreatePage: React.FC = ({ }: ProductCreatePageProps) => { const intl = useIntl(); const localizeDate = useDateLocalize(); + + const initialProductType = productTypeChoiceList?.find( + productType => initial?.productType === productType.id + ); + // Form values const { change: changeAttributeData, data: attributes, set: setAttributeData - } = useFormset([]); + } = useFormset( + initial?.productType + ? getAttributeInputFromProductType(initialProductType) + : [] + ); const { add: addStock, change: changeStockData, @@ -154,6 +166,7 @@ export const ProductCreatePage: React.FC = ({ } = useMetadataChangeTrigger(); const initialData: FormData = { + ...(initial || {}), availableForPurchase: "", basePrice: 0, category: "", @@ -185,14 +198,20 @@ export const ProductCreatePage: React.FC = ({ ProductAttributeValueChoices[] >([]); - const [selectedCategory, setSelectedCategory] = useStateFromProps(""); + const [selectedCategory, setSelectedCategory] = useStateFromProps( + initial?.category || "" + ); const [selectedCollections, setSelectedCollections] = useStateFromProps< MultiAutocompleteChoiceType[] >([]); - const [productType, setProductType] = React.useState(null); - const [selectedTaxType, setSelectedTaxType] = useStateFromProps(null); + const [productType, setProductType] = useStateFromProps( + initialProductType || null + ); + const [selectedTaxType, setSelectedTaxType] = useStateFromProps( + initial?.taxCode || null + ); const categories = getChoices(categoryChoiceList); const collections = getChoices(collectionChoiceList); @@ -274,6 +293,7 @@ export const ProductCreatePage: React.FC = ({ diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.test.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.test.tsx new file mode 100644 index 000000000..96854aaee --- /dev/null +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.test.tsx @@ -0,0 +1,92 @@ +import placeholderImage from "@assets/images/placeholder255x255.png"; +import { collections } from "@saleor/collections/fixtures"; +import { fetchMoreProps, listActionsProps } from "@saleor/fixtures"; +import { product as productFixture } from "@saleor/products/fixtures"; +import { taxTypes } from "@saleor/storybook/stories/taxes/fixtures"; +import { warehouseList } from "@saleor/warehouses/fixtures"; +import Wrapper from "@test/wrapper"; +import { configure, mount } from "enzyme"; +import React from "react"; + +import ProductUpdatePage, { ProductUpdatePageProps } from "./ProductUpdatePage"; + +const product = productFixture(placeholderImage); +import Adapter from "enzyme-adapter-react-16"; +configure({ adapter: new Adapter() }); + +const onSubmit = jest.fn(); + +const props: ProductUpdatePageProps = { + ...listActionsProps, + categories: [product.category], + collections, + defaultWeightUnit: "kg", + disabled: false, + errors: [], + fetchCategories: () => undefined, + fetchCollections: () => undefined, + fetchMoreCategories: fetchMoreProps, + fetchMoreCollections: fetchMoreProps, + header: product.name, + images: product.images, + onBack: () => undefined, + onDelete: () => undefined, + onImageDelete: () => undefined, + onImageUpload: () => undefined, + onSetDefaultVariant: () => undefined, + onSubmit, + onVariantAdd: () => undefined, + onVariantReorder: () => undefined, + onVariantShow: () => undefined, + onVariantsAdd: () => undefined, + onWarehouseConfigure: () => undefined, + placeholderImage, + product, + saveButtonBarState: "default", + taxTypes, + variants: product.variants, + warehouses: warehouseList +}; + +const selectors = { + dropdown: `[data-test="autocomplete-dropdown"]`, + empty: `[data-test-type="empty"]`, + input: `[data-test="product-attribute-value"] input` +}; + +describe("Product details page", () => { + it("can select empty option on attribute", () => { + const component = mount( + + + + ); + expect(component.find(selectors.dropdown).exists()).toBeFalsy(); + + component + .find(selectors.input) + .first() + .simulate("click"); + + expect(component.find(selectors.dropdown).exists()).toBeTruthy(); + + expect(component.find(selectors.empty).exists()); + + component + .find(selectors.empty) + .first() + .simulate("click"); + + expect( + component + .find(selectors.input) + .first() + .prop("value") + ).toEqual(""); + component + .find("form") + .first() + .simulate("submit"); + expect(onSubmit.mock.calls[0][0].attributes[0].value.length).toEqual(0); + }); +}); diff --git a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx index 8160eff20..b79f8b1bf 100644 --- a/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx +++ b/src/products/components/ProductUpdatePage/ProductUpdatePage.tsx @@ -9,7 +9,7 @@ import Metadata from "@saleor/components/Metadata/Metadata"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import SeoForm from "@saleor/components/SeoForm"; -import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; +import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment"; import { TaxTypeFragment } from "@saleor/fragments/types/TaxTypeFragment"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import useDateLocalize from "@saleor/hooks/useDateLocalize"; @@ -58,7 +58,7 @@ import ProductVariants from "../ProductVariants"; export interface ProductUpdatePageProps extends ListActions { defaultWeightUnit: string; - errors: ProductErrorFragment[]; + errors: ProductErrorWithAttributesFragment[]; placeholderImage: string; collections: SearchCollections_search_edges_node[]; categories: SearchCategories_search_edges_node[]; @@ -296,6 +296,7 @@ export const ProductUpdatePage: React.FC = ({ {attributes.length > 0 && ( ; } @@ -84,31 +84,45 @@ const ProductVariantAttributes: React.FC = ({ {attributes === undefined ? ( ) : ( - attributes.map(attribute => ( - onChange(attribute.id, event.target.value)} - value={getAttributeValue(attribute.id, attributes)} - choices={getAttributeValueChoices(attribute.id, attributes)} - allowCustomValues - data-test="variant-attribute-input" - /> - )) + attributes.map(attribute => { + const error = errors.find(err => + err.attributes?.includes(attribute.id) + ); + + return ( + onChange(attribute.id, event.target.value)} + value={getAttributeValue(attribute.id, attributes)} + choices={getAttributeValueChoices(attribute.id, attributes)} + allowCustomValues + data-test="variant-attribute-input" + /> + ); + }) )} {errors.length > 0 && ( <> {errors - .filter(error => error.field === "attributes") + .filter( + error => + error.field === "attributes" && error.attributes === null + ) .map(error => ( {getProductVariantAttributeErrorMessage(error, intl)} diff --git a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx index 8c345e4f2..23a3c1f0a 100644 --- a/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx +++ b/src/products/components/ProductVariantCreatePage/ProductVariantCreatePage.tsx @@ -7,7 +7,7 @@ import Grid from "@saleor/components/Grid"; import Metadata, { MetadataFormData } from "@saleor/components/Metadata"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; -import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; +import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment"; import useFormset, { FormsetChange, FormsetData @@ -48,7 +48,7 @@ export interface ProductVariantCreatePageSubmitData interface ProductVariantCreatePageProps { currencySymbol: string; disabled: boolean; - errors: ProductErrorFragment[]; + errors: ProductErrorWithAttributesFragment[]; header: string; product: ProductVariantCreateData_product; saveButtonBarState: ConfirmButtonTransitionState; diff --git a/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx b/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx index ba8fc274a..6d9214d22 100644 --- a/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx +++ b/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx @@ -28,6 +28,9 @@ const useStyles = makeStyles( colName: { paddingLeft: 0 }, + firstVariant: { + width: 88 + }, link: { cursor: "pointer" }, @@ -126,7 +129,10 @@ const ProductVariantNavigation: React.FC = props className={classNames( classes.colAvatar, classes.tabActive, - classes.noHandle + classes.noHandle, + { + [classes.firstVariant]: variants?.length === 0 + } )} thumbnail={null} colSpan={2} diff --git a/src/products/components/ProductVariantPage/ProductVariantPage.tsx b/src/products/components/ProductVariantPage/ProductVariantPage.tsx index d875acf0d..a91167439 100644 --- a/src/products/components/ProductVariantPage/ProductVariantPage.tsx +++ b/src/products/components/ProductVariantPage/ProductVariantPage.tsx @@ -8,13 +8,13 @@ import { MetadataFormData } from "@saleor/components/Metadata"; import Metadata from "@saleor/components/Metadata/Metadata"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; +import { ProductErrorWithAttributesFragment } from "@saleor/fragments/types/ProductErrorWithAttributesFragment"; import { ProductVariant } from "@saleor/fragments/types/ProductVariant"; import { WarehouseFragment } from "@saleor/fragments/types/WarehouseFragment"; import useFormset, { FormsetChange, FormsetData } from "@saleor/hooks/useFormset"; -import { VariantUpdate_productVariantUpdate_errors } from "@saleor/products/types/VariantUpdate"; import { getAttributeInputFromVariant, getStockInputFromVariant @@ -56,7 +56,7 @@ export interface ProductVariantPageSubmitData interface ProductVariantPageProps { defaultWeightUnit: string; variant?: ProductVariant; - errors: VariantUpdate_productVariantUpdate_errors[]; + errors: ProductErrorWithAttributesFragment[]; saveButtonBarState: ConfirmButtonTransitionState; loading?: boolean; placeholderImage?: string; diff --git a/src/products/fixtures.ts b/src/products/fixtures.ts index 1207f656c..fdd046a1e 100644 --- a/src/products/fixtures.ts +++ b/src/products/fixtures.ts @@ -24,7 +24,7 @@ export const product: ( inputType: AttributeInputTypeEnum.DROPDOWN, name: "Borders", slug: "Borders", - valueRequired: true, + valueRequired: false, values: [ { __typename: "AttributeValue", diff --git a/src/products/mutations.ts b/src/products/mutations.ts index 45e6ea4fa..1b63cf258 100644 --- a/src/products/mutations.ts +++ b/src/products/mutations.ts @@ -3,6 +3,7 @@ import { bulkStockErrorFragment, exportErrorFragment, productErrorFragment, + productErrorWithAttributesFragment, stockErrorFragment } from "@saleor/fragments/errors"; import { @@ -159,12 +160,12 @@ export const useProductVariantSetDefaultMutation = makeMutation< >(productVariantSetDefault); export const productUpdateMutation = gql` - ${productErrorFragment} + ${productErrorWithAttributesFragment} ${productFragmentDetails} mutation ProductUpdate($id: ID!, $input: ProductInput!) { productUpdate(id: $id, input: $input) { errors: productErrors { - ...ProductErrorFragment + ...ProductErrorWithAttributesFragment } product { ...Product @@ -179,7 +180,7 @@ export const useProductUpdateMutation = makeMutation< export const simpleProductUpdateMutation = gql` ${bulkStockErrorFragment} - ${productErrorFragment} + ${productErrorWithAttributesFragment} ${productFragmentDetails} ${stockErrorFragment} ${fragmentVariant} @@ -194,7 +195,7 @@ export const simpleProductUpdateMutation = gql` ) { productUpdate(id: $id, input: $input) { errors: productErrors { - ...ProductErrorFragment + ...ProductErrorWithAttributesFragment } product { ...Product @@ -202,7 +203,7 @@ export const simpleProductUpdateMutation = gql` } productVariantUpdate(id: $productVariantId, input: $productVariantInput) { errors: productErrors { - ...ProductErrorFragment + ...ProductErrorWithAttributesFragment } productVariant { ...ProductVariant @@ -249,12 +250,12 @@ export const useSimpleProductUpdateMutation = makeMutation< >(simpleProductUpdateMutation); export const productCreateMutation = gql` - ${productErrorFragment} + ${productErrorWithAttributesFragment} ${productFragmentDetails} mutation ProductCreate($input: ProductCreateInput!) { productCreate(input: $input) { errors: productErrors { - ...ProductErrorFragment + ...ProductErrorWithAttributesFragment } product { ...Product @@ -288,7 +289,7 @@ export const useVariantDeleteMutation = makeMutation< export const variantUpdateMutation = gql` ${bulkStockErrorFragment} ${fragmentVariant} - ${productErrorFragment} + ${productErrorWithAttributesFragment} mutation VariantUpdate( $addStocks: [StockInput!]! $removeStocks: [ID!]! @@ -313,7 +314,7 @@ export const variantUpdateMutation = gql` } ) { errors: productErrors { - ...ProductErrorFragment + ...ProductErrorWithAttributesFragment } productVariant { ...ProductVariant @@ -359,11 +360,11 @@ export const useVariantUpdateMutation = makeMutation< export const variantCreateMutation = gql` ${fragmentVariant} - ${productErrorFragment} + ${productErrorWithAttributesFragment} mutation VariantCreate($input: ProductVariantCreateInput!) { productVariantCreate(input: $input) { errors: productErrors { - ...ProductErrorFragment + ...ProductErrorWithAttributesFragment } productVariant { ...ProductVariant diff --git a/src/products/types/ProductCreate.ts b/src/products/types/ProductCreate.ts index f31768995..6db6a62df 100644 --- a/src/products/types/ProductCreate.ts +++ b/src/products/types/ProductCreate.ts @@ -12,6 +12,7 @@ export interface ProductCreate_productCreate_errors { __typename: "ProductError"; code: ProductErrorCode; field: string | null; + attributes: string[] | null; } export interface ProductCreate_productCreate_product_attributes_attribute_values { diff --git a/src/products/types/ProductUpdate.ts b/src/products/types/ProductUpdate.ts index 8da5ceab4..db1c2a1d9 100644 --- a/src/products/types/ProductUpdate.ts +++ b/src/products/types/ProductUpdate.ts @@ -12,6 +12,7 @@ export interface ProductUpdate_productUpdate_errors { __typename: "ProductError"; code: ProductErrorCode; field: string | null; + attributes: string[] | null; } export interface ProductUpdate_productUpdate_product_attributes_attribute_values { diff --git a/src/products/types/SimpleProductUpdate.ts b/src/products/types/SimpleProductUpdate.ts index cbc11614e..ae15c1b09 100644 --- a/src/products/types/SimpleProductUpdate.ts +++ b/src/products/types/SimpleProductUpdate.ts @@ -12,6 +12,7 @@ export interface SimpleProductUpdate_productUpdate_errors { __typename: "ProductError"; code: ProductErrorCode; field: string | null; + attributes: string[] | null; } export interface SimpleProductUpdate_productUpdate_product_attributes_attribute_values { @@ -251,6 +252,7 @@ export interface SimpleProductUpdate_productVariantUpdate_errors { __typename: "ProductError"; code: ProductErrorCode; field: string | null; + attributes: string[] | null; } export interface SimpleProductUpdate_productVariantUpdate_productVariant_metadata { diff --git a/src/products/types/VariantCreate.ts b/src/products/types/VariantCreate.ts index 888b46a09..6d1585bc8 100644 --- a/src/products/types/VariantCreate.ts +++ b/src/products/types/VariantCreate.ts @@ -12,6 +12,7 @@ export interface VariantCreate_productVariantCreate_errors { __typename: "ProductError"; code: ProductErrorCode; field: string | null; + attributes: string[] | null; } export interface VariantCreate_productVariantCreate_productVariant_metadata { diff --git a/src/products/types/VariantUpdate.ts b/src/products/types/VariantUpdate.ts index 9ebe6a027..b5a179ec8 100644 --- a/src/products/types/VariantUpdate.ts +++ b/src/products/types/VariantUpdate.ts @@ -12,6 +12,7 @@ export interface VariantUpdate_productVariantUpdate_errors { __typename: "ProductError"; code: ProductErrorCode; field: string | null; + attributes: string[] | null; } export interface VariantUpdate_productVariantUpdate_productVariant_metadata { diff --git a/src/products/utils/handlers.ts b/src/products/utils/handlers.ts index e6ae599b5..39d3099a3 100644 --- a/src/products/utils/handlers.ts +++ b/src/products/utils/handlers.ts @@ -42,7 +42,7 @@ export function createAttributeChangeHandler( ]); triggerChange(); - changeAttributeData(attributeId, [value]); + changeAttributeData(attributeId, value === "" ? [] : [value]); }; } diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 1797af3a8..177b3ebd1 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -8236,6 +8236,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-selected-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id MuiListItem-selected-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AF" role="menuitem" tabindex="-1" > @@ -8245,6 +8247,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AX" role="menuitem" tabindex="-1" > @@ -8254,6 +8258,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AL" role="menuitem" tabindex="-1" > @@ -8263,6 +8269,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="DZ" role="menuitem" tabindex="-1" > @@ -8272,6 +8280,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AS" role="menuitem" tabindex="-1" > @@ -8281,6 +8291,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AD" role="menuitem" tabindex="-1" > @@ -8290,6 +8302,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AO" role="menuitem" tabindex="-1" > @@ -8299,6 +8313,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AI" role="menuitem" tabindex="-1" > @@ -8308,6 +8324,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AQ" role="menuitem" tabindex="-1" > @@ -8317,6 +8335,8 @@ exports[`Storyshots Generics / Select with autocomplete can load more 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AG" role="menuitem" tabindex="-1" > @@ -8388,6 +8408,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-selected-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id MuiListItem-selected-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AF" role="menuitem" tabindex="-1" > @@ -8397,6 +8419,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AX" role="menuitem" tabindex="-1" > @@ -8406,6 +8430,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AL" role="menuitem" tabindex="-1" > @@ -8415,6 +8441,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="DZ" role="menuitem" tabindex="-1" > @@ -8424,6 +8452,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AS" role="menuitem" tabindex="-1" > @@ -8433,6 +8463,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AD" role="menuitem" tabindex="-1" > @@ -8442,6 +8474,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AO" role="menuitem" tabindex="-1" > @@ -8451,6 +8485,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AI" role="menuitem" tabindex="-1" > @@ -8460,6 +8496,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AQ" role="menuitem" tabindex="-1" > @@ -8469,6 +8507,8 @@ exports[`Storyshots Generics / Select with autocomplete default 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AG" role="menuitem" tabindex="-1" > @@ -8880,6 +8920,7 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option-add" + data-test-type="add" role="menuitem" tabindex="-1" > @@ -8907,6 +8948,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-selected-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id MuiListItem-selected-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AF" role="menuitem" tabindex="-1" > @@ -8916,6 +8959,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AX" role="menuitem" tabindex="-1" > @@ -8925,6 +8970,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AL" role="menuitem" tabindex="-1" > @@ -8934,6 +8981,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="DZ" role="menuitem" tabindex="-1" > @@ -8943,6 +8992,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AS" role="menuitem" tabindex="-1" > @@ -8952,6 +9003,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AD" role="menuitem" tabindex="-1" > @@ -8961,6 +9014,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AO" role="menuitem" tabindex="-1" > @@ -8970,6 +9025,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AI" role="menuitem" tabindex="-1" > @@ -8979,6 +9036,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AQ" role="menuitem" tabindex="-1" > @@ -8988,6 +9047,8 @@ exports[`Storyshots Generics / Select with autocomplete with add 1`] = ` aria-disabled="false" class="MuiButtonBase-root-id MuiListItem-root-id MuiMenuItem-root-id SingleAutocompleteSelectFieldContent-menuItem-id MuiMenuItem-gutters-id MuiListItem-gutters-id MuiListItem-button-id" data-test="singleautocomplete-select-option" + data-test-type="option" + data-test-value="AG" role="menuitem" tabindex="-1" > @@ -140044,6 +140105,152 @@ Ctrl + K"
+
+
+ + Attributes + +
+
+
+
+
+
+
+
+ 1 Attributes +
+
+ +
+
+
+
+
+ Author +
+
+
+
+
+ + +

+ Invalid value +

+
+
+
+
+
+
@@ -140252,8 +140459,8 @@ Ctrl + K" class="MuiFormControl-root-id MuiTextField-root-id MuiFormControl-fullWidth-id" > @@ -140268,7 +140475,7 @@ Ctrl + K" autocomplete="off" class="MuiInputBase-input-id MuiOutlinedInput-input-id MuiInputBase-inputAdornedEnd-id MuiOutlinedInput-inputAdornedEnd-id" type="text" - value="" + value="Candy" />
​ @@ -140303,7 +140510,7 @@ Ctrl + K"

Invalid value

@@ -140980,7 +141187,7 @@ exports[`Storyshots Views / Products / Create product variant add first variant class="MuiTableRow-root-id" >
-
- All attributes should have value -
@@ -145969,7 +146176,7 @@ Ctrl + K" class="MuiFormControl-root-id MuiTextField-root-id MuiFormControl-fullWidth-id" >
@@ -173713,7 +173925,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors class="MuiFormControl-root-id MuiTextField-root-id MuiFormControl-fullWidth-id" >
-
- All attributes should have value -
diff --git a/src/storybook/stories/products/ProductCreatePage.tsx b/src/storybook/stories/products/ProductCreatePage.tsx index df02a860f..4a1cd132d 100644 --- a/src/storybook/stories/products/ProductCreatePage.tsx +++ b/src/storybook/stories/products/ProductCreatePage.tsx @@ -68,13 +68,23 @@ storiesOf("Views / Products / Create product", module) ).map(field => ({ - __typename: "ProductError", - code: ProductErrorCode.INVALID, - field - }))} + errors={([ + "attributes", + "name", + "productType", + "category", + "sku" + ] as Array).map( + field => ({ + __typename: "ProductError", + attributes: + field === "attributes" + ? [productTypes[0].productAttributes[0].id] + : null, + code: ProductErrorCode.INVALID, + field + }) + )} header="Add product" collections={product.collections} fetchCategories={() => undefined} @@ -83,6 +93,9 @@ storiesOf("Views / Products / Create product", module) fetchMoreCategories={fetchMoreProps} fetchMoreCollections={fetchMoreProps} fetchMoreProductTypes={fetchMoreProps} + initial={{ + productType: productTypes[0].id + }} productTypes={productTypes} categories={[product.category]} onBack={() => undefined} diff --git a/src/storybook/stories/products/ProductUpdatePage.tsx b/src/storybook/stories/products/ProductUpdatePage.tsx index e596485b1..4346e5f6d 100644 --- a/src/storybook/stories/products/ProductUpdatePage.tsx +++ b/src/storybook/stories/products/ProductUpdatePage.tsx @@ -92,6 +92,7 @@ storiesOf("Views / Products / Product edit", module) {...props} product={{ ...product, + productType: { ...product.productType, hasVariants: false @@ -137,6 +138,7 @@ storiesOf("Views / Products / Product edit", module) ).map(field => ({ - __typename: "ProductError", - code: ProductErrorCode.INVALID, - field - }))} + ] as Array).map( + field => ({ + __typename: "ProductError", + attributes: + field === "attributes" + ? [product.attributes[0].attribute.id] + : null, + code: ProductErrorCode.INVALID, + field + }) + )} /> )); diff --git a/src/storybook/stories/products/ProductVariantCreatePage.tsx b/src/storybook/stories/products/ProductVariantCreatePage.tsx index d16d4ec3d..f98a34328 100644 --- a/src/storybook/stories/products/ProductVariantCreatePage.tsx +++ b/src/storybook/stories/products/ProductVariantCreatePage.tsx @@ -36,14 +36,17 @@ storiesOf("Views / Products / Create product variant", module) disabled={false} errors={[ { + attributes: [product.productType.variantAttributes[0].id], code: ProductErrorCode.REQUIRED, field: "attributes" }, { + attributes: null, code: ProductErrorCode.UNIQUE, field: "attributes" }, { + attributes: null, code: ProductErrorCode.ALREADY_EXISTS, field: "sku" } diff --git a/src/storybook/stories/products/ProductVariantPage.tsx b/src/storybook/stories/products/ProductVariantPage.tsx index b85ca0e57..34e88f346 100644 --- a/src/storybook/stories/products/ProductVariantPage.tsx +++ b/src/storybook/stories/products/ProductVariantPage.tsx @@ -86,14 +86,17 @@ storiesOf("Views / Products / Product variant details", module) saveButtonBarState="default" errors={[ { + attributes: [variant.attributes[0].attribute.id], code: ProductErrorCode.REQUIRED, field: "attributes" }, { + attributes: null, code: ProductErrorCode.UNIQUE, field: "attributes" }, { + attributes: null, code: ProductErrorCode.ALREADY_EXISTS, field: "sku" } diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index f79be52c5..8d75979a3 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -705,6 +705,7 @@ export enum ProductErrorCode { INVALID = "INVALID", NOT_FOUND = "NOT_FOUND", NOT_PRODUCTS_IMAGE = "NOT_PRODUCTS_IMAGE", + NOT_PRODUCTS_VARIANT = "NOT_PRODUCTS_VARIANT", REQUIRED = "REQUIRED", UNIQUE = "UNIQUE", VARIANT_NO_DIGITAL_CONTENT = "VARIANT_NO_DIGITAL_CONTENT", diff --git a/src/utils/errors/product.ts b/src/utils/errors/product.ts index 2c1295765..2b8f83b8f 100644 --- a/src/utils/errors/product.ts +++ b/src/utils/errors/product.ts @@ -83,8 +83,6 @@ export function getProductVariantAttributeErrorMessage( ): string { if (err) { switch (err.code) { - case ProductErrorCode.REQUIRED: - return intl.formatMessage(messages.attributeRequired); case ProductErrorCode.UNIQUE: return intl.formatMessage(messages.variantUnique); default: