108 lines
3.1 KiB
JavaScript
108 lines
3.1 KiB
JavaScript
|
/**
|
||
|
* External dependencies
|
||
|
*/
|
||
|
import defaultAddressFields from '@woocommerce/base-components/cart-checkout/address-form/default-address-fields';
|
||
|
import { useState, useEffect } from '@wordpress/element';
|
||
|
import {
|
||
|
useShippingDataContext,
|
||
|
useBillingDataContext,
|
||
|
useCheckoutContext,
|
||
|
} from '@woocommerce/base-context';
|
||
|
import { isEqual } from 'lodash';
|
||
|
|
||
|
/**
|
||
|
* 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 ]
|
||
|
);
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Custom hook for tracking address field state on checkout and persisting it to
|
||
|
* context globally on change.
|
||
|
*/
|
||
|
export const useCheckoutAddress = () => {
|
||
|
const { customerId } = useCheckoutContext();
|
||
|
const {
|
||
|
shippingAddress,
|
||
|
setShippingAddress,
|
||
|
needsShipping,
|
||
|
} = useShippingDataContext();
|
||
|
const { billingData, setBillingData } = useBillingDataContext();
|
||
|
|
||
|
// These are the local states of address fields, which are persisted
|
||
|
// globally when changed. They default to the global shipping address which
|
||
|
// is populated from the current customer data or default location.
|
||
|
const [ shippingFields, updateShippingFields ] = useState(
|
||
|
shippingAddress
|
||
|
);
|
||
|
const [ billingFields, updateBillingFields ] = useState( billingData );
|
||
|
|
||
|
// 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 ) )
|
||
|
);
|
||
|
|
||
|
// Pushes to global state when changes are made locally.
|
||
|
useEffect( () => {
|
||
|
if ( ! isEqual( shippingFields, shippingAddress ) ) {
|
||
|
setShippingAddress( shippingFields );
|
||
|
}
|
||
|
|
||
|
const newBillingData = shippingAsBilling
|
||
|
? shippingFields
|
||
|
: billingFields;
|
||
|
|
||
|
if ( ! isEqual( newBillingData, billingData ) ) {
|
||
|
setBillingData( newBillingData );
|
||
|
}
|
||
|
}, [ shippingFields, billingFields, shippingAsBilling ] );
|
||
|
|
||
|
/**
|
||
|
* Wrapper for updateBillingFields (from useState) which handles merging.
|
||
|
*
|
||
|
* @param {Object} newValues New values to store to state.
|
||
|
*/
|
||
|
const setBillingFields = ( newValues ) =>
|
||
|
void updateBillingFields( ( prevState ) => ( {
|
||
|
...prevState,
|
||
|
...newValues,
|
||
|
} ) );
|
||
|
|
||
|
/**
|
||
|
* Wrapper for updateShippingFields (from useState) which handles merging.
|
||
|
*
|
||
|
* @param {Object} newValues New values to store to state.
|
||
|
*/
|
||
|
const setShippingFields = ( newValues ) =>
|
||
|
void updateShippingFields( ( prevState ) => ( {
|
||
|
...prevState,
|
||
|
...newValues,
|
||
|
} ) );
|
||
|
|
||
|
const setEmail = ( value ) => void setBillingFields( { email: value } );
|
||
|
const setPhone = ( value ) => void setBillingFields( { phone: value } );
|
||
|
|
||
|
return {
|
||
|
defaultAddressFields,
|
||
|
shippingFields,
|
||
|
setShippingFields,
|
||
|
billingFields,
|
||
|
setBillingFields,
|
||
|
setEmail,
|
||
|
setPhone,
|
||
|
shippingAsBilling,
|
||
|
setShippingAsBilling,
|
||
|
showBillingFields: ! needsShipping || ! shippingAsBilling,
|
||
|
};
|
||
|
};
|