Skip to content

Commit

Permalink
chore: ECE copy for tokenized cart implementation (#9730)
Browse files Browse the repository at this point in the history
  • Loading branch information
frosso authored Nov 15, 2024
1 parent f31d8ee commit f358e9d
Show file tree
Hide file tree
Showing 27 changed files with 3,071 additions and 99 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Significance: patch
Type: add
Comment: chore: create copy of ECE for tokenized cart feature flag


10 changes: 8 additions & 2 deletions client/checkout/blocks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ import {
expressCheckoutElementApplePay,
expressCheckoutElementGooglePay,
} from '../../express-checkout/blocks';
import tokenizedCartPaymentRequestPaymentMethod from '../../tokenized-payment-request/blocks';
import {
tokenizedExpressCheckoutElementApplePay,
tokenizedExpressCheckoutElementGooglePay,
} from 'wcpay/tokenized-express-checkout/blocks';

import {
PAYMENT_METHOD_NAME_CARD,
Expand Down Expand Up @@ -162,7 +165,10 @@ if ( getUPEConfig( 'isWooPayEnabled' ) ) {
if ( getUPEConfig( 'isPaymentRequestEnabled' ) ) {
if ( getUPEConfig( 'isTokenizedCartEceEnabled' ) ) {
registerExpressPaymentMethod(
tokenizedCartPaymentRequestPaymentMethod( api )
tokenizedExpressCheckoutElementApplePay( api )
);
registerExpressPaymentMethod(
tokenizedExpressCheckoutElementGooglePay( api )
);
} else {
registerExpressPaymentMethod( expressCheckoutElementApplePay( api ) );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/**
* External dependencies
*/
import { ExpressCheckoutElement } from '@stripe/react-stripe-js';
/**
* Internal dependencies
*/
import {
shippingAddressChangeHandler,
shippingRateChangeHandler,
} from '../../event-handlers';
import { useExpressCheckout } from '../hooks/use-express-checkout';
import { PAYMENT_METHOD_NAME_EXPRESS_CHECKOUT_ELEMENT } from 'wcpay/checkout/constants';

const getPaymentMethodsOverride = ( enabledPaymentMethod ) => {
const allDisabled = {
amazonPay: 'never',
applePay: 'never',
googlePay: 'never',
link: 'never',
paypal: 'never',
};

const enabledParam = [ 'applePay', 'googlePay' ].includes(
enabledPaymentMethod
)
? 'always'
: 'auto';

return {
paymentMethods: {
...allDisabled,
[ enabledPaymentMethod ]: enabledParam,
},
};
};

// Visual adjustments to horizontally align the buttons.
const adjustButtonHeights = ( buttonOptions, expressPaymentMethod ) => {
// Apple Pay has a nearly imperceptible height difference. We increase it by 1px here.
if ( buttonOptions.buttonTheme.applePay === 'black' ) {
if ( expressPaymentMethod === 'applePay' ) {
buttonOptions.buttonHeight = buttonOptions.buttonHeight + 0.4;
}
}

// GooglePay with the white theme has a 2px height difference due to its border.
if (
expressPaymentMethod === 'googlePay' &&
buttonOptions.buttonTheme.googlePay === 'white'
) {
buttonOptions.buttonHeight = buttonOptions.buttonHeight - 2;
}

// Clamp the button height to the allowed range 40px to 55px.
buttonOptions.buttonHeight = Math.max(
40,
Math.min( buttonOptions.buttonHeight, 55 )
);
return buttonOptions;
};

/**
* ExpressCheckout express payment method component.
*
* @param {Object} props PaymentMethodProps.
*
* @return {ReactNode} Stripe Elements component.
*/
const ExpressCheckoutComponent = ( {
api,
billing,
shippingData,
setExpressPaymentError,
onClick,
onClose,
expressPaymentMethod = '',
buttonAttributes,
isPreview = false,
} ) => {
const {
buttonOptions,
onButtonClick,
onConfirm,
onReady,
onCancel,
elements,
} = useExpressCheckout( {
api,
billing,
shippingData,
onClick,
onClose,
setExpressPaymentError,
} );
const onClickHandler = ! isPreview ? onButtonClick : () => {};
const onShippingAddressChange = ( event ) =>
shippingAddressChangeHandler( api, event, elements );

const onShippingRateChange = ( event ) =>
shippingRateChangeHandler( api, event, elements );

const onElementsReady = ( event ) => {
const paymentMethodContainer = document.getElementById(
`express-payment-method-${ PAYMENT_METHOD_NAME_EXPRESS_CHECKOUT_ELEMENT }_${ expressPaymentMethod }`
);

const availablePaymentMethods = event.availablePaymentMethods || {};

if (
paymentMethodContainer &&
! availablePaymentMethods[ expressPaymentMethod ]
) {
paymentMethodContainer.remove();
}

// Any actions that WooPayments needs to perform.
onReady( event );
};

// The Cart & Checkout blocks provide unified styles across all buttons,
// which should override the extension specific settings.
const withBlockOverride = () => {
const override = {};
if ( typeof buttonAttributes !== 'undefined' ) {
override.buttonHeight = Number( buttonAttributes.height );
}
return {
...buttonOptions,
...override,
};
};

return (
<ExpressCheckoutElement
options={ {
...withBlockOverride( buttonOptions ),
...adjustButtonHeights(
withBlockOverride( buttonOptions ),
expressPaymentMethod
),
...getPaymentMethodsOverride( expressPaymentMethod ),
} }
onClick={ onClickHandler }
onConfirm={ onConfirm }
onReady={ onElementsReady }
onCancel={ onCancel }
onShippingAddressChange={ onShippingAddressChange }
onShippingRateChange={ onShippingRateChange }
/>
);
};

export default ExpressCheckoutComponent;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* External dependencies
*/
import { useMemo } from 'react';
import { Elements } from '@stripe/react-stripe-js';

/**
* Internal dependencies
*/
import ExpressCheckoutComponent from './express-checkout-component';
import {
getExpressCheckoutButtonAppearance,
getExpressCheckoutData,
} from 'wcpay/express-checkout/utils';
import '../express-checkout-element.scss';

const ExpressCheckoutContainer = ( props ) => {
const { api, billing, buttonAttributes, isPreview } = props;

const stripePromise = useMemo( () => {
return api.loadStripeForExpressCheckout();
}, [ api ] );

const options = {
mode: 'payment',
paymentMethodCreation: 'manual',
amount: ! isPreview ? billing.cartTotal.value : 10,
currency: ! isPreview ? billing.currency.code.toLowerCase() : 'usd',
appearance: getExpressCheckoutButtonAppearance( buttonAttributes ),
locale: getExpressCheckoutData( 'stripe' )?.locale ?? 'en',
};

return (
<div style={ { minHeight: '40px' } }>
<Elements stripe={ stripePromise } options={ options }>
<ExpressCheckoutComponent { ...props } />
</Elements>
</div>
);
};

export default ExpressCheckoutContainer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* External dependencies
*/
import { useState } from 'react';
import { Elements, ExpressCheckoutElement } from '@stripe/react-stripe-js';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import InlineNotice from 'components/inline-notice';
import { getDefaultBorderRadius } from 'wcpay/utils/express-checkout';

export const ExpressCheckoutPreviewComponent = ( {
stripe,
buttonType,
theme,
height,
radius,
} ) => {
const [ canRenderButtons, setCanRenderButtons ] = useState( true );

const options = {
mode: 'payment',
amount: 1000,
currency: 'usd',
appearance: {
variables: {
borderRadius: `${ radius ?? getDefaultBorderRadius() }px`,
spacingUnit: '6px',
},
},
};

const mapThemeConfigToButtonTheme = ( paymentMethod, buttonTheme ) => {
switch ( buttonTheme ) {
case 'dark':
return 'black';
case 'light':
return 'white';
case 'light-outline':
if ( paymentMethod === 'googlePay' ) {
return 'white';
}

return 'white-outline';
default:
return 'black';
}
};

const type = buttonType === 'default' ? 'plain' : buttonType;

const buttonOptions = {
buttonHeight: Math.min( Math.max( height, 40 ), 55 ),
buttonTheme: {
googlePay: mapThemeConfigToButtonTheme( 'googlePay', theme ),
applePay: mapThemeConfigToButtonTheme( 'applePay', theme ),
},
buttonType: {
googlePay: type,
applePay: type,
},
paymentMethods: {
link: 'never',
googlePay: 'always',
applePay: 'always',
},
layout: { overflow: 'never' },
};

const onReady = ( { availablePaymentMethods } ) => {
if ( availablePaymentMethods ) {
setCanRenderButtons( true );
} else {
setCanRenderButtons( false );
}
};

if ( canRenderButtons ) {
return (
<div
key={ `${ buttonType }-${ theme }` }
style={ { minHeight: `${ height }px`, width: '100%' } }
>
<Elements stripe={ stripe } options={ options }>
<ExpressCheckoutElement
options={ buttonOptions }
onClick={ () => {} }
onReady={ onReady }
/>
</Elements>
</div>
);
}

return (
<InlineNotice icon status="error" isDismissible={ false }>
{ __(
'Failed to preview the Apple Pay or Google Pay button. ' +
'Ensure your store uses HTTPS on a publicly available domain ' +
"and you're viewing this page in a Safari or Chrome browser. " +
'Your device must be configured to use Apple Pay or Google Pay.',
'woocommerce-payments'
) }
</InlineNotice>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Cart Block
.wc-block-components-express-payment--cart {
.wc-block-components-express-payment__event-buttons > li {
padding-bottom: 12px !important;

&:last-child {
padding-bottom: 0 !important;
}
}
}

// OR separator
.wc-block-components-express-payment-continue-rule--cart {
margin: 24px 0 !important;
height: 20px;
}

.wc-block-components-express-payment
.wc-block-components-express-payment__event-buttons
> li {
margin-left: 1px !important;
width: 99% !important;
}
Loading

0 comments on commit f358e9d

Please sign in to comment.