8889841cPK [©àR°Ò Ò customer-address.tsxnu„[µü¤/** * External dependencies */ import { useState, useCallback, useEffect } from '@wordpress/element'; import { AddressForm } from '@woocommerce/base-components/cart-checkout'; import { useCheckoutAddress, useStoreEvents } from '@woocommerce/base-context'; import type { BillingAddress, AddressField, AddressFields, } from '@woocommerce/settings'; import { useSelect } from '@wordpress/data'; import { VALIDATION_STORE_KEY } from '@woocommerce/block-data'; /** * Internal dependencies */ import AddressWrapper from '../../address-wrapper'; import AddressCard from '../../address-card'; const CustomerAddress = ( { addressFieldsConfig, defaultEditing = false, }: { addressFieldsConfig: Record< keyof AddressFields, Partial< AddressField > >; defaultEditing?: boolean; } ) => { const { defaultAddressFields, billingAddress, setShippingAddress, setBillingAddress, useBillingAsShipping, } = useCheckoutAddress(); const { dispatchCheckoutEvent } = useStoreEvents(); const [ editing, setEditing ] = useState( defaultEditing ); // Forces editing state if store has errors. const { hasValidationErrors, invalidProps } = useSelect( ( select ) => { const store = select( VALIDATION_STORE_KEY ); return { hasValidationErrors: store.hasValidationErrors(), invalidProps: Object.keys( billingAddress ) .filter( ( key ) => { return ( key !== 'email' && store.getValidationError( 'billing_' + key ) !== undefined ); } ) .filter( Boolean ), }; } ); useEffect( () => { if ( invalidProps.length > 0 && editing === false ) { setEditing( true ); } }, [ editing, hasValidationErrors, invalidProps.length ] ); const addressFieldKeys = Object.keys( defaultAddressFields ) as ( keyof AddressFields )[]; const onChangeAddress = useCallback( ( values: Partial< BillingAddress > ) => { setBillingAddress( values ); if ( useBillingAsShipping ) { setShippingAddress( values ); dispatchCheckoutEvent( 'set-shipping-address' ); } dispatchCheckoutEvent( 'set-billing-address' ); }, [ dispatchCheckoutEvent, setBillingAddress, setShippingAddress, useBillingAsShipping, ] ); const renderAddressCardComponent = useCallback( () => ( { setEditing( true ); } } fieldConfig={ addressFieldsConfig } /> ), [ billingAddress, addressFieldsConfig ] ); const renderAddressFormComponent = useCallback( () => ( <> ), [ addressFieldKeys, addressFieldsConfig, billingAddress, onChangeAddress, ] ); return ( ); }; export default CustomerAddress; PK [øÊþ]XX block.jsonnu„[µü¤{ "name": "woocommerce/checkout-billing-address-block", "version": "1.0.0", "title": "Billing Address", "description": "Collect your customer's billing address.", "category": "woocommerce", "supports": { "align": false, "html": false, "multiple": false, "reusable": false, "inserter": false, "lock": false }, "attributes": { "lock": { "type": "object", "default": { "remove": true, "move": true } } }, "parent": [ "woocommerce/checkout-fields-block" ], "textdomain": "woocommerce", "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2 } PK [*ñtÀ››edit.tsxnu„[µü¤/** * External dependencies */ import classnames from 'classnames'; import { useBlockProps } from '@wordpress/block-editor'; import { useCheckoutAddress } from '@woocommerce/base-context/hooks'; import { innerBlockAreas } from '@woocommerce/blocks-checkout'; import type { BlockAttributes } from '@wordpress/blocks'; /** * Internal dependencies */ import { FormStepBlock, AdditionalFields, AdditionalFieldsContent, } from '../../form-step'; import { useCheckoutBlockContext, useCheckoutBlockControlsContext, } from '../../context'; import Block from './block'; import { getBillingAddresssBlockTitle, getBillingAddresssBlockDescription, } from './utils'; export const Edit = ( { attributes, setAttributes, }: { attributes: { title: string; description: string; showStepNumber: boolean; className: string; }; setAttributes: ( attributes: BlockAttributes ) => void; } ): JSX.Element | null => { const { showCompanyField, showApartmentField, requireCompanyField, showPhoneField, requirePhoneField, } = useCheckoutBlockContext(); const { addressFieldControls: Controls } = useCheckoutBlockControlsContext(); const { showBillingFields, forcedBillingAddress, useBillingAsShipping } = useCheckoutAddress(); if ( ! showBillingFields && ! useBillingAsShipping ) { return null; } attributes.title = getBillingAddresssBlockTitle( attributes.title, forcedBillingAddress ); attributes.description = getBillingAddresssBlockDescription( attributes.description, forcedBillingAddress ); return ( ); }; export const Save = (): JSX.Element => { return (
); }; PK [°&A//attributes.tsxnu„[µü¤/** * External dependencies */ import type { BlockAttributes } from '@wordpress/blocks'; /** * Internal dependencies */ import formStepAttributes from '../../form-step/attributes'; import { DEFAULT_TITLE, DEFAULT_DESCRIPTION } from './constants'; const attributes: BlockAttributes = { ...formStepAttributes( { defaultTitle: DEFAULT_TITLE, defaultDescription: DEFAULT_DESCRIPTION, } ), className: { type: 'string', default: '', }, lock: { type: 'object', default: { move: true, remove: true, }, }, }; export default attributes; PK [’<šš frontend.tsxnu„[µü¤/** * External dependencies */ import classnames from 'classnames'; import { withFilteredAttributes } from '@woocommerce/shared-hocs'; import { FormStep } from '@woocommerce/blocks-components'; import { useCheckoutAddress } from '@woocommerce/base-context/hooks'; import { useSelect } from '@wordpress/data'; import { CHECKOUT_STORE_KEY } from '@woocommerce/block-data'; /** * Internal dependencies */ import Block from './block'; import attributes from './attributes'; import { useCheckoutBlockContext } from '../../context'; import { getBillingAddresssBlockTitle, getBillingAddresssBlockDescription, } from './utils'; const FrontendBlock = ( { title, description, showStepNumber, children, className, }: { title: string; description: string; showStepNumber: boolean; children: JSX.Element; className?: string; } ): JSX.Element | null => { const checkoutIsProcessing = useSelect( ( select ) => select( CHECKOUT_STORE_KEY ).isProcessing() ); const { requireCompanyField, requirePhoneField, showApartmentField, showCompanyField, showPhoneField, } = useCheckoutBlockContext(); const { showBillingFields, forcedBillingAddress, useBillingAsShipping } = useCheckoutAddress(); if ( ! showBillingFields && ! useBillingAsShipping ) { return null; } title = getBillingAddresssBlockTitle( title, forcedBillingAddress ); description = getBillingAddresssBlockDescription( description, forcedBillingAddress ); return ( { children } ); }; export default withFilteredAttributes( attributes )( FrontendBlock ); PK [©`¶áá utils.tsxnu„[µü¤/** * Internal dependencies */ import { DEFAULT_TITLE, DEFAULT_DESCRIPTION, DEFAULT_FORCED_BILLING_DESCRIPTION, DEFAULT_FORCED_BILLING_TITLE, } from './constants'; export const getBillingAddresssBlockTitle = ( title: string, forcedBillingAddress: boolean ): string => { if ( forcedBillingAddress ) { // Returns default forced billing title when forced billing address is enabled and there is no title set. return title === DEFAULT_TITLE ? DEFAULT_FORCED_BILLING_TITLE : title; } // Returns default title when forced billing address is disabled and there is no title set. return title === DEFAULT_FORCED_BILLING_TITLE ? DEFAULT_TITLE : title; }; export const getBillingAddresssBlockDescription = ( description: string, forcedBillingAddress: boolean ): string => { if ( forcedBillingAddress ) { // Returns default forced billing description when forced billing address is enabled and there is no description set. return description === DEFAULT_DESCRIPTION ? DEFAULT_FORCED_BILLING_DESCRIPTION : description; } // Returns default description when forced billing address is disabled and there is no description set. return description === DEFAULT_FORCED_BILLING_DESCRIPTION ? DEFAULT_DESCRIPTION : description; }; PK [!N¶wàà index.tsxnu„[µü¤/** * External dependencies */ import { Icon, mapMarker } from '@wordpress/icons'; import { registerBlockType } from '@wordpress/blocks'; /** * Internal dependencies */ import { Edit, Save } from './edit'; import attributes from './attributes'; registerBlockType( 'woocommerce/checkout-billing-address-block', { icon: { src: ( ), }, attributes, edit: Edit, save: Save, } ); PK [è'"2 2 block.tsxnu„[µü¤/** * External dependencies */ import { useMemo, Fragment } from '@wordpress/element'; import { useEffectOnce } from 'usehooks-ts'; import { useCheckoutAddress, useEditorContext, noticeContexts, } from '@woocommerce/base-context'; import Noninteractive from '@woocommerce/base-components/noninteractive'; import type { ShippingAddress, AddressField, AddressFields, } from '@woocommerce/settings'; import { StoreNoticesContainer } from '@woocommerce/blocks-components'; import { useSelect } from '@wordpress/data'; import { CART_STORE_KEY } from '@woocommerce/block-data'; import isShallowEqual from '@wordpress/is-shallow-equal'; /** * Internal dependencies */ import CustomerAddress from './customer-address'; 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 { shippingAddress, billingAddress, setShippingAddress, useBillingAsShipping, } = useCheckoutAddress(); const { isEditor } = useEditorContext(); // Syncs shipping address with billing address if "Force shipping to the customer billing address" is enabled. useEffectOnce( () => { if ( useBillingAsShipping ) { const { email, ...addressValues } = billingAddress; const syncValues: Partial< ShippingAddress > = { ...addressValues, }; if ( ! showPhoneField ) { delete syncValues.phone; } if ( showCompanyField ) { delete syncValues.company; } setShippingAddress( syncValues ); } } ); const addressFieldsConfig = useMemo( () => { return { company: { hidden: ! showCompanyField, required: requireCompanyField, }, address_2: { hidden: ! showApartmentField, }, phone: { hidden: ! showPhoneField, required: requirePhoneField, }, }; }, [ showCompanyField, requireCompanyField, showApartmentField, showPhoneField, requirePhoneField, ] ) as Record< keyof AddressFields, Partial< AddressField > >; const WrapperComponent = isEditor ? Noninteractive : Fragment; const noticeContext = useBillingAsShipping ? [ noticeContexts.BILLING_ADDRESS, noticeContexts.SHIPPING_ADDRESS ] : [ noticeContexts.BILLING_ADDRESS ]; const { cartDataLoaded } = useSelect( ( select ) => { const store = select( CART_STORE_KEY ); return { cartDataLoaded: store.hasFinishedResolution( 'getCartData' ), }; } ); // Default editing state for CustomerAddress component comes from the current address and whether or not we're in the editor. const hasAddress = !! ( billingAddress.address_1 && ( billingAddress.first_name || billingAddress.last_name ) ); const { email, ...billingAddressWithoutEmail } = billingAddress; const billingMatchesShipping = isShallowEqual( billingAddressWithoutEmail, shippingAddress ); const defaultEditingAddress = isEditor || ! hasAddress || billingMatchesShipping; return ( <> { cartDataLoaded ? ( ) : null } ); }; export default Block; PK [™³á¶EE constants.tsxnu„[µü¤/** * External dependencies */ import { __ } from '@wordpress/i18n'; export const DEFAULT_TITLE = __( 'Billing address', 'woo-gutenberg-products-block' ); export const DEFAULT_DESCRIPTION = __( 'Enter the billing address that matches your payment method.', 'woo-gutenberg-products-block' ); export const DEFAULT_FORCED_BILLING_TITLE = __( 'Billing and shipping address', 'woo-gutenberg-products-block' ); export const DEFAULT_FORCED_BILLING_DESCRIPTION = __( 'Enter the billing and shipping address that matches your payment method.', 'woo-gutenberg-products-block' ); PK [©àR°Ò Ò customer-address.tsxnu„[µü¤PK [øÊþ]XX  block.jsonnu„[µü¤PK [*ñtÀ››¨edit.tsxnu„[µü¤PK [°&A//{attributes.tsxnu„[µü¤PK [’<šš èfrontend.tsxnu„[µü¤PK [©`¶áá '"utils.tsxnu„[µü¤PK [!N¶wàà A'index.tsxnu„[µü¤PK [è'"2 2 Z)block.tsxnu„[µü¤PK [™³á¶EE Å6constants.tsxnu„[µü¤PK ¨G9