diff --git a/assets/js/base/context/hooks/cart/use-store-cart.ts b/assets/js/base/context/hooks/cart/use-store-cart.ts index c59602fed09..7430f0978bc 100644 --- a/assets/js/base/context/hooks/cart/use-store-cart.ts +++ b/assets/js/base/context/hooks/cart/use-store-cart.ts @@ -184,6 +184,7 @@ export const useStoreCart = ( const cartIsLoading = ! store.hasFinishedResolution( 'getCartData' ); + const shippingRatesLoading = store.isCustomerDataUpdating(); const { receiveCart } = dispatch( storeKey ); const billingAddress = decodeValues( cartData.billingAddress ); diff --git a/assets/js/base/context/hooks/use-customer-data.ts b/assets/js/base/context/hooks/use-customer-data.ts index 98dcce60c2d..2f7fec296e5 100644 --- a/assets/js/base/context/hooks/use-customer-data.ts +++ b/assets/js/base/context/hooks/use-customer-data.ts @@ -11,9 +11,12 @@ import { pluckAddress, pluckEmail, } from '@woocommerce/base-utils'; -import type { +import { CartResponseBillingAddress, CartResponseShippingAddress, + BillingAddressShippingAddress, + CartBillingAddress, + CartShippingAddress, } from '@woocommerce/types'; declare type CustomerData = { @@ -92,6 +95,26 @@ export const useCustomerData = (): { 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. const previousCustomerData = useRef< CustomerData >( customerData ); @@ -146,23 +169,40 @@ export const useCustomerData = (): { */ useEffect( () => { // Only push updates when enough fields are populated. - if ( - ! shouldUpdateAddressStore( - previousCustomerData.current.billingData, - debouncedCustomerData.billingData - ) && - ! shouldUpdateAddressStore( - previousCustomerData.current.shippingAddress, - debouncedCustomerData.shippingAddress - ) - ) { + const shouldUpdateBillingAddress = shouldUpdateAddressStore( + previousCustomerData.current.billingData, + debouncedCustomerData.billingData + ); + + const shouldUpdateShippingAddress = shouldUpdateAddressStore( + previousCustomerData.current.shippingAddress, + debouncedCustomerData.shippingAddress + ); + + if ( ! shouldUpdateBillingAddress && ! shouldUpdateShippingAddress ) { 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; - updateCustomerData( { - billing_address: debouncedCustomerData.billingData, - shipping_address: debouncedCustomerData.shippingAddress, - } ) + updateCustomerData( + customerDataToUpdate as Partial< BillingAddressShippingAddress > + ) .then( () => { removeNotice( 'checkout' ); } ) diff --git a/assets/js/data/cart/actions.ts b/assets/js/data/cart/actions.ts index 7b276a1aba6..253c8b3ffd7 100644 --- a/assets/js/data/cart/actions.ts +++ b/assets/js/data/cart/actions.ts @@ -6,9 +6,8 @@ import type { Cart, CartResponse, CartResponseItem, - CartBillingAddress, - CartShippingAddress, ExtensionCartUpdateArgs, + BillingAddressShippingAddress, } from '@woocommerce/types'; import { ReturnOrGeneratorYieldUnion } from '@automattic/data-stores'; import { camelCase, mapKeys } from 'lodash'; @@ -463,11 +462,6 @@ export function* selectShippingRate( return true; } -type BillingAddressShippingAddress = { - billing_address: CartBillingAddress; - shipping_address: CartShippingAddress; -}; - /** * Updates the shipping and/or billing address for the customer and returns an * updated cart. @@ -476,7 +470,7 @@ type BillingAddressShippingAddress = { * billing_address and shipping_address. */ export function* updateCustomerData( - customerData: BillingAddressShippingAddress + customerData: Partial< BillingAddressShippingAddress > ): Generator< unknown, boolean, { response: CartResponse } > { yield updatingCustomerData( true ); diff --git a/assets/js/types/type-defs/cart.ts b/assets/js/types/type-defs/cart.ts index c04cb3a0e24..ce8cbe83ed0 100644 --- a/assets/js/types/type-defs/cart.ts +++ b/assets/js/types/type-defs/cart.ts @@ -198,3 +198,8 @@ export interface ExtensionCartUpdateArgs { data: Record< string, unknown >; namespace: string; } + +export interface BillingAddressShippingAddress { + billing_address: CartBillingAddress; + shipping_address: CartShippingAddress; +}