Ensure validation of fields occurs when collapsing fields (https://github.com/woocommerce/woocommerce-blocks/pull/11199)
* Ensure validation of fields occurs when collapsing fields * update click for edit button * turn off pointer events when hidden * Add visibility rule
This commit is contained in:
parent
41724e9400
commit
75bac91787
|
@ -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 (
|
||||
<TransitionGroup className="address-fade-transition-wrapper">
|
||||
{ ! isEditing && (
|
||||
<CSSTransition
|
||||
timeout={ 300 }
|
||||
classNames="address-fade-transition"
|
||||
>
|
||||
<div className={ wrapperClasses }>
|
||||
<div className="wc-block-components-address-card-wrapper">
|
||||
{ addressCard() }
|
||||
</CSSTransition>
|
||||
) }
|
||||
{ isEditing && (
|
||||
<CSSTransition
|
||||
timeout={ 300 }
|
||||
classNames="address-fade-transition"
|
||||
>
|
||||
</div>
|
||||
<div className="wc-block-components-address-form-wrapper">
|
||||
{ addressForm() }
|
||||
</CSSTransition>
|
||||
) }
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
.address-fade-transition-wrapper {
|
||||
.wc-block-components-address-address-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
.address-fade-transition-enter {
|
||||
|
||||
.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;
|
||||
}
|
||||
.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;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
.address-fade-transition-exit-active {
|
||||
opacity: 0;
|
||||
transition: opacity 300ms ease-out;
|
||||
}
|
||||
.address-fade-transition-done {
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.is-editing) {
|
||||
.wc-block-components-address-form-wrapper {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
}
|
||||
.wc-block-components-address-card-wrapper {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
/>
|
||||
</WrapperComponent>
|
||||
|
|
|
@ -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 )[];
|
||||
|
|
|
@ -104,7 +104,6 @@ const Block = ( {
|
|||
addressFieldsConfig={ addressFieldsConfig }
|
||||
showPhoneField={ showPhoneField }
|
||||
requirePhoneField={ requirePhoneField }
|
||||
hasAddress={ hasAddress }
|
||||
/>
|
||||
</WrapperComponent>
|
||||
{ hasAddress && (
|
||||
|
|
|
@ -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 )[];
|
||||
|
|
|
@ -126,34 +126,22 @@ export class CheckoutPage {
|
|||
}
|
||||
|
||||
async editBillingDetails() {
|
||||
const editButton = await this.page
|
||||
.locator(
|
||||
const editButton = this.page.locator(
|
||||
'.wc-block-checkout__billing-fields .wc-block-components-address-card__edit'
|
||||
)
|
||||
.isVisible();
|
||||
);
|
||||
|
||||
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(
|
||||
const editButton = this.page.locator(
|
||||
'.wc-block-checkout__shipping-fields .wc-block-components-address-card__edit'
|
||||
)
|
||||
.isVisible();
|
||||
);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue