diff --git a/modules/ppcp-settings/node_modules/.gitkeep b/modules/ppcp-settings/node_modules/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/modules/ppcp-settings/package.json b/modules/ppcp-settings/package.json index 94018d509..dfcad023c 100644 --- a/modules/ppcp-settings/package.json +++ b/modules/ppcp-settings/package.json @@ -15,6 +15,7 @@ "dependencies": { "@paypal/paypal-js": "^8.1.2", "@woocommerce/settings": "^1.0.0", + "deepmerge": "^4.3.1", "react-select": "^5.8.3" } } diff --git a/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabStyling.js b/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabStyling.js index d3eff525b..4eafbb665 100644 --- a/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabStyling.js +++ b/modules/ppcp-settings/resources/js/Components/Screens/Overview/TabStyling.js @@ -2,6 +2,7 @@ import { __, sprintf } from '@wordpress/i18n'; import { SelectControl, RadioControl } from '@wordpress/components'; import { PayPalCheckboxGroup } from '../../ReusableComponents/Fields'; import { useState, useMemo, useEffect } from '@wordpress/element'; +import Renderer from '../../../../../../ppcp-button/resources/js/modules/Renderer/Renderer'; import { defaultLocationSettings, paymentMethodOptions, @@ -10,7 +11,6 @@ import { buttonLayoutOptions, buttonLabelOptions, } from '../../../data/settings/tab-styling-data'; -import Renderer from '../../../utils/renderer'; const TabStyling = () => { useEffect( () => { @@ -178,11 +178,8 @@ const TabStyling = () => { ) } -
-
+
+
); @@ -229,28 +226,73 @@ const SectionIntro = () => { }; const generatePreview = () => { - const settings = { - button: { - wrapper: '#ppcp-r-styling-preview', - style: { - color: 'gold', - shape: 'rect', - label: 'paypal', - tagline: false, - layout: 'horizontal', + const render = () => { + const settings = { + button: { + wrapper: '#ppcp-r-styling-preview', + style: { + color: 'gold', + shape: 'rect', + label: 'paypal', + tagline: false, + layout: 'horizontal', + }, }, - }, - separate_buttons: {}, + separate_buttons: {}, + }; + const wrapperSelector = + Object.values( settings.separate_buttons ).length > 0 + ? Object.values( settings.separate_buttons )[ 0 ].wrapper + : settings.button.wrapper; + const wrapper = document.querySelector( wrapperSelector ); + if ( ! wrapper ) { + return; + } + wrapper.innerHTML = ''; + + const renderer = new Renderer( + null, + settings, + ( data, actions ) => actions.reject(), + null + ); + + try { + renderer.render( {} ); + jQuery( document ).trigger( + 'ppcp_paypal_render_preview', + settings + ); + } catch ( err ) { + console.error( err ); + } }; - const renderer = new Renderer( - null, - settings, - ( data, actions ) => actions.reject(), - null - ); - jQuery( document ).trigger( 'ppcp_paypal_render_preview', settings ); - renderer.render( {} ); + renderPreview( () => { + console.log( 'CALLBACK' ); + }, render ); }; +function renderPreview( settingsCallback, render ) { + let oldSettings = settingsCallback(); + const form = jQuery( '#mainform' ); + form.on( 'change', ':input', () => { + const newSettings = settingsCallback(); + if ( JSON.stringify( oldSettings ) === JSON.stringify( newSettings ) ) { + return; + } + + render( newSettings ); + + oldSettings = newSettings; + } ); + + jQuery( document ).on( 'ppcp_paypal_script_loaded', () => { + oldSettings = settingsCallback(); + + render( oldSettings ); + } ); + + render( oldSettings ); +} export default TabStyling; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/ApmButtons.js b/modules/ppcp-settings/resources/js/utils/Helper/ApmButtons.js deleted file mode 100644 index 385432357..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/ApmButtons.js +++ /dev/null @@ -1,129 +0,0 @@ -export const apmButtonsInit = ( config, selector = '.ppcp-button-apm' ) => { - let selectorInContainer = selector; - - if ( window.ppcpApmButtons ) { - return; - } - - if ( config && config.button ) { - // If it's separate gateways, modify wrapper to account for the individual buttons as individual APMs. - const wrapper = config.button.wrapper; - const isSeparateGateways = - jQuery( wrapper ).children( 'div[class^="item-"]' ).length > 0; - - if ( isSeparateGateways ) { - selector += `, ${ wrapper } div[class^="item-"]`; - selectorInContainer += `, div[class^="item-"]`; - } - } - - window.ppcpApmButtons = new ApmButtons( selector, selectorInContainer ); -}; - -export class ApmButtons { - constructor( selector, selectorInContainer ) { - this.selector = selector; - this.selectorInContainer = selectorInContainer; - this.containers = []; - - // Reloads button containers. - this.reloadContainers(); - - // Refresh button layout. - jQuery( window ) - .resize( () => { - this.refresh(); - } ) - .resize(); - - jQuery( document ).on( 'ppcp-smart-buttons-init', () => { - this.refresh(); - } ); - - jQuery( document ).on( - 'ppcp-shown ppcp-hidden ppcp-enabled ppcp-disabled', - ( ev, data ) => { - this.refresh(); - setTimeout( this.refresh.bind( this ), 200 ); - } - ); - - // Observes for new buttons. - new MutationObserver( - this.observeElementsCallback.bind( this ) - ).observe( document.body, { childList: true, subtree: true } ); - } - - observeElementsCallback( mutationsList, observer ) { - const observeSelector = - this.selector + - ', .widget_shopping_cart, .widget_shopping_cart_content'; - - let shouldReload = false; - for ( const mutation of mutationsList ) { - if ( mutation.type === 'childList' ) { - mutation.addedNodes.forEach( ( node ) => { - if ( node.matches && node.matches( observeSelector ) ) { - shouldReload = true; - } - } ); - } - } - - if ( shouldReload ) { - this.reloadContainers(); - this.refresh(); - } - } - - reloadContainers() { - jQuery( this.selector ).each( ( index, el ) => { - const parent = jQuery( el ).parent(); - if ( ! this.containers.some( ( $el ) => $el.is( parent ) ) ) { - this.containers.push( parent ); - } - } ); - } - - refresh() { - for ( const container of this.containers ) { - const $container = jQuery( container ); - - // Check width and add classes - const width = $container.width(); - - $container.removeClass( - 'ppcp-width-500 ppcp-width-300 ppcp-width-min' - ); - - if ( width >= 500 ) { - $container.addClass( 'ppcp-width-500' ); - } else if ( width >= 300 ) { - $container.addClass( 'ppcp-width-300' ); - } else { - $container.addClass( 'ppcp-width-min' ); - } - - // Check first apm button - const $firstElement = $container.children( ':visible' ).first(); - - // Assign margins to buttons - $container.find( this.selectorInContainer ).each( ( index, el ) => { - const $el = jQuery( el ); - - if ( $el.is( $firstElement ) ) { - $el.css( 'margin-top', `0px` ); - return true; - } - - const minMargin = 11; // Minimum margin. - const height = $el.height(); - const margin = Math.max( - minMargin, - Math.round( height * 0.3 ) - ); - $el.css( 'margin-top', `${ margin }px` ); - } ); - } - } -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/BootstrapHelper.js b/modules/ppcp-settings/resources/js/utils/Helper/BootstrapHelper.js deleted file mode 100644 index f30b2ade6..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/BootstrapHelper.js +++ /dev/null @@ -1,54 +0,0 @@ -import { disable, enable, isDisabled } from './ButtonDisabler'; -import merge from 'deepmerge'; - -/** - * Common Bootstrap methods to avoid code repetition. - */ -export default class BootstrapHelper { - static handleButtonStatus( bs, options ) { - options = options || {}; - options.wrapper = options.wrapper || bs.gateway.button.wrapper; - - const wasDisabled = isDisabled( options.wrapper ); - const shouldEnable = bs.shouldEnable(); - - // Handle enable / disable - if ( shouldEnable && wasDisabled ) { - bs.renderer.enableSmartButtons( options.wrapper ); - enable( options.wrapper ); - } else if ( ! shouldEnable && ! wasDisabled ) { - bs.renderer.disableSmartButtons( options.wrapper ); - disable( options.wrapper, options.formSelector || null ); - } - - if ( wasDisabled !== ! shouldEnable ) { - jQuery( options.wrapper ).trigger( 'ppcp_buttons_enabled_changed', [ - shouldEnable, - ] ); - } - } - - static shouldEnable( bs, options ) { - options = options || {}; - if ( typeof options.isDisabled === 'undefined' ) { - options.isDisabled = bs.gateway.button.is_disabled; - } - - return bs.shouldRender() && options.isDisabled !== true; - } - - static updateScriptData( bs, newData ) { - const newObj = merge( bs.gateway, newData ); - - const isChanged = - JSON.stringify( bs.gateway ) !== JSON.stringify( newObj ); - - bs.gateway = newObj; - - if ( isChanged ) { - jQuery( document.body ).trigger( 'ppcp_script_data_changed', [ - newObj, - ] ); - } - } -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/ButtonDisabler.js b/modules/ppcp-settings/resources/js/utils/Helper/ButtonDisabler.js deleted file mode 100644 index 30cc3f31b..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/ButtonDisabler.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @param selectorOrElement - * @return {Element} - */ -const getElement = ( selectorOrElement ) => { - if ( typeof selectorOrElement === 'string' ) { - return document.querySelector( selectorOrElement ); - } - return selectorOrElement; -}; - -const triggerEnabled = ( selectorOrElement, element ) => { - jQuery( document ).trigger( 'ppcp-enabled', { - handler: 'ButtonsDisabler.setEnabled', - action: 'enable', - selector: selectorOrElement, - element, - } ); -}; - -const triggerDisabled = ( selectorOrElement, element ) => { - jQuery( document ).trigger( 'ppcp-disabled', { - handler: 'ButtonsDisabler.setEnabled', - action: 'disable', - selector: selectorOrElement, - element, - } ); -}; - -export const setEnabled = ( selectorOrElement, enable, form = null ) => { - const element = getElement( selectorOrElement ); - - if ( ! element ) { - return; - } - - if ( enable ) { - jQuery( element ) - .removeClass( 'ppcp-disabled' ) - .off( 'mouseup' ) - .find( '> *' ) - .css( 'pointer-events', '' ); - - triggerEnabled( selectorOrElement, element ); - } else { - jQuery( element ) - .addClass( 'ppcp-disabled' ) - .on( 'mouseup', function ( event ) { - event.stopImmediatePropagation(); - - if ( form ) { - // Trigger form submit to show the error message - const $form = jQuery( form ); - if ( - $form - .find( '.single_add_to_cart_button' ) - .hasClass( 'disabled' ) - ) { - $form.find( ':submit' ).trigger( 'click' ); - } - } - } ) - .find( '> *' ) - .css( 'pointer-events', 'none' ); - - triggerDisabled( selectorOrElement, element ); - } -}; - -export const isDisabled = ( selectorOrElement ) => { - const element = getElement( selectorOrElement ); - - if ( ! element ) { - return false; - } - - return jQuery( element ).hasClass( 'ppcp-disabled' ); -}; - -export const disable = ( selectorOrElement, form = null ) => { - setEnabled( selectorOrElement, false, form ); -}; - -export const enable = ( selectorOrElement ) => { - setEnabled( selectorOrElement, true ); -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/ButtonRefreshHelper.js b/modules/ppcp-settings/resources/js/utils/Helper/ButtonRefreshHelper.js deleted file mode 100644 index 7620547c0..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/ButtonRefreshHelper.js +++ /dev/null @@ -1,46 +0,0 @@ -import { debounce } from '../../../../../ppcp-blocks/resources/js/Helper/debounce'; - -const REFRESH_BUTTON_EVENT = 'ppcp_refresh_payment_buttons'; - -/** - * Triggers a refresh of the payment buttons. - * This function dispatches a custom event that the button components listen for. - * - * Use this function on the front-end to update payment buttons after the checkout form was updated. - */ -export function refreshButtons() { - document.dispatchEvent( new Event( REFRESH_BUTTON_EVENT ) ); -} - -/** - * Sets up event listeners for various cart and checkout update events. - * When these events occur, it triggers a refresh of the payment buttons. - * - * @param {Function} refresh - Callback responsible to re-render the payment button. - */ -export function setupButtonEvents( refresh ) { - const miniCartInitDelay = 1000; - const debouncedRefresh = debounce( refresh, 50 ); - - // Listen for our custom refresh event. - document.addEventListener( REFRESH_BUTTON_EVENT, debouncedRefresh ); - - // Listen for cart and checkout update events. - // Note: we need jQuery here, because WooCommerce uses jQuery.trigger() to dispatch the events. - window - .jQuery( 'body' ) - .on( 'updated_cart_totals', debouncedRefresh ) - .on( 'updated_checkout', debouncedRefresh ); - - // Use setTimeout for fragment events to avoid unnecessary refresh on initial render. - setTimeout( () => { - document.body.addEventListener( - 'wc_fragments_loaded', - debouncedRefresh - ); - document.body.addEventListener( - 'wc_fragments_refreshed', - debouncedRefresh - ); - }, miniCartInitDelay ); -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/CartHelper.js b/modules/ppcp-settings/resources/js/utils/Helper/CartHelper.js deleted file mode 100644 index 746df7b40..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/CartHelper.js +++ /dev/null @@ -1,77 +0,0 @@ -class CartHelper { - constructor( cartItemKeys = [] ) { - this.cartItemKeys = cartItemKeys; - } - - getEndpoint() { - let ajaxUrl = '/?wc-ajax=%%endpoint%%'; - - if ( - typeof wc_cart_fragments_params !== 'undefined' && - wc_cart_fragments_params.wc_ajax_url - ) { - ajaxUrl = wc_cart_fragments_params.wc_ajax_url; - } - - return ajaxUrl.toString().replace( '%%endpoint%%', 'remove_from_cart' ); - } - - addFromPurchaseUnits( purchaseUnits ) { - for ( const purchaseUnit of purchaseUnits || [] ) { - for ( const item of purchaseUnit.items || [] ) { - if ( ! item.cart_item_key ) { - continue; - } - this.cartItemKeys.push( item.cart_item_key ); - } - } - - return this; - } - - removeFromCart() { - return new Promise( ( resolve, reject ) => { - if ( ! this.cartItemKeys || ! this.cartItemKeys.length ) { - resolve(); - return; - } - - const numRequests = this.cartItemKeys.length; - let numResponses = 0; - - const tryToResolve = () => { - numResponses++; - if ( numResponses >= numRequests ) { - resolve(); - } - }; - - for ( const cartItemKey of this.cartItemKeys ) { - const params = new URLSearchParams(); - params.append( 'cart_item_key', cartItemKey ); - - if ( ! cartItemKey ) { - tryToResolve(); - continue; - } - - fetch( this.getEndpoint(), { - method: 'POST', - credentials: 'same-origin', - body: params, - } ) - .then( function ( res ) { - return res.json(); - } ) - .then( () => { - tryToResolve(); - } ) - .catch( () => { - tryToResolve(); - } ); - } - } ); - } -} - -export default CartHelper; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/CheckoutFormValidation.js b/modules/ppcp-settings/resources/js/utils/Helper/CheckoutFormValidation.js deleted file mode 100644 index 26070ecf2..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/CheckoutFormValidation.js +++ /dev/null @@ -1,55 +0,0 @@ -import Spinner from './Spinner'; -import FormValidator from './FormValidator'; -import ErrorHandler from '../ErrorHandler'; - -const validateCheckoutForm = function ( config ) { - return new Promise( async ( resolve, reject ) => { - try { - const spinner = new Spinner(); - const errorHandler = new ErrorHandler( - config.labels.error.generic, - document.querySelector( '.woocommerce-notices-wrapper' ) - ); - - const formSelector = - config.context === 'checkout' - ? 'form.checkout' - : 'form#order_review'; - const formValidator = config.early_checkout_validation_enabled - ? new FormValidator( - config.ajax.validate_checkout.endpoint, - config.ajax.validate_checkout.nonce - ) - : null; - - if ( ! formValidator ) { - resolve(); - return; - } - - formValidator - .validate( document.querySelector( formSelector ) ) - .then( ( errors ) => { - if ( errors.length > 0 ) { - spinner.unblock(); - errorHandler.clear(); - errorHandler.messages( errors ); - - // fire WC event for other plugins - jQuery( document.body ).trigger( 'checkout_error', [ - errorHandler.currentHtml(), - ] ); - - reject(); - } else { - resolve(); - } - } ); - } catch ( error ) { - console.error( error ); - reject(); - } - } ); -}; - -export default validateCheckoutForm; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/CheckoutMethodState.js b/modules/ppcp-settings/resources/js/utils/Helper/CheckoutMethodState.js deleted file mode 100644 index 4275e48d4..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/CheckoutMethodState.js +++ /dev/null @@ -1,48 +0,0 @@ -export const PaymentMethods = { - PAYPAL: 'ppcp-gateway', - CARDS: 'ppcp-credit-card-gateway', - OXXO: 'ppcp-oxxo-gateway', - CARD_BUTTON: 'ppcp-card-button-gateway', - GOOGLEPAY: 'ppcp-googlepay', - APPLEPAY: 'ppcp-applepay', -}; - -/** - * List of valid context values that the button can have. - * - * The "context" describes the placement or page where a payment button might be displayed. - * - * @type {Object} - */ -export const PaymentContext = { - Cart: 'cart', // Classic cart. - Checkout: 'checkout', // Classic checkout. - BlockCart: 'cart-block', // Block cart. - BlockCheckout: 'checkout-block', // Block checkout. - Product: 'product', // Single product page. - MiniCart: 'mini-cart', // Mini cart available on all pages except checkout & cart. - PayNow: 'pay-now', // Pay for order, via admin generated link. - Preview: 'preview', // Layout preview on settings page. - - // Contexts that use blocks to render payment methods. - Blocks: [ 'cart-block', 'checkout-block' ], - - // Contexts that display "classic" payment gateways. - Gateways: [ 'checkout', 'pay-now' ], -}; - -export const ORDER_BUTTON_SELECTOR = '#place_order'; - -export const getCurrentPaymentMethod = () => { - const el = document.querySelector( 'input[name="payment_method"]:checked' ); - if ( ! el ) { - return null; - } - - return el.value; -}; - -export const isSavedCardSelected = () => { - const savedCardList = document.querySelector( '#saved-credit-card' ); - return savedCardList && savedCardList.value !== ''; -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/ConfigProcessor.js b/modules/ppcp-settings/resources/js/utils/Helper/ConfigProcessor.js deleted file mode 100644 index b8736d0e1..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/ConfigProcessor.js +++ /dev/null @@ -1,31 +0,0 @@ -import merge from 'deepmerge'; -import { v4 as uuidv4 } from 'uuid'; -import { keysToCamelCase } from './Utils'; - -const processAxoConfig = ( config ) => { - const scriptOptions = {}; - const sdkClientToken = config?.axo?.sdk_client_token; - const uuid = uuidv4().replace( /-/g, '' ); - if ( sdkClientToken && config?.user?.is_logged !== true ) { - scriptOptions[ 'data-sdk-client-token' ] = sdkClientToken; - scriptOptions[ 'data-client-metadata-id' ] = uuid; - } - return scriptOptions; -}; - -const processUserIdToken = ( config ) => { - const userIdToken = config?.save_payment_methods?.id_token; - return userIdToken && config?.user?.is_logged === true - ? { 'data-user-id-token': userIdToken } - : {}; -}; - -export const processConfig = ( config ) => { - let scriptOptions = keysToCamelCase( config.url_params ); - if ( config.script_attributes ) { - scriptOptions = merge( scriptOptions, config.script_attributes ); - } - const axoOptions = processAxoConfig( config ); - const userIdTokenOptions = processUserIdToken( config ); - return merge.all( [ scriptOptions, axoOptions, userIdTokenOptions ] ); -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/DccInputFactory.js b/modules/ppcp-settings/resources/js/utils/Helper/DccInputFactory.js deleted file mode 100644 index 114c9102e..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/DccInputFactory.js +++ /dev/null @@ -1,21 +0,0 @@ -const dccInputFactory = ( original ) => { - const styles = window.getComputedStyle( original ); - const newElement = document.createElement( 'span' ); - - newElement.setAttribute( 'id', original.id ); - newElement.setAttribute( 'class', original.className ); - - Object.values( styles ).forEach( ( prop ) => { - if ( - ! styles[ prop ] || - ! isNaN( prop ) || - prop === 'background-image' - ) { - return; - } - newElement.style.setProperty( prop, '' + styles[ prop ] ); - } ); - return newElement; -}; - -export default dccInputFactory; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/FormHelper.js b/modules/ppcp-settings/resources/js/utils/Helper/FormHelper.js deleted file mode 100644 index 0fc5cdbe4..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/FormHelper.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Common Form utility methods - */ -export default class FormHelper { - static getPrefixedFields( formElement, prefix ) { - const formData = new FormData( formElement ); - const fields = {}; - - for ( const [ name, value ] of formData.entries() ) { - if ( ! prefix || name.startsWith( prefix ) ) { - fields[ name ] = value; - } - } - - return fields; - } - - static getFilteredFields( formElement, exactFilters, prefixFilters ) { - const formData = new FormData( formElement ); - const fields = {}; - const counters = {}; - - for ( let [ name, value ] of formData.entries() ) { - // Handle array format - if ( name.indexOf( '[]' ) !== -1 ) { - const k = name; - counters[ k ] = counters[ k ] || 0; - name = name.replace( '[]', `[${ counters[ k ] }]` ); - counters[ k ]++; - } - - if ( ! name ) { - continue; - } - if ( exactFilters && exactFilters.indexOf( name ) !== -1 ) { - continue; - } - if ( - prefixFilters && - prefixFilters.some( ( prefixFilter ) => - name.startsWith( prefixFilter ) - ) - ) { - continue; - } - - fields[ name ] = value; - } - - return fields; - } -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/FormSaver.js b/modules/ppcp-settings/resources/js/utils/Helper/FormSaver.js deleted file mode 100644 index dfc27ceff..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/FormSaver.js +++ /dev/null @@ -1,28 +0,0 @@ -export default class FormSaver { - constructor( url, nonce ) { - this.url = url; - this.nonce = nonce; - } - - async save( form ) { - const formData = new FormData( form ); - - const res = await fetch( this.url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'same-origin', - body: JSON.stringify( { - nonce: this.nonce, - form_encoded: new URLSearchParams( formData ).toString(), - } ), - } ); - - const data = await res.json(); - - if ( ! data.success ) { - throw Error( data.data.message ); - } - } -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/FormValidator.js b/modules/ppcp-settings/resources/js/utils/Helper/FormValidator.js deleted file mode 100644 index 01fdfa20b..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/FormValidator.js +++ /dev/null @@ -1,37 +0,0 @@ -export default class FormValidator { - constructor( url, nonce ) { - this.url = url; - this.nonce = nonce; - } - - async validate( form ) { - const formData = new FormData( form ); - - const res = await fetch( this.url, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'same-origin', - body: JSON.stringify( { - nonce: this.nonce, - form_encoded: new URLSearchParams( formData ).toString(), - } ), - } ); - - const data = await res.json(); - - if ( ! data.success ) { - if ( data.data.refresh ) { - jQuery( document.body ).trigger( 'update_checkout' ); - } - - if ( data.data.errors ) { - return data.data.errors; - } - throw Error( data.data.message ); - } - - return []; - } -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/Hiding.js b/modules/ppcp-settings/resources/js/utils/Helper/Hiding.js deleted file mode 100644 index e5b937a52..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/Hiding.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * @param selectorOrElement - * @return {Element} - */ -const getElement = ( selectorOrElement ) => { - if ( typeof selectorOrElement === 'string' ) { - return document.querySelector( selectorOrElement ); - } - return selectorOrElement; -}; - -const triggerHidden = ( handler, selectorOrElement, element ) => { - jQuery( document ).trigger( 'ppcp-hidden', { - handler, - action: 'hide', - selector: selectorOrElement, - element, - } ); -}; - -const triggerShown = ( handler, selectorOrElement, element ) => { - jQuery( document ).trigger( 'ppcp-shown', { - handler, - action: 'show', - selector: selectorOrElement, - element, - } ); -}; - -export const isVisible = ( element ) => { - return !! ( - element.offsetWidth || - element.offsetHeight || - element.getClientRects().length - ); -}; - -export const setVisible = ( selectorOrElement, show, important = false ) => { - const element = getElement( selectorOrElement ); - if ( ! element ) { - return; - } - - const currentValue = element.style.getPropertyValue( 'display' ); - - if ( ! show ) { - if ( currentValue === 'none' ) { - return; - } - - element.style.setProperty( - 'display', - 'none', - important ? 'important' : '' - ); - triggerHidden( 'Hiding.setVisible', selectorOrElement, element ); - } else { - if ( currentValue === 'none' ) { - element.style.removeProperty( 'display' ); - triggerShown( 'Hiding.setVisible', selectorOrElement, element ); - } - - // still not visible (if something else added display: none in CSS) - if ( ! isVisible( element ) ) { - element.style.setProperty( 'display', 'block' ); - triggerShown( 'Hiding.setVisible', selectorOrElement, element ); - } - } -}; - -export const setVisibleByClass = ( selectorOrElement, show, hiddenClass ) => { - const element = getElement( selectorOrElement ); - if ( ! element ) { - return; - } - - if ( show ) { - element.classList.remove( hiddenClass ); - triggerShown( 'Hiding.setVisibleByClass', selectorOrElement, element ); - } else { - element.classList.add( hiddenClass ); - triggerHidden( 'Hiding.setVisibleByClass', selectorOrElement, element ); - } -}; - -export const hide = ( selectorOrElement, important = false ) => { - setVisible( selectorOrElement, false, important ); -}; - -export const show = ( selectorOrElement ) => { - setVisible( selectorOrElement, true ); -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/LocalStorage.js b/modules/ppcp-settings/resources/js/utils/Helper/LocalStorage.js deleted file mode 100644 index 65494369e..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/LocalStorage.js +++ /dev/null @@ -1,179 +0,0 @@ -/* global localStorage */ - -function checkLocalStorageAvailability() { - try { - const testKey = '__ppcp_test__'; - localStorage.setItem( testKey, 'test' ); - localStorage.removeItem( testKey ); - return true; - } catch ( e ) { - return false; - } -} - -function sanitizeKey( name ) { - return name - .toLowerCase() - .trim() - .replace( /[^a-z0-9_-]/g, '_' ); -} - -function deserializeEntry( serialized ) { - try { - const payload = JSON.parse( serialized ); - - return { - data: payload.data, - expires: payload.expires || 0, - }; - } catch ( e ) { - return null; - } -} - -function serializeEntry( data, timeToLive ) { - const payload = { - data, - expires: calculateExpiration( timeToLive ), - }; - - return JSON.stringify( payload ); -} - -function calculateExpiration( timeToLive ) { - return timeToLive ? Date.now() + timeToLive * 1000 : 0; -} - -/** - * A reusable class for handling data storage in the browser's local storage, - * with optional expiration. - * - * Can be extended for module specific logic. - * - * @see GooglePaySession - */ -export class LocalStorage { - /** - * @type {string} - */ - #group = ''; - - /** - * @type {null|boolean} - */ - #canUseLocalStorage = null; - - /** - * @param {string} group - Group name for all storage keys managed by this instance. - */ - constructor( group ) { - this.#group = sanitizeKey( group ) + ':'; - this.#removeExpired(); - } - - /** - * Removes all items in the current group that have reached the expiry date. - */ - #removeExpired() { - if ( ! this.canUseLocalStorage ) { - return; - } - - Object.keys( localStorage ).forEach( ( key ) => { - if ( ! key.startsWith( this.#group ) ) { - return; - } - - const entry = deserializeEntry( localStorage.getItem( key ) ); - if ( entry && entry.expires > 0 && entry.expires < Date.now() ) { - localStorage.removeItem( key ); - } - } ); - } - - /** - * Sanitizes the given entry name and adds the group prefix. - * - * @throws {Error} If the name is empty after sanitization. - * @param {string} name - Entry name. - * @return {string} Prefixed and sanitized entry name. - */ - #entryKey( name ) { - const sanitizedName = sanitizeKey( name ); - - if ( sanitizedName.length === 0 ) { - throw new Error( 'Name cannot be empty after sanitization' ); - } - - return `${ this.#group }${ sanitizedName }`; - } - - /** - * Indicates, whether localStorage is available. - * - * @return {boolean} True means the localStorage API is available. - */ - get canUseLocalStorage() { - if ( null === this.#canUseLocalStorage ) { - this.#canUseLocalStorage = checkLocalStorageAvailability(); - } - - return this.#canUseLocalStorage; - } - - /** - * Stores data in the browser's local storage, with an optional timeout. - * - * @param {string} name - Name of the item in the storage. - * @param {any} data - The data to store. - * @param {number} [timeToLive=0] - Lifespan in seconds. 0 means the data won't expire. - * @throws {Error} If local storage is not available. - */ - set( name, data, timeToLive = 0 ) { - if ( ! this.canUseLocalStorage ) { - throw new Error( 'Local storage is not available' ); - } - - const entry = serializeEntry( data, timeToLive ); - const entryKey = this.#entryKey( name ); - - localStorage.setItem( entryKey, entry ); - } - - /** - * Retrieves previously stored data from the browser's local storage. - * - * @param {string} name - Name of the stored item. - * @return {any|null} The stored data, or null when no valid entry is found or it has expired. - * @throws {Error} If local storage is not available. - */ - get( name ) { - if ( ! this.canUseLocalStorage ) { - throw new Error( 'Local storage is not available' ); - } - - const itemKey = this.#entryKey( name ); - const entry = deserializeEntry( localStorage.getItem( itemKey ) ); - - if ( ! entry ) { - return null; - } - - return entry.data; - } - - /** - * Removes the specified entry from the browser's local storage. - * - * @param {string} name - Name of the stored item. - * @throws {Error} If local storage is not available. - */ - clear( name ) { - if ( ! this.canUseLocalStorage ) { - throw new Error( 'Local storage is not available' ); - } - - const itemKey = this.#entryKey( name ); - localStorage.removeItem( itemKey ); - } -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/MultistepCheckoutHelper.js b/modules/ppcp-settings/resources/js/utils/Helper/MultistepCheckoutHelper.js deleted file mode 100644 index 1e71d6bb7..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/MultistepCheckoutHelper.js +++ /dev/null @@ -1,123 +0,0 @@ -import { refreshButtons } from './ButtonRefreshHelper'; - -const DEFAULT_TRIGGER_ELEMENT_SELECTOR = '.woocommerce-checkout-payment'; - -/** - * The MultistepCheckoutHelper class ensures the initialization of payment buttons - * on websites using a multistep checkout plugin. These plugins usually hide the - * payment button on page load up and reveal it later using JS. During the - * invisibility period of wrappers, some payment buttons fail to initialize, - * so we wait for the payment element to be visible. - * - * @property {HTMLElement} form - Checkout form element. - * @property {HTMLElement} triggerElement - Element, which visibility we need to detect. - * @property {boolean} isVisible - Whether the triggerElement is visible. - */ -class MultistepCheckoutHelper { - /** - * Selector that defines the HTML element we are waiting to become visible. - * @type {string} - */ - #triggerElementSelector; - - /** - * Interval (in milliseconds) in which the visibility of the trigger element is checked. - * @type {number} - */ - #intervalTime = 150; - - /** - * The interval ID returned by the setInterval() method. - * @type {number|false} - */ - #intervalId; - - /** - * Selector passed to the constructor that identifies the checkout form - * @type {string} - */ - #formSelector; - - /** - * @param {string} formSelector - Selector of the checkout form - * @param {string} triggerElementSelector - Optional. Selector of the dependant element. - */ - constructor( formSelector, triggerElementSelector = '' ) { - this.#formSelector = formSelector; - this.#triggerElementSelector = - triggerElementSelector || DEFAULT_TRIGGER_ELEMENT_SELECTOR; - this.#intervalId = false; - - /* - Start the visibility checker after a brief delay. This allows eventual multistep plugins to - dynamically prepare the checkout page, so we can decide whether this helper is needed. - */ - setTimeout( () => { - if ( this.form && ! this.isVisible ) { - this.start(); - } - }, 250 ); - } - - /** - * The checkout form element. - * @return {Element|null} - Form element or null. - */ - get form() { - return document.querySelector( this.#formSelector ); - } - - /** - * The element which must be visible before payment buttons should be initialized. - * @return {Element|null} - Trigger element or null. - */ - get triggerElement() { - return this.form?.querySelector( this.#triggerElementSelector ); - } - - /** - * Checks the visibility of the payment button wrapper. - * @return {boolean} - returns boolean value on the basis of visibility of element. - */ - get isVisible() { - const box = this.triggerElement?.getBoundingClientRect(); - - return !! ( box && box.width && box.height ); - } - - /** - * Starts the observation of the DOM, initiates monitoring the checkout form. - * To ensure multiple calls to start don't create multiple intervals, we first call stop. - */ - start() { - this.stop(); - this.#intervalId = setInterval( - () => this.checkElement(), - this.#intervalTime - ); - } - - /** - * Stops the observation of the checkout form. - * Multiple calls to stop are safe as clearInterval doesn't throw if provided ID doesn't exist. - */ - stop() { - if ( this.#intervalId ) { - clearInterval( this.#intervalId ); - this.#intervalId = false; - } - } - - /** - * Checks if the trigger element is visible. - * If visible, it initialises the payment buttons and stops the observation. - */ - checkElement() { - if ( this.isVisible ) { - refreshButtons(); - this.stop(); - } - } -} - -export default MultistepCheckoutHelper; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/PayPalScriptLoading.js b/modules/ppcp-settings/resources/js/utils/Helper/PayPalScriptLoading.js deleted file mode 100644 index 48134d2bc..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/PayPalScriptLoading.js +++ /dev/null @@ -1,101 +0,0 @@ -import { loadScript } from '@paypal/paypal-js'; -import dataClientIdAttributeHandler from '../DataClientIdAttributeHandler'; -import widgetBuilder from '../Renderer/WidgetBuilder'; -import { processConfig } from './ConfigProcessor'; - -const loadedScripts = new Map(); -const scriptPromises = new Map(); - -const handleDataClientIdAttribute = async ( scriptOptions, config ) => { - if ( - config.data_client_id?.set_attribute && - config.vault_v3_enabled !== true - ) { - return new Promise( ( resolve, reject ) => { - dataClientIdAttributeHandler( - scriptOptions, - config.data_client_id, - ( paypal ) => { - widgetBuilder.setPaypal( paypal ); - resolve( paypal ); - }, - reject - ); - } ); - } - return null; -}; - -export const loadPayPalScript = async ( namespace, config ) => { - if ( ! namespace ) { - throw new Error( 'Namespace is required' ); - } - - if ( loadedScripts.has( namespace ) ) { - console.log( `Script already loaded for namespace: ${ namespace }` ); - return loadedScripts.get( namespace ); - } - - if ( scriptPromises.has( namespace ) ) { - console.log( - `Script loading in progress for namespace: ${ namespace }` - ); - return scriptPromises.get( namespace ); - } - - const scriptOptions = { - ...processConfig( config ), - 'data-namespace': namespace, - }; - - const dataClientIdResult = await handleDataClientIdAttribute( - scriptOptions, - config - ); - if ( dataClientIdResult ) { - return dataClientIdResult; - } - - const scriptPromise = new Promise( ( resolve, reject ) => { - loadScript( scriptOptions ) - .then( ( script ) => { - widgetBuilder.setPaypal( script ); - loadedScripts.set( namespace, script ); - console.log( `Script loaded for namespace: ${ namespace }` ); - resolve( script ); - } ) - .catch( ( error ) => { - console.error( - `Failed to load script for namespace: ${ namespace }`, - error - ); - reject( error ); - } ) - .finally( () => { - scriptPromises.delete( namespace ); - } ); - } ); - - scriptPromises.set( namespace, scriptPromise ); - return scriptPromise; -}; - -export const loadAndRenderPayPalScript = async ( - namespace, - options, - renderFunction, - renderTarget -) => { - if ( ! namespace ) { - throw new Error( 'Namespace is required' ); - } - - const scriptOptions = { - ...options, - 'data-namespace': namespace, - }; - - const script = await loadScript( scriptOptions ); - widgetBuilder.setPaypal( script ); - await renderFunction( script, renderTarget ); -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/PayerData.js b/modules/ppcp-settings/resources/js/utils/Helper/PayerData.js deleted file mode 100644 index 5695facb0..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/PayerData.js +++ /dev/null @@ -1,196 +0,0 @@ -/** - * Name details. - * - * @typedef {Object} NameDetails - * @property {string} [given_name] - First name, e.g. "John". - * @property {string} [surname] - Last name, e.g. "Doe". - */ - -/** - * Postal address details. - * - * @typedef {Object} AddressDetails - * @property {string} [country_code] - Country code (2-letter). - * @property {string} [address_line_1] - Address details, line 1 (street, house number). - * @property {string} [address_line_2] - Address details, line 2. - * @property {string} [admin_area_1] - State or region. - * @property {string} [admin_area_2] - State or region. - * @property {string} [postal_code] - Zip code. - */ - -/** - * Phone details. - * - * @typedef {Object} PhoneDetails - * @property {string} [phone_type] - Type, usually 'HOME' - * @property {{national_number: string}} [phone_number] - Phone number details. - */ - -/** - * Payer details. - * - * @typedef {Object} PayerDetails - * @property {string} [email_address] - Email address for billing communication. - * @property {PhoneDetails} [phone] - Phone number for billing communication. - * @property {NameDetails} [name] - Payer's name. - * @property {AddressDetails} [address] - Postal billing address. - */ - -// Map checkout fields to PayerData object properties. -const FIELD_MAP = { - '#billing_email': [ 'email_address' ], - '#billing_last_name': [ 'name', 'surname' ], - '#billing_first_name': [ 'name', 'given_name' ], - '#billing_country': [ 'address', 'country_code' ], - '#billing_address_1': [ 'address', 'address_line_1' ], - '#billing_address_2': [ 'address', 'address_line_2' ], - '#billing_state': [ 'address', 'admin_area_1' ], - '#billing_city': [ 'address', 'admin_area_2' ], - '#billing_postcode': [ 'address', 'postal_code' ], - '#billing_phone': [ 'phone' ], -}; - -function normalizePayerDetails( details ) { - return { - email_address: details.email_address, - phone: details.phone, - name: { - surname: details.name?.surname, - given_name: details.name?.given_name, - }, - address: { - country_code: details.address?.country_code, - address_line_1: details.address?.address_line_1, - address_line_2: details.address?.address_line_2, - admin_area_1: details.address?.admin_area_1, - admin_area_2: details.address?.admin_area_2, - postal_code: details.address?.postal_code, - }, - }; -} - -function mergePayerDetails( firstPayer, secondPayer ) { - const mergeNestedObjects = ( target, source ) => { - for ( const [ key, value ] of Object.entries( source ) ) { - if ( null !== value && undefined !== value ) { - if ( 'object' === typeof value ) { - target[ key ] = mergeNestedObjects( - target[ key ] || {}, - value - ); - } else { - target[ key ] = value; - } - } - } - return target; - }; - - return mergeNestedObjects( - normalizePayerDetails( firstPayer ), - normalizePayerDetails( secondPayer ) - ); -} - -function getCheckoutBillingDetails() { - const getElementValue = ( selector ) => - document.querySelector( selector )?.value; - - const setNestedValue = ( obj, path, value ) => { - let current = obj; - for ( let i = 0; i < path.length - 1; i++ ) { - current = current[ path[ i ] ] = current[ path[ i ] ] || {}; - } - current[ path[ path.length - 1 ] ] = value; - }; - - const data = {}; - - Object.entries( FIELD_MAP ).forEach( ( [ selector, path ] ) => { - const value = getElementValue( selector ); - if ( value ) { - setNestedValue( data, path, value ); - } - } ); - - if ( data.phone && 'string' === typeof data.phone ) { - data.phone = { - phone_type: 'HOME', - phone_number: { national_number: data.phone }, - }; - } - - return data; -} - -function setCheckoutBillingDetails( payer ) { - const setValue = ( path, field, value ) => { - if ( null === value || undefined === value || ! field ) { - return; - } - - if ( 'phone' === path[ 0 ] && 'object' === typeof value ) { - value = value.phone_number?.national_number; - } - - field.value = value; - }; - - const getNestedValue = ( obj, path ) => - path.reduce( ( current, key ) => current?.[ key ], obj ); - - Object.entries( FIELD_MAP ).forEach( ( [ selector, path ] ) => { - const value = getNestedValue( payer, path ); - const element = document.querySelector( selector ); - - setValue( path, element, value ); - } ); -} - -export function getWooCommerceCustomerDetails() { - // Populated on server-side with details about the current WooCommerce customer. - return window?.PayPalCommerceGateway?.payer; -} - -export function getSessionBillingDetails() { - // Populated by JS via `setSessionBillingDetails()` - return window._PpcpPayerSessionDetails; -} - -/** - * Stores customer details in the current JS context for use in the same request. - * Details that are set are not persisted during navigation. - * - * @param {unknown} details - New payer details - */ -export function setSessionBillingDetails( details ) { - if ( ! details || 'object' !== typeof details ) { - return; - } - - window._PpcpPayerSessionDetails = normalizePayerDetails( details ); -} - -export function payerData() { - const payer = getWooCommerceCustomerDetails() ?? getSessionBillingDetails(); - - if ( ! payer ) { - return null; - } - - const formData = getCheckoutBillingDetails(); - - if ( formData ) { - return mergePayerDetails( payer, formData ); - } - - return normalizePayerDetails( payer ); -} - -export function setPayerData( payerDetails, updateCheckoutForm = false ) { - setSessionBillingDetails( payerDetails ); - - if ( updateCheckoutForm ) { - setCheckoutBillingDetails( payerDetails ); - } -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/PaymentButtonHelpers.js b/modules/ppcp-settings/resources/js/utils/Helper/PaymentButtonHelpers.js deleted file mode 100644 index f9a066a23..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/PaymentButtonHelpers.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * Helper function used by PaymentButton instances. - * - * @file - */ - -/** - * Collection of recognized event names for payment button events. - * - * @type {Object} - */ -export const ButtonEvents = Object.freeze( { - INVALIDATE: 'ppcp_invalidate_methods', - RENDER: 'ppcp_render_method', - REDRAW: 'ppcp_redraw_method', -} ); - -/** - * - * @param {string} defaultId - Default wrapper ID. - * @param {string} miniCartId - Wrapper inside the mini-cart. - * @param {string} smartButtonId - ID of the smart button wrapper. - * @param {string} blockId - Block wrapper ID (express checkout, block cart). - * @param {string} gatewayId - Gateway wrapper ID (classic checkout). - * @return {{MiniCart, Gateway, Block, SmartButton, Default}} List of all wrapper IDs, by context. - */ -export function combineWrapperIds( - defaultId = '', - miniCartId = '', - smartButtonId = '', - blockId = '', - gatewayId = '' -) { - const sanitize = ( id ) => id.replace( /^#/, '' ); - - return { - Default: sanitize( defaultId ), - SmartButton: sanitize( smartButtonId ), - Block: sanitize( blockId ), - Gateway: sanitize( gatewayId ), - MiniCart: sanitize( miniCartId ), - }; -} - -/** - * Returns full payment button styles by combining the global ppcpConfig with - * payment-method-specific styling provided via buttonConfig. - * - * @param {Object} ppcpConfig - Global plugin configuration. - * @param {Object} buttonConfig - Payment method specific configuration. - * @return {{MiniCart: (*), Default: (*)}} Combined styles, separated by context. - */ -export function combineStyles( ppcpConfig, buttonConfig ) { - return { - Default: { - ...ppcpConfig.style, - ...buttonConfig.style, - }, - MiniCart: { - ...ppcpConfig.mini_cart_style, - ...buttonConfig.mini_cart_style, - }, - }; -} - -/** - * Verifies if the given event name is a valid Payment Button event. - * - * @param {string} event - The event name to verify. - * @return {boolean} True, if the event name is valid. - */ -export function isValidButtonEvent( event ) { - const buttonEventValues = Object.values( ButtonEvents ); - - return buttonEventValues.includes( event ); -} - -/** - * Dispatches a payment button event. - * - * @param {Object} options - The options for dispatching the event. - * @param {string} options.event - Event to dispatch. - * @param {string} [options.paymentMethod] - Optional. Name of payment method, to target a specific button only. - * @throws {Error} Throws an error if the event is invalid. - */ -export function dispatchButtonEvent( { event, paymentMethod = '' } ) { - if ( ! isValidButtonEvent( event ) ) { - throw new Error( `Invalid event: ${ event }` ); - } - - const fullEventName = paymentMethod - ? `${ event }-${ paymentMethod }` - : event; - - document.body.dispatchEvent( new Event( fullEventName ) ); -} - -/** - * Adds an event listener for the provided button event. - * - * @param {Object} options - The options for the event listener. - * @param {string} options.event - Event to observe. - * @param {string} [options.paymentMethod] - The payment method name (optional). - * @param {Function} options.callback - The callback function to execute when the event is triggered. - * @throws {Error} Throws an error if the event is invalid. - */ -export function observeButtonEvent( { event, paymentMethod = '', callback } ) { - if ( ! isValidButtonEvent( event ) ) { - throw new Error( `Invalid event: ${ event }` ); - } - - const fullEventName = paymentMethod - ? `${ event }-${ paymentMethod }` - : event; - - document.body.addEventListener( fullEventName, callback ); -} diff --git a/modules/ppcp-settings/resources/js/utils/Helper/ScriptLoading.js b/modules/ppcp-settings/resources/js/utils/Helper/ScriptLoading.js deleted file mode 100644 index 00ae98a9c..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/ScriptLoading.js +++ /dev/null @@ -1,128 +0,0 @@ -import dataClientIdAttributeHandler from '../DataClientIdAttributeHandler'; -import { loadScript } from '@paypal/paypal-js'; -import widgetBuilder from '../Renderer/WidgetBuilder'; -import merge from 'deepmerge'; -import { keysToCamelCase } from './Utils'; -import { getCurrentPaymentMethod } from './CheckoutMethodState'; -import { v4 as uuidv4 } from 'uuid'; - -// This component may be used by multiple modules. This assures that options are shared between all instances. -const scriptOptionsMap = {}; - -const getNamespaceOptions = ( namespace ) => { - if ( ! scriptOptionsMap[ namespace ] ) { - scriptOptionsMap[ namespace ] = { - isLoading: false, - onLoadedCallbacks: [], - onErrorCallbacks: [], - }; - } - return scriptOptionsMap[ namespace ]; -}; - -export const loadPaypalScript = ( config, onLoaded, onError = null ) => { - const dataNamespace = config?.data_namespace || ''; - const options = getNamespaceOptions( dataNamespace ); - - // If PayPal is already loaded for this namespace, call the onLoaded callback and return. - if ( typeof window.paypal !== 'undefined' && ! dataNamespace ) { - onLoaded(); - return; - } - - // Add the onLoaded callback to the onLoadedCallbacks stack. - options.onLoadedCallbacks.push( onLoaded ); - if ( onError ) { - options.onErrorCallbacks.push( onError ); - } - - // Return if it's still loading. - if ( options.isLoading ) { - return; - } - options.isLoading = true; - - const resetState = () => { - options.isLoading = false; - options.onLoadedCallbacks = []; - options.onErrorCallbacks = []; - }; - - // Callback to be called once the PayPal script is loaded. - const callback = ( paypal ) => { - widgetBuilder.setPaypal( paypal ); - - for ( const onLoadedCallback of options.onLoadedCallbacks ) { - onLoadedCallback(); - } - - resetState(); - }; - const errorCallback = ( err ) => { - for ( const onErrorCallback of options.onErrorCallbacks ) { - onErrorCallback( err ); - } - - resetState(); - }; - - // Build the PayPal script options. - let scriptOptions = keysToCamelCase( config.url_params ); - if ( config.script_attributes ) { - scriptOptions = merge( scriptOptions, config.script_attributes ); - } - - // Axo SDK options - const sdkClientToken = config?.axo?.sdk_client_token; - const uuid = uuidv4().replace( /-/g, '' ); - if ( sdkClientToken && config?.user?.is_logged !== true ) { - scriptOptions[ 'data-sdk-client-token' ] = sdkClientToken; - scriptOptions[ 'data-client-metadata-id' ] = uuid; - } - - // Load PayPal script for special case with data-client-token - if ( - config.data_client_id?.set_attribute && - config.vault_v3_enabled !== '1' - ) { - dataClientIdAttributeHandler( - scriptOptions, - config.data_client_id, - callback, - errorCallback - ); - return; - } - - // Adds data-user-id-token to script options. - const userIdToken = config?.save_payment_methods?.id_token; - if ( userIdToken && config?.user?.is_logged === true ) { - scriptOptions[ 'data-user-id-token' ] = userIdToken; - } - - // Adds data-namespace to script options. - if ( dataNamespace ) { - scriptOptions.dataNamespace = dataNamespace; - } - - // Load PayPal script - loadScript( scriptOptions ).then( callback ).catch( errorCallback ); -}; - -export const loadPaypalScriptPromise = ( config ) => { - return new Promise( ( resolve, reject ) => { - loadPaypalScript( config, resolve, reject ); - } ); -}; - -export const loadPaypalJsScript = ( options, buttons, container ) => { - loadScript( options ).then( ( paypal ) => { - paypal.Buttons( buttons ).render( container ); - } ); -}; - -export const loadPaypalJsScriptPromise = ( options ) => { - return new Promise( ( resolve, reject ) => { - loadScript( options ).then( resolve ).catch( reject ); - } ); -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/ShippingHandler.js b/modules/ppcp-settings/resources/js/utils/Helper/ShippingHandler.js deleted file mode 100644 index ae86ddea0..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/ShippingHandler.js +++ /dev/null @@ -1,151 +0,0 @@ -import { paypalAddressToWc } from '../../../../../ppcp-blocks/resources/js/Helper/Address.js'; -import { convertKeysToSnakeCase } from '../../../../../ppcp-blocks/resources/js/Helper/Helper.js'; - -/** - * Handles the shipping option change in PayPal. - * - * @param data - * @param actions - * @param config - * @return {Promise} - */ -export const handleShippingOptionsChange = async ( data, actions, config ) => { - try { - const shippingOptionId = data.selectedShippingOption?.id; - - if ( shippingOptionId ) { - await fetch( - config.ajax.update_customer_shipping.shipping_options.endpoint, - { - method: 'POST', - credentials: 'same-origin', - headers: { - 'Content-Type': 'application/json', - 'X-WC-Store-API-Nonce': - config.ajax.update_customer_shipping.wp_rest_nonce, - }, - body: JSON.stringify( { - rate_id: shippingOptionId, - } ), - } - ) - .then( ( response ) => { - return response.json(); - } ) - .then( ( cardData ) => { - const shippingMethods = - document.querySelectorAll( '.shipping_method' ); - - shippingMethods.forEach( function ( method ) { - if ( method.value === shippingOptionId ) { - method.checked = true; - } - } ); - } ); - } - - if ( ! config.data_client_id.has_subscriptions ) { - const res = await fetch( config.ajax.update_shipping.endpoint, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify( { - nonce: config.ajax.update_shipping.nonce, - order_id: data.orderID, - } ), - } ); - - const json = await res.json(); - - if ( ! json.success ) { - throw new Error( json.data.message ); - } - } - } catch ( e ) { - console.error( e ); - - actions.reject(); - } -}; - -/** - * Handles the shipping address change in PayPal. - * - * @param data - * @param actions - * @param config - * @return {Promise} - */ -export const handleShippingAddressChange = async ( data, actions, config ) => { - try { - const address = paypalAddressToWc( - convertKeysToSnakeCase( data.shippingAddress ) - ); - - // Retrieve current cart contents - await fetch( - config.ajax.update_customer_shipping.shipping_address.cart_endpoint - ) - .then( ( response ) => { - return response.json(); - } ) - .then( ( cartData ) => { - // Update shipping address in the cart data - cartData.shipping_address.address_1 = address.address_1; - cartData.shipping_address.address_2 = address.address_2; - cartData.shipping_address.city = address.city; - cartData.shipping_address.state = address.state; - cartData.shipping_address.postcode = address.postcode; - cartData.shipping_address.country = address.country; - - // Send update request - return fetch( - config.ajax.update_customer_shipping.shipping_address - .update_customer_endpoint, - { - method: 'POST', - credentials: 'same-origin', - headers: { - 'Content-Type': 'application/json', - 'X-WC-Store-API-Nonce': - config.ajax.update_customer_shipping - .wp_rest_nonce, - }, - body: JSON.stringify( { - shipping_address: cartData.shipping_address, - } ), - } - ) - .then( function ( res ) { - return res.json(); - } ) - .then( function ( customerData ) { - jQuery( '.cart_totals .shop_table' ).load( - location.href + - ' ' + - '.cart_totals .shop_table' + - '>*', - '' - ); - } ); - } ); - - const res = await fetch( config.ajax.update_shipping.endpoint, { - method: 'POST', - credentials: 'same-origin', - body: JSON.stringify( { - nonce: config.ajax.update_shipping.nonce, - order_id: data.orderID, - } ), - } ); - - const json = await res.json(); - - if ( ! json.success ) { - throw new Error( json.data.message ); - } - } catch ( e ) { - console.error( e ); - - actions.reject(); - } -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/SimulateCart.js b/modules/ppcp-settings/resources/js/utils/Helper/SimulateCart.js deleted file mode 100644 index 4dd67be76..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/SimulateCart.js +++ /dev/null @@ -1,42 +0,0 @@ -class SimulateCart { - constructor( endpoint, nonce ) { - this.endpoint = endpoint; - this.nonce = nonce; - } - - /** - * - * @param onResolve - * @param {Product[]} products - * @return {Promise} - */ - simulate( onResolve, products ) { - return new Promise( ( resolve, reject ) => { - fetch( this.endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'same-origin', - body: JSON.stringify( { - nonce: this.nonce, - products, - } ), - } ) - .then( ( result ) => { - return result.json(); - } ) - .then( ( result ) => { - if ( ! result.success ) { - reject( result.data ); - return; - } - - const resolved = onResolve( result.data ); - resolve( resolved ); - } ); - } ); - } -} - -export default SimulateCart; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/Spinner.js b/modules/ppcp-settings/resources/js/utils/Helper/Spinner.js deleted file mode 100644 index 30d0830f9..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/Spinner.js +++ /dev/null @@ -1,25 +0,0 @@ -class Spinner { - constructor( target = 'form.woocommerce-checkout' ) { - this.target = target; - } - - setTarget( target ) { - this.target = target; - } - - block() { - jQuery( this.target ).block( { - message: null, - overlayCSS: { - background: '#fff', - opacity: 0.6, - }, - } ); - } - - unblock() { - jQuery( this.target ).unblock(); - } -} - -export default Spinner; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/Style.js b/modules/ppcp-settings/resources/js/utils/Helper/Style.js deleted file mode 100644 index 3f3f64e04..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/Style.js +++ /dev/null @@ -1,20 +0,0 @@ -export const normalizeStyleForFundingSource = ( style, fundingSource ) => { - const commonProps = {}; - [ 'shape', 'height' ].forEach( ( prop ) => { - if ( style[ prop ] ) { - commonProps[ prop ] = style[ prop ]; - } - } ); - - switch ( fundingSource ) { - case 'paypal': - return style; - case 'paylater': - return { - color: style.color, - ...commonProps, - }; - default: - return commonProps; - } -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/Subscriptions.js b/modules/ppcp-settings/resources/js/utils/Helper/Subscriptions.js deleted file mode 100644 index e4bf0f389..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/Subscriptions.js +++ /dev/null @@ -1,28 +0,0 @@ -export const isChangePaymentPage = () => { - const urlParams = new URLSearchParams( window.location.search ); - return urlParams.has( 'change_payment_method' ); -}; - -export const getPlanIdFromVariation = ( variation ) => { - let subscription_plan = ''; - PayPalCommerceGateway.variable_paypal_subscription_variations.forEach( - ( element ) => { - const obj = {}; - variation.forEach( ( { name, value } ) => { - Object.assign( obj, { - [ name.replace( 'attribute_', '' ) ]: value, - } ); - } ); - - if ( - JSON.stringify( obj ) === - JSON.stringify( element.attributes ) && - element.subscription_plan !== '' - ) { - subscription_plan = element.subscription_plan; - } - } - ); - - return subscription_plan; -}; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/UpdateCart.js b/modules/ppcp-settings/resources/js/utils/Helper/UpdateCart.js deleted file mode 100644 index 454eacfc6..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/UpdateCart.js +++ /dev/null @@ -1,45 +0,0 @@ -import Product from '../Entity/Product'; -class UpdateCart { - constructor( endpoint, nonce ) { - this.endpoint = endpoint; - this.nonce = nonce; - } - - /** - * - * @param onResolve - * @param {Product[]} products - * @param {Object} options - * @return {Promise} - */ - update( onResolve, products, options = {} ) { - return new Promise( ( resolve, reject ) => { - fetch( this.endpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - credentials: 'same-origin', - body: JSON.stringify( { - nonce: this.nonce, - products, - ...options, - } ), - } ) - .then( ( result ) => { - return result.json(); - } ) - .then( ( result ) => { - if ( ! result.success ) { - reject( result.data ); - return; - } - - const resolved = onResolve( result.data ); - resolve( resolved ); - } ); - } ); - } -} - -export default UpdateCart; diff --git a/modules/ppcp-settings/resources/js/utils/Helper/Utils.js b/modules/ppcp-settings/resources/js/utils/Helper/Utils.js deleted file mode 100644 index cf4121ead..000000000 --- a/modules/ppcp-settings/resources/js/utils/Helper/Utils.js +++ /dev/null @@ -1,69 +0,0 @@ -export const toCamelCase = ( str ) => { - return str.replace( /([-_]\w)/g, function ( match ) { - return match[ 1 ].toUpperCase(); - } ); -}; - -export const keysToCamelCase = ( obj ) => { - const output = {}; - for ( const key in obj ) { - if ( Object.prototype.hasOwnProperty.call( obj, key ) ) { - output[ toCamelCase( key ) ] = obj[ key ]; - } - } - return output; -}; - -export const strAddWord = ( str, word, separator = ',' ) => { - const arr = str.split( separator ); - if ( ! arr.includes( word ) ) { - arr.push( word ); - } - return arr.join( separator ); -}; - -export const strRemoveWord = ( str, word, separator = ',' ) => { - const arr = str.split( separator ); - const index = arr.indexOf( word ); - if ( index !== -1 ) { - arr.splice( index, 1 ); - } - return arr.join( separator ); -}; - -export const throttle = ( func, limit ) => { - let inThrottle, lastArgs, lastContext; - - function execute() { - inThrottle = true; - func.apply( this, arguments ); - setTimeout( () => { - inThrottle = false; - if ( lastArgs ) { - const nextArgs = lastArgs; - const nextContext = lastContext; - lastArgs = lastContext = null; - execute.apply( nextContext, nextArgs ); - } - }, limit ); - } - - return function () { - if ( ! inThrottle ) { - execute.apply( this, arguments ); - } else { - lastArgs = arguments; - lastContext = this; - } - }; -}; - -const Utils = { - toCamelCase, - keysToCamelCase, - strAddWord, - strRemoveWord, - throttle, -}; - -export default Utils; diff --git a/modules/ppcp-settings/resources/js/utils/renderer.js b/modules/ppcp-settings/resources/js/utils/renderer.js deleted file mode 100644 index b7a80f687..000000000 --- a/modules/ppcp-settings/resources/js/utils/renderer.js +++ /dev/null @@ -1,264 +0,0 @@ -import merge from 'deepmerge'; -import { loadScript } from '@paypal/paypal-js'; -import { keysToCamelCase } from './Helper/Utils'; -import widgetBuilder from './widget-builder'; -import { normalizeStyleForFundingSource } from './Helper/Style'; - -class Renderer { - constructor( - creditCardRenderer, - defaultSettings, - onSmartButtonClick, - onSmartButtonsInit - ) { - this.defaultSettings = defaultSettings; - this.creditCardRenderer = creditCardRenderer; - this.onSmartButtonClick = onSmartButtonClick; - this.onSmartButtonsInit = onSmartButtonsInit; - - this.buttonsOptions = {}; - this.onButtonsInitListeners = {}; - - this.renderedSources = new Set(); - - this.reloadEventName = 'ppcp-reload-buttons'; - } - - render( - contextConfig, - settingsOverride = {}, - contextConfigOverride = () => {} - ) { - const settings = merge( this.defaultSettings, settingsOverride ); - const enabledSeparateGateways = Object.fromEntries( - Object.entries( settings.separate_buttons ).filter( - ( [ s, data ] ) => document.querySelector( data.wrapper ) - ) - ); - const hasEnabledSeparateGateways = - Object.keys( enabledSeparateGateways ).length !== 0; - - if ( ! hasEnabledSeparateGateways ) { - console.log( 'RENDER 1', settings ); - this.renderButtons( - settings.button.wrapper, - settings.button.style, - contextConfig, - hasEnabledSeparateGateways - ); - } else { - // render each button separately - for ( const fundingSource of paypal - .getFundingSources() - .filter( ( s ) => ! ( s in enabledSeparateGateways ) ) ) { - const style = normalizeStyleForFundingSource( - settings.button.style, - fundingSource - ); - console.log( 'RENDER' ); - this.renderButtons( - settings.button.wrapper, - style, - contextConfig, - hasEnabledSeparateGateways, - fundingSource - ); - } - } - - if ( this.creditCardRenderer ) { - this.creditCardRenderer.render( - settings.hosted_fields.wrapper, - contextConfigOverride - ); - } - - for ( const [ fundingSource, data ] of Object.entries( - enabledSeparateGateways - ) ) { - this.renderButtons( - data.wrapper, - data.style, - contextConfig, - hasEnabledSeparateGateways, - fundingSource - ); - } - } - - renderButtons( - wrapper, - style, - contextConfig, - hasEnabledSeparateGateways, - fundingSource = null - ) { - if ( - ! document.querySelector( wrapper ) || - this.isAlreadyRendered( - wrapper, - fundingSource, - hasEnabledSeparateGateways - ) - ) { - // Try to render registered buttons again in case they were removed from the DOM by an external source. - widgetBuilder.renderButtons( [ wrapper, fundingSource ] ); - return; - } - - if ( fundingSource ) { - contextConfig.fundingSource = fundingSource; - } - - let venmoButtonClicked = false; - - const buttonsOptions = () => { - const options = { - style, - ...contextConfig, - onClick: ( data, actions ) => { - if ( this.onSmartButtonClick ) { - this.onSmartButtonClick( data, actions ); - } - - venmoButtonClicked = false; - if ( data.fundingSource === 'venmo' ) { - venmoButtonClicked = true; - } - }, - onInit: ( data, actions ) => { - if ( this.onSmartButtonsInit ) { - this.onSmartButtonsInit( data, actions ); - } - this.handleOnButtonsInit( wrapper, data, actions ); - }, - }; - - return options; - }; - - jQuery( document ) - .off( this.reloadEventName, wrapper ) - .on( - this.reloadEventName, - wrapper, - ( event, settingsOverride = {}, triggeredFundingSource ) => { - // Only accept events from the matching funding source - if ( - fundingSource && - triggeredFundingSource && - triggeredFundingSource !== fundingSource - ) { - return; - } - - const settings = merge( - this.defaultSettings, - settingsOverride - ); - let scriptOptions = keysToCamelCase( settings.url_params ); - scriptOptions = merge( - scriptOptions, - settings.script_attributes - ); - - loadScript( scriptOptions ).then( ( paypal ) => { - widgetBuilder.setPaypal( paypal ); - widgetBuilder.registerButtons( - [ wrapper, fundingSource ], - buttonsOptions() - ); - widgetBuilder.renderAll(); - } ); - } - ); - - this.renderedSources.add( wrapper + ( fundingSource ?? '' ) ); - - if ( - typeof paypal !== 'undefined' && - typeof paypal.Buttons !== 'undefined' - ) { - widgetBuilder.registerButtons( - [ wrapper, fundingSource ], - buttonsOptions() - ); - widgetBuilder.renderButtons( [ wrapper, fundingSource ] ); - } - } - - isVenmoButtonClickedWhenVaultingIsEnabled = ( venmoButtonClicked ) => { - return venmoButtonClicked && this.defaultSettings.vaultingEnabled; - }; - - shouldEnableShippingCallback = () => { - const needShipping = - this.defaultSettings.needShipping || - this.defaultSettings.context === 'product'; - return ( - this.defaultSettings.should_handle_shipping_in_paypal && - needShipping - ); - }; - - isAlreadyRendered( wrapper, fundingSource ) { - return this.renderedSources.has( wrapper + ( fundingSource ?? '' ) ); - } - - disableCreditCardFields() { - this.creditCardRenderer.disableFields(); - } - - enableCreditCardFields() { - this.creditCardRenderer.enableFields(); - } - - onButtonsInit( wrapper, handler, reset ) { - this.onButtonsInitListeners[ wrapper ] = reset - ? [] - : this.onButtonsInitListeners[ wrapper ] || []; - this.onButtonsInitListeners[ wrapper ].push( handler ); - } - - handleOnButtonsInit( wrapper, data, actions ) { - this.buttonsOptions[ wrapper ] = { - data, - actions, - }; - - if ( this.onButtonsInitListeners[ wrapper ] ) { - for ( const handler of this.onButtonsInitListeners[ wrapper ] ) { - if ( typeof handler === 'function' ) { - handler( { - wrapper, - ...this.buttonsOptions[ wrapper ], - } ); - } - } - } - } - - disableSmartButtons( wrapper ) { - if ( ! this.buttonsOptions[ wrapper ] ) { - return; - } - try { - this.buttonsOptions[ wrapper ].actions.disable(); - } catch ( err ) { - console.log( 'Failed to disable buttons: ' + err ); - } - } - - enableSmartButtons( wrapper ) { - if ( ! this.buttonsOptions[ wrapper ] ) { - return; - } - try { - this.buttonsOptions[ wrapper ].actions.enable(); - } catch ( err ) { - console.log( 'Failed to enable buttons: ' + err ); - } - } -} - -export default Renderer; diff --git a/modules/ppcp-settings/resources/js/utils/widget-builder.js b/modules/ppcp-settings/resources/js/utils/widget-builder.js deleted file mode 100644 index 9481cc029..000000000 --- a/modules/ppcp-settings/resources/js/utils/widget-builder.js +++ /dev/null @@ -1,179 +0,0 @@ -/** - * Handles the registration and rendering of PayPal widgets: Buttons and Messages. - * To have several Buttons per wrapper, an array should be provided, ex: [wrapper, fundingSource]. - */ -class WidgetBuilder { - constructor() { - this.paypal = null; - this.buttons = new Map(); - this.messages = new Map(); - - this.renderEventName = 'ppcp-render'; - - document.ppcpWidgetBuilderStatus = () => { - console.log( { - buttons: this.buttons, - messages: this.messages, - } ); - }; - - jQuery( document ) - .off( this.renderEventName ) - .on( this.renderEventName, () => { - this.renderAll(); - } ); - } - - setPaypal( paypal ) { - this.paypal = paypal; - jQuery( document ).trigger( 'ppcp-paypal-loaded', paypal ); - } - - registerButtons( wrapper, options ) { - wrapper = this.sanitizeWrapper( wrapper ); - - this.buttons.set( this.toKey( wrapper ), { - wrapper, - options, - } ); - } - - renderButtons( wrapper ) { - wrapper = this.sanitizeWrapper( wrapper ); - - if ( ! this.buttons.has( this.toKey( wrapper ) ) ) { - return; - } - - if ( this.hasRendered( wrapper ) ) { - return; - } - - const entry = this.buttons.get( this.toKey( wrapper ) ); - const btn = this.paypal.Buttons( entry.options ); - - if ( ! btn.isEligible() ) { - this.buttons.delete( this.toKey( wrapper ) ); - return; - } - - const target = this.buildWrapperTarget( wrapper ); - - if ( ! target ) { - return; - } - - btn.render( target ); - } - - renderAllButtons() { - for ( const [ wrapper, entry ] of this.buttons ) { - this.renderButtons( wrapper ); - } - } - - registerMessages( wrapper, options ) { - this.messages.set( wrapper, { - wrapper, - options, - } ); - } - - renderMessages( wrapper ) { - if ( ! this.messages.has( wrapper ) ) { - return; - } - - const entry = this.messages.get( wrapper ); - - if ( this.hasRendered( wrapper ) ) { - const element = document.querySelector( wrapper ); - element.setAttribute( 'data-pp-amount', entry.options.amount ); - return; - } - - const btn = this.paypal.Messages( entry.options ); - - btn.render( entry.wrapper ); - - // watchdog to try to handle some strange cases where the wrapper may not be present - setTimeout( () => { - if ( ! this.hasRendered( wrapper ) ) { - btn.render( entry.wrapper ); - } - }, 100 ); - } - - renderAllMessages() { - for ( const [ wrapper, entry ] of this.messages ) { - this.renderMessages( wrapper ); - } - } - - renderAll() { - this.renderAllButtons(); - this.renderAllMessages(); - } - - hasRendered( wrapper ) { - let selector = wrapper; - - if ( Array.isArray( wrapper ) ) { - selector = wrapper[ 0 ]; - for ( const item of wrapper.slice( 1 ) ) { - selector += ' .item-' + item; - } - } - - const element = document.querySelector( selector ); - return element && element.hasChildNodes(); - } - - sanitizeWrapper( wrapper ) { - if ( Array.isArray( wrapper ) ) { - wrapper = wrapper.filter( ( item ) => !! item ); - if ( wrapper.length === 1 ) { - wrapper = wrapper[ 0 ]; - } - } - return wrapper; - } - - buildWrapperTarget( wrapper ) { - let target = wrapper; - - if ( Array.isArray( wrapper ) ) { - const $wrapper = jQuery( wrapper[ 0 ] ); - - if ( ! $wrapper.length ) { - return; - } - - const itemClass = 'item-' + wrapper[ 1 ]; - - // Check if the parent element exists and it doesn't already have the div with the class - let $item = $wrapper.find( '.' + itemClass ); - - if ( ! $item.length ) { - $item = jQuery( `
` ); - $wrapper.append( $item ); - } - - target = $item.get( 0 ); - } - - if ( ! jQuery( target ).length ) { - return null; - } - - return target; - } - - toKey( wrapper ) { - if ( Array.isArray( wrapper ) ) { - return JSON.stringify( wrapper ); - } - return wrapper; - } -} -export default window.widgetBuilder; diff --git a/modules/ppcp-settings/webpack.config.js b/modules/ppcp-settings/webpack.config.js index 70372b646..a3a6d709d 100644 --- a/modules/ppcp-settings/webpack.config.js +++ b/modules/ppcp-settings/webpack.config.js @@ -14,19 +14,5 @@ module.exports = { ), style: path.resolve( process.cwd(), 'resources/css', 'style.scss' ), }, - resolve: { - ...defaultConfig.resolve, - ...{ - alias: { - ...defaultConfig.resolve.alias, - ...{ - ppcpButton: path.resolve( - __dirname, - '../ppcp-button/resources/js' - ), - }, - }, - }, - }, }, }; diff --git a/modules/ppcp-wc-gateway/resources/css/gateway-settings.scss b/modules/ppcp-wc-gateway/resources/css/gateway-settings.scss index 768f95c75..537d035b4 100644 --- a/modules/ppcp-wc-gateway/resources/css/gateway-settings.scss +++ b/modules/ppcp-wc-gateway/resources/css/gateway-settings.scss @@ -8,7 +8,7 @@ } } -.ppcp-preview { +.ppcp-preview:not(.ppcp-r-styling__preview) { width: var(--box-width, 100%); padding: 15px; border: 1px solid lightgray;