From 527d4da142b22b2d92d45266a27bcf76569ee048 Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Wed, 4 Jan 2023 16:34:33 +0000 Subject: [PATCH 01/14] WIP --- assets/js/data/payment/actions.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/js/data/payment/actions.ts b/assets/js/data/payment/actions.ts index f1c735111a5..7264105da59 100644 --- a/assets/js/data/payment/actions.ts +++ b/assets/js/data/payment/actions.ts @@ -37,6 +37,10 @@ export const __internalSetPaymentReady = () => ( { type: ACTION_TYPES.SET_PAYMENT_READY, } ); +export const __internalSetPaymentReady = () => ( { + type: ACTION_TYPES.SET_PAYMENT_READY, +} ); + /** * Set whether the payment methods have been initialised or not * From fe747940ff459e06751a164424933ca9ef86aa74 Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Mon, 9 Jan 2023 11:51:10 +0000 Subject: [PATCH 02/14] Deprecate isPaymentPristine and undeprecate isPaymentStarted --- assets/js/data/payment/action-types.ts | 1 + assets/js/data/payment/constants.ts | 1 + assets/js/data/payment/reducers.ts | 7 +++++++ 3 files changed, 9 insertions(+) diff --git a/assets/js/data/payment/action-types.ts b/assets/js/data/payment/action-types.ts index 5e4a57613a0..baa3d83b7ff 100644 --- a/assets/js/data/payment/action-types.ts +++ b/assets/js/data/payment/action-types.ts @@ -1,4 +1,5 @@ export enum ACTION_TYPES { + SET_PAYMENT_PRISTINE = 'SET_PAYMENT_PRISTINE', SET_PAYMENT_IDLE = 'SET_PAYMENT_IDLE', SET_EXPRESS_PAYMENT_STARTED = 'SET_EXPRESS_PAYMENT_STARTED', SET_PAYMENT_READY = 'SET_PAYMENT_READY', diff --git a/assets/js/data/payment/constants.ts b/assets/js/data/payment/constants.ts index 9f4ccd0f72b..85f8962abdf 100644 --- a/assets/js/data/payment/constants.ts +++ b/assets/js/data/payment/constants.ts @@ -1,6 +1,7 @@ export const STORE_KEY = 'wc/store/payment'; export enum STATUS { + PRISTINE = 'pristine', IDLE = 'idle', EXPRESS_STARTED = 'express_started', PROCESSING = 'processing', diff --git a/assets/js/data/payment/reducers.ts b/assets/js/data/payment/reducers.ts index 800db3f45fb..b4a8adc5f82 100644 --- a/assets/js/data/payment/reducers.ts +++ b/assets/js/data/payment/reducers.ts @@ -17,6 +17,13 @@ const reducer: Reducer< PaymentState > = ( ) => { let newState = state; switch ( action.type ) { + case ACTION_TYPES.SET_PAYMENT_PRISTINE: + newState = { + ...state, + status: STATUS.PRISTINE, + }; + break; + case ACTION_TYPES.SET_PAYMENT_IDLE: newState = { ...state, From abb4308e1c4f290acf5026f357970c6b30b628da Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Mon, 9 Jan 2023 12:08:56 +0000 Subject: [PATCH 03/14] Set payment status to FAILED or SUCCESS when the storeAPI fetch returns --- .../context/providers/cart-checkout/checkout-processor.ts | 5 +++++ 1 file changed, 5 insertions(+) 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..951b016aa5c 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts @@ -107,6 +107,9 @@ const CheckoutProcessor = () => { }; }, [] ); + const { __internalSetPaymentFailed, __internalSetPaymentSuccess } = + useDispatch( PAYMENT_STORE_KEY ); + const paymentMethods = getPaymentMethods(); const expressPaymentMethods = getExpressPaymentMethods(); const currentBillingAddress = useRef( billingAddress ); @@ -259,6 +262,7 @@ const CheckoutProcessor = () => { if ( ! response.ok ) { throw response; } + __internalSetPaymentSuccess(); return response.json(); } ) .then( ( responseJson: CheckoutResponseSuccess ) => { @@ -266,6 +270,7 @@ const CheckoutProcessor = () => { setIsProcessingOrder( false ); } ) .catch( ( errorResponse: ApiResponse< CheckoutResponseError > ) => { + __internalSetPaymentFailed(); processCheckoutResponseHeaders( errorResponse?.headers ); try { // This attempts to parse a JSON error response where the status code was 4xx/5xx. From 55e642e416e7c1d321016ea375d5701607bb216c Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Fri, 20 Jan 2023 16:37:19 +0000 Subject: [PATCH 04/14] Remove FINISHED as a status --- .../context/providers/cart-checkout/checkout-processor.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 951b016aa5c..9c3687ebe8e 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts @@ -107,7 +107,7 @@ const CheckoutProcessor = () => { }; }, [] ); - const { __internalSetPaymentFailed, __internalSetPaymentSuccess } = + const { __internalSetPaymentError, __internalSetPaymentSuccess } = useDispatch( PAYMENT_STORE_KEY ); const paymentMethods = getPaymentMethods(); @@ -270,7 +270,7 @@ const CheckoutProcessor = () => { setIsProcessingOrder( false ); } ) .catch( ( errorResponse: ApiResponse< CheckoutResponseError > ) => { - __internalSetPaymentFailed(); + __internalSetPaymentError(); processCheckoutResponseHeaders( errorResponse?.headers ); try { // This attempts to parse a JSON error response where the status code was 4xx/5xx. From 099af5e98c25005397811f734a037b7264b5e2e9 Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Fri, 20 Jan 2023 16:48:11 +0000 Subject: [PATCH 05/14] Remove ready status --- .../context/providers/cart-checkout/checkout-processor.ts | 6 +++--- assets/js/data/payment/actions.ts | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) 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 9c3687ebe8e..9cbed789e24 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts @@ -92,7 +92,7 @@ const CheckoutProcessor = () => { paymentMethodData, isExpressPaymentMethodActive, hasPaymentError, - isPaymentReady, + isPaymentStarted, shouldSavePayment, } = useSelect( ( select ) => { const store = select( PAYMENT_STORE_KEY ); @@ -102,7 +102,7 @@ const CheckoutProcessor = () => { paymentMethodData: store.getPaymentMethodData(), isExpressPaymentMethodActive: store.isExpressPaymentMethodActive(), hasPaymentError: store.hasPaymentError(), - isPaymentReady: store.isPaymentReady(), + isPaymentStarted: store.isPaymentStarted(), shouldSavePayment: store.getShouldSavePaymentMethod(), }; }, [] ); @@ -133,7 +133,7 @@ const CheckoutProcessor = () => { const paidAndWithoutErrors = ! checkoutHasError && ! checkoutWillHaveError && - ( isPaymentReady || ! cartNeedsPayment ) && + ( isPaymentStarted || ! cartNeedsPayment ) && checkoutIsProcessing; // Determine if checkout has an error. diff --git a/assets/js/data/payment/actions.ts b/assets/js/data/payment/actions.ts index 7264105da59..f1c735111a5 100644 --- a/assets/js/data/payment/actions.ts +++ b/assets/js/data/payment/actions.ts @@ -37,10 +37,6 @@ export const __internalSetPaymentReady = () => ( { type: ACTION_TYPES.SET_PAYMENT_READY, } ); -export const __internalSetPaymentReady = () => ( { - type: ACTION_TYPES.SET_PAYMENT_READY, -} ); - /** * Set whether the payment methods have been initialised or not * From 76d10b3c9388a7783c94f7480f2bbcf55d7a80aa Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Fri, 20 Jan 2023 16:49:29 +0000 Subject: [PATCH 06/14] Revert "Remove FINISHED as a status" This reverts commit 38d66ed1d9565756d2373533c7a7c5b107a68ddd. --- .../context/providers/cart-checkout/checkout-processor.ts | 4 ++-- assets/js/data/payment/action-types.ts | 1 + assets/js/data/payment/actions.ts | 4 ++++ 3 files changed, 7 insertions(+), 2 deletions(-) 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 9cbed789e24..de9b1508efb 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts @@ -107,7 +107,7 @@ const CheckoutProcessor = () => { }; }, [] ); - const { __internalSetPaymentError, __internalSetPaymentSuccess } = + const { __internalSetPaymentFailed, __internalSetPaymentSuccess } = useDispatch( PAYMENT_STORE_KEY ); const paymentMethods = getPaymentMethods(); @@ -270,7 +270,7 @@ const CheckoutProcessor = () => { setIsProcessingOrder( false ); } ) .catch( ( errorResponse: ApiResponse< CheckoutResponseError > ) => { - __internalSetPaymentError(); + __internalSetPaymentFailed(); processCheckoutResponseHeaders( errorResponse?.headers ); try { // This attempts to parse a JSON error response where the status code was 4xx/5xx. diff --git a/assets/js/data/payment/action-types.ts b/assets/js/data/payment/action-types.ts index baa3d83b7ff..96a59c7e939 100644 --- a/assets/js/data/payment/action-types.ts +++ b/assets/js/data/payment/action-types.ts @@ -4,6 +4,7 @@ export enum ACTION_TYPES { SET_EXPRESS_PAYMENT_STARTED = 'SET_EXPRESS_PAYMENT_STARTED', SET_PAYMENT_READY = 'SET_PAYMENT_READY', SET_PAYMENT_PROCESSING = 'SET_PAYMENT_PROCESSING', + SET_PAYMENT_FAILED = 'SET_PAYMENT_FAILED', SET_PAYMENT_ERROR = 'SET_PAYMENT_ERROR', SET_PAYMENT_METHODS_INITIALIZED = 'SET_PAYMENT_METHODS_INITIALIZED', SET_EXPRESS_PAYMENT_METHODS_INITIALIZED = 'SET_EXPRESS_PAYMENT_METHODS_INITIALIZED', diff --git a/assets/js/data/payment/actions.ts b/assets/js/data/payment/actions.ts index f1c735111a5..b2f94a45a6a 100644 --- a/assets/js/data/payment/actions.ts +++ b/assets/js/data/payment/actions.ts @@ -29,6 +29,10 @@ export const __internalSetPaymentProcessing = () => ( { type: ACTION_TYPES.SET_PAYMENT_PROCESSING, } ); +export const __internalSetPaymentFailed = () => ( { + type: ACTION_TYPES.SET_PAYMENT_FAILED, +} ); + export const __internalSetPaymentError = () => ( { type: ACTION_TYPES.SET_PAYMENT_ERROR, } ); From b7b92892ec8ab7827e8102a8b4b1b77ce8685c16 Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Thu, 2 Feb 2023 15:46:13 +0000 Subject: [PATCH 07/14] Add payment status READY --- .../context/providers/cart-checkout/checkout-processor.ts | 6 +++--- assets/js/data/payment/actions.ts | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) 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 de9b1508efb..951b016aa5c 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts @@ -92,7 +92,7 @@ const CheckoutProcessor = () => { paymentMethodData, isExpressPaymentMethodActive, hasPaymentError, - isPaymentStarted, + isPaymentReady, shouldSavePayment, } = useSelect( ( select ) => { const store = select( PAYMENT_STORE_KEY ); @@ -102,7 +102,7 @@ const CheckoutProcessor = () => { paymentMethodData: store.getPaymentMethodData(), isExpressPaymentMethodActive: store.isExpressPaymentMethodActive(), hasPaymentError: store.hasPaymentError(), - isPaymentStarted: store.isPaymentStarted(), + isPaymentReady: store.isPaymentReady(), shouldSavePayment: store.getShouldSavePaymentMethod(), }; }, [] ); @@ -133,7 +133,7 @@ const CheckoutProcessor = () => { const paidAndWithoutErrors = ! checkoutHasError && ! checkoutWillHaveError && - ( isPaymentStarted || ! cartNeedsPayment ) && + ( isPaymentReady || ! cartNeedsPayment ) && checkoutIsProcessing; // Determine if checkout has an error. diff --git a/assets/js/data/payment/actions.ts b/assets/js/data/payment/actions.ts index b2f94a45a6a..a3c2e840d84 100644 --- a/assets/js/data/payment/actions.ts +++ b/assets/js/data/payment/actions.ts @@ -41,6 +41,10 @@ export const __internalSetPaymentReady = () => ( { type: ACTION_TYPES.SET_PAYMENT_READY, } ); +export const __internalSetPaymentReady = () => ( { + type: ACTION_TYPES.SET_PAYMENT_READY, +} ); + /** * Set whether the payment methods have been initialised or not * From 49a9f010621e6d9ee0388a8e2630d43497219a7b Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Thu, 2 Feb 2023 16:33:32 +0000 Subject: [PATCH 08/14] Removed payment statuses pristine, failed and success --- .../context/providers/cart-checkout/checkout-processor.ts | 5 ----- assets/js/data/payment/action-types.ts | 2 -- assets/js/data/payment/actions.ts | 4 ---- assets/js/data/payment/constants.ts | 1 - assets/js/data/payment/reducers.ts | 7 ------- 5 files changed, 19 deletions(-) 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 951b016aa5c..0428c215b5b 100644 --- a/assets/js/base/context/providers/cart-checkout/checkout-processor.ts +++ b/assets/js/base/context/providers/cart-checkout/checkout-processor.ts @@ -107,9 +107,6 @@ const CheckoutProcessor = () => { }; }, [] ); - const { __internalSetPaymentFailed, __internalSetPaymentSuccess } = - useDispatch( PAYMENT_STORE_KEY ); - const paymentMethods = getPaymentMethods(); const expressPaymentMethods = getExpressPaymentMethods(); const currentBillingAddress = useRef( billingAddress ); @@ -262,7 +259,6 @@ const CheckoutProcessor = () => { if ( ! response.ok ) { throw response; } - __internalSetPaymentSuccess(); return response.json(); } ) .then( ( responseJson: CheckoutResponseSuccess ) => { @@ -270,7 +266,6 @@ const CheckoutProcessor = () => { setIsProcessingOrder( false ); } ) .catch( ( errorResponse: ApiResponse< CheckoutResponseError > ) => { - __internalSetPaymentFailed(); processCheckoutResponseHeaders( errorResponse?.headers ); try { // This attempts to parse a JSON error response where the status code was 4xx/5xx. diff --git a/assets/js/data/payment/action-types.ts b/assets/js/data/payment/action-types.ts index 96a59c7e939..5e4a57613a0 100644 --- a/assets/js/data/payment/action-types.ts +++ b/assets/js/data/payment/action-types.ts @@ -1,10 +1,8 @@ export enum ACTION_TYPES { - SET_PAYMENT_PRISTINE = 'SET_PAYMENT_PRISTINE', SET_PAYMENT_IDLE = 'SET_PAYMENT_IDLE', SET_EXPRESS_PAYMENT_STARTED = 'SET_EXPRESS_PAYMENT_STARTED', SET_PAYMENT_READY = 'SET_PAYMENT_READY', SET_PAYMENT_PROCESSING = 'SET_PAYMENT_PROCESSING', - SET_PAYMENT_FAILED = 'SET_PAYMENT_FAILED', SET_PAYMENT_ERROR = 'SET_PAYMENT_ERROR', SET_PAYMENT_METHODS_INITIALIZED = 'SET_PAYMENT_METHODS_INITIALIZED', SET_EXPRESS_PAYMENT_METHODS_INITIALIZED = 'SET_EXPRESS_PAYMENT_METHODS_INITIALIZED', diff --git a/assets/js/data/payment/actions.ts b/assets/js/data/payment/actions.ts index a3c2e840d84..7264105da59 100644 --- a/assets/js/data/payment/actions.ts +++ b/assets/js/data/payment/actions.ts @@ -29,10 +29,6 @@ export const __internalSetPaymentProcessing = () => ( { type: ACTION_TYPES.SET_PAYMENT_PROCESSING, } ); -export const __internalSetPaymentFailed = () => ( { - type: ACTION_TYPES.SET_PAYMENT_FAILED, -} ); - export const __internalSetPaymentError = () => ( { type: ACTION_TYPES.SET_PAYMENT_ERROR, } ); diff --git a/assets/js/data/payment/constants.ts b/assets/js/data/payment/constants.ts index 85f8962abdf..9f4ccd0f72b 100644 --- a/assets/js/data/payment/constants.ts +++ b/assets/js/data/payment/constants.ts @@ -1,7 +1,6 @@ export const STORE_KEY = 'wc/store/payment'; export enum STATUS { - PRISTINE = 'pristine', IDLE = 'idle', EXPRESS_STARTED = 'express_started', PROCESSING = 'processing', diff --git a/assets/js/data/payment/reducers.ts b/assets/js/data/payment/reducers.ts index b4a8adc5f82..800db3f45fb 100644 --- a/assets/js/data/payment/reducers.ts +++ b/assets/js/data/payment/reducers.ts @@ -17,13 +17,6 @@ const reducer: Reducer< PaymentState > = ( ) => { let newState = state; switch ( action.type ) { - case ACTION_TYPES.SET_PAYMENT_PRISTINE: - newState = { - ...state, - status: STATUS.PRISTINE, - }; - break; - case ACTION_TYPES.SET_PAYMENT_IDLE: newState = { ...state, From 5802a5be3f9b2df1a47bda2e13d2ba46122a4439 Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Thu, 2 Feb 2023 17:17:14 +0000 Subject: [PATCH 09/14] Remove deprecated selectors and update docs --- .../context/providers/cart-checkout/payment-events/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..e14f71dc9c1 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 @@ -65,7 +65,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 From 2912b2598f1c3490cb9d73b332eab0bccc84e048 Mon Sep 17 00:00:00 2001 From: Alex Florisca Date: Fri, 3 Feb 2023 16:28:37 +0000 Subject: [PATCH 10/14] Rename the checkout events --- .../use-payment-method-interface.ts | 9 ++- .../checkout-events/event-emit.ts | 21 +++-- .../cart-checkout/checkout-events/index.tsx | 80 +++++++++++++++---- .../cart-checkout/checkout-processor.ts | 9 +-- .../payment-events/event-emit.ts | 6 +- .../cart-checkout/payment-events/index.tsx | 20 ++++- assets/js/data/checkout/thunks.ts | 60 +++++++------- assets/js/data/checkout/utils.ts | 10 +-- assets/js/data/payment/thunks.ts | 2 +- .../type-defs/payment-method-interface.ts | 16 +++- .../checkout/checkout-api.md | 6 +- .../checkout/checkout-flow-and-events.md | 70 ++++++++-------- .../testing/cart-checkout/data-stores.md | 45 +++++------ .../payment-method-integration.md | 2 +- 14 files changed, 213 insertions(+), 143 deletions(-) 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..e6673378420 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( () => { @@ -180,16 +186,53 @@ 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', plugin: 'WooCommerce Blocks', } ); - return onCheckoutValidationBeforeProcessing( ...args ); + return onCheckoutValidation( ...args ); + }; + }, [ onCheckoutValidation ] ); + + /** + * @deprecated use onCheckoutValidation instead + */ + const onCheckoutValidationBeforeProcessing = useMemo( () => { + return function ( ...args: Parameters< typeof onCheckoutValidation > ) { + deprecated( 'onCheckoutValidationBeforeProcessing', { + alternative: 'onCheckoutValidation', + plugin: 'WooCommerce Blocks', + } ); + return onCheckoutValidation( ...args ); + }; + }, [ onCheckoutValidation ] ); + + /** + * @deprecated use onCheckoutSuccess instead + */ + const onCheckoutAfterProcessingWithSuccess = useMemo( () => { + return function ( ...args: Parameters< typeof onCheckoutSuccess > ) { + deprecated( 'onCheckoutAfterProcessingWithSuccess', { + alternative: 'onCheckoutSuccess', + plugin: 'WooCommerce Blocks', + } ); + return onCheckoutSuccess( ...args ); + }; + }, [ onCheckoutSuccess ] ); + + /** + * @deprecated use onCheckoutFail instead + */ + const onCheckoutAfterProcessingWithError = useMemo( () => { + return function ( ...args: Parameters< typeof onCheckoutFail > ) { + deprecated( 'onCheckoutAfterProcessingWithError', { + alternative: 'onCheckoutFail', + plugin: 'WooCommerce Blocks', + } ); + return onCheckoutFail( ...args ); }; - }, [ onCheckoutValidationBeforeProcessing ] ); + }, [ onCheckoutFail ] ); // Emit CHECKOUT_VALIDATE event and set the error state based on the response of // the registered callbacks @@ -209,7 +252,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_FAL events // and set checkout errors according to the callback responses useEffect( () => { if ( @@ -258,6 +301,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 e14f71dc9c1..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 = () => { @@ -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/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. |
  • `ValidationInputError`: a container for holding validation errors which typically you'll include after any inputs
  • [`PaymentMethodLabel`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e089ae17043fa525e8397d605f0f470959f2ae95/assets/js/payment-method-extensions/payment-methods/paypal/index.js#L37-L40): use this component for the payment method label, including an optional icon
  • `PaymentMethodIcons`: a React component used for displaying payment method icons
  • `LoadingMask`: a wrapper component that handles displaying a loading state when the isLoading prop is true. Exposes the [LoadingMask component](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c9074a4941919987dbad16a80f358b960336a09d/assets/js/base/components/loading-mask/index.js)
| | `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. |
  • `noticeContexts`: This is an object containing properties referencing areas where notices can be targeted in the checkout. The object has the following properties:
    • `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).
