mirror of
https://github.com/woocommerce/woocommerce-paypal-payments.git
synced 2025-08-31 04:58:28 +08:00
Run autofix code style
This commit is contained in:
commit
cf8eaba0a3
173 changed files with 14902 additions and 11906 deletions
|
@ -25,6 +25,10 @@ if (!defined('ABSPATH')) {
|
|||
define('ABSPATH', '');
|
||||
}
|
||||
|
||||
if (!defined('PPCP_PAYPAL_BN_CODE')) {
|
||||
define('PPCP_PAYPAL_BN_CODE', 'Woo_PPCP');
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the next occurrence of a scheduled action.
|
||||
*
|
||||
|
|
|
@ -1,5 +1,23 @@
|
|||
*** Changelog ***
|
||||
|
||||
= 2.8.2 - 2024-07-22 =
|
||||
* Fix - Sold individually checkbox automatically disabled after adding product to the cart more than once #2415
|
||||
* Fix - All products "Sold individually" when PayPal Subscriptions selected as Subscriptions Mode #2400
|
||||
* Fix - W3 Total Cache: Remove type from file parameter as sometimes null gets passed causing errors #2403
|
||||
* Fix - Shipping methods during callback not updated correctly #2421
|
||||
* Fix - Preserve subscription renewal processing when switching Subscriptions Mode or disabling gateway #2394
|
||||
* Fix - Remove shipping callback for Venmo express button #2374
|
||||
* Fix - Google Pay: Fix issuse with data.paymentSource being undefined #2390
|
||||
* Fix - Loading of non-Order as a WC_Order causes warnings and potential data corruption #2343
|
||||
* Fix - Apple Pay and Google Pay buttons don't appear in PayPal Button stack on multi-step Checkout #2372
|
||||
* Fix - Apple Pay: Fix when shipping is disabled #2391
|
||||
* Fix - Wrong string in smart button preview on Standard Payments tab #2409
|
||||
* Fix - Don't break orders screen when there is an exception for package tracking #2369
|
||||
* Fix - Pay Later button preview is missing #2371
|
||||
* Fix - Apple Pay button layout #2367
|
||||
* Enhancement - Remove BCDC button from block Express Checkout area #2381
|
||||
* Enhancement - Extend Advanced Card Processing country eligibility for China #2397
|
||||
|
||||
= 2.8.1 - 2024-07-01 =
|
||||
* Fix - Don't render tracking metabox if PayPal order does not belong to connected merchant #2360
|
||||
* Fix - Fatal error when the ppcp-paylater-configurator module is disabled via code snippet #2327
|
||||
|
|
|
@ -723,6 +723,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CN' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CY' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
@ -1416,6 +1440,10 @@ return array(
|
|||
'visa' => array(),
|
||||
'amex' => array(),
|
||||
),
|
||||
'CN' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
),
|
||||
'CY' => array(
|
||||
'mastercard' => array(),
|
||||
'visa' => array(),
|
||||
|
|
|
@ -42,7 +42,7 @@ trait RequestTrait {
|
|||
*/
|
||||
$args = apply_filters( 'ppcp_request_args', $args, $url );
|
||||
if ( ! isset( $args['headers']['PayPal-Partner-Attribution-Id'] ) ) {
|
||||
$args['headers']['PayPal-Partner-Attribution-Id'] = 'Woo_PPCP';
|
||||
$args['headers']['PayPal-Partner-Attribution-Id'] = PPCP_PAYPAL_BN_CODE;
|
||||
}
|
||||
|
||||
$response = wp_remote_get( $url, $args );
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,55 +1,52 @@
|
|||
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
||||
import ApplepayButton from "./ApplepayButton";
|
||||
import buttonModuleWatcher from '../../../ppcp-button/resources/js/modules/ButtonModuleWatcher';
|
||||
import ApplepayButton from './ApplepayButton';
|
||||
|
||||
class ApplepayManager {
|
||||
|
||||
constructor(buttonConfig, ppcpConfig) {
|
||||
|
||||
constructor( buttonConfig, ppcpConfig ) {
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.ApplePayConfig = null;
|
||||
this.buttons = [];
|
||||
|
||||
buttonModuleWatcher.watchContextBootstrap((bootstrap) => {
|
||||
buttonModuleWatcher.watchContextBootstrap( ( bootstrap ) => {
|
||||
const button = new ApplepayButton(
|
||||
bootstrap.context,
|
||||
bootstrap.handler,
|
||||
buttonConfig,
|
||||
ppcpConfig,
|
||||
ppcpConfig
|
||||
);
|
||||
|
||||
this.buttons.push(button);
|
||||
this.buttons.push( button );
|
||||
|
||||
if (this.ApplePayConfig) {
|
||||
button.init(this.ApplePayConfig);
|
||||
if ( this.ApplePayConfig ) {
|
||||
button.init( this.ApplePayConfig );
|
||||
}
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
init() {
|
||||
(async () => {
|
||||
( async () => {
|
||||
await this.config();
|
||||
for (const button of this.buttons) {
|
||||
button.init(this.ApplePayConfig);
|
||||
for ( const button of this.buttons ) {
|
||||
button.init( this.ApplePayConfig );
|
||||
}
|
||||
})();
|
||||
} )();
|
||||
}
|
||||
|
||||
reinit() {
|
||||
for (const button of this.buttons) {
|
||||
for ( const button of this.buttons ) {
|
||||
button.reinit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets ApplePay configuration of the PayPal merchant.
|
||||
* @returns {Promise<null>}
|
||||
* @return {Promise<null>}
|
||||
*/
|
||||
async config() {
|
||||
this.ApplePayConfig = await paypal.Applepay().config();
|
||||
return this.ApplePayConfig;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ApplepayManager;
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import ApplepayButton from "./ApplepayButton";
|
||||
import ApplepayButton from './ApplepayButton';
|
||||
|
||||
class ApplepayManagerBlockEditor {
|
||||
|
||||
constructor(buttonConfig, ppcpConfig) {
|
||||
constructor( buttonConfig, ppcpConfig ) {
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.applePayConfig = null;
|
||||
}
|
||||
|
||||
init() {
|
||||
(async () => {
|
||||
( async () => {
|
||||
await this.config();
|
||||
})();
|
||||
} )();
|
||||
}
|
||||
|
||||
async config() {
|
||||
|
@ -22,13 +21,12 @@ class ApplepayManagerBlockEditor {
|
|||
this.ppcpConfig.context,
|
||||
null,
|
||||
this.buttonConfig,
|
||||
this.ppcpConfig,
|
||||
this.ppcpConfig
|
||||
);
|
||||
|
||||
button.init(this.applePayConfig);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Apple Pay:', error);
|
||||
button.init( this.applePayConfig );
|
||||
} catch ( error ) {
|
||||
console.error( 'Failed to initialize Apple Pay:', error );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import ErrorHandler from "../../../../ppcp-button/resources/js/modules/ErrorHandler";
|
||||
import CartActionHandler
|
||||
from "../../../../ppcp-button/resources/js/modules/ActionHandler/CartActionHandler";
|
||||
import {isPayPalSubscription} from "../../../../ppcp-blocks/resources/js/Helper/Subscription";
|
||||
import ErrorHandler from '../../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
import CartActionHandler from '../../../../ppcp-button/resources/js/modules/ActionHandler/CartActionHandler';
|
||||
import { isPayPalSubscription } from '../../../../ppcp-blocks/resources/js/Helper/Subscription';
|
||||
|
||||
class BaseHandler {
|
||||
|
||||
constructor(buttonConfig, ppcpConfig) {
|
||||
constructor( buttonConfig, ppcpConfig ) {
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
}
|
||||
|
||||
isVaultV3Mode() {
|
||||
return this.ppcpConfig?.save_payment_methods?.id_token // vault v3
|
||||
&& ! this.ppcpConfig?.data_client_id?.paypal_subscriptions_enabled // not PayPal Subscriptions mode
|
||||
&& this.ppcpConfig?.can_save_vault_token; // vault is enabled
|
||||
return (
|
||||
this.ppcpConfig?.save_payment_methods?.id_token && // vault v3
|
||||
! this.ppcpConfig?.data_client_id?.paypal_subscriptions_enabled && // not PayPal Subscriptions mode
|
||||
this.ppcpConfig?.can_save_vault_token
|
||||
); // vault is enabled
|
||||
}
|
||||
|
||||
validateContext() {
|
||||
|
@ -28,68 +28,61 @@ class BaseHandler {
|
|||
}
|
||||
|
||||
transactionInfo() {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
const endpoint = this.ppcpConfig.ajax.cart_script_params.endpoint;
|
||||
const separator = (endpoint.indexOf('?') !== -1) ? '&' : '?';
|
||||
const separator = endpoint.indexOf( '?' ) !== -1 ? '&' : '?';
|
||||
|
||||
fetch(
|
||||
endpoint + separator + 'shipping=1',
|
||||
{
|
||||
fetch( endpoint + separator + 'shipping=1', {
|
||||
method: 'GET',
|
||||
credentials: 'same-origin'
|
||||
}
|
||||
)
|
||||
.then(result => result.json())
|
||||
.then(result => {
|
||||
if (! result.success) {
|
||||
credentials: 'same-origin',
|
||||
} )
|
||||
.then( ( result ) => result.json() )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// handle script reload
|
||||
const data = result.data;
|
||||
|
||||
resolve({
|
||||
resolve( {
|
||||
countryCode: data.country_code,
|
||||
currencyCode: data.currency_code,
|
||||
totalPriceStatus: 'FINAL',
|
||||
totalPrice: data.total_str,
|
||||
chosenShippingMethods: data.chosen_shipping_methods || null,
|
||||
chosenShippingMethods:
|
||||
data.chosen_shipping_methods || null,
|
||||
shippingPackages: data.shipping_packages || null,
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
createOrder() {
|
||||
return this.actionHandler().configuration().createOrder(null, null);
|
||||
return this.actionHandler().configuration().createOrder( null, null );
|
||||
}
|
||||
|
||||
approveOrder(data, actions) {
|
||||
return this.actionHandler().configuration().onApprove(data, actions);
|
||||
approveOrder( data, actions ) {
|
||||
return this.actionHandler().configuration().onApprove( data, actions );
|
||||
}
|
||||
|
||||
actionHandler() {
|
||||
return new CartActionHandler(
|
||||
this.ppcpConfig,
|
||||
this.errorHandler(),
|
||||
return new CartActionHandler( this.ppcpConfig, this.errorHandler() );
|
||||
}
|
||||
|
||||
errorHandler() {
|
||||
return new ErrorHandler(
|
||||
this.ppcpConfig.labels.error.generic,
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
}
|
||||
|
||||
errorHandler() {
|
||||
return new ErrorHandler(
|
||||
this.ppcpConfig.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
}
|
||||
|
||||
errorHandler() {
|
||||
return new ErrorHandler(
|
||||
this.ppcpConfig.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BaseHandler;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class CartBlockHandler extends BaseHandler {
|
||||
|
||||
}
|
||||
class CartBlockHandler extends BaseHandler {}
|
||||
|
||||
export default CartBlockHandler;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class CartHandler extends BaseHandler {
|
||||
|
||||
}
|
||||
class CartHandler extends BaseHandler {}
|
||||
|
||||
export default CartHandler;
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class CheckoutBlockHandler extends BaseHandler{
|
||||
|
||||
}
|
||||
class CheckoutBlockHandler extends BaseHandler {}
|
||||
|
||||
export default CheckoutBlockHandler;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import Spinner from "../../../../ppcp-button/resources/js/modules/Helper/Spinner";
|
||||
import CheckoutActionHandler
|
||||
from "../../../../ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler";
|
||||
import BaseHandler from "./BaseHandler";
|
||||
import Spinner from '../../../../ppcp-button/resources/js/modules/Helper/Spinner';
|
||||
import CheckoutActionHandler from '../../../../ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler';
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class CheckoutHandler extends BaseHandler {
|
||||
|
||||
actionHandler() {
|
||||
return new CheckoutActionHandler(
|
||||
this.ppcpConfig,
|
||||
|
|
|
@ -1,32 +1,31 @@
|
|||
import SingleProductHandler from "./SingleProductHandler";
|
||||
import CartHandler from "./CartHandler";
|
||||
import CheckoutHandler from "./CheckoutHandler";
|
||||
import CartBlockHandler from "./CartBlockHandler";
|
||||
import CheckoutBlockHandler from "./CheckoutBlockHandler";
|
||||
import MiniCartHandler from "./MiniCartHandler";
|
||||
import PreviewHandler from "./PreviewHandler";
|
||||
import PayNowHandler from "./PayNowHandler";
|
||||
import SingleProductHandler from './SingleProductHandler';
|
||||
import CartHandler from './CartHandler';
|
||||
import CheckoutHandler from './CheckoutHandler';
|
||||
import CartBlockHandler from './CartBlockHandler';
|
||||
import CheckoutBlockHandler from './CheckoutBlockHandler';
|
||||
import MiniCartHandler from './MiniCartHandler';
|
||||
import PreviewHandler from './PreviewHandler';
|
||||
import PayNowHandler from './PayNowHandler';
|
||||
|
||||
class ContextHandlerFactory {
|
||||
|
||||
static create(context, buttonConfig, ppcpConfig) {
|
||||
switch (context) {
|
||||
static create( context, buttonConfig, ppcpConfig ) {
|
||||
switch ( context ) {
|
||||
case 'product':
|
||||
return new SingleProductHandler(buttonConfig, ppcpConfig);
|
||||
return new SingleProductHandler( buttonConfig, ppcpConfig );
|
||||
case 'cart':
|
||||
return new CartHandler(buttonConfig, ppcpConfig);
|
||||
return new CartHandler( buttonConfig, ppcpConfig );
|
||||
case 'checkout':
|
||||
return new CheckoutHandler(buttonConfig, ppcpConfig);
|
||||
return new CheckoutHandler( buttonConfig, ppcpConfig );
|
||||
case 'pay-now':
|
||||
return new PayNowHandler(buttonConfig, ppcpConfig);
|
||||
return new PayNowHandler( buttonConfig, ppcpConfig );
|
||||
case 'mini-cart':
|
||||
return new MiniCartHandler(buttonConfig, ppcpConfig);
|
||||
return new MiniCartHandler( buttonConfig, ppcpConfig );
|
||||
case 'cart-block':
|
||||
return new CartBlockHandler(buttonConfig, ppcpConfig);
|
||||
return new CartBlockHandler( buttonConfig, ppcpConfig );
|
||||
case 'checkout-block':
|
||||
return new CheckoutBlockHandler(buttonConfig, ppcpConfig);
|
||||
return new CheckoutBlockHandler( buttonConfig, ppcpConfig );
|
||||
case 'preview':
|
||||
return new PreviewHandler(buttonConfig, ppcpConfig);
|
||||
return new PreviewHandler( buttonConfig, ppcpConfig );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class MiniCartHandler extends BaseHandler {
|
||||
|
||||
}
|
||||
class MiniCartHandler extends BaseHandler {}
|
||||
|
||||
export default MiniCartHandler;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import Spinner from "../../../../ppcp-button/resources/js/modules/Helper/Spinner";
|
||||
import BaseHandler from "./BaseHandler";
|
||||
import CheckoutActionHandler
|
||||
from "../../../../ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler";
|
||||
import Spinner from '../../../../ppcp-button/resources/js/modules/Helper/Spinner';
|
||||
import BaseHandler from './BaseHandler';
|
||||
import CheckoutActionHandler from '../../../../ppcp-button/resources/js/modules/ActionHandler/CheckoutActionHandler';
|
||||
|
||||
class PayNowHandler extends BaseHandler {
|
||||
|
||||
validateContext() {
|
||||
if ( this.ppcpConfig?.locations_with_subscription_product?.payorder ) {
|
||||
return this.isVaultV3Mode();
|
||||
|
@ -13,16 +11,16 @@ class PayNowHandler extends BaseHandler {
|
|||
}
|
||||
|
||||
transactionInfo() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const data = this.ppcpConfig['pay_now'];
|
||||
return new Promise( async ( resolve, reject ) => {
|
||||
const data = this.ppcpConfig.pay_now;
|
||||
|
||||
resolve({
|
||||
resolve( {
|
||||
countryCode: data.country_code,
|
||||
currencyCode: data.currency_code,
|
||||
totalPriceStatus: 'FINAL',
|
||||
totalPrice: data.total_str
|
||||
});
|
||||
});
|
||||
totalPrice: data.total_str,
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
actionHandler() {
|
||||
|
@ -32,7 +30,6 @@ class PayNowHandler extends BaseHandler {
|
|||
new Spinner()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PayNowHandler;
|
||||
|
|
|
@ -1,37 +1,35 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class PreviewHandler extends BaseHandler {
|
||||
|
||||
constructor(buttonConfig, ppcpConfig, externalHandler) {
|
||||
super(buttonConfig, ppcpConfig, externalHandler);
|
||||
constructor( buttonConfig, ppcpConfig, externalHandler ) {
|
||||
super( buttonConfig, ppcpConfig, externalHandler );
|
||||
}
|
||||
|
||||
transactionInfo() {
|
||||
// We need to return something as ApplePay button initialization expects valid data.
|
||||
return {
|
||||
countryCode: "US",
|
||||
currencyCode: "USD",
|
||||
totalPrice: "10.00",
|
||||
totalPriceStatus: "FINAL"
|
||||
}
|
||||
countryCode: 'US',
|
||||
currencyCode: 'USD',
|
||||
totalPrice: '10.00',
|
||||
totalPriceStatus: 'FINAL',
|
||||
};
|
||||
}
|
||||
|
||||
createOrder() {
|
||||
throw new Error('Create order fail. This is just a preview.');
|
||||
throw new Error( 'Create order fail. This is just a preview.' );
|
||||
}
|
||||
|
||||
approveOrder(data, actions) {
|
||||
throw new Error('Approve order fail. This is just a preview.');
|
||||
approveOrder( data, actions ) {
|
||||
throw new Error( 'Approve order fail. This is just a preview.' );
|
||||
}
|
||||
|
||||
actionHandler() {
|
||||
throw new Error('Action handler fail. This is just a preview.');
|
||||
throw new Error( 'Action handler fail. This is just a preview.' );
|
||||
}
|
||||
|
||||
errorHandler() {
|
||||
throw new Error('Error handler fail. This is just a preview.');
|
||||
throw new Error( 'Error handler fail. This is just a preview.' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PreviewHandler;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import SingleProductActionHandler
|
||||
from "../../../../ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler";
|
||||
import SimulateCart from "../../../../ppcp-button/resources/js/modules/Helper/SimulateCart";
|
||||
import ErrorHandler from "../../../../ppcp-button/resources/js/modules/ErrorHandler";
|
||||
import UpdateCart from "../../../../ppcp-button/resources/js/modules/Helper/UpdateCart";
|
||||
import BaseHandler from "./BaseHandler";
|
||||
import SingleProductActionHandler from '../../../../ppcp-button/resources/js/modules/ActionHandler/SingleProductActionHandler';
|
||||
import SimulateCart from '../../../../ppcp-button/resources/js/modules/Helper/SimulateCart';
|
||||
import ErrorHandler from '../../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
import UpdateCart from '../../../../ppcp-button/resources/js/modules/Helper/UpdateCart';
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class SingleProductHandler extends BaseHandler {
|
||||
|
||||
validateContext() {
|
||||
if ( this.ppcpConfig?.locations_with_subscription_product?.product ) {
|
||||
return this.isVaultV3Mode();
|
||||
|
@ -17,50 +15,51 @@ class SingleProductHandler extends BaseHandler {
|
|||
transactionInfo() {
|
||||
const errorHandler = new ErrorHandler(
|
||||
this.ppcpConfig.labels.error.generic,
|
||||
document.querySelector('.woocommerce-notices-wrapper')
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
|
||||
function form() {
|
||||
return document.querySelector('form.cart');
|
||||
return document.querySelector( 'form.cart' );
|
||||
}
|
||||
|
||||
const actionHandler = new SingleProductActionHandler(
|
||||
null,
|
||||
null,
|
||||
form(),
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
const hasSubscriptions = PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled;
|
||||
const hasSubscriptions =
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions &&
|
||||
PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled;
|
||||
|
||||
const products = hasSubscriptions
|
||||
? actionHandler.getSubscriptionProducts()
|
||||
: actionHandler.getProducts();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
(new SimulateCart(
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
new SimulateCart(
|
||||
this.ppcpConfig.ajax.simulate_cart.endpoint,
|
||||
this.ppcpConfig.ajax.simulate_cart.nonce,
|
||||
)).simulate((data) => {
|
||||
|
||||
resolve({
|
||||
this.ppcpConfig.ajax.simulate_cart.nonce
|
||||
).simulate( ( data ) => {
|
||||
resolve( {
|
||||
countryCode: data.country_code,
|
||||
currencyCode: data.currency_code,
|
||||
totalPriceStatus: 'FINAL',
|
||||
totalPrice: data.total_str
|
||||
});
|
||||
|
||||
}, products);
|
||||
});
|
||||
totalPrice: data.total_str,
|
||||
} );
|
||||
}, products );
|
||||
} );
|
||||
}
|
||||
|
||||
createOrder() {
|
||||
return this.actionHandler().configuration().createOrder(null, null, {
|
||||
'updateCartOptions': {
|
||||
'keepShipping': true
|
||||
}
|
||||
});
|
||||
return this.actionHandler()
|
||||
.configuration()
|
||||
.createOrder( null, null, {
|
||||
updateCartOptions: {
|
||||
keepShipping: true,
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
actionHandler() {
|
||||
|
@ -68,10 +67,10 @@ class SingleProductHandler extends BaseHandler {
|
|||
this.ppcpConfig,
|
||||
new UpdateCart(
|
||||
this.ppcpConfig.ajax.change_cart.endpoint,
|
||||
this.ppcpConfig.ajax.change_cart.nonce,
|
||||
this.ppcpConfig.ajax.change_cart.nonce
|
||||
),
|
||||
document.querySelector('form.cart'),
|
||||
this.errorHandler(),
|
||||
document.querySelector( 'form.cart' ),
|
||||
this.errorHandler()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
export function createAppleErrors(errors) {
|
||||
const errorList = []
|
||||
for (const error of errors) {
|
||||
const {contactField = null, code = null, message = null} = error
|
||||
const appleError = contactField ? new ApplePayError(code, contactField, message) : new ApplePayError(code)
|
||||
errorList.push(appleError)
|
||||
export function createAppleErrors( errors ) {
|
||||
const errorList = [];
|
||||
for ( const error of errors ) {
|
||||
const { contactField = null, code = null, message = null } = error;
|
||||
const appleError = contactField
|
||||
? new ApplePayError( code, contactField, message )
|
||||
: new ApplePayError( code );
|
||||
errorList.push( appleError );
|
||||
}
|
||||
|
||||
return errorList
|
||||
return errorList;
|
||||
}
|
||||
|
|
|
@ -5,4 +5,4 @@ export const endpoints = {
|
|||
createOrderProduct: '_apple_pay_create_order_product',
|
||||
updateShippingMethod: '_apple_pay_update_shipping_contact',
|
||||
updateShippingContact: '_apple_pay_update_billing_contact',
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,14 +6,14 @@ import PreviewButtonManager from '../../../ppcp-button/resources/js/modules/Rend
|
|||
* Accessor that creates and returns a single PreviewButtonManager instance.
|
||||
*/
|
||||
const buttonManager = () => {
|
||||
if (!ApplePayPreviewButtonManager.instance) {
|
||||
ApplePayPreviewButtonManager.instance = new ApplePayPreviewButtonManager();
|
||||
if ( ! ApplePayPreviewButtonManager.instance ) {
|
||||
ApplePayPreviewButtonManager.instance =
|
||||
new ApplePayPreviewButtonManager();
|
||||
}
|
||||
|
||||
return ApplePayPreviewButtonManager.instance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Manages all Apple Pay preview buttons on this page.
|
||||
*/
|
||||
|
@ -24,7 +24,7 @@ class ApplePayPreviewButtonManager extends PreviewButtonManager {
|
|||
buttonConfig: window.wc_ppcp_applepay_admin,
|
||||
};
|
||||
|
||||
super(args);
|
||||
super( args );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -34,11 +34,13 @@ class ApplePayPreviewButtonManager extends PreviewButtonManager {
|
|||
* @param {{}} payPal - The PayPal SDK object provided by WidgetBuilder.
|
||||
* @return {Promise<{}>}
|
||||
*/
|
||||
async fetchConfig(payPal) {
|
||||
async fetchConfig( payPal ) {
|
||||
const apiMethod = payPal?.Applepay()?.config;
|
||||
|
||||
if (!apiMethod) {
|
||||
this.error('configuration object cannot be retrieved from PayPal');
|
||||
if ( ! apiMethod ) {
|
||||
this.error(
|
||||
'configuration object cannot be retrieved from PayPal'
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -51,23 +53,22 @@ class ApplePayPreviewButtonManager extends PreviewButtonManager {
|
|||
* @param {string} wrapperId - CSS ID of the wrapper element.
|
||||
* @return {ApplePayPreviewButton}
|
||||
*/
|
||||
createButtonInstance(wrapperId) {
|
||||
return new ApplePayPreviewButton({
|
||||
createButtonInstance( wrapperId ) {
|
||||
return new ApplePayPreviewButton( {
|
||||
selector: wrapperId,
|
||||
apiConfig: this.apiConfig,
|
||||
});
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A single Apple Pay preview button instance.
|
||||
*/
|
||||
class ApplePayPreviewButton extends PreviewButton {
|
||||
constructor(args) {
|
||||
super(args);
|
||||
constructor( args ) {
|
||||
super( args );
|
||||
|
||||
this.selector = `${args.selector}ApplePay`;
|
||||
this.selector = `${ args.selector }ApplePay`;
|
||||
this.defaultAttributes = {
|
||||
button: {
|
||||
type: 'pay',
|
||||
|
@ -79,31 +80,42 @@ class ApplePayPreviewButton extends PreviewButton {
|
|||
|
||||
createNewWrapper() {
|
||||
const element = super.createNewWrapper();
|
||||
element.addClass('ppcp-button-applepay');
|
||||
element.addClass( 'ppcp-button-applepay' );
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
createButton(buttonConfig) {
|
||||
const button = new ApplepayButton('preview', null, buttonConfig, this.ppcpConfig);
|
||||
createButton( buttonConfig ) {
|
||||
const button = new ApplepayButton(
|
||||
'preview',
|
||||
null,
|
||||
buttonConfig,
|
||||
this.ppcpConfig
|
||||
);
|
||||
|
||||
button.init(this.apiConfig);
|
||||
button.init( this.apiConfig );
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge form details into the config object for preview.
|
||||
* Mutates the previewConfig object; no return value.
|
||||
* @param buttonConfig
|
||||
* @param ppcpConfig
|
||||
*/
|
||||
dynamicPreviewConfig(buttonConfig, ppcpConfig) {
|
||||
dynamicPreviewConfig( buttonConfig, ppcpConfig ) {
|
||||
// The Apple Pay button expects the "wrapper" to be an ID without `#` prefix!
|
||||
buttonConfig.button.wrapper = buttonConfig.button.wrapper.replace(/^#/, '');
|
||||
buttonConfig.button.wrapper = buttonConfig.button.wrapper.replace(
|
||||
/^#/,
|
||||
''
|
||||
);
|
||||
|
||||
// Merge the current form-values into the preview-button configuration.
|
||||
if (ppcpConfig.button) {
|
||||
if ( ppcpConfig.button ) {
|
||||
buttonConfig.button.type = ppcpConfig.button.style.type;
|
||||
buttonConfig.button.color = ppcpConfig.button.style.color;
|
||||
buttonConfig.button.lang =
|
||||
ppcpConfig.button.style?.lang || ppcpConfig.button.style.language;
|
||||
ppcpConfig.button.style?.lang ||
|
||||
ppcpConfig.button.style.language;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,79 +1,81 @@
|
|||
import {useEffect, useState} from '@wordpress/element';
|
||||
import {registerExpressPaymentMethod} from '@woocommerce/blocks-registry';
|
||||
import {loadPaypalScript} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
|
||||
import {cartHasSubscriptionProducts} from '../../../ppcp-blocks/resources/js/Helper/Subscription'
|
||||
import {loadCustomScript} from "@paypal/paypal-js";
|
||||
import CheckoutHandler from "./Context/CheckoutHandler";
|
||||
import ApplepayManager from "./ApplepayManager";
|
||||
import ApplepayManagerBlockEditor from "./ApplepayManagerBlockEditor";
|
||||
import { useEffect, useState } from '@wordpress/element';
|
||||
import { registerExpressPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading';
|
||||
import { cartHasSubscriptionProducts } from '../../../ppcp-blocks/resources/js/Helper/Subscription';
|
||||
import { loadCustomScript } from '@paypal/paypal-js';
|
||||
import CheckoutHandler from './Context/CheckoutHandler';
|
||||
import ApplepayManager from './ApplepayManager';
|
||||
import ApplepayManagerBlockEditor from './ApplepayManagerBlockEditor';
|
||||
|
||||
const ppcpData = wc.wcSettings.getSetting('ppcp-gateway_data');
|
||||
const ppcpData = wc.wcSettings.getSetting( 'ppcp-gateway_data' );
|
||||
const ppcpConfig = ppcpData.scriptData;
|
||||
|
||||
const buttonData = wc.wcSettings.getSetting('ppcp-applepay_data');
|
||||
const buttonData = wc.wcSettings.getSetting( 'ppcp-applepay_data' );
|
||||
const buttonConfig = buttonData.scriptData;
|
||||
|
||||
if (typeof window.PayPalCommerceGateway === 'undefined') {
|
||||
if ( typeof window.PayPalCommerceGateway === 'undefined' ) {
|
||||
window.PayPalCommerceGateway = ppcpConfig;
|
||||
}
|
||||
|
||||
const ApplePayComponent = ( props ) => {
|
||||
const [bootstrapped, setBootstrapped] = useState(false);
|
||||
const [paypalLoaded, setPaypalLoaded] = useState(false);
|
||||
const [applePayLoaded, setApplePayLoaded] = useState(false);
|
||||
const [ bootstrapped, setBootstrapped ] = useState( false );
|
||||
const [ paypalLoaded, setPaypalLoaded ] = useState( false );
|
||||
const [ applePayLoaded, setApplePayLoaded ] = useState( false );
|
||||
|
||||
const bootstrap = function () {
|
||||
const ManagerClass = props.isEditing ? ApplepayManagerBlockEditor : ApplepayManager;
|
||||
const manager = new ManagerClass(buttonConfig, ppcpConfig);
|
||||
const ManagerClass = props.isEditing
|
||||
? ApplepayManagerBlockEditor
|
||||
: ApplepayManager;
|
||||
const manager = new ManagerClass( buttonConfig, ppcpConfig );
|
||||
manager.init();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
useEffect( () => {
|
||||
// Load ApplePay SDK
|
||||
loadCustomScript({ url: buttonConfig.sdk_url }).then(() => {
|
||||
setApplePayLoaded(true);
|
||||
});
|
||||
loadCustomScript( { url: buttonConfig.sdk_url } ).then( () => {
|
||||
setApplePayLoaded( true );
|
||||
} );
|
||||
|
||||
ppcpConfig.url_params.components += ',applepay';
|
||||
|
||||
// Load PayPal
|
||||
loadPaypalScript(ppcpConfig, () => {
|
||||
setPaypalLoaded(true);
|
||||
});
|
||||
}, []);
|
||||
loadPaypalScript( ppcpConfig, () => {
|
||||
setPaypalLoaded( true );
|
||||
} );
|
||||
}, [] );
|
||||
|
||||
useEffect(() => {
|
||||
if (!bootstrapped && paypalLoaded && applePayLoaded) {
|
||||
setBootstrapped(true);
|
||||
useEffect( () => {
|
||||
if ( ! bootstrapped && paypalLoaded && applePayLoaded ) {
|
||||
setBootstrapped( true );
|
||||
bootstrap();
|
||||
}
|
||||
}, [paypalLoaded, applePayLoaded]);
|
||||
}, [ paypalLoaded, applePayLoaded ] );
|
||||
|
||||
return (
|
||||
<div
|
||||
id={buttonConfig.button.wrapper.replace('#', '')}
|
||||
className="ppcp-button-apm ppcp-button-applepay">
|
||||
</div>
|
||||
id={ buttonConfig.button.wrapper.replace( '#', '' ) }
|
||||
className="ppcp-button-apm ppcp-button-applepay"
|
||||
></div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const features = ['products'];
|
||||
const features = [ 'products' ];
|
||||
|
||||
if (
|
||||
cartHasSubscriptionProducts(ppcpConfig)
|
||||
&& (new CheckoutHandler(buttonConfig, ppcpConfig)).isVaultV3Mode()
|
||||
cartHasSubscriptionProducts( ppcpConfig ) &&
|
||||
new CheckoutHandler( buttonConfig, ppcpConfig ).isVaultV3Mode()
|
||||
) {
|
||||
features.push('subscriptions');
|
||||
features.push( 'subscriptions' );
|
||||
}
|
||||
|
||||
registerExpressPaymentMethod({
|
||||
registerExpressPaymentMethod( {
|
||||
name: buttonData.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: buttonData.title}}/>,
|
||||
content: <ApplePayComponent isEditing={false}/>,
|
||||
edit: <ApplePayComponent isEditing={true}/>,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: buttonData.title } } />,
|
||||
content: <ApplePayComponent isEditing={ false } />,
|
||||
edit: <ApplePayComponent isEditing={ true } />,
|
||||
ariaLabel: buttonData.title,
|
||||
canMakePayment: () => buttonData.enabled,
|
||||
supports: {
|
||||
features: features,
|
||||
features,
|
||||
},
|
||||
});
|
||||
} );
|
||||
|
|
|
@ -1,41 +1,34 @@
|
|||
import {loadCustomScript} from "@paypal/paypal-js";
|
||||
import {loadPaypalScript} from "../../../ppcp-button/resources/js/modules/Helper/ScriptLoading";
|
||||
import ApplepayManager from "./ApplepayManager";
|
||||
import {setupButtonEvents} from '../../../ppcp-button/resources/js/modules/Helper/ButtonRefreshHelper';
|
||||
|
||||
(function ({
|
||||
buttonConfig,
|
||||
ppcpConfig,
|
||||
jQuery
|
||||
}) {
|
||||
import { loadCustomScript } from '@paypal/paypal-js';
|
||||
import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading';
|
||||
import ApplepayManager from './ApplepayManager';
|
||||
import { setupButtonEvents } from '../../../ppcp-button/resources/js/modules/Helper/ButtonRefreshHelper';
|
||||
|
||||
( function ( { buttonConfig, ppcpConfig, jQuery } ) {
|
||||
let manager;
|
||||
|
||||
const bootstrap = function () {
|
||||
manager = new ApplepayManager(buttonConfig, ppcpConfig);
|
||||
manager = new ApplepayManager( buttonConfig, ppcpConfig );
|
||||
manager.init();
|
||||
};
|
||||
|
||||
setupButtonEvents(function() {
|
||||
if (manager) {
|
||||
setupButtonEvents( function () {
|
||||
if ( manager ) {
|
||||
manager.reinit();
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
if (
|
||||
(typeof (buttonConfig) === 'undefined') ||
|
||||
(typeof (ppcpConfig) === 'undefined')
|
||||
typeof buttonConfig === 'undefined' ||
|
||||
typeof ppcpConfig === 'undefined'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const isMiniCart = ppcpConfig.mini_cart_buttons_enabled;
|
||||
const isButton = jQuery('#' + buttonConfig.button.wrapper).length > 0;
|
||||
const isButton = jQuery( '#' + buttonConfig.button.wrapper ).length > 0;
|
||||
// If button wrapper is not present then there is no need to load the scripts.
|
||||
// minicart loads later?
|
||||
if (!isMiniCart && !isButton) {
|
||||
if ( ! isMiniCart && ! isButton ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -44,28 +37,26 @@ import {setupButtonEvents} from '../../../ppcp-button/resources/js/modules/Helpe
|
|||
let applePayLoaded = false;
|
||||
|
||||
const tryToBoot = () => {
|
||||
if (!bootstrapped && paypalLoaded && applePayLoaded) {
|
||||
if ( ! bootstrapped && paypalLoaded && applePayLoaded ) {
|
||||
bootstrapped = true;
|
||||
bootstrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load ApplePay SDK
|
||||
loadCustomScript({ url: buttonConfig.sdk_url }).then(() => {
|
||||
loadCustomScript( { url: buttonConfig.sdk_url } ).then( () => {
|
||||
applePayLoaded = true;
|
||||
tryToBoot();
|
||||
});
|
||||
} );
|
||||
|
||||
// Load PayPal
|
||||
loadPaypalScript(ppcpConfig, () => {
|
||||
loadPaypalScript( ppcpConfig, () => {
|
||||
paypalLoaded = true;
|
||||
tryToBoot();
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
})({
|
||||
} );
|
||||
} );
|
||||
} )( {
|
||||
buttonConfig: window.wc_ppcp_applepay,
|
||||
ppcpConfig: window.PayPalCommerceGateway,
|
||||
jQuery: window.jQuery
|
||||
});
|
||||
jQuery: window.jQuery,
|
||||
} );
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,5 @@
|
|||
class DomElement {
|
||||
|
||||
constructor(config) {
|
||||
constructor( config ) {
|
||||
this.$ = jQuery;
|
||||
this.config = config;
|
||||
this.selector = this.config.selector;
|
||||
|
@ -10,20 +9,20 @@ class DomElement {
|
|||
this.anchorSelector = this.config.anchorSelector || null;
|
||||
}
|
||||
|
||||
trigger(action) {
|
||||
this.$(this.selector).trigger(action);
|
||||
trigger( action ) {
|
||||
this.$( this.selector ).trigger( action );
|
||||
}
|
||||
|
||||
on(action, callable) {
|
||||
this.$(document).on(action, this.selector, callable);
|
||||
on( action, callable ) {
|
||||
this.$( document ).on( action, this.selector, callable );
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.$(this.selector).hide();
|
||||
this.$( this.selector ).hide();
|
||||
}
|
||||
|
||||
show() {
|
||||
this.$(this.selector).show();
|
||||
this.$( this.selector ).show();
|
||||
}
|
||||
|
||||
click() {
|
||||
|
@ -31,9 +30,8 @@ class DomElement {
|
|||
}
|
||||
|
||||
get() {
|
||||
return document.querySelector(this.selector);
|
||||
return document.querySelector( this.selector );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DomElement;
|
||||
|
|
|
@ -1,115 +1,115 @@
|
|||
import DomElement from "./DomElement";
|
||||
import DomElement from './DomElement';
|
||||
|
||||
class DomElementCollection {
|
||||
|
||||
constructor() {
|
||||
this.gatewayRadioButton = new DomElement({
|
||||
this.gatewayRadioButton = new DomElement( {
|
||||
selector: '#payment_method_ppcp-axo-gateway',
|
||||
});
|
||||
} );
|
||||
|
||||
this.gatewayDescription = new DomElement({
|
||||
this.gatewayDescription = new DomElement( {
|
||||
selector: '.payment_box.payment_method_ppcp-axo-gateway',
|
||||
});
|
||||
} );
|
||||
|
||||
this.defaultSubmitButton = new DomElement({
|
||||
this.defaultSubmitButton = new DomElement( {
|
||||
selector: '#place_order',
|
||||
});
|
||||
} );
|
||||
|
||||
this.paymentContainer = new DomElement({
|
||||
this.paymentContainer = new DomElement( {
|
||||
id: 'ppcp-axo-payment-container',
|
||||
selector: '#ppcp-axo-payment-container',
|
||||
className: 'ppcp-axo-payment-container'
|
||||
});
|
||||
className: 'ppcp-axo-payment-container',
|
||||
} );
|
||||
|
||||
this.watermarkContainer = new DomElement({
|
||||
this.watermarkContainer = new DomElement( {
|
||||
id: 'ppcp-axo-watermark-container',
|
||||
selector: '#ppcp-axo-watermark-container',
|
||||
className: 'ppcp-axo-watermark-container ppcp-axo-watermark-loading loader'
|
||||
});
|
||||
className:
|
||||
'ppcp-axo-watermark-container ppcp-axo-watermark-loading loader',
|
||||
} );
|
||||
|
||||
this.customerDetails = new DomElement({
|
||||
selector: '#customer_details > *:not(#ppcp-axo-customer-details)'
|
||||
});
|
||||
this.customerDetails = new DomElement( {
|
||||
selector: '#customer_details > *:not(#ppcp-axo-customer-details)',
|
||||
} );
|
||||
|
||||
this.axoCustomerDetails = new DomElement({
|
||||
this.axoCustomerDetails = new DomElement( {
|
||||
id: 'ppcp-axo-customer-details',
|
||||
selector: '#ppcp-axo-customer-details',
|
||||
className: 'ppcp-axo-customer-details',
|
||||
anchorSelector: '#customer_details'
|
||||
});
|
||||
anchorSelector: '#customer_details',
|
||||
} );
|
||||
|
||||
this.emailWidgetContainer = new DomElement({
|
||||
this.emailWidgetContainer = new DomElement( {
|
||||
id: 'ppcp-axo-email-widget',
|
||||
selector: '#ppcp-axo-email-widget',
|
||||
className: 'ppcp-axo-email-widget'
|
||||
});
|
||||
className: 'ppcp-axo-email-widget',
|
||||
} );
|
||||
|
||||
this.shippingAddressContainer = new DomElement({
|
||||
this.shippingAddressContainer = new DomElement( {
|
||||
id: 'ppcp-axo-shipping-address-container',
|
||||
selector: '#ppcp-axo-shipping-address-container',
|
||||
className: 'ppcp-axo-shipping-address-container'
|
||||
});
|
||||
className: 'ppcp-axo-shipping-address-container',
|
||||
} );
|
||||
|
||||
this.billingAddressContainer = new DomElement({
|
||||
this.billingAddressContainer = new DomElement( {
|
||||
id: 'ppcp-axo-billing-address-container',
|
||||
selector: '#ppcp-axo-billing-address-container',
|
||||
className: 'ppcp-axo-billing-address-container'
|
||||
});
|
||||
className: 'ppcp-axo-billing-address-container',
|
||||
} );
|
||||
|
||||
this.fieldBillingEmail = new DomElement({
|
||||
selector: '#billing_email_field'
|
||||
});
|
||||
this.fieldBillingEmail = new DomElement( {
|
||||
selector: '#billing_email_field',
|
||||
} );
|
||||
|
||||
this.billingEmailFieldWrapper = new DomElement({
|
||||
this.billingEmailFieldWrapper = new DomElement( {
|
||||
id: 'ppcp-axo-billing-email-field-wrapper',
|
||||
selector: '#ppcp-axo-billing-email-field-wrapper',
|
||||
});
|
||||
} );
|
||||
|
||||
this.billingEmailSubmitButton = new DomElement({
|
||||
this.billingEmailSubmitButton = new DomElement( {
|
||||
id: 'ppcp-axo-billing-email-submit-button',
|
||||
selector: '#ppcp-axo-billing-email-submit-button',
|
||||
className: 'ppcp-axo-billing-email-submit-button-hidden button alt wp-element-button wc-block-components-button'
|
||||
});
|
||||
className:
|
||||
'ppcp-axo-billing-email-submit-button-hidden button alt wp-element-button wc-block-components-button',
|
||||
} );
|
||||
|
||||
this.billingEmailSubmitButtonSpinner = new DomElement({
|
||||
this.billingEmailSubmitButtonSpinner = new DomElement( {
|
||||
id: 'ppcp-axo-billing-email-submit-button-spinner',
|
||||
selector: '#ppcp-axo-billing-email-submit-button-spinner',
|
||||
className: 'loader ppcp-axo-overlay'
|
||||
});
|
||||
className: 'loader ppcp-axo-overlay',
|
||||
} );
|
||||
|
||||
this.submitButtonContainer = new DomElement({
|
||||
this.submitButtonContainer = new DomElement( {
|
||||
selector: '#ppcp-axo-submit-button-container',
|
||||
});
|
||||
} );
|
||||
|
||||
this.submitButton = new DomElement({
|
||||
selector: '#ppcp-axo-submit-button-container button'
|
||||
});
|
||||
this.submitButton = new DomElement( {
|
||||
selector: '#ppcp-axo-submit-button-container button',
|
||||
} );
|
||||
|
||||
this.changeShippingAddressLink = new DomElement({
|
||||
this.changeShippingAddressLink = new DomElement( {
|
||||
selector: '*[data-ppcp-axo-change-shipping-address]',
|
||||
attributes: 'data-ppcp-axo-change-shipping-address',
|
||||
});
|
||||
} );
|
||||
|
||||
this.changeBillingAddressLink = new DomElement({
|
||||
this.changeBillingAddressLink = new DomElement( {
|
||||
selector: '*[data-ppcp-axo-change-billing-address]',
|
||||
attributes: 'data-ppcp-axo-change-billing-address',
|
||||
});
|
||||
} );
|
||||
|
||||
this.changeCardLink = new DomElement({
|
||||
this.changeCardLink = new DomElement( {
|
||||
selector: '*[data-ppcp-axo-change-card]',
|
||||
attributes: 'data-ppcp-axo-change-card',
|
||||
});
|
||||
} );
|
||||
|
||||
this.showGatewaySelectionLink = new DomElement({
|
||||
this.showGatewaySelectionLink = new DomElement( {
|
||||
selector: '*[data-ppcp-axo-show-gateway-selection]',
|
||||
attributes: 'data-ppcp-axo-show-gateway-selection',
|
||||
});
|
||||
} );
|
||||
|
||||
this.axoNonceInput = new DomElement({
|
||||
this.axoNonceInput = new DomElement( {
|
||||
id: 'ppcp-axo-nonce',
|
||||
selector: '#ppcp-axo-nonce',
|
||||
});
|
||||
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
|
||||
class FormFieldGroup {
|
||||
|
||||
constructor(config) {
|
||||
constructor( config ) {
|
||||
this.data = {};
|
||||
|
||||
this.baseSelector = config.baseSelector;
|
||||
|
@ -12,27 +10,33 @@ class FormFieldGroup {
|
|||
this.active = false;
|
||||
}
|
||||
|
||||
setData(data) {
|
||||
setData( data ) {
|
||||
this.data = data;
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
dataValue(fieldKey) {
|
||||
if (!fieldKey || !this.fields[fieldKey]) {
|
||||
dataValue( fieldKey ) {
|
||||
if ( ! fieldKey || ! this.fields[ fieldKey ] ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (typeof this.fields[fieldKey].valueCallback === 'function') {
|
||||
return this.fields[fieldKey].valueCallback(this.data);
|
||||
if ( typeof this.fields[ fieldKey ].valueCallback === 'function' ) {
|
||||
return this.fields[ fieldKey ].valueCallback( this.data );
|
||||
}
|
||||
|
||||
const path = this.fields[fieldKey].valuePath;
|
||||
const path = this.fields[ fieldKey ].valuePath;
|
||||
|
||||
if (!path) {
|
||||
if ( ! path ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const value = path.split('.').reduce((acc, key) => (acc && acc[key] !== undefined) ? acc[key] : undefined, this.data);
|
||||
const value = path
|
||||
.split( '.' )
|
||||
.reduce(
|
||||
( acc, key ) =>
|
||||
acc && acc[ key ] !== undefined ? acc[ key ] : undefined,
|
||||
this.data
|
||||
);
|
||||
return value ? value : '';
|
||||
}
|
||||
|
||||
|
@ -51,103 +55,105 @@ class FormFieldGroup {
|
|||
}
|
||||
|
||||
refresh() {
|
||||
let content = document.querySelector(this.contentSelector);
|
||||
const content = document.querySelector( this.contentSelector );
|
||||
|
||||
if (!content) {
|
||||
if ( ! content ) {
|
||||
return;
|
||||
}
|
||||
|
||||
content.innerHTML = '';
|
||||
|
||||
if (!this.active) {
|
||||
this.hideField(this.contentSelector);
|
||||
if ( ! this.active ) {
|
||||
this.hideField( this.contentSelector );
|
||||
} else {
|
||||
this.showField(this.contentSelector);
|
||||
this.showField( this.contentSelector );
|
||||
}
|
||||
|
||||
Object.keys(this.fields).forEach((key) => {
|
||||
const field = this.fields[key];
|
||||
Object.keys( this.fields ).forEach( ( key ) => {
|
||||
const field = this.fields[ key ];
|
||||
|
||||
if (this.active && !field.showInput) {
|
||||
this.hideField(field.selector);
|
||||
if ( this.active && ! field.showInput ) {
|
||||
this.hideField( field.selector );
|
||||
} else {
|
||||
this.showField(field.selector);
|
||||
this.showField( field.selector );
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
if (typeof this.template === 'function') {
|
||||
content.innerHTML = this.template({
|
||||
value: (fieldKey) => {
|
||||
return this.dataValue(fieldKey);
|
||||
if ( typeof this.template === 'function' ) {
|
||||
content.innerHTML = this.template( {
|
||||
value: ( fieldKey ) => {
|
||||
return this.dataValue( fieldKey );
|
||||
},
|
||||
isEmpty: () => {
|
||||
let isEmpty = true;
|
||||
Object.keys(this.fields).forEach((fieldKey) => {
|
||||
if (this.dataValue(fieldKey)) {
|
||||
Object.keys( this.fields ).forEach( ( fieldKey ) => {
|
||||
if ( this.dataValue( fieldKey ) ) {
|
||||
isEmpty = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
} );
|
||||
return isEmpty;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
showField(selector) {
|
||||
const field = document.querySelector(this.baseSelector + ' ' + selector);
|
||||
if (field) {
|
||||
field.classList.remove('ppcp-axo-field-hidden');
|
||||
},
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
hideField(selector) {
|
||||
const field = document.querySelector(this.baseSelector + ' ' + selector);
|
||||
if (field) {
|
||||
field.classList.add('ppcp-axo-field-hidden');
|
||||
showField( selector ) {
|
||||
const field = document.querySelector(
|
||||
this.baseSelector + ' ' + selector
|
||||
);
|
||||
if ( field ) {
|
||||
field.classList.remove( 'ppcp-axo-field-hidden' );
|
||||
}
|
||||
}
|
||||
|
||||
inputElement(name) {
|
||||
const baseSelector = this.fields[name].selector;
|
||||
hideField( selector ) {
|
||||
const field = document.querySelector(
|
||||
this.baseSelector + ' ' + selector
|
||||
);
|
||||
if ( field ) {
|
||||
field.classList.add( 'ppcp-axo-field-hidden' );
|
||||
}
|
||||
}
|
||||
|
||||
const select = document.querySelector(baseSelector + ' select');
|
||||
if (select) {
|
||||
inputElement( name ) {
|
||||
const baseSelector = this.fields[ name ].selector;
|
||||
|
||||
const select = document.querySelector( baseSelector + ' select' );
|
||||
if ( select ) {
|
||||
return select;
|
||||
}
|
||||
|
||||
const input = document.querySelector(baseSelector + ' input');
|
||||
if (input) {
|
||||
const input = document.querySelector( baseSelector + ' input' );
|
||||
if ( input ) {
|
||||
return input;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
inputValue(name) {
|
||||
const el = this.inputElement(name);
|
||||
inputValue( name ) {
|
||||
const el = this.inputElement( name );
|
||||
return el ? el.value : '';
|
||||
}
|
||||
|
||||
toSubmitData(data) {
|
||||
Object.keys(this.fields).forEach((fieldKey) => {
|
||||
const field = this.fields[fieldKey];
|
||||
toSubmitData( data ) {
|
||||
Object.keys( this.fields ).forEach( ( fieldKey ) => {
|
||||
const field = this.fields[ fieldKey ];
|
||||
|
||||
if (!field.valuePath || !field.selector) {
|
||||
if ( ! field.valuePath || ! field.selector ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const inputElement = this.inputElement(fieldKey);
|
||||
const inputElement = this.inputElement( fieldKey );
|
||||
|
||||
if (!inputElement) {
|
||||
if ( ! inputElement ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
data[inputElement.name] = this.dataValue(fieldKey);
|
||||
});
|
||||
data[ inputElement.name ] = this.dataValue( fieldKey );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FormFieldGroup;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
class Fastlane {
|
||||
|
||||
construct() {
|
||||
this.connection = null;
|
||||
this.identity = null;
|
||||
|
@ -10,33 +8,35 @@ class Fastlane {
|
|||
this.FastlaneWatermarkComponent = null;
|
||||
}
|
||||
|
||||
connect(config) {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.paypal.Fastlane(config)
|
||||
.then((result) => {
|
||||
this.init(result);
|
||||
connect( config ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
window.paypal
|
||||
.Fastlane( config )
|
||||
.then( ( result ) => {
|
||||
this.init( result );
|
||||
resolve();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error)
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
console.error( error );
|
||||
reject();
|
||||
});
|
||||
});
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
init(connection) {
|
||||
init( connection ) {
|
||||
this.connection = connection;
|
||||
this.identity = this.connection.identity;
|
||||
this.profile = this.connection.profile;
|
||||
this.FastlaneCardComponent = this.connection.FastlaneCardComponent;
|
||||
this.FastlanePaymentComponent = this.connection.FastlanePaymentComponent;
|
||||
this.FastlaneWatermarkComponent = this.connection.FastlaneWatermarkComponent
|
||||
this.FastlanePaymentComponent =
|
||||
this.connection.FastlanePaymentComponent;
|
||||
this.FastlaneWatermarkComponent =
|
||||
this.connection.FastlaneWatermarkComponent;
|
||||
}
|
||||
|
||||
setLocale(locale) {
|
||||
this.connection.setLocale(locale);
|
||||
setLocale( locale ) {
|
||||
this.connection.setLocale( locale );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Fastlane;
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
export function log(message, level = 'info') {
|
||||
export function log( message, level = 'info' ) {
|
||||
const wpDebug = window.wc_ppcp_axo?.wp_debug;
|
||||
const endpoint = window.wc_ppcp_axo?.ajax?.frontend_logger?.endpoint;
|
||||
if (!endpoint) {
|
||||
if ( ! endpoint ) {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(endpoint, {
|
||||
fetch( endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: window.wc_ppcp_axo.ajax.frontend_logger.nonce,
|
||||
log: {
|
||||
message,
|
||||
level,
|
||||
}
|
||||
})
|
||||
}).then(() => {
|
||||
if (wpDebug) {
|
||||
switch (level) {
|
||||
},
|
||||
} ),
|
||||
} ).then( () => {
|
||||
if ( wpDebug ) {
|
||||
switch ( level ) {
|
||||
case 'error':
|
||||
console.error(`[AXO] ${message}`);
|
||||
console.error( `[AXO] ${ message }` );
|
||||
break;
|
||||
default:
|
||||
console.log(`[AXO] ${message}`);
|
||||
console.log( `[AXO] ${ message }` );
|
||||
}
|
||||
}
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -1,58 +1,55 @@
|
|||
|
||||
class PayPalInsights {
|
||||
|
||||
constructor() {
|
||||
window.paypalInsightDataLayer = window.paypalInsightDataLayer || [];
|
||||
document.paypalInsight = () => {
|
||||
paypalInsightDataLayer.push(arguments);
|
||||
}
|
||||
paypalInsightDataLayer.push( arguments );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {PayPalInsights}
|
||||
* @return {PayPalInsights}
|
||||
*/
|
||||
static init() {
|
||||
if (!PayPalInsights.instance) {
|
||||
if ( ! PayPalInsights.instance ) {
|
||||
PayPalInsights.instance = new PayPalInsights();
|
||||
}
|
||||
return PayPalInsights.instance;
|
||||
}
|
||||
|
||||
static track(eventName, data) {
|
||||
static track( eventName, data ) {
|
||||
PayPalInsights.init();
|
||||
paypalInsight('event', eventName, data);
|
||||
paypalInsight( 'event', eventName, data );
|
||||
}
|
||||
|
||||
static config (clientId, data) {
|
||||
static config( clientId, data ) {
|
||||
PayPalInsights.init();
|
||||
paypalInsight('config', clientId, data);
|
||||
paypalInsight( 'config', clientId, data );
|
||||
}
|
||||
|
||||
static setSessionId (sessionId) {
|
||||
static setSessionId( sessionId ) {
|
||||
PayPalInsights.init();
|
||||
paypalInsight('set', { session_id: sessionId });
|
||||
paypalInsight( 'set', { session_id: sessionId } );
|
||||
}
|
||||
|
||||
static trackJsLoad () {
|
||||
PayPalInsights.track('js_load', { timestamp: Date.now() });
|
||||
static trackJsLoad() {
|
||||
PayPalInsights.track( 'js_load', { timestamp: Date.now() } );
|
||||
}
|
||||
|
||||
static trackBeginCheckout (data) {
|
||||
PayPalInsights.track('begin_checkout', data);
|
||||
static trackBeginCheckout( data ) {
|
||||
PayPalInsights.track( 'begin_checkout', data );
|
||||
}
|
||||
|
||||
static trackSubmitCheckoutEmail (data) {
|
||||
PayPalInsights.track('submit_checkout_email', data);
|
||||
static trackSubmitCheckoutEmail( data ) {
|
||||
PayPalInsights.track( 'submit_checkout_email', data );
|
||||
}
|
||||
|
||||
static trackSelectPaymentMethod (data) {
|
||||
PayPalInsights.track('select_payment_method', data);
|
||||
static trackSelectPaymentMethod( data ) {
|
||||
PayPalInsights.track( 'select_payment_method', data );
|
||||
}
|
||||
|
||||
static trackEndCheckout (data) {
|
||||
PayPalInsights.track('end_checkout', data);
|
||||
static trackEndCheckout( data ) {
|
||||
PayPalInsights.track( 'end_checkout', data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PayPalInsights;
|
||||
|
|
|
@ -1,34 +1,36 @@
|
|||
import FormFieldGroup from "../Components/FormFieldGroup";
|
||||
import FormFieldGroup from '../Components/FormFieldGroup';
|
||||
|
||||
class BillingView {
|
||||
|
||||
constructor(selector, elements) {
|
||||
constructor( selector, elements ) {
|
||||
this.el = elements;
|
||||
|
||||
this.group = new FormFieldGroup({
|
||||
this.group = new FormFieldGroup( {
|
||||
baseSelector: '.woocommerce-checkout',
|
||||
contentSelector: selector,
|
||||
template: (data) => {
|
||||
const valueOfSelect = (selectSelector, key) => {
|
||||
if (!key) {
|
||||
template: ( data ) => {
|
||||
const valueOfSelect = ( selectSelector, key ) => {
|
||||
if ( ! key ) {
|
||||
return '';
|
||||
}
|
||||
const selectElement = document.querySelector(selectSelector);
|
||||
const selectElement =
|
||||
document.querySelector( selectSelector );
|
||||
|
||||
if (!selectElement) {
|
||||
if ( ! selectElement ) {
|
||||
return key;
|
||||
}
|
||||
|
||||
const option = selectElement.querySelector(`option[value="${key}"]`);
|
||||
const option = selectElement.querySelector(
|
||||
`option[value="${ key }"]`
|
||||
);
|
||||
return option ? option.textContent : key;
|
||||
}
|
||||
};
|
||||
|
||||
if (data.isEmpty()) {
|
||||
if ( data.isEmpty() ) {
|
||||
return `
|
||||
<div style="margin-bottom: 20px;">
|
||||
<div class="axo-checkout-header-section">
|
||||
<h3>Billing</h3>
|
||||
<a href="javascript:void(0)" ${this.el.changeBillingAddressLink.attributes}>Edit</a>
|
||||
<a href="javascript:void(0)" ${ this.el.changeBillingAddressLink.attributes }>Edit</a>
|
||||
</div>
|
||||
<div>Please fill in your billing details.</div>
|
||||
</div>
|
||||
|
@ -38,50 +40,50 @@ class BillingView {
|
|||
},
|
||||
fields: {
|
||||
email: {
|
||||
'valuePath': 'email',
|
||||
valuePath: 'email',
|
||||
},
|
||||
firstName: {
|
||||
'selector': '#billing_first_name_field',
|
||||
'valuePath': null
|
||||
selector: '#billing_first_name_field',
|
||||
valuePath: null,
|
||||
},
|
||||
lastName: {
|
||||
'selector': '#billing_last_name_field',
|
||||
'valuePath': null
|
||||
selector: '#billing_last_name_field',
|
||||
valuePath: null,
|
||||
},
|
||||
street1: {
|
||||
'selector': '#billing_address_1_field',
|
||||
'valuePath': 'billing.address.addressLine1',
|
||||
selector: '#billing_address_1_field',
|
||||
valuePath: 'billing.address.addressLine1',
|
||||
},
|
||||
street2: {
|
||||
'selector': '#billing_address_2_field',
|
||||
'valuePath': null
|
||||
selector: '#billing_address_2_field',
|
||||
valuePath: null,
|
||||
},
|
||||
postCode: {
|
||||
'selector': '#billing_postcode_field',
|
||||
'valuePath': 'billing.address.postalCode',
|
||||
selector: '#billing_postcode_field',
|
||||
valuePath: 'billing.address.postalCode',
|
||||
},
|
||||
city: {
|
||||
'selector': '#billing_city_field',
|
||||
'valuePath': 'billing.address.adminArea2',
|
||||
selector: '#billing_city_field',
|
||||
valuePath: 'billing.address.adminArea2',
|
||||
},
|
||||
stateCode: {
|
||||
'selector': '#billing_state_field',
|
||||
'valuePath': 'billing.address.adminArea1',
|
||||
selector: '#billing_state_field',
|
||||
valuePath: 'billing.address.adminArea1',
|
||||
},
|
||||
countryCode: {
|
||||
'selector': '#billing_country_field',
|
||||
'valuePath': 'billing.address.countryCode',
|
||||
selector: '#billing_country_field',
|
||||
valuePath: 'billing.address.countryCode',
|
||||
},
|
||||
company: {
|
||||
'selector': '#billing_company_field',
|
||||
'valuePath': null,
|
||||
selector: '#billing_company_field',
|
||||
valuePath: null,
|
||||
},
|
||||
phone: {
|
||||
'selector': '#billing_phone_field',
|
||||
'valuePath': 'billing.phoneNumber'
|
||||
}
|
||||
}
|
||||
});
|
||||
selector: '#billing_phone_field',
|
||||
valuePath: 'billing.phoneNumber',
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
isActive() {
|
||||
|
@ -100,22 +102,23 @@ class BillingView {
|
|||
this.group.refresh();
|
||||
}
|
||||
|
||||
setData(data) {
|
||||
this.group.setData(data);
|
||||
setData( data ) {
|
||||
this.group.setData( data );
|
||||
}
|
||||
|
||||
inputValue(name) {
|
||||
return this.group.inputValue(name);
|
||||
inputValue( name ) {
|
||||
return this.group.inputValue( name );
|
||||
}
|
||||
|
||||
fullName() {
|
||||
return `${this.inputValue('firstName')} ${this.inputValue('lastName')}`.trim();
|
||||
return `${ this.inputValue( 'firstName' ) } ${ this.inputValue(
|
||||
'lastName'
|
||||
) }`.trim();
|
||||
}
|
||||
|
||||
toSubmitData(data) {
|
||||
return this.group.toSubmitData(data);
|
||||
toSubmitData( data ) {
|
||||
return this.group.toSubmitData( data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BillingView;
|
||||
|
|
|
@ -1,80 +1,90 @@
|
|||
import FormFieldGroup from "../Components/FormFieldGroup";
|
||||
import FormFieldGroup from '../Components/FormFieldGroup';
|
||||
|
||||
class CardView {
|
||||
|
||||
constructor(selector, elements, manager) {
|
||||
constructor( selector, elements, manager ) {
|
||||
this.el = elements;
|
||||
this.manager = manager;
|
||||
|
||||
this.group = new FormFieldGroup({
|
||||
this.group = new FormFieldGroup( {
|
||||
baseSelector: '.ppcp-axo-payment-container',
|
||||
contentSelector: selector,
|
||||
template: (data) => {
|
||||
template: ( data ) => {
|
||||
const selectOtherPaymentMethod = () => {
|
||||
if (!this.manager.hideGatewaySelection) {
|
||||
if ( ! this.manager.hideGatewaySelection ) {
|
||||
return '';
|
||||
}
|
||||
return `<p style="margin-top: 40px; text-align: center;"><a href="javascript:void(0)" ${this.el.showGatewaySelectionLink.attributes}>Select other payment method</a></p>`;
|
||||
return `<p style="margin-top: 40px; text-align: center;"><a href="javascript:void(0)" ${ this.el.showGatewaySelectionLink.attributes }>Select other payment method</a></p>`;
|
||||
};
|
||||
|
||||
if (data.isEmpty()) {
|
||||
if ( data.isEmpty() ) {
|
||||
return `
|
||||
<div style="margin-bottom: 20px; text-align: center;">
|
||||
${selectOtherPaymentMethod()}
|
||||
${ selectOtherPaymentMethod() }
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
const expiry = data.value('expiry').split('-');
|
||||
const expiry = data.value( 'expiry' ).split( '-' );
|
||||
|
||||
const cardIcons = {
|
||||
'VISA': 'visa-light.svg',
|
||||
'MASTER_CARD': 'mastercard-light.svg',
|
||||
'AMEX': 'amex-light.svg',
|
||||
'DISCOVER': 'discover-light.svg',
|
||||
'DINERS': 'dinersclub-light.svg',
|
||||
'JCB': 'jcb-light.svg',
|
||||
'UNIONPAY': 'unionpay-light.svg',
|
||||
VISA: 'visa-light.svg',
|
||||
MASTER_CARD: 'mastercard-light.svg',
|
||||
AMEX: 'amex-light.svg',
|
||||
DISCOVER: 'discover-light.svg',
|
||||
DINERS: 'dinersclub-light.svg',
|
||||
JCB: 'jcb-light.svg',
|
||||
UNIONPAY: 'unionpay-light.svg',
|
||||
};
|
||||
|
||||
return `
|
||||
<div style="margin-bottom: 20px;">
|
||||
<div class="axo-checkout-header-section">
|
||||
<h3>Card Details</h3>
|
||||
<a href="javascript:void(0)" ${this.el.changeCardLink.attributes}>Edit</a>
|
||||
<a href="javascript:void(0)" ${
|
||||
this.el.changeCardLink.attributes
|
||||
}>Edit</a>
|
||||
</div>
|
||||
<div style="border:2px solid #cccccc; border-radius: 10px; padding: 16px 20px; background-color:#f6f6f6">
|
||||
<div style="float: right;">
|
||||
<img
|
||||
class="ppcp-card-icon"
|
||||
title="${data.value('brand')}"
|
||||
src="${window.wc_ppcp_axo.icons_directory}${cardIcons[data.value('brand')]}"
|
||||
alt="${data.value('brand')}"
|
||||
title="${ data.value( 'brand' ) }"
|
||||
src="${
|
||||
window.wc_ppcp_axo.icons_directory
|
||||
}${ cardIcons[ data.value( 'brand' ) ] }"
|
||||
alt="${ data.value( 'brand' ) }"
|
||||
>
|
||||
</div>
|
||||
<div style="font-family: monospace; font-size: 1rem; margin-top: 10px;">${data.value('lastDigits') ? '**** **** **** ' + data.value('lastDigits'): ''}</div>
|
||||
<div>${expiry[1]}/${expiry[0]}</div>
|
||||
<div style="text-transform: uppercase">${data.value('name')}</div>
|
||||
<div style="font-family: monospace; font-size: 1rem; margin-top: 10px;">${
|
||||
data.value( 'lastDigits' )
|
||||
? '**** **** **** ' +
|
||||
data.value( 'lastDigits' )
|
||||
: ''
|
||||
}</div>
|
||||
<div>${ expiry[ 1 ] }/${ expiry[ 0 ] }</div>
|
||||
<div style="text-transform: uppercase">${ data.value(
|
||||
'name'
|
||||
) }</div>
|
||||
</div>
|
||||
${selectOtherPaymentMethod()}
|
||||
${ selectOtherPaymentMethod() }
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
fields: {
|
||||
brand: {
|
||||
'valuePath': 'card.paymentSource.card.brand',
|
||||
valuePath: 'card.paymentSource.card.brand',
|
||||
},
|
||||
expiry: {
|
||||
'valuePath': 'card.paymentSource.card.expiry',
|
||||
valuePath: 'card.paymentSource.card.expiry',
|
||||
},
|
||||
lastDigits: {
|
||||
'valuePath': 'card.paymentSource.card.lastDigits',
|
||||
valuePath: 'card.paymentSource.card.lastDigits',
|
||||
},
|
||||
name: {
|
||||
'valuePath': 'card.paymentSource.card.name',
|
||||
valuePath: 'card.paymentSource.card.name',
|
||||
},
|
||||
}
|
||||
});
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
activate() {
|
||||
|
@ -89,28 +99,28 @@ class CardView {
|
|||
this.group.refresh();
|
||||
}
|
||||
|
||||
setData(data) {
|
||||
this.group.setData(data);
|
||||
setData( data ) {
|
||||
this.group.setData( data );
|
||||
}
|
||||
|
||||
toSubmitData(data) {
|
||||
const name = this.group.dataValue('name');
|
||||
const { firstName, lastName } = this.splitName(name);
|
||||
toSubmitData( data ) {
|
||||
const name = this.group.dataValue( 'name' );
|
||||
const { firstName, lastName } = this.splitName( name );
|
||||
|
||||
data['billing_first_name'] = firstName;
|
||||
data['billing_last_name'] = lastName ? lastName : firstName;
|
||||
data.billing_first_name = firstName;
|
||||
data.billing_last_name = lastName ? lastName : firstName;
|
||||
|
||||
return this.group.toSubmitData(data);
|
||||
return this.group.toSubmitData( data );
|
||||
}
|
||||
|
||||
splitName(fullName) {
|
||||
let nameParts = fullName.trim().split(' ');
|
||||
let firstName = nameParts[0];
|
||||
let lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : '';
|
||||
splitName( fullName ) {
|
||||
const nameParts = fullName.trim().split( ' ' );
|
||||
const firstName = nameParts[ 0 ];
|
||||
const lastName =
|
||||
nameParts.length > 1 ? nameParts[ nameParts.length - 1 ] : '';
|
||||
|
||||
return { firstName, lastName };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CardView;
|
||||
|
|
|
@ -1,51 +1,55 @@
|
|||
import FormFieldGroup from "../Components/FormFieldGroup";
|
||||
import FormFieldGroup from '../Components/FormFieldGroup';
|
||||
|
||||
class ShippingView {
|
||||
|
||||
constructor(selector, elements, states) {
|
||||
constructor( selector, elements, states ) {
|
||||
this.el = elements;
|
||||
this.states = states;
|
||||
this.group = new FormFieldGroup({
|
||||
this.group = new FormFieldGroup( {
|
||||
baseSelector: '.woocommerce-checkout',
|
||||
contentSelector: selector,
|
||||
template: (data) => {
|
||||
const valueOfSelect = (selectSelector, key) => {
|
||||
if (!key) {
|
||||
template: ( data ) => {
|
||||
const valueOfSelect = ( selectSelector, key ) => {
|
||||
if ( ! key ) {
|
||||
return '';
|
||||
}
|
||||
const selectElement = document.querySelector(selectSelector);
|
||||
const selectElement =
|
||||
document.querySelector( selectSelector );
|
||||
|
||||
if (!selectElement) {
|
||||
if ( ! selectElement ) {
|
||||
return key;
|
||||
}
|
||||
|
||||
const option = selectElement.querySelector(`option[value="${key}"]`);
|
||||
const option = selectElement.querySelector(
|
||||
`option[value="${ key }"]`
|
||||
);
|
||||
return option ? option.textContent : key;
|
||||
}
|
||||
};
|
||||
|
||||
if (data.isEmpty()) {
|
||||
if ( data.isEmpty() ) {
|
||||
return `
|
||||
<div style="margin-bottom: 20px;">
|
||||
<div class="axo-checkout-header-section">
|
||||
<h3>Shipping</h3>
|
||||
<a href="javascript:void(0)" ${this.el.changeShippingAddressLink.attributes}>Edit</a>
|
||||
<a href="javascript:void(0)" ${ this.el.changeShippingAddressLink.attributes }>Edit</a>
|
||||
</div>
|
||||
<div>Please fill in your shipping details.</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
const countryCode = data.value('countryCode');
|
||||
const stateCode = data.value('stateCode');
|
||||
const stateName = (this.states[countryCode] && this.states[countryCode][stateCode]) ? this.states[countryCode][stateCode] : stateCode;
|
||||
const countryCode = data.value( 'countryCode' );
|
||||
const stateCode = data.value( 'stateCode' );
|
||||
const stateName =
|
||||
this.states[ countryCode ] &&
|
||||
this.states[ countryCode ][ stateCode ]
|
||||
? this.states[ countryCode ][ stateCode ]
|
||||
: stateCode;
|
||||
|
||||
if(
|
||||
this.hasEmptyValues(data, stateName)
|
||||
) {
|
||||
if ( this.hasEmptyValues( data, stateName ) ) {
|
||||
return `
|
||||
<div style="margin-bottom: 20px;">
|
||||
<div class="axo-checkout-header-section">
|
||||
<h3>Shipping</h3>
|
||||
<a href="javascript:void(0)" ${this.el.changeShippingAddressLink.attributes}>Edit</a>
|
||||
<a href="javascript:void(0)" ${ this.el.changeShippingAddressLink.attributes }>Edit</a>
|
||||
</div>
|
||||
<div>Please fill in your shipping details.</div>
|
||||
</div>
|
||||
|
@ -56,89 +60,101 @@ class ShippingView {
|
|||
<div style="margin-bottom: 20px;">
|
||||
<div class="axo-checkout-header-section">
|
||||
<h3>Shipping</h3>
|
||||
<a href="javascript:void(0)" ${this.el.changeShippingAddressLink.attributes}>Edit</a>
|
||||
<a href="javascript:void(0)" ${
|
||||
this.el.changeShippingAddressLink.attributes
|
||||
}>Edit</a>
|
||||
</div>
|
||||
<div>${data.value('email')}</div>
|
||||
<div>${data.value('company')}</div>
|
||||
<div>${data.value('firstName')} ${data.value('lastName')}</div>
|
||||
<div>${data.value('street1')}</div>
|
||||
<div>${data.value('street2')}</div>
|
||||
<div>${data.value('city')}, ${stateName} ${data.value('postCode')}</div>
|
||||
<div>${valueOfSelect('#billing_country', countryCode)}</div>
|
||||
<div>${data.value('phone')}</div>
|
||||
<div>${ data.value( 'email' ) }</div>
|
||||
<div>${ data.value( 'company' ) }</div>
|
||||
<div>${ data.value( 'firstName' ) } ${ data.value(
|
||||
'lastName'
|
||||
) }</div>
|
||||
<div>${ data.value( 'street1' ) }</div>
|
||||
<div>${ data.value( 'street2' ) }</div>
|
||||
<div>${ data.value(
|
||||
'city'
|
||||
) }, ${ stateName } ${ data.value( 'postCode' ) }</div>
|
||||
<div>${ valueOfSelect(
|
||||
'#billing_country',
|
||||
countryCode
|
||||
) }</div>
|
||||
<div>${ data.value( 'phone' ) }</div>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
fields: {
|
||||
email: {
|
||||
'valuePath': 'email',
|
||||
valuePath: 'email',
|
||||
},
|
||||
firstName: {
|
||||
'key': 'firstName',
|
||||
'selector': '#shipping_first_name_field',
|
||||
'valuePath': 'shipping.name.firstName',
|
||||
key: 'firstName',
|
||||
selector: '#shipping_first_name_field',
|
||||
valuePath: 'shipping.name.firstName',
|
||||
},
|
||||
lastName: {
|
||||
'selector': '#shipping_last_name_field',
|
||||
'valuePath': 'shipping.name.lastName',
|
||||
selector: '#shipping_last_name_field',
|
||||
valuePath: 'shipping.name.lastName',
|
||||
},
|
||||
street1: {
|
||||
'selector': '#shipping_address_1_field',
|
||||
'valuePath': 'shipping.address.addressLine1',
|
||||
selector: '#shipping_address_1_field',
|
||||
valuePath: 'shipping.address.addressLine1',
|
||||
},
|
||||
street2: {
|
||||
'selector': '#shipping_address_2_field',
|
||||
'valuePath': null
|
||||
selector: '#shipping_address_2_field',
|
||||
valuePath: null,
|
||||
},
|
||||
postCode: {
|
||||
'selector': '#shipping_postcode_field',
|
||||
'valuePath': 'shipping.address.postalCode',
|
||||
selector: '#shipping_postcode_field',
|
||||
valuePath: 'shipping.address.postalCode',
|
||||
},
|
||||
city: {
|
||||
'selector': '#shipping_city_field',
|
||||
'valuePath': 'shipping.address.adminArea2',
|
||||
selector: '#shipping_city_field',
|
||||
valuePath: 'shipping.address.adminArea2',
|
||||
},
|
||||
stateCode: {
|
||||
'selector': '#shipping_state_field',
|
||||
'valuePath': 'shipping.address.adminArea1',
|
||||
selector: '#shipping_state_field',
|
||||
valuePath: 'shipping.address.adminArea1',
|
||||
},
|
||||
countryCode: {
|
||||
'selector': '#shipping_country_field',
|
||||
'valuePath': 'shipping.address.countryCode',
|
||||
selector: '#shipping_country_field',
|
||||
valuePath: 'shipping.address.countryCode',
|
||||
},
|
||||
company: {
|
||||
'selector': '#shipping_company_field',
|
||||
'valuePath': null,
|
||||
selector: '#shipping_company_field',
|
||||
valuePath: null,
|
||||
},
|
||||
shipDifferentAddress: {
|
||||
'selector': '#ship-to-different-address',
|
||||
'valuePath': null,
|
||||
selector: '#ship-to-different-address',
|
||||
valuePath: null,
|
||||
},
|
||||
phone: {
|
||||
//'selector': '#billing_phone_field', // There is no shipping phone field.
|
||||
'valueCallback': function (data) {
|
||||
valueCallback( data ) {
|
||||
let phone = '';
|
||||
const cc = data?.shipping?.phoneNumber?.countryCode;
|
||||
const number = data?.shipping?.phoneNumber?.nationalNumber;
|
||||
const number =
|
||||
data?.shipping?.phoneNumber?.nationalNumber;
|
||||
|
||||
if (cc) {
|
||||
phone = `+${cc} `;
|
||||
if ( cc ) {
|
||||
phone = `+${ cc } `;
|
||||
}
|
||||
phone += number;
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
hasEmptyValues(data, stateName) {
|
||||
return !data.value('email')
|
||||
|| !data.value('firstName')
|
||||
|| !data.value('lastName')
|
||||
|| !data.value('street1')
|
||||
|| !data.value('city')
|
||||
|| !stateName;
|
||||
hasEmptyValues( data, stateName ) {
|
||||
return (
|
||||
! data.value( 'email' ) ||
|
||||
! data.value( 'firstName' ) ||
|
||||
! data.value( 'lastName' ) ||
|
||||
! data.value( 'street1' ) ||
|
||||
! data.value( 'city' ) ||
|
||||
! stateName
|
||||
);
|
||||
}
|
||||
|
||||
isActive() {
|
||||
|
@ -157,14 +173,13 @@ class ShippingView {
|
|||
this.group.refresh();
|
||||
}
|
||||
|
||||
setData(data) {
|
||||
this.group.setData(data);
|
||||
setData( data ) {
|
||||
this.group.setData( data );
|
||||
}
|
||||
|
||||
toSubmitData(data) {
|
||||
return this.group.toSubmitData(data);
|
||||
toSubmitData( data ) {
|
||||
return this.group.toSubmitData( data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ShippingView;
|
||||
|
|
|
@ -1,33 +1,24 @@
|
|||
import AxoManager from "./AxoManager";
|
||||
import {loadPaypalScript} from "../../../ppcp-button/resources/js/modules/Helper/ScriptLoading";
|
||||
|
||||
(function ({
|
||||
axoConfig,
|
||||
ppcpConfig,
|
||||
jQuery
|
||||
}) {
|
||||
import AxoManager from './AxoManager';
|
||||
import { loadPaypalScript } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading';
|
||||
|
||||
( function ( { axoConfig, ppcpConfig, jQuery } ) {
|
||||
const bootstrap = () => {
|
||||
new AxoManager(axoConfig, ppcpConfig);
|
||||
}
|
||||
new AxoManager( axoConfig, ppcpConfig );
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
if (!typeof (PayPalCommerceGateway)) {
|
||||
console.error('AXO could not be configured.');
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
if ( ! typeof PayPalCommerceGateway ) {
|
||||
console.error( 'AXO could not be configured.' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Load PayPal
|
||||
loadPaypalScript(ppcpConfig, () => {
|
||||
loadPaypalScript( ppcpConfig, () => {
|
||||
bootstrap();
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
})({
|
||||
} );
|
||||
} );
|
||||
} )( {
|
||||
axoConfig: window.wc_ppcp_axo,
|
||||
ppcpConfig: window.PayPalCommerceGateway,
|
||||
jQuery: window.jQuery
|
||||
});
|
||||
jQuery: window.jQuery,
|
||||
} );
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import * as $ from 'jquery';
|
||||
import DomElement from "../Components/DomElement";
|
||||
import FormFieldGroup from "../Components/FormFieldGroup";
|
||||
import DomElement from '../Components/DomElement';
|
||||
import FormFieldGroup from '../Components/FormFieldGroup';
|
||||
|
||||
global['$'] = global['jQuery'] = $;
|
||||
global.$ = global.jQuery = $;
|
||||
|
||||
test('get dom element selector', () => {
|
||||
const element = new DomElement({selector: '.foo'});
|
||||
test( 'get dom element selector', () => {
|
||||
const element = new DomElement( { selector: '.foo' } );
|
||||
|
||||
expect(element.selector).toBe('.foo')
|
||||
});
|
||||
expect( element.selector ).toBe( '.foo' );
|
||||
} );
|
||||
|
||||
test('form field group activate', () => {
|
||||
const formFieldGroup = new FormFieldGroup({});
|
||||
test( 'form field group activate', () => {
|
||||
const formFieldGroup = new FormFieldGroup( {} );
|
||||
|
||||
expect(formFieldGroup.active).toBe(false)
|
||||
expect( formFieldGroup.active ).toBe( false );
|
||||
|
||||
formFieldGroup.activate()
|
||||
expect(formFieldGroup.active).toBe(true)
|
||||
});
|
||||
formFieldGroup.activate();
|
||||
expect( formFieldGroup.active ).toBe( true );
|
||||
} );
|
||||
|
|
|
@ -140,12 +140,17 @@ class AxoModule implements ModuleInterface {
|
|||
);
|
||||
|
||||
add_action(
|
||||
'init',
|
||||
'wp_loaded',
|
||||
function () use ( $c ) {
|
||||
$module = $this;
|
||||
|
||||
$subscription_helper = $c->get( 'wc-subscriptions.helper' );
|
||||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
|
||||
// Check if the module is applicable, correct country, currency, ... etc.
|
||||
if ( ! $c->get( 'axo.eligible' ) || 'continuation' === $c->get( 'button.context' ) ) {
|
||||
if ( ! $c->get( 'axo.eligible' )
|
||||
|| 'continuation' === $c->get( 'button.context' )
|
||||
|| $subscription_helper->cart_contains_subscription() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -334,15 +339,11 @@ class AxoModule implements ModuleInterface {
|
|||
$is_axo_enabled = $settings->has( 'axo_enabled' ) && $settings->get( 'axo_enabled' ) ?? false;
|
||||
$is_dcc_enabled = $settings->has( 'dcc_enabled' ) && $settings->get( 'dcc_enabled' ) ?? false;
|
||||
|
||||
$subscription_helper = $c->get( 'wc-subscriptions.helper' );
|
||||
assert( $subscription_helper instanceof SubscriptionHelper );
|
||||
|
||||
return ! is_user_logged_in()
|
||||
&& CartCheckoutDetector::has_classic_checkout()
|
||||
&& $is_axo_enabled
|
||||
&& $is_dcc_enabled
|
||||
&& ! $this->is_excluded_endpoint()
|
||||
&& ! $subscription_helper->cart_contains_subscription();
|
||||
&& ! $this->is_excluded_endpoint();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import MessagesBootstrap from "../../../../ppcp-button/resources/js/modules/ContextBootstrap/MessagesBootstap";
|
||||
import {debounce} from "../Helper/debounce";
|
||||
import MessagesBootstrap from '../../../../ppcp-button/resources/js/modules/ContextBootstrap/MessagesBootstap';
|
||||
import { debounce } from '../Helper/debounce';
|
||||
|
||||
class BlockCheckoutMessagesBootstrap {
|
||||
constructor(scriptData) {
|
||||
this.messagesBootstrap = new MessagesBootstrap(scriptData, null);
|
||||
constructor( scriptData ) {
|
||||
this.messagesBootstrap = new MessagesBootstrap( scriptData, null );
|
||||
this.lastCartTotal = null;
|
||||
}
|
||||
|
||||
|
@ -12,10 +12,12 @@ class BlockCheckoutMessagesBootstrap {
|
|||
|
||||
this._updateCartTotal();
|
||||
|
||||
if (wp.data?.subscribe) {
|
||||
wp.data.subscribe(debounce(() => {
|
||||
if ( wp.data?.subscribe ) {
|
||||
wp.data.subscribe(
|
||||
debounce( () => {
|
||||
this._updateCartTotal();
|
||||
}, 300));
|
||||
}, 300 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,17 +25,20 @@ class BlockCheckoutMessagesBootstrap {
|
|||
* @private
|
||||
*/
|
||||
_getCartTotal() {
|
||||
if (!wp.data.select) {
|
||||
if ( ! wp.data.select ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const cart = wp.data.select('wc/store/cart')
|
||||
if (!cart) {
|
||||
const cart = wp.data.select( 'wc/store/cart' );
|
||||
if ( ! cart ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const totals = cart.getCartTotals();
|
||||
return parseInt(totals.total_price, 10) / 10 ** totals.currency_minor_unit;
|
||||
return (
|
||||
parseInt( totals.total_price, 10 ) /
|
||||
10 ** totals.currency_minor_unit
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,13 +46,15 @@ class BlockCheckoutMessagesBootstrap {
|
|||
*/
|
||||
_updateCartTotal() {
|
||||
const currentTotal = this._getCartTotal();
|
||||
if (currentTotal === null) {
|
||||
if ( currentTotal === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentTotal !== this.lastCartTotal) {
|
||||
if ( currentTotal !== this.lastCartTotal ) {
|
||||
this.lastCartTotal = currentTotal;
|
||||
jQuery(document.body).trigger('ppcp_block_cart_total_updated', [currentTotal]);
|
||||
jQuery( document.body ).trigger( 'ppcp_block_cart_total_updated', [
|
||||
currentTotal,
|
||||
] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,87 +1,95 @@
|
|||
import {useEffect, useState} from '@wordpress/element';
|
||||
import { useEffect, useState } from '@wordpress/element';
|
||||
|
||||
import {
|
||||
PayPalScriptProvider,
|
||||
PayPalCardFieldsProvider,
|
||||
PayPalCardFieldsForm,
|
||||
} from "@paypal/react-paypal-js";
|
||||
} from '@paypal/react-paypal-js';
|
||||
|
||||
import {CheckoutHandler} from "./checkout-handler";
|
||||
import {createOrder, onApprove} from "../card-fields-config";
|
||||
import {cartHasSubscriptionProducts} from "../Helper/Subscription";
|
||||
import { CheckoutHandler } from './checkout-handler';
|
||||
import { createOrder, onApprove } from '../card-fields-config';
|
||||
import { cartHasSubscriptionProducts } from '../Helper/Subscription';
|
||||
|
||||
export function CardFields({config, eventRegistration, emitResponse, components}) {
|
||||
const {onPaymentSetup} = eventRegistration;
|
||||
const {responseTypes} = emitResponse;
|
||||
export function CardFields( {
|
||||
config,
|
||||
eventRegistration,
|
||||
emitResponse,
|
||||
components,
|
||||
} ) {
|
||||
const { onPaymentSetup } = eventRegistration;
|
||||
const { responseTypes } = emitResponse;
|
||||
const { PaymentMethodIcons } = components;
|
||||
|
||||
const [cardFieldsForm, setCardFieldsForm] = useState();
|
||||
const getCardFieldsForm = (cardFieldsForm) => {
|
||||
setCardFieldsForm(cardFieldsForm)
|
||||
const [ cardFieldsForm, setCardFieldsForm ] = useState();
|
||||
const getCardFieldsForm = ( cardFieldsForm ) => {
|
||||
setCardFieldsForm( cardFieldsForm );
|
||||
};
|
||||
|
||||
const getSavePayment = ( savePayment ) => {
|
||||
localStorage.setItem( 'ppcp-save-card-payment', savePayment );
|
||||
};
|
||||
|
||||
const hasSubscriptionProducts = cartHasSubscriptionProducts(
|
||||
config.scriptData
|
||||
);
|
||||
useEffect( () => {
|
||||
localStorage.removeItem( 'ppcp-save-card-payment' );
|
||||
|
||||
if ( hasSubscriptionProducts ) {
|
||||
localStorage.setItem( 'ppcp-save-card-payment', 'true' );
|
||||
}
|
||||
|
||||
const getSavePayment = (savePayment) => {
|
||||
localStorage.setItem('ppcp-save-card-payment', savePayment);
|
||||
}
|
||||
|
||||
const hasSubscriptionProducts = cartHasSubscriptionProducts(config.scriptData);
|
||||
useEffect(() => {
|
||||
localStorage.removeItem('ppcp-save-card-payment');
|
||||
|
||||
if(hasSubscriptionProducts) {
|
||||
localStorage.setItem('ppcp-save-card-payment', 'true');
|
||||
}
|
||||
|
||||
}, [hasSubscriptionProducts])
|
||||
}, [ hasSubscriptionProducts ] );
|
||||
|
||||
useEffect(
|
||||
() =>
|
||||
onPaymentSetup(() => {
|
||||
onPaymentSetup( () => {
|
||||
async function handlePaymentProcessing() {
|
||||
await cardFieldsForm.submit()
|
||||
.catch((error) => {
|
||||
await cardFieldsForm.submit().catch( ( error ) => {
|
||||
return {
|
||||
type: responseTypes.ERROR,
|
||||
}
|
||||
});
|
||||
};
|
||||
} );
|
||||
|
||||
return {
|
||||
type: responseTypes.SUCCESS,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return handlePaymentProcessing();
|
||||
}),
|
||||
[onPaymentSetup, cardFieldsForm]
|
||||
} ),
|
||||
[ onPaymentSetup, cardFieldsForm ]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<PayPalScriptProvider
|
||||
options={{
|
||||
options={ {
|
||||
clientId: config.scriptData.client_id,
|
||||
components: "card-fields",
|
||||
components: 'card-fields',
|
||||
dataNamespace: 'ppcp-block-card-fields',
|
||||
}}
|
||||
} }
|
||||
>
|
||||
<PayPalCardFieldsProvider
|
||||
createOrder={createOrder}
|
||||
onApprove={onApprove}
|
||||
onError={(err) => {
|
||||
console.error(err);
|
||||
}}
|
||||
createOrder={ createOrder }
|
||||
onApprove={ onApprove }
|
||||
onError={ ( err ) => {
|
||||
console.error( err );
|
||||
} }
|
||||
>
|
||||
<PayPalCardFieldsForm/>
|
||||
<PaymentMethodIcons icons={config.card_icons} align="left" />
|
||||
<PayPalCardFieldsForm />
|
||||
<PaymentMethodIcons
|
||||
icons={ config.card_icons }
|
||||
align="left"
|
||||
/>
|
||||
<CheckoutHandler
|
||||
getCardFieldsForm={getCardFieldsForm}
|
||||
getSavePayment={getSavePayment}
|
||||
hasSubscriptionProducts={hasSubscriptionProducts}
|
||||
saveCardText={config.save_card_text}
|
||||
is_vaulting_enabled={config.is_vaulting_enabled}
|
||||
getCardFieldsForm={ getCardFieldsForm }
|
||||
getSavePayment={ getSavePayment }
|
||||
hasSubscriptionProducts={ hasSubscriptionProducts }
|
||||
saveCardText={ config.save_card_text }
|
||||
is_vaulting_enabled={ config.is_vaulting_enabled }
|
||||
/>
|
||||
</PayPalCardFieldsProvider>
|
||||
</PayPalScriptProvider>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
import {useEffect} from '@wordpress/element';
|
||||
import {usePayPalCardFields} from "@paypal/react-paypal-js";
|
||||
import { useEffect } from '@wordpress/element';
|
||||
import { usePayPalCardFields } from '@paypal/react-paypal-js';
|
||||
|
||||
export const CheckoutHandler = ({getCardFieldsForm, getSavePayment, hasSubscriptionProducts, saveCardText, is_vaulting_enabled}) => {
|
||||
const {cardFieldsForm} = usePayPalCardFields();
|
||||
export const CheckoutHandler = ( {
|
||||
getCardFieldsForm,
|
||||
getSavePayment,
|
||||
hasSubscriptionProducts,
|
||||
saveCardText,
|
||||
is_vaulting_enabled,
|
||||
} ) => {
|
||||
const { cardFieldsForm } = usePayPalCardFields();
|
||||
|
||||
useEffect(() => {
|
||||
getCardFieldsForm(cardFieldsForm)
|
||||
}, []);
|
||||
useEffect( () => {
|
||||
getCardFieldsForm( cardFieldsForm );
|
||||
}, [] );
|
||||
|
||||
if (!is_vaulting_enabled) {
|
||||
if ( ! is_vaulting_enabled ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -18,11 +24,11 @@ export const CheckoutHandler = ({getCardFieldsForm, getSavePayment, hasSubscript
|
|||
type="checkbox"
|
||||
id="save"
|
||||
name="save"
|
||||
onChange={(e) => getSavePayment(e.target.checked)}
|
||||
defaultChecked={hasSubscriptionProducts}
|
||||
disabled={hasSubscriptionProducts}
|
||||
onChange={ ( e ) => getSavePayment( e.target.checked ) }
|
||||
defaultChecked={ hasSubscriptionProducts }
|
||||
disabled={ hasSubscriptionProducts }
|
||||
/>
|
||||
<label htmlFor="save">{saveCardText}</label>
|
||||
<label htmlFor="save">{ saveCardText }</label>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
/**
|
||||
* @param {String} fullName
|
||||
* @returns {Array}
|
||||
* @param {string} fullName
|
||||
* @return {Array}
|
||||
*/
|
||||
export const splitFullName = (fullName) => {
|
||||
fullName = fullName.trim()
|
||||
if (!fullName.includes(' ')) {
|
||||
return [fullName, ''];
|
||||
export const splitFullName = ( fullName ) => {
|
||||
fullName = fullName.trim();
|
||||
if ( ! fullName.includes( ' ' ) ) {
|
||||
return [ fullName, '' ];
|
||||
}
|
||||
const parts = fullName.split(' ');
|
||||
const firstName = parts[0];
|
||||
const parts = fullName.split( ' ' );
|
||||
const firstName = parts[ 0 ];
|
||||
parts.shift();
|
||||
const lastName = parts.join(' ');
|
||||
return [firstName, lastName];
|
||||
}
|
||||
const lastName = parts.join( ' ' );
|
||||
return [ firstName, lastName ];
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} address
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalAddressToWc = (address) => {
|
||||
export const paypalAddressToWc = ( address ) => {
|
||||
let map = {
|
||||
country_code: 'country',
|
||||
address_line_1: 'address_1',
|
||||
|
@ -27,7 +27,8 @@ export const paypalAddressToWc = (address) => {
|
|||
admin_area_2: 'city',
|
||||
postal_code: 'postcode',
|
||||
};
|
||||
if (address.city) { // address not from API, such as onShippingChange
|
||||
if ( address.city ) {
|
||||
// address not from API, such as onShippingChange
|
||||
map = {
|
||||
country_code: 'country',
|
||||
state: 'state',
|
||||
|
@ -36,11 +37,11 @@ export const paypalAddressToWc = (address) => {
|
|||
};
|
||||
}
|
||||
const result = {};
|
||||
Object.entries(map).forEach(([paypalKey, wcKey]) => {
|
||||
if (address[paypalKey]) {
|
||||
result[wcKey] = address[paypalKey];
|
||||
Object.entries( map ).forEach( ( [ paypalKey, wcKey ] ) => {
|
||||
if ( address[ paypalKey ] ) {
|
||||
result[ wcKey ] = address[ paypalKey ];
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
const defaultAddress = {
|
||||
first_name: '',
|
||||
|
@ -55,117 +56,124 @@ export const paypalAddressToWc = (address) => {
|
|||
phone: '',
|
||||
};
|
||||
|
||||
return {...defaultAddress, ...result};
|
||||
}
|
||||
return { ...defaultAddress, ...result };
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} shipping
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalShippingToWc = (shipping) => {
|
||||
const [firstName, lastName] = (shipping.name ? splitFullName(shipping.name.full_name) : ['','']);
|
||||
export const paypalShippingToWc = ( shipping ) => {
|
||||
const [ firstName, lastName ] = shipping.name
|
||||
? splitFullName( shipping.name.full_name )
|
||||
: [ '', '' ];
|
||||
return {
|
||||
...paypalAddressToWc(shipping.address),
|
||||
...paypalAddressToWc( shipping.address ),
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} payer
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalPayerToWc = (payer) => {
|
||||
export const paypalPayerToWc = ( payer ) => {
|
||||
const firstName = payer?.name?.given_name ?? '';
|
||||
const lastName = payer?.name?.surname ?? '';
|
||||
const address = payer.address ? paypalAddressToWc(payer.address) : {};
|
||||
const address = payer.address ? paypalAddressToWc( payer.address ) : {};
|
||||
return {
|
||||
...address,
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
email: payer.email_address,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} subscriber
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalSubscriberToWc = (subscriber) => {
|
||||
export const paypalSubscriberToWc = ( subscriber ) => {
|
||||
const firstName = subscriber?.name?.given_name ?? '';
|
||||
const lastName = subscriber?.name?.surname ?? '';
|
||||
const address = subscriber.address ? paypalAddressToWc(subscriber.shipping_address.address) : {};
|
||||
const address = subscriber.address
|
||||
? paypalAddressToWc( subscriber.shipping_address.address )
|
||||
: {};
|
||||
return {
|
||||
...address,
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
email: subscriber.email_address,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} order
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalOrderToWcShippingAddress = (order) => {
|
||||
const shipping = order.purchase_units[0].shipping;
|
||||
if (!shipping) {
|
||||
export const paypalOrderToWcShippingAddress = ( order ) => {
|
||||
const shipping = order.purchase_units[ 0 ].shipping;
|
||||
if ( ! shipping ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const res = paypalShippingToWc(shipping);
|
||||
const res = paypalShippingToWc( shipping );
|
||||
|
||||
// use the name from billing if the same, to avoid possible mistakes when splitting full_name
|
||||
if (order.payer) {
|
||||
const billingAddress = paypalPayerToWc(order.payer);
|
||||
if (`${res.first_name} ${res.last_name}` === `${billingAddress.first_name} ${billingAddress.last_name}`) {
|
||||
if ( order.payer ) {
|
||||
const billingAddress = paypalPayerToWc( order.payer );
|
||||
if (
|
||||
`${ res.first_name } ${ res.last_name }` ===
|
||||
`${ billingAddress.first_name } ${ billingAddress.last_name }`
|
||||
) {
|
||||
res.first_name = billingAddress.first_name;
|
||||
res.last_name = billingAddress.last_name;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param order
|
||||
* @returns {{shippingAddress: Object, billingAddress: Object}}
|
||||
* @return {{shippingAddress: Object, billingAddress: Object}}
|
||||
*/
|
||||
export const paypalOrderToWcAddresses = (order) => {
|
||||
const shippingAddress = paypalOrderToWcShippingAddress(order);
|
||||
export const paypalOrderToWcAddresses = ( order ) => {
|
||||
const shippingAddress = paypalOrderToWcShippingAddress( order );
|
||||
let billingAddress = shippingAddress;
|
||||
if (order.payer) {
|
||||
billingAddress = paypalPayerToWc(order.payer);
|
||||
if ( order.payer ) {
|
||||
billingAddress = paypalPayerToWc( order.payer );
|
||||
// no billing address, such as if billing address retrieval is not allowed in the merchant account
|
||||
if (!billingAddress.address_line_1) {
|
||||
if ( ! billingAddress.address_line_1 ) {
|
||||
// use only non empty values from payer address, otherwise it will override shipping address
|
||||
let payerAddress = Object.fromEntries(
|
||||
Object.entries(billingAddress).filter(
|
||||
([key, value]) => value !== '' && key !== 'country'
|
||||
const payerAddress = Object.fromEntries(
|
||||
Object.entries( billingAddress ).filter(
|
||||
( [ key, value ] ) => value !== '' && key !== 'country'
|
||||
)
|
||||
);
|
||||
|
||||
billingAddress = {
|
||||
...shippingAddress,
|
||||
...payerAddress
|
||||
...payerAddress,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {billingAddress, shippingAddress};
|
||||
}
|
||||
return { billingAddress, shippingAddress };
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param subscription
|
||||
* @returns {{shippingAddress: Object, billingAddress: Object}}
|
||||
* @return {{shippingAddress: Object, billingAddress: Object}}
|
||||
*/
|
||||
export const paypalSubscriptionToWcAddresses = (subscription) => {
|
||||
const shippingAddress = paypalSubscriberToWc(subscription.subscriber);
|
||||
let billingAddress = shippingAddress;
|
||||
return {billingAddress, shippingAddress};
|
||||
}
|
||||
export const paypalSubscriptionToWcAddresses = ( subscription ) => {
|
||||
const shippingAddress = paypalSubscriberToWc( subscription.subscriber );
|
||||
const billingAddress = shippingAddress;
|
||||
return { billingAddress, shippingAddress };
|
||||
};
|
||||
|
||||
/**
|
||||
* Merges two WC addresses.
|
||||
|
@ -173,22 +181,28 @@ export const paypalSubscriptionToWcAddresses = (subscription) => {
|
|||
*
|
||||
* @param {Object} address1
|
||||
* @param {Object} address2
|
||||
* @returns {any}
|
||||
* @return {any}
|
||||
*/
|
||||
export const mergeWcAddress = (address1, address2) => {
|
||||
if ('billingAddress' in address1) {
|
||||
export const mergeWcAddress = ( address1, address2 ) => {
|
||||
if ( 'billingAddress' in address1 ) {
|
||||
return {
|
||||
billingAddress: mergeWcAddress(address1.billingAddress, address2.billingAddress),
|
||||
shippingAddress: mergeWcAddress(address1.shippingAddress, address2.shippingAddress),
|
||||
}
|
||||
billingAddress: mergeWcAddress(
|
||||
address1.billingAddress,
|
||||
address2.billingAddress
|
||||
),
|
||||
shippingAddress: mergeWcAddress(
|
||||
address1.shippingAddress,
|
||||
address2.shippingAddress
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
let address2WithoutEmpty = {...address2};
|
||||
Object.keys(address2).forEach(key => {
|
||||
if (address2[key] === '') {
|
||||
delete address2WithoutEmpty[key];
|
||||
const address2WithoutEmpty = { ...address2 };
|
||||
Object.keys( address2 ).forEach( ( key ) => {
|
||||
if ( address2[ key ] === '' ) {
|
||||
delete address2WithoutEmpty[ key ];
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
return {...address1, ...address2WithoutEmpty};
|
||||
}
|
||||
return { ...address1, ...address2WithoutEmpty };
|
||||
};
|
||||
|
|
|
@ -1,22 +1,24 @@
|
|||
/**
|
||||
* @param str
|
||||
* @returns {string}
|
||||
* @return {string}
|
||||
*/
|
||||
export const toSnakeCase = (str) => {
|
||||
return str.replace(/[\w]([A-Z])/g, function(m) {
|
||||
return m[0] + "_" + m[1];
|
||||
}).toLowerCase();
|
||||
}
|
||||
export const toSnakeCase = ( str ) => {
|
||||
return str
|
||||
.replace( /[\w]([A-Z])/g, function ( m ) {
|
||||
return m[ 0 ] + '_' + m[ 1 ];
|
||||
} )
|
||||
.toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
* @returns {{}}
|
||||
* @return {{}}
|
||||
*/
|
||||
export const convertKeysToSnakeCase = (obj) => {
|
||||
export const convertKeysToSnakeCase = ( obj ) => {
|
||||
const newObj = {};
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const newKey = toSnakeCase(key);
|
||||
newObj[newKey] = obj[key];
|
||||
});
|
||||
Object.keys( obj ).forEach( ( key ) => {
|
||||
const newKey = toSnakeCase( key );
|
||||
newObj[ newKey ] = obj[ key ];
|
||||
} );
|
||||
return newObj;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
/**
|
||||
* @param {Object} scriptData
|
||||
* @returns {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const isPayPalSubscription = (scriptData) => {
|
||||
return scriptData.data_client_id.has_subscriptions
|
||||
&& scriptData.data_client_id.paypal_subscriptions_enabled;
|
||||
}
|
||||
export const isPayPalSubscription = ( scriptData ) => {
|
||||
return (
|
||||
scriptData.data_client_id.has_subscriptions &&
|
||||
scriptData.data_client_id.paypal_subscriptions_enabled
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} scriptData
|
||||
* @returns {Boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
export const cartHasSubscriptionProducts = (scriptData) => {
|
||||
export const cartHasSubscriptionProducts = ( scriptData ) => {
|
||||
return !! scriptData?.locations_with_subscription_product?.cart;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
export const debounce = (callback, delayMs) => {
|
||||
export const debounce = ( callback, delayMs ) => {
|
||||
let timeoutId = null;
|
||||
return (...args) => {
|
||||
window.clearTimeout(timeoutId);
|
||||
timeoutId = window.setTimeout(() => {
|
||||
callback.apply(null, args);
|
||||
}, delayMs);
|
||||
return ( ...args ) => {
|
||||
window.clearTimeout( timeoutId );
|
||||
timeoutId = window.setTimeout( () => {
|
||||
callback.apply( null, args );
|
||||
}, delayMs );
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
|
||||
import {CardFields} from "./Components/card-fields";
|
||||
import { CardFields } from './Components/card-fields';
|
||||
|
||||
const config = wc.wcSettings.getSetting('ppcp-credit-card-gateway_data');
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
registerPaymentMethod({
|
||||
registerPaymentMethod( {
|
||||
name: config.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
||||
content: <CardFields config={config}/>,
|
||||
label: <div dangerouslySetInnerHTML={ { __html: config.title } } />,
|
||||
content: <CardFields config={ config } />,
|
||||
edit: <div></div>,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: () => {return true},
|
||||
canMakePayment: () => {
|
||||
return true;
|
||||
},
|
||||
supports: {
|
||||
showSavedCards: true,
|
||||
features: config.supports
|
||||
}
|
||||
})
|
||||
features: config.supports,
|
||||
},
|
||||
} );
|
||||
|
|
|
@ -1,45 +1,46 @@
|
|||
export async function createOrder() {
|
||||
const config = wc.wcSettings.getSetting('ppcp-credit-card-gateway_data');
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
return fetch(config.scriptData.ajax.create_order.endpoint, {
|
||||
method: "POST",
|
||||
return fetch( config.scriptData.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: config.scriptData.ajax.create_order.nonce,
|
||||
context: config.scriptData.context,
|
||||
payment_method: 'ppcp-credit-card-gateway',
|
||||
save_payment_method: localStorage.getItem('ppcp-save-card-payment') === 'true',
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((order) => {
|
||||
save_payment_method:
|
||||
localStorage.getItem( 'ppcp-save-card-payment' ) === 'true',
|
||||
} ),
|
||||
} )
|
||||
.then( ( response ) => response.json() )
|
||||
.then( ( order ) => {
|
||||
return order.data.id;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
} )
|
||||
.catch( ( err ) => {
|
||||
console.error( err );
|
||||
} );
|
||||
}
|
||||
|
||||
export async function onApprove(data) {
|
||||
const config = wc.wcSettings.getSetting('ppcp-credit-card-gateway_data');
|
||||
export async function onApprove( data ) {
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
return fetch(config.scriptData.ajax.approve_order.endpoint, {
|
||||
method: "POST",
|
||||
return fetch( config.scriptData.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
order_id: data.orderID,
|
||||
nonce: config.scriptData.ajax.approve_order.nonce,
|
||||
}),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
localStorage.removeItem('ppcp-save-card-payment');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
} ),
|
||||
} )
|
||||
.then( ( response ) => response.json() )
|
||||
.then( ( data ) => {
|
||||
localStorage.removeItem( 'ppcp-save-card-payment' );
|
||||
} )
|
||||
.catch( ( err ) => {
|
||||
console.error( err );
|
||||
} );
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,34 +1,34 @@
|
|||
import {render, screen} from '@testing-library/react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import '@testing-library/jest-dom';
|
||||
import {CheckoutHandler} from "../Components/checkout-handler";
|
||||
import { CheckoutHandler } from '../Components/checkout-handler';
|
||||
|
||||
test('checkbox label displays the given text', async () => {
|
||||
test( 'checkbox label displays the given text', async () => {
|
||||
render(
|
||||
<CheckoutHandler
|
||||
getCardFieldsForm={() => {}}
|
||||
getCardFieldsForm={ () => {} }
|
||||
saveCardText="Foo"
|
||||
is_vaulting_enabled={true}
|
||||
is_vaulting_enabled={ true }
|
||||
/>
|
||||
);
|
||||
|
||||
await expect(screen.getByLabelText('Foo')).toBeInTheDocument();
|
||||
});
|
||||
await expect( screen.getByLabelText( 'Foo' ) ).toBeInTheDocument();
|
||||
} );
|
||||
|
||||
test('click checkbox calls function passing checked value', async () => {
|
||||
test( 'click checkbox calls function passing checked value', async () => {
|
||||
const getSavePayment = jest.fn();
|
||||
|
||||
render(
|
||||
<CheckoutHandler
|
||||
getSavePayment={getSavePayment}
|
||||
getCardFieldsForm={() => {}}
|
||||
getSavePayment={ getSavePayment }
|
||||
getCardFieldsForm={ () => {} }
|
||||
saveCardText="Foo"
|
||||
is_vaulting_enabled={true}
|
||||
is_vaulting_enabled={ true }
|
||||
/>
|
||||
);
|
||||
|
||||
await userEvent.click(screen.getByLabelText('Foo'));
|
||||
await userEvent.click( screen.getByLabelText( 'Foo' ) );
|
||||
|
||||
await expect(getSavePayment.mock.calls).toHaveLength(1);
|
||||
await expect(getSavePayment.mock.calls[0][0]).toBe(true);
|
||||
});
|
||||
await expect( getSavePayment.mock.calls ).toHaveLength( 1 );
|
||||
await expect( getSavePayment.mock.calls[ 0 ][ 0 ] ).toBe( true );
|
||||
} );
|
||||
|
|
|
@ -52,7 +52,7 @@ class AdvancedCardPaymentMethod extends AbstractPaymentMethodType {
|
|||
*
|
||||
* @var Settings
|
||||
*/
|
||||
protected $settings;
|
||||
protected $plugin_settings;
|
||||
|
||||
/**
|
||||
* AdvancedCardPaymentMethod constructor.
|
||||
|
@ -75,7 +75,7 @@ class AdvancedCardPaymentMethod extends AbstractPaymentMethodType {
|
|||
$this->version = $version;
|
||||
$this->gateway = $gateway;
|
||||
$this->smart_button = $smart_button;
|
||||
$this->settings = $settings;
|
||||
$this->plugin_settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,8 +118,8 @@ class AdvancedCardPaymentMethod extends AbstractPaymentMethodType {
|
|||
'scriptData' => $script_data,
|
||||
'supports' => $this->gateway->supports,
|
||||
'save_card_text' => esc_html__( 'Save your card', 'woocommerce-paypal-payments' ),
|
||||
'is_vaulting_enabled' => $this->settings->has( 'vault_enabled_dcc' ) && $this->settings->get( 'vault_enabled_dcc' ),
|
||||
'card_icons' => $this->settings->has( 'card_icons' ) ? (array) $this->settings->get( 'card_icons' ) : array(),
|
||||
'is_vaulting_enabled' => $this->plugin_settings->has( 'vault_enabled_dcc' ) && $this->plugin_settings->get( 'vault_enabled_dcc' ),
|
||||
'card_icons' => $this->plugin_settings->has( 'card_icons' ) ? (array) $this->plugin_settings->get( 'card_icons' ) : array(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ use WooCommerce\PayPalCommerce\Button\Endpoint\RequestData;
|
|||
*/
|
||||
class UpdateShippingEndpoint implements EndpointInterface {
|
||||
const ENDPOINT = 'ppc-update-shipping';
|
||||
const WC_STORE_API_ENDPOINT = '/wp-json/wc/store/cart/';
|
||||
|
||||
/**
|
||||
* The Request Data Helper.
|
||||
|
|
|
@ -2,33 +2,35 @@ import MiniCartBootstap from './modules/ContextBootstrap/MiniCartBootstap';
|
|||
import SingleProductBootstap from './modules/ContextBootstrap/SingleProductBootstap';
|
||||
import CartBootstrap from './modules/ContextBootstrap/CartBootstap';
|
||||
import CheckoutBootstap from './modules/ContextBootstrap/CheckoutBootstap';
|
||||
import PayNowBootstrap from "./modules/ContextBootstrap/PayNowBootstrap";
|
||||
import PayNowBootstrap from './modules/ContextBootstrap/PayNowBootstrap';
|
||||
import Renderer from './modules/Renderer/Renderer';
|
||||
import ErrorHandler from './modules/ErrorHandler';
|
||||
import HostedFieldsRenderer from "./modules/Renderer/HostedFieldsRenderer";
|
||||
import CardFieldsRenderer from "./modules/Renderer/CardFieldsRenderer";
|
||||
import MessageRenderer from "./modules/Renderer/MessageRenderer";
|
||||
import Spinner from "./modules/Helper/Spinner";
|
||||
import HostedFieldsRenderer from './modules/Renderer/HostedFieldsRenderer';
|
||||
import CardFieldsRenderer from './modules/Renderer/CardFieldsRenderer';
|
||||
import MessageRenderer from './modules/Renderer/MessageRenderer';
|
||||
import Spinner from './modules/Helper/Spinner';
|
||||
import {
|
||||
getCurrentPaymentMethod,
|
||||
ORDER_BUTTON_SELECTOR,
|
||||
PaymentMethods
|
||||
} from "./modules/Helper/CheckoutMethodState";
|
||||
import {setVisibleByClass} from "./modules/Helper/Hiding";
|
||||
import {isChangePaymentPage} from "./modules/Helper/Subscriptions";
|
||||
import FreeTrialHandler from "./modules/ActionHandler/FreeTrialHandler";
|
||||
import MultistepCheckoutHelper from "./modules/Helper/MultistepCheckoutHelper";
|
||||
PaymentMethods,
|
||||
} from './modules/Helper/CheckoutMethodState';
|
||||
import { setVisibleByClass } from './modules/Helper/Hiding';
|
||||
import { isChangePaymentPage } from './modules/Helper/Subscriptions';
|
||||
import FreeTrialHandler from './modules/ActionHandler/FreeTrialHandler';
|
||||
import MultistepCheckoutHelper from './modules/Helper/MultistepCheckoutHelper';
|
||||
import FormSaver from './modules/Helper/FormSaver';
|
||||
import FormValidator from "./modules/Helper/FormValidator";
|
||||
import {loadPaypalScript} from "./modules/Helper/ScriptLoading";
|
||||
import buttonModuleWatcher from "./modules/ButtonModuleWatcher";
|
||||
import MessagesBootstrap from "./modules/ContextBootstrap/MessagesBootstap";
|
||||
import {apmButtonsInit} from "./modules/Helper/ApmButtons";
|
||||
import FormValidator from './modules/Helper/FormValidator';
|
||||
import { loadPaypalScript } from './modules/Helper/ScriptLoading';
|
||||
import buttonModuleWatcher from './modules/ButtonModuleWatcher';
|
||||
import MessagesBootstrap from './modules/ContextBootstrap/MessagesBootstap';
|
||||
import { apmButtonsInit } from './modules/Helper/ApmButtons';
|
||||
|
||||
// TODO: could be a good idea to have a separate spinner for each gateway,
|
||||
// but I think we care mainly about the script loading, so one spinner should be enough.
|
||||
const buttonsSpinner = new Spinner(document.querySelector('.ppc-button-wrapper'));
|
||||
const cardsSpinner = new Spinner('#ppcp-hosted-fields');
|
||||
const buttonsSpinner = new Spinner(
|
||||
document.querySelector( '.ppc-button-wrapper' )
|
||||
);
|
||||
const cardsSpinner = new Spinner( '#ppcp-hosted-fields' );
|
||||
|
||||
const bootstrap = () => {
|
||||
const checkoutFormSelector = 'form.woocommerce-checkout';
|
||||
|
@ -37,76 +39,117 @@ const bootstrap = () => {
|
|||
|
||||
const errorHandler = new ErrorHandler(
|
||||
PayPalCommerceGateway.labels.error.generic,
|
||||
document.querySelector(checkoutFormSelector) ?? document.querySelector('.woocommerce-notices-wrapper')
|
||||
document.querySelector( checkoutFormSelector ) ??
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
const spinner = new Spinner();
|
||||
|
||||
const formSaver = new FormSaver(
|
||||
PayPalCommerceGateway.ajax.save_checkout_form.endpoint,
|
||||
PayPalCommerceGateway.ajax.save_checkout_form.nonce,
|
||||
PayPalCommerceGateway.ajax.save_checkout_form.nonce
|
||||
);
|
||||
|
||||
const formValidator = PayPalCommerceGateway.early_checkout_validation_enabled ?
|
||||
new FormValidator(
|
||||
const formValidator =
|
||||
PayPalCommerceGateway.early_checkout_validation_enabled
|
||||
? new FormValidator(
|
||||
PayPalCommerceGateway.ajax.validate_checkout.endpoint,
|
||||
PayPalCommerceGateway.ajax.validate_checkout.nonce,
|
||||
) : null;
|
||||
PayPalCommerceGateway.ajax.validate_checkout.nonce
|
||||
)
|
||||
: null;
|
||||
|
||||
const freeTrialHandler = new FreeTrialHandler(PayPalCommerceGateway, checkoutFormSelector, formSaver, formValidator, spinner, errorHandler);
|
||||
const freeTrialHandler = new FreeTrialHandler(
|
||||
PayPalCommerceGateway,
|
||||
checkoutFormSelector,
|
||||
formSaver,
|
||||
formValidator,
|
||||
spinner,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
new MultistepCheckoutHelper(checkoutFormSelector);
|
||||
new MultistepCheckoutHelper( checkoutFormSelector );
|
||||
|
||||
jQuery('form.woocommerce-checkout input').on('keydown', e => {
|
||||
if (e.key === 'Enter' && [
|
||||
jQuery( 'form.woocommerce-checkout input' ).on( 'keydown', ( e ) => {
|
||||
if (
|
||||
e.key === 'Enter' &&
|
||||
[
|
||||
PaymentMethods.PAYPAL,
|
||||
PaymentMethods.CARDS,
|
||||
PaymentMethods.CARD_BUTTON,
|
||||
].includes(getCurrentPaymentMethod())) {
|
||||
].includes( getCurrentPaymentMethod() )
|
||||
) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
const hasMessages = () => {
|
||||
return PayPalCommerceGateway.messages.is_hidden === false
|
||||
&& document.querySelector(PayPalCommerceGateway.messages.wrapper);
|
||||
}
|
||||
return (
|
||||
PayPalCommerceGateway.messages.is_hidden === false &&
|
||||
document.querySelector( PayPalCommerceGateway.messages.wrapper )
|
||||
);
|
||||
};
|
||||
|
||||
const doBasicCheckoutValidation = () => {
|
||||
if (PayPalCommerceGateway.basic_checkout_validation_enabled) {
|
||||
if ( PayPalCommerceGateway.basic_checkout_validation_enabled ) {
|
||||
// A quick fix to get the errors about empty form fields before attempting PayPal order,
|
||||
// it should solve #513 for most of the users, but it is not a proper solution.
|
||||
// Currently it is disabled by default because a better solution is now implemented
|
||||
// (see woocommerce_paypal_payments_basic_checkout_validation_enabled,
|
||||
// woocommerce_paypal_payments_early_wc_checkout_validation_enabled filters).
|
||||
const invalidFields = Array.from(jQuery('form.woocommerce-checkout .validate-required.woocommerce-invalid:visible'));
|
||||
if (invalidFields.length) {
|
||||
const billingFieldsContainer = document.querySelector('.woocommerce-billing-fields');
|
||||
const shippingFieldsContainer = document.querySelector('.woocommerce-shipping-fields');
|
||||
const invalidFields = Array.from(
|
||||
jQuery(
|
||||
'form.woocommerce-checkout .validate-required.woocommerce-invalid:visible'
|
||||
)
|
||||
);
|
||||
if ( invalidFields.length ) {
|
||||
const billingFieldsContainer = document.querySelector(
|
||||
'.woocommerce-billing-fields'
|
||||
);
|
||||
const shippingFieldsContainer = document.querySelector(
|
||||
'.woocommerce-shipping-fields'
|
||||
);
|
||||
|
||||
const nameMessageMap = PayPalCommerceGateway.labels.error.required.elements;
|
||||
const messages = invalidFields.map(el => {
|
||||
const name = el.querySelector('[name]')?.getAttribute('name');
|
||||
if (name && name in nameMessageMap) {
|
||||
return nameMessageMap[name];
|
||||
const nameMessageMap =
|
||||
PayPalCommerceGateway.labels.error.required.elements;
|
||||
const messages = invalidFields
|
||||
.map( ( el ) => {
|
||||
const name = el
|
||||
.querySelector( '[name]' )
|
||||
?.getAttribute( 'name' );
|
||||
if ( name && name in nameMessageMap ) {
|
||||
return nameMessageMap[ name ];
|
||||
}
|
||||
let label = el.querySelector('label').textContent
|
||||
.replaceAll('*', '')
|
||||
let label = el
|
||||
.querySelector( 'label' )
|
||||
.textContent.replaceAll( '*', '' )
|
||||
.trim();
|
||||
if (billingFieldsContainer?.contains(el)) {
|
||||
label = PayPalCommerceGateway.labels.billing_field.replace('%s', label);
|
||||
if ( billingFieldsContainer?.contains( el ) ) {
|
||||
label =
|
||||
PayPalCommerceGateway.labels.billing_field.replace(
|
||||
'%s',
|
||||
label
|
||||
);
|
||||
}
|
||||
if (shippingFieldsContainer?.contains(el)) {
|
||||
label = PayPalCommerceGateway.labels.shipping_field.replace('%s', label);
|
||||
if ( shippingFieldsContainer?.contains( el ) ) {
|
||||
label =
|
||||
PayPalCommerceGateway.labels.shipping_field.replace(
|
||||
'%s',
|
||||
label
|
||||
);
|
||||
}
|
||||
return PayPalCommerceGateway.labels.error.required.field
|
||||
.replace('%s', `<strong>${label}</strong>`)
|
||||
}).filter(s => s.length > 2);
|
||||
return PayPalCommerceGateway.labels.error.required.field.replace(
|
||||
'%s',
|
||||
`<strong>${ label }</strong>`
|
||||
);
|
||||
} )
|
||||
.filter( ( s ) => s.length > 2 );
|
||||
|
||||
errorHandler.clear();
|
||||
if (messages.length) {
|
||||
errorHandler.messages(messages);
|
||||
if ( messages.length ) {
|
||||
errorHandler.messages( messages );
|
||||
} else {
|
||||
errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);
|
||||
errorHandler.message(
|
||||
PayPalCommerceGateway.labels.error.required.generic
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -119,150 +162,178 @@ const bootstrap = () => {
|
|||
return doBasicCheckoutValidation();
|
||||
};
|
||||
|
||||
const onSmartButtonClick = async (data, actions) => {
|
||||
const onSmartButtonClick = async ( data, actions ) => {
|
||||
window.ppcpFundingSource = data.fundingSource;
|
||||
const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
|
||||
requiredFields.each((i, input) => {
|
||||
jQuery(input).trigger('validate');
|
||||
});
|
||||
const requiredFields = jQuery(
|
||||
'form.woocommerce-checkout .validate-required:visible :input'
|
||||
);
|
||||
requiredFields.each( ( i, input ) => {
|
||||
jQuery( input ).trigger( 'validate' );
|
||||
} );
|
||||
|
||||
if (!doBasicCheckoutValidation()) {
|
||||
if ( ! doBasicCheckoutValidation() ) {
|
||||
return actions.reject();
|
||||
}
|
||||
|
||||
const form = document.querySelector(checkoutFormSelector);
|
||||
if (form) {
|
||||
jQuery('#ppcp-funding-source-form-input').remove();
|
||||
const form = document.querySelector( checkoutFormSelector );
|
||||
if ( form ) {
|
||||
jQuery( '#ppcp-funding-source-form-input' ).remove();
|
||||
form.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`<input type="hidden" name="ppcp-funding-source" value="${data.fundingSource}" id="ppcp-funding-source-form-input">`
|
||||
)
|
||||
`<input type="hidden" name="ppcp-funding-source" value="${ data.fundingSource }" id="ppcp-funding-source-form-input">`
|
||||
);
|
||||
}
|
||||
|
||||
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
||||
if (
|
||||
isFreeTrial
|
||||
&& data.fundingSource !== 'card'
|
||||
&& ! PayPalCommerceGateway.subscription_plan_id
|
||||
&& ! PayPalCommerceGateway.vault_v3_enabled
|
||||
isFreeTrial &&
|
||||
data.fundingSource !== 'card' &&
|
||||
! PayPalCommerceGateway.subscription_plan_id &&
|
||||
! PayPalCommerceGateway.vault_v3_enabled
|
||||
) {
|
||||
freeTrialHandler.handle();
|
||||
return actions.reject();
|
||||
}
|
||||
|
||||
if (context === 'checkout') {
|
||||
if ( context === 'checkout' ) {
|
||||
try {
|
||||
await formSaver.save(form);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await formSaver.save( form );
|
||||
} catch ( error ) {
|
||||
console.error( error );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onSmartButtonsInit = () => {
|
||||
jQuery(document).trigger('ppcp-smart-buttons-init', this);
|
||||
jQuery( document ).trigger( 'ppcp-smart-buttons-init', this );
|
||||
buttonsSpinner.unblock();
|
||||
};
|
||||
|
||||
let creditCardRenderer = new HostedFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner);
|
||||
if (typeof paypal.CardFields !== 'undefined') {
|
||||
creditCardRenderer = new CardFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner, onCardFieldsBeforeSubmit);
|
||||
let creditCardRenderer = new HostedFieldsRenderer(
|
||||
PayPalCommerceGateway,
|
||||
errorHandler,
|
||||
spinner
|
||||
);
|
||||
if ( typeof paypal.CardFields !== 'undefined' ) {
|
||||
creditCardRenderer = new CardFieldsRenderer(
|
||||
PayPalCommerceGateway,
|
||||
errorHandler,
|
||||
spinner,
|
||||
onCardFieldsBeforeSubmit
|
||||
);
|
||||
}
|
||||
|
||||
const renderer = new Renderer(creditCardRenderer, PayPalCommerceGateway, onSmartButtonClick, onSmartButtonsInit);
|
||||
const messageRenderer = new MessageRenderer(PayPalCommerceGateway.messages);
|
||||
const renderer = new Renderer(
|
||||
creditCardRenderer,
|
||||
PayPalCommerceGateway,
|
||||
onSmartButtonClick,
|
||||
onSmartButtonsInit
|
||||
);
|
||||
const messageRenderer = new MessageRenderer(
|
||||
PayPalCommerceGateway.messages
|
||||
);
|
||||
|
||||
if (PayPalCommerceGateway.mini_cart_buttons_enabled === '1') {
|
||||
if ( PayPalCommerceGateway.mini_cart_buttons_enabled === '1' ) {
|
||||
const miniCartBootstrap = new MiniCartBootstap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
miniCartBootstrap.init();
|
||||
buttonModuleWatcher.registerContextBootstrap('mini-cart', miniCartBootstrap);
|
||||
buttonModuleWatcher.registerContextBootstrap(
|
||||
'mini-cart',
|
||||
miniCartBootstrap
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
context === 'product'
|
||||
&& (
|
||||
PayPalCommerceGateway.single_product_buttons_enabled === '1'
|
||||
|| hasMessages()
|
||||
)
|
||||
context === 'product' &&
|
||||
( PayPalCommerceGateway.single_product_buttons_enabled === '1' ||
|
||||
hasMessages() )
|
||||
) {
|
||||
const singleProductBootstrap = new SingleProductBootstap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
singleProductBootstrap.init();
|
||||
buttonModuleWatcher.registerContextBootstrap('product', singleProductBootstrap);
|
||||
buttonModuleWatcher.registerContextBootstrap(
|
||||
'product',
|
||||
singleProductBootstrap
|
||||
);
|
||||
}
|
||||
|
||||
if (context === 'cart') {
|
||||
if ( context === 'cart' ) {
|
||||
const cartBootstrap = new CartBootstrap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
cartBootstrap.init();
|
||||
buttonModuleWatcher.registerContextBootstrap('cart', cartBootstrap);
|
||||
buttonModuleWatcher.registerContextBootstrap( 'cart', cartBootstrap );
|
||||
}
|
||||
|
||||
if (context === 'checkout') {
|
||||
if ( context === 'checkout' ) {
|
||||
const checkoutBootstap = new CheckoutBootstap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
spinner,
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
checkoutBootstap.init();
|
||||
buttonModuleWatcher.registerContextBootstrap('checkout', checkoutBootstap);
|
||||
buttonModuleWatcher.registerContextBootstrap(
|
||||
'checkout',
|
||||
checkoutBootstap
|
||||
);
|
||||
}
|
||||
|
||||
if (context === 'pay-now' ) {
|
||||
if ( context === 'pay-now' ) {
|
||||
const payNowBootstrap = new PayNowBootstrap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
spinner,
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
payNowBootstrap.init();
|
||||
buttonModuleWatcher.registerContextBootstrap('pay-now', payNowBootstrap);
|
||||
buttonModuleWatcher.registerContextBootstrap(
|
||||
'pay-now',
|
||||
payNowBootstrap
|
||||
);
|
||||
}
|
||||
|
||||
const messagesBootstrap = new MessagesBootstrap(
|
||||
PayPalCommerceGateway,
|
||||
messageRenderer,
|
||||
messageRenderer
|
||||
);
|
||||
messagesBootstrap.init();
|
||||
|
||||
apmButtonsInit(PayPalCommerceGateway);
|
||||
apmButtonsInit( PayPalCommerceGateway );
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
if (!typeof (PayPalCommerceGateway)) {
|
||||
console.error('PayPal button could not be configured.');
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
if ( ! typeof PayPalCommerceGateway ) {
|
||||
console.error( 'PayPal button could not be configured.' );
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
PayPalCommerceGateway.context !== 'checkout'
|
||||
&& PayPalCommerceGateway.data_client_id.user === 0
|
||||
&& PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
PayPalCommerceGateway.context !== 'checkout' &&
|
||||
PayPalCommerceGateway.data_client_id.user === 0 &&
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const paypalButtonGatewayIds = [
|
||||
PaymentMethods.PAYPAL,
|
||||
...Object.entries(PayPalCommerceGateway.separate_buttons).map(([k, data]) => data.id),
|
||||
]
|
||||
...Object.entries( PayPalCommerceGateway.separate_buttons ).map(
|
||||
( [ k, data ] ) => data.id
|
||||
),
|
||||
];
|
||||
|
||||
// Sometimes PayPal script takes long time to load,
|
||||
// so we additionally hide the standard order button here to avoid failed orders.
|
||||
|
@ -271,60 +342,74 @@ document.addEventListener(
|
|||
// only in checkout and pay now page, otherwise it may break things (e.g. payment via product page),
|
||||
// and also the loading spinner may look weird on other pages
|
||||
if (
|
||||
!['checkout', 'pay-now'].includes(PayPalCommerceGateway.context)
|
||||
|| isChangePaymentPage()
|
||||
|| (PayPalCommerceGateway.is_free_trial_cart && PayPalCommerceGateway.vaulted_paypal_email !== '')
|
||||
! [ 'checkout', 'pay-now' ].includes(
|
||||
PayPalCommerceGateway.context
|
||||
) ||
|
||||
isChangePaymentPage() ||
|
||||
( PayPalCommerceGateway.is_free_trial_cart &&
|
||||
PayPalCommerceGateway.vaulted_paypal_email !== '' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPaymentMethod = getCurrentPaymentMethod();
|
||||
const isPaypalButton = paypalButtonGatewayIds.includes(currentPaymentMethod);
|
||||
const isPaypalButton =
|
||||
paypalButtonGatewayIds.includes( currentPaymentMethod );
|
||||
const isCards = currentPaymentMethod === PaymentMethods.CARDS;
|
||||
|
||||
setVisibleByClass(ORDER_BUTTON_SELECTOR, !isPaypalButton && !isCards, 'ppcp-hidden');
|
||||
setVisibleByClass(
|
||||
ORDER_BUTTON_SELECTOR,
|
||||
! isPaypalButton && ! isCards,
|
||||
'ppcp-hidden'
|
||||
);
|
||||
|
||||
if (isPaypalButton) {
|
||||
if ( isPaypalButton ) {
|
||||
// stopped after the first rendering of the buttons, in onInit
|
||||
buttonsSpinner.block();
|
||||
} else {
|
||||
buttonsSpinner.unblock();
|
||||
}
|
||||
|
||||
if (isCards) {
|
||||
if ( isCards ) {
|
||||
cardsSpinner.block();
|
||||
} else {
|
||||
cardsSpinner.unblock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jQuery(document).on('hosted_fields_loaded', () => {
|
||||
jQuery( document ).on( 'hosted_fields_loaded', () => {
|
||||
cardsSpinner.unblock();
|
||||
});
|
||||
} );
|
||||
|
||||
let bootstrapped = false;
|
||||
let failed = false;
|
||||
|
||||
hideOrderButtonIfPpcpGateway();
|
||||
|
||||
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
|
||||
if (bootstrapped || failed) {
|
||||
jQuery( document.body ).on(
|
||||
'updated_checkout payment_method_selected',
|
||||
() => {
|
||||
if ( bootstrapped || failed ) {
|
||||
return;
|
||||
}
|
||||
|
||||
hideOrderButtonIfPpcpGateway();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
loadPaypalScript(PayPalCommerceGateway, () => {
|
||||
loadPaypalScript(
|
||||
PayPalCommerceGateway,
|
||||
() => {
|
||||
bootstrapped = true;
|
||||
|
||||
bootstrap();
|
||||
}, () => {
|
||||
},
|
||||
() => {
|
||||
failed = true;
|
||||
|
||||
setVisibleByClass(ORDER_BUTTON_SELECTOR, true, 'ppcp-hidden');
|
||||
setVisibleByClass( ORDER_BUTTON_SELECTOR, true, 'ppcp-hidden' );
|
||||
buttonsSpinner.unblock();
|
||||
cardsSpinner.unblock();
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
);
|
||||
} );
|
||||
|
|
|
@ -1,87 +1,97 @@
|
|||
import onApprove from '../OnApproveHandler/onApproveForContinue.js';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
||||
import { payerData } from '../Helper/PayerData';
|
||||
import { PaymentMethods } from '../Helper/CheckoutMethodState';
|
||||
|
||||
class CartActionHandler {
|
||||
|
||||
constructor(config, errorHandler) {
|
||||
constructor( config, errorHandler ) {
|
||||
this.config = config;
|
||||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
subscriptionsConfiguration(subscription_plan_id) {
|
||||
subscriptionsConfiguration( subscription_plan_id ) {
|
||||
return {
|
||||
createSubscription: (data, actions) => {
|
||||
return actions.subscription.create({
|
||||
'plan_id': subscription_plan_id
|
||||
});
|
||||
createSubscription: ( data, actions ) => {
|
||||
return actions.subscription.create( {
|
||||
plan_id: subscription_plan_id,
|
||||
} );
|
||||
},
|
||||
onApprove: (data, actions) => {
|
||||
fetch(this.config.ajax.approve_subscription.endpoint, {
|
||||
onApprove: ( data, actions ) => {
|
||||
fetch( this.config.ajax.approve_subscription.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.approve_subscription.nonce,
|
||||
order_id: data.orderID,
|
||||
subscription_id: data.subscriptionID,
|
||||
should_create_wc_order: !context.config.vaultingEnabled || data.paymentSource !== 'venmo'
|
||||
})
|
||||
}).then((res)=>{
|
||||
should_create_wc_order:
|
||||
! context.config.vaultingEnabled ||
|
||||
data.paymentSource !== 'venmo',
|
||||
} ),
|
||||
} )
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data) => {
|
||||
if (!data.success) {
|
||||
console.log(data)
|
||||
throw Error(data.data.message);
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
if ( ! data.success ) {
|
||||
console.log( data );
|
||||
throw Error( data.data.message );
|
||||
}
|
||||
|
||||
let orderReceivedUrl = data.data?.order_received_url
|
||||
const orderReceivedUrl = data.data?.order_received_url;
|
||||
|
||||
location.href = orderReceivedUrl ? orderReceivedUrl : context.config.redirect;
|
||||
});
|
||||
location.href = orderReceivedUrl
|
||||
? orderReceivedUrl
|
||||
: context.config.redirect;
|
||||
} );
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
onError: ( err ) => {
|
||||
console.error( err );
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
configuration() {
|
||||
const createOrder = (data, actions) => {
|
||||
const createOrder = ( data, actions ) => {
|
||||
const payer = payerData();
|
||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||
this.config.bn_codes[this.config.context] : '';
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
const bnCode =
|
||||
typeof this.config.bn_codes[ this.config.context ] !==
|
||||
'undefined'
|
||||
? this.config.bn_codes[ this.config.context ]
|
||||
: '';
|
||||
return fetch( this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.create_order.nonce,
|
||||
purchase_units: [],
|
||||
payment_method: PaymentMethods.PAYPAL,
|
||||
funding_source: window.ppcpFundingSource,
|
||||
bn_code:bnCode,
|
||||
bn_code: bnCode,
|
||||
payer,
|
||||
context:this.config.context
|
||||
}),
|
||||
}).then(function(res) {
|
||||
context: this.config.context,
|
||||
} ),
|
||||
} )
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(function(data) {
|
||||
if (!data.success) {
|
||||
console.error(data);
|
||||
throw Error(data.data.message);
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
if ( ! data.success ) {
|
||||
console.error( data );
|
||||
throw Error( data.data.message );
|
||||
}
|
||||
return data.data.id;
|
||||
});
|
||||
} );
|
||||
};
|
||||
|
||||
return {
|
||||
createOrder,
|
||||
onApprove: onApprove(this, this.errorHandler),
|
||||
onError: (error) => {
|
||||
onApprove: onApprove( this, this.errorHandler ),
|
||||
onError: ( error ) => {
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,196 +1,232 @@
|
|||
import 'formdata-polyfill';
|
||||
import onApprove from '../OnApproveHandler/onApproveForPayNow.js';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
import {getCurrentPaymentMethod} from "../Helper/CheckoutMethodState";
|
||||
import validateCheckoutForm from "../Helper/CheckoutFormValidation";
|
||||
import { payerData } from '../Helper/PayerData';
|
||||
import { getCurrentPaymentMethod } from '../Helper/CheckoutMethodState';
|
||||
import validateCheckoutForm from '../Helper/CheckoutFormValidation';
|
||||
|
||||
class CheckoutActionHandler {
|
||||
|
||||
constructor(config, errorHandler, spinner) {
|
||||
constructor( config, errorHandler, spinner ) {
|
||||
this.config = config;
|
||||
this.errorHandler = errorHandler;
|
||||
this.spinner = spinner;
|
||||
}
|
||||
|
||||
subscriptionsConfiguration(subscription_plan_id) {
|
||||
subscriptionsConfiguration( subscription_plan_id ) {
|
||||
return {
|
||||
createSubscription: async (data, actions) => {
|
||||
createSubscription: async ( data, actions ) => {
|
||||
try {
|
||||
await validateCheckoutForm(this.config);
|
||||
} catch (error) {
|
||||
throw {type: 'form-validation-error'};
|
||||
await validateCheckoutForm( this.config );
|
||||
} catch ( error ) {
|
||||
throw { type: 'form-validation-error' };
|
||||
}
|
||||
|
||||
return actions.subscription.create({
|
||||
'plan_id': subscription_plan_id
|
||||
});
|
||||
return actions.subscription.create( {
|
||||
plan_id: subscription_plan_id,
|
||||
} );
|
||||
},
|
||||
onApprove: (data, actions) => {
|
||||
fetch(this.config.ajax.approve_subscription.endpoint, {
|
||||
onApprove: ( data, actions ) => {
|
||||
fetch( this.config.ajax.approve_subscription.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.approve_subscription.nonce,
|
||||
order_id: data.orderID,
|
||||
subscription_id: data.subscriptionID
|
||||
})
|
||||
}).then((res)=>{
|
||||
subscription_id: data.subscriptionID,
|
||||
} ),
|
||||
} )
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data) => {
|
||||
document.querySelector('#place_order').click();
|
||||
});
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
document.querySelector( '#place_order' ).click();
|
||||
} );
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
onError: ( err ) => {
|
||||
console.error( err );
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
configuration() {
|
||||
const spinner = this.spinner;
|
||||
const createOrder = (data, actions) => {
|
||||
const createOrder = ( data, actions ) => {
|
||||
const payer = payerData();
|
||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||
this.config.bn_codes[this.config.context] : '';
|
||||
const bnCode =
|
||||
typeof this.config.bn_codes[ this.config.context ] !==
|
||||
'undefined'
|
||||
? this.config.bn_codes[ this.config.context ]
|
||||
: '';
|
||||
|
||||
const errorHandler = this.errorHandler;
|
||||
|
||||
const formSelector = this.config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
|
||||
const formData = new FormData(document.querySelector(formSelector));
|
||||
const formSelector =
|
||||
this.config.context === 'checkout'
|
||||
? 'form.checkout'
|
||||
: 'form#order_review';
|
||||
const formData = new FormData(
|
||||
document.querySelector( formSelector )
|
||||
);
|
||||
|
||||
const createaccount = jQuery('#createaccount').is(":checked") ? true : false;
|
||||
const createaccount = jQuery( '#createaccount' ).is( ':checked' )
|
||||
? true
|
||||
: false;
|
||||
|
||||
const paymentMethod = getCurrentPaymentMethod();
|
||||
const fundingSource = window.ppcpFundingSource;
|
||||
|
||||
const savePaymentMethod = !!document.getElementById('wc-ppcp-credit-card-gateway-new-payment-method')?.checked;
|
||||
const savePaymentMethod = !! document.getElementById(
|
||||
'wc-ppcp-credit-card-gateway-new-payment-method'
|
||||
)?.checked;
|
||||
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
return fetch( this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.create_order.nonce,
|
||||
payer,
|
||||
bn_code:bnCode,
|
||||
context:this.config.context,
|
||||
order_id:this.config.order_id,
|
||||
bn_code: bnCode,
|
||||
context: this.config.context,
|
||||
order_id: this.config.order_id,
|
||||
payment_method: paymentMethod,
|
||||
funding_source: fundingSource,
|
||||
// send as urlencoded string to handle complex fields via PHP functions the same as normal form submit
|
||||
form_encoded: new URLSearchParams(formData).toString(),
|
||||
createaccount: createaccount,
|
||||
save_payment_method: savePaymentMethod
|
||||
})
|
||||
}).then(function (res) {
|
||||
form_encoded: new URLSearchParams( formData ).toString(),
|
||||
createaccount,
|
||||
save_payment_method: savePaymentMethod,
|
||||
} ),
|
||||
} )
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(function (data) {
|
||||
if (!data.success) {
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
if ( ! data.success ) {
|
||||
spinner.unblock();
|
||||
//handle both messages sent from Woocommerce (data.messages) and this plugin (data.data.message)
|
||||
if (typeof(data.messages) !== 'undefined' )
|
||||
{
|
||||
if ( typeof data.messages !== 'undefined' ) {
|
||||
const domParser = new DOMParser();
|
||||
errorHandler.appendPreparedErrorMessageElement(
|
||||
domParser.parseFromString(data.messages, 'text/html')
|
||||
.querySelector('ul')
|
||||
domParser
|
||||
.parseFromString(
|
||||
data.messages,
|
||||
'text/html'
|
||||
)
|
||||
.querySelector( 'ul' )
|
||||
);
|
||||
} else {
|
||||
errorHandler.clear();
|
||||
|
||||
if (data.data.refresh) {
|
||||
jQuery( document.body ).trigger( 'update_checkout' );
|
||||
if ( data.data.refresh ) {
|
||||
jQuery( document.body ).trigger(
|
||||
'update_checkout'
|
||||
);
|
||||
}
|
||||
|
||||
if (data.data.errors?.length > 0) {
|
||||
errorHandler.messages(data.data.errors);
|
||||
} else if (data.data.details?.length > 0) {
|
||||
errorHandler.message(data.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
if ( data.data.errors?.length > 0 ) {
|
||||
errorHandler.messages( data.data.errors );
|
||||
} else if ( data.data.details?.length > 0 ) {
|
||||
errorHandler.message(
|
||||
data.data.details
|
||||
.map(
|
||||
( d ) =>
|
||||
`${ d.issue } ${ d.description }`
|
||||
)
|
||||
.join( '<br/>' )
|
||||
);
|
||||
} else {
|
||||
errorHandler.message(data.data.message);
|
||||
errorHandler.message( data.data.message );
|
||||
}
|
||||
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
jQuery( document.body ).trigger( 'checkout_error', [
|
||||
errorHandler.currentHtml(),
|
||||
] );
|
||||
}
|
||||
|
||||
throw {type: 'create-order-error', data: data.data};
|
||||
throw { type: 'create-order-error', data: data.data };
|
||||
}
|
||||
const input = document.createElement('input');
|
||||
input.setAttribute('type', 'hidden');
|
||||
input.setAttribute('name', 'ppcp-resume-order');
|
||||
input.setAttribute('value', data.data.custom_id);
|
||||
document.querySelector(formSelector).appendChild(input);
|
||||
const input = document.createElement( 'input' );
|
||||
input.setAttribute( 'type', 'hidden' );
|
||||
input.setAttribute( 'name', 'ppcp-resume-order' );
|
||||
input.setAttribute( 'value', data.data.custom_id );
|
||||
document.querySelector( formSelector ).appendChild( input );
|
||||
return data.data.id;
|
||||
});
|
||||
}
|
||||
} );
|
||||
};
|
||||
return {
|
||||
createOrder,
|
||||
onApprove:onApprove(this, this.errorHandler, this.spinner),
|
||||
onApprove: onApprove( this, this.errorHandler, this.spinner ),
|
||||
onCancel: () => {
|
||||
spinner.unblock();
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
onError: ( err ) => {
|
||||
console.error( err );
|
||||
spinner.unblock();
|
||||
|
||||
if (err && err.type === 'create-order-error') {
|
||||
if ( err && err.type === 'create-order-error' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
addPaymentMethodConfiguration() {
|
||||
return {
|
||||
createVaultSetupToken: async () => {
|
||||
const response = await fetch(this.config.ajax.create_setup_token.endpoint, {
|
||||
method: "POST",
|
||||
const response = await fetch(
|
||||
this.config.ajax.create_setup_token.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.create_setup_token.nonce,
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json()
|
||||
if (result.data.id) {
|
||||
return result.data.id
|
||||
} ),
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
},
|
||||
onApprove: async ({vaultSetupToken}) => {
|
||||
const response = await fetch(this.config.ajax.create_payment_token_for_guest.endpoint, {
|
||||
method: "POST",
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
nonce: this.config.ajax.create_payment_token_for_guest.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
})
|
||||
})
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if (result.success === true) {
|
||||
document.querySelector('#place_order').click()
|
||||
if ( result.data.id ) {
|
||||
return result.data.id;
|
||||
}
|
||||
|
||||
console.error( result );
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const response = await fetch(
|
||||
this.config.ajax.create_payment_token_for_guest.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax
|
||||
.create_payment_token_for_guest.nonce,
|
||||
vault_setup_token: vaultSetupToken,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json();
|
||||
if ( result.success === true ) {
|
||||
document.querySelector( '#place_order' ).click();
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
console.error( result );
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
onError: ( error ) => {
|
||||
console.error( error );
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,57 +23,62 @@ class FreeTrialHandler {
|
|||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
async handle()
|
||||
{
|
||||
async handle() {
|
||||
this.spinner.block();
|
||||
|
||||
try {
|
||||
await this.formSaver.save(document.querySelector(this.formSelector));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await this.formSaver.save(
|
||||
document.querySelector( this.formSelector )
|
||||
);
|
||||
} catch ( error ) {
|
||||
console.error( error );
|
||||
}
|
||||
|
||||
try {
|
||||
if (this.formValidator) {
|
||||
if ( this.formValidator ) {
|
||||
try {
|
||||
const errors = await this.formValidator.validate(document.querySelector(this.formSelector));
|
||||
if (errors.length > 0) {
|
||||
const errors = await this.formValidator.validate(
|
||||
document.querySelector( this.formSelector )
|
||||
);
|
||||
if ( errors.length > 0 ) {
|
||||
this.spinner.unblock();
|
||||
this.errorHandler.messages(errors);
|
||||
this.errorHandler.messages( errors );
|
||||
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ this.errorHandler.currentHtml() ] );
|
||||
jQuery( document.body ).trigger( 'checkout_error', [
|
||||
this.errorHandler.currentHtml(),
|
||||
] );
|
||||
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} catch ( error ) {
|
||||
console.error( error );
|
||||
}
|
||||
}
|
||||
|
||||
const res = await fetch(this.config.ajax.vault_paypal.endpoint, {
|
||||
const res = await fetch( this.config.ajax.vault_paypal.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.vault_paypal.nonce,
|
||||
return_url: location.href,
|
||||
}),
|
||||
});
|
||||
} ),
|
||||
} );
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success) {
|
||||
throw Error(data.data.message);
|
||||
if ( ! data.success ) {
|
||||
throw Error( data.data.message );
|
||||
}
|
||||
|
||||
location.href = data.data.approve_link;
|
||||
} catch (error) {
|
||||
} catch ( error ) {
|
||||
this.spinner.unblock();
|
||||
console.error(error);
|
||||
this.errorHandler.message(data.data.message);
|
||||
console.error( error );
|
||||
this.errorHandler.message( data.data.message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
import Product from '../Entity/Product';
|
||||
import BookingProduct from "../Entity/BookingProduct";
|
||||
import BookingProduct from '../Entity/BookingProduct';
|
||||
import onApprove from '../OnApproveHandler/onApproveForContinue';
|
||||
import {payerData} from "../Helper/PayerData";
|
||||
import {PaymentMethods} from "../Helper/CheckoutMethodState";
|
||||
import CartHelper from "../Helper/CartHelper";
|
||||
import FormHelper from "../Helper/FormHelper";
|
||||
import { payerData } from '../Helper/PayerData';
|
||||
import { PaymentMethods } from '../Helper/CheckoutMethodState';
|
||||
import CartHelper from '../Helper/CartHelper';
|
||||
import FormHelper from '../Helper/FormHelper';
|
||||
|
||||
class SingleProductActionHandler {
|
||||
|
||||
constructor(
|
||||
config,
|
||||
updateCart,
|
||||
formElement,
|
||||
errorHandler
|
||||
) {
|
||||
constructor( config, updateCart, formElement, errorHandler ) {
|
||||
this.config = config;
|
||||
this.updateCart = updateCart;
|
||||
this.formElement = formElement;
|
||||
|
@ -21,72 +15,74 @@ class SingleProductActionHandler {
|
|||
this.cartHelper = null;
|
||||
}
|
||||
|
||||
subscriptionsConfiguration(subscription_plan) {
|
||||
subscriptionsConfiguration( subscription_plan ) {
|
||||
return {
|
||||
createSubscription: (data, actions) => {
|
||||
return actions.subscription.create({
|
||||
'plan_id': subscription_plan
|
||||
});
|
||||
createSubscription: ( data, actions ) => {
|
||||
return actions.subscription.create( {
|
||||
plan_id: subscription_plan,
|
||||
} );
|
||||
},
|
||||
onApprove: (data, actions) => {
|
||||
fetch(this.config.ajax.approve_subscription.endpoint, {
|
||||
onApprove: ( data, actions ) => {
|
||||
fetch( this.config.ajax.approve_subscription.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.approve_subscription.nonce,
|
||||
order_id: data.orderID,
|
||||
subscription_id: data.subscriptionID
|
||||
})
|
||||
}).then((res)=>{
|
||||
subscription_id: data.subscriptionID,
|
||||
} ),
|
||||
} )
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then(() => {
|
||||
} )
|
||||
.then( () => {
|
||||
const products = this.getSubscriptionProducts();
|
||||
|
||||
fetch(this.config.ajax.change_cart.endpoint, {
|
||||
fetch( this.config.ajax.change_cart.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.change_cart.nonce,
|
||||
products,
|
||||
})
|
||||
}).then((result) => {
|
||||
} ),
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
return result.json();
|
||||
}).then((result) => {
|
||||
if (!result.success) {
|
||||
console.log(result)
|
||||
throw Error(result.data.message);
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
console.log( result );
|
||||
throw Error( result.data.message );
|
||||
}
|
||||
|
||||
location.href = this.config.redirect;
|
||||
})
|
||||
});
|
||||
} );
|
||||
} );
|
||||
},
|
||||
onError: (err) => {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
onError: ( err ) => {
|
||||
console.error( err );
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getSubscriptionProducts()
|
||||
{
|
||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||
return [new Product(id, 1, this.variations(), this.extraFields())];
|
||||
getSubscriptionProducts() {
|
||||
const id = document.querySelector( '[name="add-to-cart"]' ).value;
|
||||
return [ new Product( id, 1, this.variations(), this.extraFields() ) ];
|
||||
}
|
||||
|
||||
configuration()
|
||||
{
|
||||
configuration() {
|
||||
return {
|
||||
createOrder: this.createOrder(),
|
||||
onApprove: onApprove(this, this.errorHandler),
|
||||
onError: (error) => {
|
||||
onApprove: onApprove( this, this.errorHandler ),
|
||||
onError: ( error ) => {
|
||||
this.refreshMiniCart();
|
||||
|
||||
if (this.isBookingProduct() && error.message) {
|
||||
if ( this.isBookingProduct() && error.message ) {
|
||||
this.errorHandler.clear();
|
||||
this.errorHandler.message(error.message);
|
||||
this.errorHandler.message( error.message );
|
||||
return;
|
||||
}
|
||||
this.errorHandler.genericError();
|
||||
|
@ -94,136 +90,158 @@ class SingleProductActionHandler {
|
|||
onCancel: () => {
|
||||
// Could be used for every product type,
|
||||
// but only clean the cart for Booking products for now.
|
||||
if (this.isBookingProduct()) {
|
||||
if ( this.isBookingProduct() ) {
|
||||
this.cleanCart();
|
||||
} else {
|
||||
this.refreshMiniCart();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getProducts()
|
||||
{
|
||||
getProducts() {
|
||||
if ( this.isBookingProduct() ) {
|
||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||
return [new BookingProduct(id, 1, FormHelper.getPrefixedFields(this.formElement, "wc_bookings_field"), this.extraFields())];
|
||||
const id = document.querySelector( '[name="add-to-cart"]' ).value;
|
||||
return [
|
||||
new BookingProduct(
|
||||
id,
|
||||
1,
|
||||
FormHelper.getPrefixedFields(
|
||||
this.formElement,
|
||||
'wc_bookings_field'
|
||||
),
|
||||
this.extraFields()
|
||||
),
|
||||
];
|
||||
} else if ( this.isGroupedProduct() ) {
|
||||
const products = [];
|
||||
this.formElement.querySelectorAll('input[type="number"]').forEach((element) => {
|
||||
if (! element.value) {
|
||||
this.formElement
|
||||
.querySelectorAll( 'input[type="number"]' )
|
||||
.forEach( ( element ) => {
|
||||
if ( ! element.value ) {
|
||||
return;
|
||||
}
|
||||
const elementName = element.getAttribute('name').match(/quantity\[([\d]*)\]/);
|
||||
if (elementName.length !== 2) {
|
||||
const elementName = element
|
||||
.getAttribute( 'name' )
|
||||
.match( /quantity\[([\d]*)\]/ );
|
||||
if ( elementName.length !== 2 ) {
|
||||
return;
|
||||
}
|
||||
const id = parseInt(elementName[1]);
|
||||
const quantity = parseInt(element.value);
|
||||
products.push(new Product(id, quantity, null, this.extraFields()));
|
||||
})
|
||||
const id = parseInt( elementName[ 1 ] );
|
||||
const quantity = parseInt( element.value );
|
||||
products.push(
|
||||
new Product( id, quantity, null, this.extraFields() )
|
||||
);
|
||||
} );
|
||||
return products;
|
||||
} else {
|
||||
const id = document.querySelector('[name="add-to-cart"]').value;
|
||||
const qty = document.querySelector('[name="quantity"]').value;
|
||||
const variations = this.variations();
|
||||
return [new Product(id, qty, variations, this.extraFields())];
|
||||
}
|
||||
const id = document.querySelector( '[name="add-to-cart"]' ).value;
|
||||
const qty = document.querySelector( '[name="quantity"]' ).value;
|
||||
const variations = this.variations();
|
||||
return [ new Product( id, qty, variations, this.extraFields() ) ];
|
||||
}
|
||||
|
||||
extraFields() {
|
||||
return FormHelper.getFilteredFields(
|
||||
this.formElement,
|
||||
['add-to-cart', 'quantity', 'product_id', 'variation_id'],
|
||||
['attribute_', 'wc_bookings_field']
|
||||
[ 'add-to-cart', 'quantity', 'product_id', 'variation_id' ],
|
||||
[ 'attribute_', 'wc_bookings_field' ]
|
||||
);
|
||||
}
|
||||
|
||||
createOrder()
|
||||
{
|
||||
createOrder() {
|
||||
this.cartHelper = null;
|
||||
|
||||
return (data, actions, options = {}) => {
|
||||
return ( data, actions, options = {} ) => {
|
||||
this.errorHandler.clear();
|
||||
|
||||
const onResolve = (purchase_units) => {
|
||||
this.cartHelper = (new CartHelper()).addFromPurchaseUnits(purchase_units);
|
||||
const onResolve = ( purchase_units ) => {
|
||||
this.cartHelper = new CartHelper().addFromPurchaseUnits(
|
||||
purchase_units
|
||||
);
|
||||
|
||||
const payer = payerData();
|
||||
const bnCode = typeof this.config.bn_codes[this.config.context] !== 'undefined' ?
|
||||
this.config.bn_codes[this.config.context] : '';
|
||||
return fetch(this.config.ajax.create_order.endpoint, {
|
||||
const bnCode =
|
||||
typeof this.config.bn_codes[ this.config.context ] !==
|
||||
'undefined'
|
||||
? this.config.bn_codes[ this.config.context ]
|
||||
: '';
|
||||
return fetch( this.config.ajax.create_order.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.create_order.nonce,
|
||||
purchase_units,
|
||||
payer,
|
||||
bn_code:bnCode,
|
||||
bn_code: bnCode,
|
||||
payment_method: PaymentMethods.PAYPAL,
|
||||
funding_source: window.ppcpFundingSource,
|
||||
context:this.config.context
|
||||
})
|
||||
}).then(function (res) {
|
||||
context: this.config.context,
|
||||
} ),
|
||||
} )
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(function (data) {
|
||||
if (!data.success) {
|
||||
console.error(data);
|
||||
throw Error(data.data.message);
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
if ( ! data.success ) {
|
||||
console.error( data );
|
||||
throw Error( data.data.message );
|
||||
}
|
||||
return data.data.id;
|
||||
});
|
||||
} );
|
||||
};
|
||||
|
||||
return this.updateCart.update(onResolve, this.getProducts(), options.updateCartOptions || {});
|
||||
return this.updateCart.update(
|
||||
onResolve,
|
||||
this.getProducts(),
|
||||
options.updateCartOptions || {}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
variations()
|
||||
{
|
||||
if (! this.hasVariations()) {
|
||||
variations() {
|
||||
if ( ! this.hasVariations() ) {
|
||||
return null;
|
||||
}
|
||||
return [...this.formElement.querySelectorAll("[name^='attribute_']")].map(
|
||||
(element) => {
|
||||
return [
|
||||
...this.formElement.querySelectorAll( "[name^='attribute_']" ),
|
||||
].map( ( element ) => {
|
||||
return {
|
||||
value:element.value,
|
||||
name:element.name
|
||||
}
|
||||
}
|
||||
);
|
||||
value: element.value,
|
||||
name: element.name,
|
||||
};
|
||||
} );
|
||||
}
|
||||
|
||||
hasVariations()
|
||||
{
|
||||
return this.formElement.classList.contains('variations_form');
|
||||
hasVariations() {
|
||||
return this.formElement.classList.contains( 'variations_form' );
|
||||
}
|
||||
|
||||
isGroupedProduct()
|
||||
{
|
||||
return this.formElement.classList.contains('grouped_form');
|
||||
isGroupedProduct() {
|
||||
return this.formElement.classList.contains( 'grouped_form' );
|
||||
}
|
||||
|
||||
isBookingProduct()
|
||||
{
|
||||
isBookingProduct() {
|
||||
// detection for "woocommerce-bookings" plugin
|
||||
return !!this.formElement.querySelector('.wc-booking-product-id');
|
||||
return !! this.formElement.querySelector( '.wc-booking-product-id' );
|
||||
}
|
||||
|
||||
cleanCart() {
|
||||
this.cartHelper.removeFromCart().then(() => {
|
||||
this.cartHelper
|
||||
.removeFromCart()
|
||||
.then( () => {
|
||||
this.refreshMiniCart();
|
||||
}).catch(error => {
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
this.refreshMiniCart();
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
refreshMiniCart() {
|
||||
jQuery(document.body).trigger('wc_fragment_refresh');
|
||||
jQuery( document.body ).trigger( 'wc_fragment_refresh' );
|
||||
}
|
||||
|
||||
}
|
||||
export default SingleProductActionHandler;
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
|
||||
class ButtonModuleWatcher {
|
||||
|
||||
constructor() {
|
||||
this.contextBootstrapRegistry = {};
|
||||
this.contextBootstrapWatchers = [];
|
||||
}
|
||||
|
||||
watchContextBootstrap(callable) {
|
||||
this.contextBootstrapWatchers.push(callable);
|
||||
Object.values(this.contextBootstrapRegistry).forEach(callable);
|
||||
watchContextBootstrap( callable ) {
|
||||
this.contextBootstrapWatchers.push( callable );
|
||||
Object.values( this.contextBootstrapRegistry ).forEach( callable );
|
||||
}
|
||||
|
||||
registerContextBootstrap(context, handler) {
|
||||
this.contextBootstrapRegistry[context] = {
|
||||
context: context,
|
||||
handler: handler
|
||||
}
|
||||
registerContextBootstrap( context, handler ) {
|
||||
this.contextBootstrapRegistry[ context ] = {
|
||||
context,
|
||||
handler,
|
||||
};
|
||||
|
||||
// Call registered watchers
|
||||
for (const callable of this.contextBootstrapWatchers) {
|
||||
callable(this.contextBootstrapRegistry[context]);
|
||||
for ( const callable of this.contextBootstrapWatchers ) {
|
||||
callable( this.contextBootstrapRegistry[ context ] );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
window.ppcpResources = window.ppcpResources || {};
|
||||
const buttonModuleWatcher = window.ppcpResources['ButtonModuleWatcher'] = window.ppcpResources['ButtonModuleWatcher'] || new ButtonModuleWatcher();
|
||||
const buttonModuleWatcher = ( window.ppcpResources.ButtonModuleWatcher =
|
||||
window.ppcpResources.ButtonModuleWatcher || new ButtonModuleWatcher() );
|
||||
|
||||
export default buttonModuleWatcher;
|
||||
|
|
|
@ -1,103 +1,121 @@
|
|||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import BootstrapHelper from '../Helper/BootstrapHelper';
|
||||
|
||||
class CartBootstrap {
|
||||
constructor(gateway, renderer, errorHandler) {
|
||||
constructor( gateway, renderer, errorHandler ) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.errorHandler = errorHandler;
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.renderer.onButtonsInit(
|
||||
this.gateway.button.wrapper,
|
||||
() => {
|
||||
this.handleButtonStatus();
|
||||
}, true);
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.shouldRender()) {
|
||||
if ( this.shouldRender() ) {
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
}
|
||||
|
||||
jQuery(document.body).on('updated_cart_totals updated_checkout', () => {
|
||||
if (this.shouldRender()) {
|
||||
jQuery( document.body ).on(
|
||||
'updated_cart_totals updated_checkout',
|
||||
() => {
|
||||
if ( this.shouldRender() ) {
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
}
|
||||
|
||||
fetch(
|
||||
this.gateway.ajax.cart_script_params.endpoint,
|
||||
{
|
||||
fetch( this.gateway.ajax.cart_script_params.endpoint, {
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
}
|
||||
)
|
||||
.then(result => result.json())
|
||||
.then(result => {
|
||||
if (! result.success) {
|
||||
} )
|
||||
.then( ( result ) => result.json() )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// handle script reload
|
||||
const newParams = result.data.url_params;
|
||||
const reloadRequired = JSON.stringify(this.gateway.url_params) !== JSON.stringify(newParams);
|
||||
const reloadRequired =
|
||||
JSON.stringify( this.gateway.url_params ) !==
|
||||
JSON.stringify( newParams );
|
||||
|
||||
if (reloadRequired) {
|
||||
if ( reloadRequired ) {
|
||||
this.gateway.url_params = newParams;
|
||||
jQuery(this.gateway.button.wrapper).trigger('ppcp-reload-buttons');
|
||||
jQuery( this.gateway.button.wrapper ).trigger(
|
||||
'ppcp-reload-buttons'
|
||||
);
|
||||
}
|
||||
|
||||
// handle button status
|
||||
const newData = {};
|
||||
if (result.data.button) {
|
||||
if ( result.data.button ) {
|
||||
newData.button = result.data.button;
|
||||
}
|
||||
if (result.data.messages) {
|
||||
if ( result.data.messages ) {
|
||||
newData.messages = result.data.messages;
|
||||
}
|
||||
if (newData) {
|
||||
BootstrapHelper.updateScriptData(this, newData);
|
||||
if ( newData ) {
|
||||
BootstrapHelper.updateScriptData( this, newData );
|
||||
this.handleButtonStatus();
|
||||
}
|
||||
|
||||
jQuery(document.body).trigger('ppcp_cart_total_updated', [result.data.amount]);
|
||||
});
|
||||
});
|
||||
jQuery( document.body ).trigger(
|
||||
'ppcp_cart_total_updated',
|
||||
[ result.data.amount ]
|
||||
);
|
||||
} );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleButtonStatus() {
|
||||
BootstrapHelper.handleButtonStatus(this);
|
||||
BootstrapHelper.handleButtonStatus( this );
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
return document.querySelector(this.gateway.button.wrapper) !== null;
|
||||
return document.querySelector( this.gateway.button.wrapper ) !== null;
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
return BootstrapHelper.shouldEnable(this);
|
||||
return BootstrapHelper.shouldEnable( this );
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldRender()) {
|
||||
if ( ! this.shouldRender() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actionHandler = new CartActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
this.errorHandler,
|
||||
this.errorHandler
|
||||
);
|
||||
|
||||
if(
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
if (
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions &&
|
||||
PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
) {
|
||||
let subscription_plan_id = PayPalCommerceGateway.subscription_plan_id
|
||||
if(PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart !== '') {
|
||||
subscription_plan_id = PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart
|
||||
let subscription_plan_id =
|
||||
PayPalCommerceGateway.subscription_plan_id;
|
||||
if (
|
||||
PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart !==
|
||||
''
|
||||
) {
|
||||
subscription_plan_id =
|
||||
PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart;
|
||||
}
|
||||
|
||||
this.renderer.render(actionHandler.subscriptionsConfiguration(subscription_plan_id));
|
||||
this.renderer.render(
|
||||
actionHandler.subscriptionsConfiguration( subscription_plan_id )
|
||||
);
|
||||
|
||||
if(!PayPalCommerceGateway.subscription_product_allowed) {
|
||||
if ( ! PayPalCommerceGateway.subscription_product_allowed ) {
|
||||
this.gateway.button.is_disabled = true;
|
||||
this.handleButtonStatus();
|
||||
}
|
||||
|
@ -105,11 +123,9 @@ class CartBootstrap {
|
|||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(
|
||||
actionHandler.configuration()
|
||||
);
|
||||
this.renderer.render( actionHandler.configuration() );
|
||||
|
||||
jQuery(document.body).trigger('ppcp_cart_rendered');
|
||||
jQuery( document.body ).trigger( 'ppcp_cart_rendered' );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import CheckoutActionHandler from '../ActionHandler/CheckoutActionHandler';
|
||||
import {setVisible, setVisibleByClass} from '../Helper/Hiding';
|
||||
import { setVisible, setVisibleByClass } from '../Helper/Hiding';
|
||||
import {
|
||||
getCurrentPaymentMethod,
|
||||
isSavedCardSelected, ORDER_BUTTON_SELECTOR,
|
||||
PaymentMethods
|
||||
} from "../Helper/CheckoutMethodState";
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
isSavedCardSelected,
|
||||
ORDER_BUTTON_SELECTOR,
|
||||
PaymentMethods,
|
||||
} from '../Helper/CheckoutMethodState';
|
||||
import BootstrapHelper from '../Helper/BootstrapHelper';
|
||||
|
||||
class CheckoutBootstap {
|
||||
constructor(gateway, renderer, spinner, errorHandler) {
|
||||
constructor( gateway, renderer, spinner, errorHandler ) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.spinner = spinner;
|
||||
|
@ -16,9 +17,13 @@ class CheckoutBootstap {
|
|||
|
||||
this.standardOrderButtonSelector = ORDER_BUTTON_SELECTOR;
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.renderer.onButtonsInit(
|
||||
this.gateway.button.wrapper,
|
||||
() => {
|
||||
this.handleButtonStatus();
|
||||
}, true);
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
init() {
|
||||
|
@ -29,72 +34,91 @@ class CheckoutBootstap {
|
|||
// WC saves form values, so with our current UI it would be a bit weird
|
||||
// if the user paid with saved, then after some time tries to pay again,
|
||||
// but wants to enter a new card, and to do that they have to choose “Select payment” in the list.
|
||||
jQuery('#saved-credit-card').val(jQuery('#saved-credit-card option:first').val());
|
||||
jQuery( '#saved-credit-card' ).val(
|
||||
jQuery( '#saved-credit-card option:first' ).val()
|
||||
);
|
||||
|
||||
jQuery(document.body).on('updated_checkout', () => {
|
||||
this.render()
|
||||
jQuery( document.body ).on( 'updated_checkout', () => {
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
|
||||
if (this.shouldShowMessages() && document.querySelector(this.gateway.messages.wrapper)) { // currently we need amount only for Pay Later
|
||||
fetch(
|
||||
this.gateway.ajax.cart_script_params.endpoint,
|
||||
{
|
||||
if (
|
||||
this.shouldShowMessages() &&
|
||||
document.querySelector( this.gateway.messages.wrapper )
|
||||
) {
|
||||
// currently we need amount only for Pay Later
|
||||
fetch( this.gateway.ajax.cart_script_params.endpoint, {
|
||||
method: 'GET',
|
||||
credentials: 'same-origin',
|
||||
}
|
||||
)
|
||||
.then(result => result.json())
|
||||
.then(result => {
|
||||
if (! result.success) {
|
||||
} )
|
||||
.then( ( result ) => result.json() )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
return;
|
||||
}
|
||||
|
||||
jQuery(document.body).trigger('ppcp_checkout_total_updated', [result.data.amount]);
|
||||
});
|
||||
jQuery( document.body ).trigger(
|
||||
'ppcp_checkout_total_updated',
|
||||
[ result.data.amount ]
|
||||
);
|
||||
} );
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
|
||||
jQuery( document.body ).on(
|
||||
'updated_checkout payment_method_selected',
|
||||
() => {
|
||||
this.updateUi();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
jQuery(document).on('hosted_fields_loaded', () => {
|
||||
jQuery('#saved-credit-card').on('change', () => {
|
||||
jQuery( document ).on( 'hosted_fields_loaded', () => {
|
||||
jQuery( '#saved-credit-card' ).on( 'change', () => {
|
||||
this.updateUi();
|
||||
})
|
||||
});
|
||||
} );
|
||||
} );
|
||||
|
||||
jQuery(document).on('ppcp_should_show_messages', (e, data) => {
|
||||
if (!this.shouldShowMessages()) {
|
||||
jQuery( document ).on( 'ppcp_should_show_messages', ( e, data ) => {
|
||||
if ( ! this.shouldShowMessages() ) {
|
||||
data.result = false;
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
this.updateUi();
|
||||
}
|
||||
|
||||
handleButtonStatus() {
|
||||
BootstrapHelper.handleButtonStatus(this);
|
||||
BootstrapHelper.handleButtonStatus( this );
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
if (document.querySelector(this.gateway.button.cancel_wrapper)) {
|
||||
if ( document.querySelector( this.gateway.button.cancel_wrapper ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return document.querySelector(this.gateway.button.wrapper) !== null || document.querySelector(this.gateway.hosted_fields.wrapper) !== null;
|
||||
return (
|
||||
document.querySelector( this.gateway.button.wrapper ) !== null ||
|
||||
document.querySelector( this.gateway.hosted_fields.wrapper ) !==
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
return BootstrapHelper.shouldEnable(this);
|
||||
return BootstrapHelper.shouldEnable( this );
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldRender()) {
|
||||
if ( ! this.shouldRender() ) {
|
||||
return;
|
||||
}
|
||||
if (document.querySelector(this.gateway.hosted_fields.wrapper + '>div')) {
|
||||
document.querySelector(this.gateway.hosted_fields.wrapper + '>div').setAttribute('style', '');
|
||||
if (
|
||||
document.querySelector(
|
||||
this.gateway.hosted_fields.wrapper + '>div'
|
||||
)
|
||||
) {
|
||||
document
|
||||
.querySelector( this.gateway.hosted_fields.wrapper + '>div' )
|
||||
.setAttribute( 'style', '' );
|
||||
}
|
||||
const actionHandler = new CheckoutActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
|
@ -102,17 +126,28 @@ class CheckoutBootstap {
|
|||
this.spinner
|
||||
);
|
||||
|
||||
if(
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
if (
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions &&
|
||||
PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
) {
|
||||
let subscription_plan_id = PayPalCommerceGateway.subscription_plan_id
|
||||
if(PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart !== '') {
|
||||
subscription_plan_id = PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart
|
||||
let subscription_plan_id =
|
||||
PayPalCommerceGateway.subscription_plan_id;
|
||||
if (
|
||||
PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart !==
|
||||
''
|
||||
) {
|
||||
subscription_plan_id =
|
||||
PayPalCommerceGateway.variable_paypal_subscription_variation_from_cart;
|
||||
}
|
||||
this.renderer.render(actionHandler.subscriptionsConfiguration(subscription_plan_id), {}, actionHandler.configuration());
|
||||
this.renderer.render(
|
||||
actionHandler.subscriptionsConfiguration(
|
||||
subscription_plan_id
|
||||
),
|
||||
{},
|
||||
actionHandler.configuration()
|
||||
);
|
||||
|
||||
if(!PayPalCommerceGateway.subscription_product_allowed) {
|
||||
if ( ! PayPalCommerceGateway.subscription_product_allowed ) {
|
||||
this.gateway.button.is_disabled = true;
|
||||
this.handleButtonStatus();
|
||||
}
|
||||
|
@ -120,90 +155,161 @@ class CheckoutBootstap {
|
|||
return;
|
||||
}
|
||||
|
||||
if(
|
||||
PayPalCommerceGateway.is_free_trial_cart
|
||||
&& PayPalCommerceGateway.vault_v3_enabled
|
||||
if (
|
||||
PayPalCommerceGateway.is_free_trial_cart &&
|
||||
PayPalCommerceGateway.vault_v3_enabled
|
||||
) {
|
||||
this.renderer.render(actionHandler.addPaymentMethodConfiguration(), {}, actionHandler.configuration());
|
||||
this.renderer.render(
|
||||
actionHandler.addPaymentMethodConfiguration(),
|
||||
{},
|
||||
actionHandler.configuration()
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(actionHandler.configuration(), {}, actionHandler.configuration());
|
||||
this.renderer.render(
|
||||
actionHandler.configuration(),
|
||||
{},
|
||||
actionHandler.configuration()
|
||||
);
|
||||
}
|
||||
|
||||
updateUi() {
|
||||
const currentPaymentMethod = getCurrentPaymentMethod();
|
||||
const isPaypal = currentPaymentMethod === PaymentMethods.PAYPAL;
|
||||
const isCard = currentPaymentMethod === PaymentMethods.CARDS;
|
||||
const isSeparateButtonGateway = [PaymentMethods.CARD_BUTTON].includes(currentPaymentMethod);
|
||||
const isSeparateButtonGateway = [ PaymentMethods.CARD_BUTTON ].includes(
|
||||
currentPaymentMethod
|
||||
);
|
||||
const isGooglePayMethod =
|
||||
currentPaymentMethod === PaymentMethods.GOOGLEPAY;
|
||||
const isSavedCard = isCard && isSavedCardSelected();
|
||||
const isNotOurGateway = !isPaypal && !isCard && !isSeparateButtonGateway;
|
||||
const isNotOurGateway =
|
||||
! isPaypal &&
|
||||
! isCard &&
|
||||
! isSeparateButtonGateway &&
|
||||
! isGooglePayMethod;
|
||||
const isFreeTrial = PayPalCommerceGateway.is_free_trial_cart;
|
||||
const hasVaultedPaypal = PayPalCommerceGateway.vaulted_paypal_email !== '';
|
||||
const hasVaultedPaypal =
|
||||
PayPalCommerceGateway.vaulted_paypal_email !== '';
|
||||
|
||||
const paypalButtonWrappers = {
|
||||
...Object.entries(PayPalCommerceGateway.separate_buttons)
|
||||
.reduce((result, [k, data]) => {
|
||||
return {...result, [data.id]: data.wrapper}
|
||||
}, {}),
|
||||
...Object.entries( PayPalCommerceGateway.separate_buttons ).reduce(
|
||||
( result, [ k, data ] ) => {
|
||||
return { ...result, [ data.id ]: data.wrapper };
|
||||
},
|
||||
{}
|
||||
),
|
||||
};
|
||||
|
||||
setVisibleByClass(this.standardOrderButtonSelector, (isPaypal && isFreeTrial && hasVaultedPaypal) || isNotOurGateway || isSavedCard, 'ppcp-hidden');
|
||||
setVisible('.ppcp-vaulted-paypal-details', isPaypal);
|
||||
setVisible(this.gateway.button.wrapper, isPaypal && !(isFreeTrial && hasVaultedPaypal));
|
||||
setVisible(this.gateway.hosted_fields.wrapper, isCard && !isSavedCard);
|
||||
for (const [gatewayId, wrapper] of Object.entries(paypalButtonWrappers)) {
|
||||
setVisible(wrapper, gatewayId === currentPaymentMethod);
|
||||
setVisibleByClass(
|
||||
this.standardOrderButtonSelector,
|
||||
( isPaypal && isFreeTrial && hasVaultedPaypal ) ||
|
||||
isNotOurGateway ||
|
||||
isSavedCard,
|
||||
'ppcp-hidden'
|
||||
);
|
||||
setVisible( '.ppcp-vaulted-paypal-details', isPaypal );
|
||||
setVisible(
|
||||
this.gateway.button.wrapper,
|
||||
isPaypal && ! ( isFreeTrial && hasVaultedPaypal )
|
||||
);
|
||||
setVisible(
|
||||
this.gateway.hosted_fields.wrapper,
|
||||
isCard && ! isSavedCard
|
||||
);
|
||||
for ( const [ gatewayId, wrapper ] of Object.entries(
|
||||
paypalButtonWrappers
|
||||
) ) {
|
||||
setVisible( wrapper, gatewayId === currentPaymentMethod );
|
||||
}
|
||||
|
||||
if (isCard) {
|
||||
if (isSavedCard) {
|
||||
if ( isCard ) {
|
||||
if ( isSavedCard ) {
|
||||
this.disableCreditCardFields();
|
||||
} else {
|
||||
this.enableCreditCardFields();
|
||||
}
|
||||
}
|
||||
|
||||
jQuery(document.body).trigger('ppcp_checkout_rendered');
|
||||
setVisible( '#ppc-button-ppcp-googlepay', isGooglePayMethod );
|
||||
|
||||
jQuery( document.body ).trigger( 'ppcp_checkout_rendered' );
|
||||
}
|
||||
|
||||
shouldShowMessages() {
|
||||
// hide when another method selected only if messages are near buttons
|
||||
const messagesWrapper = document.querySelector(this.gateway.messages.wrapper);
|
||||
if (getCurrentPaymentMethod() !== PaymentMethods.PAYPAL &&
|
||||
messagesWrapper && jQuery(messagesWrapper).closest('.ppc-button-wrapper').length
|
||||
const messagesWrapper = document.querySelector(
|
||||
this.gateway.messages.wrapper
|
||||
);
|
||||
if (
|
||||
getCurrentPaymentMethod() !== PaymentMethods.PAYPAL &&
|
||||
messagesWrapper &&
|
||||
jQuery( messagesWrapper ).closest( '.ppc-button-wrapper' ).length
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !PayPalCommerceGateway.is_free_trial_cart;
|
||||
return ! PayPalCommerceGateway.is_free_trial_cart;
|
||||
}
|
||||
|
||||
disableCreditCardFields() {
|
||||
jQuery('label[for="ppcp-credit-card-gateway-card-number"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-gateway-card-number').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('label[for="ppcp-credit-card-gateway-card-expiry"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-gateway-card-expiry').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('label[for="ppcp-credit-card-gateway-card-cvc"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-gateway-card-cvc').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('label[for="vault"]').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-vault').addClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-vault').attr("disabled", true)
|
||||
this.renderer.disableCreditCardFields()
|
||||
jQuery( 'label[for="ppcp-credit-card-gateway-card-number"]' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-gateway-card-number' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( 'label[for="ppcp-credit-card-gateway-card-expiry"]' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-gateway-card-expiry' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( 'label[for="ppcp-credit-card-gateway-card-cvc"]' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-gateway-card-cvc' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( 'label[for="vault"]' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-vault' ).addClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-vault' ).attr( 'disabled', true );
|
||||
this.renderer.disableCreditCardFields();
|
||||
}
|
||||
|
||||
enableCreditCardFields() {
|
||||
jQuery('label[for="ppcp-credit-card-gateway-card-number"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-gateway-card-number').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('label[for="ppcp-credit-card-gateway-card-expiry"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-gateway-card-expiry').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('label[for="ppcp-credit-card-gateway-card-cvc"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-gateway-card-cvc').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('label[for="vault"]').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-vault').removeClass('ppcp-credit-card-gateway-form-field-disabled')
|
||||
jQuery('#ppcp-credit-card-vault').attr("disabled", false)
|
||||
this.renderer.enableCreditCardFields()
|
||||
jQuery(
|
||||
'label[for="ppcp-credit-card-gateway-card-number"]'
|
||||
).removeClass( 'ppcp-credit-card-gateway-form-field-disabled' );
|
||||
jQuery( '#ppcp-credit-card-gateway-card-number' ).removeClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery(
|
||||
'label[for="ppcp-credit-card-gateway-card-expiry"]'
|
||||
).removeClass( 'ppcp-credit-card-gateway-form-field-disabled' );
|
||||
jQuery( '#ppcp-credit-card-gateway-card-expiry' ).removeClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( 'label[for="ppcp-credit-card-gateway-card-cvc"]' ).removeClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-gateway-card-cvc' ).removeClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( 'label[for="vault"]' ).removeClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-vault' ).removeClass(
|
||||
'ppcp-credit-card-gateway-form-field-disabled'
|
||||
);
|
||||
jQuery( '#ppcp-credit-card-vault' ).attr( 'disabled', false );
|
||||
this.renderer.enableCreditCardFields();
|
||||
}
|
||||
}
|
||||
|
||||
export default CheckoutBootstap
|
||||
export default CheckoutBootstap;
|
||||
|
|
|
@ -1,97 +1,110 @@
|
|||
import {setVisible} from "../Helper/Hiding";
|
||||
import MessageRenderer from "../Renderer/MessageRenderer";
|
||||
import { setVisible } from '../Helper/Hiding';
|
||||
import MessageRenderer from '../Renderer/MessageRenderer';
|
||||
|
||||
class MessagesBootstrap {
|
||||
constructor(gateway, messageRenderer) {
|
||||
constructor( gateway, messageRenderer ) {
|
||||
this.gateway = gateway;
|
||||
this.renderers = [];
|
||||
this.lastAmount = this.gateway.messages.amount;
|
||||
if (messageRenderer) {
|
||||
this.renderers.push(messageRenderer);
|
||||
if ( messageRenderer ) {
|
||||
this.renderers.push( messageRenderer );
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (this.gateway.messages?.block?.enabled) {
|
||||
await this.attemptDiscoverBlocks(3); // Try up to 3 times
|
||||
if ( this.gateway.messages?.block?.enabled ) {
|
||||
await this.attemptDiscoverBlocks( 3 ); // Try up to 3 times
|
||||
}
|
||||
jQuery(document.body).on('ppcp_cart_rendered ppcp_checkout_rendered', () => {
|
||||
jQuery( document.body ).on(
|
||||
'ppcp_cart_rendered ppcp_checkout_rendered',
|
||||
() => {
|
||||
this.render();
|
||||
});
|
||||
jQuery(document.body).on('ppcp_script_data_changed', (e, data) => {
|
||||
}
|
||||
);
|
||||
jQuery( document.body ).on( 'ppcp_script_data_changed', ( e, data ) => {
|
||||
this.gateway = data;
|
||||
this.render();
|
||||
});
|
||||
jQuery(document.body).on('ppcp_cart_total_updated ppcp_checkout_total_updated ppcp_product_total_updated ppcp_block_cart_total_updated', (e, amount) => {
|
||||
if (this.lastAmount !== amount) {
|
||||
} );
|
||||
jQuery( document.body ).on(
|
||||
'ppcp_cart_total_updated ppcp_checkout_total_updated ppcp_product_total_updated ppcp_block_cart_total_updated',
|
||||
( e, amount ) => {
|
||||
if ( this.lastAmount !== amount ) {
|
||||
this.lastAmount = amount;
|
||||
this.render();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
attemptDiscoverBlocks(retries) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.discoverBlocks().then(found => {
|
||||
if (!found && retries > 0) {
|
||||
setTimeout(() => {
|
||||
this.attemptDiscoverBlocks(retries - 1).then(resolve);
|
||||
}, 2000); // Wait 2 seconds before retrying
|
||||
attemptDiscoverBlocks( retries ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
this.discoverBlocks().then( ( found ) => {
|
||||
if ( ! found && retries > 0 ) {
|
||||
setTimeout( () => {
|
||||
this.attemptDiscoverBlocks( retries - 1 ).then(
|
||||
resolve
|
||||
);
|
||||
}, 2000 ); // Wait 2 seconds before retrying
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
discoverBlocks() {
|
||||
return new Promise((resolve) => {
|
||||
const elements = document.querySelectorAll('.ppcp-messages');
|
||||
if (elements.length === 0) {
|
||||
resolve(false);
|
||||
return new Promise( ( resolve ) => {
|
||||
const elements = document.querySelectorAll( '.ppcp-messages' );
|
||||
if ( elements.length === 0 ) {
|
||||
resolve( false );
|
||||
return;
|
||||
}
|
||||
|
||||
Array.from(elements).forEach(blockElement => {
|
||||
if (!blockElement.id) {
|
||||
blockElement.id = `ppcp-message-${Math.random().toString(36).substr(2, 9)}`; // Ensure each block has a unique ID
|
||||
Array.from( elements ).forEach( ( blockElement ) => {
|
||||
if ( ! blockElement.id ) {
|
||||
blockElement.id = `ppcp-message-${ Math.random()
|
||||
.toString( 36 )
|
||||
.substr( 2, 9 ) }`; // Ensure each block has a unique ID
|
||||
}
|
||||
const config = {wrapper: '#' + blockElement.id};
|
||||
if (!blockElement.getAttribute('data-pp-placement')) {
|
||||
const config = { wrapper: '#' + blockElement.id };
|
||||
if ( ! blockElement.getAttribute( 'data-pp-placement' ) ) {
|
||||
config.placement = this.gateway.messages.placement;
|
||||
}
|
||||
this.renderers.push(new MessageRenderer(config));
|
||||
});
|
||||
resolve(true);
|
||||
});
|
||||
this.renderers.push( new MessageRenderer( config ) );
|
||||
} );
|
||||
resolve( true );
|
||||
} );
|
||||
}
|
||||
|
||||
shouldShow(renderer) {
|
||||
if (this.gateway.messages.is_hidden === true) {
|
||||
shouldShow( renderer ) {
|
||||
if ( this.gateway.messages.is_hidden === true ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const eventData = {result: true}
|
||||
jQuery(document.body).trigger('ppcp_should_show_messages', [eventData, renderer.config.wrapper]);
|
||||
const eventData = { result: true };
|
||||
jQuery( document.body ).trigger( 'ppcp_should_show_messages', [
|
||||
eventData,
|
||||
renderer.config.wrapper,
|
||||
] );
|
||||
return eventData.result;
|
||||
}
|
||||
|
||||
render() {
|
||||
this.renderers.forEach(renderer => {
|
||||
const shouldShow = this.shouldShow(renderer);
|
||||
setVisible(renderer.config.wrapper, shouldShow);
|
||||
if (!shouldShow) {
|
||||
this.renderers.forEach( ( renderer ) => {
|
||||
const shouldShow = this.shouldShow( renderer );
|
||||
setVisible( renderer.config.wrapper, shouldShow );
|
||||
if ( ! shouldShow ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!renderer.shouldRender()) {
|
||||
if ( ! renderer.shouldRender() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer.renderWithAmount(this.lastAmount);
|
||||
});
|
||||
renderer.renderWithAmount( this.lastAmount );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import BootstrapHelper from '../Helper/BootstrapHelper';
|
||||
|
||||
class MiniCartBootstap {
|
||||
constructor(gateway, renderer, errorHandler) {
|
||||
constructor( gateway, renderer, errorHandler ) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.errorHandler = errorHandler;
|
||||
|
@ -10,56 +10,64 @@ class MiniCartBootstap {
|
|||
}
|
||||
|
||||
init() {
|
||||
|
||||
this.actionHandler = new CartActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
this.errorHandler,
|
||||
this.errorHandler
|
||||
);
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
|
||||
jQuery(document.body).on('wc_fragments_loaded wc_fragments_refreshed', () => {
|
||||
jQuery( document.body ).on(
|
||||
'wc_fragments_loaded wc_fragments_refreshed',
|
||||
() => {
|
||||
this.render();
|
||||
this.handleButtonStatus();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.mini_cart_wrapper, () => {
|
||||
this.renderer.onButtonsInit(
|
||||
this.gateway.button.mini_cart_wrapper,
|
||||
() => {
|
||||
this.handleButtonStatus();
|
||||
}, true);
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
handleButtonStatus() {
|
||||
BootstrapHelper.handleButtonStatus(this, {
|
||||
BootstrapHelper.handleButtonStatus( this, {
|
||||
wrapper: this.gateway.button.mini_cart_wrapper,
|
||||
skipMessages: true
|
||||
});
|
||||
skipMessages: true,
|
||||
} );
|
||||
}
|
||||
|
||||
shouldRender() {
|
||||
return document.querySelector(this.gateway.button.mini_cart_wrapper) !== null
|
||||
|| document.querySelector(this.gateway.hosted_fields.mini_cart_wrapper) !== null;
|
||||
return (
|
||||
document.querySelector( this.gateway.button.mini_cart_wrapper ) !==
|
||||
null ||
|
||||
document.querySelector(
|
||||
this.gateway.hosted_fields.mini_cart_wrapper
|
||||
) !== null
|
||||
);
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
return BootstrapHelper.shouldEnable(this, {
|
||||
isDisabled: !!this.gateway.button.is_mini_cart_disabled
|
||||
});
|
||||
return BootstrapHelper.shouldEnable( this, {
|
||||
isDisabled: !! this.gateway.button.is_mini_cart_disabled,
|
||||
} );
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.shouldRender()) {
|
||||
if ( ! this.shouldRender() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(
|
||||
this.actionHandler.configuration(),
|
||||
{
|
||||
this.renderer.render( this.actionHandler.configuration(), {
|
||||
button: {
|
||||
wrapper: this.gateway.button.mini_cart_wrapper,
|
||||
style: this.gateway.button.mini_cart_style,
|
||||
},
|
||||
}
|
||||
);
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
import CheckoutBootstap from './CheckoutBootstap'
|
||||
import {isChangePaymentPage} from "../Helper/Subscriptions";
|
||||
import CheckoutBootstap from './CheckoutBootstap';
|
||||
import { isChangePaymentPage } from '../Helper/Subscriptions';
|
||||
|
||||
class PayNowBootstrap extends CheckoutBootstap {
|
||||
constructor(gateway, renderer, spinner, errorHandler) {
|
||||
super(gateway, renderer, spinner, errorHandler)
|
||||
constructor( gateway, renderer, spinner, errorHandler ) {
|
||||
super( gateway, renderer, spinner, errorHandler );
|
||||
}
|
||||
|
||||
updateUi() {
|
||||
if (isChangePaymentPage()) {
|
||||
return
|
||||
if ( isChangePaymentPage() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
super.updateUi();
|
||||
|
|
|
@ -1,58 +1,72 @@
|
|||
import UpdateCart from "../Helper/UpdateCart";
|
||||
import SingleProductActionHandler from "../ActionHandler/SingleProductActionHandler";
|
||||
import {hide, show} from "../Helper/Hiding";
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import {loadPaypalJsScript} from "../Helper/ScriptLoading";
|
||||
import {getPlanIdFromVariation} from "../Helper/Subscriptions"
|
||||
import SimulateCart from "../Helper/SimulateCart";
|
||||
import {strRemoveWord, strAddWord, throttle} from "../Helper/Utils";
|
||||
import merge from "deepmerge";
|
||||
import UpdateCart from '../Helper/UpdateCart';
|
||||
import SingleProductActionHandler from '../ActionHandler/SingleProductActionHandler';
|
||||
import { hide, show } from '../Helper/Hiding';
|
||||
import BootstrapHelper from '../Helper/BootstrapHelper';
|
||||
import { loadPaypalJsScript } from '../Helper/ScriptLoading';
|
||||
import { getPlanIdFromVariation } from '../Helper/Subscriptions';
|
||||
import SimulateCart from '../Helper/SimulateCart';
|
||||
import { strRemoveWord, strAddWord, throttle } from '../Helper/Utils';
|
||||
import merge from 'deepmerge';
|
||||
import { debounce } from '../../../../../ppcp-blocks/resources/js/Helper/debounce';
|
||||
|
||||
class SingleProductBootstap {
|
||||
constructor(gateway, renderer, errorHandler) {
|
||||
constructor( gateway, renderer, errorHandler ) {
|
||||
this.gateway = gateway;
|
||||
this.renderer = renderer;
|
||||
this.errorHandler = errorHandler;
|
||||
this.mutationObserver = new MutationObserver(this.handleChange.bind(this));
|
||||
this.mutationObserver = new MutationObserver(
|
||||
this.handleChange.bind( this )
|
||||
);
|
||||
this.formSelector = 'form.cart';
|
||||
|
||||
// Prevent simulate cart being called too many times in a burst.
|
||||
this.simulateCartThrottled = throttle(this.simulateCart, this.gateway.simulate_cart.throttling || 5000);
|
||||
this.simulateCartThrottled = throttle(
|
||||
this.simulateCart.bind( this ),
|
||||
this.gateway.simulate_cart.throttling || 5000
|
||||
);
|
||||
this.debouncedHandleChange = debounce(
|
||||
this.handleChange.bind( this ),
|
||||
100
|
||||
);
|
||||
|
||||
this.renderer.onButtonsInit(this.gateway.button.wrapper, () => {
|
||||
this.renderer.onButtonsInit(
|
||||
this.gateway.button.wrapper,
|
||||
() => {
|
||||
this.handleChange();
|
||||
}, true);
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
this.subscriptionButtonsLoaded = false
|
||||
this.subscriptionButtonsLoaded = false;
|
||||
}
|
||||
|
||||
form() {
|
||||
return document.querySelector(this.formSelector);
|
||||
return document.querySelector( this.formSelector );
|
||||
}
|
||||
|
||||
handleChange() {
|
||||
this.subscriptionButtonsLoaded = false
|
||||
this.subscriptionButtonsLoaded = false;
|
||||
|
||||
if (!this.shouldRender()) {
|
||||
this.renderer.disableSmartButtons(this.gateway.button.wrapper);
|
||||
hide(this.gateway.button.wrapper, this.formSelector);
|
||||
if ( ! this.shouldRender() ) {
|
||||
this.renderer.disableSmartButtons( this.gateway.button.wrapper );
|
||||
hide( this.gateway.button.wrapper, this.formSelector );
|
||||
return;
|
||||
}
|
||||
|
||||
this.render();
|
||||
|
||||
this.renderer.enableSmartButtons(this.gateway.button.wrapper);
|
||||
show(this.gateway.button.wrapper);
|
||||
this.renderer.enableSmartButtons( this.gateway.button.wrapper );
|
||||
show( this.gateway.button.wrapper );
|
||||
|
||||
this.handleButtonStatus();
|
||||
}
|
||||
|
||||
handleButtonStatus(simulateCart = true) {
|
||||
BootstrapHelper.handleButtonStatus(this, {
|
||||
formSelector: this.formSelector
|
||||
});
|
||||
handleButtonStatus( simulateCart = true ) {
|
||||
BootstrapHelper.handleButtonStatus( this, {
|
||||
formSelector: this.formSelector,
|
||||
} );
|
||||
|
||||
if (simulateCart) {
|
||||
if ( simulateCart ) {
|
||||
this.simulateCartThrottled();
|
||||
}
|
||||
}
|
||||
|
@ -60,29 +74,35 @@ class SingleProductBootstap {
|
|||
init() {
|
||||
const form = this.form();
|
||||
|
||||
if (!form) {
|
||||
if ( ! form ) {
|
||||
return;
|
||||
}
|
||||
|
||||
jQuery(document).on('change', this.formSelector, () => {
|
||||
this.handleChange();
|
||||
});
|
||||
this.mutationObserver.observe(form, { childList: true, subtree: true });
|
||||
jQuery( document ).on( 'change', this.formSelector, () => {
|
||||
this.debouncedHandleChange();
|
||||
} );
|
||||
this.mutationObserver.observe( form, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
} );
|
||||
|
||||
const addToCartButton = form.querySelector('.single_add_to_cart_button');
|
||||
const addToCartButton = form.querySelector(
|
||||
'.single_add_to_cart_button'
|
||||
);
|
||||
|
||||
if (addToCartButton) {
|
||||
(new MutationObserver(this.handleButtonStatus.bind(this)))
|
||||
.observe(addToCartButton, { attributes : true });
|
||||
if ( addToCartButton ) {
|
||||
new MutationObserver(
|
||||
this.handleButtonStatus.bind( this )
|
||||
).observe( addToCartButton, { attributes: true } );
|
||||
}
|
||||
|
||||
jQuery(document).on('ppcp_should_show_messages', (e, data) => {
|
||||
if (!this.shouldRender()) {
|
||||
jQuery( document ).on( 'ppcp_should_show_messages', ( e, data ) => {
|
||||
if ( ! this.shouldRender() ) {
|
||||
data.result = false;
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
if (!this.shouldRender()) {
|
||||
if ( ! this.shouldRender() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -91,83 +111,116 @@ class SingleProductBootstap {
|
|||
}
|
||||
|
||||
shouldRender() {
|
||||
return this.form() !== null
|
||||
&& !this.isWcsattSubscriptionMode();
|
||||
return this.form() !== null && ! this.isWcsattSubscriptionMode();
|
||||
}
|
||||
|
||||
shouldEnable() {
|
||||
const form = this.form();
|
||||
const addToCartButton = form ? form.querySelector('.single_add_to_cart_button') : null;
|
||||
const addToCartButton = form
|
||||
? form.querySelector( '.single_add_to_cart_button' )
|
||||
: null;
|
||||
|
||||
return BootstrapHelper.shouldEnable(this)
|
||||
&& !this.priceAmountIsZero()
|
||||
&& ((null === addToCartButton) || !addToCartButton.classList.contains('disabled'));
|
||||
return (
|
||||
BootstrapHelper.shouldEnable( this ) &&
|
||||
! this.priceAmountIsZero() &&
|
||||
( null === addToCartButton ||
|
||||
! addToCartButton.classList.contains( 'disabled' ) )
|
||||
);
|
||||
}
|
||||
|
||||
priceAmount(returnOnUndefined = 0) {
|
||||
priceAmount( returnOnUndefined = 0 ) {
|
||||
const priceText = [
|
||||
() => document.querySelector('form.cart ins .woocommerce-Price-amount')?.innerText,
|
||||
() => document.querySelector('form.cart .woocommerce-Price-amount')?.innerText,
|
||||
() =>
|
||||
document.querySelector(
|
||||
'form.cart ins .woocommerce-Price-amount'
|
||||
)?.innerText,
|
||||
() =>
|
||||
document.querySelector( 'form.cart .woocommerce-Price-amount' )
|
||||
?.innerText,
|
||||
() => {
|
||||
const priceEl = document.querySelector('.product .woocommerce-Price-amount');
|
||||
const priceEl = document.querySelector(
|
||||
'.product .woocommerce-Price-amount'
|
||||
);
|
||||
// variable products show price like 10.00 - 20.00 here
|
||||
// but the second price also can be the suffix with the price incl/excl tax
|
||||
if (priceEl) {
|
||||
const allPriceElements = Array.from(priceEl.parentElement.querySelectorAll('.woocommerce-Price-amount'))
|
||||
.filter(el => !el.parentElement.classList.contains('woocommerce-price-suffix'));
|
||||
if (allPriceElements.length === 1) {
|
||||
if ( priceEl ) {
|
||||
const allPriceElements = Array.from(
|
||||
priceEl.parentElement.querySelectorAll(
|
||||
'.woocommerce-Price-amount'
|
||||
)
|
||||
).filter(
|
||||
( el ) =>
|
||||
! el.parentElement.classList.contains(
|
||||
'woocommerce-price-suffix'
|
||||
)
|
||||
);
|
||||
if ( allPriceElements.length === 1 ) {
|
||||
return priceEl.innerText;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
].map(f => f()).find(val => val);
|
||||
]
|
||||
.map( ( f ) => f() )
|
||||
.find( ( val ) => val );
|
||||
|
||||
if (typeof priceText === 'undefined') {
|
||||
if ( typeof priceText === 'undefined' ) {
|
||||
return returnOnUndefined;
|
||||
}
|
||||
|
||||
if (!priceText) {
|
||||
if ( ! priceText ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return parseFloat(priceText.replace(/,/g, '.').replace(/([^\d,\.\s]*)/g, ''));
|
||||
return parseFloat(
|
||||
priceText.replace( /,/g, '.' ).replace( /([^\d,\.\s]*)/g, '' )
|
||||
);
|
||||
}
|
||||
|
||||
priceAmountIsZero() {
|
||||
const price = this.priceAmount(-1);
|
||||
const price = this.priceAmount( -1 );
|
||||
|
||||
// if we can't find the price in the DOM we want to return true so the button is visible.
|
||||
if (price === -1) {
|
||||
if ( price === -1 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !price || price === 0;
|
||||
return ! price || price === 0;
|
||||
}
|
||||
|
||||
isWcsattSubscriptionMode() {
|
||||
// Check "All products for subscriptions" plugin.
|
||||
return document.querySelector('.wcsatt-options-product:not(.wcsatt-options-product--hidden) .subscription-option input[type="radio"]:checked') !== null
|
||||
|| document.querySelector('.wcsatt-options-prompt-label-subscription input[type="radio"]:checked') !== null; // grouped
|
||||
return (
|
||||
document.querySelector(
|
||||
'.wcsatt-options-product:not(.wcsatt-options-product--hidden) .subscription-option input[type="radio"]:checked'
|
||||
) !== null ||
|
||||
document.querySelector(
|
||||
'.wcsatt-options-prompt-label-subscription input[type="radio"]:checked'
|
||||
) !== null
|
||||
); // grouped
|
||||
}
|
||||
|
||||
variations() {
|
||||
if (!this.hasVariations()) {
|
||||
if ( ! this.hasVariations() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [...document.querySelector('form.cart')?.querySelectorAll("[name^='attribute_']")].map(
|
||||
(element) => {
|
||||
return [
|
||||
...document
|
||||
.querySelector( 'form.cart' )
|
||||
?.querySelectorAll( "[name^='attribute_']" ),
|
||||
].map( ( element ) => {
|
||||
return {
|
||||
value: element.value,
|
||||
name: element.name
|
||||
}
|
||||
}
|
||||
);
|
||||
name: element.name,
|
||||
};
|
||||
} );
|
||||
}
|
||||
|
||||
hasVariations() {
|
||||
return document.querySelector('form.cart')?.classList.contains('variations_form');
|
||||
return document
|
||||
.querySelector( 'form.cart' )
|
||||
?.classList.contains( 'variations_form' );
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -175,49 +228,52 @@ class SingleProductBootstap {
|
|||
this.gateway,
|
||||
new UpdateCart(
|
||||
this.gateway.ajax.change_cart.endpoint,
|
||||
this.gateway.ajax.change_cart.nonce,
|
||||
this.gateway.ajax.change_cart.nonce
|
||||
),
|
||||
this.form(),
|
||||
this.errorHandler,
|
||||
this.errorHandler
|
||||
);
|
||||
|
||||
if(
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
if (
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions &&
|
||||
PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
) {
|
||||
const buttonWrapper = document.getElementById('ppc-button-ppcp-gateway');
|
||||
const buttonWrapper = document.getElementById(
|
||||
'ppc-button-ppcp-gateway'
|
||||
);
|
||||
buttonWrapper.innerHTML = '';
|
||||
|
||||
const subscription_plan = this.variations() !== null
|
||||
? getPlanIdFromVariation(this.variations())
|
||||
: PayPalCommerceGateway.subscription_plan_id
|
||||
if(!subscription_plan) {
|
||||
const subscription_plan =
|
||||
this.variations() !== null
|
||||
? getPlanIdFromVariation( this.variations() )
|
||||
: PayPalCommerceGateway.subscription_plan_id;
|
||||
if ( ! subscription_plan ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.subscriptionButtonsLoaded) return
|
||||
if ( this.subscriptionButtonsLoaded ) {
|
||||
return;
|
||||
}
|
||||
loadPaypalJsScript(
|
||||
{
|
||||
clientId: PayPalCommerceGateway.client_id,
|
||||
currency: PayPalCommerceGateway.currency,
|
||||
intent: 'subscription',
|
||||
vault: true
|
||||
vault: true,
|
||||
},
|
||||
actionHandler.subscriptionsConfiguration(subscription_plan),
|
||||
actionHandler.subscriptionsConfiguration( subscription_plan ),
|
||||
this.gateway.button.wrapper
|
||||
);
|
||||
|
||||
this.subscriptionButtonsLoaded = true
|
||||
this.subscriptionButtonsLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(
|
||||
actionHandler.configuration()
|
||||
);
|
||||
this.renderer.render( actionHandler.configuration() );
|
||||
}
|
||||
|
||||
simulateCart() {
|
||||
if (!this.gateway.simulate_cart.enabled) {
|
||||
if ( ! this.gateway.simulate_cart.enabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -225,63 +281,81 @@ class SingleProductBootstap {
|
|||
null,
|
||||
null,
|
||||
this.form(),
|
||||
this.errorHandler,
|
||||
this.errorHandler
|
||||
);
|
||||
|
||||
const hasSubscriptions = PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled;
|
||||
const hasSubscriptions =
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions &&
|
||||
PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled;
|
||||
|
||||
const products = hasSubscriptions
|
||||
? actionHandler.getSubscriptionProducts()
|
||||
: actionHandler.getProducts();
|
||||
|
||||
(new SimulateCart(
|
||||
new SimulateCart(
|
||||
this.gateway.ajax.simulate_cart.endpoint,
|
||||
this.gateway.ajax.simulate_cart.nonce,
|
||||
)).simulate((data) => {
|
||||
|
||||
jQuery(document.body).trigger('ppcp_product_total_updated', [data.total]);
|
||||
this.gateway.ajax.simulate_cart.nonce
|
||||
).simulate( ( data ) => {
|
||||
jQuery( document.body ).trigger( 'ppcp_product_total_updated', [
|
||||
data.total,
|
||||
] );
|
||||
|
||||
let newData = {};
|
||||
if (typeof data.button.is_disabled === 'boolean') {
|
||||
newData = merge(newData, {button: {is_disabled: data.button.is_disabled}});
|
||||
if ( typeof data.button.is_disabled === 'boolean' ) {
|
||||
newData = merge( newData, {
|
||||
button: { is_disabled: data.button.is_disabled },
|
||||
} );
|
||||
}
|
||||
if (typeof data.messages.is_hidden === 'boolean') {
|
||||
newData = merge(newData, {messages: {is_hidden: data.messages.is_hidden}});
|
||||
if ( typeof data.messages.is_hidden === 'boolean' ) {
|
||||
newData = merge( newData, {
|
||||
messages: { is_hidden: data.messages.is_hidden },
|
||||
} );
|
||||
}
|
||||
if (newData) {
|
||||
BootstrapHelper.updateScriptData(this, newData);
|
||||
if ( newData ) {
|
||||
BootstrapHelper.updateScriptData( this, newData );
|
||||
}
|
||||
|
||||
if ( this.gateway.single_product_buttons_enabled !== '1' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
let enableFunding = this.gateway.url_params['enable-funding'];
|
||||
let disableFunding = this.gateway.url_params['disable-funding'];
|
||||
let enableFunding = this.gateway.url_params[ 'enable-funding' ];
|
||||
let disableFunding = this.gateway.url_params[ 'disable-funding' ];
|
||||
|
||||
for (const [fundingSource, funding] of Object.entries(data.funding)) {
|
||||
if (funding.enabled === true) {
|
||||
enableFunding = strAddWord(enableFunding, fundingSource);
|
||||
disableFunding = strRemoveWord(disableFunding, fundingSource);
|
||||
} else if (funding.enabled === false) {
|
||||
enableFunding = strRemoveWord(enableFunding, fundingSource);
|
||||
disableFunding = strAddWord(disableFunding, fundingSource);
|
||||
for ( const [ fundingSource, funding ] of Object.entries(
|
||||
data.funding
|
||||
) ) {
|
||||
if ( funding.enabled === true ) {
|
||||
enableFunding = strAddWord( enableFunding, fundingSource );
|
||||
disableFunding = strRemoveWord(
|
||||
disableFunding,
|
||||
fundingSource
|
||||
);
|
||||
} else if ( funding.enabled === false ) {
|
||||
enableFunding = strRemoveWord(
|
||||
enableFunding,
|
||||
fundingSource
|
||||
);
|
||||
disableFunding = strAddWord(
|
||||
disableFunding,
|
||||
fundingSource
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(enableFunding !== this.gateway.url_params['enable-funding']) ||
|
||||
(disableFunding !== this.gateway.url_params['disable-funding'])
|
||||
enableFunding !== this.gateway.url_params[ 'enable-funding' ] ||
|
||||
disableFunding !== this.gateway.url_params[ 'disable-funding' ]
|
||||
) {
|
||||
this.gateway.url_params['enable-funding'] = enableFunding;
|
||||
this.gateway.url_params['disable-funding'] = disableFunding;
|
||||
jQuery(this.gateway.button.wrapper).trigger('ppcp-reload-buttons');
|
||||
this.gateway.url_params[ 'enable-funding' ] = enableFunding;
|
||||
this.gateway.url_params[ 'disable-funding' ] = disableFunding;
|
||||
jQuery( this.gateway.button.wrapper ).trigger(
|
||||
'ppcp-reload-buttons'
|
||||
);
|
||||
}
|
||||
|
||||
this.handleButtonStatus(false);
|
||||
|
||||
}, products);
|
||||
this.handleButtonStatus( false );
|
||||
}, products );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,62 +1,71 @@
|
|||
import {loadScript} from "@paypal/paypal-js";
|
||||
import { loadScript } from '@paypal/paypal-js';
|
||||
|
||||
const storageKey = 'ppcp-data-client-id';
|
||||
|
||||
const validateToken = (token, user) => {
|
||||
if (! token) {
|
||||
const validateToken = ( token, user ) => {
|
||||
if ( ! token ) {
|
||||
return false;
|
||||
}
|
||||
if (token.user !== user) {
|
||||
if ( token.user !== user ) {
|
||||
return false;
|
||||
}
|
||||
const currentTime = new Date().getTime();
|
||||
const isExpired = currentTime >= token.expiration * 1000;
|
||||
return ! isExpired;
|
||||
}
|
||||
};
|
||||
|
||||
const storedTokenForUser = (user) => {
|
||||
const token = JSON.parse(sessionStorage.getItem(storageKey));
|
||||
if (validateToken(token, user)) {
|
||||
const storedTokenForUser = ( user ) => {
|
||||
const token = JSON.parse( sessionStorage.getItem( storageKey ) );
|
||||
if ( validateToken( token, user ) ) {
|
||||
return token.token;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const storeToken = (token) => {
|
||||
sessionStorage.setItem(storageKey, JSON.stringify(token));
|
||||
}
|
||||
const storeToken = ( token ) => {
|
||||
sessionStorage.setItem( storageKey, JSON.stringify( token ) );
|
||||
};
|
||||
|
||||
const dataClientIdAttributeHandler = (scriptOptions, config, callback, errorCallback = null) => {
|
||||
fetch(config.endpoint, {
|
||||
const dataClientIdAttributeHandler = (
|
||||
scriptOptions,
|
||||
config,
|
||||
callback,
|
||||
errorCallback = null
|
||||
) => {
|
||||
fetch( config.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
nonce: config.nonce
|
||||
})
|
||||
}).then((res)=>{
|
||||
body: JSON.stringify( {
|
||||
nonce: config.nonce,
|
||||
} ),
|
||||
} )
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
const isValid = validateToken(data, config.user);
|
||||
if (!isValid) {
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
const isValid = validateToken( data, config.user );
|
||||
if ( ! isValid ) {
|
||||
return;
|
||||
}
|
||||
storeToken(data);
|
||||
storeToken( data );
|
||||
|
||||
scriptOptions['data-client-token'] = data.token;
|
||||
scriptOptions[ 'data-client-token' ] = data.token;
|
||||
|
||||
loadScript(scriptOptions).then((paypal) => {
|
||||
if (typeof callback === 'function') {
|
||||
callback(paypal);
|
||||
loadScript( scriptOptions )
|
||||
.then( ( paypal ) => {
|
||||
if ( typeof callback === 'function' ) {
|
||||
callback( paypal );
|
||||
}
|
||||
}).catch(err => {
|
||||
if (typeof errorCallback === 'function') {
|
||||
errorCallback(err);
|
||||
} )
|
||||
.catch( ( err ) => {
|
||||
if ( typeof errorCallback === 'function' ) {
|
||||
errorCallback( err );
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
} );
|
||||
} );
|
||||
};
|
||||
|
||||
export default dataClientIdAttributeHandler;
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
import Product from "./Product";
|
||||
import Product from './Product';
|
||||
|
||||
class BookingProduct extends Product {
|
||||
|
||||
constructor(id, quantity, booking, extra) {
|
||||
super(id, quantity, null, extra);
|
||||
constructor( id, quantity, booking, extra ) {
|
||||
super( id, quantity, null, extra );
|
||||
this.booking = booking;
|
||||
}
|
||||
|
||||
data() {
|
||||
return {
|
||||
...super.data(),
|
||||
booking: this.booking
|
||||
}
|
||||
booking: this.booking,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
class Product {
|
||||
|
||||
constructor(id, quantity, variations, extra) {
|
||||
constructor( id, quantity, variations, extra ) {
|
||||
this.id = id;
|
||||
this.quantity = quantity;
|
||||
this.variations = variations;
|
||||
|
@ -8,11 +7,11 @@ class Product {
|
|||
}
|
||||
data() {
|
||||
return {
|
||||
id:this.id,
|
||||
id: this.id,
|
||||
quantity: this.quantity,
|
||||
variations: this.variations,
|
||||
extra: this.extra,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +1,27 @@
|
|||
class ErrorHandler {
|
||||
|
||||
/**
|
||||
* @param {String} genericErrorText
|
||||
* @param {string} genericErrorText
|
||||
* @param {Element} wrapper
|
||||
*/
|
||||
constructor(genericErrorText, wrapper)
|
||||
{
|
||||
constructor( genericErrorText, wrapper ) {
|
||||
this.genericErrorText = genericErrorText;
|
||||
this.wrapper = wrapper;
|
||||
}
|
||||
|
||||
genericError() {
|
||||
this.clear();
|
||||
this.message(this.genericErrorText)
|
||||
this.message( this.genericErrorText );
|
||||
}
|
||||
|
||||
appendPreparedErrorMessageElement(errorMessageElement)
|
||||
{
|
||||
this._getMessageContainer().replaceWith(errorMessageElement);
|
||||
appendPreparedErrorMessageElement( errorMessageElement ) {
|
||||
this._getMessageContainer().replaceWith( errorMessageElement );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} text
|
||||
* @param {string} text
|
||||
*/
|
||||
message(text)
|
||||
{
|
||||
this._addMessage(text);
|
||||
message( text ) {
|
||||
this._addMessage( text );
|
||||
|
||||
this._scrollToMessages();
|
||||
}
|
||||
|
@ -33,74 +29,68 @@ class ErrorHandler {
|
|||
/**
|
||||
* @param {Array} texts
|
||||
*/
|
||||
messages(texts)
|
||||
{
|
||||
texts.forEach(t => this._addMessage(t));
|
||||
messages( texts ) {
|
||||
texts.forEach( ( t ) => this._addMessage( t ) );
|
||||
|
||||
this._scrollToMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {String}
|
||||
* @return {string}
|
||||
*/
|
||||
currentHtml()
|
||||
{
|
||||
currentHtml() {
|
||||
const messageContainer = this._getMessageContainer();
|
||||
return messageContainer.outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {String} text
|
||||
* @param {string} text
|
||||
*/
|
||||
_addMessage(text)
|
||||
{
|
||||
if(! typeof String || text.length === 0) {
|
||||
throw new Error('A new message text must be a non-empty string.');
|
||||
_addMessage( text ) {
|
||||
if ( ! typeof String || text.length === 0 ) {
|
||||
throw new Error( 'A new message text must be a non-empty string.' );
|
||||
}
|
||||
|
||||
const messageContainer = this._getMessageContainer();
|
||||
|
||||
let messageNode = this._prepareMessageElement(text);
|
||||
messageContainer.appendChild(messageNode);
|
||||
const messageNode = this._prepareMessageElement( text );
|
||||
messageContainer.appendChild( messageNode );
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_scrollToMessages()
|
||||
{
|
||||
jQuery.scroll_to_notices(jQuery('.woocommerce-error'));
|
||||
_scrollToMessages() {
|
||||
jQuery.scroll_to_notices( jQuery( '.woocommerce-error' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getMessageContainer()
|
||||
{
|
||||
let messageContainer = document.querySelector('ul.woocommerce-error');
|
||||
if (messageContainer === null) {
|
||||
messageContainer = document.createElement('ul');
|
||||
messageContainer.setAttribute('class', 'woocommerce-error');
|
||||
messageContainer.setAttribute('role', 'alert');
|
||||
jQuery(this.wrapper).prepend(messageContainer);
|
||||
_getMessageContainer() {
|
||||
let messageContainer = document.querySelector( 'ul.woocommerce-error' );
|
||||
if ( messageContainer === null ) {
|
||||
messageContainer = document.createElement( 'ul' );
|
||||
messageContainer.setAttribute( 'class', 'woocommerce-error' );
|
||||
messageContainer.setAttribute( 'role', 'alert' );
|
||||
jQuery( this.wrapper ).prepend( messageContainer );
|
||||
}
|
||||
return messageContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @private
|
||||
*/
|
||||
_prepareMessageElement(message)
|
||||
{
|
||||
const li = document.createElement('li');
|
||||
_prepareMessageElement( message ) {
|
||||
const li = document.createElement( 'li' );
|
||||
li.innerHTML = message;
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
clear()
|
||||
{
|
||||
clear() {
|
||||
jQuery( '.woocommerce-error, .woocommerce-message' ).remove();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,29 +1,27 @@
|
|||
|
||||
export const apmButtonsInit = (config, selector = '.ppcp-button-apm') => {
|
||||
export const apmButtonsInit = ( config, selector = '.ppcp-button-apm' ) => {
|
||||
let selectorInContainer = selector;
|
||||
|
||||
if (window.ppcpApmButtons) {
|
||||
if ( window.ppcpApmButtons ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config && config.button) {
|
||||
|
||||
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;
|
||||
const isSeparateGateways =
|
||||
jQuery( wrapper ).children( 'div[class^="item-"]' ).length > 0;
|
||||
|
||||
if (isSeparateGateways) {
|
||||
selector += `, ${wrapper} div[class^="item-"]`;
|
||||
if ( isSeparateGateways ) {
|
||||
selector += `, ${ wrapper } div[class^="item-"]`;
|
||||
selectorInContainer += `, div[class^="item-"]`;
|
||||
}
|
||||
}
|
||||
|
||||
window.ppcpApmButtons = new ApmButtons(selector, selectorInContainer);
|
||||
}
|
||||
window.ppcpApmButtons = new ApmButtons( selector, selectorInContainer );
|
||||
};
|
||||
|
||||
export class ApmButtons {
|
||||
|
||||
constructor(selector, selectorInContainer) {
|
||||
constructor( selector, selectorInContainer ) {
|
||||
this.selector = selector;
|
||||
this.selectorInContainer = selectorInContainer;
|
||||
this.containers = [];
|
||||
|
@ -32,89 +30,100 @@ export class ApmButtons {
|
|||
this.reloadContainers();
|
||||
|
||||
// Refresh button layout.
|
||||
jQuery(window).resize(() => {
|
||||
jQuery( window )
|
||||
.resize( () => {
|
||||
this.refresh();
|
||||
}).resize();
|
||||
} )
|
||||
.resize();
|
||||
|
||||
jQuery(document).on('ppcp-smart-buttons-init', () => {
|
||||
jQuery( document ).on( 'ppcp-smart-buttons-init', () => {
|
||||
this.refresh();
|
||||
});
|
||||
} );
|
||||
|
||||
jQuery(document).on('ppcp-shown ppcp-hidden ppcp-enabled ppcp-disabled', (ev, data) => {
|
||||
jQuery( document ).on(
|
||||
'ppcp-shown ppcp-hidden ppcp-enabled ppcp-disabled',
|
||||
( ev, data ) => {
|
||||
this.refresh();
|
||||
setTimeout(this.refresh.bind(this), 200);
|
||||
});
|
||||
setTimeout( this.refresh.bind( this ), 200 );
|
||||
}
|
||||
);
|
||||
|
||||
// Observes for new buttons.
|
||||
(new MutationObserver(this.observeElementsCallback.bind(this)))
|
||||
.observe(document.body, { childList: true, subtree: true });
|
||||
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';
|
||||
observeElementsCallback( mutationsList, observer ) {
|
||||
const observeSelector =
|
||||
this.selector +
|
||||
', .widget_shopping_cart, .widget_shopping_cart_content';
|
||||
|
||||
let shouldReload = false;
|
||||
for (let mutation of mutationsList) {
|
||||
if (mutation.type === 'childList') {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
if (node.matches && node.matches(observeSelector)) {
|
||||
for ( const mutation of mutationsList ) {
|
||||
if ( mutation.type === 'childList' ) {
|
||||
mutation.addedNodes.forEach( ( node ) => {
|
||||
if ( node.matches && node.matches( observeSelector ) ) {
|
||||
shouldReload = true;
|
||||
}
|
||||
});
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReload) {
|
||||
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);
|
||||
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);
|
||||
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');
|
||||
$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');
|
||||
if ( width >= 500 ) {
|
||||
$container.addClass( 'ppcp-width-500' );
|
||||
} else if ( width >= 300 ) {
|
||||
$container.addClass( 'ppcp-width-300' );
|
||||
} else {
|
||||
$container.addClass('ppcp-width-min');
|
||||
$container.addClass( 'ppcp-width-min' );
|
||||
}
|
||||
|
||||
// Check first apm button
|
||||
const $firstElement = $container.children(':visible').first();
|
||||
const $firstElement = $container.children( ':visible' ).first();
|
||||
|
||||
// Assign margins to buttons
|
||||
$container.find(this.selectorInContainer).each((index, el) => {
|
||||
const $el = jQuery(el);
|
||||
$container.find( this.selectorInContainer ).each( ( index, el ) => {
|
||||
const $el = jQuery( el );
|
||||
|
||||
if ($el.is($firstElement)) {
|
||||
$el.css('margin-top', `0px`);
|
||||
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`);
|
||||
});
|
||||
|
||||
const margin = Math.max(
|
||||
minMargin,
|
||||
Math.round( height * 0.3 )
|
||||
);
|
||||
$el.css( 'margin-top', `${ margin }px` );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,51 +1,54 @@
|
|||
import {disable, enable, isDisabled} from "./ButtonDisabler";
|
||||
import merge from "deepmerge";
|
||||
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) {
|
||||
static handleButtonStatus( bs, options ) {
|
||||
options = options || {};
|
||||
options.wrapper = options.wrapper || bs.gateway.button.wrapper;
|
||||
|
||||
const wasDisabled = isDisabled(options.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 ( 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]);
|
||||
if ( wasDisabled !== ! shouldEnable ) {
|
||||
jQuery( options.wrapper ).trigger( 'ppcp_buttons_enabled_changed', [
|
||||
shouldEnable,
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
static shouldEnable(bs, options) {
|
||||
static shouldEnable( bs, options ) {
|
||||
options = options || {};
|
||||
if (typeof options.isDisabled === 'undefined') {
|
||||
if ( typeof options.isDisabled === 'undefined' ) {
|
||||
options.isDisabled = bs.gateway.button.is_disabled;
|
||||
}
|
||||
|
||||
return bs.shouldRender()
|
||||
&& options.isDisabled !== true;
|
||||
return bs.shouldRender() && options.isDisabled !== true;
|
||||
}
|
||||
|
||||
static updateScriptData(bs, newData) {
|
||||
const newObj = merge(bs.gateway, newData);
|
||||
static updateScriptData( bs, newData ) {
|
||||
const newObj = merge( bs.gateway, newData );
|
||||
|
||||
const isChanged = JSON.stringify(bs.gateway) !== JSON.stringify(newObj);
|
||||
const isChanged =
|
||||
JSON.stringify( bs.gateway ) !== JSON.stringify( newObj );
|
||||
|
||||
bs.gateway = newObj;
|
||||
|
||||
if (isChanged) {
|
||||
jQuery(document.body).trigger('ppcp_script_data_changed', [newObj]);
|
||||
if ( isChanged ) {
|
||||
jQuery( document.body ).trigger( 'ppcp_script_data_changed', [
|
||||
newObj,
|
||||
] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,83 +1,86 @@
|
|||
/**
|
||||
* @param selectorOrElement
|
||||
* @returns {Element}
|
||||
* @return {Element}
|
||||
*/
|
||||
const getElement = (selectorOrElement) => {
|
||||
if (typeof selectorOrElement === 'string') {
|
||||
return document.querySelector(selectorOrElement);
|
||||
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': element
|
||||
});
|
||||
}
|
||||
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': 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);
|
||||
export const setEnabled = ( selectorOrElement, enable, form = null ) => {
|
||||
const element = getElement( selectorOrElement );
|
||||
|
||||
if (!element) {
|
||||
if ( ! element ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
jQuery(element)
|
||||
.removeClass('ppcp-disabled')
|
||||
.off('mouseup')
|
||||
.find('> *')
|
||||
.css('pointer-events', '');
|
||||
|
||||
triggerEnabled(selectorOrElement, element);
|
||||
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) {
|
||||
jQuery( element )
|
||||
.addClass( 'ppcp-disabled' )
|
||||
.on( 'mouseup', function ( event ) {
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
if (form) {
|
||||
if ( form ) {
|
||||
// Trigger form submit to show the error message
|
||||
let $form = jQuery(form);
|
||||
if ($form.find('.single_add_to_cart_button').hasClass('disabled')) {
|
||||
$form.find(':submit').trigger('click');
|
||||
const $form = jQuery( form );
|
||||
if (
|
||||
$form
|
||||
.find( '.single_add_to_cart_button' )
|
||||
.hasClass( 'disabled' )
|
||||
) {
|
||||
$form.find( ':submit' ).trigger( 'click' );
|
||||
}
|
||||
}
|
||||
})
|
||||
.find('> *')
|
||||
.css('pointer-events', 'none');
|
||||
} )
|
||||
.find( '> *' )
|
||||
.css( 'pointer-events', 'none' );
|
||||
|
||||
triggerDisabled(selectorOrElement, element);
|
||||
triggerDisabled( selectorOrElement, element );
|
||||
}
|
||||
};
|
||||
|
||||
export const isDisabled = (selectorOrElement) => {
|
||||
const element = getElement(selectorOrElement);
|
||||
export const isDisabled = ( selectorOrElement ) => {
|
||||
const element = getElement( selectorOrElement );
|
||||
|
||||
if (!element) {
|
||||
if ( ! element ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return jQuery(element).hasClass('ppcp-disabled');
|
||||
return jQuery( element ).hasClass( 'ppcp-disabled' );
|
||||
};
|
||||
|
||||
export const disable = (selectorOrElement, form = null) => {
|
||||
setEnabled(selectorOrElement, false, form);
|
||||
export const disable = ( selectorOrElement, form = null ) => {
|
||||
setEnabled( selectorOrElement, false, form );
|
||||
};
|
||||
|
||||
export const enable = (selectorOrElement) => {
|
||||
setEnabled(selectorOrElement, true);
|
||||
export const enable = ( selectorOrElement ) => {
|
||||
setEnabled( selectorOrElement, true );
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@ const REFRESH_BUTTON_EVENT = 'ppcp_refresh_payment_buttons';
|
|||
* 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));
|
||||
document.dispatchEvent( new Event( REFRESH_BUTTON_EVENT ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,20 +18,26 @@ export function refreshButtons() {
|
|||
*
|
||||
* @param {Function} refresh - Callback responsible to re-render the payment button.
|
||||
*/
|
||||
export function setupButtonEvents(refresh) {
|
||||
export function setupButtonEvents( refresh ) {
|
||||
const miniCartInitDelay = 1000;
|
||||
const debouncedRefresh = debounce(refresh, 50);
|
||||
const debouncedRefresh = debounce( refresh, 50 );
|
||||
|
||||
// Listen for our custom refresh event.
|
||||
document.addEventListener(REFRESH_BUTTON_EVENT, debouncedRefresh);
|
||||
document.addEventListener( REFRESH_BUTTON_EVENT, debouncedRefresh );
|
||||
|
||||
// Listen for cart and checkout update events.
|
||||
document.body.addEventListener('updated_cart_totals', debouncedRefresh);
|
||||
document.body.addEventListener('updated_checkout', debouncedRefresh);
|
||||
document.body.addEventListener( 'updated_cart_totals', debouncedRefresh );
|
||||
document.body.addEventListener( '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);
|
||||
setTimeout( () => {
|
||||
document.body.addEventListener(
|
||||
'wc_fragments_loaded',
|
||||
debouncedRefresh
|
||||
);
|
||||
document.body.addEventListener(
|
||||
'wc_fragments_refreshed',
|
||||
debouncedRefresh
|
||||
);
|
||||
}, miniCartInitDelay );
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const cardFieldStyles = (field) => {
|
||||
export const cardFieldStyles = ( field ) => {
|
||||
const allowedProperties = [
|
||||
'appearance',
|
||||
'color',
|
||||
|
@ -37,14 +37,14 @@ export const cardFieldStyles = (field) => {
|
|||
'-webkit-transition',
|
||||
];
|
||||
|
||||
const stylesRaw = window.getComputedStyle(field);
|
||||
const stylesRaw = window.getComputedStyle( field );
|
||||
const styles = {};
|
||||
Object.values(stylesRaw).forEach((prop) => {
|
||||
if (!stylesRaw[prop] || !allowedProperties.includes(prop)) {
|
||||
Object.values( stylesRaw ).forEach( ( prop ) => {
|
||||
if ( ! stylesRaw[ prop ] || ! allowedProperties.includes( prop ) ) {
|
||||
return;
|
||||
}
|
||||
styles[prop] = '' + stylesRaw[prop];
|
||||
});
|
||||
styles[ prop ] = '' + stylesRaw[ prop ];
|
||||
} );
|
||||
|
||||
return styles;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,37 +1,37 @@
|
|||
class CartHelper {
|
||||
|
||||
constructor(cartItemKeys = [])
|
||||
{
|
||||
constructor( cartItemKeys = [] ) {
|
||||
this.cartItemKeys = cartItemKeys;
|
||||
}
|
||||
|
||||
getEndpoint() {
|
||||
let ajaxUrl = "/?wc-ajax=%%endpoint%%";
|
||||
let ajaxUrl = '/?wc-ajax=%%endpoint%%';
|
||||
|
||||
if ((typeof wc_cart_fragments_params !== 'undefined') && wc_cart_fragments_params.wc_ajax_url) {
|
||||
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');
|
||||
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) {
|
||||
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);
|
||||
this.cartItemKeys.push( item.cart_item_key );
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
removeFromCart()
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.cartItemKeys || !this.cartItemKeys.length) {
|
||||
removeFromCart() {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
if ( ! this.cartItemKeys || ! this.cartItemKeys.length ) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
@ -41,33 +41,36 @@ class CartHelper {
|
|||
|
||||
const tryToResolve = () => {
|
||||
numResponses++;
|
||||
if (numResponses >= numRequests) {
|
||||
if ( numResponses >= numRequests ) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for (const cartItemKey of this.cartItemKeys) {
|
||||
for ( const cartItemKey of this.cartItemKeys ) {
|
||||
const params = new URLSearchParams();
|
||||
params.append('cart_item_key', cartItemKey);
|
||||
params.append( 'cart_item_key', cartItemKey );
|
||||
|
||||
if (!cartItemKey) {
|
||||
if ( ! cartItemKey ) {
|
||||
tryToResolve();
|
||||
continue;
|
||||
}
|
||||
|
||||
fetch(this.getEndpoint(), {
|
||||
fetch( this.getEndpoint(), {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: params
|
||||
}).then(function (res) {
|
||||
body: params,
|
||||
} )
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(() => {
|
||||
} )
|
||||
.then( () => {
|
||||
tryToResolve();
|
||||
}).catch(() => {
|
||||
} )
|
||||
.catch( () => {
|
||||
tryToResolve();
|
||||
});
|
||||
} );
|
||||
}
|
||||
});
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,48 +1,55 @@
|
|||
import Spinner from "./Spinner";
|
||||
import FormValidator from "./FormValidator";
|
||||
import ErrorHandler from "../ErrorHandler";
|
||||
import Spinner from './Spinner';
|
||||
import FormValidator from './FormValidator';
|
||||
import ErrorHandler from '../ErrorHandler';
|
||||
|
||||
const validateCheckoutForm = function (config) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
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')
|
||||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
|
||||
const formSelector = config.context === 'checkout' ? 'form.checkout' : 'form#order_review';
|
||||
const formValidator = config.early_checkout_validation_enabled ?
|
||||
new FormValidator(
|
||||
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;
|
||||
config.ajax.validate_checkout.nonce
|
||||
)
|
||||
: null;
|
||||
|
||||
if (!formValidator) {
|
||||
if ( ! formValidator ) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
formValidator.validate(document.querySelector(formSelector)).then((errors) => {
|
||||
if (errors.length > 0) {
|
||||
formValidator
|
||||
.validate( document.querySelector( formSelector ) )
|
||||
.then( ( errors ) => {
|
||||
if ( errors.length > 0 ) {
|
||||
spinner.unblock();
|
||||
errorHandler.clear();
|
||||
errorHandler.messages(errors);
|
||||
errorHandler.messages( errors );
|
||||
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
jQuery( document.body ).trigger( 'checkout_error', [
|
||||
errorHandler.currentHtml(),
|
||||
] );
|
||||
|
||||
reject();
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} );
|
||||
} catch ( error ) {
|
||||
console.error( error );
|
||||
reject();
|
||||
}
|
||||
});
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
export default validateCheckoutForm;
|
||||
|
|
|
@ -3,13 +3,14 @@ export const PaymentMethods = {
|
|||
CARDS: 'ppcp-credit-card-gateway',
|
||||
OXXO: 'ppcp-oxxo-gateway',
|
||||
CARD_BUTTON: 'ppcp-card-button-gateway',
|
||||
GOOGLEPAY: 'ppcp-googlepay',
|
||||
};
|
||||
|
||||
export const ORDER_BUTTON_SELECTOR = '#place_order';
|
||||
|
||||
export const getCurrentPaymentMethod = () => {
|
||||
const el = document.querySelector('input[name="payment_method"]:checked');
|
||||
if (!el) {
|
||||
const el = document.querySelector( 'input[name="payment_method"]:checked' );
|
||||
if ( ! el ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -17,6 +18,6 @@ export const getCurrentPaymentMethod = () => {
|
|||
};
|
||||
|
||||
export const isSavedCardSelected = () => {
|
||||
const savedCardList = document.querySelector('#saved-credit-card');
|
||||
const savedCardList = document.querySelector( '#saved-credit-card' );
|
||||
return savedCardList && savedCardList.value !== '';
|
||||
};
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
const dccInputFactory = (original) => {
|
||||
const styles = window.getComputedStyle(original);
|
||||
const newElement = document.createElement('span');
|
||||
const dccInputFactory = ( original ) => {
|
||||
const styles = window.getComputedStyle( original );
|
||||
const newElement = document.createElement( 'span' );
|
||||
|
||||
newElement.setAttribute('id', original.id);
|
||||
newElement.setAttribute('class', original.className);
|
||||
newElement.setAttribute( 'id', original.id );
|
||||
newElement.setAttribute( 'class', original.className );
|
||||
|
||||
Object.values(styles).forEach( (prop) => {
|
||||
if (! styles[prop] || ! isNaN(prop) || prop === 'background-image' ) {
|
||||
Object.values( styles ).forEach( ( prop ) => {
|
||||
if (
|
||||
! styles[ prop ] ||
|
||||
! isNaN( prop ) ||
|
||||
prop === 'background-image'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
newElement.style.setProperty(prop,'' + styles[prop]);
|
||||
});
|
||||
newElement.style.setProperty( prop, '' + styles[ prop ] );
|
||||
} );
|
||||
return newElement;
|
||||
}
|
||||
};
|
||||
|
||||
export default dccInputFactory;
|
||||
|
|
|
@ -1,48 +1,50 @@
|
|||
|
||||
/**
|
||||
* Common Form utility methods
|
||||
*/
|
||||
export default class FormHelper {
|
||||
static getPrefixedFields( formElement, prefix ) {
|
||||
const formData = new FormData( formElement );
|
||||
const fields = {};
|
||||
|
||||
static getPrefixedFields(formElement, prefix) {
|
||||
const formData = new FormData(formElement);
|
||||
let fields = {};
|
||||
|
||||
for (const [name, value] of formData.entries()) {
|
||||
if (!prefix || name.startsWith(prefix)) {
|
||||
fields[name] = value;
|
||||
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);
|
||||
let fields = {};
|
||||
let counters = {};
|
||||
|
||||
for (let [name, value] of formData.entries()) {
|
||||
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) {
|
||||
if ( name.indexOf( '[]' ) !== -1 ) {
|
||||
const k = name;
|
||||
counters[k] = counters[k] || 0;
|
||||
name = name.replace('[]', `[${counters[k]}]`);
|
||||
counters[k]++;
|
||||
counters[ k ] = counters[ k ] || 0;
|
||||
name = name.replace( '[]', `[${ counters[ k ] }]` );
|
||||
counters[ k ]++;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
if ( ! name ) {
|
||||
continue;
|
||||
}
|
||||
if (exactFilters && (exactFilters.indexOf(name) !== -1)) {
|
||||
if ( exactFilters && exactFilters.indexOf( name ) !== -1 ) {
|
||||
continue;
|
||||
}
|
||||
if (prefixFilters && prefixFilters.some(prefixFilter => name.startsWith(prefixFilter))) {
|
||||
if (
|
||||
prefixFilters &&
|
||||
prefixFilters.some( ( prefixFilter ) =>
|
||||
name.startsWith( prefixFilter )
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fields[name] = value;
|
||||
fields[ name ] = value;
|
||||
}
|
||||
|
||||
return fields;
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
export default class FormSaver {
|
||||
constructor(url, nonce) {
|
||||
constructor( url, nonce ) {
|
||||
this.url = url;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
async save(form) {
|
||||
const formData = new FormData(form);
|
||||
async save( form ) {
|
||||
const formData = new FormData( form );
|
||||
|
||||
const res = await fetch(this.url, {
|
||||
const res = await fetch( this.url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.nonce,
|
||||
form_encoded: new URLSearchParams(formData).toString(),
|
||||
}),
|
||||
});
|
||||
form_encoded: new URLSearchParams( formData ).toString(),
|
||||
} ),
|
||||
} );
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success) {
|
||||
throw Error(data.data.message);
|
||||
if ( ! data.success ) {
|
||||
throw Error( data.data.message );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
export default class FormValidator {
|
||||
constructor(url, nonce) {
|
||||
constructor( url, nonce ) {
|
||||
this.url = url;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
||||
async validate(form) {
|
||||
const formData = new FormData(form);
|
||||
async validate( form ) {
|
||||
const formData = new FormData( form );
|
||||
|
||||
const res = await fetch(this.url, {
|
||||
const res = await fetch( this.url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.nonce,
|
||||
form_encoded: new URLSearchParams(formData).toString(),
|
||||
}),
|
||||
});
|
||||
form_encoded: new URLSearchParams( formData ).toString(),
|
||||
} ),
|
||||
} );
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
if (!data.success) {
|
||||
if (data.data.refresh) {
|
||||
if ( ! data.success ) {
|
||||
if ( data.data.refresh ) {
|
||||
jQuery( document.body ).trigger( 'update_checkout' );
|
||||
}
|
||||
|
||||
if (data.data.errors) {
|
||||
if ( data.data.errors ) {
|
||||
return data.data.errors;
|
||||
}
|
||||
throw Error(data.data.message);
|
||||
throw Error( data.data.message );
|
||||
}
|
||||
|
||||
return [];
|
||||
|
|
|
@ -1,85 +1,92 @@
|
|||
/**
|
||||
* @param selectorOrElement
|
||||
* @returns {Element}
|
||||
* @return {Element}
|
||||
*/
|
||||
const getElement = (selectorOrElement) => {
|
||||
if (typeof selectorOrElement === 'string') {
|
||||
return document.querySelector(selectorOrElement);
|
||||
const getElement = ( selectorOrElement ) => {
|
||||
if ( typeof selectorOrElement === 'string' ) {
|
||||
return document.querySelector( selectorOrElement );
|
||||
}
|
||||
return selectorOrElement;
|
||||
}
|
||||
};
|
||||
|
||||
const triggerHidden = (handler, selectorOrElement, element) => {
|
||||
jQuery(document).trigger('ppcp-hidden', {
|
||||
'handler': handler,
|
||||
'action': 'hide',
|
||||
'selector': selectorOrElement,
|
||||
'element': element
|
||||
});
|
||||
}
|
||||
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': handler,
|
||||
'action': 'show',
|
||||
'selector': selectorOrElement,
|
||||
'element': 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 isVisible = ( element ) => {
|
||||
return !! (
|
||||
element.offsetWidth ||
|
||||
element.offsetHeight ||
|
||||
element.getClientRects().length
|
||||
);
|
||||
};
|
||||
|
||||
export const setVisible = (selectorOrElement, show, important = false) => {
|
||||
const element = getElement(selectorOrElement);
|
||||
if (!element) {
|
||||
export const setVisible = ( selectorOrElement, show, important = false ) => {
|
||||
const element = getElement( selectorOrElement );
|
||||
if ( ! element ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentValue = element.style.getPropertyValue('display');
|
||||
const currentValue = element.style.getPropertyValue( 'display' );
|
||||
|
||||
if (!show) {
|
||||
if (currentValue === 'none') {
|
||||
if ( ! show ) {
|
||||
if ( currentValue === 'none' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
element.style.setProperty('display', 'none', important ? 'important' : '');
|
||||
triggerHidden('Hiding.setVisible', selectorOrElement, element);
|
||||
|
||||
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);
|
||||
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);
|
||||
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) {
|
||||
export const setVisibleByClass = ( selectorOrElement, show, hiddenClass ) => {
|
||||
const element = getElement( selectorOrElement );
|
||||
if ( ! element ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (show) {
|
||||
element.classList.remove(hiddenClass);
|
||||
triggerShown('Hiding.setVisibleByClass', selectorOrElement, element);
|
||||
if ( show ) {
|
||||
element.classList.remove( hiddenClass );
|
||||
triggerShown( 'Hiding.setVisibleByClass', selectorOrElement, element );
|
||||
} else {
|
||||
element.classList.add(hiddenClass);
|
||||
triggerHidden('Hiding.setVisibleByClass', selectorOrElement, element);
|
||||
element.classList.add( hiddenClass );
|
||||
triggerHidden( 'Hiding.setVisibleByClass', selectorOrElement, element );
|
||||
}
|
||||
};
|
||||
|
||||
export const hide = (selectorOrElement, important = false) => {
|
||||
setVisible(selectorOrElement, false, important);
|
||||
export const hide = ( selectorOrElement, important = false ) => {
|
||||
setVisible( selectorOrElement, false, important );
|
||||
};
|
||||
|
||||
export const show = (selectorOrElement) => {
|
||||
setVisible(selectorOrElement, true);
|
||||
export const show = ( selectorOrElement ) => {
|
||||
setVisible( selectorOrElement, true );
|
||||
};
|
||||
|
|
|
@ -14,7 +14,6 @@ const DEFAULT_TRIGGER_ELEMENT_SELECTOR = '.woocommerce-checkout-payment';
|
|||
* @property {boolean} isVisible - Whether the triggerElement is visible.
|
||||
*/
|
||||
class MultistepCheckoutHelper {
|
||||
|
||||
/**
|
||||
* Selector that defines the HTML element we are waiting to become visible.
|
||||
* @type {string}
|
||||
|
@ -43,46 +42,47 @@ class MultistepCheckoutHelper {
|
|||
* @param {string} formSelector - Selector of the checkout form
|
||||
* @param {string} triggerElementSelector - Optional. Selector of the dependant element.
|
||||
*/
|
||||
constructor(formSelector, triggerElementSelector = '') {
|
||||
constructor( formSelector, triggerElementSelector = '' ) {
|
||||
this.#formSelector = formSelector;
|
||||
this.#triggerElementSelector = triggerElementSelector || DEFAULT_TRIGGER_ELEMENT_SELECTOR;
|
||||
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) {
|
||||
setTimeout( () => {
|
||||
if ( this.form && ! this.isVisible ) {
|
||||
this.start();
|
||||
}
|
||||
}, 250);
|
||||
}, 250 );
|
||||
}
|
||||
|
||||
/**
|
||||
* The checkout form element.
|
||||
* @returns {Element|null} - Form element or null.
|
||||
* @return {Element|null} - Form element or null.
|
||||
*/
|
||||
get form() {
|
||||
return document.querySelector(this.#formSelector);
|
||||
return document.querySelector( this.#formSelector );
|
||||
}
|
||||
|
||||
/**
|
||||
* The element which must be visible before payment buttons should be initialized.
|
||||
* @returns {Element|null} - Trigger element or null.
|
||||
* @return {Element|null} - Trigger element or null.
|
||||
*/
|
||||
get triggerElement() {
|
||||
return this.form?.querySelector(this.#triggerElementSelector);
|
||||
return this.form?.querySelector( this.#triggerElementSelector );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the visibility of the payment button wrapper.
|
||||
* @returns {boolean} - returns boolean value on the basis of visibility of element.
|
||||
* @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);
|
||||
return !! ( box && box.width && box.height );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,7 +91,10 @@ class MultistepCheckoutHelper {
|
|||
*/
|
||||
start() {
|
||||
this.stop();
|
||||
this.#intervalId = setInterval(() => this.checkElement(), this.#intervalTime);
|
||||
this.#intervalId = setInterval(
|
||||
() => this.checkElement(),
|
||||
this.#intervalTime
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,8 +102,8 @@ class MultistepCheckoutHelper {
|
|||
* Multiple calls to stop are safe as clearInterval doesn't throw if provided ID doesn't exist.
|
||||
*/
|
||||
stop() {
|
||||
if (this.#intervalId) {
|
||||
clearInterval(this.#intervalId);
|
||||
if ( this.#intervalId ) {
|
||||
clearInterval( this.#intervalId );
|
||||
this.#intervalId = false;
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +113,7 @@ class MultistepCheckoutHelper {
|
|||
* If visible, it initialises the payment buttons and stops the observation.
|
||||
*/
|
||||
checkElement() {
|
||||
if (this.isVisible) {
|
||||
if ( this.isVisible ) {
|
||||
refreshButtons();
|
||||
this.stop();
|
||||
}
|
||||
|
|
|
@ -1,34 +1,59 @@
|
|||
export const payerData = () => {
|
||||
const payer = PayPalCommerceGateway.payer;
|
||||
if (! payer) {
|
||||
if ( ! payer ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const phone = (document.querySelector('#billing_phone') || typeof payer.phone !== 'undefined') ?
|
||||
{
|
||||
phone_type:"HOME",
|
||||
phone_number:{
|
||||
national_number : (document.querySelector('#billing_phone')) ? document.querySelector('#billing_phone').value : payer.phone.phone_number.national_number
|
||||
}
|
||||
} : null;
|
||||
const payerData = {
|
||||
email_address:(document.querySelector('#billing_email')) ? document.querySelector('#billing_email').value : payer.email_address,
|
||||
name : {
|
||||
surname: (document.querySelector('#billing_last_name')) ? document.querySelector('#billing_last_name').value : payer.name.surname,
|
||||
given_name: (document.querySelector('#billing_first_name')) ? document.querySelector('#billing_first_name').value : payer.name.given_name
|
||||
const phone =
|
||||
document.querySelector( '#billing_phone' ) ||
|
||||
typeof payer.phone !== 'undefined'
|
||||
? {
|
||||
phone_type: 'HOME',
|
||||
phone_number: {
|
||||
national_number: document.querySelector(
|
||||
'#billing_phone'
|
||||
)
|
||||
? document.querySelector( '#billing_phone' ).value
|
||||
: payer.phone.phone_number.national_number,
|
||||
},
|
||||
address : {
|
||||
country_code : (document.querySelector('#billing_country')) ? document.querySelector('#billing_country').value : payer.address.country_code,
|
||||
address_line_1 : (document.querySelector('#billing_address_1')) ? document.querySelector('#billing_address_1').value : payer.address.address_line_1,
|
||||
address_line_2 : (document.querySelector('#billing_address_2')) ? document.querySelector('#billing_address_2').value : payer.address.address_line_2,
|
||||
admin_area_1 : (document.querySelector('#billing_state')) ? document.querySelector('#billing_state').value : payer.address.admin_area_1,
|
||||
admin_area_2 : (document.querySelector('#billing_city')) ? document.querySelector('#billing_city').value : payer.address.admin_area_2,
|
||||
postal_code : (document.querySelector('#billing_postcode')) ? document.querySelector('#billing_postcode').value : payer.address.postal_code
|
||||
}
|
||||
: null;
|
||||
const payerData = {
|
||||
email_address: document.querySelector( '#billing_email' )
|
||||
? document.querySelector( '#billing_email' ).value
|
||||
: payer.email_address,
|
||||
name: {
|
||||
surname: document.querySelector( '#billing_last_name' )
|
||||
? document.querySelector( '#billing_last_name' ).value
|
||||
: payer.name.surname,
|
||||
given_name: document.querySelector( '#billing_first_name' )
|
||||
? document.querySelector( '#billing_first_name' ).value
|
||||
: payer.name.given_name,
|
||||
},
|
||||
address: {
|
||||
country_code: document.querySelector( '#billing_country' )
|
||||
? document.querySelector( '#billing_country' ).value
|
||||
: payer.address.country_code,
|
||||
address_line_1: document.querySelector( '#billing_address_1' )
|
||||
? document.querySelector( '#billing_address_1' ).value
|
||||
: payer.address.address_line_1,
|
||||
address_line_2: document.querySelector( '#billing_address_2' )
|
||||
? document.querySelector( '#billing_address_2' ).value
|
||||
: payer.address.address_line_2,
|
||||
admin_area_1: document.querySelector( '#billing_state' )
|
||||
? document.querySelector( '#billing_state' ).value
|
||||
: payer.address.admin_area_1,
|
||||
admin_area_2: document.querySelector( '#billing_city' )
|
||||
? document.querySelector( '#billing_city' ).value
|
||||
: payer.address.admin_area_2,
|
||||
postal_code: document.querySelector( '#billing_postcode' )
|
||||
? document.querySelector( '#billing_postcode' ).value
|
||||
: payer.address.postal_code,
|
||||
},
|
||||
};
|
||||
|
||||
if (phone) {
|
||||
if ( phone ) {
|
||||
payerData.phone = phone;
|
||||
}
|
||||
return payerData;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,33 +1,33 @@
|
|||
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 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.
|
||||
let options = window.ppcpWidgetBuilder = window.ppcpWidgetBuilder || {
|
||||
const options = ( window.ppcpWidgetBuilder = window.ppcpWidgetBuilder || {
|
||||
isLoading: false,
|
||||
onLoadedCallbacks: [],
|
||||
onErrorCallbacks: [],
|
||||
};
|
||||
} );
|
||||
|
||||
export const loadPaypalScript = (config, onLoaded, onError = null) => {
|
||||
export const loadPaypalScript = ( config, onLoaded, onError = null ) => {
|
||||
// If PayPal is already loaded call the onLoaded callback and return.
|
||||
if (typeof paypal !== 'undefined') {
|
||||
if ( typeof paypal !== 'undefined' ) {
|
||||
onLoaded();
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the onLoaded callback to the onLoadedCallbacks stack.
|
||||
options.onLoadedCallbacks.push(onLoaded);
|
||||
if (onError) {
|
||||
options.onErrorCallbacks.push(onError);
|
||||
options.onLoadedCallbacks.push( onLoaded );
|
||||
if ( onError ) {
|
||||
options.onErrorCallbacks.push( onError );
|
||||
}
|
||||
|
||||
// Return if it's still loading.
|
||||
if (options.isLoading) {
|
||||
if ( options.isLoading ) {
|
||||
return;
|
||||
}
|
||||
options.isLoading = true;
|
||||
|
@ -36,74 +36,75 @@ export const loadPaypalScript = (config, onLoaded, onError = null) => {
|
|||
options.isLoading = false;
|
||||
options.onLoadedCallbacks = [];
|
||||
options.onErrorCallbacks = [];
|
||||
}
|
||||
};
|
||||
|
||||
// Callback to be called once the PayPal script is loaded.
|
||||
const callback = (paypal) => {
|
||||
widgetBuilder.setPaypal(paypal);
|
||||
const callback = ( paypal ) => {
|
||||
widgetBuilder.setPaypal( paypal );
|
||||
|
||||
for (const onLoadedCallback of options.onLoadedCallbacks) {
|
||||
for ( const onLoadedCallback of options.onLoadedCallbacks ) {
|
||||
onLoadedCallback();
|
||||
}
|
||||
|
||||
resetState();
|
||||
}
|
||||
const errorCallback = (err) => {
|
||||
for (const onErrorCallback of options.onErrorCallbacks) {
|
||||
onErrorCallback(err);
|
||||
};
|
||||
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);
|
||||
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) {
|
||||
scriptOptions['data-sdk-client-token'] = sdkClientToken;
|
||||
scriptOptions['data-client-metadata-id'] = uuid;
|
||||
const uuid = uuidv4().replace( /-/g, '' );
|
||||
if ( sdkClientToken ) {
|
||||
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) {
|
||||
dataClientIdAttributeHandler(scriptOptions, config.data_client_id, callback, errorCallback);
|
||||
if ( config.data_client_id?.set_attribute ) {
|
||||
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 && !sdkClientToken) {
|
||||
scriptOptions['data-user-id-token'] = userIdToken;
|
||||
if ( userIdToken && ! sdkClientToken ) {
|
||||
scriptOptions[ 'data-user-id-token' ] = userIdToken;
|
||||
}
|
||||
|
||||
// Load PayPal script
|
||||
loadScript(scriptOptions)
|
||||
.then(callback)
|
||||
.catch(errorCallback);
|
||||
}
|
||||
loadScript( scriptOptions ).then( callback ).catch( errorCallback );
|
||||
};
|
||||
|
||||
export const loadPaypalScriptPromise = (config) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
loadPaypalScript(config, resolve, reject)
|
||||
});
|
||||
}
|
||||
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 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);
|
||||
});
|
||||
}
|
||||
export const loadPaypalJsScriptPromise = ( options ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
loadScript( options ).then( resolve ).catch( reject );
|
||||
} );
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {paypalAddressToWc} from "../../../../../ppcp-blocks/resources/js/Helper/Address.js";
|
||||
import {convertKeysToSnakeCase} from "../../../../../ppcp-blocks/resources/js/Helper/Helper.js";
|
||||
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.
|
||||
|
@ -7,56 +7,61 @@ import {convertKeysToSnakeCase} from "../../../../../ppcp-blocks/resources/js/He
|
|||
* @param data
|
||||
* @param actions
|
||||
* @param config
|
||||
* @returns {Promise<void>}
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
export const handleShippingOptionsChange = async (data, actions, config) => {
|
||||
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, {
|
||||
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,
|
||||
'X-WC-Store-API-Nonce':
|
||||
config.ajax.update_customer_shipping.wp_rest_nonce,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
rate_id: shippingOptionId,
|
||||
})
|
||||
})
|
||||
.then(response => {
|
||||
} ),
|
||||
}
|
||||
)
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
})
|
||||
.then(cardData => {
|
||||
const shippingMethods = document.querySelectorAll('.shipping_method');
|
||||
} )
|
||||
.then( ( cardData ) => {
|
||||
const shippingMethods =
|
||||
document.querySelectorAll( '.shipping_method' );
|
||||
|
||||
shippingMethods.forEach(function(method) {
|
||||
if (method.value === shippingOptionId) {
|
||||
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, {
|
||||
if ( ! config.data_client_id.has_subscriptions ) {
|
||||
const res = await fetch( config.ajax.update_shipping.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
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);
|
||||
if ( ! json.success ) {
|
||||
throw new Error( json.data.message );
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} catch ( e ) {
|
||||
console.error( e );
|
||||
|
||||
actions.reject();
|
||||
}
|
||||
|
@ -68,18 +73,22 @@ export const handleShippingOptionsChange = async (data, actions, config) => {
|
|||
* @param data
|
||||
* @param actions
|
||||
* @param config
|
||||
* @returns {Promise<void>}
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
export const handleShippingAddressChange = async (data, actions, config) => {
|
||||
export const handleShippingAddressChange = async ( data, actions, config ) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
const address = paypalAddressToWc(
|
||||
convertKeysToSnakeCase( data.shippingAddress )
|
||||
);
|
||||
|
||||
// Retrieve current cart contents
|
||||
await fetch(config.ajax.update_customer_shipping.shipping_address.cart_endpoint)
|
||||
.then(response => {
|
||||
await fetch(
|
||||
config.ajax.update_customer_shipping.shipping_address.cart_endpoint
|
||||
)
|
||||
.then( ( response ) => {
|
||||
return response.json();
|
||||
})
|
||||
.then(cartData => {
|
||||
} )
|
||||
.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;
|
||||
|
@ -89,39 +98,53 @@ export const handleShippingAddressChange = async (data, actions, config) => {
|
|||
cartData.shipping_address.country = address.country;
|
||||
|
||||
// Send update request
|
||||
return fetch(config.ajax.update_customer_shipping.shipping_address.update_customer_endpoint, {
|
||||
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,
|
||||
'X-WC-Store-API-Nonce':
|
||||
config.ajax.update_customer_shipping
|
||||
.wp_rest_nonce,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
shipping_address: cartData.shipping_address,
|
||||
})
|
||||
}).then(function (res) {
|
||||
} ),
|
||||
}
|
||||
)
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(function (customerData) {
|
||||
jQuery(".cart_totals .shop_table").load(location.href + " " + ".cart_totals .shop_table" + ">*", "");
|
||||
})
|
||||
})
|
||||
} )
|
||||
.then( function ( customerData ) {
|
||||
jQuery( '.cart_totals .shop_table' ).load(
|
||||
location.href +
|
||||
' ' +
|
||||
'.cart_totals .shop_table' +
|
||||
'>*',
|
||||
''
|
||||
);
|
||||
} );
|
||||
} );
|
||||
|
||||
const res = await fetch(config.ajax.update_shipping.endpoint, {
|
||||
const res = await fetch( config.ajax.update_shipping.endpoint, {
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
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);
|
||||
if ( ! json.success ) {
|
||||
throw new Error( json.data.message );
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} catch ( e ) {
|
||||
console.error( e );
|
||||
|
||||
actions.reject();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
class SimulateCart {
|
||||
|
||||
constructor(endpoint, nonce)
|
||||
{
|
||||
constructor( endpoint, nonce ) {
|
||||
this.endpoint = endpoint;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
@ -10,38 +8,34 @@ class SimulateCart {
|
|||
*
|
||||
* @param onResolve
|
||||
* @param {Product[]} products
|
||||
* @returns {Promise<unknown>}
|
||||
* @return {Promise<unknown>}
|
||||
*/
|
||||
simulate(onResolve, products)
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(
|
||||
this.endpoint,
|
||||
{
|
||||
simulate( onResolve, products ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fetch( this.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.nonce,
|
||||
products,
|
||||
})
|
||||
}
|
||||
).then(
|
||||
(result) => {
|
||||
} ),
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
return result.json();
|
||||
}
|
||||
).then((result) => {
|
||||
if (! result.success) {
|
||||
reject(result.data);
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
reject( result.data );
|
||||
return;
|
||||
}
|
||||
|
||||
const resolved = onResolve(result.data);
|
||||
resolve(resolved);
|
||||
})
|
||||
});
|
||||
const resolved = onResolve( result.data );
|
||||
resolve( resolved );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,23 @@
|
|||
class Spinner {
|
||||
|
||||
constructor(target = 'form.woocommerce-checkout') {
|
||||
constructor( target = 'form.woocommerce-checkout' ) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
setTarget(target) {
|
||||
setTarget( target ) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
block() {
|
||||
|
||||
jQuery( this.target ).block({
|
||||
jQuery( this.target ).block( {
|
||||
message: null,
|
||||
overlayCSS: {
|
||||
background: '#fff',
|
||||
opacity: 0.6
|
||||
}
|
||||
});
|
||||
opacity: 0.6,
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
unblock() {
|
||||
|
||||
jQuery( this.target ).unblock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
export const normalizeStyleForFundingSource = (style, fundingSource) => {
|
||||
export const normalizeStyleForFundingSource = ( style, fundingSource ) => {
|
||||
const commonProps = {};
|
||||
['shape', 'height'].forEach(prop => {
|
||||
if (style[prop]) {
|
||||
commonProps[prop] = style[prop];
|
||||
[ 'shape', 'height' ].forEach( ( prop ) => {
|
||||
if ( style[ prop ] ) {
|
||||
commonProps[ prop ] = style[ prop ];
|
||||
}
|
||||
});
|
||||
} );
|
||||
|
||||
switch (fundingSource) {
|
||||
switch ( fundingSource ) {
|
||||
case 'paypal':
|
||||
return style;
|
||||
case 'paylater':
|
||||
return {
|
||||
color: style.color,
|
||||
...commonProps
|
||||
...commonProps,
|
||||
};
|
||||
default:
|
||||
return commonProps;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,20 +1,28 @@
|
|||
export const isChangePaymentPage = () => {
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
return urlParams.has('change_payment_method');
|
||||
}
|
||||
const urlParams = new URLSearchParams( window.location.search );
|
||||
return urlParams.has( 'change_payment_method' );
|
||||
};
|
||||
|
||||
export const getPlanIdFromVariation = (variation) => {
|
||||
export const getPlanIdFromVariation = ( variation ) => {
|
||||
let subscription_plan = '';
|
||||
PayPalCommerceGateway.variable_paypal_subscription_variations.forEach((element) => {
|
||||
let obj = {};
|
||||
variation.forEach(({name, value}) => {
|
||||
Object.assign(obj, {[name.replace('attribute_', '')]: value});
|
||||
})
|
||||
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 !== '') {
|
||||
if (
|
||||
JSON.stringify( obj ) ===
|
||||
JSON.stringify( element.attributes ) &&
|
||||
element.subscription_plan !== ''
|
||||
) {
|
||||
subscription_plan = element.subscription_plan;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return subscription_plan;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import Product from "../Entity/Product";
|
||||
import Product from '../Entity/Product';
|
||||
class UpdateCart {
|
||||
|
||||
constructor(endpoint, nonce)
|
||||
{
|
||||
constructor( endpoint, nonce ) {
|
||||
this.endpoint = endpoint;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
@ -12,39 +10,35 @@ class UpdateCart {
|
|||
* @param onResolve
|
||||
* @param {Product[]} products
|
||||
* @param {Object} options
|
||||
* @returns {Promise<unknown>}
|
||||
* @return {Promise<unknown>}
|
||||
*/
|
||||
update(onResolve, products, options = {})
|
||||
{
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(
|
||||
this.endpoint,
|
||||
{
|
||||
update( onResolve, products, options = {} ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fetch( this.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: this.nonce,
|
||||
products,
|
||||
...options
|
||||
})
|
||||
}
|
||||
).then(
|
||||
(result) => {
|
||||
...options,
|
||||
} ),
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
return result.json();
|
||||
}
|
||||
).then((result) => {
|
||||
if (! result.success) {
|
||||
reject(result.data);
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
reject( result.data );
|
||||
return;
|
||||
}
|
||||
|
||||
const resolved = onResolve(result.data);
|
||||
resolve(resolved);
|
||||
})
|
||||
});
|
||||
const resolved = onResolve( result.data );
|
||||
resolve( resolved );
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,69 +1,69 @@
|
|||
export const toCamelCase = (str) => {
|
||||
return str.replace(/([-_]\w)/g, function(match) {
|
||||
return match[1].toUpperCase();
|
||||
});
|
||||
}
|
||||
export const toCamelCase = ( str ) => {
|
||||
return str.replace( /([-_]\w)/g, function ( match ) {
|
||||
return match[ 1 ].toUpperCase();
|
||||
} );
|
||||
};
|
||||
|
||||
export const keysToCamelCase = (obj) => {
|
||||
let output = {};
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||
output[toCamelCase(key)] = obj[key];
|
||||
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 = ',') => {
|
||||
let arr = str.split(separator);
|
||||
if (!arr.includes(word)) {
|
||||
arr.push(word);
|
||||
}
|
||||
return arr.join(separator);
|
||||
};
|
||||
|
||||
export const strRemoveWord = (str, word, separator = ',') => {
|
||||
let arr = str.split(separator);
|
||||
let index = arr.indexOf(word);
|
||||
if (index !== -1) {
|
||||
arr.splice(index, 1);
|
||||
export const strAddWord = ( str, word, separator = ',' ) => {
|
||||
const arr = str.split( separator );
|
||||
if ( ! arr.includes( word ) ) {
|
||||
arr.push( word );
|
||||
}
|
||||
return arr.join(separator);
|
||||
return arr.join( separator );
|
||||
};
|
||||
|
||||
export const throttle = (func, limit) => {
|
||||
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(() => {
|
||||
func.apply( this, arguments );
|
||||
setTimeout( () => {
|
||||
inThrottle = false;
|
||||
if (lastArgs) {
|
||||
if ( lastArgs ) {
|
||||
const nextArgs = lastArgs;
|
||||
const nextContext = lastContext;
|
||||
lastArgs = lastContext = null;
|
||||
execute.apply(nextContext, nextArgs);
|
||||
execute.apply( nextContext, nextArgs );
|
||||
}
|
||||
}, limit);
|
||||
}, limit );
|
||||
}
|
||||
|
||||
return function() {
|
||||
if (!inThrottle) {
|
||||
execute.apply(this, arguments);
|
||||
return function () {
|
||||
if ( ! inThrottle ) {
|
||||
execute.apply( this, arguments );
|
||||
} else {
|
||||
lastArgs = arguments;
|
||||
lastContext = this;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const Utils = {
|
||||
toCamelCase,
|
||||
keysToCamelCase,
|
||||
strAddWord,
|
||||
strRemoveWord,
|
||||
throttle
|
||||
throttle,
|
||||
};
|
||||
|
||||
export default Utils;
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
const onApprove = (context, errorHandler) => {
|
||||
return (data, actions) => {
|
||||
return fetch(context.config.ajax.approve_order.endpoint, {
|
||||
const onApprove = ( context, errorHandler ) => {
|
||||
return ( data, actions ) => {
|
||||
return fetch( context.config.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: context.config.ajax.approve_order.nonce,
|
||||
order_id:data.orderID,
|
||||
order_id: data.orderID,
|
||||
funding_source: window.ppcpFundingSource,
|
||||
should_create_wc_order: !context.config.vaultingEnabled || data.paymentSource !== 'venmo'
|
||||
})
|
||||
}).then((res)=>{
|
||||
should_create_wc_order:
|
||||
! context.config.vaultingEnabled ||
|
||||
data.paymentSource !== 'venmo',
|
||||
} ),
|
||||
} )
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
if (!data.success) {
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
if ( ! data.success ) {
|
||||
errorHandler.genericError();
|
||||
return actions.restart().catch(err => {
|
||||
return actions.restart().catch( ( err ) => {
|
||||
errorHandler.genericError();
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
let orderReceivedUrl = data.data?.order_received_url
|
||||
const orderReceivedUrl = data.data?.order_received_url;
|
||||
|
||||
location.href = orderReceivedUrl ? orderReceivedUrl : context.config.redirect;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
location.href = orderReceivedUrl
|
||||
? orderReceivedUrl
|
||||
: context.config.redirect;
|
||||
} );
|
||||
};
|
||||
};
|
||||
|
||||
export default onApprove;
|
||||
|
|
|
@ -1,38 +1,42 @@
|
|||
const onApprove = (context, errorHandler, spinner) => {
|
||||
return (data, actions) => {
|
||||
const onApprove = ( context, errorHandler, spinner ) => {
|
||||
return ( data, actions ) => {
|
||||
spinner.block();
|
||||
errorHandler.clear();
|
||||
|
||||
return fetch(context.config.ajax.approve_order.endpoint, {
|
||||
return fetch( context.config.ajax.approve_order.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify({
|
||||
body: JSON.stringify( {
|
||||
nonce: context.config.ajax.approve_order.nonce,
|
||||
order_id:data.orderID,
|
||||
order_id: data.orderID,
|
||||
funding_source: window.ppcpFundingSource,
|
||||
})
|
||||
}).then((res)=>{
|
||||
} ),
|
||||
} )
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
spinner.unblock();
|
||||
if (!data.success) {
|
||||
if (data.data.code === 100) {
|
||||
errorHandler.message(data.data.message);
|
||||
if ( ! data.success ) {
|
||||
if ( data.data.code === 100 ) {
|
||||
errorHandler.message( data.data.message );
|
||||
} else {
|
||||
errorHandler.genericError();
|
||||
}
|
||||
if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {
|
||||
if (
|
||||
typeof actions !== 'undefined' &&
|
||||
typeof actions.restart !== 'undefined'
|
||||
) {
|
||||
return actions.restart();
|
||||
}
|
||||
throw new Error(data.data.message);
|
||||
throw new Error( data.data.message );
|
||||
}
|
||||
document.querySelector('#place_order').click()
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
document.querySelector( '#place_order' ).click();
|
||||
} );
|
||||
};
|
||||
};
|
||||
|
||||
export default onApprove;
|
||||
|
|
|
@ -1,148 +1,182 @@
|
|||
import {show} from "../Helper/Hiding";
|
||||
import {cardFieldStyles} from "../Helper/CardFieldsHelper";
|
||||
import { show } from '../Helper/Hiding';
|
||||
import { cardFieldStyles } from '../Helper/CardFieldsHelper';
|
||||
|
||||
class CardFieldsRenderer {
|
||||
|
||||
constructor(defaultConfig, errorHandler, spinner, onCardFieldsBeforeSubmit) {
|
||||
constructor(
|
||||
defaultConfig,
|
||||
errorHandler,
|
||||
spinner,
|
||||
onCardFieldsBeforeSubmit
|
||||
) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
this.errorHandler = errorHandler;
|
||||
this.spinner = spinner;
|
||||
this.cardValid = false;
|
||||
this.formValid = false;
|
||||
this.emptyFields = new Set(['number', 'cvv', 'expirationDate']);
|
||||
this.emptyFields = new Set( [ 'number', 'cvv', 'expirationDate' ] );
|
||||
this.currentHostedFieldsInstance = null;
|
||||
this.onCardFieldsBeforeSubmit = onCardFieldsBeforeSubmit;
|
||||
}
|
||||
|
||||
render(wrapper, contextConfig) {
|
||||
render( wrapper, contextConfig ) {
|
||||
if (
|
||||
(
|
||||
this.defaultConfig.context !== 'checkout'
|
||||
&& this.defaultConfig.context !== 'pay-now'
|
||||
)
|
||||
|| wrapper === null
|
||||
|| document.querySelector(wrapper) === null
|
||||
( this.defaultConfig.context !== 'checkout' &&
|
||||
this.defaultConfig.context !== 'pay-now' ) ||
|
||||
wrapper === null ||
|
||||
document.querySelector( wrapper ) === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const buttonSelector = wrapper + ' button';
|
||||
|
||||
const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway');
|
||||
if (!gateWayBox) {
|
||||
return
|
||||
const gateWayBox = document.querySelector(
|
||||
'.payment_box.payment_method_ppcp-credit-card-gateway'
|
||||
);
|
||||
if ( ! gateWayBox ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldDisplayStyle = gateWayBox.style.display;
|
||||
gateWayBox.style.display = 'block';
|
||||
|
||||
const hideDccGateway = document.querySelector('#ppcp-hide-dcc');
|
||||
if (hideDccGateway) {
|
||||
hideDccGateway.parentNode.removeChild(hideDccGateway);
|
||||
const hideDccGateway = document.querySelector( '#ppcp-hide-dcc' );
|
||||
if ( hideDccGateway ) {
|
||||
hideDccGateway.parentNode.removeChild( hideDccGateway );
|
||||
}
|
||||
|
||||
const cardField = paypal.CardFields({
|
||||
const cardField = paypal.CardFields( {
|
||||
createOrder: contextConfig.createOrder,
|
||||
onApprove: function (data) {
|
||||
return contextConfig.onApprove(data);
|
||||
onApprove( data ) {
|
||||
return contextConfig.onApprove( data );
|
||||
},
|
||||
onError: function (error) {
|
||||
console.error(error)
|
||||
onError( error ) {
|
||||
console.error( error );
|
||||
this.spinner.unblock();
|
||||
}
|
||||
});
|
||||
},
|
||||
} );
|
||||
|
||||
if (cardField.isEligible()) {
|
||||
const nameField = document.getElementById('ppcp-credit-card-gateway-card-name');
|
||||
if (nameField) {
|
||||
let styles = cardFieldStyles(nameField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
if ( cardField.isEligible() ) {
|
||||
const nameField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-name'
|
||||
);
|
||||
if ( nameField ) {
|
||||
const styles = cardFieldStyles( nameField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( nameField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
nameField.getAttribute( 'placeholder' );
|
||||
}
|
||||
if (nameField.getAttribute('placeholder')) {
|
||||
fieldOptions.placeholder = nameField.getAttribute('placeholder');
|
||||
}
|
||||
cardField.NameField(fieldOptions).render(nameField.parentNode);
|
||||
cardField
|
||||
.NameField( fieldOptions )
|
||||
.render( nameField.parentNode );
|
||||
nameField.remove();
|
||||
}
|
||||
|
||||
const numberField = document.getElementById('ppcp-credit-card-gateway-card-number');
|
||||
if (numberField) {
|
||||
let styles = cardFieldStyles(numberField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
const numberField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-number'
|
||||
);
|
||||
if ( numberField ) {
|
||||
const styles = cardFieldStyles( numberField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( numberField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
numberField.getAttribute( 'placeholder' );
|
||||
}
|
||||
if (numberField.getAttribute('placeholder')) {
|
||||
fieldOptions.placeholder = numberField.getAttribute('placeholder');
|
||||
}
|
||||
cardField.NumberField(fieldOptions).render(numberField.parentNode);
|
||||
cardField
|
||||
.NumberField( fieldOptions )
|
||||
.render( numberField.parentNode );
|
||||
numberField.remove();
|
||||
}
|
||||
|
||||
const expiryField = document.getElementById('ppcp-credit-card-gateway-card-expiry');
|
||||
if (expiryField) {
|
||||
let styles = cardFieldStyles(expiryField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
const expiryField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-expiry'
|
||||
);
|
||||
if ( expiryField ) {
|
||||
const styles = cardFieldStyles( expiryField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( expiryField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
expiryField.getAttribute( 'placeholder' );
|
||||
}
|
||||
if (expiryField.getAttribute('placeholder')) {
|
||||
fieldOptions.placeholder = expiryField.getAttribute('placeholder');
|
||||
}
|
||||
cardField.ExpiryField(fieldOptions).render(expiryField.parentNode);
|
||||
cardField
|
||||
.ExpiryField( fieldOptions )
|
||||
.render( expiryField.parentNode );
|
||||
expiryField.remove();
|
||||
}
|
||||
|
||||
const cvvField = document.getElementById('ppcp-credit-card-gateway-card-cvc');
|
||||
if (cvvField) {
|
||||
let styles = cardFieldStyles(cvvField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
const cvvField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-cvc'
|
||||
);
|
||||
if ( cvvField ) {
|
||||
const styles = cardFieldStyles( cvvField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( cvvField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder =
|
||||
cvvField.getAttribute( 'placeholder' );
|
||||
}
|
||||
if (cvvField.getAttribute('placeholder')) {
|
||||
fieldOptions.placeholder = cvvField.getAttribute('placeholder');
|
||||
}
|
||||
cardField.CVVField(fieldOptions).render(cvvField.parentNode);
|
||||
cardField
|
||||
.CVVField( fieldOptions )
|
||||
.render( cvvField.parentNode );
|
||||
cvvField.remove();
|
||||
}
|
||||
|
||||
document.dispatchEvent(new CustomEvent("hosted_fields_loaded"));
|
||||
document.dispatchEvent( new CustomEvent( 'hosted_fields_loaded' ) );
|
||||
}
|
||||
|
||||
gateWayBox.style.display = oldDisplayStyle;
|
||||
|
||||
show(buttonSelector);
|
||||
show( buttonSelector );
|
||||
|
||||
if(this.defaultConfig.cart_contains_subscription) {
|
||||
const saveToAccount = document.querySelector('#wc-ppcp-credit-card-gateway-new-payment-method');
|
||||
if(saveToAccount) {
|
||||
if ( this.defaultConfig.cart_contains_subscription ) {
|
||||
const saveToAccount = document.querySelector(
|
||||
'#wc-ppcp-credit-card-gateway-new-payment-method'
|
||||
);
|
||||
if ( saveToAccount ) {
|
||||
saveToAccount.checked = true;
|
||||
saveToAccount.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelector(buttonSelector).addEventListener("click", (event) => {
|
||||
document
|
||||
.querySelector( buttonSelector )
|
||||
.addEventListener( 'click', ( event ) => {
|
||||
event.preventDefault();
|
||||
this.spinner.block();
|
||||
this.errorHandler.clear();
|
||||
|
||||
const paymentToken = document.querySelector('input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked')?.value
|
||||
if(paymentToken && paymentToken !== 'new') {
|
||||
document.querySelector('#place_order').click();
|
||||
const paymentToken = document.querySelector(
|
||||
'input[name="wc-ppcp-credit-card-gateway-payment-token"]:checked'
|
||||
)?.value;
|
||||
if ( paymentToken && paymentToken !== 'new' ) {
|
||||
document.querySelector( '#place_order' ).click();
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.onCardFieldsBeforeSubmit === 'function' && !this.onCardFieldsBeforeSubmit()) {
|
||||
if (
|
||||
typeof this.onCardFieldsBeforeSubmit === 'function' &&
|
||||
! this.onCardFieldsBeforeSubmit()
|
||||
) {
|
||||
this.spinner.unblock();
|
||||
return;
|
||||
}
|
||||
|
||||
cardField.submit()
|
||||
.catch((error) => {
|
||||
cardField.submit().catch( ( error ) => {
|
||||
this.spinner.unblock();
|
||||
console.error(error)
|
||||
this.errorHandler.message(this.defaultConfig.hosted_fields.labels.fields_not_valid);
|
||||
});
|
||||
});
|
||||
console.error( error );
|
||||
this.errorHandler.message(
|
||||
this.defaultConfig.hosted_fields.labels.fields_not_valid
|
||||
);
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
disableFields() {}
|
||||
|
|
|
@ -1,273 +1,356 @@
|
|||
import dccInputFactory from "../Helper/DccInputFactory";
|
||||
import {show} from "../Helper/Hiding";
|
||||
import dccInputFactory from '../Helper/DccInputFactory';
|
||||
import { show } from '../Helper/Hiding';
|
||||
|
||||
class HostedFieldsRenderer {
|
||||
|
||||
constructor(defaultConfig, errorHandler, spinner) {
|
||||
constructor( defaultConfig, errorHandler, spinner ) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
this.errorHandler = errorHandler;
|
||||
this.spinner = spinner;
|
||||
this.cardValid = false;
|
||||
this.formValid = false;
|
||||
this.emptyFields = new Set(['number', 'cvv', 'expirationDate']);
|
||||
this.emptyFields = new Set( [ 'number', 'cvv', 'expirationDate' ] );
|
||||
this.currentHostedFieldsInstance = null;
|
||||
}
|
||||
|
||||
render(wrapper, contextConfig) {
|
||||
render( wrapper, contextConfig ) {
|
||||
if (
|
||||
(
|
||||
this.defaultConfig.context !== 'checkout'
|
||||
&& this.defaultConfig.context !== 'pay-now'
|
||||
)
|
||||
|| wrapper === null
|
||||
|| document.querySelector(wrapper) === null
|
||||
( this.defaultConfig.context !== 'checkout' &&
|
||||
this.defaultConfig.context !== 'pay-now' ) ||
|
||||
wrapper === null ||
|
||||
document.querySelector( wrapper ) === null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof paypal.HostedFields !== 'undefined' && paypal.HostedFields.isEligible()) {
|
||||
if (
|
||||
typeof paypal.HostedFields !== 'undefined' &&
|
||||
paypal.HostedFields.isEligible()
|
||||
) {
|
||||
const buttonSelector = wrapper + ' button';
|
||||
|
||||
if (this.currentHostedFieldsInstance) {
|
||||
this.currentHostedFieldsInstance.teardown()
|
||||
.catch(err => console.error(`Hosted fields teardown error: ${err}`));
|
||||
if ( this.currentHostedFieldsInstance ) {
|
||||
this.currentHostedFieldsInstance
|
||||
.teardown()
|
||||
.catch( ( err ) =>
|
||||
console.error(
|
||||
`Hosted fields teardown error: ${ err }`
|
||||
)
|
||||
);
|
||||
this.currentHostedFieldsInstance = null;
|
||||
}
|
||||
|
||||
const gateWayBox = document.querySelector('.payment_box.payment_method_ppcp-credit-card-gateway');
|
||||
if (!gateWayBox) {
|
||||
return
|
||||
const gateWayBox = document.querySelector(
|
||||
'.payment_box.payment_method_ppcp-credit-card-gateway'
|
||||
);
|
||||
if ( ! gateWayBox ) {
|
||||
return;
|
||||
}
|
||||
const oldDisplayStyle = gateWayBox.style.display;
|
||||
gateWayBox.style.display = 'block';
|
||||
|
||||
const hideDccGateway = document.querySelector('#ppcp-hide-dcc');
|
||||
if (hideDccGateway) {
|
||||
hideDccGateway.parentNode.removeChild(hideDccGateway);
|
||||
const hideDccGateway = document.querySelector( '#ppcp-hide-dcc' );
|
||||
if ( hideDccGateway ) {
|
||||
hideDccGateway.parentNode.removeChild( hideDccGateway );
|
||||
}
|
||||
|
||||
const cardNumberField = document.querySelector('#ppcp-credit-card-gateway-card-number');
|
||||
const cardNumberField = document.querySelector(
|
||||
'#ppcp-credit-card-gateway-card-number'
|
||||
);
|
||||
|
||||
const stylesRaw = window.getComputedStyle(cardNumberField);
|
||||
let styles = {};
|
||||
Object.values(stylesRaw).forEach((prop) => {
|
||||
if (!stylesRaw[prop]) {
|
||||
const stylesRaw = window.getComputedStyle( cardNumberField );
|
||||
const styles = {};
|
||||
Object.values( stylesRaw ).forEach( ( prop ) => {
|
||||
if ( ! stylesRaw[ prop ] ) {
|
||||
return;
|
||||
}
|
||||
styles[prop] = '' + stylesRaw[prop];
|
||||
});
|
||||
styles[ prop ] = '' + stylesRaw[ prop ];
|
||||
} );
|
||||
|
||||
const cardNumber = dccInputFactory(cardNumberField);
|
||||
cardNumberField.parentNode.replaceChild(cardNumber, cardNumberField);
|
||||
const cardNumber = dccInputFactory( cardNumberField );
|
||||
cardNumberField.parentNode.replaceChild(
|
||||
cardNumber,
|
||||
cardNumberField
|
||||
);
|
||||
|
||||
const cardExpiryField = document.querySelector('#ppcp-credit-card-gateway-card-expiry');
|
||||
const cardExpiry = dccInputFactory(cardExpiryField);
|
||||
cardExpiryField.parentNode.replaceChild(cardExpiry, cardExpiryField);
|
||||
const cardExpiryField = document.querySelector(
|
||||
'#ppcp-credit-card-gateway-card-expiry'
|
||||
);
|
||||
const cardExpiry = dccInputFactory( cardExpiryField );
|
||||
cardExpiryField.parentNode.replaceChild(
|
||||
cardExpiry,
|
||||
cardExpiryField
|
||||
);
|
||||
|
||||
const cardCodeField = document.querySelector('#ppcp-credit-card-gateway-card-cvc');
|
||||
const cardCode = dccInputFactory(cardCodeField);
|
||||
cardCodeField.parentNode.replaceChild(cardCode, cardCodeField);
|
||||
const cardCodeField = document.querySelector(
|
||||
'#ppcp-credit-card-gateway-card-cvc'
|
||||
);
|
||||
const cardCode = dccInputFactory( cardCodeField );
|
||||
cardCodeField.parentNode.replaceChild( cardCode, cardCodeField );
|
||||
|
||||
gateWayBox.style.display = oldDisplayStyle;
|
||||
|
||||
const formWrapper = '.payment_box payment_method_ppcp-credit-card-gateway';
|
||||
const formWrapper =
|
||||
'.payment_box payment_method_ppcp-credit-card-gateway';
|
||||
if (
|
||||
this.defaultConfig.enforce_vault
|
||||
&& document.querySelector(formWrapper + ' .ppcp-credit-card-vault')
|
||||
this.defaultConfig.enforce_vault &&
|
||||
document.querySelector(
|
||||
formWrapper + ' .ppcp-credit-card-vault'
|
||||
)
|
||||
) {
|
||||
document.querySelector(formWrapper + ' .ppcp-credit-card-vault').checked = true;
|
||||
document.querySelector(formWrapper + ' .ppcp-credit-card-vault').setAttribute('disabled', true);
|
||||
document.querySelector(
|
||||
formWrapper + ' .ppcp-credit-card-vault'
|
||||
).checked = true;
|
||||
document
|
||||
.querySelector( formWrapper + ' .ppcp-credit-card-vault' )
|
||||
.setAttribute( 'disabled', true );
|
||||
}
|
||||
paypal.HostedFields.render({
|
||||
paypal.HostedFields.render( {
|
||||
createOrder: contextConfig.createOrder,
|
||||
styles: {
|
||||
'input': styles
|
||||
input: styles,
|
||||
},
|
||||
fields: {
|
||||
number: {
|
||||
selector: '#ppcp-credit-card-gateway-card-number',
|
||||
placeholder: this.defaultConfig.hosted_fields.labels.credit_card_number,
|
||||
placeholder:
|
||||
this.defaultConfig.hosted_fields.labels
|
||||
.credit_card_number,
|
||||
},
|
||||
cvv: {
|
||||
selector: '#ppcp-credit-card-gateway-card-cvc',
|
||||
placeholder: this.defaultConfig.hosted_fields.labels.cvv,
|
||||
placeholder:
|
||||
this.defaultConfig.hosted_fields.labels.cvv,
|
||||
},
|
||||
expirationDate: {
|
||||
selector: '#ppcp-credit-card-gateway-card-expiry',
|
||||
placeholder: this.defaultConfig.hosted_fields.labels.mm_yy,
|
||||
}
|
||||
}
|
||||
}).then(hostedFields => {
|
||||
document.dispatchEvent(new CustomEvent("hosted_fields_loaded"));
|
||||
placeholder:
|
||||
this.defaultConfig.hosted_fields.labels.mm_yy,
|
||||
},
|
||||
},
|
||||
} ).then( ( hostedFields ) => {
|
||||
document.dispatchEvent(
|
||||
new CustomEvent( 'hosted_fields_loaded' )
|
||||
);
|
||||
this.currentHostedFieldsInstance = hostedFields;
|
||||
|
||||
hostedFields.on('inputSubmitRequest', () => {
|
||||
this._submit(contextConfig);
|
||||
});
|
||||
hostedFields.on('cardTypeChange', (event) => {
|
||||
if (!event.cards.length) {
|
||||
hostedFields.on( 'inputSubmitRequest', () => {
|
||||
this._submit( contextConfig );
|
||||
} );
|
||||
hostedFields.on( 'cardTypeChange', ( event ) => {
|
||||
if ( ! event.cards.length ) {
|
||||
this.cardValid = false;
|
||||
return;
|
||||
}
|
||||
const validCards = this.defaultConfig.hosted_fields.valid_cards;
|
||||
this.cardValid = validCards.indexOf(event.cards[0].type) !== -1;
|
||||
const validCards =
|
||||
this.defaultConfig.hosted_fields.valid_cards;
|
||||
this.cardValid =
|
||||
validCards.indexOf( event.cards[ 0 ].type ) !== -1;
|
||||
|
||||
const className = this._cardNumberFiledCLassNameByCardType(event.cards[0].type);
|
||||
this._recreateElementClassAttribute(cardNumber, cardNumberField.className);
|
||||
if (event.cards.length === 1) {
|
||||
cardNumber.classList.add(className);
|
||||
const className = this._cardNumberFiledCLassNameByCardType(
|
||||
event.cards[ 0 ].type
|
||||
);
|
||||
this._recreateElementClassAttribute(
|
||||
cardNumber,
|
||||
cardNumberField.className
|
||||
);
|
||||
if ( event.cards.length === 1 ) {
|
||||
cardNumber.classList.add( className );
|
||||
}
|
||||
})
|
||||
hostedFields.on('validityChange', (event) => {
|
||||
this.formValid = Object.keys(event.fields).every(function (key) {
|
||||
return event.fields[key].isValid;
|
||||
});
|
||||
});
|
||||
hostedFields.on('empty', (event) => {
|
||||
this._recreateElementClassAttribute(cardNumber, cardNumberField.className);
|
||||
this.emptyFields.add(event.emittedBy);
|
||||
});
|
||||
hostedFields.on('notEmpty', (event) => {
|
||||
this.emptyFields.delete(event.emittedBy);
|
||||
});
|
||||
|
||||
show(buttonSelector);
|
||||
|
||||
if (document.querySelector(wrapper).getAttribute('data-ppcp-subscribed') !== true) {
|
||||
document.querySelector(buttonSelector).addEventListener(
|
||||
'click',
|
||||
event => {
|
||||
event.preventDefault();
|
||||
this._submit(contextConfig);
|
||||
} );
|
||||
hostedFields.on( 'validityChange', ( event ) => {
|
||||
this.formValid = Object.keys( event.fields ).every(
|
||||
function ( key ) {
|
||||
return event.fields[ key ].isValid;
|
||||
}
|
||||
);
|
||||
} );
|
||||
hostedFields.on( 'empty', ( event ) => {
|
||||
this._recreateElementClassAttribute(
|
||||
cardNumber,
|
||||
cardNumberField.className
|
||||
);
|
||||
this.emptyFields.add( event.emittedBy );
|
||||
} );
|
||||
hostedFields.on( 'notEmpty', ( event ) => {
|
||||
this.emptyFields.delete( event.emittedBy );
|
||||
} );
|
||||
|
||||
document.querySelector(wrapper).setAttribute('data-ppcp-subscribed', true);
|
||||
}
|
||||
});
|
||||
show( buttonSelector );
|
||||
|
||||
document.querySelector('#payment_method_ppcp-credit-card-gateway').addEventListener(
|
||||
'click',
|
||||
() => {
|
||||
document.querySelector('label[for=ppcp-credit-card-gateway-card-number]').click();
|
||||
if (
|
||||
document
|
||||
.querySelector( wrapper )
|
||||
.getAttribute( 'data-ppcp-subscribed' ) !== true
|
||||
) {
|
||||
document
|
||||
.querySelector( buttonSelector )
|
||||
.addEventListener( 'click', ( event ) => {
|
||||
event.preventDefault();
|
||||
this._submit( contextConfig );
|
||||
} );
|
||||
|
||||
document
|
||||
.querySelector( wrapper )
|
||||
.setAttribute( 'data-ppcp-subscribed', true );
|
||||
}
|
||||
} );
|
||||
|
||||
document
|
||||
.querySelector( '#payment_method_ppcp-credit-card-gateway' )
|
||||
.addEventListener( 'click', () => {
|
||||
document
|
||||
.querySelector(
|
||||
'label[for=ppcp-credit-card-gateway-card-number]'
|
||||
)
|
||||
.click();
|
||||
} );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapperElement = document.querySelector(wrapper);
|
||||
wrapperElement.parentNode.removeChild(wrapperElement);
|
||||
const wrapperElement = document.querySelector( wrapper );
|
||||
wrapperElement.parentNode.removeChild( wrapperElement );
|
||||
}
|
||||
|
||||
disableFields() {
|
||||
if (this.currentHostedFieldsInstance) {
|
||||
this.currentHostedFieldsInstance.setAttribute({
|
||||
if ( this.currentHostedFieldsInstance ) {
|
||||
this.currentHostedFieldsInstance.setAttribute( {
|
||||
field: 'number',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
this.currentHostedFieldsInstance.setAttribute({
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.setAttribute( {
|
||||
field: 'cvv',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
this.currentHostedFieldsInstance.setAttribute({
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.setAttribute( {
|
||||
field: 'expirationDate',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
enableFields() {
|
||||
if (this.currentHostedFieldsInstance) {
|
||||
this.currentHostedFieldsInstance.removeAttribute({
|
||||
if ( this.currentHostedFieldsInstance ) {
|
||||
this.currentHostedFieldsInstance.removeAttribute( {
|
||||
field: 'number',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
this.currentHostedFieldsInstance.removeAttribute({
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.removeAttribute( {
|
||||
field: 'cvv',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
this.currentHostedFieldsInstance.removeAttribute({
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.removeAttribute( {
|
||||
field: 'expirationDate',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
_submit(contextConfig) {
|
||||
_submit( contextConfig ) {
|
||||
this.spinner.block();
|
||||
this.errorHandler.clear();
|
||||
|
||||
if (this.formValid && this.cardValid) {
|
||||
const save_card = this.defaultConfig.can_save_vault_token ? true : false;
|
||||
let vault = document.getElementById('ppcp-credit-card-vault') ?
|
||||
document.getElementById('ppcp-credit-card-vault').checked : save_card;
|
||||
if (this.defaultConfig.enforce_vault) {
|
||||
if ( this.formValid && this.cardValid ) {
|
||||
const save_card = this.defaultConfig.can_save_vault_token
|
||||
? true
|
||||
: false;
|
||||
let vault = document.getElementById( 'ppcp-credit-card-vault' )
|
||||
? document.getElementById( 'ppcp-credit-card-vault' ).checked
|
||||
: save_card;
|
||||
if ( this.defaultConfig.enforce_vault ) {
|
||||
vault = true;
|
||||
}
|
||||
const contingency = this.defaultConfig.hosted_fields.contingency;
|
||||
const hostedFieldsData = {
|
||||
vault: vault
|
||||
vault,
|
||||
};
|
||||
if (contingency !== 'NO_3D_SECURE') {
|
||||
hostedFieldsData.contingencies = [contingency];
|
||||
if ( contingency !== 'NO_3D_SECURE' ) {
|
||||
hostedFieldsData.contingencies = [ contingency ];
|
||||
}
|
||||
|
||||
if (this.defaultConfig.payer) {
|
||||
hostedFieldsData.cardholderName = this.defaultConfig.payer.name.given_name + ' ' + this.defaultConfig.payer.name.surname;
|
||||
if ( this.defaultConfig.payer ) {
|
||||
hostedFieldsData.cardholderName =
|
||||
this.defaultConfig.payer.name.given_name +
|
||||
' ' +
|
||||
this.defaultConfig.payer.name.surname;
|
||||
}
|
||||
if (!hostedFieldsData.cardholderName) {
|
||||
const firstName = document.getElementById('billing_first_name') ? document.getElementById('billing_first_name').value : '';
|
||||
const lastName = document.getElementById('billing_last_name') ? document.getElementById('billing_last_name').value : '';
|
||||
if ( ! hostedFieldsData.cardholderName ) {
|
||||
const firstName = document.getElementById(
|
||||
'billing_first_name'
|
||||
)
|
||||
? document.getElementById( 'billing_first_name' ).value
|
||||
: '';
|
||||
const lastName = document.getElementById( 'billing_last_name' )
|
||||
? document.getElementById( 'billing_last_name' ).value
|
||||
: '';
|
||||
|
||||
hostedFieldsData.cardholderName = firstName + ' ' + lastName;
|
||||
}
|
||||
|
||||
this.currentHostedFieldsInstance.submit(hostedFieldsData).then((payload) => {
|
||||
this.currentHostedFieldsInstance
|
||||
.submit( hostedFieldsData )
|
||||
.then( ( payload ) => {
|
||||
payload.orderID = payload.orderId;
|
||||
this.spinner.unblock();
|
||||
return contextConfig.onApprove(payload);
|
||||
}).catch(err => {
|
||||
return contextConfig.onApprove( payload );
|
||||
} )
|
||||
.catch( ( err ) => {
|
||||
this.spinner.unblock();
|
||||
this.errorHandler.clear();
|
||||
|
||||
if (err.data?.details?.length) {
|
||||
this.errorHandler.message(err.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
} else if (err.details?.length) {
|
||||
this.errorHandler.message(err.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
} else if (err.data?.errors?.length > 0) {
|
||||
this.errorHandler.messages(err.data.errors);
|
||||
} else if (err.data?.message) {
|
||||
this.errorHandler.message(err.data.message);
|
||||
} else if (err.message) {
|
||||
this.errorHandler.message(err.message);
|
||||
if ( err.data?.details?.length ) {
|
||||
this.errorHandler.message(
|
||||
err.data.details
|
||||
.map(
|
||||
( d ) => `${ d.issue } ${ d.description }`
|
||||
)
|
||||
.join( '<br/>' )
|
||||
);
|
||||
} else if ( err.details?.length ) {
|
||||
this.errorHandler.message(
|
||||
err.details
|
||||
.map(
|
||||
( d ) => `${ d.issue } ${ d.description }`
|
||||
)
|
||||
.join( '<br/>' )
|
||||
);
|
||||
} else if ( err.data?.errors?.length > 0 ) {
|
||||
this.errorHandler.messages( err.data.errors );
|
||||
} else if ( err.data?.message ) {
|
||||
this.errorHandler.message( err.data.message );
|
||||
} else if ( err.message ) {
|
||||
this.errorHandler.message( err.message );
|
||||
} else {
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
});
|
||||
} );
|
||||
} else {
|
||||
this.spinner.unblock();
|
||||
|
||||
let message = this.defaultConfig.labels.error.generic;
|
||||
if (this.emptyFields.size > 0) {
|
||||
if ( this.emptyFields.size > 0 ) {
|
||||
message = this.defaultConfig.hosted_fields.labels.fields_empty;
|
||||
} else if (!this.cardValid) {
|
||||
message = this.defaultConfig.hosted_fields.labels.card_not_supported;
|
||||
} else if (!this.formValid) {
|
||||
message = this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
||||
} else if ( ! this.cardValid ) {
|
||||
message =
|
||||
this.defaultConfig.hosted_fields.labels.card_not_supported;
|
||||
} else if ( ! this.formValid ) {
|
||||
message =
|
||||
this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
||||
}
|
||||
|
||||
this.errorHandler.message(message);
|
||||
this.errorHandler.message( message );
|
||||
}
|
||||
}
|
||||
|
||||
_cardNumberFiledCLassNameByCardType(cardType) {
|
||||
return cardType === 'american-express' ? 'amex' : cardType.replace('-', '');
|
||||
_cardNumberFiledCLassNameByCardType( cardType ) {
|
||||
return cardType === 'american-express'
|
||||
? 'amex'
|
||||
: cardType.replace( '-', '' );
|
||||
}
|
||||
|
||||
_recreateElementClassAttribute(element, newClassName) {
|
||||
element.removeAttribute('class')
|
||||
element.setAttribute('class', newClassName);
|
||||
_recreateElementClassAttribute( element, newClassName ) {
|
||||
element.removeAttribute( 'class' );
|
||||
element.setAttribute( 'class', newClassName );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,49 +1,53 @@
|
|||
import widgetBuilder from "./WidgetBuilder";
|
||||
import widgetBuilder from './WidgetBuilder';
|
||||
|
||||
class MessageRenderer {
|
||||
|
||||
constructor(config) {
|
||||
constructor( config ) {
|
||||
this.config = config;
|
||||
this.optionsFingerprint = null;
|
||||
this.currentNumber = 0;
|
||||
}
|
||||
|
||||
renderWithAmount(amount) {
|
||||
if (! this.shouldRender()) {
|
||||
renderWithAmount( amount ) {
|
||||
if ( ! this.shouldRender() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
amount,
|
||||
};
|
||||
if (this.config.placement) {
|
||||
if ( this.config.placement ) {
|
||||
options.placement = this.config.placement;
|
||||
}
|
||||
if (this.config.style) {
|
||||
if ( this.config.style ) {
|
||||
options.style = this.config.style;
|
||||
}
|
||||
|
||||
// sometimes the element is destroyed while the options stay the same
|
||||
if (document.querySelector(this.config.wrapper).getAttribute('data-render-number') !== this.currentNumber.toString()) {
|
||||
if (
|
||||
document
|
||||
.querySelector( this.config.wrapper )
|
||||
.getAttribute( 'data-render-number' ) !==
|
||||
this.currentNumber.toString()
|
||||
) {
|
||||
this.optionsFingerprint = null;
|
||||
}
|
||||
|
||||
if (this.optionsEqual(options)) {
|
||||
if ( this.optionsEqual( options ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const wrapper = document.querySelector(this.config.wrapper);
|
||||
const wrapper = document.querySelector( this.config.wrapper );
|
||||
this.currentNumber++;
|
||||
wrapper.setAttribute('data-render-number', this.currentNumber);
|
||||
wrapper.setAttribute( 'data-render-number', this.currentNumber );
|
||||
|
||||
widgetBuilder.registerMessages(this.config.wrapper, options);
|
||||
widgetBuilder.renderMessages(this.config.wrapper);
|
||||
widgetBuilder.registerMessages( this.config.wrapper, options );
|
||||
widgetBuilder.renderMessages( this.config.wrapper );
|
||||
}
|
||||
|
||||
optionsEqual(options) {
|
||||
const fingerprint = JSON.stringify(options);
|
||||
optionsEqual( options ) {
|
||||
const fingerprint = JSON.stringify( options );
|
||||
|
||||
if (this.optionsFingerprint === fingerprint) {
|
||||
if ( this.optionsFingerprint === fingerprint ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -52,11 +56,14 @@ class MessageRenderer {
|
|||
}
|
||||
|
||||
shouldRender() {
|
||||
|
||||
if (typeof paypal === 'undefined' || typeof paypal.Messages === 'undefined' || typeof this.config.wrapper === 'undefined' ) {
|
||||
if (
|
||||
typeof paypal === 'undefined' ||
|
||||
typeof paypal.Messages === 'undefined' ||
|
||||
typeof this.config.wrapper === 'undefined'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
if (! document.querySelector(this.config.wrapper)) {
|
||||
if ( ! document.querySelector( this.config.wrapper ) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -6,13 +6,10 @@ import merge from 'deepmerge';
|
|||
class PreviewButton {
|
||||
/**
|
||||
* @param {string} selector - CSS ID of the wrapper, including the `#`
|
||||
* @param {object} apiConfig - PayPal configuration object; retrieved via a
|
||||
* @param {Object} apiConfig - PayPal configuration object; retrieved via a
|
||||
* widgetBuilder API method
|
||||
*/
|
||||
constructor({
|
||||
selector,
|
||||
apiConfig,
|
||||
}) {
|
||||
constructor( { selector, apiConfig } ) {
|
||||
this.apiConfig = apiConfig;
|
||||
this.defaultAttributes = {};
|
||||
this.buttonConfig = {};
|
||||
|
@ -32,10 +29,10 @@ class PreviewButton {
|
|||
* @return {jQuery} Always a single jQuery element with the new DOM node.
|
||||
*/
|
||||
createNewWrapper() {
|
||||
const previewId = this.selector.replace('#', '');
|
||||
const previewId = this.selector.replace( '#', '' );
|
||||
const previewClass = 'ppcp-button-apm';
|
||||
|
||||
return jQuery(`<div id='${previewId}' class='${previewClass}'>`);
|
||||
return jQuery( `<div id='${ previewId }' class='${ previewClass }'>` );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -43,9 +40,10 @@ class PreviewButton {
|
|||
* When the button is dynamic, it will reflect current form values. A static button always
|
||||
* uses the settings that were provided via PHP.
|
||||
*
|
||||
* @param state
|
||||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
setDynamic(state) {
|
||||
setDynamic( state ) {
|
||||
this.isDynamic = state;
|
||||
return this;
|
||||
}
|
||||
|
@ -53,10 +51,11 @@ class PreviewButton {
|
|||
/**
|
||||
* Sets server-side configuration for the button.
|
||||
*
|
||||
* @param config
|
||||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
setButtonConfig(config) {
|
||||
this.buttonConfig = merge(this.defaultAttributes, config);
|
||||
setButtonConfig( config ) {
|
||||
this.buttonConfig = merge( this.defaultAttributes, config );
|
||||
this.buttonConfig.button.wrapper = this.selector;
|
||||
|
||||
return this;
|
||||
|
@ -65,10 +64,11 @@ class PreviewButton {
|
|||
/**
|
||||
* Updates the button configuration with current details from the form.
|
||||
*
|
||||
* @param config
|
||||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
setPpcpConfig(config) {
|
||||
this.ppcpConfig = merge({}, config);
|
||||
setPpcpConfig( config ) {
|
||||
this.ppcpConfig = merge( {}, config );
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -76,17 +76,22 @@ class PreviewButton {
|
|||
/**
|
||||
* Merge form details into the config object for preview.
|
||||
* Mutates the previewConfig object; no return value.
|
||||
* @param previewConfig
|
||||
* @param formConfig
|
||||
*/
|
||||
dynamicPreviewConfig(previewConfig, formConfig) {
|
||||
dynamicPreviewConfig( previewConfig, formConfig ) {
|
||||
// Implement in derived class.
|
||||
}
|
||||
|
||||
/**
|
||||
* Responsible for creating the actual payment button preview.
|
||||
* Called by the `render()` method, after the wrapper DOM element is ready.
|
||||
* @param previewConfig
|
||||
*/
|
||||
createButton(previewConfig) {
|
||||
throw new Error('The "createButton" method must be implemented by the derived class');
|
||||
createButton( previewConfig ) {
|
||||
throw new Error(
|
||||
'The "createButton" method must be implemented by the derived class'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,40 +100,47 @@ class PreviewButton {
|
|||
*/
|
||||
render() {
|
||||
// The APM button is disabled and cannot be enabled on the current page: Do not render it.
|
||||
if (!this.isDynamic && !this.buttonConfig.is_enabled) {
|
||||
if ( ! this.isDynamic && ! this.buttonConfig.is_enabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.domWrapper) {
|
||||
if (!this.wrapper) {
|
||||
console.error('Skip render, button is not configured yet');
|
||||
if ( ! this.domWrapper ) {
|
||||
if ( ! this.wrapper ) {
|
||||
console.error( 'Skip render, button is not configured yet' );
|
||||
return;
|
||||
}
|
||||
this.domWrapper = this.createNewWrapper();
|
||||
this.domWrapper.insertAfter(this.wrapper);
|
||||
this.domWrapper.insertAfter( this.wrapper );
|
||||
} else {
|
||||
this.domWrapper.empty().show();
|
||||
}
|
||||
|
||||
this.isVisible = true;
|
||||
const previewButtonConfig = merge({}, this.buttonConfig);
|
||||
const previewPpcpConfig = this.isDynamic ? merge({}, this.ppcpConfig) : {};
|
||||
const previewButtonConfig = merge( {}, this.buttonConfig );
|
||||
const previewPpcpConfig = this.isDynamic
|
||||
? merge( {}, this.ppcpConfig )
|
||||
: {};
|
||||
previewButtonConfig.button.wrapper = this.selector;
|
||||
|
||||
this.dynamicPreviewConfig(previewButtonConfig, previewPpcpConfig);
|
||||
this.dynamicPreviewConfig( previewButtonConfig, previewPpcpConfig );
|
||||
|
||||
/*
|
||||
* previewButtonConfig.button.wrapper must be different from this.ppcpConfig.button.wrapper!
|
||||
* If both selectors point to the same element, an infinite loop is triggered.
|
||||
*/
|
||||
const buttonWrapper = previewButtonConfig.button.wrapper.replace(/^#/, '');
|
||||
const ppcpWrapper = this.ppcpConfig.button.wrapper.replace(/^#/, '');
|
||||
const buttonWrapper = previewButtonConfig.button.wrapper.replace(
|
||||
/^#/,
|
||||
''
|
||||
);
|
||||
const ppcpWrapper = this.ppcpConfig.button.wrapper.replace( /^#/, '' );
|
||||
|
||||
if (buttonWrapper === ppcpWrapper) {
|
||||
throw new Error(`[APM Preview Button] Infinite loop detected. Provide different selectors for the button/ppcp wrapper elements! Selector: "#${buttonWrapper}"`);
|
||||
if ( buttonWrapper === ppcpWrapper ) {
|
||||
throw new Error(
|
||||
`[APM Preview Button] Infinite loop detected. Provide different selectors for the button/ppcp wrapper elements! Selector: "#${ buttonWrapper }"`
|
||||
);
|
||||
}
|
||||
|
||||
this.createButton(previewButtonConfig);
|
||||
this.createButton( previewButtonConfig );
|
||||
|
||||
/*
|
||||
* Unfortunately, a hacky way that is required to guarantee that this preview button is
|
||||
|
@ -139,13 +151,13 @@ class PreviewButton {
|
|||
* Using a timeout here will make the button visible again at the end of the current
|
||||
* event queue.
|
||||
*/
|
||||
setTimeout(() => this.domWrapper.show());
|
||||
setTimeout( () => this.domWrapper.show() );
|
||||
}
|
||||
|
||||
remove() {
|
||||
this.isVisible = false;
|
||||
|
||||
if (this.domWrapper) {
|
||||
if ( this.domWrapper ) {
|
||||
this.domWrapper.hide().empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,11 +20,7 @@ class PreviewButtonManager {
|
|||
*/
|
||||
#onInit;
|
||||
|
||||
constructor({
|
||||
methodName,
|
||||
buttonConfig,
|
||||
defaultAttributes,
|
||||
}) {
|
||||
constructor( { methodName, buttonConfig, defaultAttributes } ) {
|
||||
// Define the payment method name in the derived class.
|
||||
this.methodName = methodName;
|
||||
|
||||
|
@ -36,12 +32,12 @@ class PreviewButtonManager {
|
|||
this.apiConfig = null;
|
||||
this.apiError = '';
|
||||
|
||||
this.#onInit = new Promise(resolve => {
|
||||
this.#onInit = new Promise( ( resolve ) => {
|
||||
this.#onInitResolver = resolve;
|
||||
});
|
||||
} );
|
||||
|
||||
this.bootstrap = this.bootstrap.bind(this);
|
||||
this.renderPreview = this.renderPreview.bind(this);
|
||||
this.bootstrap = this.bootstrap.bind( this );
|
||||
this.renderPreview = this.renderPreview.bind( this );
|
||||
|
||||
/**
|
||||
* The "configureAllButtons" method applies ppcpConfig to all buttons that were created
|
||||
|
@ -52,7 +48,10 @@ class PreviewButtonManager {
|
|||
* buttons, but only a single time, passing in a random button's wrapper-ID; however,
|
||||
* that event should always refresh all preview buttons, not only that single button.
|
||||
*/
|
||||
this._configureAllButtons = debounce(this._configureAllButtons.bind(this), 100);
|
||||
this._configureAllButtons = debounce(
|
||||
this._configureAllButtons.bind( this ),
|
||||
100
|
||||
);
|
||||
|
||||
this.registerEventListeners();
|
||||
}
|
||||
|
@ -65,8 +64,10 @@ class PreviewButtonManager {
|
|||
* @param {{}} payPal - The PayPal SDK object provided by WidgetBuilder.
|
||||
* @return {Promise<{}>}
|
||||
*/
|
||||
async fetchConfig(payPal) {
|
||||
throw new Error('The "fetchConfig" method must be implemented by the derived class');
|
||||
async fetchConfig( payPal ) {
|
||||
throw new Error(
|
||||
'The "fetchConfig" method must be implemented by the derived class'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,8 +77,10 @@ class PreviewButtonManager {
|
|||
* @param {string} wrapperId - CSS ID of the wrapper element.
|
||||
* @return {PreviewButton}
|
||||
*/
|
||||
createButtonInstance(wrapperId) {
|
||||
throw new Error('The "createButtonInstance" method must be implemented by the derived class');
|
||||
createButtonInstance( wrapperId ) {
|
||||
throw new Error(
|
||||
'The "createButtonInstance" method must be implemented by the derived class'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,12 +93,14 @@ class PreviewButtonManager {
|
|||
* @param wrapperId
|
||||
* @return {any}
|
||||
*/
|
||||
createDummy(wrapperId) {
|
||||
const elButton = document.createElement('div');
|
||||
elButton.classList.add('ppcp-button-apm', 'ppcp-button-dummy');
|
||||
elButton.innerHTML = `<span>${this.apiError ?? 'Not Available'}</span>`;
|
||||
createDummy( wrapperId ) {
|
||||
const elButton = document.createElement( 'div' );
|
||||
elButton.classList.add( 'ppcp-button-apm', 'ppcp-button-dummy' );
|
||||
elButton.innerHTML = `<span>${
|
||||
this.apiError ?? 'Not Available'
|
||||
}</span>`;
|
||||
|
||||
document.querySelector(wrapperId).appendChild(elButton);
|
||||
document.querySelector( wrapperId ).appendChild( elButton );
|
||||
|
||||
const instDummy = {
|
||||
setDynamic: () => instDummy,
|
||||
|
@ -108,20 +113,28 @@ class PreviewButtonManager {
|
|||
}
|
||||
|
||||
registerEventListeners() {
|
||||
jQuery(document).one('DOMContentLoaded', this.bootstrap);
|
||||
jQuery( document ).one( 'DOMContentLoaded', this.bootstrap );
|
||||
|
||||
// General event that all APM buttons react to.
|
||||
jQuery(document).on('ppcp_paypal_render_preview', this.renderPreview);
|
||||
jQuery( document ).on(
|
||||
'ppcp_paypal_render_preview',
|
||||
this.renderPreview
|
||||
);
|
||||
|
||||
// Specific event to only (re)render the current APM button type.
|
||||
jQuery(document).on(`ppcp_paypal_render_preview_${this.methodName}`, this.renderPreview);
|
||||
jQuery( document ).on(
|
||||
`ppcp_paypal_render_preview_${ this.methodName }`,
|
||||
this.renderPreview
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output an error message to the console, with a module-specific prefix.
|
||||
* @param message
|
||||
* @param {...any} args
|
||||
*/
|
||||
error(message, ...args) {
|
||||
console.error(`${this.methodName} ${message}`, ...args);
|
||||
error( message, ...args ) {
|
||||
console.error( `${ this.methodName } ${ message }`, ...args );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,7 +143,9 @@ class PreviewButtonManager {
|
|||
* style settings that were provided from server-side.
|
||||
*/
|
||||
isDynamic() {
|
||||
return !!document.querySelector(`[data-ppcp-apm-name="${this.methodName}"]`);
|
||||
return !! document.querySelector(
|
||||
`[data-ppcp-apm-name="${ this.methodName }"]`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,48 +159,56 @@ class PreviewButtonManager {
|
|||
const MAX_WAIT_TIME = 10000; // Fail, if PayPal SDK is unavailable after 10 seconds.
|
||||
const RESOLVE_INTERVAL = 200;
|
||||
|
||||
if (!this.buttonConfig?.sdk_url || !widgetBuilder) {
|
||||
this.error('Button could not be configured.');
|
||||
if ( ! this.buttonConfig?.sdk_url || ! widgetBuilder ) {
|
||||
this.error( 'Button could not be configured.' );
|
||||
return;
|
||||
}
|
||||
|
||||
// This is a localization object of "gateway-settings.js". If it's missing, the script was
|
||||
// not loaded.
|
||||
if (!window.PayPalCommerceGatewaySettings) {
|
||||
if ( ! window.PayPalCommerceGatewaySettings ) {
|
||||
this.error(
|
||||
'PayPal settings are not fully loaded. Please clear the cache and reload the page.');
|
||||
'PayPal settings are not fully loaded. Please clear the cache and reload the page.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// A helper function that clears the interval and resolves/rejects the promise.
|
||||
const resolveOrReject = (resolve, reject, id, success = true) => {
|
||||
clearInterval(id);
|
||||
success ? resolve() : reject('Timeout while waiting for widgetBuilder.paypal');
|
||||
const resolveOrReject = ( resolve, reject, id, success = true ) => {
|
||||
clearInterval( id );
|
||||
success
|
||||
? resolve()
|
||||
: reject( 'Timeout while waiting for widgetBuilder.paypal' );
|
||||
};
|
||||
|
||||
// Wait for the PayPal SDK to be ready.
|
||||
const paypalPromise = new Promise((resolve, reject) => {
|
||||
const paypalPromise = new Promise( ( resolve, reject ) => {
|
||||
let elapsedTime = 0;
|
||||
|
||||
const id = setInterval(() => {
|
||||
if (widgetBuilder.paypal) {
|
||||
resolveOrReject(resolve, reject, id);
|
||||
} else if (elapsedTime >= MAX_WAIT_TIME) {
|
||||
resolveOrReject(resolve, reject, id, false);
|
||||
const id = setInterval( () => {
|
||||
if ( widgetBuilder.paypal ) {
|
||||
resolveOrReject( resolve, reject, id );
|
||||
} else if ( elapsedTime >= MAX_WAIT_TIME ) {
|
||||
resolveOrReject( resolve, reject, id, false );
|
||||
}
|
||||
elapsedTime += RESOLVE_INTERVAL;
|
||||
}, RESOLVE_INTERVAL);
|
||||
});
|
||||
}, RESOLVE_INTERVAL );
|
||||
} );
|
||||
|
||||
// Load the custom SDK script.
|
||||
const customScriptPromise = loadCustomScript({ url: this.buttonConfig.sdk_url });
|
||||
const customScriptPromise = loadCustomScript( {
|
||||
url: this.buttonConfig.sdk_url,
|
||||
} );
|
||||
|
||||
// Wait for both promises to resolve before continuing.
|
||||
await Promise
|
||||
.all([customScriptPromise, paypalPromise])
|
||||
.catch(err => {
|
||||
console.log(`Failed to load ${this.methodName} dependencies:`, err);
|
||||
});
|
||||
await Promise.all( [ customScriptPromise, paypalPromise ] ).catch(
|
||||
( err ) => {
|
||||
console.log(
|
||||
`Failed to load ${ this.methodName } dependencies:`,
|
||||
err
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
/*
|
||||
The fetchConfig method requires two objects to succeed:
|
||||
|
@ -193,8 +216,8 @@ class PreviewButtonManager {
|
|||
(b) the `widgetBuilder.paypal` object
|
||||
*/
|
||||
try {
|
||||
this.apiConfig = await this.fetchConfig(widgetBuilder.paypal);
|
||||
} catch (error) {
|
||||
this.apiConfig = await this.fetchConfig( widgetBuilder.paypal );
|
||||
} catch ( error ) {
|
||||
this.apiConfig = null;
|
||||
}
|
||||
|
||||
|
@ -210,23 +233,23 @@ class PreviewButtonManager {
|
|||
* @param ev - Ignored
|
||||
* @param ppcpConfig - The button settings for the preview.
|
||||
*/
|
||||
renderPreview(ev, ppcpConfig) {
|
||||
renderPreview( ev, ppcpConfig ) {
|
||||
const id = ppcpConfig.button.wrapper;
|
||||
|
||||
if (!id) {
|
||||
this.error('Button did not provide a wrapper ID', ppcpConfig);
|
||||
if ( ! id ) {
|
||||
this.error( 'Button did not provide a wrapper ID', ppcpConfig );
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.shouldInsertPreviewButton(id)) {
|
||||
if ( ! this.shouldInsertPreviewButton( id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.buttons[id]) {
|
||||
this._addButton(id, ppcpConfig);
|
||||
if ( ! this.buttons[ id ] ) {
|
||||
this._addButton( id, ppcpConfig );
|
||||
} else {
|
||||
// This is a debounced method, that fires after 100ms.
|
||||
this._configureAllButtons(ppcpConfig);
|
||||
this._configureAllButtons( ppcpConfig );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,30 +261,33 @@ class PreviewButtonManager {
|
|||
* @param {string} previewId - ID of the inner preview box container.
|
||||
* @return {boolean} True if the box is eligible for the preview button, false otherwise.
|
||||
*/
|
||||
shouldInsertPreviewButton(previewId) {
|
||||
const container = document.querySelector(previewId);
|
||||
const box = container.closest('.ppcp-preview');
|
||||
shouldInsertPreviewButton( previewId ) {
|
||||
const container = document.querySelector( previewId );
|
||||
const box = container.closest( '.ppcp-preview' );
|
||||
const limit = box.dataset.ppcpPreviewBlock ?? 'all';
|
||||
|
||||
return ('all' === limit) || (this.methodName === limit);
|
||||
return 'all' === limit || this.methodName === limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a new configuration to an existing preview button.
|
||||
* @param id
|
||||
* @param ppcpConfig
|
||||
*/
|
||||
_configureButton(id, ppcpConfig) {
|
||||
this.buttons[id]
|
||||
.setDynamic(this.isDynamic())
|
||||
.setPpcpConfig(ppcpConfig)
|
||||
_configureButton( id, ppcpConfig ) {
|
||||
this.buttons[ id ]
|
||||
.setDynamic( this.isDynamic() )
|
||||
.setPpcpConfig( ppcpConfig )
|
||||
.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apples the provided configuration to all existing preview buttons.
|
||||
* @param ppcpConfig
|
||||
*/
|
||||
_configureAllButtons(ppcpConfig) {
|
||||
Object.entries(this.buttons).forEach(([id, button]) => {
|
||||
this._configureButton(id, {
|
||||
_configureAllButtons( ppcpConfig ) {
|
||||
Object.entries( this.buttons ).forEach( ( [ id, button ] ) => {
|
||||
this._configureButton( id, {
|
||||
...ppcpConfig,
|
||||
button: {
|
||||
...ppcpConfig.button,
|
||||
|
@ -270,31 +296,35 @@ class PreviewButtonManager {
|
|||
// Fix the selector, to avoid unintentionally hidden preview buttons.
|
||||
wrapper: button.wrapper,
|
||||
},
|
||||
});
|
||||
});
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new preview button, that is rendered once the bootstrapping Promise resolves.
|
||||
* @param id
|
||||
* @param ppcpConfig
|
||||
*/
|
||||
_addButton(id, ppcpConfig) {
|
||||
_addButton( id, ppcpConfig ) {
|
||||
const createButton = () => {
|
||||
if (!this.buttons[id]) {
|
||||
if ( ! this.buttons[ id ] ) {
|
||||
let newInst;
|
||||
if (this.apiConfig && 'object' === typeof this.apiConfig) {
|
||||
newInst = this.createButtonInstance(id).setButtonConfig(this.buttonConfig);
|
||||
if ( this.apiConfig && 'object' === typeof this.apiConfig ) {
|
||||
newInst = this.createButtonInstance( id ).setButtonConfig(
|
||||
this.buttonConfig
|
||||
);
|
||||
} else {
|
||||
newInst = this.createDummy(id);
|
||||
newInst = this.createDummy( id );
|
||||
}
|
||||
|
||||
this.buttons[id] = newInst;
|
||||
this.buttons[ id ] = newInst;
|
||||
}
|
||||
|
||||
this._configureButton(id, ppcpConfig);
|
||||
this._configureButton( id, ppcpConfig );
|
||||
};
|
||||
|
||||
if (this.#onInit) {
|
||||
this.#onInit.then(createButton);
|
||||
if ( this.#onInit ) {
|
||||
this.#onInit.then( createButton );
|
||||
} else {
|
||||
createButton();
|
||||
}
|
||||
|
@ -306,10 +336,14 @@ class PreviewButtonManager {
|
|||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
renderButtons() {
|
||||
if (this.isEnabled) {
|
||||
Object.values(this.buttons).forEach(button => button.render());
|
||||
if ( this.isEnabled ) {
|
||||
Object.values( this.buttons ).forEach( ( button ) =>
|
||||
button.render()
|
||||
);
|
||||
} else {
|
||||
Object.values(this.buttons).forEach(button => button.remove());
|
||||
Object.values( this.buttons ).forEach( ( button ) =>
|
||||
button.remove()
|
||||
);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
@ -321,7 +355,7 @@ class PreviewButtonManager {
|
|||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
enable() {
|
||||
if (!this.isEnabled) {
|
||||
if ( ! this.isEnabled ) {
|
||||
this.isEnabled = true;
|
||||
this.renderButtons();
|
||||
}
|
||||
|
@ -335,7 +369,7 @@ class PreviewButtonManager {
|
|||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
disable() {
|
||||
if (!this.isEnabled) {
|
||||
if ( ! this.isEnabled ) {
|
||||
this.isEnabled = false;
|
||||
this.renderButtons();
|
||||
}
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
import merge from "deepmerge";
|
||||
import {loadScript} from "@paypal/paypal-js";
|
||||
import {keysToCamelCase} from "../Helper/Utils";
|
||||
import widgetBuilder from "./WidgetBuilder";
|
||||
import {normalizeStyleForFundingSource} from "../Helper/Style";
|
||||
import merge from 'deepmerge';
|
||||
import { loadScript } from '@paypal/paypal-js';
|
||||
import { keysToCamelCase } from '../Helper/Utils';
|
||||
import widgetBuilder from './WidgetBuilder';
|
||||
import { normalizeStyleForFundingSource } from '../Helper/Style';
|
||||
import {
|
||||
handleShippingOptionsChange,
|
||||
handleShippingAddressChange,
|
||||
} from "../Helper/ShippingHandler.js";
|
||||
} from '../Helper/ShippingHandler.js';
|
||||
|
||||
class Renderer {
|
||||
constructor(creditCardRenderer, defaultSettings, onSmartButtonClick, onSmartButtonsInit) {
|
||||
constructor(
|
||||
creditCardRenderer,
|
||||
defaultSettings,
|
||||
onSmartButtonClick,
|
||||
onSmartButtonsInit
|
||||
) {
|
||||
this.defaultSettings = defaultSettings;
|
||||
this.creditCardRenderer = creditCardRenderer;
|
||||
this.onSmartButtonClick = onSmartButtonClick;
|
||||
|
@ -23,15 +28,22 @@ class Renderer {
|
|||
this.reloadEventName = 'ppcp-reload-buttons';
|
||||
}
|
||||
|
||||
render(contextConfig, settingsOverride = {}, contextConfigOverride = () => {}) {
|
||||
const settings = merge(this.defaultSettings, settingsOverride);
|
||||
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;
|
||||
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) {
|
||||
if ( ! hasEnabledSeparateGateways ) {
|
||||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
settings.button.style,
|
||||
|
@ -40,8 +52,13 @@ class Renderer {
|
|||
);
|
||||
} else {
|
||||
// render each button separately
|
||||
for (const fundingSource of paypal.getFundingSources().filter(s => !(s in enabledSeparateGateways))) {
|
||||
const style = normalizeStyleForFundingSource(settings.button.style, fundingSource);
|
||||
for ( const fundingSource of paypal
|
||||
.getFundingSources()
|
||||
.filter( ( s ) => ! ( s in enabledSeparateGateways ) ) ) {
|
||||
const style = normalizeStyleForFundingSource(
|
||||
settings.button.style,
|
||||
fundingSource
|
||||
);
|
||||
|
||||
this.renderButtons(
|
||||
settings.button.wrapper,
|
||||
|
@ -53,11 +70,16 @@ class Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.creditCardRenderer) {
|
||||
this.creditCardRenderer.render(settings.hosted_fields.wrapper, contextConfigOverride);
|
||||
if ( this.creditCardRenderer ) {
|
||||
this.creditCardRenderer.render(
|
||||
settings.hosted_fields.wrapper,
|
||||
contextConfigOverride
|
||||
);
|
||||
}
|
||||
|
||||
for (const [fundingSource, data] of Object.entries(enabledSeparateGateways)) {
|
||||
for ( const [ fundingSource, data ] of Object.entries(
|
||||
enabledSeparateGateways
|
||||
) ) {
|
||||
this.renderButtons(
|
||||
data.wrapper,
|
||||
data.style,
|
||||
|
@ -68,14 +90,27 @@ class Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
renderButtons(wrapper, style, contextConfig, hasEnabledSeparateGateways, fundingSource = null) {
|
||||
if (! document.querySelector(wrapper) || this.isAlreadyRendered(wrapper, fundingSource, hasEnabledSeparateGateways) ) {
|
||||
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]);
|
||||
widgetBuilder.renderButtons( [ wrapper, fundingSource ] );
|
||||
return;
|
||||
}
|
||||
|
||||
if (fundingSource) {
|
||||
if ( fundingSource ) {
|
||||
contextConfig.fundingSource = fundingSource;
|
||||
}
|
||||
|
||||
|
@ -85,75 +120,115 @@ class Renderer {
|
|||
const options = {
|
||||
style,
|
||||
...contextConfig,
|
||||
onClick: (data, actions) => {
|
||||
if (this.onSmartButtonClick) {
|
||||
this.onSmartButtonClick(data, actions);
|
||||
onClick: ( data, actions ) => {
|
||||
if ( this.onSmartButtonClick ) {
|
||||
this.onSmartButtonClick( data, actions );
|
||||
}
|
||||
|
||||
venmoButtonClicked = false;
|
||||
if (data.fundingSource === 'venmo') {
|
||||
if ( data.fundingSource === 'venmo' ) {
|
||||
venmoButtonClicked = true;
|
||||
}
|
||||
},
|
||||
onInit: (data, actions) => {
|
||||
if (this.onSmartButtonsInit) {
|
||||
this.onSmartButtonsInit(data, actions);
|
||||
onInit: ( data, actions ) => {
|
||||
if ( this.onSmartButtonsInit ) {
|
||||
this.onSmartButtonsInit( data, actions );
|
||||
}
|
||||
this.handleOnButtonsInit(wrapper, data, actions);
|
||||
this.handleOnButtonsInit( wrapper, data, actions );
|
||||
},
|
||||
};
|
||||
|
||||
// Check the condition and add the handler if needed
|
||||
if (this.defaultSettings.should_handle_shipping_in_paypal) {
|
||||
options.onShippingOptionsChange = (data, actions) => {
|
||||
!this.isVenmoButtonClickedWhenVaultingIsEnabled(venmoButtonClicked)
|
||||
? handleShippingOptionsChange(data, actions, this.defaultSettings)
|
||||
if ( this.defaultSettings.should_handle_shipping_in_paypal ) {
|
||||
options.onShippingOptionsChange = ( data, actions ) => {
|
||||
let shippingOptionsChange =
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingOptionsChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
}
|
||||
options.onShippingAddressChange = (data, actions) => {
|
||||
!this.isVenmoButtonClickedWhenVaultingIsEnabled(venmoButtonClicked)
|
||||
? handleShippingAddressChange(data, actions, this.defaultSettings)
|
||||
|
||||
return shippingOptionsChange
|
||||
};
|
||||
options.onShippingAddressChange = ( data, actions ) => {
|
||||
let shippingAddressChange =
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingAddressChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
return shippingAddressChange
|
||||
};
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
|
||||
jQuery(document)
|
||||
.off(this.reloadEventName, wrapper)
|
||||
.on(this.reloadEventName, wrapper, (event, settingsOverride = {}, triggeredFundingSource) => {
|
||||
|
||||
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)) {
|
||||
if (
|
||||
fundingSource &&
|
||||
triggeredFundingSource &&
|
||||
triggeredFundingSource !== fundingSource
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const settings = merge(this.defaultSettings, settingsOverride);
|
||||
let scriptOptions = keysToCamelCase(settings.url_params);
|
||||
scriptOptions = merge(scriptOptions, settings.script_attributes);
|
||||
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());
|
||||
loadScript( scriptOptions ).then( ( paypal ) => {
|
||||
widgetBuilder.setPaypal( paypal );
|
||||
widgetBuilder.registerButtons(
|
||||
[ wrapper, fundingSource ],
|
||||
buttonsOptions()
|
||||
);
|
||||
widgetBuilder.renderAll();
|
||||
});
|
||||
});
|
||||
} );
|
||||
}
|
||||
);
|
||||
|
||||
this.renderedSources.add(wrapper + (fundingSource ?? ''));
|
||||
this.renderedSources.add( wrapper + ( fundingSource ?? '' ) );
|
||||
|
||||
if (typeof paypal !== 'undefined' && typeof paypal.Buttons !== 'undefined') {
|
||||
widgetBuilder.registerButtons([wrapper, fundingSource], buttonsOptions());
|
||||
widgetBuilder.renderButtons([wrapper, fundingSource]);
|
||||
if (
|
||||
typeof paypal !== 'undefined' &&
|
||||
typeof paypal.Buttons !== 'undefined'
|
||||
) {
|
||||
widgetBuilder.registerButtons(
|
||||
[ wrapper, fundingSource ],
|
||||
buttonsOptions()
|
||||
);
|
||||
widgetBuilder.renderButtons( [ wrapper, fundingSource ] );
|
||||
}
|
||||
}
|
||||
|
||||
isVenmoButtonClickedWhenVaultingIsEnabled = (venmoButtonClicked) => {
|
||||
isVenmoButtonClickedWhenVaultingIsEnabled = ( venmoButtonClicked ) => {
|
||||
return venmoButtonClicked && this.defaultSettings.vaultingEnabled;
|
||||
}
|
||||
};
|
||||
|
||||
isAlreadyRendered(wrapper, fundingSource) {
|
||||
return this.renderedSources.has(wrapper + (fundingSource ?? ''));
|
||||
isAlreadyRendered( wrapper, fundingSource ) {
|
||||
return this.renderedSources.has( wrapper + ( fundingSource ?? '' ) );
|
||||
}
|
||||
|
||||
disableCreditCardFields() {
|
||||
|
@ -164,49 +239,50 @@ class Renderer {
|
|||
this.creditCardRenderer.enableFields();
|
||||
}
|
||||
|
||||
onButtonsInit(wrapper, handler, reset) {
|
||||
this.onButtonsInitListeners[wrapper] = reset ? [] : (this.onButtonsInitListeners[wrapper] || []);
|
||||
this.onButtonsInitListeners[wrapper].push(handler);
|
||||
onButtonsInit( wrapper, handler, reset ) {
|
||||
this.onButtonsInitListeners[ wrapper ] = reset
|
||||
? []
|
||||
: this.onButtonsInitListeners[ wrapper ] || [];
|
||||
this.onButtonsInitListeners[ wrapper ].push( handler );
|
||||
}
|
||||
|
||||
handleOnButtonsInit(wrapper, data, actions) {
|
||||
handleOnButtonsInit( wrapper, data, actions ) {
|
||||
this.buttonsOptions[ wrapper ] = {
|
||||
data,
|
||||
actions,
|
||||
};
|
||||
|
||||
this.buttonsOptions[wrapper] = {
|
||||
data: data,
|
||||
actions: actions
|
||||
}
|
||||
|
||||
if (this.onButtonsInitListeners[wrapper]) {
|
||||
for (let handler of this.onButtonsInitListeners[wrapper]) {
|
||||
if (typeof handler === 'function') {
|
||||
handler({
|
||||
wrapper: wrapper,
|
||||
...this.buttonsOptions[wrapper]
|
||||
});
|
||||
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]) {
|
||||
disableSmartButtons( wrapper ) {
|
||||
if ( ! this.buttonsOptions[ wrapper ] ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.buttonsOptions[wrapper].actions.disable();
|
||||
} catch (err) {
|
||||
console.log('Failed to disable buttons: ' + err);
|
||||
this.buttonsOptions[ wrapper ].actions.disable();
|
||||
} catch ( err ) {
|
||||
console.log( 'Failed to disable buttons: ' + err );
|
||||
}
|
||||
}
|
||||
|
||||
enableSmartButtons(wrapper) {
|
||||
if (!this.buttonsOptions[wrapper]) {
|
||||
enableSmartButtons( wrapper ) {
|
||||
if ( ! this.buttonsOptions[ wrapper ] ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
this.buttonsOptions[wrapper].actions.enable();
|
||||
} catch (err) {
|
||||
console.log('Failed to enable buttons: ' + err);
|
||||
this.buttonsOptions[ wrapper ].actions.enable();
|
||||
} catch ( err ) {
|
||||
console.log( 'Failed to enable buttons: ' + err );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* To have several Buttons per wrapper, an array should be provided, ex: [wrapper, fundingSource].
|
||||
*/
|
||||
class WidgetBuilder {
|
||||
|
||||
constructor() {
|
||||
this.paypal = null;
|
||||
this.buttons = new Map();
|
||||
|
@ -12,102 +11,102 @@ class WidgetBuilder {
|
|||
this.renderEventName = 'ppcp-render';
|
||||
|
||||
document.ppcpWidgetBuilderStatus = () => {
|
||||
console.log({
|
||||
console.log( {
|
||||
buttons: this.buttons,
|
||||
messages: this.messages,
|
||||
});
|
||||
}
|
||||
} );
|
||||
};
|
||||
|
||||
jQuery(document)
|
||||
.off(this.renderEventName)
|
||||
.on(this.renderEventName, () => {
|
||||
jQuery( document )
|
||||
.off( this.renderEventName )
|
||||
.on( this.renderEventName, () => {
|
||||
this.renderAll();
|
||||
});
|
||||
} );
|
||||
}
|
||||
|
||||
setPaypal(paypal) {
|
||||
setPaypal( paypal ) {
|
||||
this.paypal = paypal;
|
||||
jQuery(document).trigger('ppcp-paypal-loaded', paypal);
|
||||
jQuery( document ).trigger( 'ppcp-paypal-loaded', paypal );
|
||||
}
|
||||
|
||||
registerButtons(wrapper, options) {
|
||||
wrapper = this.sanitizeWrapper(wrapper);
|
||||
registerButtons( wrapper, options ) {
|
||||
wrapper = this.sanitizeWrapper( wrapper );
|
||||
|
||||
this.buttons.set(this.toKey(wrapper), {
|
||||
wrapper: wrapper,
|
||||
options: options,
|
||||
});
|
||||
this.buttons.set( this.toKey( wrapper ), {
|
||||
wrapper,
|
||||
options,
|
||||
} );
|
||||
}
|
||||
|
||||
renderButtons(wrapper) {
|
||||
wrapper = this.sanitizeWrapper(wrapper);
|
||||
renderButtons( wrapper ) {
|
||||
wrapper = this.sanitizeWrapper( wrapper );
|
||||
|
||||
if (!this.buttons.has(this.toKey(wrapper))) {
|
||||
if ( ! this.buttons.has( this.toKey( wrapper ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hasRendered(wrapper)) {
|
||||
if ( this.hasRendered( wrapper ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = this.buttons.get(this.toKey(wrapper));
|
||||
const btn = this.paypal.Buttons(entry.options);
|
||||
const entry = this.buttons.get( this.toKey( wrapper ) );
|
||||
const btn = this.paypal.Buttons( entry.options );
|
||||
|
||||
if (!btn.isEligible()) {
|
||||
this.buttons.delete(this.toKey(wrapper));
|
||||
if ( ! btn.isEligible() ) {
|
||||
this.buttons.delete( this.toKey( wrapper ) );
|
||||
return;
|
||||
}
|
||||
|
||||
let target = this.buildWrapperTarget(wrapper);
|
||||
const target = this.buildWrapperTarget( wrapper );
|
||||
|
||||
if (!target) {
|
||||
if ( ! target ) {
|
||||
return;
|
||||
}
|
||||
|
||||
btn.render(target);
|
||||
btn.render( target );
|
||||
}
|
||||
|
||||
renderAllButtons() {
|
||||
for (const [wrapper, entry] of this.buttons) {
|
||||
this.renderButtons(wrapper);
|
||||
for ( const [ wrapper, entry ] of this.buttons ) {
|
||||
this.renderButtons( wrapper );
|
||||
}
|
||||
}
|
||||
|
||||
registerMessages(wrapper, options) {
|
||||
this.messages.set(wrapper, {
|
||||
wrapper: wrapper,
|
||||
options: options
|
||||
});
|
||||
registerMessages( wrapper, options ) {
|
||||
this.messages.set( wrapper, {
|
||||
wrapper,
|
||||
options,
|
||||
} );
|
||||
}
|
||||
|
||||
renderMessages(wrapper) {
|
||||
if (!this.messages.has(wrapper)) {
|
||||
renderMessages( wrapper ) {
|
||||
if ( ! this.messages.has( wrapper ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entry = this.messages.get(wrapper);
|
||||
const entry = this.messages.get( wrapper );
|
||||
|
||||
if (this.hasRendered(wrapper)) {
|
||||
const element = document.querySelector(wrapper);
|
||||
element.setAttribute('data-pp-amount', entry.options.amount);
|
||||
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);
|
||||
const btn = this.paypal.Messages( entry.options );
|
||||
|
||||
btn.render(entry.wrapper);
|
||||
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);
|
||||
setTimeout( () => {
|
||||
if ( ! this.hasRendered( wrapper ) ) {
|
||||
btn.render( entry.wrapper );
|
||||
}
|
||||
}, 100);
|
||||
}, 100 );
|
||||
}
|
||||
|
||||
renderAllMessages() {
|
||||
for (const [wrapper, entry] of this.messages) {
|
||||
this.renderMessages(wrapper);
|
||||
for ( const [ wrapper, entry ] of this.messages ) {
|
||||
this.renderMessages( wrapper );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,63 +115,63 @@ class WidgetBuilder {
|
|||
this.renderAllMessages();
|
||||
}
|
||||
|
||||
hasRendered(wrapper) {
|
||||
hasRendered( wrapper ) {
|
||||
let selector = wrapper;
|
||||
|
||||
if (Array.isArray(wrapper)) {
|
||||
selector = wrapper[0];
|
||||
for (const item of wrapper.slice(1)) {
|
||||
if ( Array.isArray( wrapper ) ) {
|
||||
selector = wrapper[ 0 ];
|
||||
for ( const item of wrapper.slice( 1 ) ) {
|
||||
selector += ' .item-' + item;
|
||||
}
|
||||
}
|
||||
|
||||
const element = document.querySelector(selector);
|
||||
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];
|
||||
sanitizeWrapper( wrapper ) {
|
||||
if ( Array.isArray( wrapper ) ) {
|
||||
wrapper = wrapper.filter( ( item ) => !! item );
|
||||
if ( wrapper.length === 1 ) {
|
||||
wrapper = wrapper[ 0 ];
|
||||
}
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
buildWrapperTarget(wrapper) {
|
||||
buildWrapperTarget( wrapper ) {
|
||||
let target = wrapper;
|
||||
|
||||
if (Array.isArray(wrapper)) {
|
||||
const $wrapper = jQuery(wrapper[0]);
|
||||
if ( Array.isArray( wrapper ) ) {
|
||||
const $wrapper = jQuery( wrapper[ 0 ] );
|
||||
|
||||
if (!$wrapper.length) {
|
||||
if ( ! $wrapper.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const itemClass = 'item-' + wrapper[1];
|
||||
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);
|
||||
let $item = $wrapper.find( '.' + itemClass );
|
||||
|
||||
if (!$item.length) {
|
||||
$item = jQuery(`<div class="${itemClass}"></div>`);
|
||||
$wrapper.append($item);
|
||||
if ( ! $item.length ) {
|
||||
$item = jQuery( `<div class="${ itemClass }"></div>` );
|
||||
$wrapper.append( $item );
|
||||
}
|
||||
|
||||
target = $item.get(0);
|
||||
target = $item.get( 0 );
|
||||
}
|
||||
|
||||
if (!jQuery(target).length) {
|
||||
if ( ! jQuery( target ).length ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
toKey(wrapper) {
|
||||
if (Array.isArray(wrapper)) {
|
||||
return JSON.stringify(wrapper);
|
||||
toKey( wrapper ) {
|
||||
if ( Array.isArray( wrapper ) ) {
|
||||
return JSON.stringify( wrapper );
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
|
|
@ -829,7 +829,9 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
*/
|
||||
do_action( "ppcp_before_{$location_hook}_message_wrapper" );
|
||||
|
||||
$messages_placeholder = '<div class="ppcp-messages" data-partner-attribution-id="Woo_PPCP"></div>';
|
||||
$bn_code = PPCP_PAYPAL_BN_CODE;
|
||||
|
||||
$messages_placeholder = '<div class="ppcp-messages" data-partner-attribution-id="' . esc_attr( $bn_code ) . '"></div>';
|
||||
|
||||
if ( is_array( $block_params ) && ( $block_params['blockName'] ?? false ) ) {
|
||||
$this->render_after_block(
|
||||
|
@ -1163,11 +1165,11 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
),
|
||||
'update_customer_shipping' => array(
|
||||
'shipping_options' => array(
|
||||
'endpoint' => '/wp-json/wc/store/cart/select-shipping-rate',
|
||||
'endpoint' => home_url( UpdateShippingEndpoint::WC_STORE_API_ENDPOINT . 'select-shipping-rate' ),
|
||||
),
|
||||
'shipping_address' => array(
|
||||
'cart_endpoint' => '/wp-json/wc/store/cart/',
|
||||
'update_customer_endpoint' => '/wp-json/wc/store/v1/cart/update-customer/',
|
||||
'cart_endpoint' => home_url( UpdateShippingEndpoint::WC_STORE_API_ENDPOINT ),
|
||||
'update_customer_endpoint' => home_url( UpdateShippingEndpoint::WC_STORE_API_ENDPOINT . 'update-customer' ),
|
||||
),
|
||||
'wp_rest_nonce' => wp_create_nonce( 'wc_store_api' ),
|
||||
'update_shipping_method' => \WC_AJAX::get_endpoint( 'update_shipping_method' ),
|
||||
|
@ -1511,7 +1513,10 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
private function bn_code_for_context( string $context ): string {
|
||||
|
||||
$codes = $this->bn_codes();
|
||||
return ( isset( $codes[ $context ] ) ) ? $codes[ $context ] : 'Woo_PPCP';
|
||||
|
||||
$bn_code = PPCP_PAYPAL_BN_CODE;
|
||||
|
||||
return ( isset( $codes[ $context ] ) ) ? $codes[ $context ] : $bn_code;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1519,13 +1524,15 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
private function bn_codes(): array {
|
||||
private function bn_codes() : array {
|
||||
|
||||
$bn_code = PPCP_PAYPAL_BN_CODE;
|
||||
|
||||
return array(
|
||||
'checkout' => 'Woo_PPCP',
|
||||
'cart' => 'Woo_PPCP',
|
||||
'mini-cart' => 'Woo_PPCP',
|
||||
'product' => 'Woo_PPCP',
|
||||
'checkout' => $bn_code,
|
||||
'cart' => $bn_code,
|
||||
'mini-cart' => $bn_code,
|
||||
'product' => $bn_code,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -14,8 +14,10 @@ use WC_Cart;
|
|||
use WC_Order;
|
||||
use WC_Order_Item_Product;
|
||||
use WC_Order_Item_Shipping;
|
||||
use WC_Product;
|
||||
use WC_Subscription;
|
||||
use WC_Subscriptions_Product;
|
||||
use WC_Tax;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
|
||||
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
|
||||
|
@ -106,6 +108,7 @@ class WooCommerceOrderCreator {
|
|||
* @param Payer|null $payer The payer.
|
||||
* @param Shipping|null $shipping The shipping.
|
||||
* @return void
|
||||
* @psalm-suppress InvalidScalarArgument
|
||||
*/
|
||||
protected function configure_line_items( WC_Order $wc_order, WC_Cart $wc_cart, ?Payer $payer, ?Shipping $shipping ): void {
|
||||
$cart_contents = $wc_cart->get_cart();
|
||||
|
@ -130,18 +133,21 @@ class WooCommerceOrderCreator {
|
|||
return;
|
||||
}
|
||||
|
||||
$total = $product->get_price() * $quantity;
|
||||
$subtotal = wc_get_price_excluding_tax( $product, array( 'qty' => $quantity ) );
|
||||
$subtotal = apply_filters( 'woocommerce_paypal_payments_shipping_callback_cart_line_item_total', $subtotal, $cart_item );
|
||||
|
||||
$item->set_name( $product->get_name() );
|
||||
$item->set_subtotal( $total );
|
||||
$item->set_total( $total );
|
||||
$item->set_subtotal( $subtotal );
|
||||
$item->set_total( $subtotal );
|
||||
|
||||
$this->configure_taxes( $product, $item, $subtotal );
|
||||
|
||||
$product_id = $product->get_id();
|
||||
|
||||
if ( $this->is_subscription( $product_id ) ) {
|
||||
$subscription = $this->create_subscription( $wc_order, $product_id );
|
||||
$sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee( $product );
|
||||
$subscription_total = $total + $sign_up_fee;
|
||||
$subscription_total = (float) $subtotal + (float) $sign_up_fee;
|
||||
|
||||
$item->set_subtotal( $subscription_total );
|
||||
$item->set_total( $subscription_total );
|
||||
|
@ -282,6 +288,30 @@ class WooCommerceOrderCreator {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the taxes.
|
||||
*
|
||||
* @param WC_Product $product The Product.
|
||||
* @param WC_Order_Item_Product $item The line item.
|
||||
* @param float|string $subtotal The subtotal.
|
||||
* @return void
|
||||
* @psalm-suppress InvalidScalarArgument
|
||||
*/
|
||||
protected function configure_taxes( WC_Product $product, WC_Order_Item_Product $item, $subtotal ): void {
|
||||
$tax_rates = WC_Tax::get_rates( $product->get_tax_class() );
|
||||
$taxes = WC_Tax::calc_tax( $subtotal, $tax_rates, true );
|
||||
|
||||
$item->set_tax_class( $product->get_tax_class() );
|
||||
$item->set_total_tax( (float) array_sum( $taxes ) );
|
||||
|
||||
foreach ( $taxes as $tax_rate_id => $tax_amount ) {
|
||||
if ( $tax_amount > 0 ) {
|
||||
$item->add_meta_data( 'tax_rate_id', $tax_rate_id, true );
|
||||
$item->add_meta_data( 'tax_amount', $tax_amount, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the product with given ID is WC subscription.
|
||||
*
|
||||
|
|
|
@ -150,6 +150,30 @@ return array(
|
|||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CN' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
'CAD',
|
||||
'CHF',
|
||||
'CZK',
|
||||
'DKK',
|
||||
'EUR',
|
||||
'GBP',
|
||||
'HKD',
|
||||
'HUF',
|
||||
'ILS',
|
||||
'JPY',
|
||||
'MXN',
|
||||
'NOK',
|
||||
'NZD',
|
||||
'PHP',
|
||||
'PLN',
|
||||
'SEK',
|
||||
'SGD',
|
||||
'THB',
|
||||
'TWD',
|
||||
'USD',
|
||||
),
|
||||
'CY' => array(
|
||||
'AUD',
|
||||
'BRL',
|
||||
|
|
|
@ -1,66 +1,93 @@
|
|||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
const config = PayPalCommerceGatewayOrderTrackingCompat;
|
||||
|
||||
const orderTrackingContainerId = "ppcp_order-tracking";
|
||||
const orderTrackingContainerSelector = "#ppcp_order-tracking .ppcp-tracking-column.shipments";
|
||||
const gzdSaveButton = document.getElementById('order-shipments-save');
|
||||
const loadLocation = location.href + " " + orderTrackingContainerSelector + ">*";
|
||||
const orderTrackingContainerId = 'ppcp_order-tracking';
|
||||
const orderTrackingContainerSelector =
|
||||
'#ppcp_order-tracking .ppcp-tracking-column.shipments';
|
||||
const gzdSaveButton = document.getElementById( 'order-shipments-save' );
|
||||
const loadLocation =
|
||||
location.href + ' ' + orderTrackingContainerSelector + '>*';
|
||||
const gzdSyncEnabled = config.gzd_sync_enabled;
|
||||
const wcShipmentSyncEnabled = config.wc_shipment_sync_enabled;
|
||||
const wcShippingTaxSyncEnabled = config.wc_shipping_tax_sync_enabled;
|
||||
const wcShipmentSaveButton = document.querySelector('#woocommerce-shipment-tracking .button-save-form');
|
||||
const wcShipmentTaxBuyLabelButtonSelector = '.components-modal__screen-overlay .label-purchase-modal__sidebar .purchase-section button.components-button';
|
||||
const wcShipmentSaveButton = document.querySelector(
|
||||
'#woocommerce-shipment-tracking .button-save-form'
|
||||
);
|
||||
const wcShipmentTaxBuyLabelButtonSelector =
|
||||
'.components-modal__screen-overlay .label-purchase-modal__sidebar .purchase-section button.components-button';
|
||||
|
||||
const toggleLoaderVisibility = function() {
|
||||
const loader = document.querySelector('.ppcp-tracking-loader');
|
||||
if (loader) {
|
||||
if (loader.style.display === 'none' || loader.style.display === '') {
|
||||
const toggleLoaderVisibility = function () {
|
||||
const loader = document.querySelector( '.ppcp-tracking-loader' );
|
||||
if ( loader ) {
|
||||
if (
|
||||
loader.style.display === 'none' ||
|
||||
loader.style.display === ''
|
||||
) {
|
||||
loader.style.display = 'block';
|
||||
} else {
|
||||
loader.style.display = 'none';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const waitForTrackingUpdate = function (elementToCheck) {
|
||||
if (elementToCheck.css('display') !== 'none') {
|
||||
setTimeout(() => waitForTrackingUpdate(elementToCheck), 100);
|
||||
const waitForTrackingUpdate = function ( elementToCheck ) {
|
||||
if ( elementToCheck.css( 'display' ) !== 'none' ) {
|
||||
setTimeout( () => waitForTrackingUpdate( elementToCheck ), 100 );
|
||||
} else {
|
||||
jQuery(orderTrackingContainerSelector).load(loadLocation, "", function(){
|
||||
jQuery( orderTrackingContainerSelector ).load(
|
||||
loadLocation,
|
||||
'',
|
||||
function () {
|
||||
toggleLoaderVisibility();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
gzdSyncEnabled &&
|
||||
typeof gzdSaveButton !== 'undefined' &&
|
||||
gzdSaveButton != null
|
||||
) {
|
||||
gzdSaveButton.addEventListener( 'click', function ( event ) {
|
||||
toggleLoaderVisibility();
|
||||
waitForTrackingUpdate( jQuery( '#order-shipments-save' ) );
|
||||
} );
|
||||
}
|
||||
|
||||
if (gzdSyncEnabled && typeof(gzdSaveButton) != 'undefined' && gzdSaveButton != null) {
|
||||
gzdSaveButton.addEventListener('click', function (event) {
|
||||
if (
|
||||
wcShipmentSyncEnabled &&
|
||||
typeof wcShipmentSaveButton !== 'undefined' &&
|
||||
wcShipmentSaveButton != null
|
||||
) {
|
||||
wcShipmentSaveButton.addEventListener( 'click', function ( event ) {
|
||||
toggleLoaderVisibility();
|
||||
waitForTrackingUpdate(jQuery('#order-shipments-save'));
|
||||
})
|
||||
waitForTrackingUpdate( jQuery( '#shipment-tracking-form' ) );
|
||||
} );
|
||||
}
|
||||
|
||||
if (wcShipmentSyncEnabled && typeof(wcShipmentSaveButton) != 'undefined' && wcShipmentSaveButton != null) {
|
||||
wcShipmentSaveButton.addEventListener('click', function (event) {
|
||||
toggleLoaderVisibility();
|
||||
waitForTrackingUpdate(jQuery('#shipment-tracking-form'));
|
||||
})
|
||||
}
|
||||
if (
|
||||
wcShippingTaxSyncEnabled &&
|
||||
typeof wcShippingTaxSyncEnabled !== 'undefined' &&
|
||||
wcShippingTaxSyncEnabled != null
|
||||
) {
|
||||
document.addEventListener( 'click', function ( event ) {
|
||||
const wcShipmentTaxBuyLabelButton = event.target.closest(
|
||||
wcShipmentTaxBuyLabelButtonSelector
|
||||
);
|
||||
|
||||
if (wcShippingTaxSyncEnabled && typeof(wcShippingTaxSyncEnabled) != 'undefined' && wcShippingTaxSyncEnabled != null) {
|
||||
document.addEventListener('click', function(event) {
|
||||
const wcShipmentTaxBuyLabelButton = event.target.closest(wcShipmentTaxBuyLabelButtonSelector);
|
||||
|
||||
if (wcShipmentTaxBuyLabelButton) {
|
||||
if ( wcShipmentTaxBuyLabelButton ) {
|
||||
toggleLoaderVisibility();
|
||||
setTimeout(function () {
|
||||
jQuery(orderTrackingContainerSelector).load(loadLocation, "", function(){
|
||||
setTimeout( function () {
|
||||
jQuery( orderTrackingContainerSelector ).load(
|
||||
loadLocation,
|
||||
'',
|
||||
function () {
|
||||
toggleLoaderVisibility();
|
||||
});
|
||||
}, 10000);
|
||||
}
|
||||
});
|
||||
);
|
||||
}, 10000 );
|
||||
}
|
||||
},
|
||||
);
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue