diff --git a/assets/js/blocks/cart-checkout-shared/address-fields/index.tsx b/assets/js/blocks/cart-checkout-shared/address-fields/index.tsx new file mode 100644 index 00000000000..114e7b08c69 --- /dev/null +++ b/assets/js/blocks/cart-checkout-shared/address-fields/index.tsx @@ -0,0 +1,154 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import { InspectorControls } from '@wordpress/block-editor'; +import { + PanelBody, + ToggleControl, + CheckboxControl, +} from '@wordpress/components'; +import { addFilter, hasFilter } from '@wordpress/hooks'; +import { useSelect } from '@wordpress/data'; +import { isString } from '@woocommerce/types'; + +interface Attributes extends Record< string, boolean | number > { + allowCreateAccount: boolean; + hasDarkControls: boolean; + showCompanyField: boolean; + showApartmentField: boolean; + showPhoneField: boolean; + requireCompanyField: boolean; + requirePhoneField: boolean; + // Deprecated. + showOrderNotes: boolean; + showPolicyLinks: boolean; + showReturnToCart: boolean; + showRateAfterTaxName: boolean; + cartPageId: number; +} + +const withAddressFields = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + const { clientId } = props; + const blockName = useSelect( ( select ) => { + return select( 'core/block-editor' ).getBlockName( clientId ); + } ); + const blocksWithAddressFields = [ + 'woocommerce/checkout-shipping-address', + 'woocommerce/checkout-billing-address', + 'woocommerce/checkout-fields-block', + ]; + + if ( + isString( blockName ) && + ! blocksWithAddressFields.includes( blockName ) + ) { + return ; + } + + const { attributes, setAttributes } = props; + const { + showCompanyField, + requireCompanyField, + showApartmentField, + showPhoneField, + requirePhoneField, + } = attributes; + + const toggleAttribute = ( key: keyof Attributes ): void => { + const newAttributes = {} as Partial< Attributes >; + newAttributes[ key ] = ! ( attributes[ key ] as boolean ); + setAttributes( newAttributes ); + }; + + return ( + <> + + +

+ { __( + 'Show or hide fields in the checkout address forms.', + 'woo-gutenberg-products-block' + ) } +

+ + toggleAttribute( 'showCompanyField' ) + } + /> + { showCompanyField && ( + + toggleAttribute( 'requireCompanyField' ) + } + className="components-base-control--nested" + /> + ) } + + toggleAttribute( 'showApartmentField' ) + } + /> + + toggleAttribute( 'showPhoneField' ) + } + /> + { showPhoneField && ( + + toggleAttribute( 'requirePhoneField' ) + } + className="components-base-control--nested" + /> + ) } +
+
+ + + + ); + }, + 'withAddressFields' +); + +if ( ! hasFilter( 'editor.BlockEdit', 'woocommerce/add/address-fields' ) ) { + addFilter( + 'editor.BlockEdit', + 'woocommerce/add/address-fields', + withAddressFields, + 9 + ); +} diff --git a/assets/js/blocks/cart-checkout-shared/index.js b/assets/js/blocks/cart-checkout-shared/index.js index 36a16f5804b..eb401bc3bc5 100644 --- a/assets/js/blocks/cart-checkout-shared/index.js +++ b/assets/js/blocks/cart-checkout-shared/index.js @@ -5,3 +5,4 @@ export * from './use-view-switcher'; export * from './default-notice'; export * from './sidebar-notices'; export * from './block-settings'; +export * from './address-fields'; diff --git a/assets/js/blocks/checkout/context.ts b/assets/js/blocks/checkout/context.ts index 7293a909e3a..07a87e5f306 100644 --- a/assets/js/blocks/checkout/context.ts +++ b/assets/js/blocks/checkout/context.ts @@ -21,12 +21,11 @@ export type CheckoutBlockContextProps = { }; export type CheckoutBlockControlsContextProps = { - addressFieldControls: () => JSX.Element | null; accountControls: () => JSX.Element | null; }; -export const CheckoutBlockContext = createContext< CheckoutBlockContextProps >( - { +export const CheckoutBlockContext: React.Context< CheckoutBlockContextProps > = + createContext< CheckoutBlockContextProps >( { allowCreateAccount: false, showCompanyField: false, showApartmentField: false, @@ -38,12 +37,10 @@ export const CheckoutBlockContext = createContext< CheckoutBlockContextProps >( showReturnToCart: true, cartPageId: 0, showRateAfterTaxName: false, - } -); + } ); -export const CheckoutBlockControlsContext = +export const CheckoutBlockControlsContext: React.Context< CheckoutBlockControlsContextProps > = createContext< CheckoutBlockControlsContextProps >( { - addressFieldControls: () => null, accountControls: () => null, } ); diff --git a/assets/js/blocks/checkout/edit.tsx b/assets/js/blocks/checkout/edit.tsx index 7c4f4a48649..00fea76f944 100644 --- a/assets/js/blocks/checkout/edit.tsx +++ b/assets/js/blocks/checkout/edit.tsx @@ -14,11 +14,7 @@ import { previewCart, previewSavedPaymentMethods, } from '@woocommerce/resource-previews'; -import { - PanelBody, - ToggleControl, - CheckboxControl, -} from '@wordpress/components'; +import { PanelBody, ToggleControl } from '@wordpress/components'; import type { TemplateArray } from '@wordpress/blocks'; /** * Internal dependencies @@ -68,12 +64,6 @@ export const Edit = ( { [ 'woocommerce/checkout-totals-block', {}, [] ], ] as TemplateArray; - const toggleAttribute = ( key: keyof Attributes ): void => { - const newAttributes = {} as Partial< Attributes >; - newAttributes[ key ] = ! ( attributes[ key ] as boolean ); - setAttributes( newAttributes ); - }; - const accountControls = (): JSX.Element => ( ); - const addressFieldControls = (): JSX.Element => ( - - -

- { __( - 'Show or hide fields in the checkout address forms.', - 'woo-gutenberg-products-block' - ) } -

- toggleAttribute( 'showCompanyField' ) } - /> - { showCompanyField && ( - - toggleAttribute( 'requireCompanyField' ) - } - className="components-base-control--nested" - /> - ) } - toggleAttribute( 'showApartmentField' ) } - /> - toggleAttribute( 'showPhoneField' ) } - /> - { showPhoneField && ( - - toggleAttribute( 'requirePhoneField' ) - } - className="components-base-control--nested" - /> - ) } -
-
- ); const blockProps = useBlockPropsWithLocking(); return (
@@ -176,7 +108,6 @@ export const Edit = ( { > diff --git a/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/edit.tsx b/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/edit.tsx index 692b9c4f20c..c3b15122b10 100644 --- a/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/edit.tsx +++ b/assets/js/blocks/checkout/inner-blocks/checkout-billing-address-block/edit.tsx @@ -14,10 +14,7 @@ import { AdditionalFields, AdditionalFieldsContent, } from '../../form-step'; -import { - useCheckoutBlockContext, - useCheckoutBlockControlsContext, -} from '../../context'; +import { useCheckoutBlockContext } from '../../context'; import Block from './block'; export const Edit = ( { @@ -39,8 +36,6 @@ export const Edit = ( { showPhoneField, requirePhoneField, } = useCheckoutBlockContext(); - const { addressFieldControls: Controls } = - useCheckoutBlockControlsContext(); const { showBillingFields } = useCheckoutAddress(); if ( ! showBillingFields ) { @@ -56,7 +51,6 @@ export const Edit = ( { attributes?.className ) } > - -
- { + // By returning false we ensure that this component is not entered into the InspectorControls + // (which is a slot fill), children array on first render, on the second render when the state + // gets updated this component does get put into the InspectorControls children array but as the + // last item, ensuring it shows last in the sidebar. + const [ isVisible, setIsVisible ] = useState( false ); + useEffect( () => { + setIsVisible( true ); + }, [] ); + return ( -
- -

- { __( 'Feedback?', 'woo-gutenberg-products-block' ) } -

-

{ text }

- - { __( - 'Give us your feedback.', - 'woo-gutenberg-products-block' - ) } - - -
+ isVisible && ( +
+ +

+ { __( 'Feedback?', 'woo-gutenberg-products-block' ) } +

+

{ text }

+ + { __( + 'Give us your feedback.', + 'woo-gutenberg-products-block' + ) } + + +
+ ) ); };