diff --git a/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx b/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx index b77002e71..3b7a77679 100644 --- a/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx +++ b/src/customers/components/CustomerAddressDialog/CustomerAddressDialog.tsx @@ -4,7 +4,6 @@ import DialogActions from "@material-ui/core/DialogActions"; import DialogContent from "@material-ui/core/DialogContent"; import DialogTitle from "@material-ui/core/DialogTitle"; import { createStyles, withStyles, WithStyles } from "@material-ui/core/styles"; - import React from "react"; import { FormattedMessage } from "react-intl"; @@ -13,10 +12,13 @@ import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Form from "@saleor/components/Form"; +import useAddressValidation from "@saleor/hooks/useAddressValidation"; +import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { buttonMessages } from "@saleor/intl"; import { maybe } from "@saleor/misc"; import { UserError } from "@saleor/types"; +import { AddressInput } from "@saleor/types/globalTypes"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; import { AddressTypeInput } from "../../types"; import { CustomerAddresses_user_addresses } from "../../types/CustomerAddresses"; @@ -32,7 +34,7 @@ export interface CustomerAddressDialogProps { open: boolean; variant: "create" | "edit"; onClose: () => void; - onConfirm: (data: AddressTypeInput) => void; + onConfirm: (data: AddressInput) => void; } const styles = createStyles({ @@ -56,6 +58,15 @@ const CustomerAddressDialog = withStyles(styles, {})( const [countryDisplayName, setCountryDisplayName] = useStateFromProps( maybe(() => address.country.country, "") ); + const { + errors: validationErrors, + submit: handleSubmit + } = useAddressValidation(onConfirm); + const dialogErrors = useModalDialogErrors( + [...errors, ...validationErrors], + open + ); + const initialForm: AddressTypeInput = { city: maybe(() => address.city, ""), cityArea: maybe(() => address.cityArea, ""), @@ -87,8 +98,12 @@ const CustomerAddressDialog = withStyles(styles, {})( fullWidth maxWidth="sm" > -
- {({ change, data, errors }) => { + + {({ change, data, errors: formErrors }) => { const handleCountrySelect = createSingleAutocompleteSelectHandler( change, setCountryDisplayName, @@ -115,7 +130,7 @@ const CustomerAddressDialog = withStyles(styles, {})( countries={countryChoices} data={data} countryDisplayValue={countryDisplayName} - errors={errors} + errors={formErrors} onChange={change} onCountryChange={handleCountrySelect} /> diff --git a/src/customers/views/CustomerAddresses.tsx b/src/customers/views/CustomerAddresses.tsx index d8b483c92..827e17beb 100644 --- a/src/customers/views/CustomerAddresses.tsx +++ b/src/customers/views/CustomerAddresses.tsx @@ -176,7 +176,7 @@ const CustomerAddresses: React.FC = ({ createCustomerAddress({ variables: { id, - input: transformFormToAddress(input) + input } }) } @@ -202,7 +202,7 @@ const CustomerAddresses: React.FC = ({ updateCustomerAddress({ variables: { id: params.id, - input: transformFormToAddress(input) + input } }) } diff --git a/src/hooks/useAddressValidation.ts b/src/hooks/useAddressValidation.ts new file mode 100644 index 000000000..9bd1e401d --- /dev/null +++ b/src/hooks/useAddressValidation.ts @@ -0,0 +1,46 @@ +import { useState } from "react"; +import { useIntl } from "react-intl"; + +import { AddressTypeInput } from "@saleor/customers/types"; +import { commonMessages } from "@saleor/intl"; +import { transformFormToAddress } from "@saleor/misc"; +import { UserError } from "@saleor/types"; +import { AddressInput } from "@saleor/types/globalTypes"; +import { add, remove } from "@saleor/utils/lists"; + +interface UseAddressValidation { + errors: UserError[]; + submit: (data: AddressTypeInput) => void; +} + +function useAddressValidation( + onSubmit: (address: AddressInput) => void +): UseAddressValidation { + const intl = useIntl(); + const [validationErrors, setValidationErrors] = useState([]); + + const countryRequiredError = { + field: "country", + message: intl.formatMessage(commonMessages.requiredField) + }; + + return { + errors: validationErrors, + submit: (data: AddressTypeInput) => { + try { + setValidationErrors( + remove( + countryRequiredError, + validationErrors, + (a, b) => a.field === b.field + ) + ); + onSubmit(transformFormToAddress(data)); + } catch { + setValidationErrors(add(countryRequiredError, validationErrors)); + } + } + }; +} + +export default useAddressValidation; diff --git a/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx b/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx index ba084169f..56b031f97 100644 --- a/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx +++ b/src/orders/components/OrderAddressEditDialog/OrderAddressEditDialog.tsx @@ -12,12 +12,15 @@ import ConfirmButton, { ConfirmButtonTransitionState } from "@saleor/components/ConfirmButton"; import Form from "@saleor/components/Form"; +import { AddressTypeInput } from "@saleor/customers/types"; +import useAddressValidation from "@saleor/hooks/useAddressValidation"; +import useModalDialogErrors from "@saleor/hooks/useModalDialogErrors"; import useStateFromProps from "@saleor/hooks/useStateFromProps"; import { buttonMessages } from "@saleor/intl"; import { maybe } from "@saleor/misc"; +import { UserError } from "@saleor/types"; +import { AddressInput } from "@saleor/types/globalTypes"; import createSingleAutocompleteSelectHandler from "@saleor/utils/handlers/singleAutocompleteSelectChangeHandler"; -import { AddressTypeInput } from "../../../customers/types"; -import { UserError } from "../../../types"; const styles = createStyles({ overflow: { @@ -36,7 +39,7 @@ interface OrderAddressEditDialogProps extends WithStyles { label: string; }>; onClose(); - onConfirm(data: AddressTypeInput); + onConfirm(data: AddressInput); } const OrderAddressEditDialog = withStyles(styles, { @@ -59,6 +62,15 @@ const OrderAddressEditDialog = withStyles(styles, { () => countries.find(country => address.country === country.code).label ) ); + const { + errors: validationErrors, + submit: handleSubmit + } = useAddressValidation(onConfirm); + const dialogErrors = useModalDialogErrors( + [...errors, ...validationErrors], + open + ); + const countryChoices = countries.map(country => ({ label: country.label, value: country.code @@ -70,7 +82,7 @@ const OrderAddressEditDialog = withStyles(styles, { open={open} classes={{ paper: classes.overflow }} > - + {({ change, data, errors, submit }) => { const handleCountrySelect = createSingleAutocompleteSelectHandler( change, diff --git a/src/orders/views/OrderDetails/index.tsx b/src/orders/views/OrderDetails/index.tsx index 051368fb9..975770497 100644 --- a/src/orders/views/OrderDetails/index.tsx +++ b/src/orders/views/OrderDetails/index.tsx @@ -607,9 +607,7 @@ export const OrderDetails: React.StatelessComponent = ({ orderUpdate.mutate({ id, input: { - shippingAddress: transformFormToAddress( - shippingAddress - ) + shippingAddress } }) }