2020-03-26 11:11:46 +00:00
/ * *
* External dependencies
* /
2021-12-10 15:26:16 +00:00
import { useMemo , cloneElement } from '@wordpress/element' ;
2020-03-26 11:11:46 +00:00
import { __ , sprintf } from '@wordpress/i18n' ;
2022-07-08 05:53:24 +00:00
import { noticeContexts } from '@woocommerce/base-context' ;
2020-03-26 11:11:46 +00:00
import RadioControl from '@woocommerce/base-components/radio-control' ;
2021-03-15 08:50:49 +00:00
import {
usePaymentMethodInterface ,
2021-12-10 15:26:16 +00:00
useStoreEvents ,
2021-04-08 12:31:12 +00:00
} from '@woocommerce/base-context/hooks' ;
2022-10-06 12:46:46 +00:00
import { PAYMENT_STORE_KEY } from '@woocommerce/block-data' ;
2022-07-08 05:53:24 +00:00
import { useDispatch , useSelect } from '@wordpress/data' ;
import { getPaymentMethods } from '@woocommerce/blocks-registry' ;
2023-06-28 08:43:38 +00:00
import { isNull } from '@woocommerce/types' ;
import { RadioControlOption } from '@woocommerce/base-components/radio-control/types' ;
2020-03-26 11:11:46 +00:00
2020-05-11 13:29:57 +00:00
/ * *
2023-06-28 08:43:38 +00:00
* Internal dependencies
2020-05-11 13:29:57 +00:00
* /
2023-06-28 08:43:38 +00:00
import { getCanMakePaymentArg } from '../../../data/payment/utils/check-payment-methods' ;
import { CustomerPaymentMethodConfiguration } from '../../../data/payment/types' ;
2020-03-26 11:11:46 +00:00
/ * *
* Returns the option object for a cc or echeck saved payment method token .
* /
2023-06-28 08:43:38 +00:00
const getCcOrEcheckLabel = ( {
method ,
expires ,
} : {
method : CustomerPaymentMethodConfiguration ;
expires : string ;
} ) : string = > {
2021-12-10 15:26:16 +00:00
return sprintf (
/* translators: %1$s is referring to the payment method brand, %2$s is referring to the last 4 digits of the payment card, %3$s is referring to the expiry date. */
__ (
'%1$s ending in %2$s (expires %3$s)' ,
'woo-gutenberg-products-block'
2020-03-26 11:11:46 +00:00
) ,
2021-12-10 15:26:16 +00:00
method . brand ,
method . last4 ,
expires
) ;
2020-03-26 11:11:46 +00:00
} ;
/ * *
* Returns the option object for any non specific saved payment method .
* /
2023-06-28 08:43:38 +00:00
const getDefaultLabel = ( {
method ,
} : {
method : CustomerPaymentMethodConfiguration ;
} ) : string = > {
2022-04-20 11:15:04 +00:00
/* For saved payment methods with brand & last 4 */
if ( method . brand && method . last4 ) {
return sprintf (
/* translators: %1$s is referring to the payment method brand, %2$s is referring to the last 4 digits of the payment card. */
__ ( '%1$s ending in %2$s' , 'woo-gutenberg-products-block' ) ,
method . brand ,
method . last4
) ;
}
/* For saved payment methods without brand & last 4 */
2021-12-10 15:26:16 +00:00
return sprintf (
/* translators: %s is the name of the payment method gateway. */
__ ( 'Saved token for %s' , 'woo-gutenberg-products-block' ) ,
method . gateway
) ;
2020-03-26 11:11:46 +00:00
} ;
2021-02-02 04:51:47 +00:00
const SavedPaymentMethodOptions = ( ) = > {
2022-07-08 05:53:24 +00:00
const { activeSavedToken , activePaymentMethod , savedPaymentMethods } =
2022-12-07 09:12:55 +00:00
useSelect ( ( select ) = > {
const store = select ( PAYMENT_STORE_KEY ) ;
return {
activeSavedToken : store.getActiveSavedToken ( ) ,
activePaymentMethod : store.getActivePaymentMethod ( ) ,
savedPaymentMethods : store.getSavedPaymentMethods ( ) ,
} ;
} ) ;
2022-10-06 12:46:46 +00:00
const { __internalSetActivePaymentMethod } =
useDispatch ( PAYMENT_STORE_KEY ) ;
2023-06-28 08:43:38 +00:00
const canMakePaymentArg = getCanMakePaymentArg ( ) ;
2022-07-08 05:53:24 +00:00
const paymentMethods = getPaymentMethods ( ) ;
2021-03-15 08:50:49 +00:00
const paymentMethodInterface = usePaymentMethodInterface ( ) ;
2022-04-08 12:11:50 +00:00
const { removeNotice } = useDispatch ( 'core/notices' ) ;
2021-12-10 15:26:16 +00:00
const { dispatchCheckoutEvent } = useStoreEvents ( ) ;
2020-03-26 11:11:46 +00:00
2023-06-28 08:43:38 +00:00
const options = useMemo < RadioControlOption [ ] > ( ( ) = > {
2022-07-08 05:53:24 +00:00
const types = Object . keys ( savedPaymentMethods ) ;
2023-06-28 08:43:38 +00:00
// Get individual payment methods from saved payment methods and put them into a unique array.
const individualPaymentGateways = new Set (
types . flatMap ( ( type ) = >
savedPaymentMethods [ type ] . map (
( paymentMethod ) = > paymentMethod . method . gateway
)
)
) ;
const gatewaysThatCanMakePayment = Array . from (
individualPaymentGateways
) . filter ( ( method ) = > {
return paymentMethods [ method ] ? . canMakePayment (
canMakePaymentArg
) ;
} ) ;
const mappedOptions = types . flatMap ( ( type ) = > {
const typeMethods = savedPaymentMethods [ type ] ;
return typeMethods . map ( ( paymentMethod ) = > {
const canMakePayment = gatewaysThatCanMakePayment . includes (
paymentMethod . method . gateway
) ;
if ( ! canMakePayment ) {
return void 0 ;
}
const isCC = type === 'cc' || type === 'echeck' ;
const paymentMethodSlug = paymentMethod . method . gateway ;
return {
name : ` wc-saved-payment-method-token- ${ paymentMethodSlug } ` ,
label : isCC
? getCcOrEcheckLabel ( paymentMethod )
: getDefaultLabel ( paymentMethod ) ,
value : paymentMethod.tokenId.toString ( ) ,
onChange : ( token : string ) = > {
const savedTokenKey = ` wc- ${ paymentMethodSlug } -payment-token ` ;
__internalSetActivePaymentMethod ( paymentMethodSlug , {
token ,
payment_method : paymentMethodSlug ,
[ savedTokenKey ] : token . toString ( ) ,
isSavedToken : true ,
} ) ;
removeNotice (
'wc-payment-error' ,
noticeContexts . PAYMENTS
) ;
dispatchCheckoutEvent ( 'set-active-payment-method' , {
paymentMethodSlug ,
} ) ;
} ,
} ;
} ) ;
} ) ;
return mappedOptions . filter (
( option ) = > typeof option !== 'undefined'
) as RadioControlOption [ ] ;
2020-05-11 13:29:57 +00:00
} , [
2022-07-08 05:53:24 +00:00
savedPaymentMethods ,
2023-06-28 08:43:38 +00:00
paymentMethods ,
2022-10-05 10:04:16 +00:00
__internalSetActivePaymentMethod ,
2021-12-10 15:26:16 +00:00
removeNotice ,
dispatchCheckoutEvent ,
2023-06-28 08:43:38 +00:00
canMakePaymentArg ,
2020-05-11 13:29:57 +00:00
] ) ;
2021-03-15 08:50:49 +00:00
const savedPaymentMethodHandler =
! ! activeSavedToken &&
paymentMethods [ activePaymentMethod ] &&
2023-06-28 08:43:38 +00:00
typeof paymentMethods [ activePaymentMethod ] ? . savedTokenComponent !==
'undefined' &&
! isNull ( paymentMethods [ activePaymentMethod ] . savedTokenComponent )
2021-03-15 08:50:49 +00:00
? cloneElement (
2023-06-28 08:43:38 +00:00
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore - we know for sure that the savedTokenComponent is not null or undefined at this point.
paymentMethods [ activePaymentMethod ] . savedTokenComponent ,
2021-03-15 08:50:49 +00:00
{ token : activeSavedToken , . . . paymentMethodInterface }
)
: null ;
2021-12-10 15:26:16 +00:00
return options . length > 0 ? (
2021-03-15 08:50:49 +00:00
< >
< RadioControl
id = { 'wc-payment-method-saved-tokens' }
selected = { activeSavedToken }
2021-12-10 15:26:16 +00:00
options = { options }
2022-08-03 10:51:56 +00:00
onChange = { ( ) = > void 0 }
2021-03-15 08:50:49 +00:00
/ >
{ savedPaymentMethodHandler }
< / >
2020-03-26 11:11:46 +00:00
) : null ;
} ;
export default SavedPaymentMethodOptions ;