Fix 'Country is required' error on the Cart block when updating shipping address (https://github.com/woocommerce/woocommerce-blocks/pull/5129)

* Fix  error on the Cart block

* Created a cartIsHydrated variable in useStoreCart hook and used this to update the billing address in the internal state of the useCustomerData hook

* Fix the country is required error on the Cart page using refs

* Separate api calls to update shipping and billingUpdate billing and shipping addresses only when needed in API calls

* Remove redundant check for customerDataToUpdate

* remove use of refs in initial values

Co-authored-by: Nadir Seghir <nadir.seghir@gmail.com>
This commit is contained in:
Alex Florisca 2021-11-16 12:39:43 +00:00 committed by GitHub
parent f9c458b090
commit 78c846bddc
4 changed files with 63 additions and 23 deletions

View File

@ -184,6 +184,7 @@ export const useStoreCart = (
const cartIsLoading = ! store.hasFinishedResolution( const cartIsLoading = ! store.hasFinishedResolution(
'getCartData' 'getCartData'
); );
const shippingRatesLoading = store.isCustomerDataUpdating(); const shippingRatesLoading = store.isCustomerDataUpdating();
const { receiveCart } = dispatch( storeKey ); const { receiveCart } = dispatch( storeKey );
const billingAddress = decodeValues( cartData.billingAddress ); const billingAddress = decodeValues( cartData.billingAddress );

View File

@ -11,9 +11,12 @@ import {
pluckAddress, pluckAddress,
pluckEmail, pluckEmail,
} from '@woocommerce/base-utils'; } from '@woocommerce/base-utils';
import type { import {
CartResponseBillingAddress, CartResponseBillingAddress,
CartResponseShippingAddress, CartResponseShippingAddress,
BillingAddressShippingAddress,
CartBillingAddress,
CartShippingAddress,
} from '@woocommerce/types'; } from '@woocommerce/types';
declare type CustomerData = { declare type CustomerData = {
@ -92,6 +95,26 @@ export const useCustomerData = (): {
shippingAddress: initialShippingAddress, shippingAddress: initialShippingAddress,
} ); } );
// We only want to update the local state once, otherwise the data on the checkout page gets overwritten
// with the initial state of the addresses here
const [ hasCustomerDataSynced, setHasCustomerDataSynced ] = useState<
boolean
>( false );
if (
! hasCustomerDataSynced &&
shouldUpdateAddressStore(
customerData.shippingAddress,
initialShippingAddress
)
) {
setCustomerData( {
billingData: initialBillingAddress,
shippingAddress: initialShippingAddress,
} );
setHasCustomerDataSynced( true );
}
// Store values last sent to the server in a ref to avoid requests unless important fields are changed. // Store values last sent to the server in a ref to avoid requests unless important fields are changed.
const previousCustomerData = useRef< CustomerData >( customerData ); const previousCustomerData = useRef< CustomerData >( customerData );
@ -146,23 +169,40 @@ export const useCustomerData = (): {
*/ */
useEffect( () => { useEffect( () => {
// Only push updates when enough fields are populated. // Only push updates when enough fields are populated.
if ( const shouldUpdateBillingAddress = shouldUpdateAddressStore(
! shouldUpdateAddressStore(
previousCustomerData.current.billingData, previousCustomerData.current.billingData,
debouncedCustomerData.billingData debouncedCustomerData.billingData
) && );
! shouldUpdateAddressStore(
const shouldUpdateShippingAddress = shouldUpdateAddressStore(
previousCustomerData.current.shippingAddress, previousCustomerData.current.shippingAddress,
debouncedCustomerData.shippingAddress debouncedCustomerData.shippingAddress
) );
) {
if ( ! shouldUpdateBillingAddress && ! shouldUpdateShippingAddress ) {
return; return;
} }
const customerDataToUpdate:
| Partial< BillingAddressShippingAddress >
| Record<
keyof BillingAddressShippingAddress,
CartBillingAddress | CartShippingAddress
> = {};
if ( shouldUpdateBillingAddress ) {
customerDataToUpdate.billing_address =
debouncedCustomerData.billingData;
}
if ( shouldUpdateShippingAddress ) {
customerDataToUpdate.shipping_address =
debouncedCustomerData.shippingAddress;
}
previousCustomerData.current = debouncedCustomerData; previousCustomerData.current = debouncedCustomerData;
updateCustomerData( { updateCustomerData(
billing_address: debouncedCustomerData.billingData, customerDataToUpdate as Partial< BillingAddressShippingAddress >
shipping_address: debouncedCustomerData.shippingAddress, )
} )
.then( () => { .then( () => {
removeNotice( 'checkout' ); removeNotice( 'checkout' );
} ) } )

View File

@ -6,9 +6,8 @@ import type {
Cart, Cart,
CartResponse, CartResponse,
CartResponseItem, CartResponseItem,
CartBillingAddress,
CartShippingAddress,
ExtensionCartUpdateArgs, ExtensionCartUpdateArgs,
BillingAddressShippingAddress,
} from '@woocommerce/types'; } from '@woocommerce/types';
import { ReturnOrGeneratorYieldUnion } from '@automattic/data-stores'; import { ReturnOrGeneratorYieldUnion } from '@automattic/data-stores';
import { camelCase, mapKeys } from 'lodash'; import { camelCase, mapKeys } from 'lodash';
@ -463,11 +462,6 @@ export function* selectShippingRate(
return true; return true;
} }
type BillingAddressShippingAddress = {
billing_address: CartBillingAddress;
shipping_address: CartShippingAddress;
};
/** /**
* Updates the shipping and/or billing address for the customer and returns an * Updates the shipping and/or billing address for the customer and returns an
* updated cart. * updated cart.
@ -476,7 +470,7 @@ type BillingAddressShippingAddress = {
* billing_address and shipping_address. * billing_address and shipping_address.
*/ */
export function* updateCustomerData( export function* updateCustomerData(
customerData: BillingAddressShippingAddress customerData: Partial< BillingAddressShippingAddress >
): Generator< unknown, boolean, { response: CartResponse } > { ): Generator< unknown, boolean, { response: CartResponse } > {
yield updatingCustomerData( true ); yield updatingCustomerData( true );

View File

@ -198,3 +198,8 @@ export interface ExtensionCartUpdateArgs {
data: Record< string, unknown >; data: Record< string, unknown >;
namespace: string; namespace: string;
} }
export interface BillingAddressShippingAddress {
billing_address: CartBillingAddress;
shipping_address: CartShippingAddress;
}