| -| `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 | - | From ebd0fa2e351202e0a48f52857767fc0bb63de72c Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Tue, 14 Feb 2023 13:17:22 +0000 Subject: [PATCH 11/14] Merge conflicts --- .../context/providers/cart-checkout/checkout-events/index.tsx | 2 +- assets/js/data/payment/actions.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) 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 e6673378420..0392acc44bf 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 @@ -252,7 +252,7 @@ export const CheckoutEventsProvider = ( { const previousStatus = usePrevious( checkoutStatus ); const previousHasError = usePrevious( checkoutHasError ); - // Emit CHECKOUT_SUCCESS and CHECKOUT_FAL events + // Emit CHECKOUT_SUCCESS and CHECKOUT_FAIL events // and set checkout errors according to the callback responses useEffect( () => { if ( diff --git a/assets/js/data/payment/actions.ts b/assets/js/data/payment/actions.ts index 7264105da59..f1c735111a5 100644 --- a/assets/js/data/payment/actions.ts +++ b/assets/js/data/payment/actions.ts @@ -37,10 +37,6 @@ export const __internalSetPaymentReady = () => ( { type: ACTION_TYPES.SET_PAYMENT_READY, } ); -export const __internalSetPaymentReady = () => ( { - type: ACTION_TYPES.SET_PAYMENT_READY, -} ); - /** * Set whether the payment methods have been initialised or not * From 92cf4138206d231d4a732acbd75e7e9243c22fe1 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Tue, 14 Feb 2023 14:00:40 +0000 Subject: [PATCH 12/14] Update test observer --- assets/js/data/payment/test/thunks.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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, } ); From 1351baf14aab38e37fa876931de5559de249cdb4 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Wed, 15 Feb 2023 16:57:09 +0000 Subject: [PATCH 13/14] Update deprecation notice --- .../context/providers/cart-checkout/checkout-events/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 0392acc44bf..f5798f8b41a 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 @@ -177,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 @@ -188,7 +188,7 @@ export const CheckoutEventsProvider = ( { const onCheckoutBeforeProcessing = useMemo( () => { return function ( ...args: Parameters< typeof onCheckoutValidation > ) { deprecated( 'onCheckoutBeforeProcessing', { - alternative: 'onCheckoutValidationBeforeProcessing', + alternative: 'onCheckoutValidation', plugin: 'WooCommerce Blocks', } ); return onCheckoutValidation( ...args ); From 6f51d550526d97e4af068931ae83301029a6a0a4 Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Wed, 15 Feb 2023 17:05:34 +0000 Subject: [PATCH 14/14] deprecation versions --- .../providers/cart-checkout/checkout-events/index.tsx | 6 ++++++ 1 file changed, 6 insertions(+) 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 f5798f8b41a..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 @@ -201,8 +201,10 @@ export const CheckoutEventsProvider = ( { 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 ); }; @@ -214,8 +216,10 @@ export const CheckoutEventsProvider = ( { 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 ); }; @@ -227,8 +231,10 @@ export const CheckoutEventsProvider = ( { 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 onCheckoutFail( ...args ); };