-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Show Express Checkout button previews in editor #10141
Changes from 11 commits
63184d1
ff760c9
b2837a7
432fd73
f2ee578
36a4544
5e94840
1fe5984
2d27578
60f6cb2
b087475
eca4c98
8b9986c
987368a
bc6a1a0
aaa14f8
d327efb
3fa843e
0301252
d22ea91
13de3e2
f26c0ad
5babdc1
b0abd9b
a86db03
8c754f1
120794a
ab4eb29
8426805
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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,112 @@ | ||||||
/** | ||||||
* External dependencies | ||||||
*/ | ||||||
import { useEffect, useMemo, useRef } from 'react'; | ||||||
|
||||||
/** | ||||||
* Internal dependencies | ||||||
*/ | ||||||
import { getExpressCheckoutButtonAppearance } from 'wcpay/express-checkout/utils'; | ||||||
|
||||||
const ExpressCheckoutButtonPreview = ( { | ||||||
frosso marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
expressPaymentMethod, | ||||||
options, | ||||||
buttonAttributes, | ||||||
} ) => { | ||||||
const appearance = useMemo( | ||||||
() => getExpressCheckoutButtonAppearance( buttonAttributes ), | ||||||
[ buttonAttributes ] | ||||||
); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar observation as the one I made in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this scenario I did it to avoid recalculating the border radius with every render, but the savings are probably negligible, I'll just remove it and see how it performs. |
||||||
const ref = useRef( null ); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be possible to use a less generic |
||||||
const renderGooglePayButtonPromise = useRef( null ); | ||||||
|
||||||
const theme = options.buttonTheme[ expressPaymentMethod ]; | ||||||
const borderRadius = appearance.variables.borderRadius; | ||||||
|
||||||
useEffect( () => { | ||||||
if ( | ||||||
ref.current && | ||||||
expressPaymentMethod === 'googlePay' && | ||||||
! renderGooglePayButtonPromise.current | ||||||
) { | ||||||
renderGooglePayButtonPromise.current = ( async () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm curious about the assignment of this function to i.e.: something like this: diff --git a/client/tokenized-express-checkout/blocks/components/express-checkout-button-preview.js b/client/tokenized-express-checkout/blocks/components/express-checkout-button-preview.js
index b612e0202..1fce7c0d4 100644
--- a/client/tokenized-express-checkout/blocks/components/express-checkout-button-preview.js
+++ b/client/tokenized-express-checkout/blocks/components/express-checkout-button-preview.js
@@ -18,7 +18,7 @@ const ExpressCheckoutButtonPreview = ( {
[ buttonAttributes ]
);
const ref = useRef( null );
- const renderGooglePayButtonPromise = useRef( null );
+ const hasStartedLoadingGooglePlayButton = useRef( false );
const theme = options.buttonTheme[ expressPaymentMethod ];
const borderRadius = appearance.variables.borderRadius;
@@ -27,9 +27,10 @@ const ExpressCheckoutButtonPreview = ( {
if (
ref.current &&
expressPaymentMethod === 'googlePay' &&
- ! renderGooglePayButtonPromise.current
+ ! hasStartedLoadingGooglePlayButton.current
) {
- renderGooglePayButtonPromise.current = ( async () => {
+ hasStartedLoadingGooglePlayButton.current = true;
+ ( async () => {
const targetDocument = ref.current.ownerDocument;
const targetWindow = targetDocument.defaultView;
if ( ! targetWindow.google?.payments?.api?.PaymentsClient ) {
|
||||||
const targetDocument = ref.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: 'plain', | ||||||
buttonColor, | ||||||
buttonRadius: parseFloat( borderRadius ), | ||||||
buttonSizeMode: 'fill', | ||||||
onClick: () => {}, | ||||||
} ); | ||||||
ref.current.appendChild( button ); | ||||||
} )(); | ||||||
} | ||||||
}, [ ref, theme, expressPaymentMethod, borderRadius ] ); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Return values from |
||||||
|
||||||
useEffect( () => { | ||||||
ref.current | ||||||
?.querySelector( 'button' ) | ||||||
?.style?.setProperty( 'border-radius', borderRadius ); | ||||||
}, [ ref, borderRadius ] ); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
if ( expressPaymentMethod === 'googlePay' ) { | ||||||
return ( | ||||||
<div | ||||||
ref={ ref } | ||||||
style={ { | ||||||
height: `${ options.buttonHeight }px`, | ||||||
width: '100%', | ||||||
} } | ||||||
/> | ||||||
); | ||||||
} | ||||||
|
||||||
const buttonStyle = { | ||||||
height: `${ options.buttonHeight }px`, | ||||||
borderRadius, | ||||||
}; | ||||||
|
||||||
if ( expressPaymentMethod === 'applePay' ) { | ||||||
buttonStyle.WebkitAppearance = '-apple-pay-button'; | ||||||
if ( theme === 'black' ) { | ||||||
buttonStyle.ApplePayButtonStyle = 'black'; | ||||||
} else if ( theme === 'outline' ) { | ||||||
buttonStyle.ApplePayButtonStyle = 'white-outline'; | ||||||
} else { | ||||||
buttonStyle.ApplePayButtonStyle = 'white'; | ||||||
} | ||||||
|
||||||
return ( | ||||||
<div> | ||||||
<button | ||||||
type="button" | ||||||
id={ `express-checkout-button-preview-${ expressPaymentMethod }` } | ||||||
className="express-checkout-button-preview" | ||||||
style={ buttonStyle } | ||||||
/> | ||||||
</div> | ||||||
); | ||||||
} | ||||||
|
||||||
return null; | ||||||
}; | ||||||
|
||||||
export default ExpressCheckoutButtonPreview; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,6 +1,7 @@ | ||||||
/** | ||||||
* External dependencies | ||||||
*/ | ||||||
import { useEffect, useMemo, useRef, useState } from 'react'; | ||||||
import { ExpressCheckoutElement } from '@stripe/react-stripe-js'; | ||||||
/** | ||||||
* Internal dependencies | ||||||
|
@@ -11,6 +12,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 from './express-checkout-button-preview'; | ||||||
|
||||||
const FALLBACK_BUTTON_WAIT_TIME = 3000; // 3 seconds | ||||||
|
||||||
const getPaymentMethodsOverride = ( enabledPaymentMethod ) => { | ||||||
const allDisabled = { | ||||||
|
@@ -93,6 +97,8 @@ const ExpressCheckoutComponent = ( { | |||||
onClose, | ||||||
setExpressPaymentError, | ||||||
} ); | ||||||
const [ showFallbackButton, setShowFallbackButton ] = useState( false ); | ||||||
const onElementsReadyCalled = useRef( false ); | ||||||
const onClickHandler = ! isPreview ? onButtonClick : () => {}; | ||||||
const onShippingAddressChange = ( event ) => | ||||||
shippingAddressChangeHandler( event, elements ); | ||||||
|
@@ -101,6 +107,7 @@ const ExpressCheckoutComponent = ( { | |||||
shippingRateChangeHandler( event, elements ); | ||||||
|
||||||
const onElementsReady = ( event ) => { | ||||||
onElementsReadyCalled.current = true; | ||||||
const paymentMethodContainer = document.getElementById( | ||||||
`express-payment-method-${ PAYMENT_METHOD_NAME_EXPRESS_CHECKOUT_ELEMENT }_${ expressPaymentMethod }` | ||||||
); | ||||||
|
@@ -118,29 +125,53 @@ const ExpressCheckoutComponent = ( { | |||||
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 ); | ||||||
} | ||||||
const checkoutElementOptions = useMemo( () => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure
The So, I noticed that Is there a specific scenario you were thinking There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was leftover from when why was trying another approach. I'll remove the |
||||||
// 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 { | ||||||
...buttonOptions, | ||||||
...override, | ||||||
...withBlockOverride(), | ||||||
...adjustButtonHeights( withBlockOverride(), expressPaymentMethod ), | ||||||
...getPaymentMethodsOverride( expressPaymentMethod ), | ||||||
}; | ||||||
}; | ||||||
}, [ expressPaymentMethod, buttonAttributes, buttonOptions ] ); | ||||||
|
||||||
useEffect( () => { | ||||||
if ( ! isPreview || onElementsReadyCalled.current ) { | ||||||
return; | ||||||
} | ||||||
|
||||||
const handle = setTimeout( () => { | ||||||
if ( ! onElementsReadyCalled.current ) { | ||||||
setShowFallbackButton( true ); | ||||||
} | ||||||
}, FALLBACK_BUTTON_WAIT_TIME ); | ||||||
|
||||||
return () => clearTimeout( handle ); | ||||||
}, [ isPreview, onElementsReadyCalled ] ); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
The value returned by |
||||||
|
||||||
if ( showFallbackButton ) { | ||||||
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 } | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this file is within the
tokenized-express-checkout
, it's best to include the functions from that directory, rather than theexpress-checkout
directory (which doesn't include "tokenized" cart changes).Otherwise the bundles are going to get mixed, and there might be modifications in the "tokenized" functions that wouldn't be considered.