Skip to content
This repository has been archived by the owner on Feb 23, 2024. It is now read-only.

Fix address block invalidations in the editor and address card display in Firefox #11714

Merged
merged 4 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
ShippingStateInput,
} from '@woocommerce/base-components/state-input';
import { useEffect, useMemo, useRef } from '@wordpress/element';
import { withInstanceId } from '@wordpress/compose';
import { useInstanceId } from '@wordpress/compose';
import { useShallowEqual } from '@woocommerce/base-hooks';
import { defaultAddressFields } from '@woocommerce/settings';
import isShallowEqual from '@wordpress/is-shallow-equal';
Expand Down Expand Up @@ -44,11 +44,12 @@ const AddressForm = ( {
id = '',
fields = defaultFields,
fieldConfig = {} as FieldConfig,
instanceId,
onChange,
type = 'shipping',
values,
}: AddressFormProps ): JSX.Element => {
const instanceId = useInstanceId( AddressForm );

// Track incoming props.
const currentFields = useShallowEqual( fields );
const currentFieldConfig = useShallowEqual( fieldConfig );
Expand Down Expand Up @@ -99,7 +100,7 @@ const AddressForm = ( {
fieldsRef.current?.postcode?.revalidate();
}, [ currentCountry ] );

id = id || instanceId;
id = id || `${ instanceId }`;

return (
<div id={ id } className="wc-block-components-address-form">
Expand Down Expand Up @@ -206,4 +207,4 @@ const AddressForm = ( {
);
};

export default withInstanceId( AddressForm );
export default AddressForm;
2 changes: 0 additions & 2 deletions assets/js/base/components/cart-checkout/address-form/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ export type AddressFormFields = {
export interface AddressFormProps {
// Id for component.
id?: string;
// Unique id for form.
instanceId: string;
// Type of form (billing or shipping).
type?: AddressType;
// Array of fields in form.
Expand Down
4 changes: 3 additions & 1 deletion assets/js/blocks/checkout/address-card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ const AddressCard = ( {
address,
onEdit,
target,
showPhoneField,
}: {
address: CartShippingAddress | CartBillingAddress;
onEdit: () => void;
target: string;
showPhoneField: boolean;
} ): JSX.Element | null => {
return (
<div className="wc-block-components-address-card">
Expand All @@ -44,7 +46,7 @@ const AddressCard = ( {
<span key={ `address-` + index }>{ field }</span>
) ) }
</div>
{ address.phone ? (
{ address.phone && showPhoneField ? (
<div
key={ `address-phone` }
className="wc-block-components-address-card__address-section"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import type {
AddressFields,
} from '@woocommerce/settings';
import { StoreNoticesContainer } from '@woocommerce/blocks-checkout';
import { useSelect } from '@wordpress/data';
import { CART_STORE_KEY } from '@woocommerce/block-data';

/**
* Internal dependencies
Expand Down Expand Up @@ -81,16 +83,24 @@ const Block = ( {
? [ noticeContexts.BILLING_ADDRESS, noticeContexts.SHIPPING_ADDRESS ]
: [ noticeContexts.BILLING_ADDRESS ];

const { cartDataLoaded } = useSelect( ( select ) => {
const store = select( CART_STORE_KEY );
return {
cartDataLoaded: store.hasFinishedResolution( 'getCartData' ),
};
} );
return (
<>
<StoreNoticesContainer context={ noticeContext } />
<WrapperComponent>
<CustomerAddress
addressFieldsConfig={ addressFieldsConfig }
showPhoneField={ showPhoneField }
requirePhoneField={ requirePhoneField }
forceEditing={ forceEditing }
/>
{ cartDataLoaded ? (
<CustomerAddress
addressFieldsConfig={ addressFieldsConfig }
showPhoneField={ showPhoneField }
requirePhoneField={ requirePhoneField }
forceEditing={ forceEditing }
/>
) : null }
</WrapperComponent>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ const CustomerAddress = ( {
onEdit={ () => {
setEditing( true );
} }
showPhoneField={ showPhoneField }
/>
),
[ billingAddress ]
[ billingAddress, showPhoneField ]
);

const renderAddressFormComponent = useCallback(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import type {
AddressField,
AddressFields,
} from '@woocommerce/settings';
import { useSelect } from '@wordpress/data';
import { CART_STORE_KEY } from '@woocommerce/block-data';

/**
* Internal dependencies
Expand Down Expand Up @@ -96,15 +98,24 @@ const Block = ( {
( shippingAddress.first_name || shippingAddress.last_name )
);

const { cartDataLoaded } = useSelect( ( select ) => {
const store = select( CART_STORE_KEY );
return {
cartDataLoaded: store.hasFinishedResolution( 'getCartData' ),
};
} );

return (
<>
<StoreNoticesContainer context={ noticeContext } />
<WrapperComponent>
<CustomerAddress
addressFieldsConfig={ addressFieldsConfig }
showPhoneField={ showPhoneField }
requirePhoneField={ requirePhoneField }
/>
{ cartDataLoaded ? (
<CustomerAddress
addressFieldsConfig={ addressFieldsConfig }
showPhoneField={ showPhoneField }
requirePhoneField={ requirePhoneField }
/>
) : null }
</WrapperComponent>
{ hasAddress && (
<CheckboxControl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
*/
import { useState, useCallback, useEffect } from '@wordpress/element';
import { AddressForm } from '@woocommerce/base-components/cart-checkout';
import { useCheckoutAddress, useStoreEvents } from '@woocommerce/base-context';
import {
useCheckoutAddress,
useStoreEvents,
useEditorContext,
} from '@woocommerce/base-context';
import type {
ShippingAddress,
AddressField,
Expand Down Expand Up @@ -38,11 +42,12 @@ const CustomerAddress = ( {
useShippingAsBilling,
} = useCheckoutAddress();
const { dispatchCheckoutEvent } = useStoreEvents();
const { isEditor } = useEditorContext();
const hasAddress = !! (
shippingAddress.address_1 &&
( shippingAddress.first_name || shippingAddress.last_name )
);
const [ editing, setEditing ] = useState( ! hasAddress );
const [ editing, setEditing ] = useState( ! hasAddress || isEditor );

// Forces editing state if store has errors.
const { hasValidationErrors, invalidProps } = useSelect( ( select ) => {
Expand Down Expand Up @@ -103,9 +108,10 @@ const CustomerAddress = ( {
onEdit={ () => {
setEditing( true );
} }
showPhoneField={ showPhoneField }
/>
),
[ shippingAddress ]
[ shippingAddress, showPhoneField ]
);

const renderAddressFormComponent = useCallback(
Expand Down Expand Up @@ -147,9 +153,11 @@ const CustomerAddress = ( {
dispatchCheckoutEvent,
onChangeAddress,
requirePhoneField,
setBillingPhone,
setShippingPhone,
shippingAddress,
showPhoneField,
useShippingAsBilling,
]
);

Expand Down
2 changes: 2 additions & 0 deletions packages/checkout/components/text-input/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export interface ValidatedTextInputProps
label?: string | undefined;
// Field value.
value: string;
// Other sibling fields that should be validated together.
values: string[];
// If true, validation errors will be shown.
showError?: boolean;
// Error message to display alongside the field regardless of validation.
Expand Down
27 changes: 14 additions & 13 deletions packages/checkout/components/text-input/validated-text-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const ValidatedTextInput = forwardRef<
customFormatter = ( newValue: string ) => newValue,
label,
validateOnMount = true,
instanceId: preferredInstanceId,
instanceId: preferredInstanceId = '',
...rest
},
forwardedRef
Expand Down Expand Up @@ -80,6 +80,14 @@ const ValidatedTextInput = forwardRef<
clearValidationError,
} = useDispatch( VALIDATION_STORE_KEY );

// Ref for validation callback.
const customValidationRef = useRef( customValidation );

// Update ref when validation callback changes.
useEffect( () => {
customValidationRef.current = customValidation;
}, [ customValidation ] );

const { validationError, validationErrorId } = useSelect(
( select ) => {
const store = select( VALIDATION_STORE_KEY );
Expand All @@ -105,7 +113,7 @@ const ValidatedTextInput = forwardRef<

if (
inputObject.checkValidity() &&
customValidation( inputObject )
customValidationRef.current( inputObject )
) {
clearValidationError( errorIdString );
return;
Expand All @@ -120,13 +128,7 @@ const ValidatedTextInput = forwardRef<
},
} );
},
[
clearValidationError,
customValidation,
errorIdString,
setValidationErrors,
label,
]
[ clearValidationError, errorIdString, setValidationErrors, label ]
);

// Allows parent to trigger revalidation.
Expand Down Expand Up @@ -160,8 +162,6 @@ const ValidatedTextInput = forwardRef<
inputRef.current?.ownerDocument?.activeElement !==
inputRef.current
) {
validateInput( true );

const formattedValue = customFormatter(
inputRef.current.value
);
Expand All @@ -186,6 +186,9 @@ const ValidatedTextInput = forwardRef<
if ( ! isPristine ) {
return;
}

setIsPristine( false );

if ( focusOnMount ) {
inputRef.current?.focus();
}
Expand All @@ -194,8 +197,6 @@ const ValidatedTextInput = forwardRef<
if ( validateOnMount || ! focusOnMount ) {
validateInput( true );
}

setIsPristine( false );
}, [
validateOnMount,
focusOnMount,
Expand Down
Loading