mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-09-06 10:55:00 +08:00
Merge pull request #2688 from woocommerce/PCP-3374-google-pay-button-not-displayed-in-the-word-press-editor-v2
Google Pay: Fix button preview in the editor (3374)
This commit is contained in:
commit
469d42f6bb
8 changed files with 287 additions and 90 deletions
|
@ -0,0 +1,53 @@
|
||||||
|
import { useState, useEffect } from '@wordpress/element';
|
||||||
|
import useGooglepayApiToGenerateButton from '../hooks/useGooglepayApiToGenerateButton';
|
||||||
|
import usePayPalScript from '../hooks/usePayPalScript';
|
||||||
|
import useGooglepayScript from '../hooks/useGooglepayScript';
|
||||||
|
import useGooglepayConfig from '../hooks/useGooglepayConfig';
|
||||||
|
|
||||||
|
const GooglepayButton = ( { namespace, buttonConfig, ppcpConfig } ) => {
|
||||||
|
const [ buttonHtml, setButtonHtml ] = useState( '' );
|
||||||
|
const [ buttonElement, setButtonElement ] = useState( null );
|
||||||
|
const [ componentFrame, setComponentFrame ] = useState( null );
|
||||||
|
const isPayPalLoaded = usePayPalScript( namespace, ppcpConfig );
|
||||||
|
|
||||||
|
const isGooglepayLoaded = useGooglepayScript(
|
||||||
|
componentFrame,
|
||||||
|
buttonConfig,
|
||||||
|
isPayPalLoaded
|
||||||
|
);
|
||||||
|
|
||||||
|
const googlepayConfig = useGooglepayConfig( namespace, isGooglepayLoaded );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
if ( ! buttonElement ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setComponentFrame( buttonElement.ownerDocument );
|
||||||
|
}, [ buttonElement ] );
|
||||||
|
|
||||||
|
const googlepayButton = useGooglepayApiToGenerateButton(
|
||||||
|
componentFrame,
|
||||||
|
namespace,
|
||||||
|
buttonConfig,
|
||||||
|
ppcpConfig,
|
||||||
|
googlepayConfig
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
if ( googlepayButton ) {
|
||||||
|
const hideLoader =
|
||||||
|
'<style>.block-editor-iframe__html .gpay-card-info-animated-progress-bar-container {display:none !important}</style>';
|
||||||
|
setButtonHtml( googlepayButton.outerHTML + hideLoader );
|
||||||
|
}
|
||||||
|
}, [ googlepayButton ] );
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={ setButtonElement }
|
||||||
|
dangerouslySetInnerHTML={ { __html: buttonHtml } }
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default GooglepayButton;
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { useMemo } from '@wordpress/element';
|
||||||
|
import { combineStyles } from '../../../../../ppcp-button/resources/js/modules/Helper/PaymentButtonHelpers';
|
||||||
|
|
||||||
|
const useButtonStyles = ( buttonConfig, ppcpConfig ) => {
|
||||||
|
return useMemo( () => {
|
||||||
|
const styles = combineStyles(
|
||||||
|
ppcpConfig?.button || {},
|
||||||
|
buttonConfig?.button || {}
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( styles.MiniCart && styles.MiniCart.type === 'buy' ) {
|
||||||
|
styles.MiniCart.type = 'pay';
|
||||||
|
}
|
||||||
|
|
||||||
|
return styles;
|
||||||
|
}, [ buttonConfig, ppcpConfig ] );
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useButtonStyles;
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { useEffect, useState } from '@wordpress/element';
|
||||||
|
import useButtonStyles from './useButtonStyles';
|
||||||
|
|
||||||
|
const useGooglepayApiToGenerateButton = (
|
||||||
|
componentDocument,
|
||||||
|
namespace,
|
||||||
|
buttonConfig,
|
||||||
|
ppcpConfig,
|
||||||
|
googlepayConfig
|
||||||
|
) => {
|
||||||
|
const [ googlepayButton, setGooglepayButton ] = useState( null );
|
||||||
|
const buttonStyles = useButtonStyles( buttonConfig, ppcpConfig );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
if (
|
||||||
|
! componentDocument?.defaultView ||
|
||||||
|
! buttonConfig ||
|
||||||
|
! googlepayConfig
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const api = componentDocument.defaultView.google?.payments?.api;
|
||||||
|
if ( ! api ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const paymentsClient = new api.PaymentsClient( {
|
||||||
|
environment: 'TEST',
|
||||||
|
} );
|
||||||
|
|
||||||
|
const googlePayButtonOptions = {
|
||||||
|
allowedPaymentMethods: googlepayConfig.allowedPaymentMethods,
|
||||||
|
buttonColor: buttonConfig.buttonColor || 'black',
|
||||||
|
buttonType: buttonConfig.buttonType || 'pay',
|
||||||
|
buttonLocale: buttonConfig.buttonLocale || 'en',
|
||||||
|
buttonSizeMode: 'fill',
|
||||||
|
};
|
||||||
|
|
||||||
|
const button = paymentsClient.createButton( {
|
||||||
|
...googlePayButtonOptions,
|
||||||
|
onClick: ( event ) => {
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
} );
|
||||||
|
|
||||||
|
setGooglepayButton( button );
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
setGooglepayButton( null );
|
||||||
|
};
|
||||||
|
}, [ namespace, buttonConfig, ppcpConfig, googlepayConfig, buttonStyles ] );
|
||||||
|
|
||||||
|
return googlepayButton;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useGooglepayApiToGenerateButton;
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { useState, useEffect } from '@wordpress/element';
|
||||||
|
|
||||||
|
const useGooglepayConfig = ( namespace, isGooglepayLoaded ) => {
|
||||||
|
const [ googlePayConfig, setGooglePayConfig ] = useState( null );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
const fetchConfig = async () => {
|
||||||
|
if ( ! isGooglepayLoaded ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const config = await window[ namespace ].Googlepay().config();
|
||||||
|
setGooglePayConfig( config );
|
||||||
|
} catch ( error ) {
|
||||||
|
console.error( 'Failed to fetch Google Pay config:', error );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchConfig();
|
||||||
|
}, [ namespace, isGooglepayLoaded ] );
|
||||||
|
|
||||||
|
return googlePayConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useGooglepayConfig;
|
|
@ -0,0 +1,65 @@
|
||||||
|
import { useState, useEffect } from '@wordpress/element';
|
||||||
|
import { loadCustomScript } from '@paypal/paypal-js';
|
||||||
|
|
||||||
|
const useGooglepayScript = (
|
||||||
|
componentDocument,
|
||||||
|
buttonConfig,
|
||||||
|
isPayPalLoaded
|
||||||
|
) => {
|
||||||
|
const [ isGooglepayLoaded, setIsGooglepayLoaded ] = useState( false );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
if ( ! componentDocument ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const injectScriptToFrame = ( scriptSrc ) => {
|
||||||
|
if ( document === componentDocument ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = document.querySelector(
|
||||||
|
`script[src^="${ scriptSrc }"]`
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( script ) {
|
||||||
|
const newScript = componentDocument.createElement( 'script' );
|
||||||
|
newScript.src = script.src;
|
||||||
|
newScript.async = script.async;
|
||||||
|
newScript.type = script.type;
|
||||||
|
|
||||||
|
componentDocument.head.appendChild( newScript );
|
||||||
|
} else {
|
||||||
|
console.error( 'Script not found in the document:', scriptSrc );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadGooglepayScript = async () => {
|
||||||
|
if ( ! isPayPalLoaded ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! buttonConfig || ! buttonConfig.sdk_url ) {
|
||||||
|
console.error( 'Invalid buttonConfig or missing sdk_url' );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await loadCustomScript( { url: buttonConfig.sdk_url } ).then(
|
||||||
|
() => {
|
||||||
|
injectScriptToFrame( buttonConfig.sdk_url );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setIsGooglepayLoaded( true );
|
||||||
|
} catch ( error ) {
|
||||||
|
console.error( 'Failed to load Googlepay script:', error );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadGooglepayScript();
|
||||||
|
}, [ componentDocument, buttonConfig, isPayPalLoaded ] );
|
||||||
|
|
||||||
|
return isGooglepayLoaded;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useGooglepayScript;
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { useState, useEffect } from '@wordpress/element';
|
||||||
|
import { loadPayPalScript } from '../../../../../ppcp-button/resources/js/modules/Helper/PayPalScriptLoading';
|
||||||
|
|
||||||
|
const usePayPalScript = ( namespace, ppcpConfig ) => {
|
||||||
|
const [ isPayPalLoaded, setIsPayPalLoaded ] = useState( false );
|
||||||
|
|
||||||
|
ppcpConfig.url_params.components += ',googlepay';
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
const loadScript = async () => {
|
||||||
|
try {
|
||||||
|
await loadPayPalScript( namespace, ppcpConfig );
|
||||||
|
setIsPayPalLoaded( true );
|
||||||
|
} catch ( error ) {
|
||||||
|
console.error( `Error loading PayPal script: ${ error }` );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadScript();
|
||||||
|
}, [ namespace, ppcpConfig ] );
|
||||||
|
|
||||||
|
return isPayPalLoaded;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default usePayPalScript;
|
|
@ -1,62 +1,15 @@
|
||||||
import GooglepayButton from './GooglepayButton';
|
import GooglepayButton from './Block/components/GooglepayButton';
|
||||||
import ContextHandlerFactory from './Context/ContextHandlerFactory';
|
|
||||||
|
|
||||||
class GooglepayManagerBlockEditor {
|
const GooglepayManagerBlockEditor = ( {
|
||||||
constructor( namespace, buttonConfig, ppcpConfig ) {
|
namespace,
|
||||||
this.namespace = namespace;
|
buttonConfig,
|
||||||
this.buttonConfig = buttonConfig;
|
ppcpConfig,
|
||||||
this.ppcpConfig = ppcpConfig;
|
} ) => (
|
||||||
this.googlePayConfig = null;
|
<GooglepayButton
|
||||||
this.transactionInfo = null;
|
namespace={ namespace }
|
||||||
this.contextHandler = null;
|
buttonConfig={ buttonConfig }
|
||||||
}
|
ppcpConfig={ ppcpConfig }
|
||||||
|
/>
|
||||||
init() {
|
|
||||||
( async () => {
|
|
||||||
await this.config();
|
|
||||||
} )();
|
|
||||||
}
|
|
||||||
|
|
||||||
async config() {
|
|
||||||
try {
|
|
||||||
// Gets GooglePay configuration of the PayPal merchant.
|
|
||||||
this.googlePayConfig = await window[ this.namespace ]
|
|
||||||
.Googlepay()
|
|
||||||
.config();
|
|
||||||
|
|
||||||
// Fetch transaction information.
|
|
||||||
this.transactionInfo = await this.fetchTransactionInfo();
|
|
||||||
|
|
||||||
const button = new GooglepayButton(
|
|
||||||
this.ppcpConfig.context,
|
|
||||||
null,
|
|
||||||
this.buttonConfig,
|
|
||||||
this.ppcpConfig,
|
|
||||||
this.contextHandler
|
|
||||||
);
|
);
|
||||||
|
|
||||||
button.init( this.googlePayConfig, this.transactionInfo );
|
|
||||||
} catch ( error ) {
|
|
||||||
console.error( 'Failed to initialize Google Pay:', error );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchTransactionInfo() {
|
|
||||||
try {
|
|
||||||
if ( ! this.contextHandler ) {
|
|
||||||
this.contextHandler = ContextHandlerFactory.create(
|
|
||||||
this.ppcpConfig.context,
|
|
||||||
this.buttonConfig,
|
|
||||||
this.ppcpConfig,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
} catch ( error ) {
|
|
||||||
console.error( 'Error fetching transaction info:', error );
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default GooglepayManagerBlockEditor;
|
export default GooglepayManagerBlockEditor;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { useEffect, useState } from '@wordpress/element';
|
import { useEffect, useState } from '@wordpress/element';
|
||||||
|
import { loadCustomScript } from '@paypal/paypal-js';
|
||||||
import {
|
import {
|
||||||
registerExpressPaymentMethod,
|
registerExpressPaymentMethod,
|
||||||
registerPaymentMethod,
|
registerPaymentMethod,
|
||||||
|
@ -6,7 +7,6 @@ import {
|
||||||
import { __ } from '@wordpress/i18n';
|
import { __ } from '@wordpress/i18n';
|
||||||
import { loadPayPalScript } from '../../../ppcp-button/resources/js/modules/Helper/PayPalScriptLoading';
|
import { loadPayPalScript } from '../../../ppcp-button/resources/js/modules/Helper/PayPalScriptLoading';
|
||||||
import GooglepayManager from './GooglepayManager';
|
import GooglepayManager from './GooglepayManager';
|
||||||
import { loadCustomScript } from '@paypal/paypal-js';
|
|
||||||
import GooglepayManagerBlockEditor from './GooglepayManagerBlockEditor';
|
import GooglepayManagerBlockEditor from './GooglepayManagerBlockEditor';
|
||||||
|
|
||||||
const ppcpData = wc.wcSettings.getSetting( 'ppcp-gateway_data' );
|
const ppcpData = wc.wcSettings.getSetting( 'ppcp-gateway_data' );
|
||||||
|
@ -20,21 +20,19 @@ if ( typeof window.PayPalCommerceGateway === 'undefined' ) {
|
||||||
window.PayPalCommerceGateway = ppcpConfig;
|
window.PayPalCommerceGateway = ppcpConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GooglePayComponent = ( props ) => {
|
const GooglePayComponent = ( { isEditing } ) => {
|
||||||
const [ bootstrapped, setBootstrapped ] = useState( false );
|
|
||||||
const [ paypalLoaded, setPaypalLoaded ] = useState( false );
|
const [ paypalLoaded, setPaypalLoaded ] = useState( false );
|
||||||
const [ googlePayLoaded, setGooglePayLoaded ] = useState( false );
|
const [ googlePayLoaded, setGooglePayLoaded ] = useState( false );
|
||||||
const [ manager, setManager ] = useState( null );
|
const [ manager, setManager ] = useState( null );
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
// Load GooglePay SDK
|
if ( ! isEditing ) {
|
||||||
loadCustomScript( { url: buttonConfig.sdk_url } ).then( () => {
|
loadCustomScript( { url: buttonConfig.sdk_url } ).then( () => {
|
||||||
setGooglePayLoaded( true );
|
setGooglePayLoaded( true );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
ppcpConfig.url_params.components += ',googlepay';
|
ppcpConfig.url_params.components += ',googlepay';
|
||||||
|
|
||||||
// Load PayPal
|
|
||||||
loadPayPalScript( namespace, ppcpConfig )
|
loadPayPalScript( namespace, ppcpConfig )
|
||||||
.then( () => {
|
.then( () => {
|
||||||
setPaypalLoaded( true );
|
setPaypalLoaded( true );
|
||||||
|
@ -42,34 +40,35 @@ const GooglePayComponent = ( props ) => {
|
||||||
.catch( ( error ) => {
|
.catch( ( error ) => {
|
||||||
console.error( 'Failed to load PayPal script: ', error );
|
console.error( 'Failed to load PayPal script: ', error );
|
||||||
} );
|
} );
|
||||||
}, [] );
|
}
|
||||||
|
}, [ isEditing, buttonConfig, ppcpConfig ] );
|
||||||
|
|
||||||
useEffect( () => {
|
useEffect( () => {
|
||||||
if ( paypalLoaded && googlePayLoaded && ! manager ) {
|
if ( ! isEditing && paypalLoaded && googlePayLoaded && ! manager ) {
|
||||||
const ManagerClass = props.isEditing
|
const newManager = new GooglepayManager(
|
||||||
? GooglepayManagerBlockEditor
|
|
||||||
: GooglepayManager;
|
|
||||||
const newManager = new ManagerClass(
|
|
||||||
namespace,
|
namespace,
|
||||||
buttonConfig,
|
buttonConfig,
|
||||||
ppcpConfig
|
ppcpConfig
|
||||||
);
|
);
|
||||||
setManager( newManager );
|
setManager( newManager );
|
||||||
}
|
}
|
||||||
}, [ paypalLoaded, googlePayLoaded, props.isEditing ] );
|
}, [ paypalLoaded, googlePayLoaded, isEditing, manager ] );
|
||||||
|
|
||||||
useEffect( () => {
|
if ( isEditing ) {
|
||||||
if ( manager && ! bootstrapped ) {
|
return (
|
||||||
setBootstrapped( true );
|
<GooglepayManagerBlockEditor
|
||||||
manager.init();
|
namespace={ namespace }
|
||||||
|
buttonConfig={ buttonConfig }
|
||||||
|
ppcpConfig={ ppcpConfig }
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}, [ manager, bootstrapped ] );
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
id={ buttonConfig.button.wrapper.replace( '#', '' ) }
|
id={ buttonConfig.button.wrapper.replace( '#', '' ) }
|
||||||
className="ppcp-button-apm ppcp-button-googlepay"
|
className="ppcp-button-apm ppcp-button-googlepay"
|
||||||
></div>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue