/** * External dependencies */ import { __ } from '@wordpress/i18n'; import { useMemo, useEffect, Fragment, useState } from '@wordpress/element'; import { AddressForm } from '@woocommerce/base-components/cart-checkout'; import { useCheckoutAddress, useStoreEvents, useEditorContext, noticeContexts, } from '@woocommerce/base-context'; import { CheckboxControl, StoreNoticesContainer, } from '@woocommerce/blocks-checkout'; import Noninteractive from '@woocommerce/base-components/noninteractive'; import type { BillingAddress, ShippingAddress, AddressField, AddressFields, } from '@woocommerce/settings'; /** * Internal dependencies */ import PhoneNumber from '../../phone-number'; const Block = ( { showCompanyField = false, showApartmentField = false, showPhoneField = false, requireCompanyField = false, requirePhoneField = false, }: { showCompanyField: boolean; showApartmentField: boolean; showPhoneField: boolean; requireCompanyField: boolean; requirePhoneField: boolean; } ): JSX.Element => { const { defaultAddressFields, setShippingAddress, setBillingAddress, shippingAddress, billingAddress, setShippingPhone, useShippingAsBilling, setUseShippingAsBilling, } = useCheckoutAddress(); const { dispatchCheckoutEvent } = useStoreEvents(); const { isEditor } = useEditorContext(); const { email } = billingAddress; // This is used to track whether the "Use shipping as billing" checkbox was checked on first load and if we synced // the shipping address to the billing address if it was. This is not used on further toggles of the checkbox. const [ addressesSynced, setAddressesSynced ] = useState( false ); // Clears data if fields are hidden. useEffect( () => { if ( ! showPhoneField ) { setShippingPhone( '' ); } }, [ showPhoneField, setShippingPhone ] ); // Run this on first render to ensure addresses sync if needed, there is no need to re-run this when toggling the // checkbox. useEffect( () => { if ( addressesSynced ) { return; } if ( useShippingAsBilling ) { setBillingAddress( { ...shippingAddress, email } ); } setAddressesSynced( true ); }, // Skip the `email` dependency since we don't want to re-run if that changes, but we do want to sync it on first render. // eslint-disable-next-line react-hooks/exhaustive-deps [ addressesSynced, setBillingAddress, shippingAddress, useShippingAsBilling, ] ); const addressFieldsConfig = useMemo( () => { return { company: { hidden: ! showCompanyField, required: requireCompanyField, }, address_2: { hidden: ! showApartmentField, }, }; }, [ showCompanyField, requireCompanyField, showApartmentField, ] ) as Record< keyof AddressFields, Partial< AddressField > >; const AddressFormWrapperComponent = isEditor ? Noninteractive : Fragment; const noticeContext = useShippingAsBilling ? [ noticeContexts.SHIPPING_ADDRESS, noticeContexts.BILLING_ADDRESS ] : [ noticeContexts.SHIPPING_ADDRESS ]; return ( <> ) => { setShippingAddress( values ); if ( useShippingAsBilling ) { setBillingAddress( { ...values, email } ); dispatchCheckoutEvent( 'set-billing-address' ); } dispatchCheckoutEvent( 'set-shipping-address' ); } } values={ shippingAddress } fields={ Object.keys( defaultAddressFields ) as ( keyof AddressFields )[] } fieldConfig={ addressFieldsConfig } /> { showPhoneField && ( { setShippingPhone( value ); dispatchCheckoutEvent( 'set-phone-number', { step: 'shipping', } ); } } /> ) } { setUseShippingAsBilling( checked ); if ( checked ) { setBillingAddress( shippingAddress as BillingAddress ); } } } /> ); }; export default Block;