Display attribute errors in product view

This commit is contained in:
dominik-zeglen 2020-09-29 16:31:17 +02:00
parent bf295e4dce
commit 369fd09853
4 changed files with 81 additions and 60 deletions

View file

@ -10,6 +10,7 @@ import { ProductErrorCode } from "./../../types/globalTypes";
export interface ProductErrorFragment { export interface ProductErrorFragment {
__typename: "ProductError"; __typename: "ProductError";
attributeId: string | null;
code: ProductErrorCode; code: ProductErrorCode;
field: string | null; field: string | null;
} }

View file

@ -13,10 +13,12 @@ import MultiAutocompleteSelectField, {
import SingleAutocompleteSelectField, { import SingleAutocompleteSelectField, {
SingleAutocompleteChoiceType SingleAutocompleteChoiceType
} from "@saleor/components/SingleAutocompleteSelectField"; } from "@saleor/components/SingleAutocompleteSelectField";
import { ProductErrorFragment } from "@saleor/fragments/types/ProductErrorFragment";
import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset"; import { FormsetAtomicData, FormsetChange } from "@saleor/hooks/useFormset";
import { maybe } from "@saleor/misc"; import { maybe } from "@saleor/misc";
import { ProductDetails_product_attributes_attribute_values } from "@saleor/products/types/ProductDetails"; import { ProductDetails_product_attributes_attribute_values } from "@saleor/products/types/ProductDetails";
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes"; import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
import { getProductErrorMessage } from "@saleor/utils/errors";
import classNames from "classnames"; import classNames from "classnames";
import React from "react"; import React from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@ -33,6 +35,7 @@ export type ProductAttributeInput = FormsetAtomicData<
export interface ProductAttributesProps { export interface ProductAttributesProps {
attributes: ProductAttributeInput[]; attributes: ProductAttributeInput[];
disabled: boolean; disabled: boolean;
errors: ProductErrorFragment[];
onChange: FormsetChange; onChange: FormsetChange;
onMultiChange: FormsetChange; onMultiChange: FormsetChange;
} }
@ -125,6 +128,7 @@ function getSingleChoices(
const ProductAttributes: React.FC<ProductAttributesProps> = ({ const ProductAttributes: React.FC<ProductAttributesProps> = ({
attributes, attributes,
disabled, disabled,
errors,
onChange, onChange,
onMultiChange onMultiChange
}) => { }) => {
@ -169,7 +173,12 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
{expanded && attributes.length > 0 && ( {expanded && attributes.length > 0 && (
<> <>
<Hr /> <Hr />
{attributes.map((attribute, attributeIndex) => ( {attributes.map((attribute, attributeIndex) => {
const error = errors.find(
err => err.attributeId === attribute.id
);
return (
<React.Fragment key={attribute.id}> <React.Fragment key={attribute.id}>
{attributeIndex > 0 && <Hr />} {attributeIndex > 0 && <Hr />}
<Grid className={classes.attributeSection} variant="uniform"> <Grid className={classes.attributeSection} variant="uniform">
@ -193,6 +202,8 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
attribute.value[0] attribute.value[0]
)} )}
emptyOption emptyOption
error={!!error}
helperText={getProductErrorMessage(error, intl)}
name={`attribute:${attribute.label}`} name={`attribute:${attribute.label}`}
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "Value", defaultMessage: "Value",
@ -208,6 +219,8 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
<MultiAutocompleteSelectField <MultiAutocompleteSelectField
choices={getMultiChoices(attribute.data.values)} choices={getMultiChoices(attribute.data.values)}
displayValues={getMultiDisplayValue(attribute)} displayValues={getMultiDisplayValue(attribute)}
error={!!error}
helperText={getProductErrorMessage(error, intl)}
label={intl.formatMessage({ label={intl.formatMessage({
defaultMessage: "Values", defaultMessage: "Values",
description: "attribute values" description: "attribute values"
@ -223,7 +236,8 @@ const ProductAttributes: React.FC<ProductAttributesProps> = ({
</div> </div>
</Grid> </Grid>
</React.Fragment> </React.Fragment>
))} );
})}
</> </>
)} )}
</CardContent> </CardContent>

View file

@ -296,6 +296,7 @@ export const ProductUpdatePage: React.FC<ProductUpdatePageProps> = ({
{attributes.length > 0 && ( {attributes.length > 0 && (
<ProductAttributes <ProductAttributes
attributes={attributes} attributes={attributes}
errors={errors}
disabled={disabled} disabled={disabled}
onChange={handleAttributeChange} onChange={handleAttributeChange}
onMultiChange={handleAttributeMultiChange} onMultiChange={handleAttributeMultiChange}

View file

@ -137,6 +137,7 @@ storiesOf("Views / Products / Product edit", module)
<ProductUpdatePage <ProductUpdatePage
{...props} {...props}
errors={([ errors={([
"attributes",
"basePrice", "basePrice",
"category", "category",
"chargeTaxes", "chargeTaxes",
@ -148,10 +149,14 @@ storiesOf("Views / Products / Product edit", module)
"seoTitle", "seoTitle",
"sku", "sku",
"stockQuantity" "stockQuantity"
] as Array<keyof ProductUpdatePageFormData>).map(field => ({ ] as Array<keyof ProductUpdatePageFormData | "attributes">).map(
field => ({
__typename: "ProductError", __typename: "ProductError",
attributeId:
field === "attributes" ? product.attributes[0].attribute.id : null,
code: ProductErrorCode.INVALID, code: ProductErrorCode.INVALID,
field field
}))} })
)}
/> />
)); ));