Rebase fixes
This commit is contained in:
parent
7b77d8b126
commit
381665409f
22 changed files with 271 additions and 188 deletions
|
@ -10,16 +10,17 @@ import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
|
|||
import FormSpacer from "@saleor/components/FormSpacer";
|
||||
import SingleSelectField from "@saleor/components/SingleSelectField";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { UserError } from "@saleor/types";
|
||||
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
|
||||
import { getFieldError } from "@saleor/utils/errors";
|
||||
import { getProductErrorMessage, getFormErrors } from "@saleor/utils/errors";
|
||||
import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment";
|
||||
import { AttributePageFormData } from "../AttributePage";
|
||||
import { getAttributeSlugErrorMessage } from "../../errors";
|
||||
|
||||
export interface AttributeDetailsProps {
|
||||
canChangeType: boolean;
|
||||
data: AttributePageFormData;
|
||||
disabled: boolean;
|
||||
errors: UserError[];
|
||||
errors: ProductErrorFragment[];
|
||||
onChange: (event: React.ChangeEvent<any>) => void;
|
||||
}
|
||||
|
||||
|
@ -48,6 +49,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
|
|||
}
|
||||
];
|
||||
|
||||
const formErrors = getFormErrors(["name", "slug", "inputType"], errors);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle
|
||||
|
@ -56,21 +59,21 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
|
|||
<CardContent>
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!getFieldError(errors, "name")}
|
||||
error={!!formErrors.name}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Default Label",
|
||||
description: "attribute's label"
|
||||
})}
|
||||
name={"name" as keyof AttributePageFormData}
|
||||
fullWidth
|
||||
helperText={getFieldError(errors, "name")?.message}
|
||||
helperText={getProductErrorMessage(formErrors.name, intl)}
|
||||
value={data.name}
|
||||
onChange={onChange}
|
||||
/>
|
||||
<FormSpacer />
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!getFieldError(errors, "slug")}
|
||||
error={!!formErrors.slug}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Attribute Code",
|
||||
description: "attribute's slug short code label"
|
||||
|
@ -79,7 +82,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
|
|||
placeholder={slugify(data.name).toLowerCase()}
|
||||
fullWidth
|
||||
helperText={
|
||||
getFieldError(errors, "slug")?.message ||
|
||||
getAttributeSlugErrorMessage(formErrors.slug, intl) ||
|
||||
intl.formatMessage({
|
||||
defaultMessage:
|
||||
"This is used internally. Make sure you don’t use spaces",
|
||||
|
@ -93,8 +96,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({
|
|||
<SingleSelectField
|
||||
choices={inputTypeChoices}
|
||||
disabled={disabled || !canChangeType}
|
||||
error={!!getFieldError(errors, "inputType")}
|
||||
hint={getFieldError(errors, "inputType")?.message}
|
||||
error={!!formErrors.inputType}
|
||||
hint={getProductErrorMessage(formErrors.inputType, intl)}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Catalog Input type for Store Owner",
|
||||
description: "attribute's editor component"
|
||||
|
|
|
@ -12,8 +12,9 @@ import PageHeader from "@saleor/components/PageHeader";
|
|||
import SaveButtonBar from "@saleor/components/SaveButtonBar";
|
||||
import { sectionNames } from "@saleor/intl";
|
||||
import { maybe } from "@saleor/misc";
|
||||
import { ReorderAction, UserError } from "@saleor/types";
|
||||
import { ReorderAction } from "@saleor/types";
|
||||
import { AttributeInputTypeEnum } from "@saleor/types/globalTypes";
|
||||
import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment";
|
||||
import {
|
||||
AttributeDetailsFragment,
|
||||
AttributeDetailsFragment_values
|
||||
|
@ -25,7 +26,7 @@ import AttributeValues from "../AttributeValues";
|
|||
export interface AttributePageProps {
|
||||
attribute: AttributeDetailsFragment | null;
|
||||
disabled: boolean;
|
||||
errors: UserError[];
|
||||
errors: ProductErrorFragment[];
|
||||
saveButtonBarState: ConfirmButtonTransitionState;
|
||||
values: AttributeDetailsFragment_values[];
|
||||
onBack: () => void;
|
||||
|
|
|
@ -11,14 +11,14 @@ import ControlledCheckbox from "@saleor/components/ControlledCheckbox";
|
|||
import FormSpacer from "@saleor/components/FormSpacer";
|
||||
import Hr from "@saleor/components/Hr";
|
||||
import { commonMessages } from "@saleor/intl";
|
||||
import { UserError } from "@saleor/types";
|
||||
import { getFieldError } from "@saleor/utils/errors";
|
||||
import { getFormErrors, getProductErrorMessage } from "@saleor/utils/errors";
|
||||
import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment";
|
||||
import { AttributePageFormData } from "../AttributePage";
|
||||
|
||||
export interface AttributePropertiesProps {
|
||||
data: AttributePageFormData;
|
||||
disabled: boolean;
|
||||
errors: UserError[];
|
||||
errors: ProductErrorFragment[];
|
||||
onChange: (event: React.ChangeEvent<any>) => void;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,8 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
|
|||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const formErrors = getFormErrors(["storefrontSearchPosition"], errors);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<CardTitle title={intl.formatMessage(commonMessages.properties)} />
|
||||
|
@ -86,11 +88,12 @@ const AttributeProperties: React.FC<AttributePropertiesProps> = ({
|
|||
{data.filterableInStorefront && (
|
||||
<TextField
|
||||
disabled={disabled}
|
||||
error={!!getFieldError(errors, "storefrontSearchPosition")}
|
||||
error={!!formErrors.storefrontSearchPosition}
|
||||
fullWidth
|
||||
helperText={
|
||||
getFieldError(errors, "storefrontSearchPosition")?.message
|
||||
}
|
||||
helperText={getProductErrorMessage(
|
||||
formErrors.storefrontSearchPosition,
|
||||
intl
|
||||
)}
|
||||
name={"storefrontSearchPosition" as keyof AttributePageFormData}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Position in faceted navigation",
|
||||
|
|
|
@ -14,8 +14,9 @@ import Form from "@saleor/components/Form";
|
|||
import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors";
|
||||
import { buttonMessages } from "@saleor/intl";
|
||||
import { maybe } from "@saleor/misc";
|
||||
import { UserError } from "@saleor/types";
|
||||
import { getFieldError } from "@saleor/utils/errors";
|
||||
import { getFormErrors } from "@saleor/utils/errors";
|
||||
import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment";
|
||||
import { getAttributeValueErrorMessage } from "@saleor/attributes/errors";
|
||||
import { AttributeDetails_attribute_values } from "../../types/AttributeDetails";
|
||||
|
||||
export interface AttributeValueEditDialogFormData {
|
||||
|
@ -25,7 +26,7 @@ export interface AttributeValueEditDialogProps {
|
|||
attributeValue: AttributeDetails_attribute_values | null;
|
||||
confirmButtonState: ConfirmButtonTransitionState;
|
||||
disabled: boolean;
|
||||
errors: UserError[];
|
||||
errors: ProductErrorFragment[];
|
||||
open: boolean;
|
||||
onSubmit: (data: AttributeValueEditDialogFormData) => void;
|
||||
onClose: () => void;
|
||||
|
@ -45,6 +46,7 @@ const AttributeValueEditDialog: React.FC<AttributeValueEditDialogProps> = ({
|
|||
name: maybe(() => attributeValue.name, "")
|
||||
};
|
||||
const errors = useModalDialogErrors(apiErrors, open);
|
||||
const formErrors = getFormErrors(["name"], errors);
|
||||
|
||||
return (
|
||||
<Dialog onClose={onClose} open={open} fullWidth maxWidth="sm">
|
||||
|
@ -68,9 +70,12 @@ const AttributeValueEditDialog: React.FC<AttributeValueEditDialogProps> = ({
|
|||
<TextField
|
||||
autoFocus
|
||||
disabled={disabled}
|
||||
error={!!getFieldError(errors, "name")}
|
||||
error={!!formErrors.name}
|
||||
fullWidth
|
||||
helperText={getFieldError(errors, "name")?.message}
|
||||
helperText={getAttributeValueErrorMessage(
|
||||
formErrors.name,
|
||||
intl
|
||||
)}
|
||||
name={"name" as keyof AttributeValueEditDialogFormData}
|
||||
label={intl.formatMessage({
|
||||
defaultMessage: "Name",
|
||||
|
|
38
src/attributes/errors.ts
Normal file
38
src/attributes/errors.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
import { IntlShape, defineMessages } from "react-intl";
|
||||
|
||||
import { ProductErrorCode } from "@saleor/types/globalTypes";
|
||||
import { getProductErrorMessage } from "@saleor/utils/errors";
|
||||
import { ProductErrorFragment } from "./types/ProductErrorFragment";
|
||||
|
||||
const messages = defineMessages({
|
||||
attributeSlugUnique: {
|
||||
defaultMessage: "Attribute with this slug already exists"
|
||||
},
|
||||
attributeValueAlreadyExists: {
|
||||
defaultMessage: "This value already exists within this attribute"
|
||||
}
|
||||
});
|
||||
|
||||
export function getAttributeSlugErrorMessage(
|
||||
err: ProductErrorFragment,
|
||||
intl: IntlShape
|
||||
): string {
|
||||
switch (err?.code) {
|
||||
case ProductErrorCode.UNIQUE:
|
||||
return intl.formatMessage(messages.attributeSlugUnique);
|
||||
default:
|
||||
return getProductErrorMessage(err, intl);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAttributeValueErrorMessage(
|
||||
err: ProductErrorFragment,
|
||||
intl: IntlShape
|
||||
): string {
|
||||
switch (err?.code) {
|
||||
case ProductErrorCode.ALREADY_EXISTS:
|
||||
return intl.formatMessage(messages.attributeValueAlreadyExists);
|
||||
default:
|
||||
return getProductErrorMessage(err, intl);
|
||||
}
|
||||
}
|
|
@ -35,12 +35,19 @@ import {
|
|||
AttributeValueUpdateVariables
|
||||
} from "./types/AttributeValueUpdate";
|
||||
|
||||
export const productErrorFragment = gql`
|
||||
fragment ProductErrorFragment on ProductError {
|
||||
code
|
||||
field
|
||||
}
|
||||
`;
|
||||
|
||||
const attributeBulkDelete = gql`
|
||||
${productErrorFragment}
|
||||
mutation AttributeBulkDelete($ids: [ID!]!) {
|
||||
attributeBulkDelete(ids: $ids) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,11 +58,11 @@ export const AttributeBulkDeleteMutation = TypedMutation<
|
|||
>(attributeBulkDelete);
|
||||
|
||||
const attributeDelete = gql`
|
||||
${productErrorFragment}
|
||||
mutation AttributeDelete($id: ID!) {
|
||||
attributeDelete(id: $id) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,15 +74,15 @@ export const AttributeDeleteMutation = TypedMutation<
|
|||
|
||||
export const attributeUpdateMutation = gql`
|
||||
${attributeDetailsFragment}
|
||||
${productErrorFragment}
|
||||
mutation AttributeUpdate($id: ID!, $input: AttributeUpdateInput!) {
|
||||
attributeUpdate(id: $id, input: $input) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
attribute {
|
||||
...AttributeDetailsFragment
|
||||
}
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -86,15 +93,15 @@ export const AttributeUpdateMutation = TypedMutation<
|
|||
|
||||
const attributeValueDelete = gql`
|
||||
${attributeDetailsFragment}
|
||||
${productErrorFragment}
|
||||
mutation AttributeValueDelete($id: ID!) {
|
||||
attributeValueDelete(id: $id) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
attribute {
|
||||
...AttributeDetailsFragment
|
||||
}
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -105,15 +112,15 @@ export const AttributeValueDeleteMutation = TypedMutation<
|
|||
|
||||
export const attributeValueUpdateMutation = gql`
|
||||
${attributeDetailsFragment}
|
||||
${productErrorFragment}
|
||||
mutation AttributeValueUpdate($id: ID!, $input: AttributeValueCreateInput!) {
|
||||
attributeValueUpdate(id: $id, input: $input) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
attribute {
|
||||
...AttributeDetailsFragment
|
||||
}
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -124,15 +131,15 @@ export const AttributeValueUpdateMutation = TypedMutation<
|
|||
|
||||
export const attributeValueCreateMutation = gql`
|
||||
${attributeDetailsFragment}
|
||||
${productErrorFragment}
|
||||
mutation AttributeValueCreate($id: ID!, $input: AttributeValueCreateInput!) {
|
||||
attributeValueCreate(attribute: $id, input: $input) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
attribute {
|
||||
...AttributeDetailsFragment
|
||||
}
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -143,15 +150,15 @@ export const AttributeValueCreateMutation = TypedMutation<
|
|||
|
||||
export const attributeCreateMutation = gql`
|
||||
${attributeDetailsFragment}
|
||||
${productErrorFragment}
|
||||
mutation AttributeCreate($input: AttributeCreateInput!) {
|
||||
attributeCreate(input: $input) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
attribute {
|
||||
...AttributeDetailsFragment
|
||||
}
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
@ -161,18 +168,18 @@ export const AttributeCreateMutation = TypedMutation<
|
|||
>(attributeCreateMutation);
|
||||
|
||||
const attributeValueReorderMutation = gql`
|
||||
${productErrorFragment}
|
||||
mutation AttributeValueReorder($id: ID!, $move: ReorderInput!) {
|
||||
attributeReorderValues(attributeId: $id, moves: [$move]) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
attribute {
|
||||
id
|
||||
values {
|
||||
id
|
||||
}
|
||||
}
|
||||
errors: productErrors {
|
||||
...ProductErrorFragment
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeBulkDelete
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeBulkDelete_attributeBulkDelete_errors {
|
||||
__typename: "Error";
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeBulkDelete_attributeBulkDelete {
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AttributeCreateInput, AttributeInputTypeEnum, AttributeValueType } from "./../../types/globalTypes";
|
||||
import { AttributeCreateInput, AttributeInputTypeEnum, AttributeValueType, ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeCreate
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeCreate_attributeCreate_errors {
|
||||
__typename: "Error";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeCreate_attributeCreate_attribute_values {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
|
@ -37,10 +31,16 @@ export interface AttributeCreate_attributeCreate_attribute {
|
|||
values: (AttributeCreate_attributeCreate_attribute_values | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AttributeCreate_attributeCreate_errors {
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeCreate_attributeCreate {
|
||||
__typename: "AttributeCreate";
|
||||
errors: AttributeCreate_attributeCreate_errors[];
|
||||
attribute: AttributeCreate_attributeCreate_attribute | null;
|
||||
errors: AttributeCreate_attributeCreate_errors[];
|
||||
}
|
||||
|
||||
export interface AttributeCreate {
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeDelete
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeDelete_attributeDelete_errors {
|
||||
__typename: "Error";
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeDelete_attributeDelete {
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AttributeUpdateInput, AttributeInputTypeEnum, AttributeValueType } from "./../../types/globalTypes";
|
||||
import { AttributeUpdateInput, AttributeInputTypeEnum, AttributeValueType, ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeUpdate
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeUpdate_attributeUpdate_errors {
|
||||
__typename: "Error";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeUpdate_attributeUpdate_attribute_values {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
|
@ -37,10 +31,16 @@ export interface AttributeUpdate_attributeUpdate_attribute {
|
|||
values: (AttributeUpdate_attributeUpdate_attribute_values | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AttributeUpdate_attributeUpdate_errors {
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeUpdate_attributeUpdate {
|
||||
__typename: "AttributeUpdate";
|
||||
errors: AttributeUpdate_attributeUpdate_errors[];
|
||||
attribute: AttributeUpdate_attributeUpdate_attribute | null;
|
||||
errors: AttributeUpdate_attributeUpdate_errors[];
|
||||
}
|
||||
|
||||
export interface AttributeUpdate {
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AttributeValueCreateInput, AttributeInputTypeEnum, AttributeValueType } from "./../../types/globalTypes";
|
||||
import { AttributeValueCreateInput, AttributeInputTypeEnum, AttributeValueType, ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeValueCreate
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeValueCreate_attributeValueCreate_errors {
|
||||
__typename: "Error";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueCreate_attributeValueCreate_attribute_values {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
|
@ -37,10 +31,16 @@ export interface AttributeValueCreate_attributeValueCreate_attribute {
|
|||
values: (AttributeValueCreate_attributeValueCreate_attribute_values | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueCreate_attributeValueCreate_errors {
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueCreate_attributeValueCreate {
|
||||
__typename: "AttributeValueCreate";
|
||||
errors: AttributeValueCreate_attributeValueCreate_errors[];
|
||||
attribute: AttributeValueCreate_attributeValueCreate_attribute | null;
|
||||
errors: AttributeValueCreate_attributeValueCreate_errors[];
|
||||
}
|
||||
|
||||
export interface AttributeValueCreate {
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AttributeInputTypeEnum, AttributeValueType } from "./../../types/globalTypes";
|
||||
import { AttributeInputTypeEnum, AttributeValueType, ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeValueDelete
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeValueDelete_attributeValueDelete_errors {
|
||||
__typename: "Error";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueDelete_attributeValueDelete_attribute_values {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
|
@ -37,10 +31,16 @@ export interface AttributeValueDelete_attributeValueDelete_attribute {
|
|||
values: (AttributeValueDelete_attributeValueDelete_attribute_values | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueDelete_attributeValueDelete_errors {
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueDelete_attributeValueDelete {
|
||||
__typename: "AttributeValueDelete";
|
||||
errors: AttributeValueDelete_attributeValueDelete_errors[];
|
||||
attribute: AttributeValueDelete_attributeValueDelete_attribute | null;
|
||||
errors: AttributeValueDelete_attributeValueDelete_errors[];
|
||||
}
|
||||
|
||||
export interface AttributeValueDelete {
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { ReorderInput } from "./../../types/globalTypes";
|
||||
import { ReorderInput, ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeValueReorder
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeValueReorder_attributeReorderValues_errors {
|
||||
__typename: "Error";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueReorder_attributeReorderValues_attribute_values {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
|
@ -25,10 +19,16 @@ export interface AttributeValueReorder_attributeReorderValues_attribute {
|
|||
values: (AttributeValueReorder_attributeReorderValues_attribute_values | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueReorder_attributeReorderValues_errors {
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueReorder_attributeReorderValues {
|
||||
__typename: "AttributeReorderValues";
|
||||
errors: AttributeValueReorder_attributeReorderValues_errors[];
|
||||
attribute: AttributeValueReorder_attributeReorderValues_attribute | null;
|
||||
errors: AttributeValueReorder_attributeReorderValues_errors[];
|
||||
}
|
||||
|
||||
export interface AttributeValueReorder {
|
||||
|
|
|
@ -2,18 +2,12 @@
|
|||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { AttributeValueCreateInput, AttributeInputTypeEnum, AttributeValueType } from "./../../types/globalTypes";
|
||||
import { AttributeValueCreateInput, AttributeInputTypeEnum, AttributeValueType, ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL mutation operation: AttributeValueUpdate
|
||||
// ====================================================
|
||||
|
||||
export interface AttributeValueUpdate_attributeValueUpdate_errors {
|
||||
__typename: "Error";
|
||||
field: string | null;
|
||||
message: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueUpdate_attributeValueUpdate_attribute_values {
|
||||
__typename: "AttributeValue";
|
||||
id: string;
|
||||
|
@ -37,10 +31,16 @@ export interface AttributeValueUpdate_attributeValueUpdate_attribute {
|
|||
values: (AttributeValueUpdate_attributeValueUpdate_attribute_values | null)[] | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueUpdate_attributeValueUpdate_errors {
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
}
|
||||
|
||||
export interface AttributeValueUpdate_attributeValueUpdate {
|
||||
__typename: "AttributeValueUpdate";
|
||||
errors: AttributeValueUpdate_attributeValueUpdate_errors[];
|
||||
attribute: AttributeValueUpdate_attributeValueUpdate_attribute | null;
|
||||
errors: AttributeValueUpdate_attributeValueUpdate_errors[];
|
||||
}
|
||||
|
||||
export interface AttributeValueUpdate {
|
||||
|
|
15
src/attributes/types/ProductErrorFragment.ts
Normal file
15
src/attributes/types/ProductErrorFragment.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// This file was automatically generated and should not be edited.
|
||||
|
||||
import { ProductErrorCode } from "./../../types/globalTypes";
|
||||
|
||||
// ====================================================
|
||||
// GraphQL fragment: ProductErrorFragment
|
||||
// ====================================================
|
||||
|
||||
export interface ProductErrorFragment {
|
||||
__typename: "ProductError";
|
||||
code: ProductErrorCode;
|
||||
field: string | null;
|
||||
}
|
|
@ -5,7 +5,7 @@ import slugify from "slugify";
|
|||
import useNavigator from "@saleor/hooks/useNavigator";
|
||||
import useNotifier from "@saleor/hooks/useNotifier";
|
||||
import { maybe } from "@saleor/misc";
|
||||
import { ReorderEvent, UserError } from "@saleor/types";
|
||||
import { ReorderEvent } from "@saleor/types";
|
||||
import {
|
||||
add,
|
||||
isSelected,
|
||||
|
@ -14,6 +14,8 @@ import {
|
|||
updateAtIndex
|
||||
} from "@saleor/utils/lists";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import { ProductErrorFragment } from "@saleor/attributes/types/ProductErrorFragment";
|
||||
import { ProductErrorCode } from "@saleor/types/globalTypes";
|
||||
import AttributePage from "../../components/AttributePage";
|
||||
import AttributeValueDeleteDialog from "../../components/AttributeValueDeleteDialog";
|
||||
import AttributeValueEditDialog, {
|
||||
|
@ -33,6 +35,12 @@ interface AttributeDetailsProps {
|
|||
params: AttributeAddUrlQueryParams;
|
||||
}
|
||||
|
||||
const attributeValueAlreadyExistsError: ProductErrorFragment = {
|
||||
__typename: "ProductError",
|
||||
code: ProductErrorCode.ALREADY_EXISTS,
|
||||
field: "name"
|
||||
};
|
||||
|
||||
function areValuesEqual(
|
||||
a: AttributeValueEditDialogFormData,
|
||||
b: AttributeValueEditDialogFormData
|
||||
|
@ -48,7 +56,9 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
const [values, setValues] = React.useState<
|
||||
AttributeValueEditDialogFormData[]
|
||||
>([]);
|
||||
const [valueErrors, setValueErrors] = React.useState<UserError[]>([]);
|
||||
const [valueErrors, setValueErrors] = React.useState<ProductErrorFragment[]>(
|
||||
[]
|
||||
);
|
||||
|
||||
const id = params.id ? parseInt(params.id, 0) : undefined;
|
||||
|
||||
|
@ -57,6 +67,8 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
AttributeAddUrlQueryParams
|
||||
>(navigate, attributeAddUrl, params);
|
||||
|
||||
React.useEffect(() => setValueErrors([]), [params.action]);
|
||||
|
||||
const handleValueDelete = () => {
|
||||
setValues(remove(values[params.id], values, areValuesEqual));
|
||||
closeModal();
|
||||
|
@ -73,20 +85,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
};
|
||||
const handleValueUpdate = (input: AttributeValueEditDialogFormData) => {
|
||||
if (isSelected(input, values, areValuesEqual)) {
|
||||
setValueErrors([
|
||||
{
|
||||
field: "name",
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "A value named {name} already exists",
|
||||
description: "attribute value edit error"
|
||||
},
|
||||
{
|
||||
name: input.name
|
||||
}
|
||||
)
|
||||
}
|
||||
]);
|
||||
setValueErrors([attributeValueAlreadyExistsError]);
|
||||
} else {
|
||||
setValues(updateAtIndex(input, values, id));
|
||||
closeModal();
|
||||
|
@ -94,20 +93,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
};
|
||||
const handleValueCreate = (input: AttributeValueEditDialogFormData) => {
|
||||
if (isSelected(input, values, areValuesEqual)) {
|
||||
setValueErrors([
|
||||
{
|
||||
field: "name",
|
||||
message: intl.formatMessage(
|
||||
{
|
||||
defaultMessage: "A value named {name} already exists",
|
||||
description: "attribute value edit error"
|
||||
},
|
||||
{
|
||||
name: input.name
|
||||
}
|
||||
)
|
||||
}
|
||||
]);
|
||||
setValueErrors([attributeValueAlreadyExistsError]);
|
||||
} else {
|
||||
setValues(add(input, values));
|
||||
closeModal();
|
||||
|
@ -123,10 +109,7 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ params }) => {
|
|||
<AttributePage
|
||||
attribute={null}
|
||||
disabled={false}
|
||||
errors={maybe(
|
||||
() => attributeCreateOpts.data.attributeCreate.errors,
|
||||
[]
|
||||
)}
|
||||
errors={attributeCreateOpts.data?.attributeCreate.errors || []}
|
||||
onBack={() => navigate(attributeListUrl())}
|
||||
onDelete={undefined}
|
||||
onSubmit={input =>
|
||||
|
|
|
@ -8,6 +8,7 @@ import { maybe } from "@saleor/misc";
|
|||
import { ReorderEvent } from "@saleor/types";
|
||||
import { move } from "@saleor/utils/lists";
|
||||
import createDialogActionHandlers from "@saleor/utils/handlers/dialogActionHandlers";
|
||||
import { getProductErrorMessage } from "@saleor/utils/errors";
|
||||
import AttributeDeleteDialog from "../../components/AttributeDeleteDialog";
|
||||
import AttributePage from "../../components/AttributePage";
|
||||
import AttributeValueDeleteDialog from "../../components/AttributeValueDeleteDialog";
|
||||
|
@ -95,7 +96,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
const handleValueReorderMutation = (data: AttributeValueReorder) => {
|
||||
if (data.attributeReorderValues.errors.length !== 0) {
|
||||
notify({
|
||||
text: data.attributeReorderValues.errors[0].message
|
||||
text: getProductErrorMessage(
|
||||
data.attributeReorderValues.errors[0],
|
||||
intl
|
||||
)
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -155,12 +159,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
<AttributePage
|
||||
attribute={maybe(() => data.attribute)}
|
||||
disabled={loading}
|
||||
errors={maybe(
|
||||
() =>
|
||||
attributeUpdateOpts.data
|
||||
.attributeUpdate.errors,
|
||||
[]
|
||||
)}
|
||||
errors={
|
||||
attributeUpdateOpts.data
|
||||
?.attributeUpdate.errors || []
|
||||
}
|
||||
onBack={() =>
|
||||
navigate(attributeListUrl())
|
||||
}
|
||||
|
@ -253,12 +255,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
attributeValueCreateOpts.status
|
||||
}
|
||||
disabled={loading}
|
||||
errors={maybe(
|
||||
() =>
|
||||
attributeValueCreateOpts.data
|
||||
.attributeValueCreate.errors,
|
||||
[]
|
||||
)}
|
||||
errors={
|
||||
attributeValueCreateOpts.data
|
||||
?.attributeValueCreate.errors || []
|
||||
}
|
||||
open={params.action === "add-value"}
|
||||
onClose={closeModal}
|
||||
onSubmit={input =>
|
||||
|
@ -280,12 +280,10 @@ const AttributeDetails: React.FC<AttributeDetailsProps> = ({ id, params }) => {
|
|||
attributeValueUpdateOpts.status
|
||||
}
|
||||
disabled={loading}
|
||||
errors={maybe(
|
||||
() =>
|
||||
attributeValueUpdateOpts.data
|
||||
.attributeValueUpdate.errors,
|
||||
[]
|
||||
)}
|
||||
errors={
|
||||
attributeValueUpdateOpts.data
|
||||
?.attributeValueUpdate.errors || []
|
||||
}
|
||||
open={params.action === "edit-value"}
|
||||
onClose={closeModal}
|
||||
onSubmit={input =>
|
||||
|
|
|
@ -95927,11 +95927,6 @@ Ctrl + K"
|
|||
</legend>
|
||||
</fieldset>
|
||||
</div>
|
||||
<p
|
||||
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-error-id MuiFormHelperText-filled-id"
|
||||
>
|
||||
Invalid value
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -96164,7 +96159,7 @@ Ctrl + K"
|
|||
class="MuiFormControl-root-id MuiTextField-root-id MuiFormControl-fullWidth-id"
|
||||
>
|
||||
<label
|
||||
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id MuiFormLabel-error-id MuiInputLabel-error-id"
|
||||
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id"
|
||||
data-shrink="false"
|
||||
>
|
||||
Collections
|
||||
|
@ -96172,11 +96167,11 @@ Ctrl + K"
|
|||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-expanded="false"
|
||||
class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-error-id MuiOutlinedInput-error-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id MuiInputBase-adornedEnd-id MuiOutlinedInput-adornedEnd-id"
|
||||
class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id MuiInputBase-adornedEnd-id MuiOutlinedInput-adornedEnd-id"
|
||||
role="combobox"
|
||||
>
|
||||
<input
|
||||
aria-invalid="true"
|
||||
aria-invalid="false"
|
||||
autocomplete="off"
|
||||
class="MuiInputBase-input-id MuiOutlinedInput-input-id MuiInputBase-inputAdornedEnd-id MuiOutlinedInput-inputAdornedEnd-id"
|
||||
type="text"
|
||||
|
@ -96215,9 +96210,9 @@ Ctrl + K"
|
|||
</fieldset>
|
||||
</div>
|
||||
<p
|
||||
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-error-id"
|
||||
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id"
|
||||
>
|
||||
Invalid value
|
||||
*Optional. Adding product to collection helps users find it.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -99501,6 +99496,11 @@ Ctrl + K"
|
|||
</legend>
|
||||
</fieldset>
|
||||
</div>
|
||||
<p
|
||||
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-error-id MuiFormHelperText-filled-id"
|
||||
>
|
||||
Invalid value
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -99867,7 +99867,7 @@ Ctrl + K"
|
|||
class="MuiFormControl-root-id MuiTextField-root-id MuiFormControl-fullWidth-id"
|
||||
>
|
||||
<label
|
||||
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id"
|
||||
class="MuiFormLabel-root-id MuiInputLabel-root-id MuiInputLabel-formControl-id MuiInputLabel-animated-id MuiInputLabel-outlined-id MuiFormLabel-error-id MuiInputLabel-error-id"
|
||||
data-shrink="false"
|
||||
>
|
||||
Collections
|
||||
|
@ -99875,11 +99875,11 @@ Ctrl + K"
|
|||
<div
|
||||
aria-autocomplete="list"
|
||||
aria-expanded="false"
|
||||
class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id MuiInputBase-adornedEnd-id MuiOutlinedInput-adornedEnd-id"
|
||||
class="MuiInputBase-root-id MuiOutlinedInput-root-id MuiInputBase-error-id MuiOutlinedInput-error-id MuiInputBase-fullWidth-id MuiInputBase-formControl-id MuiInputBase-adornedEnd-id MuiOutlinedInput-adornedEnd-id"
|
||||
role="combobox"
|
||||
>
|
||||
<input
|
||||
aria-invalid="false"
|
||||
aria-invalid="true"
|
||||
autocomplete="off"
|
||||
class="MuiInputBase-input-id MuiOutlinedInput-input-id MuiInputBase-inputAdornedEnd-id MuiOutlinedInput-inputAdornedEnd-id"
|
||||
type="text"
|
||||
|
@ -99918,9 +99918,9 @@ Ctrl + K"
|
|||
</fieldset>
|
||||
</div>
|
||||
<p
|
||||
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id"
|
||||
class="MuiFormHelperText-root-id MuiFormHelperText-contained-id MuiFormHelperText-error-id"
|
||||
>
|
||||
*Optional. Adding product to collection helps users find it.
|
||||
Invalid value
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,8 +2,10 @@ import { storiesOf } from "@storybook/react";
|
|||
import React from "react";
|
||||
|
||||
import { attribute } from "@saleor/attributes/fixtures";
|
||||
import { formError } from "@saleor/storybook/misc";
|
||||
import { AttributeValueType } from "@saleor/types/globalTypes";
|
||||
import {
|
||||
AttributeValueType,
|
||||
ProductErrorCode
|
||||
} from "@saleor/types/globalTypes";
|
||||
import AttributeValueEditDialog, {
|
||||
AttributeValueEditDialogProps
|
||||
} from "../../../attributes/components/AttributeValueEditDialog";
|
||||
|
@ -26,5 +28,14 @@ storiesOf("Attributes / Attribute value edit", module)
|
|||
.addDecorator(Decorator)
|
||||
.add("default", () => <AttributeValueEditDialog {...props} />)
|
||||
.add("form errors", () => (
|
||||
<AttributeValueEditDialog {...props} errors={[formError("name")]} />
|
||||
<AttributeValueEditDialog
|
||||
{...props}
|
||||
errors={[
|
||||
{
|
||||
__typename: "ProductError",
|
||||
code: ProductErrorCode.INVALID,
|
||||
field: "name"
|
||||
}
|
||||
]}
|
||||
/>
|
||||
));
|
||||
|
|
|
@ -7,7 +7,7 @@ import { MultiAutocompleteChoiceType } from "./components/MultiAutocompleteSelec
|
|||
|
||||
export interface UserError {
|
||||
field: string | null;
|
||||
message: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface DialogProps {
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
import { UserError } from "@saleor/types";
|
||||
|
||||
export function getFieldError(errors: UserError[], field: string): UserError {
|
||||
return errors.find(err => err.field === field);
|
||||
}
|
||||
|
||||
export function getErrors(errors: UserError[]): string[] {
|
||||
return errors
|
||||
.filter(err => ["", null].includes(err.field))
|
||||
.map(err => err.message);
|
||||
}
|
26
src/utils/errors/index.ts
Normal file
26
src/utils/errors/index.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { UserError } from "@saleor/types";
|
||||
|
||||
export function getFieldError<T extends UserError>(
|
||||
errors: T[],
|
||||
field: string
|
||||
): T {
|
||||
return errors.find(err => err.field === field);
|
||||
}
|
||||
|
||||
export function getErrors(errors: UserError[]): string[] {
|
||||
return errors
|
||||
.filter(err => ["", null].includes(err.field))
|
||||
.map(err => err.message);
|
||||
}
|
||||
|
||||
export function getFormErrors<TField extends string, TError extends UserError>(
|
||||
fields: TField[],
|
||||
errors: TError[]
|
||||
): Record<TField, TError> {
|
||||
return fields.reduce((errs, field) => {
|
||||
errs[field] = getFieldError(errors, field);
|
||||
return errs;
|
||||
}, ({} as unknown) as Record<TField, TError>);
|
||||
}
|
||||
|
||||
export { default as getProductErrorMessage } from "./product";
|
Loading…
Reference in a new issue