2020-05-06 10:21:30 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import defaultAddressFields from '@woocommerce/base-components/cart-checkout/address-form/default-address-fields';
|
2020-11-20 15:13:35 +00:00
|
|
|
import { useState, useEffect, useCallback, useRef } from '@wordpress/element';
|
2020-05-06 10:21:30 +00:00
|
|
|
import {
|
|
|
|
useShippingDataContext,
|
2020-11-20 15:13:35 +00:00
|
|
|
useCustomerDataContext,
|
2020-05-06 10:21:30 +00:00
|
|
|
useCheckoutContext,
|
|
|
|
} from '@woocommerce/base-context';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Compare two addresses and see if they are the same.
|
|
|
|
*
|
|
|
|
* @param {Object} address1 First address.
|
|
|
|
* @param {Object} address2 Second address.
|
|
|
|
*/
|
|
|
|
const isSameAddress = ( address1, address2 ) => {
|
|
|
|
return Object.keys( defaultAddressFields ).every(
|
|
|
|
( field ) => address1[ field ] === address2[ field ]
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2020-11-20 15:13:35 +00:00
|
|
|
* Custom hook for exposing address related functionality for the checkout address form.
|
2020-05-06 10:21:30 +00:00
|
|
|
*/
|
|
|
|
export const useCheckoutAddress = () => {
|
|
|
|
const { customerId } = useCheckoutContext();
|
2020-11-20 15:13:35 +00:00
|
|
|
const { needsShipping } = useShippingDataContext();
|
2020-05-06 10:21:30 +00:00
|
|
|
const {
|
2020-11-20 15:13:35 +00:00
|
|
|
billingData,
|
|
|
|
setBillingData,
|
2020-05-06 10:21:30 +00:00
|
|
|
shippingAddress,
|
|
|
|
setShippingAddress,
|
2020-11-20 15:13:35 +00:00
|
|
|
} = useCustomerDataContext();
|
2020-05-06 10:21:30 +00:00
|
|
|
|
|
|
|
// This tracks the state of the "shipping as billing" address checkbox. It's
|
|
|
|
// initial value is true (if shipping is needed), however, if the user is
|
|
|
|
// logged in and they have a different billing address, we can toggle this off.
|
|
|
|
const [ shippingAsBilling, setShippingAsBilling ] = useState(
|
|
|
|
() =>
|
|
|
|
needsShipping &&
|
|
|
|
( ! customerId || isSameAddress( shippingAddress, billingData ) )
|
|
|
|
);
|
|
|
|
|
2020-11-20 15:13:35 +00:00
|
|
|
const currentShippingAsBilling = useRef( shippingAsBilling );
|
|
|
|
const previousBillingData = useRef( billingData );
|
2020-05-06 10:21:30 +00:00
|
|
|
|
|
|
|
/**
|
2020-11-20 15:13:35 +00:00
|
|
|
* Sets shipping address data, and also billing if using the same address.
|
2020-05-06 10:21:30 +00:00
|
|
|
*/
|
2020-11-20 15:13:35 +00:00
|
|
|
const setShippingFields = useCallback(
|
|
|
|
( value ) => {
|
|
|
|
setShippingAddress( value );
|
|
|
|
|
|
|
|
if ( shippingAsBilling ) {
|
|
|
|
setBillingData( value );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[ shippingAsBilling, setShippingAddress, setBillingData ]
|
2020-05-14 00:05:09 +00:00
|
|
|
);
|
2020-05-06 10:21:30 +00:00
|
|
|
|
2020-12-23 15:10:13 +00:00
|
|
|
/**
|
|
|
|
* Sets billing address data, and also shipping if shipping is disabled.
|
|
|
|
*/
|
|
|
|
const setBillingFields = useCallback(
|
|
|
|
( value ) => {
|
|
|
|
setBillingData( value );
|
|
|
|
|
|
|
|
if ( ! needsShipping ) {
|
|
|
|
setShippingAddress( value );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[ needsShipping, setShippingAddress, setBillingData ]
|
|
|
|
);
|
|
|
|
|
2020-11-20 15:13:35 +00:00
|
|
|
// When the "Use same address" checkbox is toggled we need to update the current billing address to reflect this;
|
|
|
|
// that is either setting the billing address to the shipping address, or restoring the billing address to it's
|
|
|
|
// previous state.
|
|
|
|
useEffect( () => {
|
|
|
|
if ( currentShippingAsBilling.current !== shippingAsBilling ) {
|
|
|
|
if ( shippingAsBilling ) {
|
|
|
|
previousBillingData.current = billingData;
|
|
|
|
setBillingData( shippingAddress );
|
|
|
|
} else {
|
|
|
|
setBillingData( {
|
|
|
|
...previousBillingData.current,
|
|
|
|
email: undefined,
|
|
|
|
phone: undefined,
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
currentShippingAsBilling.current = shippingAsBilling;
|
|
|
|
}
|
|
|
|
}, [ shippingAsBilling, setBillingData, shippingAddress, billingData ] );
|
|
|
|
|
2020-12-23 15:10:13 +00:00
|
|
|
const setEmail = ( value ) =>
|
|
|
|
void setBillingData( {
|
|
|
|
email: value,
|
|
|
|
} );
|
|
|
|
const setPhone = ( value ) =>
|
|
|
|
void setBillingData( {
|
|
|
|
phone: value,
|
|
|
|
} );
|
2020-05-06 10:21:30 +00:00
|
|
|
|
2020-11-20 15:13:35 +00:00
|
|
|
// Note that currentShippingAsBilling is returned rather than the current state of shippingAsBilling--this is so that
|
|
|
|
// the billing fields are not rendered before sync (billing field values are debounced and would be outdated)
|
2020-05-06 10:21:30 +00:00
|
|
|
return {
|
|
|
|
defaultAddressFields,
|
2020-05-14 00:05:09 +00:00
|
|
|
shippingFields: shippingAddress,
|
2020-11-20 15:13:35 +00:00
|
|
|
setShippingFields,
|
|
|
|
billingFields: billingData,
|
2020-12-23 15:10:13 +00:00
|
|
|
setBillingFields,
|
2020-05-06 10:21:30 +00:00
|
|
|
setEmail,
|
|
|
|
setPhone,
|
|
|
|
shippingAsBilling,
|
|
|
|
setShippingAsBilling,
|
2020-11-20 15:13:35 +00:00
|
|
|
showBillingFields:
|
|
|
|
! needsShipping || ! currentShippingAsBilling.current,
|
2020-05-06 10:21:30 +00:00
|
|
|
};
|
|
|
|
};
|