diff --git a/changelog/fix-show-preview-for-express-checkout-buttons-in-editor b/changelog/fix-show-preview-for-express-checkout-buttons-in-editor new file mode 100644 index 00000000000..86092b348d7 --- /dev/null +++ b/changelog/fix-show-preview-for-express-checkout-buttons-in-editor @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Show Express Checkout button previews in template editor diff --git a/client/express-checkout/blocks/components/express-checkout-button-preview.js b/client/express-checkout/blocks/components/express-checkout-button-preview.js new file mode 100644 index 00000000000..f7103875833 --- /dev/null +++ b/client/express-checkout/blocks/components/express-checkout-button-preview.js @@ -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 ( +
+ ); +}; + +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 ( +
+
+ ); +}; + +const ExpressCheckoutButtonPreview = ( { + expressPaymentMethod, + options, + buttonAttributes, +} ) => { + const theme = options.buttonTheme[ expressPaymentMethod ]; + + if ( expressPaymentMethod === 'googlePay' ) { + return ( + + ); + } + + if ( expressPaymentMethod === 'applePay' ) { + return ( + + ); + } + + return null; +}; + +export default ExpressCheckoutButtonPreview; diff --git a/client/express-checkout/blocks/components/express-checkout-component.js b/client/express-checkout/blocks/components/express-checkout-component.js index bccfee2eb93..02d99524acd 100644 --- a/client/express-checkout/blocks/components/express-checkout-component.js +++ b/client/express-checkout/blocks/components/express-checkout-component.js @@ -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 = { @@ -131,16 +134,28 @@ const ExpressCheckoutComponent = ( { }; }; + const checkoutElementOptions = { + ...withBlockOverride(), + ...adjustButtonHeights( withBlockOverride(), expressPaymentMethod ), + ...getPaymentMethodsOverride( expressPaymentMethod ), + }; + + if ( + isPreview && + SUPPORTED_PREVIEW_PAYMENT_METHODS.includes( expressPaymentMethod ) + ) { + return ( + + ); + } + return ( { + 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 ( +
+ ); +}; + +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 ( +
+
+ ); +}; + +const ExpressCheckoutButtonPreview = ( { + expressPaymentMethod, + options, + buttonAttributes, +} ) => { + const theme = options.buttonTheme[ expressPaymentMethod ]; + + if ( expressPaymentMethod === 'googlePay' ) { + return ( + + ); + } + + if ( expressPaymentMethod === 'applePay' ) { + return ( + + ); + } + + return null; +}; + +export default ExpressCheckoutButtonPreview; diff --git a/client/tokenized-express-checkout/blocks/components/express-checkout-component.js b/client/tokenized-express-checkout/blocks/components/express-checkout-component.js index 9975b56d406..b794b083e0b 100644 --- a/client/tokenized-express-checkout/blocks/components/express-checkout-component.js +++ b/client/tokenized-express-checkout/blocks/components/express-checkout-component.js @@ -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 = { @@ -131,16 +134,28 @@ const ExpressCheckoutComponent = ( { }; }; + const checkoutElementOptions = { + ...withBlockOverride(), + ...adjustButtonHeights( withBlockOverride(), expressPaymentMethod ), + ...getPaymentMethodsOverride( expressPaymentMethod ), + }; + + if ( + isPreview && + SUPPORTED_PREVIEW_PAYMENT_METHODS.includes( expressPaymentMethod ) + ) { + return ( + + ); + } + return (