Skip to content

Commit

Permalink
Show Express Checkout button previews in editor (#10141)
Browse files Browse the repository at this point in the history
Co-authored-by: Francesco <[email protected]>
  • Loading branch information
danielmx-dev and frosso authored Feb 28, 2025
1 parent d14e829 commit e4b3f99
Show file tree
Hide file tree
Showing 7 changed files with 340 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: fix

Show Express Checkout button previews in template editor
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* External dependencies
*/
import { useEffect, useRef } from 'react';

/**
* Internal dependencies
*/
import { getExpressCheckoutButtonAppearance } from '../../utils';

export const SUPPORTED_PREVIEW_PAYMENT_METHODS = [ 'googlePay', 'applePay' ];

const GooglePayButtonPreview = ( { options, buttonAttributes, theme } ) => {
const googlePlayContainerRef = useRef( null );
const hasStartedLoadingGooglePlayButton = useRef( null );
const appearance = getExpressCheckoutButtonAppearance( buttonAttributes );
const borderRadius = appearance.variables.borderRadius;

useEffect( () => {
if (
googlePlayContainerRef.current &&
! hasStartedLoadingGooglePlayButton.current
) {
hasStartedLoadingGooglePlayButton.current = true;
( async () => {
// The container may be inside an iframe, so we need to retrieve a reference to the document and window objects.
const targetDocument =
googlePlayContainerRef.current.ownerDocument;
const targetWindow = targetDocument.defaultView;
if ( ! targetWindow.google?.payments?.api?.PaymentsClient ) {
await new Promise( ( resolve ) => {
const script = document.createElement( 'script' );
script.src = 'https://pay.google.com/gp/p/js/pay.js';
script.onload = resolve;
targetDocument.head.appendChild( script );
} );
}

const googlePayClient = new targetWindow.google.payments.api.PaymentsClient(
{
environment: 'TEST',
}
);

const buttonColor = theme === 'black' ? 'black' : 'white'; // There is no 'outline' theme in Google Pay.

const button = googlePayClient.createButton( {
buttonType: options.buttonType.googlePay,
buttonColor,
buttonRadius: parseFloat( borderRadius ),
buttonSizeMode: 'fill',
onClick: () => {},
} );
googlePlayContainerRef.current.appendChild( button );
} )();
}
}, [ theme, borderRadius, options.buttonType.googlePay ] );

useEffect( () => {
googlePlayContainerRef.current
?.querySelector( 'button' )
?.style?.setProperty( 'border-radius', borderRadius );
}, [ borderRadius ] );

return (
<div
ref={ googlePlayContainerRef }
id="express-checkout-button-preview-googlePay"
style={ {
height: `${ options.buttonHeight }px`,
width: '100%',
} }
/>
);
};

const ApplePayButtonPreview = ( { options, buttonAttributes, theme } ) => {
const appearance = getExpressCheckoutButtonAppearance( buttonAttributes );
const borderRadius = appearance.variables.borderRadius;

const buttonStyle = {
height: `${ options.buttonHeight }px`,
borderRadius,
ApplePayButtonType: options.buttonType.applePay,
WebkitAppearance: '-apple-pay-button',
width: '100%',
};

if ( [ 'black', 'white', 'white-outline' ].includes( theme ) ) {
buttonStyle.ApplePayButtonStyle = theme;
} else {
buttonStyle.ApplePayButtonStyle = 'white';
}

return (
<div>
<button
type="button"
id="express-checkout-button-preview-applePay"
className="express-checkout-button-preview"
style={ buttonStyle }
/>
</div>
);
};

const ExpressCheckoutButtonPreview = ( {
expressPaymentMethod,
options,
buttonAttributes,
} ) => {
const theme = options.buttonTheme[ expressPaymentMethod ];

if ( expressPaymentMethod === 'googlePay' ) {
return (
<GooglePayButtonPreview
options={ options }
buttonAttributes={ buttonAttributes }
theme={ theme }
/>
);
}

if ( expressPaymentMethod === 'applePay' ) {
return (
<ApplePayButtonPreview
options={ options }
buttonAttributes={ buttonAttributes }
theme={ theme }
/>
);
}

return null;
};

export default ExpressCheckoutButtonPreview;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {
} from '../../event-handlers';
import { useExpressCheckout } from '../hooks/use-express-checkout';
import { PAYMENT_METHOD_NAME_EXPRESS_CHECKOUT_ELEMENT } from 'wcpay/checkout/constants';
import ExpressCheckoutButtonPreview, {
SUPPORTED_PREVIEW_PAYMENT_METHODS,
} from './express-checkout-button-preview';

const getPaymentMethodsOverride = ( enabledPaymentMethod ) => {
const allDisabled = {
Expand Down Expand Up @@ -131,16 +134,28 @@ const ExpressCheckoutComponent = ( {
};
};

const checkoutElementOptions = {
...withBlockOverride(),
...adjustButtonHeights( withBlockOverride(), expressPaymentMethod ),
...getPaymentMethodsOverride( expressPaymentMethod ),
};

if (
isPreview &&
SUPPORTED_PREVIEW_PAYMENT_METHODS.includes( expressPaymentMethod )
) {
return (
<ExpressCheckoutButtonPreview
expressPaymentMethod={ expressPaymentMethod }
buttonAttributes={ buttonAttributes }
options={ checkoutElementOptions }
/>
);
}

return (
<ExpressCheckoutElement
options={ {
...withBlockOverride(),
...adjustButtonHeights(
withBlockOverride(),
expressPaymentMethod
),
...getPaymentMethodsOverride( expressPaymentMethod ),
} }
options={ checkoutElementOptions }
onClick={ onClickHandler }
onConfirm={ onConfirm }
onReady={ onElementsReady }
Expand Down
8 changes: 8 additions & 0 deletions client/express-checkout/blocks/express-checkout-element.scss
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@
margin-left: 1px !important;
width: 99% !important;
}

// Preview button
@supports not ( -webkit-appearance: -apple-pay-button ) {
/* stylelint-disable-next-line selector-id-pattern */
#express-payment-method-woocommerce_payments_express_checkout_applePay:has( #express-checkout-button-preview-applePay ) {
display: none;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* External dependencies
*/
import { useEffect, useRef } from 'react';

/**
* Internal dependencies
*/
import { getExpressCheckoutButtonAppearance } from '../../utils';

export const SUPPORTED_PREVIEW_PAYMENT_METHODS = [ 'googlePay', 'applePay' ];

const GooglePayButtonPreview = ( { options, buttonAttributes, theme } ) => {
const googlePlayContainerRef = useRef( null );
const hasStartedLoadingGooglePlayButton = useRef( null );
const appearance = getExpressCheckoutButtonAppearance( buttonAttributes );
const borderRadius = appearance.variables.borderRadius;

useEffect( () => {
if (
googlePlayContainerRef.current &&
! hasStartedLoadingGooglePlayButton.current
) {
hasStartedLoadingGooglePlayButton.current = true;
( async () => {
// The container may be inside an iframe, so we need to retrieve a reference to the document and window objects.
const targetDocument =
googlePlayContainerRef.current.ownerDocument;
const targetWindow = targetDocument.defaultView;
if ( ! targetWindow.google?.payments?.api?.PaymentsClient ) {
await new Promise( ( resolve ) => {
const script = document.createElement( 'script' );
script.src = 'https://pay.google.com/gp/p/js/pay.js';
script.onload = resolve;
targetDocument.head.appendChild( script );
} );
}

const googlePayClient = new targetWindow.google.payments.api.PaymentsClient(
{
environment: 'TEST',
}
);

const buttonColor = theme === 'black' ? 'black' : 'white'; // There is no 'outline' theme in Google Pay.

const button = googlePayClient.createButton( {
buttonType: options.buttonType.googlePay,
buttonColor,
buttonRadius: parseFloat( borderRadius ),
buttonSizeMode: 'fill',
onClick: () => {},
} );
googlePlayContainerRef.current.appendChild( button );
} )();
}
}, [ theme, borderRadius, options.buttonType.googlePay ] );

useEffect( () => {
googlePlayContainerRef.current
?.querySelector( 'button' )
?.style?.setProperty( 'border-radius', borderRadius );
}, [ borderRadius ] );

return (
<div
ref={ googlePlayContainerRef }
id="express-checkout-button-preview-googlePay"
style={ {
height: `${ options.buttonHeight }px`,
width: '100%',
} }
/>
);
};

const ApplePayButtonPreview = ( { options, buttonAttributes, theme } ) => {
const appearance = getExpressCheckoutButtonAppearance( buttonAttributes );
const borderRadius = appearance.variables.borderRadius;

const buttonStyle = {
height: `${ options.buttonHeight }px`,
borderRadius,
ApplePayButtonType: options.buttonType.applePay,
WebkitAppearance: '-apple-pay-button',
width: '100%',
};

if ( [ 'black', 'white', 'white-outline' ].includes( theme ) ) {
buttonStyle.ApplePayButtonStyle = theme;
} else {
buttonStyle.ApplePayButtonStyle = 'white';
}

return (
<div>
<button
type="button"
id="express-checkout-button-preview-applePay"
className="express-checkout-button-preview"
style={ buttonStyle }
/>
</div>
);
};

const ExpressCheckoutButtonPreview = ( {
expressPaymentMethod,
options,
buttonAttributes,
} ) => {
const theme = options.buttonTheme[ expressPaymentMethod ];

if ( expressPaymentMethod === 'googlePay' ) {
return (
<GooglePayButtonPreview
options={ options }
buttonAttributes={ buttonAttributes }
theme={ theme }
/>
);
}

if ( expressPaymentMethod === 'applePay' ) {
return (
<ApplePayButtonPreview
options={ options }
buttonAttributes={ buttonAttributes }
theme={ theme }
/>
);
}

return null;
};

export default ExpressCheckoutButtonPreview;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {
} from '../../event-handlers';
import { useExpressCheckout } from '../hooks/use-express-checkout';
import { PAYMENT_METHOD_NAME_EXPRESS_CHECKOUT_ELEMENT } from 'wcpay/checkout/constants';
import ExpressCheckoutButtonPreview, {
SUPPORTED_PREVIEW_PAYMENT_METHODS,
} from './express-checkout-button-preview';

const getPaymentMethodsOverride = ( enabledPaymentMethod ) => {
const allDisabled = {
Expand Down Expand Up @@ -131,16 +134,28 @@ const ExpressCheckoutComponent = ( {
};
};

const checkoutElementOptions = {
...withBlockOverride(),
...adjustButtonHeights( withBlockOverride(), expressPaymentMethod ),
...getPaymentMethodsOverride( expressPaymentMethod ),
};

if (
isPreview &&
SUPPORTED_PREVIEW_PAYMENT_METHODS.includes( expressPaymentMethod )
) {
return (
<ExpressCheckoutButtonPreview
expressPaymentMethod={ expressPaymentMethod }
buttonAttributes={ buttonAttributes }
options={ checkoutElementOptions }
/>
);
}

return (
<ExpressCheckoutElement
options={ {
...withBlockOverride(),
...adjustButtonHeights(
withBlockOverride(),
expressPaymentMethod
),
...getPaymentMethodsOverride( expressPaymentMethod ),
} }
options={ checkoutElementOptions }
onClick={ onClickHandler }
onConfirm={ onConfirm }
onReady={ onElementsReady }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,11 @@
margin-left: 1px !important;
width: 99% !important;
}

// Preview button
@supports not ( -webkit-appearance: -apple-pay-button ) {
/* stylelint-disable-next-line selector-id-pattern */
#express-payment-method-woocommerce_payments_express_checkout_applePay:has( #express-checkout-button-preview-applePay ) {
display: none;
}
}

0 comments on commit e4b3f99

Please sign in to comment.