diff --git a/modules/ppcp-applepay/resources/js/ApplepayButton.js b/modules/ppcp-applepay/resources/js/ApplepayButton.js
index 482557327..155ab5d7b 100644
--- a/modules/ppcp-applepay/resources/js/ApplepayButton.js
+++ b/modules/ppcp-applepay/resources/js/ApplepayButton.js
@@ -92,6 +92,24 @@ class ApplePayButton extends PaymentButton {
*/
#product = {};
+ /**
+ * The start time of the configuration process.
+ * @type {number}
+ */
+ #configureStartTime = 0;
+
+ /**
+ * The maximum time to wait for buttonAttributes before proceeding with initialization.
+ * @type {number}
+ */
+ #maxWaitTime = 1000;
+
+ /**
+ * The stored button attributes.
+ * @type {Object|null}
+ */
+ #storedButtonAttributes = null;
+
/**
* @inheritDoc
*/
@@ -125,7 +143,8 @@ class ApplePayButton extends PaymentButton {
externalHandler,
buttonConfig,
ppcpConfig,
- contextHandler
+ contextHandler,
+ buttonAttributes
) {
// Disable debug output in the browser console:
// buttonConfig.is_debug = false;
@@ -135,7 +154,8 @@ class ApplePayButton extends PaymentButton {
externalHandler,
buttonConfig,
ppcpConfig,
- contextHandler
+ contextHandler,
+ buttonAttributes
);
this.init = this.init.bind( this );
@@ -220,6 +240,20 @@ class ApplePayButton extends PaymentButton {
'No transactionInfo - missing configure() call?'
);
+ invalidIf(
+ () =>
+ this.buttonAttributes?.height &&
+ isNaN( parseInt( this.buttonAttributes.height ) ),
+ 'Invalid height in buttonAttributes'
+ );
+
+ invalidIf(
+ () =>
+ this.buttonAttributes?.borderRadius &&
+ isNaN( parseInt( this.buttonAttributes.borderRadius ) ),
+ 'Invalid borderRadius in buttonAttributes'
+ );
+
invalidIf(
() => ! this.contextHandler?.validateContext(),
`Invalid context handler.`
@@ -229,12 +263,60 @@ class ApplePayButton extends PaymentButton {
/**
* Configures the button instance. Must be called before the initial `init()`.
*
- * @param {Object} apiConfig - API configuration.
- * @param {TransactionInfo} transactionInfo - Transaction details.
+ * @param {Object} apiConfig - API configuration.
+ * @param {TransactionInfo} transactionInfo - Transaction details.
+ * @param {Object} buttonAttributes - Button attributes.
*/
- configure( apiConfig, transactionInfo ) {
+ configure( apiConfig, transactionInfo, buttonAttributes = {} ) {
+ // Start timing on first configure call
+ if ( ! this.#configureStartTime ) {
+ this.#configureStartTime = Date.now();
+ }
+
+ // If valid buttonAttributes, store them
+ if ( buttonAttributes?.height && buttonAttributes?.borderRadius ) {
+ this.#storedButtonAttributes = { ...buttonAttributes };
+ }
+
+ // Use stored attributes if current ones are missing
+ const attributes = buttonAttributes?.height
+ ? buttonAttributes
+ : this.#storedButtonAttributes;
+
+ // Check if we've exceeded wait time
+ const timeWaited = Date.now() - this.#configureStartTime;
+ if ( timeWaited > this.#maxWaitTime ) {
+ this.log(
+ 'ApplePay: Timeout waiting for buttonAttributes - proceeding with initialization'
+ );
+ this.#applePayConfig = apiConfig;
+ this.#transactionInfo = transactionInfo;
+ this.buttonAttributes = attributes || buttonAttributes;
+ this.init();
+ return;
+ }
+
+ // Block any initialization until we have valid buttonAttributes
+ if ( ! attributes?.height || ! attributes?.borderRadius ) {
+ setTimeout(
+ () =>
+ this.configure(
+ apiConfig,
+ transactionInfo,
+ buttonAttributes
+ ),
+ 100
+ );
+ return;
+ }
+
+ // Reset timer for future configure calls
+ this.#configureStartTime = 0;
+
this.#applePayConfig = apiConfig;
this.#transactionInfo = transactionInfo;
+ this.buttonAttributes = attributes;
+ this.init();
}
init() {
@@ -321,17 +403,43 @@ class ApplePayButton extends PaymentButton {
applyWrapperStyles() {
super.applyWrapperStyles();
- const { height } = this.style;
+ const wrapper = this.wrapperElement;
+ if ( ! wrapper ) {
+ return;
+ }
- if ( height ) {
- const wrapper = this.wrapperElement;
+ // Try stored attributes if current ones are missing
+ const attributes =
+ this.buttonAttributes?.height || this.buttonAttributes?.borderRadius
+ ? this.buttonAttributes
+ : this.#storedButtonAttributes;
+ const defaultHeight = 48;
+ const defaultBorderRadius = 4;
+
+ const height = attributes?.height
+ ? parseInt( attributes.height, 10 )
+ : defaultHeight;
+
+ if ( ! isNaN( height ) ) {
wrapper.style.setProperty(
'--apple-pay-button-height',
`${ height }px`
);
-
wrapper.style.height = `${ height }px`;
+ } else {
+ wrapper.style.setProperty(
+ '--apple-pay-button-height',
+ `${ defaultHeight }px`
+ );
+ wrapper.style.height = `${ defaultHeight }px`;
+ }
+
+ const borderRadius = attributes?.borderRadius
+ ? parseInt( attributes.borderRadius, 10 )
+ : defaultBorderRadius;
+ if ( ! isNaN( borderRadius ) ) {
+ wrapper.style.borderRadius = `${ borderRadius }px`;
}
}
@@ -342,12 +450,23 @@ class ApplePayButton extends PaymentButton {
addButton() {
const { color, type, language } = this.style;
+ // If current buttonAttributes are missing, try to use stored ones
+ if (
+ ! this.buttonAttributes?.height &&
+ this.#storedButtonAttributes?.height
+ ) {
+ this.buttonAttributes = { ...this.#storedButtonAttributes };
+ }
+
const button = document.createElement( 'apple-pay-button' );
button.id = 'apple-' + this.wrapperId;
+
button.setAttribute( 'buttonstyle', color );
button.setAttribute( 'type', type );
button.setAttribute( 'locale', language );
+ button.style.display = 'block';
+
button.addEventListener( 'click', ( evt ) => {
evt.preventDefault();
this.onButtonClick();
diff --git a/modules/ppcp-applepay/resources/js/ApplepayManager.js b/modules/ppcp-applepay/resources/js/ApplepayManager.js
index 673078121..794464f70 100644
--- a/modules/ppcp-applepay/resources/js/ApplepayManager.js
+++ b/modules/ppcp-applepay/resources/js/ApplepayManager.js
@@ -3,65 +3,83 @@ import ApplePayButton from './ApplepayButton';
import ContextHandlerFactory from './Context/ContextHandlerFactory';
class ApplePayManager {
- #namespace = '';
- #buttonConfig = null;
- #ppcpConfig = null;
- #applePayConfig = null;
- #contextHandler = null;
- #transactionInfo = null;
- #buttons = [];
+ constructor( namespace, buttonConfig, ppcpConfig, buttonAttributes = {} ) {
+ this.namespace = namespace;
+ this.buttonConfig = buttonConfig;
+ this.ppcpConfig = ppcpConfig;
+ this.buttonAttributes = buttonAttributes;
+ this.applePayConfig = null;
+ this.transactionInfo = null;
+ this.contextHandler = null;
- constructor( namespace, buttonConfig, ppcpConfig ) {
- this.#namespace = namespace;
- this.#buttonConfig = buttonConfig;
- this.#ppcpConfig = ppcpConfig;
+ this.buttons = [];
- this.onContextBootstrap = this.onContextBootstrap.bind( this );
- buttonModuleWatcher.watchContextBootstrap( this.onContextBootstrap );
- }
+ buttonModuleWatcher.watchContextBootstrap( async ( bootstrap ) => {
+ this.contextHandler = ContextHandlerFactory.create(
+ bootstrap.context,
+ buttonConfig,
+ ppcpConfig,
+ bootstrap.handler
+ );
- async onContextBootstrap( bootstrap ) {
- this.#contextHandler = ContextHandlerFactory.create(
- bootstrap.context,
- this.#buttonConfig,
- this.#ppcpConfig,
- bootstrap.handler
- );
+ const button = ApplePayButton.createButton(
+ bootstrap.context,
+ bootstrap.handler,
+ buttonConfig,
+ ppcpConfig,
+ this.contextHandler,
+ this.buttonAttributes
+ );
- const button = ApplePayButton.createButton(
- bootstrap.context,
- bootstrap.handler,
- this.#buttonConfig,
- this.#ppcpConfig,
- this.#contextHandler
- );
+ this.buttons.push( button );
+ const initButton = () => {
+ button.configure(
+ this.applePayConfig,
+ this.transactionInfo,
+ this.buttonAttributes
+ );
+ button.init();
+ };
- this.#buttons.push( button );
+ // Initialize button only if applePayConfig and transactionInfo are already fetched.
+ if ( this.applePayConfig && this.transactionInfo ) {
+ initButton();
+ } else {
+ // Ensure ApplePayConfig is loaded before proceeding.
+ await this.init();
- // Ensure ApplePayConfig is loaded before proceeding.
- await this.init();
-
- button.configure( this.#applePayConfig, this.#transactionInfo );
- button.init();
+ if ( this.applePayConfig && this.transactionInfo ) {
+ initButton();
+ }
+ }
+ } );
}
async init() {
try {
- if ( ! this.#applePayConfig ) {
- this.#applePayConfig = await window[ this.#namespace ]
+ if ( ! this.applePayConfig ) {
+ // Gets ApplePay configuration of the PayPal merchant.
+ this.applePayConfig = await window[ this.namespace ]
.Applepay()
.config();
-
- if ( ! this.#applePayConfig ) {
- console.error( 'No ApplePayConfig received during init' );
- }
}
- if ( ! this.#transactionInfo ) {
- this.#transactionInfo = await this.fetchTransactionInfo();
+ if ( ! this.transactionInfo ) {
+ this.transactionInfo = await this.fetchTransactionInfo();
+ }
- if ( ! this.#applePayConfig ) {
- console.error( 'No transactionInfo found during init' );
+ if ( ! this.applePayConfig ) {
+ console.error( 'No ApplePayConfig received during init' );
+ } else if ( ! this.transactionInfo ) {
+ console.error( 'No transactionInfo found during init' );
+ } else {
+ for ( const button of this.buttons ) {
+ button.configure(
+ this.applePayConfig,
+ this.transactionInfo,
+ this.buttonAttributes
+ );
+ button.init();
}
}
} catch ( error ) {
@@ -71,10 +89,10 @@ class ApplePayManager {
async fetchTransactionInfo() {
try {
- if ( ! this.#contextHandler ) {
+ if ( ! this.contextHandler ) {
throw new Error( 'ContextHandler is not initialized' );
}
- return await this.#contextHandler.transactionInfo();
+ return await this.contextHandler.transactionInfo();
} catch ( error ) {
console.error( 'Error fetching transaction info:', error );
throw error;
@@ -82,7 +100,7 @@ class ApplePayManager {
}
reinit() {
- for ( const button of this.#buttons ) {
+ for ( const button of this.buttons ) {
button.reinit();
}
}
diff --git a/modules/ppcp-applepay/resources/js/ApplepayManagerBlockEditor.js b/modules/ppcp-applepay/resources/js/ApplepayManagerBlockEditor.js
index 0d60929e4..3381baf93 100644
--- a/modules/ppcp-applepay/resources/js/ApplepayManagerBlockEditor.js
+++ b/modules/ppcp-applepay/resources/js/ApplepayManagerBlockEditor.js
@@ -4,11 +4,13 @@ const ApplePayManagerBlockEditor = ( {
namespace,
buttonConfig,
ppcpConfig,
+ buttonAttributes,
} ) => (
);
diff --git a/modules/ppcp-applepay/resources/js/Block/components/ApplePayButton.js b/modules/ppcp-applepay/resources/js/Block/components/ApplePayButton.js
index c01f04320..8b4985a1f 100644
--- a/modules/ppcp-applepay/resources/js/Block/components/ApplePayButton.js
+++ b/modules/ppcp-applepay/resources/js/Block/components/ApplePayButton.js
@@ -4,7 +4,12 @@ import usePayPalScript from '../hooks/usePayPalScript';
import useApplepayScript from '../hooks/useApplepayScript';
import useApplepayConfig from '../hooks/useApplepayConfig';
-const ApplepayButton = ( { namespace, buttonConfig, ppcpConfig } ) => {
+const ApplepayButton = ( {
+ namespace,
+ buttonConfig,
+ ppcpConfig,
+ buttonAttributes,
+} ) => {
const [ buttonHtml, setButtonHtml ] = useState( '' );
const [ buttonElement, setButtonElement ] = useState( null );
const [ componentFrame, setComponentFrame ] = useState( null );
@@ -31,19 +36,42 @@ const ApplepayButton = ( { namespace, buttonConfig, ppcpConfig } ) => {
namespace,
buttonConfig,
ppcpConfig,
- applepayConfig
+ applepayConfig,
+ buttonAttributes
);
useEffect( () => {
- if ( applepayButton ) {
- setButtonHtml( applepayButton.outerHTML );
+ if ( ! applepayButton || ! buttonElement ) {
+ return;
}
- }, [ applepayButton ] );
+
+ setButtonHtml( applepayButton.outerHTML );
+
+ // Add timeout to ensure button is displayed after render
+ setTimeout( () => {
+ const button = buttonElement.querySelector( 'apple-pay-button' );
+ if ( button ) {
+ button.style.display = 'block';
+ }
+ }, 100 ); // Add a small delay to ensure DOM is ready
+ }, [ applepayButton, buttonElement ] );
return (
);
};
diff --git a/modules/ppcp-applepay/resources/js/boot-block.js b/modules/ppcp-applepay/resources/js/boot-block.js
index 8013177d0..eff026251 100644
--- a/modules/ppcp-applepay/resources/js/boot-block.js
+++ b/modules/ppcp-applepay/resources/js/boot-block.js
@@ -19,7 +19,7 @@ if ( typeof window.PayPalCommerceGateway === 'undefined' ) {
window.PayPalCommerceGateway = ppcpConfig;
}
-const ApplePayComponent = ( { isEditing } ) => {
+const ApplePayComponent = ( { isEditing, buttonAttributes } ) => {
const [ paypalLoaded, setPaypalLoaded ] = useState( false );
const [ applePayLoaded, setApplePayLoaded ] = useState( false );
const wrapperRef = useRef( null );
@@ -57,8 +57,13 @@ const ApplePayComponent = ( { isEditing } ) => {
buttonConfig.reactWrapper = wrapperRef.current;
- new ManagerClass( namespace, buttonConfig, ppcpConfig );
- }, [ paypalLoaded, applePayLoaded, isEditing ] );
+ new ManagerClass(
+ namespace,
+ buttonConfig,
+ ppcpConfig,
+ buttonAttributes
+ );
+ }, [ paypalLoaded, applePayLoaded, isEditing, buttonAttributes ] );
if ( isEditing ) {
return (
@@ -66,6 +71,7 @@ const ApplePayComponent = ( { isEditing } ) => {
namespace={ namespace }
buttonConfig={ buttonConfig }
ppcpConfig={ ppcpConfig }
+ buttonAttributes={ buttonAttributes }
/>
);
}
@@ -102,5 +108,6 @@ registerExpressPaymentMethod( {
canMakePayment: () => buttonData.enabled,
supports: {
features,
+ style: [ 'height', 'borderRadius' ],
},
} );
diff --git a/modules/ppcp-axo-block/resources/js/plugins/PayPalInsightsLoader.js b/modules/ppcp-axo-block/resources/js/plugins/PayPalInsightsLoader.js
new file mode 100644
index 000000000..b831bd45b
--- /dev/null
+++ b/modules/ppcp-axo-block/resources/js/plugins/PayPalInsightsLoader.js
@@ -0,0 +1,259 @@
+import { registerPlugin } from '@wordpress/plugins';
+import { useEffect, useCallback, useState, useRef } from '@wordpress/element';
+import { useSelect } from '@wordpress/data';
+import { PAYMENT_STORE_KEY } from '@woocommerce/block-data';
+import PayPalInsights from '../../../../ppcp-axo/resources/js/Insights/PayPalInsights';
+import { STORE_NAME } from '../stores/axoStore';
+import usePayPalCommerceGateway from '../hooks/usePayPalCommerceGateway';
+
+const GATEWAY_HANDLE = 'ppcp-axo-gateway';
+
+const useEventTracking = () => {
+ const [ triggeredEvents, setTriggeredEvents ] = useState( {
+ initialized: false,
+ jsLoaded: false,
+ beginCheckout: false,
+ emailSubmitted: false,
+ } );
+
+ const currentPaymentMethod = useRef( null );
+
+ const setEventTriggered = useCallback( ( eventName, value = true ) => {
+ setTriggeredEvents( ( prev ) => ( {
+ ...prev,
+ [ eventName ]: value,
+ } ) );
+ }, [] );
+
+ const isEventTriggered = useCallback(
+ ( eventName ) => triggeredEvents[ eventName ],
+ [ triggeredEvents ]
+ );
+
+ const setCurrentPaymentMethod = useCallback( ( methodName ) => {
+ currentPaymentMethod.current = methodName;
+ }, [] );
+
+ const getCurrentPaymentMethod = useCallback(
+ () => currentPaymentMethod.current,
+ []
+ );
+
+ return {
+ setEventTriggered,
+ isEventTriggered,
+ setCurrentPaymentMethod,
+ getCurrentPaymentMethod,
+ };
+};
+
+const waitForPayPalInsight = () => {
+ return new Promise( ( resolve, reject ) => {
+ // If already loaded, resolve immediately
+ if ( window.paypalInsight ) {
+ resolve( window.paypalInsight );
+ return;
+ }
+
+ // Set a reasonable timeout
+ const timeoutId = setTimeout( () => {
+ observer.disconnect();
+ reject( new Error( 'PayPal Insights script load timeout' ) );
+ }, 10000 );
+
+ // Create MutationObserver to watch for script initialization
+ const observer = new MutationObserver( () => {
+ if ( window.paypalInsight ) {
+ observer.disconnect();
+ clearTimeout( timeoutId );
+ resolve( window.paypalInsight );
+ }
+ } );
+
+ // Start observing
+ observer.observe( document, {
+ childList: true,
+ subtree: true,
+ } );
+ } );
+};
+
+const usePayPalInsightsInit = ( axoConfig, ppcpConfig, eventTracking ) => {
+ const { setEventTriggered, isEventTriggered } = eventTracking;
+ const initialized = useRef( false );
+
+ useEffect( () => {
+ if (
+ ! axoConfig?.insights?.enabled ||
+ ! axoConfig?.insights?.client_id ||
+ ! axoConfig?.insights?.session_id ||
+ initialized.current ||
+ isEventTriggered( 'initialized' )
+ ) {
+ return;
+ }
+
+ const initializePayPalInsights = async () => {
+ try {
+ await waitForPayPalInsight();
+
+ if ( initialized.current ) {
+ return;
+ }
+
+ // Track JS load first
+ PayPalInsights.trackJsLoad();
+ setEventTriggered( 'jsLoaded' );
+
+ PayPalInsights.config( axoConfig.insights.client_id, {
+ debug: axoConfig?.wp_debug === '1',
+ } );
+
+ PayPalInsights.setSessionId( axoConfig.insights.session_id );
+ initialized.current = true;
+ setEventTriggered( 'initialized' );
+
+ if (
+ isEventTriggered( 'jsLoaded' ) &&
+ ! isEventTriggered( 'beginCheckout' )
+ ) {
+ PayPalInsights.trackBeginCheckout( {
+ amount: axoConfig.insights.amount,
+ page_type: 'checkout',
+ user_data: {
+ country: 'US',
+ is_store_member: false,
+ },
+ } );
+ setEventTriggered( 'beginCheckout' );
+ }
+ } catch ( error ) {
+ console.error(
+ 'PayPal Insights initialization failed:',
+ error
+ );
+ }
+ };
+
+ initializePayPalInsights();
+
+ return () => {
+ initialized.current = false;
+ };
+ }, [ axoConfig, ppcpConfig, setEventTriggered, isEventTriggered ] );
+};
+
+const usePaymentMethodTracking = ( axoConfig, eventTracking ) => {
+ const { setCurrentPaymentMethod } = eventTracking;
+ const lastPaymentMethod = useRef( null );
+ const isInitialMount = useRef( true );
+
+ const activePaymentMethod = useSelect( ( select ) => {
+ return select( PAYMENT_STORE_KEY )?.getActivePaymentMethod();
+ }, [] );
+
+ const handlePaymentMethodChange = useCallback(
+ async ( paymentMethod ) => {
+ // Skip if no payment method or same as last one
+ if (
+ ! paymentMethod ||
+ paymentMethod === lastPaymentMethod.current
+ ) {
+ return;
+ }
+
+ try {
+ await waitForPayPalInsight();
+
+ // Only track if it's not the initial mount, and we have a previous payment method
+ if ( ! isInitialMount.current && lastPaymentMethod.current ) {
+ PayPalInsights.trackSelectPaymentMethod( {
+ payment_method_selected:
+ axoConfig?.insights?.payment_method_selected_map[
+ paymentMethod
+ ] || 'other',
+ page_type: 'checkout',
+ } );
+ }
+
+ lastPaymentMethod.current = paymentMethod;
+ setCurrentPaymentMethod( paymentMethod );
+ } catch ( error ) {
+ console.error( 'Failed to track payment method:', error );
+ }
+ },
+ [
+ axoConfig?.insights?.payment_method_selected_map,
+ setCurrentPaymentMethod,
+ ]
+ );
+
+ useEffect( () => {
+ if ( activePaymentMethod ) {
+ if ( isInitialMount.current ) {
+ // Just set the initial payment method without tracking
+ lastPaymentMethod.current = activePaymentMethod;
+ setCurrentPaymentMethod( activePaymentMethod );
+ isInitialMount.current = false;
+ } else {
+ handlePaymentMethodChange( activePaymentMethod );
+ }
+ }
+ }, [
+ activePaymentMethod,
+ handlePaymentMethodChange,
+ setCurrentPaymentMethod,
+ ] );
+
+ useEffect( () => {
+ return () => {
+ lastPaymentMethod.current = null;
+ isInitialMount.current = true;
+ };
+ }, [] );
+};
+
+const PayPalInsightsLoader = () => {
+ const eventTracking = useEventTracking();
+ const { setEventTriggered, isEventTriggered } = eventTracking;
+
+ const initialConfig =
+ window?.wc?.wcSettings?.getSetting( `${ GATEWAY_HANDLE }_data` ) || {};
+
+ const { ppcpConfig } = usePayPalCommerceGateway( initialConfig );
+ const axoConfig = window?.wc_ppcp_axo;
+
+ const { isEmailSubmitted } = useSelect( ( select ) => {
+ const storeSelect = select( STORE_NAME );
+ return {
+ isEmailSubmitted: storeSelect?.getIsEmailSubmitted?.() ?? false,
+ };
+ }, [] );
+
+ usePayPalInsightsInit( axoConfig, ppcpConfig, eventTracking );
+ usePaymentMethodTracking( axoConfig, eventTracking );
+
+ useEffect( () => {
+ const trackEmail = async () => {
+ if ( isEmailSubmitted && ! isEventTriggered( 'emailSubmitted' ) ) {
+ try {
+ await waitForPayPalInsight();
+ PayPalInsights.trackSubmitCheckoutEmail();
+ setEventTriggered( 'emailSubmitted' );
+ } catch ( error ) {
+ console.error( 'Failed to track email submission:', error );
+ }
+ }
+ };
+ trackEmail();
+ }, [ isEmailSubmitted, setEventTriggered, isEventTriggered ] );
+
+ return null;
+};
+
+registerPlugin( 'wc-ppcp-paypal-insights', {
+ render: PayPalInsightsLoader,
+ scope: 'woocommerce-checkout',
+} );
+
+export default PayPalInsightsLoader;
diff --git a/modules/ppcp-axo-block/resources/js/stores/axoStore.js b/modules/ppcp-axo-block/resources/js/stores/axoStore.js
index c7afb91ef..c9c5449a4 100644
--- a/modules/ppcp-axo-block/resources/js/stores/axoStore.js
+++ b/modules/ppcp-axo-block/resources/js/stores/axoStore.js
@@ -1,4 +1,4 @@
-import { createReduxStore, register, dispatch } from '@wordpress/data';
+import { createReduxStore, register, dispatch, select } from '@wordpress/data';
export const STORE_NAME = 'woocommerce-paypal-payments/axo-block';
@@ -108,13 +108,15 @@ const selectors = {
};
// Create and register the Redux store for the AXO block
-const store = createReduxStore( STORE_NAME, {
- reducer,
- actions,
- selectors,
-} );
+if ( ! select( STORE_NAME ) ) {
+ const store = createReduxStore( STORE_NAME, {
+ reducer,
+ actions,
+ selectors,
+ } );
-register( store );
+ register( store );
+}
// Action dispatchers
diff --git a/modules/ppcp-axo-block/services.php b/modules/ppcp-axo-block/services.php
index 61a3c77a7..f91cd738a 100644
--- a/modules/ppcp-axo-block/services.php
+++ b/modules/ppcp-axo-block/services.php
@@ -33,11 +33,12 @@ return array(
$container->get( 'axoblock.url' ),
$container->get( 'ppcp.asset-version' ),
$container->get( 'axo.gateway' ),
- fn() : SmartButtonInterface => $container->get( 'button.smart-button' ),
+ fn(): SmartButtonInterface => $container->get( 'button.smart-button' ),
$container->get( 'wcgateway.settings' ),
$container->get( 'wcgateway.configuration.dcc' ),
$container->get( 'onboarding.environment' ),
$container->get( 'wcgateway.url' ),
+ $container->get( 'axo.payment_method_selected_map' ),
$container->get( 'axo.supported-country-card-type-matrix' ),
$container->get( 'axo.shipping-wc-enabled-locations' )
);
diff --git a/modules/ppcp-axo-block/src/AxoBlockModule.php b/modules/ppcp-axo-block/src/AxoBlockModule.php
index 669cc7cc5..1ebb068ed 100644
--- a/modules/ppcp-axo-block/src/AxoBlockModule.php
+++ b/modules/ppcp-axo-block/src/AxoBlockModule.php
@@ -133,6 +133,15 @@ class AxoBlockModule implements ServiceModule, ExtendingModule, ExecutableModule
wp_enqueue_style( 'wc-ppcp-axo-block' );
}
);
+
+ // Enqueue the PayPal Insights script.
+ add_action(
+ 'wp_enqueue_scripts',
+ function () use ( $c ) {
+ $this->enqueue_paypal_insights_script( $c );
+ }
+ );
+
return true;
}
@@ -166,4 +175,37 @@ class AxoBlockModule implements ServiceModule, ExtendingModule, ExecutableModule
return $localized_script_data;
}
+
+ /**
+ * Enqueues PayPal Insights analytics script for the Checkout block.
+ *
+ * @param ContainerInterface $c The service container.
+ * @return void
+ */
+ private function enqueue_paypal_insights_script( ContainerInterface $c ): void {
+ if ( ! has_block( 'woocommerce/checkout' ) || WC()->cart->is_empty() ) {
+ return;
+ }
+
+ $module_url = $c->get( 'axoblock.url' );
+ $asset_version = $c->get( 'ppcp.asset-version' );
+
+ wp_register_script(
+ 'wc-ppcp-paypal-insights',
+ untrailingslashit( $module_url ) . '/assets/js/PayPalInsightsLoader.js',
+ array( 'wp-plugins', 'wp-data', 'wp-element', 'wc-blocks-registry' ),
+ $asset_version,
+ true
+ );
+
+ wp_localize_script(
+ 'wc-ppcp-paypal-insights',
+ 'ppcpPayPalInsightsData',
+ array(
+ 'isAxoEnabled' => true,
+ )
+ );
+
+ wp_enqueue_script( 'wc-ppcp-paypal-insights' );
+ }
}
diff --git a/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php b/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php
index 373c61023..fa546d5ac 100644
--- a/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php
+++ b/modules/ppcp-axo-block/src/AxoBlockPaymentMethod.php
@@ -72,6 +72,13 @@ class AxoBlockPaymentMethod extends AbstractPaymentMethodType {
*/
private $environment;
+ /**
+ * Mapping of payment methods to the PayPal Insights 'payment_method_selected' types.
+ *
+ * @var array
+ */
+ private array $payment_method_selected_map;
+
/**
* The WcGateway module URL.
*
@@ -96,29 +103,30 @@ class AxoBlockPaymentMethod extends AbstractPaymentMethodType {
/**
* AdvancedCardPaymentMethod constructor.
*
- * @param string $module_url The URL of this module.
- * @param string $version The assets version.
- * @param WC_Payment_Gateway $gateway Credit card gateway.
- * @param SmartButtonInterface|callable $smart_button The smart button script loading
- * handler.
- * @param Settings $settings The settings.
- * @param DCCGatewayConfiguration $dcc_configuration The DCC gateway settings.
- * @param Environment $environment The environment object.
+ * @param string $module_url The URL of this module.
+ * @param string $version The assets version.
+ * @param WC_Payment_Gateway $gateway Credit card gateway.
+ * @param SmartButtonInterface|callable $smart_button The smart button script loading handler.
+ * @param Settings $settings The settings.
+ * @param DCCGatewayConfiguration $dcc_configuration The DCC gateway settings.
+ * @param Environment $environment The environment object.
* @param string $wcgateway_module_url The WcGateway module URL.
+ * @param array $payment_method_selected_map Mapping of payment methods to the PayPal Insights 'payment_method_selected' types.
* @param array $supported_country_card_type_matrix The supported country card type matrix for Axo.
* @param array $enabled_shipping_locations The list of WooCommerce enabled shipping locations.
*/
public function __construct(
- string $module_url,
- string $version,
- WC_Payment_Gateway $gateway,
- $smart_button,
- Settings $settings,
- DCCGatewayConfiguration $dcc_configuration,
- Environment $environment,
- string $wcgateway_module_url,
- array $supported_country_card_type_matrix,
- array $enabled_shipping_locations
+ string $module_url,
+ string $version,
+ WC_Payment_Gateway $gateway,
+ $smart_button,
+ Settings $settings,
+ DCCGatewayConfiguration $dcc_configuration,
+ Environment $environment,
+ string $wcgateway_module_url,
+ array $payment_method_selected_map,
+ array $supported_country_card_type_matrix,
+ array $enabled_shipping_locations
) {
$this->name = AxoGateway::ID;
$this->module_url = $module_url;
@@ -129,10 +137,10 @@ class AxoBlockPaymentMethod extends AbstractPaymentMethodType {
$this->dcc_configuration = $dcc_configuration;
$this->environment = $environment;
$this->wcgateway_module_url = $wcgateway_module_url;
+ $this->payment_method_selected_map = $payment_method_selected_map;
$this->supported_country_card_type_matrix = $supported_country_card_type_matrix;
$this->enabled_shipping_locations = $enabled_shipping_locations;
}
-
/**
* {@inheritDoc}
*/
@@ -213,18 +221,19 @@ class AxoBlockPaymentMethod extends AbstractPaymentMethodType {
'email' => 'render',
),
'insights' => array(
- 'enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG,
- 'client_id' => ( $this->settings->has( 'client_id' ) ? $this->settings->get( 'client_id' ) : null ),
- 'session_id' =>
+ 'enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG,
+ 'client_id' => ( $this->settings->has( 'client_id' ) ? $this->settings->get( 'client_id' ) : null ),
+ 'session_id' =>
( WC()->session && method_exists( WC()->session, 'get_customer_unique_id' ) )
? substr( md5( WC()->session->get_customer_unique_id() ), 0, 16 )
: '',
- 'amount' => array(
+ 'amount' => array(
'currency_code' => get_woocommerce_currency(),
'value' => ( WC()->cart && method_exists( WC()->cart, 'get_total' ) )
? WC()->cart->get_total( 'numeric' )
- : null, // Set to null if WC()->cart is null or get_total doesn't exist.
+ : null,
),
+ 'payment_method_selected_map' => $this->payment_method_selected_map,
),
'allowed_cards' => $this->supported_country_card_type_matrix,
'disable_cards' => $this->settings->has( 'disable_cards' ) ? (array) $this->settings->get( 'disable_cards' ) : array(),
diff --git a/modules/ppcp-axo-block/webpack.config.js b/modules/ppcp-axo-block/webpack.config.js
index b5db53234..86e2e2087 100644
--- a/modules/ppcp-axo-block/webpack.config.js
+++ b/modules/ppcp-axo-block/webpack.config.js
@@ -9,7 +9,10 @@ module.exports = {
target: 'web',
plugins: [ new DependencyExtractionWebpackPlugin() ],
entry: {
- 'index': path.resolve( './resources/js/index.js' ),
+ index: path.resolve( './resources/js/index.js' ),
+ PayPalInsightsLoader: path.resolve(
+ './resources/js/plugins/PayPalInsightsLoader.js'
+ ),
gateway: path.resolve( './resources/css/gateway.scss' ),
},
output: {
diff --git a/modules/ppcp-axo/resources/js/AxoManager.js b/modules/ppcp-axo/resources/js/AxoManager.js
index 51dd34147..e93fa9527 100644
--- a/modules/ppcp-axo/resources/js/AxoManager.js
+++ b/modules/ppcp-axo/resources/js/AxoManager.js
@@ -121,7 +121,7 @@ class AxoManager {
this.axoConfig?.insights?.session_id
) {
PayPalInsights.config( this.axoConfig?.insights?.client_id, {
- debug: true,
+ debug: axoConfig?.wp_debug === '1',
} );
PayPalInsights.setSessionId( this.axoConfig?.insights?.session_id );
PayPalInsights.trackJsLoad();
@@ -164,19 +164,25 @@ class AxoManager {
}
registerEventHandlers() {
+ // Payment method change tracking with duplicate prevention
+ let lastSelectedPaymentMethod = document.querySelector(
+ 'input[name=payment_method]:checked'
+ )?.value;
this.$( document ).on(
'change',
'input[name=payment_method]',
( ev ) => {
- const map = {
- 'ppcp-axo-gateway': 'card',
- 'ppcp-gateway': 'paypal',
- };
-
- PayPalInsights.trackSelectPaymentMethod( {
- payment_method_selected: map[ ev.target.value ] || 'other',
- page_type: 'checkout',
- } );
+ if ( lastSelectedPaymentMethod !== ev.target.value ) {
+ PayPalInsights.trackSelectPaymentMethod( {
+ payment_method_selected:
+ this.axoConfig?.insights
+ ?.payment_method_selected_map[
+ ev.target.value
+ ] || 'other',
+ page_type: 'checkout',
+ } );
+ lastSelectedPaymentMethod = ev.target.value;
+ }
}
);
@@ -1166,16 +1172,6 @@ class AxoManager {
this.el.axoNonceInput.get().value = nonce;
- PayPalInsights.trackEndCheckout( {
- amount: this.axoConfig?.insights?.amount,
- page_type: 'checkout',
- payment_method_selected: 'card',
- user_data: {
- country: 'US',
- is_store_member: false,
- },
- } );
-
if ( data ) {
// Ryan flow.
const form = document.querySelector( 'form.woocommerce-checkout' );
diff --git a/modules/ppcp-axo/resources/js/Insights/EndCheckoutTracker.js b/modules/ppcp-axo/resources/js/Insights/EndCheckoutTracker.js
new file mode 100644
index 000000000..e21a9d0e4
--- /dev/null
+++ b/modules/ppcp-axo/resources/js/Insights/EndCheckoutTracker.js
@@ -0,0 +1,99 @@
+import PayPalInsights from '../../../../ppcp-axo/resources/js/Insights/PayPalInsights';
+
+class EndCheckoutTracker {
+ constructor() {
+ this.initialize();
+ }
+
+ async initialize() {
+ const axoConfig = window.wc_ppcp_axo_insights_data || {};
+
+ if (
+ axoConfig?.enabled === '1' &&
+ axoConfig?.client_id &&
+ axoConfig?.session_id &&
+ axoConfig?.orderTotal &&
+ axoConfig?.orderCurrency
+ ) {
+ try {
+ await this.waitForPayPalInsight();
+
+ PayPalInsights.config( axoConfig?.client_id, {
+ debug: axoConfig?.wp_debug === '1',
+ } );
+ PayPalInsights.setSessionId( axoConfig.session_id );
+ PayPalInsights.trackJsLoad();
+
+ const trackingData = {
+ amount: {
+ currency_code: axoConfig?.orderCurrency,
+ value: axoConfig?.orderTotal,
+ },
+ page_type: 'checkout',
+ payment_method_selected:
+ axoConfig?.payment_method_selected_map[
+ axoConfig?.paymentMethod
+ ] || 'other',
+ user_data: {
+ country: 'US',
+ is_store_member: false,
+ },
+ order_id: axoConfig?.orderId,
+ order_key: axoConfig?.orderKey,
+ };
+
+ PayPalInsights.trackEndCheckout( trackingData );
+ } catch ( error ) {
+ console.error(
+ 'EndCheckoutTracker: Error during tracking:',
+ error
+ );
+ console.error( 'PayPalInsights object:', window.paypalInsight );
+ }
+ } else {
+ console.warn(
+ 'EndCheckoutTracker: Missing required configuration',
+ {
+ enabled: axoConfig?.enabled,
+ hasClientId: !! axoConfig?.client_id,
+ hasSessionId: !! axoConfig?.session_id,
+ hasOrderTotal: !! axoConfig?.orderTotal,
+ hasOrderCurrency: !! axoConfig?.orderCurrency,
+ }
+ );
+ }
+ }
+
+ waitForPayPalInsight() {
+ return new Promise( ( resolve, reject ) => {
+ // If already loaded, resolve immediately
+ if ( window.paypalInsight ) {
+ resolve( window.paypalInsight );
+ return;
+ }
+
+ const timeoutId = setTimeout( () => {
+ observer.disconnect();
+ reject( new Error( 'PayPal Insights script load timeout' ) );
+ }, 10000 );
+
+ // Create MutationObserver to watch for script initialization
+ const observer = new MutationObserver( () => {
+ if ( window.paypalInsight ) {
+ observer.disconnect();
+ clearTimeout( timeoutId );
+ resolve( window.paypalInsight );
+ }
+ } );
+
+ observer.observe( document, {
+ childList: true,
+ subtree: true,
+ } );
+ } );
+ }
+}
+
+document.addEventListener( 'DOMContentLoaded', () => {
+ new EndCheckoutTracker();
+} );
diff --git a/modules/ppcp-axo/services.php b/modules/ppcp-axo/services.php
index e93df1721..e6767a29a 100644
--- a/modules/ppcp-axo/services.php
+++ b/modules/ppcp-axo/services.php
@@ -18,6 +18,7 @@ use WooCommerce\PayPalCommerce\WcGateway\Gateway\CreditCardGateway;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use WooCommerce\PayPalCommerce\WcGateway\Helper\DCCGatewayConfiguration;
+use WooCommerce\PayPalCommerce\ApiClient\Helper\CurrencyGetter;
return array(
@@ -64,6 +65,7 @@ return array(
$container->get( 'session.handler' ),
$container->get( 'wcgateway.settings' ),
$container->get( 'onboarding.environment' ),
+ $container->get( 'axo.insights' ),
$container->get( 'wcgateway.settings.status' ),
$container->get( 'api.shop.currency.getter' ),
$container->get( 'woocommerce.logger.woocommerce' ),
@@ -91,6 +93,55 @@ return array(
);
},
+ // Data needed for the PayPal Insights.
+ 'axo.insights' => static function ( ContainerInterface $container ): array {
+ $settings = $container->get( 'wcgateway.settings' );
+ assert( $settings instanceof Settings );
+
+ $currency = $container->get( 'api.shop.currency.getter' );
+ assert( $currency instanceof CurrencyGetter );
+
+ $session_id = '';
+ if ( isset( WC()->session ) && method_exists( WC()->session, 'get_customer_unique_id' ) ) {
+ $session_id = substr(
+ md5( WC()->session->get_customer_unique_id() ),
+ 0,
+ 16
+ );
+ }
+
+ return array(
+ 'enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG,
+ 'client_id' => ( $settings->has( 'client_id' ) ? $settings->get( 'client_id' ) : null ),
+ 'session_id' => $session_id,
+ 'amount' => array(
+ 'currency_code' => $currency->get(),
+ ),
+ 'payment_method_selected_map' => $container->get( 'axo.payment_method_selected_map' ),
+ 'wp_debug' => defined( 'WP_DEBUG' ) && WP_DEBUG,
+ );
+ },
+
+ // The mapping of payment methods to the PayPal Insights 'payment_method_selected' types.
+ 'axo.payment_method_selected_map' => static function ( ContainerInterface $container ): array {
+ return array(
+ 'ppcp-axo-gateway' => 'card',
+ 'ppcp-credit-card-gateway' => 'card',
+ 'ppcp-gateway' => 'paypal',
+ 'ppcp-googlepay' => 'google_pay',
+ 'ppcp-applepay' => 'apple_pay',
+ 'ppcp-multibanco' => 'other',
+ 'ppcp-trustly' => 'other',
+ 'ppcp-p24' => 'other',
+ 'ppcp-mybank' => 'other',
+ 'ppcp-ideal' => 'other',
+ 'ppcp-eps' => 'other',
+ 'ppcp-blik' => 'other',
+ 'ppcp-bancontact' => 'other',
+ 'ppcp-card-button-gateway' => 'card',
+ );
+ },
+
/**
* The matrix which countries and currency combinations can be used for AXO.
*/
diff --git a/modules/ppcp-axo/src/Assets/AxoManager.php b/modules/ppcp-axo/src/Assets/AxoManager.php
index d2d4351a7..6fafcb681 100644
--- a/modules/ppcp-axo/src/Assets/AxoManager.php
+++ b/modules/ppcp-axo/src/Assets/AxoManager.php
@@ -52,6 +52,13 @@ class AxoManager {
*/
private Environment $environment;
+ /**
+ * Data needed for the PayPal Insights.
+ *
+ * @var array
+ */
+ private array $insights_data;
+
/**
* The Settings status helper.
*
@@ -107,6 +114,7 @@ class AxoManager {
* @param SessionHandler $session_handler The Session handler.
* @param Settings $settings The Settings.
* @param Environment $environment The environment object.
+ * @param array $insights_data Data needed for the PayPal Insights.
* @param SettingsStatus $settings_status The Settings status helper.
* @param CurrencyGetter $currency The getter of the 3-letter currency code of the shop.
* @param LoggerInterface $logger The logger.
@@ -120,6 +128,7 @@ class AxoManager {
SessionHandler $session_handler,
Settings $settings,
Environment $environment,
+ array $insights_data,
SettingsStatus $settings_status,
CurrencyGetter $currency,
LoggerInterface $logger,
@@ -133,12 +142,13 @@ class AxoManager {
$this->session_handler = $session_handler;
$this->settings = $settings;
$this->environment = $environment;
+ $this->insights_data = $insights_data;
$this->settings_status = $settings_status;
$this->currency = $currency;
$this->logger = $logger;
$this->wcgateway_module_url = $wcgateway_module_url;
- $this->supported_country_card_type_matrix = $supported_country_card_type_matrix;
$this->enabled_shipping_locations = $enabled_shipping_locations;
+ $this->supported_country_card_type_matrix = $supported_country_card_type_matrix;
}
/**
@@ -179,7 +189,7 @@ class AxoManager {
*
* @return array
*/
- private function script_data() {
+ private function script_data(): array {
return array(
'environment' => array(
'is_sandbox' => $this->environment->current_environment() === 'sandbox',
@@ -187,20 +197,10 @@ class AxoManager {
'widgets' => array(
'email' => 'render',
),
- 'insights' => array(
- 'enabled' => defined( 'WP_DEBUG' ) && WP_DEBUG,
- 'client_id' => ( $this->settings->has( 'client_id' ) ? $this->settings->get( 'client_id' ) : null ),
- 'session_id' =>
- substr(
- method_exists( WC()->session, 'get_customer_unique_id' ) ? md5( WC()->session->get_customer_unique_id() ) : '',
- 0,
- 16
- ),
- 'amount' => array(
- 'currency_code' => $this->currency->get(),
- 'value' => WC()->cart->get_total( 'numeric' ),
- ),
- ),
+ // The amount is not available when setting the insights data, so we need to merge it here.
+ 'insights' => ( function( array $data ): array {
+ $data['amount']['value'] = WC()->cart->get_total( 'numeric' );
+ return $data; } )( $this->insights_data ),
'allowed_cards' => $this->supported_country_card_type_matrix,
'disable_cards' => $this->settings->has( 'disable_cards' ) ? (array) $this->settings->get( 'disable_cards' ) : array(),
'enabled_shipping_locations' => $this->enabled_shipping_locations,
diff --git a/modules/ppcp-axo/src/AxoModule.php b/modules/ppcp-axo/src/AxoModule.php
index 2caed32d7..b055697ba 100644
--- a/modules/ppcp-axo/src/AxoModule.php
+++ b/modules/ppcp-axo/src/AxoModule.php
@@ -320,6 +320,15 @@ class AxoModule implements ServiceModule, ExtendingModule, ExecutableModule {
$endpoint->handle_request();
}
);
+
+ // Enqueue the PayPal Insights script.
+ add_action(
+ 'wp_enqueue_scripts',
+ function () use ( $c ) {
+ $this->enqueue_paypal_insights_script_on_order_received( $c );
+ }
+ );
+
return true;
}
@@ -435,8 +444,8 @@ class AxoModule implements ServiceModule, ExtendingModule, ExecutableModule {
* @return bool
*/
private function is_excluded_endpoint(): bool {
- // Exclude the Order Pay endpoint.
- return is_wc_endpoint_url( 'order-pay' );
+ // Exclude the Order Pay and Order Received endpoints.
+ return is_wc_endpoint_url( 'order-pay' ) || is_wc_endpoint_url( 'order-received' );
}
/**
@@ -457,4 +466,57 @@ class AxoModule implements ServiceModule, ExtendingModule, ExecutableModule {
$axo_enabled ? 'enabled' : 'disabled'
);
}
+
+ /**
+ * Enqueues PayPal Insights on the Order Received endpoint.
+ *
+ * @param ContainerInterface $c The service container.
+ * @return void
+ */
+ private function enqueue_paypal_insights_script_on_order_received( ContainerInterface $c ): void {
+ global $wp;
+
+ if ( ! isset( $wp->query_vars['order-received'] ) ) {
+ return;
+ }
+
+ $order_id = absint( $wp->query_vars['order-received'] );
+ if ( ! $order_id ) {
+ return;
+ }
+
+ $order = wc_get_order( $order_id );
+ if ( ! $order || ! $order instanceof \WC_Order ) {
+ return;
+ }
+
+ $module_url = $c->get( 'axo.url' );
+ $asset_version = $c->get( 'ppcp.asset-version' );
+ $insights_data = $c->get( 'axo.insights' );
+
+ wp_register_script(
+ 'wc-ppcp-paypal-insights-end-checkout',
+ untrailingslashit( $module_url ) . '/assets/js/TrackEndCheckout.js',
+ array( 'wp-plugins', 'wp-data', 'wp-element', 'wc-blocks-registry' ),
+ $asset_version,
+ true
+ );
+
+ wp_localize_script(
+ 'wc-ppcp-paypal-insights-end-checkout',
+ 'wc_ppcp_axo_insights_data',
+ array_merge(
+ $insights_data,
+ array(
+ 'orderId' => $order_id,
+ 'orderTotal' => (string) $order->get_total(),
+ 'orderCurrency' => (string) $order->get_currency(),
+ 'paymentMethod' => (string) $order->get_payment_method(),
+ 'orderKey' => (string) $order->get_order_key(),
+ )
+ )
+ );
+
+ wp_enqueue_script( 'wc-ppcp-paypal-insights-end-checkout' );
+ }
}
diff --git a/modules/ppcp-axo/webpack.config.js b/modules/ppcp-axo/webpack.config.js
index 95c7f0fc6..e8638b564 100644
--- a/modules/ppcp-axo/webpack.config.js
+++ b/modules/ppcp-axo/webpack.config.js
@@ -1,39 +1,44 @@
-const path = require('path');
+const path = require( 'path' );
const isProduction = process.env.NODE_ENV === 'production';
const DependencyExtractionWebpackPlugin = require( '@woocommerce/dependency-extraction-webpack-plugin' );
module.exports = {
- devtool: isProduction ? 'source-map' : 'eval-source-map',
- mode: isProduction ? 'production' : 'development',
- target: 'web',
- plugins: [ new DependencyExtractionWebpackPlugin() ],
- entry: {
- 'boot': path.resolve('./resources/js/boot.js'),
- 'styles': path.resolve('./resources/css/styles.scss')
- },
- output: {
- path: path.resolve(__dirname, 'assets/'),
- filename: 'js/[name].js',
- },
- module: {
- rules: [{
- test: /\.js?$/,
- exclude: /node_modules/,
- loader: 'babel-loader',
- },
- {
- test: /\.scss$/,
- exclude: /node_modules/,
- use: [
- {
- loader: 'file-loader',
- options: {
- name: 'css/[name].css',
- }
- },
- {loader:'sass-loader'}
- ]
- }]
- }
+ devtool: isProduction ? 'source-map' : 'eval-source-map',
+ mode: isProduction ? 'production' : 'development',
+ target: 'web',
+ plugins: [ new DependencyExtractionWebpackPlugin() ],
+ entry: {
+ boot: path.resolve( './resources/js/boot.js' ),
+ styles: path.resolve( './resources/css/styles.scss' ),
+ TrackEndCheckout: path.resolve(
+ './resources/js/Insights/EndCheckoutTracker.js'
+ ),
+ },
+ output: {
+ path: path.resolve( __dirname, 'assets/' ),
+ filename: 'js/[name].js',
+ },
+ module: {
+ rules: [
+ {
+ test: /\.js?$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader',
+ },
+ {
+ test: /\.scss$/,
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: 'file-loader',
+ options: {
+ name: 'css/[name].css',
+ },
+ },
+ { loader: 'sass-loader' },
+ ],
+ },
+ ],
+ },
};
diff --git a/modules/ppcp-onboarding/src/OnboardingModule.php b/modules/ppcp-onboarding/src/OnboardingModule.php
index 40e137832..3ec48fabf 100644
--- a/modules/ppcp-onboarding/src/OnboardingModule.php
+++ b/modules/ppcp-onboarding/src/OnboardingModule.php
@@ -44,26 +44,33 @@ class OnboardingModule implements ServiceModule, ExtendingModule, ExecutableModu
*/
public function run( ContainerInterface $c ): bool {
- $asset_loader = $c->get( 'onboarding.assets' );
- /**
- * The OnboardingAssets.
- *
- * @var OnboardingAssets $asset_loader
- */
- add_action(
- 'admin_enqueue_scripts',
- array(
- $asset_loader,
- 'register',
- )
- );
- add_action(
- 'woocommerce_settings_checkout',
- array(
- $asset_loader,
- 'enqueue',
- )
- );
+ if ( ! apply_filters(
+ // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
+ 'woocommerce.feature-flags.woocommerce_paypal_payments.settings_enabled',
+ getenv( 'PCP_SETTINGS_ENABLED' ) === '1'
+ ) ) {
+
+ $asset_loader = $c->get( 'onboarding.assets' );
+ /**
+ * The OnboardingAssets.
+ *
+ * @var OnboardingAssets $asset_loader
+ */
+ add_action(
+ 'admin_enqueue_scripts',
+ array(
+ $asset_loader,
+ 'register',
+ )
+ );
+ add_action(
+ 'woocommerce_settings_checkout',
+ array(
+ $asset_loader,
+ 'enqueue',
+ )
+ );
+ }
add_filter(
'woocommerce_form_field',
diff --git a/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js b/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js
index 8e75e3ad7..88df7d309 100644
--- a/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js
+++ b/modules/ppcp-save-payment-methods/resources/js/add-payment-method.js
@@ -82,9 +82,8 @@ import {
renderFields( cardFields );
}
- document
- .querySelector( '#place_order' )
- ?.addEventListener( 'click', ( event ) => {
+ const placeOrderButton = document.querySelector( '#place_order' );
+ placeOrderButton?.addEventListener( 'click', ( event ) => {
const cardPaymentToken = document.querySelector(
'input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked'
)?.value;
@@ -95,11 +94,11 @@ import {
) {
return;
}
-
+ placeOrderButton.disabled = true;
event.preventDefault();
-
cardFields.submit().catch( ( error ) => {
console.error( error );
+ placeOrderButton.disabled = false;
} );
} );
} );
diff --git a/modules/ppcp-settings/images/icon-dashboard-list.svg b/modules/ppcp-settings/images/icon-overview-list.svg
similarity index 100%
rename from modules/ppcp-settings/images/icon-dashboard-list.svg
rename to modules/ppcp-settings/images/icon-overview-list.svg
diff --git a/modules/ppcp-settings/images/icon-dashboard-status.svg b/modules/ppcp-settings/images/icon-overview-status.svg
similarity index 100%
rename from modules/ppcp-settings/images/icon-dashboard-status.svg
rename to modules/ppcp-settings/images/icon-overview-status.svg
diff --git a/modules/ppcp-settings/images/icon-dashboard-support.svg b/modules/ppcp-settings/images/icon-overview-support.svg
similarity index 100%
rename from modules/ppcp-settings/images/icon-dashboard-support.svg
rename to modules/ppcp-settings/images/icon-overview-support.svg
diff --git a/modules/ppcp-settings/resources/css/_variables.scss b/modules/ppcp-settings/resources/css/_variables.scss
index 6d4903a96..9febb1e47 100644
--- a/modules/ppcp-settings/resources/css/_variables.scss
+++ b/modules/ppcp-settings/resources/css/_variables.scss
@@ -18,7 +18,7 @@ $color-gradient-dark: #001435;
$gradient-header: linear-gradient(87.03deg, #003087 -0.49%, #001E51 29.22%, $color-gradient-dark 100%);
$max-width-onboarding: 1024px;
-$max-width-onboarding-content: 662px;
+$max-width-onboarding-content: 500px;
$max-width-settings: 938px;
#ppcp-settings-container {
diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_onboarding-header.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_onboarding-header.scss
index b73908da3..d6d8cf4f3 100644
--- a/modules/ppcp-settings/resources/css/components/reusable-components/_onboarding-header.scss
+++ b/modules/ppcp-settings/resources/css/components/reusable-components/_onboarding-header.scss
@@ -1,5 +1,5 @@
.ppcp-r-onboarding-header{
- margin: 0 0 32px 0;
+ margin: 0 0 24px 0;
&__logo {
text-align: center;
diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_select-box.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_select-box.scss
index c32bfe706..fbfb2c7e0 100644
--- a/modules/ppcp-settings/resources/css/components/reusable-components/_select-box.scss
+++ b/modules/ppcp-settings/resources/css/components/reusable-components/_select-box.scss
@@ -8,14 +8,12 @@
.ppcp-r-select-box {
position: relative;
width: 100%;
- border: 1px solid $color-gray-500;
+ border: 1px solid $color-gray-200;
outline: 1px solid transparent;
- border-radius: 8px;
+ border-radius: 4px;
display: flex;
- gap: 32px;
- align-items: center;
- box-sizing: border-box;
- padding: 28px 16px 28px 32px;
+ gap: 16px;
+ padding: 24px 16px 24px 16px;
&.selected {
@@ -59,20 +57,23 @@
&__content {
display: flex;
- gap: 18px;
}
&__title {
- @include font(16, 24, 600);
- color: $color-blueberry;
+ @include font(14, 20, 700);
+ color: $color-black;
margin: 0 0 4px 0;
display: block;
}
&__description {
- @include font(14, 20, 400);
- color: $color-gray-800;
- margin: 0 0 18px 0;
+ @include font(13, 20, 400);
+ color: $color-gray-700;
+ margin:0;
+
+ &:not(:last-child){
+ margin-block-end:18px;
+ }
}
&__radio-presentation {
diff --git a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss
index 6f067de66..7eba20d20 100644
--- a/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss
+++ b/modules/ppcp-settings/resources/css/components/reusable-components/_settings-wrapper.scss
@@ -9,7 +9,7 @@
margin-left: auto;
margin-right: auto;
padding: 0 16px 48px;
- box-sizing: border-box;
+ box-sizing: content-box;
@media screen and (max-width: 480px) {
padding-bottom: 36px;
diff --git a/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-products.scss b/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-products.scss
index 2947c8fab..2d1f759e7 100644
--- a/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-products.scss
+++ b/modules/ppcp-settings/resources/css/components/screens/onboarding/_step-products.scss
@@ -8,8 +8,7 @@
display: flex;
align-items: center;
gap: 4px;
- color: $color-gray-700;
- @include font(14, 20, 400);
+ @include font(13, 20, 400);
margin: 0;
&::before {
@@ -29,7 +28,7 @@
.ppcp-r-select-box__additional-content {
a {
- @include font(12, 20, 400);
+ @include font(13, 20, 500);
color: $color-blueberry;
}
}
diff --git a/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss b/modules/ppcp-settings/resources/css/components/screens/overview/_tab-overview.scss
similarity index 98%
rename from modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss
rename to modules/ppcp-settings/resources/css/components/screens/overview/_tab-overview.scss
index d78d43373..bffe62134 100644
--- a/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-dashboard.scss
+++ b/modules/ppcp-settings/resources/css/components/screens/overview/_tab-overview.scss
@@ -1,4 +1,4 @@
-.ppcp-r-tab-dashboard-todo {
+.ppcp-r-tab-overview-todo {
margin: 0 0 48px 0;
}
diff --git a/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-payment-methods.scss b/modules/ppcp-settings/resources/css/components/screens/overview/_tab-payment-methods.scss
similarity index 100%
rename from modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-payment-methods.scss
rename to modules/ppcp-settings/resources/css/components/screens/overview/_tab-payment-methods.scss
diff --git a/modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-settings.scss b/modules/ppcp-settings/resources/css/components/screens/overview/_tab-settings.scss
similarity index 100%
rename from modules/ppcp-settings/resources/css/components/screens/dashboard/_tab-settings.scss
rename to modules/ppcp-settings/resources/css/components/screens/overview/_tab-settings.scss
diff --git a/modules/ppcp-settings/resources/css/style.scss b/modules/ppcp-settings/resources/css/style.scss
index 5a0032536..c890803c1 100644
--- a/modules/ppcp-settings/resources/css/style.scss
+++ b/modules/ppcp-settings/resources/css/style.scss
@@ -20,9 +20,9 @@
@import './components/reusable-components/spinner-overlay';
@import './components/reusable-components/welcome-docs';
@import './components/screens/onboarding';
- @import './components/screens/dashboard/tab-dashboard';
- @import './components/screens/dashboard/tab-payment-methods';
- @import 'components/screens/dashboard/tab-settings';
+ @import './components/screens/overview/tab-overview';
+ @import './components/screens/overview/tab-payment-methods';
+ @import 'components/screens/overview/tab-settings';
}
@import './components/reusable-components/payment-method-modal';
diff --git a/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js b/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js
index 06a56c5ac..145efb223 100644
--- a/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js
+++ b/modules/ppcp-settings/resources/js/Components/ReusableComponents/SelectBox.js
@@ -31,7 +31,6 @@ const SelectBox = ( props ) => {
/>
) }
- { data().getImage( props.icon ) }
{ props.title }
diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepBusiness.js b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepBusiness.js
index 3a6632c74..6dcf435c9 100644
--- a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepBusiness.js
+++ b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepBusiness.js
@@ -33,22 +33,38 @@ const StepBusiness = ( {
diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepProducts.js b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepProducts.js
index f44cc89c1..d84fed57e 100644
--- a/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepProducts.js
+++ b/modules/ppcp-settings/resources/js/Components/Screens/Onboarding/StepProducts.js
@@ -18,7 +18,7 @@ const StepProducts = ( {
@@ -27,10 +27,9 @@ const StepProducts = ( {
{
+const TabOverview = () => {
const [ todos, setTodos ] = useState( [] );
const [ todosData, setTodosData ] = useState( todosDataDefault );
return (
-
+
{ todosData.length > 0 && (
{
) }
{
const tabs = [];
tabs.push( {
- name: 'dashboard',
- title: __( 'Dashboard', 'woocommerce-paypal-payments' ),
- component: ,
+ name: 'overview',
+ title: __( 'Overview', 'woocommerce-paypal-payments' ),
+ component: ,
} );
tabs.push( {