diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/index.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/index.tsx index b6182fa0141..bd9f5349c79 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/index.tsx @@ -1,12 +1,17 @@ /** * External dependencies */ -import { CSSTransition, TransitionGroup } from 'react-transition-group'; +import classnames from 'classnames'; + /** * Internal dependencies */ import './style.scss'; +/** + * Wrapper for address fields which handles the edit/preview transition. Form fields are always rendered so that + * validation can occur. + */ export const AddressWrapper = ( { isEditing = false, addressCard, @@ -16,25 +21,22 @@ export const AddressWrapper = ( { addressCard: () => JSX.Element; addressForm: () => JSX.Element; } ): JSX.Element | null => { + const wrapperClasses = classnames( + 'wc-block-components-address-address-wrapper', + { + 'is-editing': isEditing, + } + ); + return ( - - { ! isEditing && ( - - { addressCard() } - - ) } - { isEditing && ( - - { addressForm() } - - ) } - +
+
+ { addressCard() } +
+
+ { addressForm() } +
+
); }; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/style.scss b/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/style.scss index 6215de67970..3f18307a240 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/style.scss +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/address-wrapper/style.scss @@ -1,25 +1,32 @@ -.address-fade-transition-wrapper { +.wc-block-components-address-address-wrapper { position: relative; -} -.address-fade-transition-enter { - opacity: 0; -} -.address-fade-transition-enter-active { - opacity: 1; - transition: opacity 300ms ease-in; -} -.address-fade-transition-enter-done { - opacity: 1; -} -.address-fade-transition-exit { - opacity: 1; - position: absolute; - top: 0; -} -.address-fade-transition-exit-active { - opacity: 0; - transition: opacity 300ms ease-out; -} -.address-fade-transition-done { - opacity: 0; + + .wc-block-components-address-card-wrapper, + .wc-block-components-address-form-wrapper { + transition: all 300ms ease-in-out; + width: 100%; + } + + &.is-editing { + .wc-block-components-address-form-wrapper { + opacity: 1; + } + .wc-block-components-address-card-wrapper { + opacity: 0; + visibility: hidden; + position: absolute; + top: 0; + } + } + + &:not(.is-editing) { + .wc-block-components-address-form-wrapper { + opacity: 0; + visibility: hidden; + height: 0; + } + .wc-block-components-address-card-wrapper { + opacity: 1; + } + } } diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/block.tsx index b1f1dcdc2f4..ae722ab9228 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/block.tsx @@ -80,10 +80,6 @@ const Block = ( { const noticeContext = useBillingAsShipping ? [ noticeContexts.BILLING_ADDRESS, noticeContexts.SHIPPING_ADDRESS ] : [ noticeContexts.BILLING_ADDRESS ]; - const hasAddress = !! ( - billingAddress.address_1 && - ( billingAddress.first_name || billingAddress.last_name ) - ); return ( <> @@ -93,7 +89,6 @@ const Block = ( { addressFieldsConfig={ addressFieldsConfig } showPhoneField={ showPhoneField } requirePhoneField={ requirePhoneField } - hasAddress={ hasAddress } forceEditing={ forceEditing } /> diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx index 45bc172b382..e4dafcf40a1 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/customer-address.tsx @@ -1,7 +1,7 @@ /** * External dependencies */ -import { useState, useCallback } from '@wordpress/element'; +import { useState, useCallback, useEffect } from '@wordpress/element'; import { AddressForm } from '@woocommerce/base-components/cart-checkout'; import { useCheckoutAddress, useStoreEvents } from '@woocommerce/base-context'; import type { @@ -9,6 +9,8 @@ import type { AddressField, AddressFields, } from '@woocommerce/settings'; +import { useSelect } from '@wordpress/data'; +import { VALIDATION_STORE_KEY } from '@woocommerce/block-data'; /** * Internal dependencies @@ -21,13 +23,11 @@ const CustomerAddress = ( { addressFieldsConfig, showPhoneField, requirePhoneField, - hasAddress, forceEditing = false, }: { addressFieldsConfig: Record< keyof AddressFields, Partial< AddressField > >; showPhoneField: boolean; requirePhoneField: boolean; - hasAddress: boolean; forceEditing?: boolean; } ) => { const { @@ -40,8 +40,34 @@ const CustomerAddress = ( { useBillingAsShipping, } = useCheckoutAddress(); const { dispatchCheckoutEvent } = useStoreEvents(); - + const hasAddress = !! ( + billingAddress.address_1 && + ( billingAddress.first_name || billingAddress.last_name ) + ); const [ editing, setEditing ] = useState( ! hasAddress || forceEditing ); + + // Forces editing state if store has errors. + const { hasValidationErrors, invalidProps } = useSelect( ( select ) => { + const store = select( VALIDATION_STORE_KEY ); + return { + hasValidationErrors: store.hasValidationErrors(), + invalidProps: Object.keys( billingAddress ) + .filter( ( key ) => { + return ( + store.getValidationError( 'billing_' + key ) !== + undefined + ); + } ) + .filter( Boolean ), + }; + } ); + + useEffect( () => { + if ( invalidProps.length > 0 && editing === false ) { + setEditing( true ); + } + }, [ editing, hasValidationErrors, invalidProps.length ] ); + const addressFieldKeys = Object.keys( defaultAddressFields ) as ( keyof AddressFields )[]; diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/block.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/block.tsx index 077133c5c23..3b8dc12871f 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/block.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/block.tsx @@ -104,7 +104,6 @@ const Block = ( { addressFieldsConfig={ addressFieldsConfig } showPhoneField={ showPhoneField } requirePhoneField={ requirePhoneField } - hasAddress={ hasAddress } /> { hasAddress && ( diff --git a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx index 72431db75fa..f041c54d369 100644 --- a/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx +++ b/plugins/woocommerce-blocks/assets/js/blocks/checkout/inner-blocks/checkout-shipping-address-block/customer-address.tsx @@ -1,7 +1,7 @@ /** * External dependencies */ -import { useState, useCallback } from '@wordpress/element'; +import { useState, useCallback, useEffect } from '@wordpress/element'; import { AddressForm } from '@woocommerce/base-components/cart-checkout'; import { useCheckoutAddress, useStoreEvents } from '@woocommerce/base-context'; import type { @@ -9,6 +9,8 @@ import type { AddressField, AddressFields, } from '@woocommerce/settings'; +import { useSelect } from '@wordpress/data'; +import { VALIDATION_STORE_KEY } from '@woocommerce/block-data'; /** * Internal dependencies @@ -21,12 +23,10 @@ const CustomerAddress = ( { addressFieldsConfig, showPhoneField, requirePhoneField, - hasAddress, }: { addressFieldsConfig: Record< keyof AddressFields, Partial< AddressField > >; showPhoneField: boolean; requirePhoneField: boolean; - hasAddress: boolean; } ) => { const { defaultAddressFields, @@ -37,8 +37,34 @@ const CustomerAddress = ( { useShippingAsBilling, } = useCheckoutAddress(); const { dispatchCheckoutEvent } = useStoreEvents(); - + const hasAddress = !! ( + shippingAddress.address_1 && + ( shippingAddress.first_name || shippingAddress.last_name ) + ); const [ editing, setEditing ] = useState( ! hasAddress ); + + // Forces editing state if store has errors. + const { hasValidationErrors, invalidProps } = useSelect( ( select ) => { + const store = select( VALIDATION_STORE_KEY ); + return { + hasValidationErrors: store.hasValidationErrors(), + invalidProps: Object.keys( shippingAddress ) + .filter( ( key ) => { + return ( + store.getValidationError( 'shipping_' + key ) !== + undefined + ); + } ) + .filter( Boolean ), + }; + } ); + + useEffect( () => { + if ( invalidProps.length > 0 && editing === false ) { + setEditing( true ); + } + }, [ editing, hasValidationErrors, invalidProps.length ] ); + const addressFieldKeys = Object.keys( defaultAddressFields ) as ( keyof AddressFields )[]; diff --git a/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout.page.ts b/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout.page.ts index eaa337e9719..52990872a41 100644 --- a/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout.page.ts +++ b/plugins/woocommerce-blocks/tests/e2e/tests/checkout/checkout.page.ts @@ -126,34 +126,22 @@ export class CheckoutPage { } async editBillingDetails() { - const editButton = await this.page - .locator( - '.wc-block-checkout__billing-fields .wc-block-components-address-card__edit' - ) - .isVisible(); + const editButton = this.page.locator( + '.wc-block-checkout__billing-fields .wc-block-components-address-card__edit' + ); - if ( editButton ) { - await this.page - .locator( - '.wc-block-checkout__billing-fields .wc-block-components-address-card__edit' - ) - .click(); + if ( await editButton.isVisible() ) { + await editButton.click(); } } async editShippingDetails() { - const editButton = await this.page - .locator( - '.wc-block-checkout__shipping-fields .wc-block-components-address-card__edit' - ) - .isVisible(); + const editButton = this.page.locator( + '.wc-block-checkout__shipping-fields .wc-block-components-address-card__edit' + ); - if ( editButton ) { - await this.page - .locator( - '.wc-block-checkout__shipping-fields .wc-block-components-address-card__edit' - ) - .click(); + if ( await editButton.isVisible() ) { + await editButton.click(); } }