Skip to content

Commit

Permalink
chore: copy prb blocks implementation to tokenized cart (#8989)
Browse files Browse the repository at this point in the history
  • Loading branch information
frosso committed Jun 20, 2024
1 parent a5b186c commit e56b9f7
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: dev
Comment: chore: copy PRB blocks to tokenized cart


8 changes: 7 additions & 1 deletion client/checkout/blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import request from '../utils/request';
import enqueueFraudScripts from 'fraud-scripts';
import paymentRequestPaymentMethod from '../../payment-request/blocks';
import expressCheckoutElementPaymentMethod from '../../express-checkout/blocks';
import tokenizedCartPaymentRequestPaymentMethod from '../../tokenized-payment-request/blocks';

import {
PAYMENT_METHOD_NAME_CARD,
PAYMENT_METHOD_NAME_BANCONTACT,
Expand Down Expand Up @@ -154,7 +156,11 @@ if ( getUPEConfig( 'isWooPayEnabled' ) ) {
}
}

if ( getUPEConfig( 'isExpressCheckoutElementEnabled' ) ) {
if ( getUPEConfig( 'isTokenizedCartPrbEnabled' ) ) {
registerExpressPaymentMethod(
tokenizedCartPaymentRequestPaymentMethod( api )
);
} else if ( getUPEConfig( 'isExpressCheckoutElementEnabled' ) ) {
registerExpressPaymentMethod( expressCheckoutElementPaymentMethod( api ) );
} else {
registerExpressPaymentMethod( paymentRequestPaymentMethod( api ) );
Expand Down
3 changes: 3 additions & 0 deletions client/tokenized-payment-request/blocks/apple-pay-preview.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions client/tokenized-payment-request/blocks/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* global wcpayConfig, wcpayPaymentRequestParams */

/**
* Internal dependencies
*/
import { PaymentRequestExpress } from './payment-request-express';
import { applePayImage } from './apple-pay-preview';
import { getConfig } from '../../utils/checkout';
import { getPaymentRequest } from '../../payment-request/utils';

const PAYMENT_METHOD_NAME_PAYMENT_REQUEST =
'woocommerce_payments_tokenized_cart_payment_request';

const ApplePayPreview = () => <img src={ applePayImage } alt="" />;

const tokenizedCartPaymentRequestPaymentMethod = ( api ) => ( {
name: PAYMENT_METHOD_NAME_PAYMENT_REQUEST,
content: (
<PaymentRequestExpress api={ api } stripe={ api.loadStripe( true ) } />
),
edit: <ApplePayPreview />,
canMakePayment: ( cartData ) => {
// If in the editor context, always return true to display the `edit` prop preview.
// https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues/4101.
if ( getConfig( 'is_admin' ) ) {
return true;
}

if ( typeof wcpayPaymentRequestParams === 'undefined' ) {
return false;
}

if (
typeof wcpayConfig !== 'undefined' &&
wcpayConfig.isExpressCheckoutElementEnabled
) {
return false;
}

return api.loadStripe( true ).then( ( stripe ) => {
// Create a payment request and check if we can make a payment to determine whether to
// show the Payment Request Button or not. This is necessary because a browser might be
// able to load the Stripe JS object, but not support Payment Requests.
const pr = getPaymentRequest( {
stripe,
total: parseInt( cartData?.cartTotals?.total_price ?? 0, 10 ),
requestShipping: cartData?.cartNeedsShipping,
displayItems: [],
} );

return pr.canMakePayment();
} );
},
paymentMethodId: PAYMENT_METHOD_NAME_PAYMENT_REQUEST,
supports: {
features: getConfig( 'features' ),
},
} );

export default tokenizedCartPaymentRequestPaymentMethod;
147 changes: 147 additions & 0 deletions client/tokenized-payment-request/blocks/payment-request-express.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/* global wcpayPaymentRequestParams */

/**
* External dependencies
*/
import { Elements, PaymentRequestButtonElement } from '@stripe/react-stripe-js';
import { recordUserEvent } from 'tracks';
import { useEffect, useState } from 'react';

/**
* Internal dependencies
*/
import { useInitialization } from './use-initialization';
import { getPaymentRequestData } from '../../payment-request/utils';

/**
* PaymentRequestExpressComponent
*
* @param {Object} props Incoming props.
*
* @return {ReactNode} Payment Request button component.
*/
const PaymentRequestExpressComponent = ( {
api,
billing,
shippingData,
setExpressPaymentError,
onClick,
onClose,
onPaymentRequestAvailable,
} ) => {
// TODO: Don't display custom button when result.requestType
// is `apple_pay` or `google_pay`.
const {
paymentRequest,
// paymentRequestType,
onButtonClick,
} = useInitialization( {
api,
billing,
shippingData,
setExpressPaymentError,
onClick,
onClose,
} );

const { type, theme, height } = getPaymentRequestData( 'button' );

const paymentRequestButtonStyle = {
paymentRequestButton: {
type,
theme,
height: height + 'px',
},
};

if ( ! paymentRequest ) {
return null;
}

let paymentRequestType = '';

// Check the availability of the Payment Request API first.
paymentRequest.canMakePayment().then( ( result ) => {
if ( ! result ) {
return;
}

// Set the payment request type.
if ( result.applePay ) {
paymentRequestType = 'apple_pay';
} else if ( result.googlePay ) {
paymentRequestType = 'google_pay';
}
onPaymentRequestAvailable( paymentRequestType );
} );

const onPaymentRequestButtonClick = ( event ) => {
onButtonClick( event, paymentRequest );

const paymentRequestTypeEvents = {
google_pay: 'gpay_button_click',
apple_pay: 'applepay_button_click',
};

if ( paymentRequestTypeEvents.hasOwnProperty( paymentRequestType ) ) {
const paymentRequestEvent =
paymentRequestTypeEvents[ paymentRequestType ];
recordUserEvent( paymentRequestEvent, {
source: wcpayPaymentRequestParams?.button_context,
} );
}
};

return (
<PaymentRequestButtonElement
onClick={ onPaymentRequestButtonClick }
options={ {
style: paymentRequestButtonStyle,
paymentRequest,
} }
/>
);
};

/**
* PaymentRequestExpress express payment method component.
*
* @param {Object} props PaymentMethodProps.
*
* @return {ReactNode} Stripe Elements component.
*/
export const PaymentRequestExpress = ( props ) => {
const { stripe } = props;
const [ paymentRequestType, setPaymentRequestType ] = useState( false );

const handlePaymentRequestAvailability = ( paymentType ) => {
setPaymentRequestType( paymentType );
};

useEffect( () => {
if ( paymentRequestType ) {
const paymentRequestTypeEvents = {
google_pay: 'gpay_button_load',
apple_pay: 'applepay_button_load',
};

if (
paymentRequestTypeEvents.hasOwnProperty( paymentRequestType )
) {
const event = paymentRequestTypeEvents[ paymentRequestType ];
recordUserEvent( event, {
source: wcpayPaymentRequestParams?.button_context,
} );
}
}
}, [ paymentRequestType ] );

return (
<Elements stripe={ stripe }>
<PaymentRequestExpressComponent
{ ...props }
onPaymentRequestAvailable={ handlePaymentRequestAvailability }
/>
</Elements>
);
};
Loading

0 comments on commit e56b9f7

Please sign in to comment.