diff --git a/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx b/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx index d3c783264..61599da77 100644 --- a/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx +++ b/src/shipping/components/ShippingZoneCreatePage/ShippingZoneCreatePage.tsx @@ -11,8 +11,8 @@ import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; import { sectionNames } from "@saleor/intl"; +import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; import { CountryFragment } from "../../../taxes/types/CountryFragment"; -import { UserError } from "../../../types"; import ShippingZoneCountriesAssignDialog from "../ShippingZoneCountriesAssignDialog"; import ShippingZoneInfo from "../ShippingZoneInfo"; @@ -25,7 +25,7 @@ export interface FormData { export interface ShippingZoneCreatePageProps { countries: CountryFragment[]; disabled: boolean; - errors: UserError[]; + errors: ShippingErrorFragment[]; saveButtonBarState: ConfirmButtonTransitionState; onBack: () => void; onSubmit: (data: FormData) => void; diff --git a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx index 1ef691f76..aa30576a2 100644 --- a/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx +++ b/src/shipping/components/ShippingZoneDetailsPage/ShippingZoneDetailsPage.tsx @@ -10,8 +10,8 @@ import Form from "@saleor/components/Form"; import Grid from "@saleor/components/Grid"; import PageHeader from "@saleor/components/PageHeader"; import SaveButtonBar from "@saleor/components/SaveButtonBar"; -import { maybe } from "../../../misc"; -import { UserError } from "../../../types"; +import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; +import { maybe, getStringOrPlaceholder } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import { ShippingZoneDetailsFragment } from "../../types/ShippingZoneDetailsFragment"; import ShippingZoneInfo from "../ShippingZoneInfo"; @@ -23,7 +23,7 @@ export interface FormData { export interface ShippingZoneDetailsPageProps { disabled: boolean; - errors: UserError[]; + errors: ShippingErrorFragment[]; saveButtonBarState: ConfirmButtonTransitionState; shippingZone: ShippingZoneDetailsFragment; onBack: () => void; @@ -66,13 +66,13 @@ const ShippingZoneDetailsPage: React.FC = ({ - shippingZone.name)} /> +
shippingZone.countries)} + countries={shippingZone?.countries} disabled={disabled} emptyText={maybe( () => diff --git a/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx b/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx index 128e2b51c..1cfa2b3d9 100644 --- a/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx +++ b/src/shipping/components/ShippingZoneInfo/ShippingZoneInfo.tsx @@ -6,13 +6,14 @@ import { useIntl } from "react-intl"; import CardTitle from "@saleor/components/CardTitle"; import { commonMessages } from "@saleor/intl"; -import { getFieldError } from "@saleor/utils/errors"; -import { UserError } from "../../../types"; +import { getFormErrors } from "@saleor/utils/errors"; +import getShippingErrorMessage from "@saleor/utils/errors/shipping"; +import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; import { FormData } from "../ShippingZoneDetailsPage"; export interface ShippingZoneInfoProps { data: FormData; - errors: UserError[]; + errors: ShippingErrorFragment[]; onChange: (event: React.ChangeEvent) => void; } @@ -23,6 +24,8 @@ const ShippingZoneInfo: React.FC = ({ }) => { const intl = useIntl(); + const formErrors = getFormErrors(["name"], errors); + return ( = ({ /> = props => { const { action, - confirmButtonState, defaultCurrency, disabled, - errors, + errors: apiErrors, onClose, onSubmit, open, @@ -79,6 +84,17 @@ const ShippingZoneRateDialog: React.FC = props => { const classes = useStyles(props); const intl = useIntl(); + const errors = useModalDialogErrors(apiErrors, open); + + const formFields = [ + "name", + "minimumOrderPrice", + "minimumOrderWeight", + "maximumOrderPrice", + "maximumOrderWeight", + "price" + ]; + const formErrors = getFormErrors(formFields, errors); const initialForm: FormData = action === "create" @@ -108,6 +124,11 @@ const ShippingZoneRateDialog: React.FC = props => { initialForm.noLimits = !initialForm.maxValue && !initialForm.minValue; } + const getErrorMessage = + variant === ShippingMethodTypeEnum.PRICE + ? getShippingPriceRateErrorMessage + : getShippingWeightRateErrorMessage; + return (
@@ -139,10 +160,10 @@ const ShippingZoneRateDialog: React.FC = props => { = props => { = props => { = props => {
(deleteShippingZone); const bulkDeleteShippingZone = gql` + ${shippingErrorFragment} mutation BulkDeleteShippingZone($ids: [ID]!) { shippingZoneBulkDelete(ids: $ids) { - errors { - field - message + errors: shippingErrors { + ...ShippingErrorFragment } } } @@ -90,11 +97,11 @@ export const TypedUpdateDefaultWeightUnit = TypedMutation< const createShippingZone = gql` ${countryFragment} + ${shippingErrorFragment} mutation CreateShippingZone($input: ShippingZoneInput!) { shippingZoneCreate(input: $input) { - errors { - field - message + errors: shippingErrors { + ...ShippingErrorFragment } shippingZone { countries { @@ -114,11 +121,11 @@ export const TypedCreateShippingZone = TypedMutation< const updateShippingZone = gql` ${countryFragment} + ${shippingErrorFragment} mutation UpdateShippingZone($id: ID!, $input: ShippingZoneInput!) { shippingZoneUpdate(id: $id, input: $input) { - errors { - field - message + errors: shippingErrors { + ...ShippingErrorFragment } shippingZone { countries { @@ -137,12 +144,12 @@ export const TypedUpdateShippingZone = TypedMutation< >(updateShippingZone); const updateShippingRate = gql` + ${shippingErrorFragment} ${shippingMethodFragment} mutation UpdateShippingRate($id: ID!, $input: ShippingPriceInput!) { shippingPriceUpdate(id: $id, input: $input) { - errors { - field - message + errors: shippingErrors { + ...ShippingErrorFragment } shippingMethod { ...ShippingMethodFragment @@ -156,12 +163,12 @@ export const TypedUpdateShippingRate = TypedMutation< >(updateShippingRate); const createShippingRate = gql` + ${shippingErrorFragment} ${shippingZoneDetailsFragment} mutation CreateShippingRate($input: ShippingPriceInput!) { shippingPriceCreate(input: $input) { - errors { - field - message + errors: shippingErrors { + ...ShippingErrorFragment } shippingZone { ...ShippingZoneDetailsFragment @@ -175,12 +182,12 @@ export const TypedCreateShippingRate = TypedMutation< >(createShippingRate); const deleteShippingRate = gql` + ${shippingErrorFragment} ${shippingZoneDetailsFragment} mutation DeleteShippingRate($id: ID!) { shippingPriceDelete(id: $id) { - errors { - field - message + errors: shippingErrors { + ...ShippingErrorFragment } shippingZone { ...ShippingZoneDetailsFragment @@ -194,11 +201,11 @@ export const TypedDeleteShippingRate = TypedMutation< >(deleteShippingRate); const bulkDeleteShippingRate = gql` + ${shippingErrorFragment} mutation BulkDeleteShippingRate($ids: [ID]!) { shippingPriceBulkDelete(ids: $ids) { - errors { - field - message + errors: shippingErrors { + ...ShippingErrorFragment } } } diff --git a/src/shipping/types/BulkDeleteShippingRate.ts b/src/shipping/types/BulkDeleteShippingRate.ts index b76824672..9432974c2 100644 --- a/src/shipping/types/BulkDeleteShippingRate.ts +++ b/src/shipping/types/BulkDeleteShippingRate.ts @@ -2,14 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. +import { ShippingErrorCode } from "./../../types/globalTypes"; + // ==================================================== // GraphQL mutation operation: BulkDeleteShippingRate // ==================================================== export interface BulkDeleteShippingRate_shippingPriceBulkDelete_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface BulkDeleteShippingRate_shippingPriceBulkDelete { diff --git a/src/shipping/types/BulkDeleteShippingZone.ts b/src/shipping/types/BulkDeleteShippingZone.ts index 43525a117..b3d66fe7f 100644 --- a/src/shipping/types/BulkDeleteShippingZone.ts +++ b/src/shipping/types/BulkDeleteShippingZone.ts @@ -2,14 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. +import { ShippingErrorCode } from "./../../types/globalTypes"; + // ==================================================== // GraphQL mutation operation: BulkDeleteShippingZone // ==================================================== export interface BulkDeleteShippingZone_shippingZoneBulkDelete_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface BulkDeleteShippingZone_shippingZoneBulkDelete { diff --git a/src/shipping/types/CreateShippingRate.ts b/src/shipping/types/CreateShippingRate.ts index 5cb29a52a..c0d3a1e4a 100644 --- a/src/shipping/types/CreateShippingRate.ts +++ b/src/shipping/types/CreateShippingRate.ts @@ -2,16 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { ShippingPriceInput, ShippingMethodTypeEnum } from "./../../types/globalTypes"; +import { ShippingPriceInput, ShippingErrorCode, ShippingMethodTypeEnum } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: CreateShippingRate // ==================================================== export interface CreateShippingRate_shippingPriceCreate_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface CreateShippingRate_shippingPriceCreate_shippingZone_countries { diff --git a/src/shipping/types/CreateShippingZone.ts b/src/shipping/types/CreateShippingZone.ts index a1ad4b836..d45a7b2a9 100644 --- a/src/shipping/types/CreateShippingZone.ts +++ b/src/shipping/types/CreateShippingZone.ts @@ -2,16 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { ShippingZoneInput } from "./../../types/globalTypes"; +import { ShippingZoneInput, ShippingErrorCode } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: CreateShippingZone // ==================================================== export interface CreateShippingZone_shippingZoneCreate_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface CreateShippingZone_shippingZoneCreate_shippingZone_countries { diff --git a/src/shipping/types/DeleteShippingRate.ts b/src/shipping/types/DeleteShippingRate.ts index 226130ed7..b4ffa0352 100644 --- a/src/shipping/types/DeleteShippingRate.ts +++ b/src/shipping/types/DeleteShippingRate.ts @@ -2,16 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { ShippingMethodTypeEnum } from "./../../types/globalTypes"; +import { ShippingErrorCode, ShippingMethodTypeEnum } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: DeleteShippingRate // ==================================================== export interface DeleteShippingRate_shippingPriceDelete_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface DeleteShippingRate_shippingPriceDelete_shippingZone_countries { diff --git a/src/shipping/types/DeleteShippingZone.ts b/src/shipping/types/DeleteShippingZone.ts index 8e7f97edf..6885f77cc 100644 --- a/src/shipping/types/DeleteShippingZone.ts +++ b/src/shipping/types/DeleteShippingZone.ts @@ -2,14 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. +import { ShippingErrorCode } from "./../../types/globalTypes"; + // ==================================================== // GraphQL mutation operation: DeleteShippingZone // ==================================================== export interface DeleteShippingZone_shippingZoneDelete_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface DeleteShippingZone_shippingZoneDelete { diff --git a/src/shipping/types/ShippingErrorFragment.ts b/src/shipping/types/ShippingErrorFragment.ts new file mode 100644 index 000000000..88e8c9daf --- /dev/null +++ b/src/shipping/types/ShippingErrorFragment.ts @@ -0,0 +1,15 @@ +/* tslint:disable */ +/* eslint-disable */ +// This file was automatically generated and should not be edited. + +import { ShippingErrorCode } from "./../../types/globalTypes"; + +// ==================================================== +// GraphQL fragment: ShippingErrorFragment +// ==================================================== + +export interface ShippingErrorFragment { + __typename: "ShippingError"; + code: ShippingErrorCode; + field: string | null; +} diff --git a/src/shipping/types/UpdateShippingRate.ts b/src/shipping/types/UpdateShippingRate.ts index 4d58de639..88aa63cb4 100644 --- a/src/shipping/types/UpdateShippingRate.ts +++ b/src/shipping/types/UpdateShippingRate.ts @@ -2,16 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { ShippingPriceInput, ShippingMethodTypeEnum } from "./../../types/globalTypes"; +import { ShippingPriceInput, ShippingErrorCode, ShippingMethodTypeEnum } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: UpdateShippingRate // ==================================================== export interface UpdateShippingRate_shippingPriceUpdate_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface UpdateShippingRate_shippingPriceUpdate_shippingMethod_minimumOrderPrice { diff --git a/src/shipping/types/UpdateShippingZone.ts b/src/shipping/types/UpdateShippingZone.ts index 09eeb730f..c8883e137 100644 --- a/src/shipping/types/UpdateShippingZone.ts +++ b/src/shipping/types/UpdateShippingZone.ts @@ -2,16 +2,16 @@ /* eslint-disable */ // This file was automatically generated and should not be edited. -import { ShippingZoneInput } from "./../../types/globalTypes"; +import { ShippingZoneInput, ShippingErrorCode } from "./../../types/globalTypes"; // ==================================================== // GraphQL mutation operation: UpdateShippingZone // ==================================================== export interface UpdateShippingZone_shippingZoneUpdate_errors { - __typename: "Error"; + __typename: "ShippingError"; + code: ShippingErrorCode; field: string | null; - message: string | null; } export interface UpdateShippingZone_shippingZoneUpdate_shippingZone_countries { diff --git a/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx b/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx index f0e1183fd..36f346b39 100644 --- a/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx +++ b/src/shipping/views/ShippingZoneDetails/ShippingZoneDetailsDialogs.tsx @@ -6,7 +6,7 @@ import ActionDialog from "@saleor/components/ActionDialog"; import { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import useNavigator from "@saleor/hooks/useNavigator"; import useShop from "@saleor/hooks/useShop"; -import { maybe } from "../../../misc"; +import { getStringOrPlaceholder } from "../../../misc"; import { ShippingMethodTypeEnum } from "../../../types/globalTypes"; import ShippingZoneCountriesAssignDialog from "../../components/ShippingZoneCountriesAssignDialog"; import ShippingZoneRateDialog from "../../components/ShippingZoneRateDialog"; @@ -45,8 +45,8 @@ const ShippingZoneDetailsDialogs: React.FC = ({ const closeModal = () => navigate(shippingZoneUrl(id), true); - const rate = maybe(() => - shippingZone.shippingMethods.find(rate => rate.id === params.id) + const rate = shippingZone?.shippingMethods?.find( + rate => rate.id === params.id ); return ( @@ -54,12 +54,11 @@ const ShippingZoneDetailsDialogs: React.FC = ({ shop.defaultCurrency)} + defaultCurrency={shop?.defaultCurrency} disabled={ops.shippingRateUpdate.opts.loading} - errors={maybe( - () => ops.shippingRateUpdate.opts.data.shippingPriceUpdate.errors, - [] - )} + errors={ + ops.shippingRateUpdate.opts.data?.shippingPriceUpdate.errors || [] + } onClose={closeModal} onSubmit={formData => ops.shippingRateUpdate.mutate({ @@ -74,13 +73,13 @@ const ShippingZoneDetailsDialogs: React.FC = ({ name: formData.name, price: formData.isFree ? 0 : parseFloat(formData.price), shippingZone: id, - type: maybe(() => rate.type) + type: rate?.type } }) } open={params.action === "edit-rate"} rate={rate} - variant={maybe(() => rate.type)} + variant={rate?.type} /> = ({ description="delete shipping method" id="shippingZoneDetailsDialogsDeleteShippingMethod" values={{ - name: maybe(() => rate.name, "...") + name: getStringOrPlaceholder(rate?.name) }} /> @@ -111,12 +110,11 @@ const ShippingZoneDetailsDialogs: React.FC = ({ shop.defaultCurrency)} + defaultCurrency={shop?.defaultCurrency} disabled={ops.shippingRateCreate.opts.loading} - errors={maybe( - () => ops.shippingRateCreate.opts.data.shippingPriceCreate.errors, - [] - )} + errors={ + ops.shippingRateCreate.opts.data?.shippingPriceCreate.errors || [] + } onClose={closeModal} onSubmit={formData => ops.shippingRateCreate.mutate({ @@ -178,19 +176,18 @@ const ShippingZoneDetailsDialogs: React.FC = ({ description="delete shipping zone" id="shippingZoneDetailsDialogsDeleteShippingZone" values={{ - name: {maybe(() => shippingZone.name, "...")} + name: ( + {getStringOrPlaceholder(shippingZone?.name)} + ) }} /> shop.countries, [])} - initial={maybe( - () => shippingZone.countries.map(country => country.code), - [] - )} - isDefault={maybe(() => shippingZone.default, false)} + countries={shop?.countries} + initial={shippingZone?.countries.map(country => country.code) || []} + isDefault={!!shippingZone?.default} onClose={closeModal} onConfirm={formData => ops.shippingZoneUpdate.mutate({ @@ -230,12 +227,10 @@ const ShippingZoneDetailsDialogs: React.FC = ({ values={{ countryName: ( - {maybe( - () => - shippingZone.countries.find( - country => country.code === params.id - ).country, - "..." + {getStringOrPlaceholder( + shippingZone?.countries.find( + country => country.code === params.id + )?.country )} ) diff --git a/src/shipping/views/ShippingZoneDetails/index.tsx b/src/shipping/views/ShippingZoneDetails/index.tsx index 9d4d81e80..bf03ddef6 100644 --- a/src/shipping/views/ShippingZoneDetails/index.tsx +++ b/src/shipping/views/ShippingZoneDetails/index.tsx @@ -183,7 +183,7 @@ const ShippingZoneDetails: React.FC = ({ id={id} ops={ops} params={params} - shippingZone={maybe(() => data.shippingZone)} + shippingZone={data?.shippingZone} unassignCountryTransitionState={ ops.shippingZoneUpdate.opts.status } diff --git a/src/types/globalTypes.ts b/src/types/globalTypes.ts index 5fe8d94e5..9c0a39481 100644 --- a/src/types/globalTypes.ts +++ b/src/types/globalTypes.ts @@ -623,6 +623,16 @@ export enum ServiceAccountSortField { NAME = "NAME", } +export enum ShippingErrorCode { + ALREADY_EXISTS = "ALREADY_EXISTS", + GRAPHQL_ERROR = "GRAPHQL_ERROR", + INVALID = "INVALID", + MAX_LESS_THAN_MIN = "MAX_LESS_THAN_MIN", + NOT_FOUND = "NOT_FOUND", + REQUIRED = "REQUIRED", + UNIQUE = "UNIQUE", +} + export enum ShippingMethodTypeEnum { PRICE = "PRICE", WEIGHT = "WEIGHT", diff --git a/src/utils/errors/shipping.ts b/src/utils/errors/shipping.ts new file mode 100644 index 000000000..3e02cef60 --- /dev/null +++ b/src/utils/errors/shipping.ts @@ -0,0 +1,37 @@ +import { IntlShape, defineMessages } from "react-intl"; + +import { ShippingErrorFragment } from "@saleor/shipping/types/ShippingErrorFragment"; +import { ShippingErrorCode } from "@saleor/types/globalTypes"; +import { commonMessages } from "@saleor/intl"; +import commonErrorMessages from "./common"; + +const messages = defineMessages({ + alreadyExists: { + defaultMessage: "Default shipping zone already exists", + description: "error message" + } +}); + +function getShippingErrorMessage( + err: Omit | undefined, + intl: IntlShape +): string { + if (err) { + switch (err.code) { + case ShippingErrorCode.ALREADY_EXISTS: + return intl.formatMessage(messages.alreadyExists); + case ShippingErrorCode.GRAPHQL_ERROR: + return intl.formatMessage(commonErrorMessages.graphqlError); + case ShippingErrorCode.REQUIRED: + return intl.formatMessage(commonMessages.requiredField); + case ShippingErrorCode.INVALID: + return intl.formatMessage(commonErrorMessages.invalid); + default: + return intl.formatMessage(commonErrorMessages.unknownError); + } + } + + return undefined; +} + +export default getShippingErrorMessage;