diff --git a/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx b/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx index c07a0325da0..24e2e07c799 100644 --- a/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx +++ b/plugins/woocommerce-blocks/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx @@ -197,7 +197,6 @@ export const CheckoutEventsProvider = ( { checkoutState.orderId, checkoutState.customerId, checkoutState.orderNotes, - checkoutState.paymentResult, previousStatus, previousHasError, createErrorNotice, diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/action-types.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/action-types.ts index 757ce54b161..4a06285a5f7 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/action-types.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/action-types.ts @@ -4,7 +4,6 @@ export const ACTION_TYPES = { SET_COMPLETE: 'SET_CHECKOUT_COMPLETE', SET_BEFORE_PROCESSING: 'SET_BEFORE_PROCESSING', SET_AFTER_PROCESSING: 'SET_AFTER_PROCESSING', - SET_PAYMENT_RESULT: 'SET_PAYMENT_RESULT', SET_PROCESSING: 'SET_CHECKOUT_IS_PROCESSING', SET_HAS_ERROR: 'SET_CHECKOUT_HAS_ERROR', SET_CUSTOMER_ID: 'SET_CHECKOUT_CUSTOMER_ID', diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts index 954b3a28a94..bd4863046c8 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/actions.ts @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import { PaymentResult } from '@woocommerce/types'; - /** * Internal dependencies */ @@ -60,16 +55,6 @@ export const __internalSetRedirectUrl = ( redirectUrl: string ) => ( { redirectUrl, } ); -/** - * Store the result of the payment attempt from the /checkout StoreApi call - * - * @param data The result of the payment attempt through the StoreApi /checkout endpoints - */ -export const __internalSetPaymentResult = ( data: PaymentResult ) => ( { - type: types.SET_PAYMENT_RESULT, - data, -} ); - /** * Set whether the checkout has an error or not * @@ -157,7 +142,6 @@ export type CheckoutAction = | typeof __internalSetIdle | typeof __internalSetComplete | typeof __internalSetProcessing - | typeof __internalSetPaymentResult | typeof __internalSetBeforeProcessing | typeof __internalSetAfterProcessing | typeof __internalSetRedirectUrl diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/default-state.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/default-state.ts index e8b39de06e5..53a346c5aba 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/default-state.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/default-state.ts @@ -2,7 +2,6 @@ * External dependencies */ import { isSameAddress } from '@woocommerce/base-utils'; -import { PaymentResult } from '@woocommerce/types'; /** * Internal dependencies @@ -14,8 +13,6 @@ export type CheckoutState = { status: STATUS; // If any of the totals, taxes, shipping, etc need to be calculated, the count will be increased here calculatingCount: number; - // The result of the payment processing - paymentResult: PaymentResult | null; // True when the checkout is in an error state. Whatever caused the error (validation/payment method) will likely have triggered a notice. hasError: boolean; // This is the url that checkout will redirect to when it's ready. @@ -47,6 +44,5 @@ export const defaultState: CheckoutState = { checkoutData.shipping_address ), shouldCreateAccount: false, - paymentResult: null, extensionData: {}, }; diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/reducers.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/reducers.ts index 78051fa3b03..b4e28116110 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/reducers.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/reducers.ts @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import { PaymentResult } from '@woocommerce/types'; - /** * Internal dependencies */ @@ -35,13 +30,6 @@ const reducer = ( state = defaultState, action: CheckoutAction ) => { : state; break; - case types.SET_PAYMENT_RESULT: - newState = { - ...state, - paymentResult: action.data as PaymentResult, - }; - break; - case types.SET_COMPLETE: newState = { ...state, diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/test/reducer.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/test/reducer.ts index 5304cb559e0..bdaf595431e 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/test/reducer.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/test/reducer.ts @@ -37,28 +37,6 @@ describe.only( 'Checkout Store Reducer', () => { ).toEqual( expectedState ); } ); - it( 'should handle SET_PAYMENT_RESULT', () => { - const mockResponse = { - message: 'success', - redirectUrl: 'https://example.com', - paymentStatus: 'not set' as const, - paymentDetails: {}, - }; - - const expectedState = { - ...defaultState, - status: STATUS.IDLE, - paymentResult: mockResponse, - }; - - expect( - reducer( - defaultState, - actions.__internalSetPaymentResult( mockResponse ) - ) - ).toEqual( expectedState ); - } ); - it( 'should handle SET_COMPLETE', () => { const expectedState = { ...defaultState, diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/thunks.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/thunks.ts index 86731851534..cbb4233f72c 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/thunks.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/thunks.ts @@ -3,10 +3,12 @@ */ import type { CheckoutResponse } from '@woocommerce/types'; import { store as noticesStore } from '@wordpress/notices'; +import { dispatch as wpDispatch, select as wpSelect } from '@wordpress/data'; /** * Internal dependencies */ +import { STORE_KEY as PAYMENT_STORE_KEY } from '../payment/constants'; import { removeNoticesByStatus } from '../../utils/notices'; import { getPaymentResultFromCheckoutResponse, @@ -40,7 +42,11 @@ export const __internalProcessCheckoutResponse = ( } ) => { const paymentResult = getPaymentResultFromCheckoutResponse( response ); dispatch.__internalSetRedirectUrl( paymentResult?.redirectUrl || '' ); - dispatch.__internalSetPaymentResult( paymentResult ); + // The local `dispatch` here is bound to the actions of the data store. We need to use the global dispatch here + // to dispatch an action on a different store. + wpDispatch( PAYMENT_STORE_KEY ).__internalSetPaymentResult( + paymentResult + ); dispatch.__internalSetAfterProcessing(); }; }; @@ -90,15 +96,16 @@ export const __internalEmitAfterProcessingEvents: emitAfterProcessingEventsType ( { observers, notices } ) => { return ( { select, dispatch, registry } ) => { const { createErrorNotice } = registry.dispatch( noticesStore ); - const state = select.getCheckoutState(); + const checkoutState = select.getCheckoutState(); const data = { - redirectUrl: state.redirectUrl, - orderId: state.orderId, - customerId: state.customerId, - orderNotes: state.orderNotes, - processingResponse: state.paymentResult, + redirectUrl: checkoutState.redirectUrl, + orderId: checkoutState.orderId, + customerId: checkoutState.customerId, + orderNotes: checkoutState.orderNotes, + processingResponse: + wpSelect( PAYMENT_STORE_KEY ).getPaymentResult(), }; - if ( state.hasError ) { + if ( checkoutState.hasError ) { // allow payment methods or other things to customize the error // with a fallback if nothing customizes it. emitEventWithAbort( diff --git a/plugins/woocommerce-blocks/assets/js/data/checkout/types.ts b/plugins/woocommerce-blocks/assets/js/data/checkout/types.ts index 6fada6d6207..6057407e1da 100644 --- a/plugins/woocommerce-blocks/assets/js/data/checkout/types.ts +++ b/plugins/woocommerce-blocks/assets/js/data/checkout/types.ts @@ -9,6 +9,7 @@ import { DataRegistry } from '@wordpress/data'; */ import type { EventObserversType } from '../../base/context/event-emit/types'; import type { CheckoutState } from './default-state'; +import type { PaymentState } from '../payment/default-state'; import type { DispatchFromMap, SelectFromMap } from '../mapped-types'; import * as selectors from './selectors'; import * as actions from './actions'; @@ -19,7 +20,7 @@ export type CheckoutAfterProcessingWithErrorEventData = { orderId: CheckoutState[ 'orderId' ]; customerId: CheckoutState[ 'customerId' ]; orderNotes: CheckoutState[ 'orderNotes' ]; - processingResponse: CheckoutState[ 'paymentResult' ]; + processingResponse: PaymentState[ 'paymentResult' ]; }; export type CheckoutAndPaymentNotices = { checkoutNotices: Notice[]; diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/action-types.ts b/plugins/woocommerce-blocks/assets/js/data/payment/action-types.ts index 74f8043187e..f73208e3e83 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/action-types.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/action-types.ts @@ -15,4 +15,5 @@ export enum ACTION_TYPES { REMOVE_AVAILABLE_EXPRESS_PAYMENT_METHOD = 'REMOVE_AVAILABLE_EXPRESS_PAYMENT_METHOD', INITIALIZE_PAYMENT_METHODS = 'INITIALIZE_PAYMENT_METHODS', SET_PAYMENT_METHOD_DATA = 'SET_PAYMENT_METHOD_DATA', + SET_PAYMENT_RESULT = 'SET_PAYMENT_RESULT', } diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/actions.ts b/plugins/woocommerce-blocks/assets/js/data/payment/actions.ts index 675730fad26..d7467efb7f1 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/actions.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/actions.ts @@ -5,6 +5,7 @@ import { PlainPaymentMethods, PlainExpressPaymentMethods, } from '@woocommerce/type-defs/payments'; +import type { PaymentResult } from '@woocommerce/types'; /** * Internal dependencies @@ -112,6 +113,16 @@ export const __internalSetPaymentMethodData = ( paymentMethodData, } ); +/** + * Store the result of the payment attempt from the /checkout StoreApi call + * + * @param data The result of the payment attempt through the StoreApi /checkout endpoints + */ +export const __internalSetPaymentResult = ( data: PaymentResult ) => ( { + type: ACTION_TYPES.SET_PAYMENT_RESULT, + data, +} ); + /** * Set the available payment methods. * An available payment method is one that has been validated and can make a payment. diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts b/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts index 0ce03d4afc5..d998d2d6162 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/default-state.ts @@ -1,7 +1,7 @@ /** * External dependencies */ -import type { EmptyObjectType } from '@woocommerce/types'; +import type { EmptyObjectType, PaymentResult } from '@woocommerce/types'; import { getSetting } from '@woocommerce/settings'; import { PlainPaymentMethods, @@ -14,7 +14,7 @@ import { import { SavedPaymentMethod } from './types'; import { STATUS as PAYMENT_STATUS } from './constants'; -export interface PaymentMethodDataState { +export interface PaymentState { status: string; activePaymentMethod: string; activeSavedToken: string; @@ -25,11 +25,12 @@ export interface PaymentMethodDataState { | Record< string, SavedPaymentMethod[] > | EmptyObjectType; paymentMethodData: Record< string, unknown >; + paymentResult: PaymentResult | null; paymentMethodsInitialized: boolean; expressPaymentMethodsInitialized: boolean; shouldSavePaymentMethod: boolean; } -export const defaultPaymentMethodDataState: PaymentMethodDataState = { +export const defaultPaymentState: PaymentState = { status: PAYMENT_STATUS.PRISTINE, activePaymentMethod: '', activeSavedToken: '', @@ -39,6 +40,7 @@ export const defaultPaymentMethodDataState: PaymentMethodDataState = { Record< string, SavedPaymentMethod[] > | EmptyObjectType >( 'customerPaymentMethods', {} ), paymentMethodData: {}, + paymentResult: null, paymentMethodsInitialized: false, expressPaymentMethodsInitialized: false, shouldSavePaymentMethod: false, diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts b/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts index 758c39ffa02..18723fb3785 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/reducers.ts @@ -2,20 +2,17 @@ * External dependencies */ import type { Reducer } from 'redux'; -import { objectHasProp } from '@woocommerce/types'; +import { objectHasProp, PaymentResult } from '@woocommerce/types'; /** * Internal dependencies */ -import { - defaultPaymentMethodDataState, - PaymentMethodDataState, -} from './default-state'; +import { defaultPaymentState, PaymentState } from './default-state'; import { ACTION_TYPES } from './action-types'; import { STATUS } from './constants'; -const reducer: Reducer< PaymentMethodDataState > = ( - state = defaultPaymentMethodDataState, +const reducer: Reducer< PaymentState > = ( + state = defaultPaymentState, action ) => { let newState = state; @@ -76,6 +73,13 @@ const reducer: Reducer< PaymentMethodDataState > = ( }; break; + case ACTION_TYPES.SET_PAYMENT_RESULT: + newState = { + ...state, + paymentResult: action.data as PaymentResult, + }; + break; + case ACTION_TYPES.REMOVE_AVAILABLE_PAYMENT_METHOD: const previousAvailablePaymentMethods = { ...state.availablePaymentMethods, diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/selectors.ts b/plugins/woocommerce-blocks/assets/js/data/payment/selectors.ts index 75418d7bb98..34dbec0dc88 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/selectors.ts +++ b/plugins/woocommerce-blocks/assets/js/data/payment/selectors.ts @@ -7,29 +7,29 @@ import deprecated from '@wordpress/deprecated'; /** * Internal dependencies */ -import { PaymentMethodDataState } from './default-state'; +import { PaymentState } from './default-state'; import { filterActiveSavedPaymentMethods } from './utils/filter-active-saved-payment-methods'; import { STATUS as PAYMENT_STATUS } from './constants'; -export const isPaymentPristine = ( state: PaymentMethodDataState ) => +export const isPaymentPristine = ( state: PaymentState ) => state.status === PAYMENT_STATUS.PRISTINE; -export const isPaymentStarted = ( state: PaymentMethodDataState ) => +export const isPaymentStarted = ( state: PaymentState ) => state.status === PAYMENT_STATUS.STARTED; -export const isPaymentProcessing = ( state: PaymentMethodDataState ) => +export const isPaymentProcessing = ( state: PaymentState ) => state.status === PAYMENT_STATUS.PROCESSING; -export const isPaymentSuccess = ( state: PaymentMethodDataState ) => +export const isPaymentSuccess = ( state: PaymentState ) => state.status === PAYMENT_STATUS.SUCCESS; -export const hasPaymentError = ( state: PaymentMethodDataState ) => +export const hasPaymentError = ( state: PaymentState ) => state.status === PAYMENT_STATUS.ERROR; -export const isPaymentFailed = ( state: PaymentMethodDataState ) => +export const isPaymentFailed = ( state: PaymentState ) => state.status === PAYMENT_STATUS.FAILED; -export const isPaymentFinished = ( state: PaymentMethodDataState ) => { +export const isPaymentFinished = ( state: PaymentState ) => { return ( state.status === PAYMENT_STATUS.SUCCESS || state.status === PAYMENT_STATUS.ERROR || @@ -37,40 +37,36 @@ export const isPaymentFinished = ( state: PaymentMethodDataState ) => { ); }; -export const isExpressPaymentMethodActive = ( - state: PaymentMethodDataState -) => { +export const isExpressPaymentMethodActive = ( state: PaymentState ) => { return Object.keys( state.availableExpressPaymentMethods ).includes( state.activePaymentMethod ); }; -export const getActiveSavedToken = ( state: PaymentMethodDataState ) => { +export const getActiveSavedToken = ( state: PaymentState ) => { return typeof state.paymentMethodData === 'object' && objectHasProp( state.paymentMethodData, 'token' ) ? state.paymentMethodData.token + '' : ''; }; -export const getActivePaymentMethod = ( state: PaymentMethodDataState ) => { +export const getActivePaymentMethod = ( state: PaymentState ) => { return state.activePaymentMethod; }; -export const getAvailablePaymentMethods = ( state: PaymentMethodDataState ) => { +export const getAvailablePaymentMethods = ( state: PaymentState ) => { return state.availablePaymentMethods; }; -export const getAvailableExpressPaymentMethods = ( - state: PaymentMethodDataState -) => { +export const getAvailableExpressPaymentMethods = ( state: PaymentState ) => { return state.availableExpressPaymentMethods; }; -export const getPaymentMethodData = ( state: PaymentMethodDataState ) => { +export const getPaymentMethodData = ( state: PaymentState ) => { return state.paymentMethodData; }; -export const getSavedPaymentMethods = ( state: PaymentMethodDataState ) => { +export const getSavedPaymentMethods = ( state: PaymentState ) => { return state.savedPaymentMethods; }; @@ -78,9 +74,7 @@ export const getSavedPaymentMethods = ( state: PaymentMethodDataState ) => { * Filters the list of saved payment methods and returns only the ones which * are active and supported by the payment gateway */ -export const getActiveSavedPaymentMethods = ( - state: PaymentMethodDataState -) => { +export const getActiveSavedPaymentMethods = ( state: PaymentState ) => { const availablePaymentMethodKeys = Object.keys( state.availablePaymentMethods ); @@ -91,13 +85,11 @@ export const getActiveSavedPaymentMethods = ( ); }; -export const paymentMethodsInitialized = ( state: PaymentMethodDataState ) => { +export const paymentMethodsInitialized = ( state: PaymentState ) => { return state.paymentMethodsInitialized; }; -export const expressPaymentMethodsInitialized = ( - state: PaymentMethodDataState -) => { +export const expressPaymentMethodsInitialized = ( state: PaymentState ) => { return state.expressPaymentMethodsInitialized; }; @@ -105,7 +97,7 @@ export const expressPaymentMethodsInitialized = ( * @deprecated - use these selectors instead: isPaymentPristine, isPaymentStarted, isPaymentProcessing, * isPaymentFinished, hasPaymentError, isPaymentSuccess, isPaymentFailed */ -export const getCurrentStatus = ( state: PaymentMethodDataState ) => { +export const getCurrentStatus = ( state: PaymentState ) => { deprecated( 'getCurrentStatus', { since: '8.9.0', alternative: @@ -126,10 +118,14 @@ export const getCurrentStatus = ( state: PaymentMethodDataState ) => { }; }; -export const getShouldSavePaymentMethod = ( state: PaymentMethodDataState ) => { +export const getShouldSavePaymentMethod = ( state: PaymentState ) => { return state.shouldSavePaymentMethod; }; -export const getState = ( state: PaymentMethodDataState ) => { +export const getPaymentResult = ( state: PaymentState ) => { + return state.paymentResult; +}; + +export const getState = ( state: PaymentState ) => { return state; }; diff --git a/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js b/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js index f4575a06c93..2dc393912d6 100644 --- a/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js +++ b/plugins/woocommerce-blocks/assets/js/data/payment/test/reducers.js @@ -180,4 +180,25 @@ describe( 'paymentMethodDataReducer', () => { activeSavedToken: '', } ); } ); + + it( 'should handle SET_PAYMENT_RESULT', () => { + const mockResponse = { + message: 'success', + redirectUrl: 'https://example.com', + paymentStatus: 'not set', + paymentDetails: {}, + }; + + const expectedState = { + ...originalState, + paymentResult: mockResponse, + }; + + expect( + reducer( originalState, { + type: ACTION_TYPES.SET_PAYMENT_RESULT, + data: mockResponse, + } ) + ).toEqual( expectedState ); + } ); } ); diff --git a/plugins/woocommerce-blocks/checkstyle.xml b/plugins/woocommerce-blocks/checkstyle.xml index cf75274f51d..cf45d060794 100644 --- a/plugins/woocommerce-blocks/checkstyle.xml +++ b/plugins/woocommerce-blocks/checkstyle.xml @@ -645,22 +645,6 @@ - - - - - - - - - - - @@ -696,15 +680,31 @@ - - - - - - + + + + + + + + + + + + + + + + + -