woocommerce/plugins/woocommerce-blocks/assets/js/base/hooks/customer/use-customer-data.js

125 lines
3.0 KiB
JavaScript

/**
* External dependencies
*/
import { useDispatch } from '@wordpress/data';
import { useEffect, useState, useCallback, useRef } from '@wordpress/element';
import { useStoreNotices, useStoreCart } from '@woocommerce/base-hooks';
import { CART_STORE_KEY as storeKey } from '@woocommerce/block-data';
import { useDebounce } from 'use-debounce';
import isShallowEqual from '@wordpress/is-shallow-equal';
/**
* Internal dependencies
*/
import { shouldUpdateAddressStore } from './utils';
/**
* This is a custom hook for syncing customer address data (billing and shipping) with the server.
*/
export const useCustomerData = () => {
const { updateCustomerData } = useDispatch( storeKey );
const { addErrorNotice, removeNotice } = useStoreNotices();
const {
billingAddress: cartBillingData,
shippingAddress: cartShippingAddress,
} = useStoreCart();
const [ customerData, setCustomerData ] = useState( {
billingData: cartBillingData,
shippingAddress: cartShippingAddress,
} );
const currentCustomerData = useRef( customerData );
const [ debouncedCustomerData ] = useDebounce( customerData, 400, {
equalityFn: ( prevData, newData ) => {
return ! (
isShallowEqual( prevData.billingData, newData.billingData ) ||
isShallowEqual(
prevData.shippingAddress,
newData.shippingAddress
)
);
},
} );
/**
* Set billing data.
*
* Contains special handling for email and phone so those fields are not overwritten if simply updating address.
*/
const setBillingData = useCallback( ( newData ) => {
setCustomerData( ( prevState ) => {
return {
...prevState,
billingData: {
...prevState.billingData,
...newData,
},
};
} );
}, [] );
const setShippingAddress = useCallback( ( newData ) => {
setCustomerData( ( prevState ) => ( {
...prevState,
shippingAddress: newData,
} ) );
}, [] );
useEffect( () => {
if (
! isShallowEqual(
currentCustomerData.current.billingData,
cartBillingData
)
) {
currentCustomerData.current.billingData = cartBillingData;
}
if (
! isShallowEqual(
currentCustomerData.current.shippingAddress,
cartShippingAddress
)
) {
currentCustomerData.current.shippingAddress = cartShippingAddress;
}
}, [ cartBillingData, cartShippingAddress ] );
useEffect( () => {
if (
! (
shouldUpdateAddressStore(
currentCustomerData.current.billingData,
debouncedCustomerData.billingData
) ||
shouldUpdateAddressStore(
currentCustomerData.current.shippingAddress,
debouncedCustomerData.shippingAddress
)
)
) {
return;
}
removeNotice( 'address' );
updateCustomerData( {
billing_address: debouncedCustomerData.billingData,
shipping_address: debouncedCustomerData.shippingAddress,
} ).catch( ( error ) => {
addErrorNotice( error.message, {
id: 'address',
} );
} );
}, [
debouncedCustomerData,
addErrorNotice,
removeNotice,
updateCustomerData,
] );
return {
billingData: customerData.billingData,
shippingAddress: customerData.shippingAddress,
setBillingData,
setShippingAddress,
};
};