From 168887ac3b54f9b7afb56e8e26eccd1b6f2b6778 Mon Sep 17 00:00:00 2001 From: Wojciech Mista Date: Wed, 6 Apr 2022 11:32:31 +0200 Subject: [PATCH] Prevent form submit if country is not selected (#1966) * Prevent form submit if country is not selected * Refactor error checking function * Make address forms not invoke chrome's autofill * Add a comment * Update tests --- src/components/AddressEdit/AddressEdit.tsx | 20 +++--- .../OrderCustomerAddressesEditDialog.tsx | 21 +++--- .../OrderCustomerAddressesEditDialog/form.tsx | 6 +- .../OrderCustomerAddressesEditDialog/utils.ts | 24 +++++-- .../__snapshots__/Stories.test.ts.snap | 72 +++++++++---------- 5 files changed, 83 insertions(+), 60 deletions(-) diff --git a/src/components/AddressEdit/AddressEdit.tsx b/src/components/AddressEdit/AddressEdit.tsx index 0bc8e93a3..3d38b78f4 100644 --- a/src/components/AddressEdit/AddressEdit.tsx +++ b/src/components/AddressEdit/AddressEdit.tsx @@ -93,7 +93,9 @@ const AddressEdit: React.FC = props => { value={data.firstName} fullWidth InputProps={{ - autoComplete: "given-name" + // Setting 'autoComplete: "new-password"' is the only way to + // disable Chrome's autofill on forms as of early 2022 + autoComplete: "new-password" }} /> @@ -108,7 +110,7 @@ const AddressEdit: React.FC = props => { value={data.lastName} fullWidth InputProps={{ - autoComplete: "family-name" + autoComplete: "new-password" }} /> @@ -128,7 +130,7 @@ const AddressEdit: React.FC = props => { value={data.companyName} fullWidth InputProps={{ - autoComplete: "organization" + autoComplete: "new-password" }} /> @@ -145,7 +147,7 @@ const AddressEdit: React.FC = props => { value={data.phone} onChange={onChange} InputProps={{ - autoComplete: "tel" + autoComplete: "new-password" }} /> @@ -163,7 +165,7 @@ const AddressEdit: React.FC = props => { value={data.streetAddress1} fullWidth InputProps={{ - autoComplete: "address-line1" + autoComplete: "new-password" }} /> @@ -179,7 +181,7 @@ const AddressEdit: React.FC = props => { value={data.streetAddress2} fullWidth InputProps={{ - autoComplete: "address-line2" + autoComplete: "new-password" }} /> @@ -197,7 +199,7 @@ const AddressEdit: React.FC = props => { value={data.city} fullWidth InputProps={{ - autoComplete: "address-level2" + autoComplete: "new-password" }} /> @@ -214,7 +216,7 @@ const AddressEdit: React.FC = props => { value={data.postalCode} fullWidth InputProps={{ - autoComplete: "postal-code" + autoComplete: "new-password" }} /> @@ -251,7 +253,7 @@ const AddressEdit: React.FC = props => { value={data.countryArea} fullWidth InputProps={{ - autoComplete: "address-level1" + autoComplete: "new-password" }} /> diff --git a/src/orders/components/OrderCustomerAddressesEditDialog/OrderCustomerAddressesEditDialog.tsx b/src/orders/components/OrderCustomerAddressesEditDialog/OrderCustomerAddressesEditDialog.tsx index e82920172..474ce8f47 100644 --- a/src/orders/components/OrderCustomerAddressesEditDialog/OrderCustomerAddressesEditDialog.tsx +++ b/src/orders/components/OrderCustomerAddressesEditDialog/OrderCustomerAddressesEditDialog.tsx @@ -43,7 +43,11 @@ import { OrderCustomerAddressesEditDialogOutput, OrderCustomerSearchAddressState } from "./types"; -import { getAddressEditProps, validateDefaultAddress } from "./utils"; +import { + getAddressEditProps, + hasPreSubmitErrors, + validateDefaultAddress +} from "./utils"; export interface OrderCustomerAddressesEditDialogProps { open: boolean; @@ -131,20 +135,22 @@ const OrderCustomerAddressesEditDialog: React.FC { + // async because handleShippingSubmit can return a promise + const handleAddressesSubmit = async ( + data: OrderCustomerAddressesEditFormData + ) => { const shippingAddress = customerAddresses.length > 0 && data.shippingAddressInputOption === AddressInputOptionEnum.CUSTOMER_ADDRESS ? getCustomerAddress(data.customerShippingAddress.id) - : handleShippingSubmit(data.shippingAddress); + : await handleShippingSubmit(data.shippingAddress); const billingAddress = customerAddresses.length > 0 && data.billingAddressInputOption === AddressInputOptionEnum.CUSTOMER_ADDRESS ? getCustomerAddress(data.customerBillingAddress.id) - : handleBillingSubmit(data.billingAddress); + : await handleBillingSubmit(data.billingAddress); if (variant === AddressEditDialogVariant.CHANGE_SHIPPING_ADDRESS) { return { @@ -205,12 +211,11 @@ const OrderCustomerAddressesEditDialog: React.FC { - const addressesInput = handleAddressesSubmit(data); - if (addressesInput) { + const addressesInput = await handleAddressesSubmit(data); + if (addressesInput && !hasPreSubmitErrors(addressesInput)) { await onConfirm(addressesInput as OrderCustomerAddressesEditDialogOutput); setAddressSearchState(defaultSearchState); } - return Promise.resolve([ ...shippingValidationErrors, ...billingValidationErrors diff --git a/src/orders/components/OrderCustomerAddressesEditDialog/form.tsx b/src/orders/components/OrderCustomerAddressesEditDialog/form.tsx index 83dcea612..0e94d24a4 100644 --- a/src/orders/components/OrderCustomerAddressesEditDialog/form.tsx +++ b/src/orders/components/OrderCustomerAddressesEditDialog/form.tsx @@ -221,7 +221,11 @@ const OrderCustomerAddressesEditForm: React.FC{children(props)}; + return ( +
+ {children(props)} +
+ ); }; OrderCustomerAddressesEditForm.displayName = "OrderCustomerAddressesEditForm"; diff --git a/src/orders/components/OrderCustomerAddressesEditDialog/utils.ts b/src/orders/components/OrderCustomerAddressesEditDialog/utils.ts index ad46f0c25..3e2f19ebb 100644 --- a/src/orders/components/OrderCustomerAddressesEditDialog/utils.ts +++ b/src/orders/components/OrderCustomerAddressesEditDialog/utils.ts @@ -2,6 +2,7 @@ import { SingleAutocompleteChoiceType } from "@saleor/components/SingleAutocompl import { AccountErrorFragment, AddressFragment, + AddressInput, AddressTypeEnum, Node, OrderErrorFragment @@ -48,6 +49,21 @@ export function validateDefaultAddress( return defaultAddress; } +const filterAddressErrors = ( + dialogErrors: Array, + addressType: AddressTypeEnum +) => dialogErrors.filter(error => error.addressType === addressType); + +interface ShippingAddresses { + shippingAddress: AccountErrorFragment[] | AddressInput; + billingAddress: AccountErrorFragment[] | AddressInput; +} + +export const hasPreSubmitErrors = (input: ShippingAddresses) => + Object.values(input) + .flat() + .some(el => "code" in el); + export const getAddressEditProps = ( variant: "shipping" | "billing", data: OrderCustomerAddressesEditData, @@ -63,9 +79,7 @@ export const getAddressEditProps = ( return { ...addressEditCommonProps, addressInputName: "shippingAddressInputOption", - formErrors: dialogErrors.filter( - error => error.addressType === AddressTypeEnum.SHIPPING - ), + formErrors: filterAddressErrors(dialogErrors, AddressTypeEnum.SHIPPING), onEdit: () => setAddressSearchState({ open: true, @@ -84,9 +98,7 @@ export const getAddressEditProps = ( return { ...addressEditCommonProps, addressInputName: "billingAddressInputOption", - formErrors: dialogErrors.filter( - error => error.addressType === AddressTypeEnum.BILLING - ), + formErrors: filterAddressErrors(dialogErrors, AddressTypeEnum.BILLING), onEdit: () => setAddressSearchState({ open: true, diff --git a/src/storybook/__snapshots__/Stories.test.ts.snap b/src/storybook/__snapshots__/Stories.test.ts.snap index 2b004ceb9..6ddf47d36 100644 --- a/src/storybook/__snapshots__/Stories.test.ts.snap +++ b/src/storybook/__snapshots__/Stories.test.ts.snap @@ -3727,7 +3727,7 @@ exports[`Storyshots Generics / AddressEdit default 1`] = ` >