diff --git a/assets/js/base/context/hooks/payment-methods/use-payment-method-interface.ts b/assets/js/base/context/hooks/payment-methods/use-payment-method-interface.ts index 0a8ae83c3a8..b5dc3eceef9 100644 --- a/assets/js/base/context/hooks/payment-methods/use-payment-method-interface.ts +++ b/assets/js/base/context/hooks/payment-methods/use-payment-method-interface.ts @@ -40,6 +40,9 @@ export const usePaymentMethodInterface = (): PaymentMethodInterface => { onCheckoutAfterProcessingWithSuccess, onCheckoutAfterProcessingWithError, onSubmit, + onCheckoutSuccess, + onCheckoutFail, + onCheckoutValidation, } = useCheckoutEventsContext(); const { isCalculating, isComplete, isIdle, isProcessing, customerId } = @@ -111,7 +114,7 @@ export const usePaymentMethodInterface = (): PaymentMethodInterface => { const { __internalSetExpressPaymentError } = useDispatch( PAYMENT_STORE_KEY ); - const { onPaymentProcessing } = usePaymentEventsContext(); + const { onPaymentProcessing, onPaymentSetup } = usePaymentEventsContext(); const { shippingErrorStatus, shippingErrorTypes, @@ -210,7 +213,11 @@ export const usePaymentMethodInterface = (): PaymentMethodInterface => { onCheckoutAfterProcessingWithSuccess, onCheckoutBeforeProcessing, onCheckoutValidationBeforeProcessing, + onCheckoutSuccess, + onCheckoutFail, + onCheckoutValidation, onPaymentProcessing, + onPaymentSetup, onShippingRateFail, onShippingRateSelectFail, onShippingRateSelectSuccess, diff --git a/assets/js/base/context/providers/cart-checkout/checkout-events/event-emit.ts b/assets/js/base/context/providers/cart-checkout/checkout-events/event-emit.ts index 1f2043c59af..a8826a10def 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-events/event-emit.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-events/event-emit.ts @@ -17,12 +17,9 @@ import { // These events are emitted when the Checkout status is BEFORE_PROCESSING and AFTER_PROCESSING // to enable third parties to hook into the checkout process const EVENTS = { - CHECKOUT_VALIDATION_BEFORE_PROCESSING: - 'checkout_validation_before_processing', - CHECKOUT_AFTER_PROCESSING_WITH_SUCCESS: - 'checkout_after_processing_with_success', - CHECKOUT_AFTER_PROCESSING_WITH_ERROR: - 'checkout_after_processing_with_error', + CHECKOUT_SUCCESS: 'checkout_success', + CHECKOUT_FAIL: 'checkout_fail', + CHECKOUT_VALIDATION: 'checkout_validation', }; type EventEmittersType = Record< string, ReturnType< typeof emitterCallback > >; @@ -43,16 +40,16 @@ const useEventEmitters = ( ): EventEmittersType => { const eventEmitters = useMemo( () => ( { - onCheckoutAfterProcessingWithSuccess: emitterCallback( - EVENTS.CHECKOUT_AFTER_PROCESSING_WITH_SUCCESS, + onCheckoutSuccess: emitterCallback( + EVENTS.CHECKOUT_SUCCESS, observerDispatch ), - onCheckoutAfterProcessingWithError: emitterCallback( - EVENTS.CHECKOUT_AFTER_PROCESSING_WITH_ERROR, + onCheckoutFail: emitterCallback( + EVENTS.CHECKOUT_FAIL, observerDispatch ), - onCheckoutValidationBeforeProcessing: emitterCallback( - EVENTS.CHECKOUT_VALIDATION_BEFORE_PROCESSING, + onCheckoutValidation: emitterCallback( + EVENTS.CHECKOUT_VALIDATION, observerDispatch ), } ), diff --git a/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx b/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx index 16fc2484166..ff888086b7f 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx +++ b/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx @@ -35,22 +35,31 @@ import { useEditorContext } from '../../editor-context'; type CheckoutEventsContextType = { // Submits the checkout and begins processing. onSubmit: () => void; - // Used to register a callback that will fire after checkout has been processed and there are no errors. + // Deprecated in favour of onCheckoutSuccess. onCheckoutAfterProcessingWithSuccess: ReturnType< typeof emitterCallback >; - // Used to register a callback that will fire when the checkout has been processed and has an error. + // Deprecated in favour of onCheckoutFail. onCheckoutAfterProcessingWithError: ReturnType< typeof emitterCallback >; // Deprecated in favour of onCheckoutValidationBeforeProcessing. onCheckoutBeforeProcessing: ReturnType< typeof emitterCallback >; - // Used to register a callback that will fire when the checkout has been submitted before being sent off to the server. + // Deprecated in favour of onCheckoutValidation. onCheckoutValidationBeforeProcessing: ReturnType< typeof emitterCallback >; + // Used to register a callback that will fire if the api call to /checkout is successful + onCheckoutSuccess: ReturnType< typeof emitterCallback >; + // Used to register a callback that will fire if the api call to /checkout fails + onCheckoutFail: ReturnType< typeof emitterCallback >; + // Used to register a callback that will fire when the checkout performs validation on the form + onCheckoutValidation: ReturnType< typeof emitterCallback >; }; const CheckoutEventsContext = createContext< CheckoutEventsContextType >( { onSubmit: () => void null, - onCheckoutAfterProcessingWithSuccess: () => () => void null, - onCheckoutAfterProcessingWithError: () => () => void null, + onCheckoutAfterProcessingWithSuccess: () => () => void null, // deprecated for onCheckoutSuccess + onCheckoutAfterProcessingWithError: () => () => void null, // deprecated for onCheckoutFail onCheckoutBeforeProcessing: () => () => void null, // deprecated for onCheckoutValidationBeforeProcessing - onCheckoutValidationBeforeProcessing: () => () => void null, + onCheckoutValidationBeforeProcessing: () => () => void null, // deprecated for onCheckoutValidation + onCheckoutSuccess: () => () => void null, + onCheckoutFail: () => () => void null, + onCheckoutValidation: () => () => void null, } ); export const useCheckoutEventsContext = () => { @@ -159,11 +168,8 @@ export const CheckoutEventsProvider = ( { const [ observers, observerDispatch ] = useReducer( emitReducer, {} ); const currentObservers = useRef( observers ); - const { - onCheckoutAfterProcessingWithSuccess, - onCheckoutAfterProcessingWithError, - onCheckoutValidationBeforeProcessing, - } = useEventEmitters( observerDispatch ); + const { onCheckoutValidation, onCheckoutSuccess, onCheckoutFail } = + useEventEmitters( observerDispatch ); // set observers on ref so it's always current. useEffect( () => { @@ -171,7 +177,7 @@ export const CheckoutEventsProvider = ( { }, [ observers ] ); /** - * @deprecated use onCheckoutValidationBeforeProcessing instead + * @deprecated use onCheckoutValidation instead * * To prevent the deprecation message being shown at render time * we need an extra function between useMemo and event emitters @@ -180,16 +186,59 @@ export const CheckoutEventsProvider = ( { * See: https://github.com/woocommerce/woocommerce-gutenberg-products-block/pull/4039/commits/a502d1be8828848270993264c64220731b0ae181 */ const onCheckoutBeforeProcessing = useMemo( () => { - return function ( - ...args: Parameters< typeof onCheckoutValidationBeforeProcessing > - ) { + return function ( ...args: Parameters< typeof onCheckoutValidation > ) { deprecated( 'onCheckoutBeforeProcessing', { - alternative: 'onCheckoutValidationBeforeProcessing', + alternative: 'onCheckoutValidation', + plugin: 'WooCommerce Blocks', + } ); + return onCheckoutValidation( ...args ); + }; + }, [ onCheckoutValidation ] ); + + /** + * @deprecated use onCheckoutValidation instead + */ + const onCheckoutValidationBeforeProcessing = useMemo( () => { + return function ( ...args: Parameters< typeof onCheckoutValidation > ) { + deprecated( 'onCheckoutValidationBeforeProcessing', { + since: '9.7.0', + alternative: 'onCheckoutValidation', + plugin: 'WooCommerce Blocks', + link: 'https://github.com/woocommerce/woocommerce-blocks/pull/8381', + } ); + return onCheckoutValidation( ...args ); + }; + }, [ onCheckoutValidation ] ); + + /** + * @deprecated use onCheckoutSuccess instead + */ + const onCheckoutAfterProcessingWithSuccess = useMemo( () => { + return function ( ...args: Parameters< typeof onCheckoutSuccess > ) { + deprecated( 'onCheckoutAfterProcessingWithSuccess', { + since: '9.7.0', + alternative: 'onCheckoutSuccess', + plugin: 'WooCommerce Blocks', + link: 'https://github.com/woocommerce/woocommerce-blocks/pull/8381', + } ); + return onCheckoutSuccess( ...args ); + }; + }, [ onCheckoutSuccess ] ); + + /** + * @deprecated use onCheckoutFail instead + */ + const onCheckoutAfterProcessingWithError = useMemo( () => { + return function ( ...args: Parameters< typeof onCheckoutFail > ) { + deprecated( 'onCheckoutAfterProcessingWithError', { + since: '9.7.0', + alternative: 'onCheckoutFail', plugin: 'WooCommerce Blocks', + link: 'https://github.com/woocommerce/woocommerce-blocks/pull/8381', } ); - return onCheckoutValidationBeforeProcessing( ...args ); + return onCheckoutFail( ...args ); }; - }, [ onCheckoutValidationBeforeProcessing ] ); + }, [ onCheckoutFail ] ); // Emit CHECKOUT_VALIDATE event and set the error state based on the response of // the registered callbacks @@ -209,7 +258,7 @@ export const CheckoutEventsProvider = ( { const previousStatus = usePrevious( checkoutStatus ); const previousHasError = usePrevious( checkoutHasError ); - // Emit CHECKOUT_AFTER_PROCESSING_WITH_SUCCESS and CHECKOUT_AFTER_PROCESSING_WITH_ERROR events + // Emit CHECKOUT_SUCCESS and CHECKOUT_FAIL events // and set checkout errors according to the callback responses useEffect( () => { if ( @@ -258,6 +307,9 @@ export const CheckoutEventsProvider = ( { onCheckoutValidationBeforeProcessing, onCheckoutAfterProcessingWithSuccess, onCheckoutAfterProcessingWithError, + onCheckoutSuccess, + onCheckoutFail, + onCheckoutValidation, }; return ( diff --git a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts index 0428c215b5b..6d9de6979af 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts @@ -47,7 +47,7 @@ import { useStoreCart } from '../../hooks/cart/use-store-cart'; * Subscribes to checkout context and triggers processing via the API. */ const CheckoutProcessor = () => { - const { onCheckoutValidationBeforeProcessing } = useCheckoutEventsContext(); + const { onCheckoutValidation } = useCheckoutEventsContext(); const { hasError: checkoutHasError, @@ -188,10 +188,7 @@ const CheckoutProcessor = () => { useEffect( () => { let unsubscribeProcessing: () => void; if ( ! isExpressPaymentMethodActive ) { - unsubscribeProcessing = onCheckoutValidationBeforeProcessing( - checkValidation, - 0 - ); + unsubscribeProcessing = onCheckoutValidation( checkValidation, 0 ); } return () => { if ( @@ -202,7 +199,7 @@ const CheckoutProcessor = () => { } }; }, [ - onCheckoutValidationBeforeProcessing, + onCheckoutValidation, checkValidation, isExpressPaymentMethodActive, ] ); diff --git a/assets/js/base/context/providers/cart-checkout/payment-events/event-emit.ts b/assets/js/base/context/providers/cart-checkout/payment-events/event-emit.ts index edfd16d1ffa..af211ca4b86 100644 --- a/assets/js/base/context/providers/cart-checkout/payment-events/event-emit.ts +++ b/assets/js/base/context/providers/cart-checkout/payment-events/event-emit.ts @@ -15,7 +15,7 @@ import { } from '../../../event-emit'; const EMIT_TYPES = { - PAYMENT_PROCESSING: 'payment_processing', + PAYMENT_SETUP: 'payment_setup', }; type EventEmittersType = Record< string, ReturnType< typeof emitterCallback > >; @@ -36,8 +36,8 @@ const useEventEmitters = ( ): EventEmittersType => { const eventEmitters = useMemo( () => ( { - onPaymentProcessing: emitterCallback( - EMIT_TYPES.PAYMENT_PROCESSING, + onPaymentSetup: emitterCallback( + EMIT_TYPES.PAYMENT_SETUP, observerDispatch ), } ), diff --git a/assets/js/base/context/providers/cart-checkout/payment-events/index.tsx b/assets/js/base/context/providers/cart-checkout/payment-events/index.tsx index d9b61713597..76da086024b 100644 --- a/assets/js/base/context/providers/cart-checkout/payment-events/index.tsx +++ b/assets/js/base/context/providers/cart-checkout/payment-events/index.tsx @@ -7,6 +7,7 @@ import { useReducer, useRef, useEffect, + useMemo, } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { @@ -14,6 +15,7 @@ import { PAYMENT_STORE_KEY, VALIDATION_STORE_KEY, } from '@woocommerce/block-data'; +import deprecated from '@wordpress/deprecated'; /** * Internal dependencies @@ -24,10 +26,12 @@ import { emitterCallback } from '../../../event-emit'; type PaymentEventsContextType = { // Event registration callback for registering observers for the payment processing event. onPaymentProcessing: ReturnType< typeof emitterCallback >; + onPaymentSetup: ReturnType< typeof emitterCallback >; }; const PaymentEventsContext = createContext< PaymentEventsContextType >( { onPaymentProcessing: () => () => () => void null, + onPaymentSetup: () => () => () => void null, } ); export const usePaymentEventsContext = () => { @@ -65,7 +69,7 @@ export const PaymentEventsProvider = ( { const store = select( PAYMENT_STORE_KEY ); return { - // The PROCESSING status represents befor the checkout runs the observers + // The PROCESSING status represents before the checkout runs the observers // registered for the payment_setup event. isPaymentProcessing: store.isPaymentProcessing(), // the READY status represents when the observers have finished processing and payment data @@ -76,7 +80,7 @@ export const PaymentEventsProvider = ( { const { setValidationErrors } = useDispatch( VALIDATION_STORE_KEY ); const [ observers, observerDispatch ] = useReducer( emitReducer, {} ); - const { onPaymentProcessing } = useEventEmitters( observerDispatch ); + const { onPaymentSetup } = useEventEmitters( observerDispatch ); const currentObservers = useRef( observers ); // ensure observers are always current. @@ -131,8 +135,22 @@ export const PaymentEventsProvider = ( { } }, [ checkoutHasError, isPaymentReady, __internalSetPaymentIdle ] ); + /** + * @deprecated use onPaymentSetup instead + */ + const onPaymentProcessing = useMemo( () => { + return function ( ...args: Parameters< typeof onPaymentSetup > ) { + deprecated( 'onPaymentProcessing', { + alternative: 'onPaymentSetup', + plugin: 'WooCommerce Blocks', + } ); + return onPaymentSetup( ...args ); + }; + }, [ onPaymentSetup ] ); + const paymentContextData = { onPaymentProcessing, + onPaymentSetup, }; return ( diff --git a/assets/js/data/checkout/thunks.ts b/assets/js/data/checkout/thunks.ts index 3cfaab29165..07c7062723b 100644 --- a/assets/js/data/checkout/thunks.ts +++ b/assets/js/data/checkout/thunks.ts @@ -12,8 +12,8 @@ import { STORE_KEY as PAYMENT_STORE_KEY } from '../payment/constants'; import { removeNoticesByStatus } from '../../utils/notices'; import { getPaymentResultFromCheckoutResponse, - runCheckoutAfterProcessingWithErrorObservers, - runCheckoutAfterProcessingWithSuccessObservers, + runCheckoutFailObservers, + runCheckoutSuccessObservers, } from './utils'; import { EVENTS, @@ -52,7 +52,7 @@ export const __internalProcessCheckoutResponse = ( }; /** - * Emit the CHECKOUT_VALIDATION_BEFORE_PROCESSING event and process all + * Emit the CHECKOUT_VALIDATION event and process all * registered observers */ export const __internalEmitValidateEvent: emitValidateEventType = ( { @@ -62,36 +62,34 @@ export const __internalEmitValidateEvent: emitValidateEventType = ( { return ( { dispatch, registry } ) => { const { createErrorNotice } = registry.dispatch( noticesStore ); removeNoticesByStatus( 'error' ); - emitEvent( - observers, - EVENTS.CHECKOUT_VALIDATION_BEFORE_PROCESSING, - {} - ).then( ( response ) => { - if ( response !== true ) { - if ( Array.isArray( response ) ) { - response.forEach( - ( { - errorMessage, - validationErrors, - context = 'wc/checkout', - } ) => { - createErrorNotice( errorMessage, { context } ); - setValidationErrors( validationErrors ); - } - ); + emitEvent( observers, EVENTS.CHECKOUT_VALIDATION, {} ).then( + ( response ) => { + if ( response !== true ) { + if ( Array.isArray( response ) ) { + response.forEach( + ( { + errorMessage, + validationErrors, + context = 'wc/checkout', + } ) => { + createErrorNotice( errorMessage, { context } ); + setValidationErrors( validationErrors ); + } + ); + } + dispatch.__internalSetIdle(); + dispatch.__internalSetHasError(); + } else { + dispatch.__internalSetProcessing(); } - dispatch.__internalSetIdle(); - dispatch.__internalSetHasError(); - } else { - dispatch.__internalSetProcessing(); } - } ); + ); }; }; /** - * Emit the CHECKOUT_AFTER_PROCESSING_WITH_ERROR if the checkout contains an error, - * or the CHECKOUT_AFTER_PROCESSING_WITH_SUCCESS if not. Set checkout errors according + * Emit the CHECKOUT_FAIL if the checkout contains an error, + * or the CHECKOUT_SUCCESS if not. Set checkout errors according * to the observer responses */ export const __internalEmitAfterProcessingEvents: emitAfterProcessingEventsType = @@ -111,10 +109,10 @@ export const __internalEmitAfterProcessingEvents: emitAfterProcessingEventsType // with a fallback if nothing customizes it. emitEventWithAbort( observers, - EVENTS.CHECKOUT_AFTER_PROCESSING_WITH_ERROR, + EVENTS.CHECKOUT_FAIL, data ).then( ( observerResponses ) => { - runCheckoutAfterProcessingWithErrorObservers( { + runCheckoutFailObservers( { observerResponses, notices, dispatch, @@ -125,10 +123,10 @@ export const __internalEmitAfterProcessingEvents: emitAfterProcessingEventsType } else { emitEventWithAbort( observers, - EVENTS.CHECKOUT_AFTER_PROCESSING_WITH_SUCCESS, + EVENTS.CHECKOUT_SUCCESS, data ).then( ( observerResponses: unknown[] ) => { - runCheckoutAfterProcessingWithSuccessObservers( { + runCheckoutSuccessObservers( { observerResponses, dispatch, createErrorNotice, diff --git a/assets/js/data/checkout/utils.ts b/assets/js/data/checkout/utils.ts index b87d6958dee..64ccab4967b 100644 --- a/assets/js/data/checkout/utils.ts +++ b/assets/js/data/checkout/utils.ts @@ -55,11 +55,11 @@ export const handleErrorResponse = ( { }; /** - * This functions runs after the CHECKOUT_AFTER_PROCESSING_WITH_ERROR event has been triggered and + * This functions runs after the CHECKOUT_FAIL event has been triggered and * all observers have been processed. It sets any Error Notices and the status of the Checkout * based on the observer responses */ -export const runCheckoutAfterProcessingWithErrorObservers = ( { +export const runCheckoutFailObservers = ( { observerResponses, notices, dispatch, @@ -115,11 +115,11 @@ export const runCheckoutAfterProcessingWithErrorObservers = ( { }; /** - * This functions runs after the CHECKOUT_AFTER_PROCESSING_WITH_SUCCESS event has been triggered and + * This functions runs after the CHECKOUT_SUCCESS event has been triggered and * all observers have been processed. It sets any Error Notices and the status of the Checkout * based on the observer responses */ -export const runCheckoutAfterProcessingWithSuccessObservers = ( { +export const runCheckoutSuccessObservers = ( { observerResponses, dispatch, createErrorNotice, @@ -159,7 +159,7 @@ export const runCheckoutAfterProcessingWithSuccessObservers = ( { dispatch.__internalSetComplete( errorResponse ); } else { // this will set an error which will end up - // triggering the onCheckoutAfterProcessingWithError emitter. + // triggering the onCheckoutFail emitter. // and then setting checkout to IDLE state. dispatch.__internalSetHasError( true ); } diff --git a/assets/js/data/payment/test/thunks.tsx b/assets/js/data/payment/test/thunks.tsx index d3377df4303..b8c3f14948d 100644 --- a/assets/js/data/payment/test/thunks.tsx +++ b/assets/js/data/payment/test/thunks.tsx @@ -38,13 +38,13 @@ describe( 'wc/store/payment thunks', () => { const testPaymentProcessingCallback = jest.fn(); const testPaymentProcessingCallback2 = jest.fn(); const currentObservers: EventObserversType = { - payment_processing: new Map(), + payment_setup: new Map(), }; - currentObservers.payment_processing.set( 'test', { + currentObservers.payment_setup.set( 'test', { callback: testPaymentProcessingCallback, priority: 10, } ); - currentObservers.payment_processing.set( 'test2', { + currentObservers.payment_setup.set( 'test2', { callback: testPaymentProcessingCallback2, priority: 10, } ); @@ -76,7 +76,7 @@ describe( 'wc/store/payment thunks', () => { }, } ); - currentObservers.payment_processing.set( 'test3', { + currentObservers.payment_setup.set( 'test3', { callback: testSuccessCallbackWithMetadata, priority: 10, } ); @@ -129,7 +129,7 @@ describe( 'wc/store/payment thunks', () => { }, } ); - currentObservers.payment_processing.set( 'test4', { + currentObservers.payment_setup.set( 'test4', { callback: testFailingCallbackWithMetadata, priority: 10, } ); @@ -181,11 +181,11 @@ describe( 'wc/store/payment thunks', () => { type: 'success', } ); - currentObservers.payment_processing.set( 'test5', { + currentObservers.payment_setup.set( 'test5', { callback: testErrorCallbackWithMetadata, priority: 10, } ); - currentObservers.payment_processing.set( 'test6', { + currentObservers.payment_setup.set( 'test6', { callback: testSuccessCallback, priority: 9, } ); diff --git a/assets/js/data/payment/thunks.ts b/assets/js/data/payment/thunks.ts index d3fb85ab359..f0cec900b52 100644 --- a/assets/js/data/payment/thunks.ts +++ b/assets/js/data/payment/thunks.ts @@ -58,7 +58,7 @@ export const __internalEmitPaymentProcessingEvent: emitProcessingEventType = ( removeNotice( 'wc-payment-error', noticeContexts.PAYMENTS ); return emitEventWithAbort( currentObserver, - EMIT_TYPES.PAYMENT_PROCESSING, + EMIT_TYPES.PAYMENT_SETUP, {} ).then( ( observerResponses ) => { let successResponse: ObserverResponse | undefined, diff --git a/assets/js/types/type-defs/payment-method-interface.ts b/assets/js/types/type-defs/payment-method-interface.ts index 4b05bb6e924..b3f8b7683fa 100644 --- a/assets/js/types/type-defs/payment-method-interface.ts +++ b/assets/js/types/type-defs/payment-method-interface.ts @@ -87,16 +87,24 @@ export interface EmitResponseProps { } export interface EventRegistrationProps { - // Used to subscribe callbacks firing when checkout has completed processing with an error. + // Deprecated in favour of onCheckoutFail. onCheckoutAfterProcessingWithError: ReturnType< typeof emitterCallback >; - // Used to subscribe callbacks firing when checkout has completed processing successfully. + // Deprecated in favour of onCheckoutSuccess. onCheckoutAfterProcessingWithSuccess: ReturnType< typeof emitterCallback >; // Used to subscribe callbacks firing before checkout begins processing. onCheckoutBeforeProcessing: ReturnType< typeof emitterCallback >; - // Used to subscribe callbacks firing when validation of the submitted checkout data happens, before it's sent off to the server. + // Used to register a callback that will fire if the api call to /checkout is successful + onCheckoutSuccess: ReturnType< typeof emitterCallback >; + // Used to register a callback that will fire if the api call to /checkout fails + onCheckoutFail: ReturnType< typeof emitterCallback >; + // Used to register a callback that will fire when the checkout performs validation on the form + onCheckoutValidation: ReturnType< typeof emitterCallback >; + // Deprecated in favour of onCheckoutValidation. onCheckoutValidationBeforeProcessing: ReturnType< typeof emitterCallback >; - // Event registration callback for registering observers for the payment processing event. + // Deprecated in favour of onPaymentSetup onPaymentProcessing: ReturnType< typeof emitterCallback >; + // Event registration callback for registering observers for the payment setup event. + onPaymentSetup: ReturnType< typeof emitterCallback >; // Used to subscribe callbacks that will fire when retrieving shipping rates failed. onShippingRateFail: ReturnType< typeof emitterCallback >; // Used to subscribe callbacks that will fire after selecting a shipping rate unsuccessfully. diff --git a/docs/internal-developers/block-client-apis/checkout/checkout-api.md b/docs/internal-developers/block-client-apis/checkout/checkout-api.md index ee7d4a0ba03..ea8afbd495d 100644 --- a/docs/internal-developers/block-client-apis/checkout/checkout-api.md +++ b/docs/internal-developers/block-client-apis/checkout/checkout-api.md @@ -102,9 +102,9 @@ The payment method events context exposes any event handlers related to payments The checkout events contexy exposes any event handlers related to the processing of the checkout: - `onSubmit`: This is a callback to be invoked either by submitting the checkout button, or by express payment methods to start checkout processing after they have finished their initialization process when their button has been clicked. -- `onCheckoutValidationBeforeProcessing`: Used to register observers that will be invoked at validation time, after the checkout has been submitted but before the processing request is sent to the server. -- `onCheckoutAfterProcessingWithSuccess`: Used to register observers that will be invoked after checkout has been processed by the server successfully. -- `onCheckoutAfterProcessingWithError`: Used to register observers that will be invoked after checkout has been processed by the server and there was an error. +- `onCheckoutValidation`: Used to register observers that will be invoked at validation time, after the checkout has been submitted but before the processing request is sent to the server. +- `onCheckoutSuccess`: Used to register observers that will be invoked after checkout has been processed by the server successfully. +- `onCheckoutError`: Used to register observers that will be invoked after checkout has been processed by the server and there was an error. ## Hooks diff --git a/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md b/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md index 2f85077e151..77a0bb7e96a 100644 --- a/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md +++ b/docs/internal-developers/block-client-apis/checkout/checkout-flow-and-events.md @@ -9,13 +9,13 @@ - [`ShippingProvider` Exposed Statuses](#shippingprovider-exposed-statuses) - [Payment Method Data Store Status](#payment-method-data-store-status) - [Emitting Events](#emitting-events) - - [`onCheckoutValidationBeforeProcessing`](#oncheckoutvalidationbeforeprocessing) + - [`onCheckoutValidation`](#onCheckoutValidation) - [`onPaymentProcessing`](#onpaymentprocessing) - [Success](#success) - [Fail](#fail) - [Error](#error) - - [`onCheckoutAfterProcessingWithSuccess`](#oncheckoutafterprocessingwithsuccess) - - [`onCheckoutAfterProcessingWithError`](#oncheckoutafterprocessingwitherror) + - [`onCheckoutSuccess`](#oncheckoutsuccess) + - [`onCheckoutFail`](#oncheckoutfail) - [`onShippingRateSuccess`](#onshippingratesuccess) - [`onShippingRateFail`](#onshippingratefail) - [`onShippingRateSelectSuccess`](#onshippingrateselectsuccess) @@ -146,16 +146,16 @@ One _**very important rule**_ when it comes to observers registered to any event const unsubscribe = emitter( myCallback ); ``` -You could substitute in whatever emitter you are registering for the `emitter` function. So for example if you are registering for the `onCheckoutValidationBeforeProcessing` event emitter, you'd have something like: +You could substitute in whatever emitter you are registering for the `emitter` function. So for example if you are registering for the `onCheckoutValidation` event emitter, you'd have something like: ```jsx -const unsubscribe = onCheckoutValidationBeforeProcessing( myCallback ); +const unsubscribe = onCheckoutValidation( myCallback ); ``` You can also indicate what priority you want your observer to execute at. Lower priority is run before higher priority, so you can affect when your observer will run in the stack of observers registered to an emitter. You indicate priority via an number on the second argument: ```jsx -const unsubscribe = onCheckoutValidationBeforeProcessing( myCallback, 10 ); +const unsubscribe = onCheckoutValidation( myCallback, 10 ); ``` In the examples, `myCallback`, is your subscriber function. The subscriber function could receive data from the event emitter (described in the emitter details below) and may be expected to return a response in a specific shape (also described in the specific emitter details). The subscriber function can be a `Promise` and when the event emitter cycles through the registered observers it will await for any registered Promise to resolve. @@ -163,11 +163,11 @@ In the examples, `myCallback`, is your subscriber function. The subscriber funct Finally, the return value of the call to the emitter function is an unsubscribe function that can be used to unregister your observer. This is especially useful in a React component context where you need to make sure you unsubscribe the observer on component unmount. An example is usage in a `useEffect` hook: ```jsx -const MyComponent = ( { onCheckoutValidationBeforeProcessing } ) => { +const MyComponent = ( { onCheckoutValidation } ) => { useEffect( () => { - const unsubscribe = onCheckoutValidationBeforeProcessing( () => true ); + const unsubscribe = onCheckoutValidation( () => true ); return unsubscribe; - }, [ onCheckoutValidationBeforeProcessing ] ); + }, [ onCheckoutValidation ] ); return null; }; ``` @@ -195,7 +195,7 @@ The helper functions are described below: - `PAYMENTS`: This is a reference to the notice area in the payment methods step. - `EXPRESS_PAYMENTS`: This is a reference to the notice area in the express payment methods step. - `responseTypes`: This is an object containing properties referencing the various response types that can be returned by observers for some event emitters. It makes it easier for autocompleting the types and avoiding typos due to human error. The types are `SUCCESS`, `FAIL`, `ERROR`. The values for these types also correspond to the [payment status types](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/Payments/PaymentResult.php#L21) from the [checkout endpoint response from the server](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/RestApi/StoreApi/Schemas/CheckoutSchema.php#L103-L113). -- `shouldRetry`: This is a function containing the logic whether the checkout flow should allow the user to retry the payment after a previous payment failed. It receives the `response` object and by default checks whether the `retry` property is true/undefined or false. Refer to the [`onCheckoutAfterProcessingWithSuccess`](#oncheckoutafterprocessingwithsuccess) documentation for more details. +- `shouldRetry`: This is a function containing the logic whether the checkout flow should allow the user to retry the payment after a previous payment failed. It receives the `response` object and by default checks whether the `retry` property is true/undefined or false. Refer to the [`onCheckoutSuccess`](#oncheckoutsuccess) documentation for more details. Note: `noticeContexts` and `responseTypes` are exposed to payment methods via the `emitResponse` prop given to their component: @@ -208,7 +208,7 @@ const MyPaymentMethodComponent = ( { emitResponse } ) => { The following event emitters are available to extensions to register observers to: -### `onCheckoutValidationBeforeProcessing` +### `onCheckoutValidation` Observers registered to this event emitter will receive nothing as an argument. Also, all observers will be executed before the checkout handles the responses from the emitters. Observers registered to this emitter can return `true` if they have nothing to communicate back to checkout, `false` if they want checkout to go back to `IDLE` status state, or an object with any of the following properties: @@ -229,11 +229,11 @@ import { useCheckoutContext } from '@woocommerce/base-contexts'; import { useEffect } from '@wordpress/element'; const Component = () => { - const { onCheckoutValidationBeforeProcessing } = useCheckoutContext(); + const { onCheckoutValidation } = useCheckoutContext(); useEffect( () => { - const unsubscribe = onCheckoutValidationBeforeProcessing( () => true ); + const unsubscribe = onCheckoutValidation( () => true ); return unsubscribe; - }, [ onCheckoutValidationBeforeProcessing ] ); + }, [ onCheckoutValidation ] ); return null; }; ``` @@ -244,11 +244,11 @@ _For registered payment method components:_ import { useEffect } from '@wordpress/element'; const PaymentMethodComponent = ( { eventRegistration } ) => { - const { onCheckoutValidationBeforeProcessing } = eventRegistration; + const { onCheckoutValidation } = eventRegistration; useEffect( () => { - const unsubscribe = onCheckoutValidationBeforeProcessing( () => true ); + const unsubscribe = onCheckoutValidation( () => true ); return unsubscribe; - }, [ onCheckoutValidationBeforeProcessing ] ); + }, [ onCheckoutValidation ] ); }; ``` @@ -342,9 +342,9 @@ const PaymentMethodComponent = ( { eventRegistration } ) => { }; ``` -### `onCheckoutAfterProcessingWithSuccess` +### `onCheckoutSuccess` -This event emitter is fired when the checkout context status is `AFTER_PROCESSING` and the checkout `hasError` state is false. The `AFTER_PROCESSING` status is set by the `CheckoutProcessor` component after receiving a response from the server for the checkout processing request. +This event emitter is fired when the checkout status is `AFTER_PROCESSING` and the checkout `hasError` state is false. The `AFTER_PROCESSING` status is set by the `CheckoutProcessor` component after receiving a response from the server for the checkout processing request. Observers registered to this event emitter will receive the following object as an argument: @@ -392,11 +392,11 @@ import { useCheckoutContext } from '@woocommerce/base-contexts'; import { useEffect } from '@wordpress/element'; const Component = () => { - const { onCheckoutAfterProcessingWithSuccess } = useCheckoutContext(); + const { onCheckoutSuccess } = useCheckoutContext(); useEffect( () => { - const unsubscribe = onCheckoutAfterProcessingWithSuccess( () => true ); + const unsubscribe = onCheckoutSuccess( () => true ); return unsubscribe; - }, [ onCheckoutAfterProcessingWithSuccess ] ); + }, [ onCheckoutSuccess ] ); return null; }; ``` @@ -407,21 +407,21 @@ _For registered payment method components:_ import { useEffect } from '@wordpress/element'; const PaymentMethodComponent = ( { eventRegistration } ) => { - const { onCheckoutAfterProcessingWithSuccess } = eventRegistration; + const { onCheckoutSuccess } = eventRegistration; useEffect( () => { - const unsubscribe = onCheckoutAfterProcessingWithSuccess( () => true ); + const unsubscribe = onCheckoutSuccess( () => true ); return unsubscribe; - }, [ onCheckoutAfterProcessingWithSuccess ] ); + }, [ onCheckoutSuccess ] ); }; ``` -### `onCheckoutAfterProcessingWithError` +### `onCheckoutFail` -This event emitter is fired when the checkout context status is `AFTER_PROCESSING` and the checkout `hasError` state is `true`. The `AFTER_PROCESSING` status is set by the `CheckoutProcessor` component after receiving a response from the server for the checkout processing request. +This event emitter is fired when the checkout status is `AFTER_PROCESSING` and the checkout `hasError` state is `true`. The `AFTER_PROCESSING` status is set by the `CheckoutProcessor` component after receiving a response from the server for the checkout processing request. -Observers registered to this emitter will receive the same data package as those registered to `onCheckoutAfterProcessingWithSuccess`. +Observers registered to this emitter will receive the same data package as those registered to `onCheckoutSuccess`. -The response from the first observer returning a value that does not `===` true will be handled similarly as the `onCheckoutAfterProcessingWithSuccess` except it only handles when the type is `error` or `failure`. +The response from the first observer returning a value that does not `===` true will be handled similarly as the `onCheckoutSuccess` except it only handles when the type is `error` or `failure`. If all observers return `true`, then the checkout status will just be set to `IDLE` and a default error notice will be shown in the checkout context. @@ -434,11 +434,11 @@ import { useCheckoutContext } from '@woocommerce/base-contexts'; import { useEffect } from '@wordpress/element'; const Component = () => { - const { onCheckoutAfterProcessingWithError } = useCheckoutContext(); + const { onCheckoutFail } = useCheckoutContext(); useEffect( () => { - const unsubscribe = onCheckoutAfterProcessingWithError( () => true ); + const unsubscribe = onCheckoutFail( () => true ); return unsubscribe; - }, [ onCheckoutAfterProcessingWithError ] ); + }, [ onCheckoutFail ] ); return null; }; ``` @@ -449,11 +449,11 @@ _For registered payment method components:_ import { useEffect } from '@wordpress/element'; const PaymentMethodComponent = ( { eventRegistration } ) => { - const { onCheckoutAfterProcessingWithError } = eventRegistration; + const { onCheckoutFail } = eventRegistration; useEffect( () => { - const unsubscribe = onCheckoutAfterProcessingWithError( () => true ); + const unsubscribe = onCheckoutFail( () => true ); return unsubscribe; - }, [ onCheckoutAfterProcessingWithError ] ); + }, [ onCheckoutFail ] ); }; ``` diff --git a/docs/internal-developers/testing/cart-checkout/data-stores.md b/docs/internal-developers/testing/cart-checkout/data-stores.md index 88220021ece..e8686e5ad6e 100644 --- a/docs/internal-developers/testing/cart-checkout/data-stores.md +++ b/docs/internal-developers/testing/cart-checkout/data-stores.md @@ -110,31 +110,30 @@ export const usePaymentProcessing = ( In the location linked in point 3, add the following: -#### `onCheckoutValidationBeforeProcessing` +#### `onCheckoutValidation` ```js -const unsubscribeValidationBeforeProcessing = - eventRegistration.onCheckoutValidationBeforeProcessing( ( a ) => { - console.log( 'onCheckoutValidationBeforeProcessing', a ); - } ); +const unsubscribeValidation = eventRegistration.onCheckoutValidation( ( a ) => { + console.log( 'onCheckoutValidation', a ); +} ); ``` -#### `onCheckoutAfterProcessingWithError` +#### `onCheckoutFail` ```js -const unsubscribeOnCheckoutAfterProcessingWithError = - eventRegistration.onCheckoutAfterProcessingWithError( ( a ) => { - console.log( 'onCheckoutAfterProcessingWithError', a ); - } ); +const unsubscribeOnCheckoutFail = eventRegistration.onCheckoutFail( ( a ) => { + console.log( 'onCheckoutFail', a ); +} ); ``` -#### `onCheckoutAfterProcessingWithSuccess` +#### `onCheckoutSuccess` ```js -const unsubscribeOnCheckoutAfterProcessingWithSuccess = - eventRegistration.onCheckoutAfterProcessingWithSuccess( ( a ) => { - console.log( 'onCheckoutAfterProcessingWithSuccess', a ); - } ); +const unsubscribeOnCheckoutSuccess = eventRegistration.onCheckoutSuccess( + ( a ) => { + console.log( 'onCheckoutSuccess', a ); + } +); ``` #### `onCheckoutBeforeProcessing` (deprecated) @@ -150,10 +149,10 @@ const unsubscribeOnCheckoutBeforeProcessing = Then, in the returned function, [https://github.com/woocommerce/woocommerce-gateway-stripe/blob/8ffd22aff3b06eda02a1ae2fd8368b71450b36a9/client/blocks/credit-card/use-payment-processing.js#L147-L149](https://github.com/woocommerce/woocommerce-gateway-stripe/blob/8ffd22aff3b06eda02a1ae2fd8368b71450b36a9/client/blocks/credit-card/use-payment-processing.js#L147-L149) below, add: ```js +unsubscribeOnCheckoutValidation(); +unsubscribeOnCheckoutSuccess(); +unsubscribeOnCheckoutFail(); unsubscribeOnCheckoutBeforeProcessing(); -unsubscribeOnCheckoutAfterProcessingWithSuccess(); -unsubscribeOnCheckoutAfterProcessingWithError(); -unsubscribeValidationBeforeProcessing(); ``` After these changes have been made, your file should look like this: [https://gist.github.com/opr/1f71e72ea8bee0a58d33f6f0412af51f](https://gist.github.com/opr/1f71e72ea8bee0a58d33f6f0412af51f) @@ -170,19 +169,19 @@ After these changes have been made, your file should look like this: [https://gi - Check out using a valid card. You should see a message telling you `onCheckoutBeforeProcessing` is deprecated then when you check out you should see, in the same order, the following logs: - - `onCheckoutValidationBeforeProcessing` `{}` + - `onCheckoutValidation` `{}` - `onCheckoutBeforeProcessing` `{}` - - `onCheckoutAfterProcessingWithSuccess` `{redirectUrl, orderId, customerId, orderNotes, paymentResult } + - `onCheckoutSuccess` `{redirectUrl, orderId, customerId, orderNotes, paymentResult } - Check out using an invalid card, you should only see: - - `onCheckoutValidationBeforeProcessing` `{}` + - `onCheckoutValidation` `{}` - `onCheckoutBeforeProcessing` `{}` - Reload the checkout page and then go to [https://github.com/woocommerce/woocommerce-blocks/blob/029b379138906872dec3ed920fcb23d24404a3f2/src/StoreApi/Schemas/V1/CheckoutSchema.php#L26-L25](https://github.com/woocommerce/woocommerce-blocks/blob/029b379138906872dec3ed920fcb23d24404a3f2/src/StoreApi/Schemas/V1/CheckoutSchema.php#L26-L25) and introduce a syntax error. Try to check out using a valid card, then an invalid card you should see: - - `onCheckoutValidationBeforeProcessing` `{}` + - `onCheckoutValidation` `{}` - `onCheckoutBeforeProcessing` `{}` - - `onCheckoutAfterProcessingWithError` `{redirectUrl, orderId, customerId, orderNotes, paymentResult }` + - `onCheckoutFail` `{redirectUrl, orderId, customerId, orderNotes, paymentResult }` ## WordPress.com diff --git a/docs/third-party-developers/extensibility/checkout-payment-methods/payment-method-integration.md b/docs/third-party-developers/extensibility/checkout-payment-methods/payment-method-integration.md index 57b7217b205..b0218add8e5 100644 --- a/docs/third-party-developers/extensibility/checkout-payment-methods/payment-method-integration.md +++ b/docs/third-party-developers/extensibility/checkout-payment-methods/payment-method-integration.md @@ -169,7 +169,7 @@ A big part of the payment method integration is the interface that is exposed fo | `checkoutStatus` | Object | The current checkout status exposed as various boolean state. | `isCalculating`, `isComplete`, `isIdle`, `isProcessing` | | `components` | Object | It exposes React components that can be implemented by your payment method for various common interface elements used by payment methods. | | | `emitResponse` | Object | Contains some constants that can be helpful when using the event emitter. Read the _[Emitting Events](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e267cd96a4329a4eeef816b2ef627e113ebb72a5/docs/extensibility/checkout-flow-and-events.md#emitting-events)_ section for more details. | | -| `eventRegistration` | object | Contains all the checkout event emitter registration functions. These are functions the payment method can register observers on to interact with various points in the checkout flow (see [this doc](./checkout-flow-and-events.md) for more info). | `onCheckoutValidationBeforeProcessing`, `onCheckoutAfterProcessingWithSuccess`, `onCheckoutAfterProcessingWithError`, `onPaymentProcessing`, `onShippingRateSuccess`, `onShippingRateFail`, `onShippingRateSelectSuccess`, `onShippingRateSelectFail` | +| `eventRegistration` | object | Contains all the checkout event emitter registration functions. These are functions the payment method can register observers on to interact with various points in the checkout flow (see [this doc](./checkout-flow-and-events.md) for more info). | `onCheckoutValidation`, `onCheckoutSuccess`, `onCheckoutFail`, `onPaymentProcessing`, `onShippingRateSuccess`, `onShippingRateFail`, `onShippingRateSelectSuccess`, `onShippingRateSelectFail` | | `onClick` | Function | **Provided to express payment methods** that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing) | - | | `onClose` | Function | **Provided to express payment methods** that should be triggered when the express payment method modal closes and control is returned to checkout. | - | | `onSubmit` | Function | Submits the checkout and begins processing | - |