diff --git a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx
index ea1ef15d9d693..2c6d1c3c1af18 100644
--- a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx
+++ b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-element-field.tsx
@@ -3,8 +3,8 @@ import { CardElement } from '@stripe/react-stripe-js';
import { useSelect } from '@wordpress/data';
import { useI18n } from '@wordpress/react-i18n';
import classnames from 'classnames';
+import { creditCardStore } from 'calypso/state/partner-portal/credit-card-form';
import type { StripeElementChangeEvent, StripeElementStyle } from '@stripe/stripe-js';
-import type { CreditCardSelectors } from 'calypso/state/partner-portal/types';
export default function CreditCardElementField( {
setIsStripeFullyLoaded,
@@ -19,7 +19,7 @@ export default function CreditCardElementField( {
const { formStatus } = useFormStatus();
const isDisabled = formStatus !== FormStatus.READY;
const { card: cardError } = useSelect(
- ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).getCardDataErrors(),
+ ( select ) => select( creditCardStore ).getCardDataErrors(),
[]
);
diff --git a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx
index db222c4133062..46e598b01c0ce 100644
--- a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx
+++ b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/credit-card-submit-button.tsx
@@ -1,41 +1,40 @@
import { Button, FormStatus, useFormStatus } from '@automattic/composite-checkout';
import { useElements, CardElement } from '@stripe/react-stripe-js';
-import { useSelect } from '@wordpress/data';
+import { useDispatch, useSelect } from '@wordpress/data';
import { useI18n } from '@wordpress/react-i18n';
import debugFactory from 'debug';
import { useMemo } from 'react';
+import { creditCardStore } from 'calypso/state/partner-portal/credit-card-form';
import type { StripeConfiguration } from '@automattic/calypso-stripe';
import type { ProcessPayment } from '@automattic/composite-checkout';
-import type { StoreState } from '@automattic/wpcom-checkout';
import type { Stripe } from '@stripe/stripe-js';
-import type { I18n } from '@wordpress/i18n';
-import type { State } from 'calypso/state/partner-portal/credit-card-form/reducer';
-import type { CreditCardSelectors } from 'calypso/state/partner-portal/types';
const debug = debugFactory( 'calypso:partner-portal:credit-card' );
export default function CreditCardSubmitButton( {
disabled,
onClick,
- store,
stripe,
stripeConfiguration,
activeButtonText,
}: {
disabled?: boolean;
onClick?: ProcessPayment;
- store: State;
stripe: Stripe | null;
stripeConfiguration: StripeConfiguration | null;
activeButtonText: string | undefined;
} ) {
const { __ } = useI18n();
- const fields: StoreState< string > = useSelect(
- ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).getFields(),
- []
- );
- const useAsPrimaryPaymentMethod: boolean = useSelect(
- ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).useAsPrimaryPaymentMethod(),
+ const { fields, useAsPrimaryPaymentMethod, errors, incompleteFieldKeys } = useSelect(
+ ( select ) => {
+ const store = select( creditCardStore );
+ return {
+ fields: store.getFields(),
+ useAsPrimaryPaymentMethod: store.useAsPrimaryPaymentMethod(),
+ errors: store.getCardDataErrors(),
+ incompleteFieldKeys: store.getIncompleteFieldKeys(),
+ };
+ },
[]
);
const cardholderName = fields.cardholderName;
@@ -54,30 +53,53 @@ export default function CreditCardSubmitButton( {
return __( 'Please wait…' );
}, [ formStatus, activeButtonText, __ ] );
+ const { setCardDataError, setFieldValue, setFieldError } = useDispatch( creditCardStore );
+
+ const handleButtonClick = () => {
+ debug( 'validating credit card fields' );
+
+ if ( ! cardholderName?.value.length ) {
+ // Touch the field so it displays a validation error
+ setFieldValue( 'cardholderName', '' );
+ setFieldError( 'cardholderName', __( 'This field is required' ) );
+ }
+ const areThereErrors = Object.keys( errors ).some( ( errorKey ) => errors[ errorKey ] );
+
+ if ( incompleteFieldKeys.length > 0 ) {
+ // Show "this field is required" for each incomplete field
+ incompleteFieldKeys.map( ( key: string ) =>
+ setCardDataError( key, __( 'This field is required' ) )
+ );
+ }
+
+ if ( areThereErrors || ! cardholderName?.value.length || incompleteFieldKeys.length > 0 ) {
+ // credit card is invalid
+ return false;
+ }
+
+ debug( 'submitting stripe payment' );
+
+ if ( ! onClick ) {
+ throw new Error(
+ 'Missing onClick prop; CreditCardSubmitButton must be used as a payment button in CheckoutSubmitButton'
+ );
+ }
+
+ onClick( {
+ stripe,
+ name: cardholderName?.value,
+ stripeConfiguration,
+ cardElement,
+ useAsPrimaryPaymentMethod,
+ } );
+ return;
+ };
+
return (
);
}
-
-function isCreditCardFormValid( store: State, __: I18n[ '__' ] ) {
- debug( 'validating credit card fields' );
-
- const fields = store.selectors.getFields( store.getState() );
- const cardholderName = fields.cardholderName;
- if ( ! cardholderName?.value.length ) {
- // Touch the field so it displays a validation error
- store.dispatch( store.actions.setFieldValue( 'cardholderName', '' ) );
- store.dispatch(
- store.actions.setFieldError( 'cardholderName', __( 'This field is required' ) )
- );
- }
- const errors = store.selectors.getCardDataErrors( store.getState() );
- const incompleteFieldKeys = store.selectors.getIncompleteFieldKeys( store.getState() );
- const areThereErrors = Object.keys( errors ).some( ( errorKey ) => errors[ errorKey ] );
-
- if ( incompleteFieldKeys.length > 0 ) {
- // Show "this field is required" for each incomplete field
- incompleteFieldKeys.map( ( key: string ) =>
- store.dispatch( store.actions.setCardDataError( key, __( 'This field is required' ) ) )
- );
- }
- if ( areThereErrors || ! cardholderName?.value.length || incompleteFieldKeys.length > 0 ) {
- return false;
- }
- return true;
-}
diff --git a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx
index ad520178ee92d..7de8574aefa1d 100644
--- a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx
+++ b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/index.tsx
@@ -7,23 +7,23 @@ import { useState } from 'react';
import { useDispatch as useReduxDispatch } from 'react-redux';
import { useRecentPaymentMethodsQuery } from 'calypso/jetpack-cloud/sections/partner-portal/hooks';
import { recordTracksEvent } from 'calypso/state/analytics/actions';
+import { creditCardStore } from 'calypso/state/partner-portal/credit-card-form';
import CreditCardElementField from './credit-card-element-field';
import CreditCardLoading from './credit-card-loading';
import SetAsPrimaryPaymentMethod from './set-as-primary-payment-method';
import type { StoreState } from '@automattic/wpcom-checkout';
import type { StripeElementChangeEvent, StripeElementStyle } from '@stripe/stripe-js';
-import type { CreditCardSelectors } from 'calypso/state/partner-portal/types';
import './style.scss';
export default function CreditCardFields() {
const { __ } = useI18n();
const [ isStripeFullyLoaded, setIsStripeFullyLoaded ] = useState( false );
const fields: StoreState< string > = useSelect(
- ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).getFields(),
+ ( select ) => select( creditCardStore ).getFields(),
[]
);
const useAsPrimaryPaymentMethod: boolean = useSelect(
- ( select ) => ( select( 'credit-card' ) as CreditCardSelectors ).useAsPrimaryPaymentMethod(),
+ ( select ) => select( creditCardStore ).useAsPrimaryPaymentMethod(),
[]
);
const getField = ( key: string | number ) => fields[ key ] || {};
diff --git a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/test/credit-card-submit-button.jsx b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/test/credit-card-submit-button.jsx
index bfabe38501737..08833f8494a69 100644
--- a/client/jetpack-cloud/sections/partner-portal/credit-card-fields/test/credit-card-submit-button.jsx
+++ b/client/jetpack-cloud/sections/partner-portal/credit-card-fields/test/credit-card-submit-button.jsx
@@ -7,20 +7,16 @@ import { Elements } from '@stripe/react-stripe-js';
import { loadStripe } from '@stripe/stripe-js';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { useSelect } from '@wordpress/data';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import * as actions from 'calypso/state/partner-portal/credit-card-form/actions';
import * as selectors from 'calypso/state/partner-portal/credit-card-form/selectors';
import CreditCardSubmitButton from '../credit-card-submit-button';
-const mockUseSelector = () => () => null;
-
jest.mock( '@stripe/stripe-js', () => ( {
loadStripe: () => null,
} ) );
-jest.mock( '@wordpress/data' );
jest.mock( 'calypso/state/partner-portal/credit-card-form/selectors', () => {
const items = jest.requireActual( 'calypso/state/partner-portal/credit-card-form/selectors' );
return {
@@ -71,7 +67,6 @@ describe( '', () => {
beforeEach( () => {
// Re-mock dependencies
jest.clearAllMocks();
- useSelect.mockImplementation( mockUseSelector );
useFormStatus.mockImplementation( () => {
return {
formStatus: 'ready',
@@ -81,7 +76,6 @@ describe( '', () => {
} );
afterEach( () => {
- useSelect.mockClear();
useFormStatus.mockClear();
} );
@@ -106,7 +100,6 @@ describe( '', () => {
const buttonText = 'Save payment method';
const props = {
- store: newStore,
stripe,
stripeConfiguration,
disabled: false,
diff --git a/client/jetpack-cloud/sections/partner-portal/payment-methods/hooks/use-create-stored-credit-card.ts b/client/jetpack-cloud/sections/partner-portal/payment-methods/hooks/use-create-stored-credit-card.ts
index 540a3aa9baf91..27149b956b543 100644
--- a/client/jetpack-cloud/sections/partner-portal/payment-methods/hooks/use-create-stored-credit-card.ts
+++ b/client/jetpack-cloud/sections/partner-portal/payment-methods/hooks/use-create-stored-credit-card.ts
@@ -1,6 +1,5 @@
import { useMemo } from 'react';
import { createStoredCreditCardMethod } from 'calypso/jetpack-cloud/sections/partner-portal/payment-methods/stored-credit-card-method';
-import { createStoredCreditCardPaymentMethodStore } from 'calypso/state/partner-portal/credit-card-form';
import type { StripeConfiguration, StripeLoadingError } from '@automattic/calypso-stripe';
import type { PaymentMethod } from '@automattic/composite-checkout';
import type { Stripe } from '@stripe/stripe-js';
@@ -20,18 +19,15 @@ export function useCreateStoredCreditCardMethod( {
} ): PaymentMethod | null {
const shouldLoadStripeMethod = ! isStripeLoading && ! stripeLoadingError;
- const store = useMemo( () => createStoredCreditCardPaymentMethodStore(), [] );
-
return useMemo(
() =>
shouldLoadStripeMethod
? createStoredCreditCardMethod( {
- store,
stripe,
stripeConfiguration,
activePayButtonText,
} )
: null,
- [ shouldLoadStripeMethod, store, stripe, stripeConfiguration, activePayButtonText ]
+ [ shouldLoadStripeMethod, stripe, stripeConfiguration, activePayButtonText ]
);
}
diff --git a/client/jetpack-cloud/sections/partner-portal/payment-methods/stored-credit-card-method.tsx b/client/jetpack-cloud/sections/partner-portal/payment-methods/stored-credit-card-method.tsx
index b6235b8a147d2..dd24da0b70d51 100644
--- a/client/jetpack-cloud/sections/partner-portal/payment-methods/stored-credit-card-method.tsx
+++ b/client/jetpack-cloud/sections/partner-portal/payment-methods/stored-credit-card-method.tsx
@@ -3,15 +3,12 @@ import CreditCardSubmitButton from 'calypso/jetpack-cloud/sections/partner-porta
import type { StripeConfiguration } from '@automattic/calypso-stripe';
import type { PaymentMethod } from '@automattic/composite-checkout';
import type { Stripe } from '@stripe/stripe-js';
-import type { State } from 'calypso/state/partner-portal/credit-card-form/reducer';
export function createStoredCreditCardMethod( {
- store,
stripe,
stripeConfiguration,
activePayButtonText = undefined,
}: {
- store: State;
stripe: Stripe | null;
stripeConfiguration: StripeConfiguration | null;
activePayButtonText?: string | undefined;
@@ -23,7 +20,6 @@ export function createStoredCreditCardMethod( {
activeContent: ,
submitButton: (
( select( 'credit-card' ) as CreditCardSelectors ).useAsPrimaryPaymentMethod(),
+ ( select ) => select( creditCardStore ).useAsPrimaryPaymentMethod(),
[]
);
diff --git a/client/state/partner-portal/credit-card-form/index.ts b/client/state/partner-portal/credit-card-form/index.ts
index 76d6df2f387f4..661069397b8e6 100644
--- a/client/state/partner-portal/credit-card-form/index.ts
+++ b/client/state/partner-portal/credit-card-form/index.ts
@@ -1,14 +1,12 @@
-import { registerStore } from '@wordpress/data';
+import { createReduxStore, register } from '@wordpress/data';
import * as actions from 'calypso/state/partner-portal/credit-card-form/actions';
import reducer from 'calypso/state/partner-portal/credit-card-form/reducer';
import * as selectors from 'calypso/state/partner-portal/credit-card-form/selectors';
-export function createStoredCreditCardPaymentMethodStore(): Record< string, unknown > {
- const store = registerStore( 'credit-card', {
- reducer,
- actions,
- selectors,
- } );
+export const creditCardStore = createReduxStore( 'credit-card', {
+ reducer,
+ actions,
+ selectors,
+} );
- return { ...store, actions, selectors };
-}
+register( creditCardStore );
diff --git a/client/state/partner-portal/types.ts b/client/state/partner-portal/types.ts
index 783220e74e4d4..2288a8a434b61 100644
--- a/client/state/partner-portal/types.ts
+++ b/client/state/partner-portal/types.ts
@@ -5,10 +5,6 @@ import {
LicenseSortDirection,
LicenseSortField,
} from 'calypso/jetpack-cloud/sections/partner-portal/types';
-import * as creditCardSelectors from './credit-card-form/selectors';
-import type { SelectFromMap } from '@automattic/data-stores';
-
-export type CreditCardSelectors = SelectFromMap< typeof creditCardSelectors >;
/**
* Utility.