From ee1ecff1f8108300d0af1f982cae97a5be3ce108 Mon Sep 17 00:00:00 2001 From: dominik-zeglen Date: Tue, 29 Sep 2020 17:04:48 +0200 Subject: [PATCH] Handle attribute errors in product views --- .../ProductVariantAttributes.tsx | 57 ++++++++++++------- .../ProductVariantNavigation.tsx | 8 ++- .../ProductVariantPage/ProductVariantPage.tsx | 4 +- .../products/ProductVariantCreatePage.tsx | 3 + .../stories/products/ProductVariantPage.tsx | 3 + src/utils/errors/product.ts | 2 - 6 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx b/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx index a873f1d20..552e7d686 100644 --- a/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx +++ b/src/products/components/ProductVariantAttributes/ProductVariantAttributes.tsx @@ -8,10 +8,10 @@ import SingleAutocompleteSelectField, { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompleteSelectField"; import Skeleton from "@saleor/components/Skeleton"; +import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; import { ProductVariant_attributes_attribute_values } from "@saleor/fragments/types/ProductVariant"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; import { commonMessages } from "@saleor/intl"; -import { VariantCreate_productVariantCreate_errors } from "@saleor/products/types/VariantCreate"; import { getProductVariantAttributeErrorMessage } from "@saleor/utils/errors/product"; import React from "react"; import { useIntl } from "react-intl"; @@ -27,7 +27,7 @@ export type VariantAttributeInput = FormsetAtomicData< interface ProductVariantAttributesProps { attributes: VariantAttributeInput[]; disabled: boolean; - errors: VariantCreate_productVariantCreate_errors[]; + errors: ProductErrorFragment[]; onChange: FormsetChange; } @@ -84,31 +84,46 @@ 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.attributeId === 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.attributeId === null + ) .map(error => ( {getProductVariantAttributeErrorMessage(error, intl)} diff --git a/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx b/src/products/components/ProductVariantNavigation/ProductVariantNavigation.tsx index ba8fc274a..b091a818e 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..135b4c984 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 { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment"; 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: ProductErrorFragment[]; saveButtonBarState: ConfirmButtonTransitionState; loading?: boolean; placeholderImage?: string; diff --git a/src/storybook/stories/products/ProductVariantCreatePage.tsx b/src/storybook/stories/products/ProductVariantCreatePage.tsx index d16d4ec3d..94edf107f 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={[ { + attributeId: product.productType.variantAttributes[0].id, code: ProductErrorCode.REQUIRED, field: "attributes" }, { + attributeId: null, code: ProductErrorCode.UNIQUE, field: "attributes" }, { + attributeId: 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..a5073e2a1 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={[ { + attributeId: variant.attributes[0].attribute.id, code: ProductErrorCode.REQUIRED, field: "attributes" }, { + attributeId: null, code: ProductErrorCode.UNIQUE, field: "attributes" }, { + attributeId: null, code: ProductErrorCode.ALREADY_EXISTS, field: "sku" } 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: