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 );
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
import ContextHandlerFactory from "./Context/ContextHandlerFactory";
|
||||
import {createAppleErrors} from "./Helper/applePayError";
|
||||
import ContextHandlerFactory from './Context/ContextHandlerFactory';
|
||||
import { createAppleErrors } from './Helper/applePayError';
|
||||
import { setVisible } from '../../../ppcp-button/resources/js/modules/Helper/Hiding';
|
||||
import { setEnabled } from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler';
|
||||
import FormValidator from "../../../ppcp-button/resources/js/modules/Helper/FormValidator";
|
||||
import FormValidator from '../../../ppcp-button/resources/js/modules/Helper/FormValidator';
|
||||
import ErrorHandler from '../../../ppcp-button/resources/js/modules/ErrorHandler';
|
||||
import widgetBuilder from "../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder";
|
||||
import {apmButtonsInit} from "../../../ppcp-button/resources/js/modules/Helper/ApmButtons";
|
||||
import widgetBuilder from '../../../ppcp-button/resources/js/modules/Renderer/WidgetBuilder';
|
||||
import { apmButtonsInit } from '../../../ppcp-button/resources/js/modules/Helper/ApmButtons';
|
||||
|
||||
class ApplepayButton {
|
||||
|
||||
constructor( context, externalHandler, buttonConfig, ppcpConfig ) {
|
||||
apmButtonsInit( ppcpConfig );
|
||||
|
||||
|
@ -27,9 +26,11 @@ class ApplepayButton {
|
|||
this.ppcpConfig
|
||||
);
|
||||
|
||||
this.updatedContactInfo = []
|
||||
this.selectedShippingMethod = []
|
||||
this.nonce = document.getElementById('woocommerce-process-checkout-nonce')?.value || buttonConfig.nonce
|
||||
this.updatedContactInfo = [];
|
||||
this.selectedShippingMethod = [];
|
||||
this.nonce =
|
||||
document.getElementById( 'woocommerce-process-checkout-nonce' )
|
||||
?.value || buttonConfig.nonce;
|
||||
|
||||
// Stores initialization data sent to the button.
|
||||
this.initialPaymentRequest = null;
|
||||
|
@ -41,7 +42,7 @@ class ApplepayButton {
|
|||
if ( this.buttonConfig.is_debug ) {
|
||||
//console.log('[ApplePayButton]', ...arguments);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.refreshContextData();
|
||||
|
||||
|
@ -66,21 +67,28 @@ class ApplepayButton {
|
|||
this.initEventHandlers();
|
||||
this.isInitialized = true;
|
||||
this.applePayConfig = config;
|
||||
this.isEligible = (this.applePayConfig.isEligible && window.ApplePaySession) || this.buttonConfig.is_admin;
|
||||
this.isEligible =
|
||||
( this.applePayConfig.isEligible && window.ApplePaySession ) ||
|
||||
this.buttonConfig.is_admin;
|
||||
|
||||
if ( this.isEligible ) {
|
||||
this.fetchTransactionInfo().then( () => {
|
||||
this.addButton();
|
||||
const id_minicart = "#apple-" + this.buttonConfig.button.mini_cart_wrapper;
|
||||
const id = "#apple-" + this.buttonConfig.button.wrapper;
|
||||
const id_minicart =
|
||||
'#apple-' + this.buttonConfig.button.mini_cart_wrapper;
|
||||
const id = '#apple-' + this.buttonConfig.button.wrapper;
|
||||
|
||||
if ( this.context === 'mini-cart' ) {
|
||||
document.querySelector(id_minicart)?.addEventListener('click', (evt) => {
|
||||
document
|
||||
.querySelector( id_minicart )
|
||||
?.addEventListener( 'click', ( evt ) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
} );
|
||||
} else {
|
||||
document.querySelector(id)?.addEventListener('click', (evt) => {
|
||||
document
|
||||
.querySelector( id )
|
||||
?.addEventListener( 'click', ( evt ) => {
|
||||
evt.preventDefault();
|
||||
this.onButtonClick();
|
||||
} );
|
||||
|
@ -110,12 +118,12 @@ class ApplepayButton {
|
|||
* Returns configurations relative to this button context.
|
||||
*/
|
||||
contextConfig() {
|
||||
let config = {
|
||||
const config = {
|
||||
wrapper: this.buttonConfig.button.wrapper,
|
||||
ppcpStyle: this.ppcpConfig.button.style,
|
||||
buttonStyle: this.buttonConfig.button.style,
|
||||
ppcpButtonWrapper: this.ppcpConfig.button.wrapper
|
||||
}
|
||||
ppcpButtonWrapper: this.ppcpConfig.button.wrapper,
|
||||
};
|
||||
|
||||
if ( this.context === 'mini-cart' ) {
|
||||
config.wrapper = this.buttonConfig.button.mini_cart_wrapper;
|
||||
|
@ -124,8 +132,11 @@ class ApplepayButton {
|
|||
config.ppcpButtonWrapper = this.ppcpConfig.button.mini_cart_wrapper;
|
||||
}
|
||||
|
||||
if (['cart-block', 'checkout-block'].indexOf(this.context) !== -1) {
|
||||
config.ppcpButtonWrapper = '#express-payment-method-ppcp-gateway-paypal';
|
||||
if (
|
||||
[ 'cart-block', 'checkout-block' ].indexOf( this.context ) !== -1
|
||||
) {
|
||||
config.ppcpButtonWrapper =
|
||||
'#express-payment-method-ppcp-gateway-paypal';
|
||||
}
|
||||
|
||||
return config;
|
||||
|
@ -136,7 +147,9 @@ class ApplepayButton {
|
|||
const wrapper_id = '#' + wrapper;
|
||||
|
||||
if ( wrapper_id === ppcpButtonWrapper ) {
|
||||
throw new Error(`[ApplePayButton] "wrapper" and "ppcpButtonWrapper" values must differ to avoid infinite loop. Current value: "${wrapper_id}"`);
|
||||
throw new Error(
|
||||
`[ApplePayButton] "wrapper" and "ppcpButtonWrapper" values must differ to avoid infinite loop. Current value: "${ wrapper_id }"`
|
||||
);
|
||||
}
|
||||
|
||||
const syncButtonVisibility = () => {
|
||||
|
@ -146,20 +159,27 @@ class ApplepayButton {
|
|||
|
||||
const $ppcpButtonWrapper = jQuery( ppcpButtonWrapper );
|
||||
setVisible( wrapper_id, $ppcpButtonWrapper.is( ':visible' ) );
|
||||
setEnabled(wrapper_id, !$ppcpButtonWrapper.hasClass('ppcp-disabled'));
|
||||
}
|
||||
setEnabled(
|
||||
wrapper_id,
|
||||
! $ppcpButtonWrapper.hasClass( 'ppcp-disabled' )
|
||||
);
|
||||
};
|
||||
|
||||
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 ) => {
|
||||
if ( jQuery( data.selector ).is( ppcpButtonWrapper ) ) {
|
||||
syncButtonVisibility();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
syncButtonVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts an ApplePay session.
|
||||
* @param paymentRequest
|
||||
*/
|
||||
applePaySession( paymentRequest ) {
|
||||
this.log( 'applePaySession', paymentRequest );
|
||||
|
@ -167,8 +187,10 @@ class ApplepayButton {
|
|||
session.begin();
|
||||
|
||||
if ( this.shouldRequireShippingInButton() ) {
|
||||
session.onshippingmethodselected = this.onShippingMethodSelected(session);
|
||||
session.onshippingcontactselected = this.onShippingContactSelected(session);
|
||||
session.onshippingmethodselected =
|
||||
this.onShippingMethodSelected( session );
|
||||
session.onshippingcontactselected =
|
||||
this.onShippingContactSelected( session );
|
||||
}
|
||||
session.onvalidatemerchant = this.onValidateMerchant( session );
|
||||
session.onpaymentauthorized = this.onPaymentAuthorized( session );
|
||||
|
@ -187,7 +209,7 @@ class ApplepayButton {
|
|||
const type = this.buttonConfig.button.type;
|
||||
const language = this.buttonConfig.button.lang;
|
||||
const color = this.buttonConfig.button.color;
|
||||
const id = "apple-" + wrapper;
|
||||
const id = 'apple-' + wrapper;
|
||||
|
||||
if ( appleContainer ) {
|
||||
appleContainer.innerHTML = `<apple-pay-button id="${ id }" buttonstyle="${ color }" type="${ type }" locale="${ language }">`;
|
||||
|
@ -197,8 +219,11 @@ class ApplepayButton {
|
|||
$wrapper.addClass( 'ppcp-button-' + ppcpStyle.shape );
|
||||
|
||||
if ( ppcpStyle.height ) {
|
||||
$wrapper.css('--apple-pay-button-height', `${ppcpStyle.height}px`)
|
||||
$wrapper.css('height', `${ppcpStyle.height}px`)
|
||||
$wrapper.css(
|
||||
'--apple-pay-button-height',
|
||||
`${ ppcpStyle.height }px`
|
||||
);
|
||||
$wrapper.css( 'height', `${ ppcpStyle.height }px` );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -224,7 +249,9 @@ class ApplepayButton {
|
|||
document.querySelector( '.woocommerce-notices-wrapper' )
|
||||
);
|
||||
try {
|
||||
const formData = new FormData(document.querySelector(checkoutFormSelector));
|
||||
const formData = new FormData(
|
||||
document.querySelector( checkoutFormSelector )
|
||||
);
|
||||
this.formData = Object.fromEntries( formData.entries() );
|
||||
|
||||
this.updateRequestDataWithForm( paymentRequest );
|
||||
|
@ -235,17 +262,23 @@ class ApplepayButton {
|
|||
this.log( '=== paymentRequest', paymentRequest );
|
||||
|
||||
const session = this.applePaySession( paymentRequest );
|
||||
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;
|
||||
if ( formValidator ) {
|
||||
try {
|
||||
const errors = await formValidator.validate(document.querySelector(checkoutFormSelector));
|
||||
const errors = await formValidator.validate(
|
||||
document.querySelector( checkoutFormSelector )
|
||||
);
|
||||
if ( errors.length > 0 ) {
|
||||
errorHandler.messages( errors );
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
jQuery( document.body ).trigger( 'checkout_error', [
|
||||
errorHandler.currentHtml(),
|
||||
] );
|
||||
session.abort();
|
||||
return;
|
||||
}
|
||||
|
@ -263,31 +296,37 @@ class ApplepayButton {
|
|||
/**
|
||||
* If the button should show the shipping fields.
|
||||
*
|
||||
* @returns {false|*}
|
||||
* @return {false|*}
|
||||
*/
|
||||
shouldRequireShippingInButton() {
|
||||
return this.contextHandler.shippingAllowed()
|
||||
&& this.buttonConfig.product.needShipping
|
||||
&& (this.context !== 'checkout' || this.shouldUpdateButtonWithFormData());
|
||||
return (
|
||||
this.contextHandler.shippingAllowed() &&
|
||||
this.buttonConfig.product.needShipping &&
|
||||
( this.context !== 'checkout' ||
|
||||
this.shouldUpdateButtonWithFormData() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the button should be updated with the form addresses.
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
shouldUpdateButtonWithFormData() {
|
||||
if ( this.context !== 'checkout' ) {
|
||||
return false;
|
||||
}
|
||||
return this.buttonConfig?.preferences?.checkout_data_mode === 'use_applepay';
|
||||
return (
|
||||
this.buttonConfig?.preferences?.checkout_data_mode ===
|
||||
'use_applepay'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates how payment completion should be handled if with the context handler default actions.
|
||||
* Or with ApplePay module specific completion.
|
||||
*
|
||||
* @returns {boolean}
|
||||
* @return {boolean}
|
||||
*/
|
||||
shouldCompletePaymentWithContextHandler() {
|
||||
// Data already handled, ex: PayNow
|
||||
|
@ -295,7 +334,10 @@ class ApplepayButton {
|
|||
return true;
|
||||
}
|
||||
// Use WC form data mode in Checkout.
|
||||
if (this.context === 'checkout' && !this.shouldUpdateButtonWithFormData()) {
|
||||
if (
|
||||
this.context === 'checkout' &&
|
||||
! this.shouldUpdateButtonWithFormData()
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -303,6 +345,7 @@ class ApplepayButton {
|
|||
|
||||
/**
|
||||
* Updates ApplePay paymentRequest with form data.
|
||||
* @param paymentRequest
|
||||
*/
|
||||
updateRequestDataWithForm( paymentRequest ) {
|
||||
if ( ! this.shouldUpdateButtonWithFormData() ) {
|
||||
|
@ -310,7 +353,9 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
// Add billing address.
|
||||
paymentRequest.billingContact = this.fillBillingContact(this.formData);
|
||||
paymentRequest.billingContact = this.fillBillingContact(
|
||||
this.formData
|
||||
);
|
||||
|
||||
// Add custom data.
|
||||
// "applicationData" is originating a "PayPalApplePayError: An internal server error has occurred" on paypal.Applepay().confirmOrder().
|
||||
|
@ -321,7 +366,9 @@ class ApplepayButton {
|
|||
}
|
||||
|
||||
// Add shipping address.
|
||||
paymentRequest.shippingContact = this.fillShippingContact(this.formData);
|
||||
paymentRequest.shippingContact = this.fillShippingContact(
|
||||
this.formData
|
||||
);
|
||||
|
||||
// Get shipping methods.
|
||||
const rate = this.transactionInfo.chosenShippingMethods[ 0 ];
|
||||
|
@ -331,10 +378,10 @@ class ApplepayButton {
|
|||
for ( const shippingPackage of this.transactionInfo.shippingPackages ) {
|
||||
if ( rate === shippingPackage.id ) {
|
||||
const shippingMethod = {
|
||||
'label' : shippingPackage.label,
|
||||
'detail' : '',
|
||||
'amount' : shippingPackage.cost_str,
|
||||
'identifier' : shippingPackage.id,
|
||||
label: shippingPackage.label,
|
||||
detail: '',
|
||||
amount: shippingPackage.cost_str,
|
||||
identifier: shippingPackage.id,
|
||||
};
|
||||
|
||||
// Remember this shipping method as the selected one.
|
||||
|
@ -349,10 +396,10 @@ class ApplepayButton {
|
|||
for ( const shippingPackage of this.transactionInfo.shippingPackages ) {
|
||||
if ( rate !== shippingPackage.id ) {
|
||||
paymentRequest.shippingMethods.push( {
|
||||
'label' : shippingPackage.label,
|
||||
'detail' : '',
|
||||
'amount' : shippingPackage.cost_str,
|
||||
'identifier' : shippingPackage.id,
|
||||
label: shippingPackage.label,
|
||||
detail: '',
|
||||
amount: shippingPackage.cost_str,
|
||||
identifier: shippingPackage.id,
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
@ -360,19 +407,26 @@ class ApplepayButton {
|
|||
// Store for reuse in case this data is not provided by ApplePay on authorization.
|
||||
this.initialPaymentRequest = paymentRequest;
|
||||
|
||||
this.log('=== paymentRequest.shippingMethods', paymentRequest.shippingMethods);
|
||||
this.log(
|
||||
'=== paymentRequest.shippingMethods',
|
||||
paymentRequest.shippingMethods
|
||||
);
|
||||
}
|
||||
|
||||
paymentRequest() {
|
||||
const applepayConfig = this.applePayConfig
|
||||
const buttonConfig = this.buttonConfig
|
||||
let baseRequest = {
|
||||
const applepayConfig = this.applePayConfig;
|
||||
const buttonConfig = this.buttonConfig;
|
||||
const baseRequest = {
|
||||
countryCode: applepayConfig.countryCode,
|
||||
merchantCapabilities: applepayConfig.merchantCapabilities,
|
||||
supportedNetworks: applepayConfig.supportedNetworks,
|
||||
requiredShippingContactFields: ["postalAddress", "email", "phone"],
|
||||
requiredBillingContactFields: ["postalAddress"], // ApplePay does not implement billing email and phone fields.
|
||||
}
|
||||
requiredShippingContactFields: [
|
||||
'postalAddress',
|
||||
'email',
|
||||
'phone',
|
||||
],
|
||||
requiredBillingContactFields: [ 'postalAddress' ], // ApplePay does not implement billing email and phone fields.
|
||||
};
|
||||
|
||||
if ( ! this.shouldRequireShippingInButton() ) {
|
||||
if ( this.shouldCompletePaymentWithContextHandler() ) {
|
||||
|
@ -380,7 +434,10 @@ class ApplepayButton {
|
|||
baseRequest.requiredShippingContactFields = [];
|
||||
} else {
|
||||
// Minimum data required for order creation.
|
||||
baseRequest.requiredShippingContactFields = ["email", "phone"];
|
||||
baseRequest.requiredShippingContactFields = [
|
||||
'email',
|
||||
'phone',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -388,9 +445,9 @@ class ApplepayButton {
|
|||
paymentRequest.currencyCode = buttonConfig.shop.currencyCode;
|
||||
paymentRequest.total = {
|
||||
label: buttonConfig.shop.totalLabel,
|
||||
type: "final",
|
||||
type: 'final',
|
||||
amount: this.transactionInfo.totalPrice,
|
||||
}
|
||||
};
|
||||
|
||||
return paymentRequest;
|
||||
}
|
||||
|
@ -399,7 +456,8 @@ class ApplepayButton {
|
|||
switch ( this.context ) {
|
||||
case 'product':
|
||||
// Refresh product data that makes the price change.
|
||||
this.productQuantity = document.querySelector('input.qty')?.value;
|
||||
this.productQuantity =
|
||||
document.querySelector( 'input.qty' )?.value;
|
||||
this.products = this.contextHandler.products();
|
||||
this.log( 'Products updated', this.products );
|
||||
break;
|
||||
|
@ -415,12 +473,16 @@ class ApplepayButton {
|
|||
return ( applePayValidateMerchantEvent ) => {
|
||||
this.log( 'onvalidatemerchant call' );
|
||||
|
||||
widgetBuilder.paypal.Applepay().validateMerchant({
|
||||
validationUrl: applePayValidateMerchantEvent.validationURL
|
||||
widgetBuilder.paypal
|
||||
.Applepay()
|
||||
.validateMerchant( {
|
||||
validationUrl: applePayValidateMerchantEvent.validationURL,
|
||||
} )
|
||||
.then(validateResult => {
|
||||
.then( ( validateResult ) => {
|
||||
this.log( 'onvalidatemerchant ok' );
|
||||
session.completeMerchantValidation(validateResult.merchantSession);
|
||||
session.completeMerchantValidation(
|
||||
validateResult.merchantSession
|
||||
);
|
||||
//call backend to update validation to true
|
||||
jQuery.ajax( {
|
||||
url: this.buttonConfig.ajax_url,
|
||||
|
@ -429,10 +491,10 @@ class ApplepayButton {
|
|||
action: 'ppcp_validate',
|
||||
validation: true,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
},
|
||||
} );
|
||||
} )
|
||||
})
|
||||
.catch(validateError => {
|
||||
.catch( ( validateError ) => {
|
||||
this.log( 'onvalidatemerchant error', validateError );
|
||||
console.error( validateError );
|
||||
//call backend to update validation to false
|
||||
|
@ -443,7 +505,7 @@ class ApplepayButton {
|
|||
action: 'ppcp_validate',
|
||||
validation: false,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
},
|
||||
} );
|
||||
this.log( 'onvalidatemerchant session abort' );
|
||||
session.abort();
|
||||
|
@ -462,18 +524,25 @@ class ApplepayButton {
|
|||
jQuery.ajax( {
|
||||
url: ajax_url,
|
||||
method: 'POST',
|
||||
data: data,
|
||||
success: (applePayShippingMethodUpdate, textStatus, jqXHR) => {
|
||||
data,
|
||||
success: (
|
||||
applePayShippingMethodUpdate,
|
||||
textStatus,
|
||||
jqXHR
|
||||
) => {
|
||||
this.log( 'onshippingmethodselected ok' );
|
||||
let response = applePayShippingMethodUpdate.data;
|
||||
const response = applePayShippingMethodUpdate.data;
|
||||
if ( applePayShippingMethodUpdate.success === false ) {
|
||||
response.errors = createAppleErrors( response.errors );
|
||||
}
|
||||
this.selectedShippingMethod = event.shippingMethod;
|
||||
|
||||
// Sort the response shipping methods, so that the selected shipping method is the first one.
|
||||
response.newShippingMethods = response.newShippingMethods.sort((a, b) => {
|
||||
if (a.label === this.selectedShippingMethod.label) {
|
||||
response.newShippingMethods =
|
||||
response.newShippingMethods.sort( ( a, b ) => {
|
||||
if (
|
||||
a.label === this.selectedShippingMethod.label
|
||||
) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
|
@ -506,16 +575,21 @@ class ApplepayButton {
|
|||
jQuery.ajax( {
|
||||
url: ajax_url,
|
||||
method: 'POST',
|
||||
data: data,
|
||||
success: (applePayShippingContactUpdate, textStatus, jqXHR) => {
|
||||
data,
|
||||
success: (
|
||||
applePayShippingContactUpdate,
|
||||
textStatus,
|
||||
jqXHR
|
||||
) => {
|
||||
this.log( 'onshippingcontactselected ok' );
|
||||
let response = applePayShippingContactUpdate.data;
|
||||
const response = applePayShippingContactUpdate.data;
|
||||
this.updatedContactInfo = event.shippingContact;
|
||||
if ( applePayShippingContactUpdate.success === false ) {
|
||||
response.errors = createAppleErrors( response.errors );
|
||||
}
|
||||
if ( response.newShippingMethods ) {
|
||||
this.selectedShippingMethod = response.newShippingMethods[0];
|
||||
this.selectedShippingMethod =
|
||||
response.newShippingMethods[ 0 ];
|
||||
}
|
||||
session.completeShippingContactSelection( response );
|
||||
},
|
||||
|
@ -537,7 +611,7 @@ class ApplepayButton {
|
|||
case 'product':
|
||||
return {
|
||||
action: 'ppcp_update_shipping_contact',
|
||||
product_id: product_id,
|
||||
product_id,
|
||||
products: JSON.stringify( this.products ),
|
||||
caller_page: 'productDetail',
|
||||
product_quantity: this.productQuantity,
|
||||
|
@ -566,16 +640,20 @@ class ApplepayButton {
|
|||
this.refreshContextData();
|
||||
|
||||
switch ( this.context ) {
|
||||
case 'product': return {
|
||||
case 'product':
|
||||
return {
|
||||
action: 'ppcp_update_shipping_method',
|
||||
shipping_method: event.shippingMethod,
|
||||
simplified_contact: this.updatedContactInfo || this.initialPaymentRequest.shippingContact || this.initialPaymentRequest.billingContact,
|
||||
product_id: product_id,
|
||||
simplified_contact:
|
||||
this.updatedContactInfo ||
|
||||
this.initialPaymentRequest.shippingContact ||
|
||||
this.initialPaymentRequest.billingContact,
|
||||
product_id,
|
||||
products: JSON.stringify( this.products ),
|
||||
caller_page: 'productDetail',
|
||||
product_quantity: this.productQuantity,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
};
|
||||
case 'cart':
|
||||
case 'checkout':
|
||||
case 'cart-block':
|
||||
|
@ -584,10 +662,13 @@ class ApplepayButton {
|
|||
return {
|
||||
action: 'ppcp_update_shipping_method',
|
||||
shipping_method: event.shippingMethod,
|
||||
simplified_contact: this.updatedContactInfo || this.initialPaymentRequest.shippingContact || this.initialPaymentRequest.billingContact,
|
||||
simplified_contact:
|
||||
this.updatedContactInfo ||
|
||||
this.initialPaymentRequest.shippingContact ||
|
||||
this.initialPaymentRequest.billingContact,
|
||||
caller_page: 'cart',
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -602,27 +683,38 @@ class ApplepayButton {
|
|||
const processInWooAndCapture = async ( data ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
try {
|
||||
const billingContact = data.billing_contact || this.initialPaymentRequest.billingContact;
|
||||
const shippingContact = data.shipping_contact || this.initialPaymentRequest.shippingContact;
|
||||
const shippingMethod = this.selectedShippingMethod || (this.initialPaymentRequest.shippingMethods || [])[0];
|
||||
const billingContact =
|
||||
data.billing_contact ||
|
||||
this.initialPaymentRequest.billingContact;
|
||||
const shippingContact =
|
||||
data.shipping_contact ||
|
||||
this.initialPaymentRequest.shippingContact;
|
||||
const shippingMethod =
|
||||
this.selectedShippingMethod ||
|
||||
( this.initialPaymentRequest.shippingMethods ||
|
||||
[] )[ 0 ];
|
||||
|
||||
let request_data = {
|
||||
const request_data = {
|
||||
action: 'ppcp_create_order',
|
||||
'caller_page': this.context,
|
||||
'product_id': this.buttonConfig.product.id ?? null,
|
||||
'products': JSON.stringify(this.products),
|
||||
'product_quantity': this.productQuantity ?? null,
|
||||
'shipping_contact': shippingContact,
|
||||
'billing_contact': billingContact,
|
||||
'token': event.payment.token,
|
||||
'shipping_method': shippingMethod,
|
||||
caller_page: this.context,
|
||||
product_id: this.buttonConfig.product.id ?? null,
|
||||
products: JSON.stringify( this.products ),
|
||||
product_quantity: this.productQuantity ?? null,
|
||||
shipping_contact: shippingContact,
|
||||
billing_contact: billingContact,
|
||||
token: event.payment.token,
|
||||
shipping_method: shippingMethod,
|
||||
'woocommerce-process-checkout-nonce': this.nonce,
|
||||
'funding_source': 'applepay',
|
||||
'_wp_http_referer': '/?wc-ajax=update_order_review',
|
||||
'paypal_order_id': data.paypal_order_id,
|
||||
funding_source: 'applepay',
|
||||
_wp_http_referer: '/?wc-ajax=update_order_review',
|
||||
paypal_order_id: data.paypal_order_id,
|
||||
};
|
||||
|
||||
this.log('onpaymentauthorized request', this.buttonConfig.ajax_url, data);
|
||||
this.log(
|
||||
'onpaymentauthorized request',
|
||||
this.buttonConfig.ajax_url,
|
||||
data
|
||||
);
|
||||
|
||||
jQuery.ajax( {
|
||||
url: this.buttonConfig.ajax_url,
|
||||
|
@ -631,12 +723,19 @@ class ApplepayButton {
|
|||
complete: ( jqXHR, textStatus ) => {
|
||||
this.log( 'onpaymentauthorized complete' );
|
||||
},
|
||||
success: (authorizationResult, textStatus, jqXHR) => {
|
||||
success: (
|
||||
authorizationResult,
|
||||
textStatus,
|
||||
jqXHR
|
||||
) => {
|
||||
this.log( 'onpaymentauthorized ok' );
|
||||
resolve( authorizationResult );
|
||||
},
|
||||
error: ( jqXHR, textStatus, errorThrown ) => {
|
||||
this.log('onpaymentauthorized error', textStatus);
|
||||
this.log(
|
||||
'onpaymentauthorized error',
|
||||
textStatus
|
||||
);
|
||||
reject( new Error( errorThrown ) );
|
||||
},
|
||||
} );
|
||||
|
@ -645,86 +744,135 @@ class ApplepayButton {
|
|||
console.log( error ); // handle error
|
||||
}
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
let id = await this.contextHandler.createOrder();
|
||||
const id = await this.contextHandler.createOrder();
|
||||
|
||||
this.log('onpaymentauthorized paypal order ID', id, event.payment.token, event.payment.billingContact);
|
||||
this.log(
|
||||
'onpaymentauthorized paypal order ID',
|
||||
id,
|
||||
event.payment.token,
|
||||
event.payment.billingContact
|
||||
);
|
||||
|
||||
try {
|
||||
const confirmOrderResponse = await widgetBuilder.paypal.Applepay().confirmOrder({
|
||||
const confirmOrderResponse = await widgetBuilder.paypal
|
||||
.Applepay()
|
||||
.confirmOrder( {
|
||||
orderId: id,
|
||||
token: event.payment.token,
|
||||
billingContact: event.payment.billingContact,
|
||||
} );
|
||||
|
||||
this.log('onpaymentauthorized confirmOrderResponse', confirmOrderResponse);
|
||||
this.log(
|
||||
'onpaymentauthorized confirmOrderResponse',
|
||||
confirmOrderResponse
|
||||
);
|
||||
|
||||
if (confirmOrderResponse && confirmOrderResponse.approveApplePayPayment) {
|
||||
if (confirmOrderResponse.approveApplePayPayment.status === "APPROVED") {
|
||||
if (
|
||||
confirmOrderResponse &&
|
||||
confirmOrderResponse.approveApplePayPayment
|
||||
) {
|
||||
if (
|
||||
confirmOrderResponse.approveApplePayPayment.status ===
|
||||
'APPROVED'
|
||||
) {
|
||||
try {
|
||||
|
||||
if (this.shouldCompletePaymentWithContextHandler()) {
|
||||
if (
|
||||
this.shouldCompletePaymentWithContextHandler()
|
||||
) {
|
||||
// No shipping, expect immediate capture, ex: PayNow, Checkout with form data.
|
||||
|
||||
let approveFailed = false;
|
||||
await this.contextHandler.approveOrder({
|
||||
orderID: id
|
||||
}, { // actions mock object.
|
||||
restart: () => new Promise((resolve, reject) => {
|
||||
await this.contextHandler.approveOrder(
|
||||
{
|
||||
orderID: id,
|
||||
},
|
||||
{
|
||||
// actions mock object.
|
||||
restart: () =>
|
||||
new Promise(
|
||||
( resolve, reject ) => {
|
||||
approveFailed = true;
|
||||
resolve();
|
||||
}),
|
||||
order: {
|
||||
get: () => new Promise((resolve, reject) => {
|
||||
resolve(null);
|
||||
})
|
||||
}
|
||||
});
|
||||
),
|
||||
order: {
|
||||
get: () =>
|
||||
new Promise(
|
||||
( resolve, reject ) => {
|
||||
resolve( null );
|
||||
}
|
||||
),
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if ( ! approveFailed ) {
|
||||
this.log('onpaymentauthorized approveOrder OK');
|
||||
session.completePayment(ApplePaySession.STATUS_SUCCESS);
|
||||
this.log(
|
||||
'onpaymentauthorized approveOrder OK'
|
||||
);
|
||||
session.completePayment(
|
||||
ApplePaySession.STATUS_SUCCESS
|
||||
);
|
||||
} else {
|
||||
this.log('onpaymentauthorized approveOrder FAIL');
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
this.log(
|
||||
'onpaymentauthorized approveOrder FAIL'
|
||||
);
|
||||
session.completePayment(
|
||||
ApplePaySession.STATUS_FAILURE
|
||||
);
|
||||
session.abort();
|
||||
console.error( error );
|
||||
}
|
||||
|
||||
} else {
|
||||
// Default payment.
|
||||
|
||||
let data = {
|
||||
billing_contact: event.payment.billingContact,
|
||||
shipping_contact: event.payment.shippingContact,
|
||||
const data = {
|
||||
billing_contact:
|
||||
event.payment.billingContact,
|
||||
shipping_contact:
|
||||
event.payment.shippingContact,
|
||||
paypal_order_id: id,
|
||||
};
|
||||
let authorizationResult = await processInWooAndCapture(data);
|
||||
if (authorizationResult.result === "success") {
|
||||
session.completePayment(ApplePaySession.STATUS_SUCCESS);
|
||||
window.location.href = authorizationResult.redirect;
|
||||
const authorizationResult =
|
||||
await processInWooAndCapture( data );
|
||||
if (
|
||||
authorizationResult.result === 'success'
|
||||
) {
|
||||
session.completePayment(
|
||||
ApplePaySession.STATUS_SUCCESS
|
||||
);
|
||||
window.location.href =
|
||||
authorizationResult.redirect;
|
||||
} else {
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
session.completePayment(
|
||||
ApplePaySession.STATUS_FAILURE
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch ( error ) {
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
session.completePayment(
|
||||
ApplePaySession.STATUS_FAILURE
|
||||
);
|
||||
session.abort();
|
||||
console.error( error );
|
||||
}
|
||||
} else {
|
||||
console.error( 'Error status is not APPROVED' );
|
||||
session.completePayment(ApplePaySession.STATUS_FAILURE);
|
||||
session.completePayment(
|
||||
ApplePaySession.STATUS_FAILURE
|
||||
);
|
||||
}
|
||||
} else {
|
||||
console.error( 'Invalid confirmOrderResponse' );
|
||||
session.completePayment( ApplePaySession.STATUS_FAILURE );
|
||||
}
|
||||
} catch ( error ) {
|
||||
console.error('Error confirming order with applepay token', error);
|
||||
console.error(
|
||||
'Error confirming order with applepay token',
|
||||
error
|
||||
);
|
||||
session.completePayment( ApplePaySession.STATUS_FAILURE );
|
||||
session.abort();
|
||||
}
|
||||
|
@ -742,31 +890,61 @@ class ApplepayButton {
|
|||
postalCode: data.billing_postcode ?? '',
|
||||
countryCode: data.billing_country ?? '',
|
||||
administrativeArea: data.billing_state ?? '',
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fillShippingContact( data ) {
|
||||
if (data.shipping_first_name === "") {
|
||||
if ( data.shipping_first_name === '' ) {
|
||||
return this.fillBillingContact( data );
|
||||
}
|
||||
return {
|
||||
givenName: (data?.shipping_first_name && data.shipping_first_name !== "") ? data.shipping_first_name : data?.billing_first_name,
|
||||
familyName: (data?.shipping_last_name && data.shipping_last_name !== "") ? data.shipping_last_name : data?.billing_last_name,
|
||||
emailAddress: (data?.shipping_email && data.shipping_email !== "") ? data.shipping_email : data?.billing_email,
|
||||
phoneNumber: (data?.shipping_phone && data.shipping_phone !== "") ? data.shipping_phone : data?.billing_phone,
|
||||
addressLines: [data.shipping_address_1 ?? '', data.shipping_address_2 ?? ''],
|
||||
locality: (data?.shipping_city && data.shipping_city !== "") ? data.shipping_city : data?.billing_city,
|
||||
postalCode: (data?.shipping_postcode && data.shipping_postcode !== "") ? data.shipping_postcode : data?.billing_postcode,
|
||||
countryCode: (data?.shipping_country && data.shipping_country !== "") ? data.shipping_country : data?.billing_country,
|
||||
administrativeArea: (data?.shipping_state && data.shipping_state !== "") ? data.shipping_state : data?.billing_state,
|
||||
}
|
||||
givenName:
|
||||
data?.shipping_first_name && data.shipping_first_name !== ''
|
||||
? data.shipping_first_name
|
||||
: data?.billing_first_name,
|
||||
familyName:
|
||||
data?.shipping_last_name && data.shipping_last_name !== ''
|
||||
? data.shipping_last_name
|
||||
: data?.billing_last_name,
|
||||
emailAddress:
|
||||
data?.shipping_email && data.shipping_email !== ''
|
||||
? data.shipping_email
|
||||
: data?.billing_email,
|
||||
phoneNumber:
|
||||
data?.shipping_phone && data.shipping_phone !== ''
|
||||
? data.shipping_phone
|
||||
: data?.billing_phone,
|
||||
addressLines: [
|
||||
data.shipping_address_1 ?? '',
|
||||
data.shipping_address_2 ?? '',
|
||||
],
|
||||
locality:
|
||||
data?.shipping_city && data.shipping_city !== ''
|
||||
? data.shipping_city
|
||||
: data?.billing_city,
|
||||
postalCode:
|
||||
data?.shipping_postcode && data.shipping_postcode !== ''
|
||||
? data.shipping_postcode
|
||||
: data?.billing_postcode,
|
||||
countryCode:
|
||||
data?.shipping_country && data.shipping_country !== ''
|
||||
? data.shipping_country
|
||||
: data?.billing_country,
|
||||
administrativeArea:
|
||||
data?.shipping_state && data.shipping_state !== ''
|
||||
? data.shipping_state
|
||||
: data?.billing_state,
|
||||
};
|
||||
}
|
||||
|
||||
fillApplicationData( data ) {
|
||||
const jsonString = JSON.stringify( data );
|
||||
let utf8Str = encodeURIComponent(jsonString).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
||||
const utf8Str = encodeURIComponent( jsonString ).replace(
|
||||
/%([0-9A-F]{2})/g,
|
||||
( match, p1 ) => {
|
||||
return String.fromCharCode( '0x' + p1 );
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
return btoa( utf8Str );
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
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 ) {
|
||||
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
this.ApplePayConfig = null;
|
||||
|
@ -15,7 +13,7 @@ class ApplepayManager {
|
|||
bootstrap.context,
|
||||
bootstrap.handler,
|
||||
buttonConfig,
|
||||
ppcpConfig,
|
||||
ppcpConfig
|
||||
);
|
||||
|
||||
this.buttons.push( button );
|
||||
|
@ -43,13 +41,12 @@ class ApplepayManager {
|
|||
|
||||
/**
|
||||
* 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,7 +1,6 @@
|
|||
import ApplepayButton from "./ApplepayButton";
|
||||
import ApplepayButton from './ApplepayButton';
|
||||
|
||||
class ApplepayManagerBlockEditor {
|
||||
|
||||
constructor( buttonConfig, ppcpConfig ) {
|
||||
this.buttonConfig = buttonConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
|
@ -22,11 +21,10 @@ 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 );
|
||||
}
|
||||
|
|
|
@ -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 ) {
|
||||
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() {
|
||||
|
@ -30,17 +30,14 @@ class BaseHandler {
|
|||
transactionInfo() {
|
||||
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 => {
|
||||
credentials: 'same-origin',
|
||||
} )
|
||||
.then( ( result ) => result.json() )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
return;
|
||||
}
|
||||
|
@ -53,10 +50,10 @@ class BaseHandler {
|
|||
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,
|
||||
} );
|
||||
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
@ -70,10 +67,7 @@ class BaseHandler {
|
|||
}
|
||||
|
||||
actionHandler() {
|
||||
return new CartActionHandler(
|
||||
this.ppcpConfig,
|
||||
this.errorHandler(),
|
||||
);
|
||||
return new CartActionHandler( this.ppcpConfig, this.errorHandler() );
|
||||
}
|
||||
|
||||
errorHandler() {
|
||||
|
@ -89,7 +83,6 @@ class BaseHandler {
|
|||
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,14 +1,13 @@
|
|||
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 ) {
|
||||
case 'product':
|
||||
|
|
|
@ -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();
|
||||
|
@ -14,13 +12,13 @@ class PayNowHandler extends BaseHandler {
|
|||
|
||||
transactionInfo() {
|
||||
return new Promise( async ( resolve, reject ) => {
|
||||
const data = this.ppcpConfig['pay_now'];
|
||||
const data = this.ppcpConfig.pay_now;
|
||||
|
||||
resolve( {
|
||||
countryCode: data.country_code,
|
||||
currencyCode: data.currency_code,
|
||||
totalPriceStatus: 'FINAL',
|
||||
totalPrice: data.total_str
|
||||
totalPrice: data.total_str,
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
@ -32,7 +30,6 @@ class PayNowHandler extends BaseHandler {
|
|||
new Spinner()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PayNowHandler;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import BaseHandler from "./BaseHandler";
|
||||
import BaseHandler from './BaseHandler';
|
||||
|
||||
class PreviewHandler extends BaseHandler {
|
||||
|
||||
constructor( buttonConfig, ppcpConfig, externalHandler ) {
|
||||
super( buttonConfig, ppcpConfig, externalHandler );
|
||||
}
|
||||
|
@ -9,11 +8,11 @@ class PreviewHandler extends BaseHandler {
|
|||
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() {
|
||||
|
@ -31,7 +30,6 @@ class PreviewHandler extends BaseHandler {
|
|||
errorHandler() {
|
||||
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();
|
||||
|
@ -28,38 +26,39 @@ class SingleProductHandler extends BaseHandler {
|
|||
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(
|
||||
new SimulateCart(
|
||||
this.ppcpConfig.ajax.simulate_cart.endpoint,
|
||||
this.ppcpConfig.ajax.simulate_cart.nonce,
|
||||
)).simulate((data) => {
|
||||
|
||||
this.ppcpConfig.ajax.simulate_cart.nonce
|
||||
).simulate( ( data ) => {
|
||||
resolve( {
|
||||
countryCode: data.country_code,
|
||||
currencyCode: data.currency_code,
|
||||
totalPriceStatus: 'FINAL',
|
||||
totalPrice: data.total_str
|
||||
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,
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
this.errorHandler()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
export function createAppleErrors( errors ) {
|
||||
const errorList = []
|
||||
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)
|
||||
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',
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,13 +7,13 @@ import PreviewButtonManager from '../../../ppcp-button/resources/js/modules/Rend
|
|||
*/
|
||||
const buttonManager = () => {
|
||||
if ( ! ApplePayPreviewButtonManager.instance ) {
|
||||
ApplePayPreviewButtonManager.instance = new ApplePayPreviewButtonManager();
|
||||
ApplePayPreviewButtonManager.instance =
|
||||
new ApplePayPreviewButtonManager();
|
||||
}
|
||||
|
||||
return ApplePayPreviewButtonManager.instance;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Manages all Apple Pay preview buttons on this page.
|
||||
*/
|
||||
|
@ -38,7 +38,9 @@ class ApplePayPreviewButtonManager extends PreviewButtonManager {
|
|||
const apiMethod = payPal?.Applepay()?.config;
|
||||
|
||||
if ( ! apiMethod ) {
|
||||
this.error('configuration object cannot be retrieved from PayPal');
|
||||
this.error(
|
||||
'configuration object cannot be retrieved from PayPal'
|
||||
);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -59,7 +61,6 @@ class ApplePayPreviewButtonManager extends PreviewButtonManager {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A single Apple Pay preview button instance.
|
||||
*/
|
||||
|
@ -85,7 +86,12 @@ class ApplePayPreviewButton extends PreviewButton {
|
|||
}
|
||||
|
||||
createButton( buttonConfig ) {
|
||||
const button = new ApplepayButton('preview', null, buttonConfig, this.ppcpConfig);
|
||||
const button = new ApplepayButton(
|
||||
'preview',
|
||||
null,
|
||||
buttonConfig,
|
||||
this.ppcpConfig
|
||||
);
|
||||
|
||||
button.init( this.apiConfig );
|
||||
}
|
||||
|
@ -93,17 +99,23 @@ class ApplePayPreviewButton extends PreviewButton {
|
|||
/**
|
||||
* Merge form details into the config object for preview.
|
||||
* Mutates the previewConfig object; no return value.
|
||||
* @param buttonConfig
|
||||
* @param 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 ) {
|
||||
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,11 +1,11 @@
|
|||
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 { 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 ppcpConfig = ppcpData.scriptData;
|
||||
|
@ -23,7 +23,9 @@ const ApplePayComponent = ( props ) => {
|
|||
const [ applePayLoaded, setApplePayLoaded ] = useState( false );
|
||||
|
||||
const bootstrap = function () {
|
||||
const ManagerClass = props.isEditing ? ApplepayManagerBlockEditor : ApplepayManager;
|
||||
const ManagerClass = props.isEditing
|
||||
? ApplepayManagerBlockEditor
|
||||
: ApplepayManager;
|
||||
const manager = new ManagerClass( buttonConfig, ppcpConfig );
|
||||
manager.init();
|
||||
};
|
||||
|
@ -52,16 +54,16 @@ const ApplePayComponent = ( props ) => {
|
|||
return (
|
||||
<div
|
||||
id={ buttonConfig.button.wrapper.replace( '#', '' ) }
|
||||
className="ppcp-button-apm ppcp-button-applepay">
|
||||
</div>
|
||||
className="ppcp-button-apm ppcp-button-applepay"
|
||||
></div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const features = [ 'products' ];
|
||||
|
||||
if (
|
||||
cartHasSubscriptionProducts(ppcpConfig)
|
||||
&& (new CheckoutHandler(buttonConfig, ppcpConfig)).isVaultV3Mode()
|
||||
cartHasSubscriptionProducts( ppcpConfig ) &&
|
||||
new CheckoutHandler( buttonConfig, ppcpConfig ).isVaultV3Mode()
|
||||
) {
|
||||
features.push( 'subscriptions' );
|
||||
}
|
||||
|
@ -74,6 +76,6 @@ registerExpressPaymentMethod({
|
|||
ariaLabel: buttonData.title,
|
||||
canMakePayment: () => buttonData.enabled,
|
||||
supports: {
|
||||
features: features,
|
||||
features,
|
||||
},
|
||||
} );
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
import {loadCustomScript} from "@paypal/paypal-js";
|
||||
import {loadPaypalScript} from "../../../ppcp-button/resources/js/modules/Helper/ScriptLoading";
|
||||
import ApplepayManager from "./ApplepayManager";
|
||||
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
|
||||
}) {
|
||||
|
||||
( function ( { buttonConfig, ppcpConfig, jQuery } ) {
|
||||
let manager;
|
||||
|
||||
const bootstrap = function () {
|
||||
|
@ -22,12 +17,10 @@ import {setupButtonEvents} from '../../../ppcp-button/resources/js/modules/Helpe
|
|||
}
|
||||
} );
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
if (
|
||||
(typeof (buttonConfig) === 'undefined') ||
|
||||
(typeof (ppcpConfig) === 'undefined')
|
||||
typeof buttonConfig === 'undefined' ||
|
||||
typeof ppcpConfig === 'undefined'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
@ -48,7 +41,7 @@ import {setupButtonEvents} from '../../../ppcp-button/resources/js/modules/Helpe
|
|||
bootstrapped = true;
|
||||
bootstrap();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Load ApplePay SDK
|
||||
loadCustomScript( { url: buttonConfig.sdk_url } ).then( () => {
|
||||
|
@ -61,11 +54,9 @@ import {setupButtonEvents} from '../../../ppcp-button/resources/js/modules/Helpe
|
|||
paypalLoaded = true;
|
||||
tryToBoot();
|
||||
} );
|
||||
},
|
||||
);
|
||||
|
||||
} );
|
||||
} )( {
|
||||
buttonConfig: window.wc_ppcp_applepay,
|
||||
ppcpConfig: window.PayPalCommerceGateway,
|
||||
jQuery: window.jQuery
|
||||
jQuery: window.jQuery,
|
||||
} );
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
import Fastlane from "./Connection/Fastlane";
|
||||
import {log} from "./Helper/Debug";
|
||||
import DomElementCollection from "./Components/DomElementCollection";
|
||||
import ShippingView from "./Views/ShippingView";
|
||||
import BillingView from "./Views/BillingView";
|
||||
import CardView from "./Views/CardView";
|
||||
import PayPalInsights from "./Insights/PayPalInsights";
|
||||
import {disable,enable} from "../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler";
|
||||
import {getCurrentPaymentMethod} from "../../../ppcp-button/resources/js/modules/Helper/CheckoutMethodState";
|
||||
import Fastlane from './Connection/Fastlane';
|
||||
import { log } from './Helper/Debug';
|
||||
import DomElementCollection from './Components/DomElementCollection';
|
||||
import ShippingView from './Views/ShippingView';
|
||||
import BillingView from './Views/BillingView';
|
||||
import CardView from './Views/CardView';
|
||||
import PayPalInsights from './Insights/PayPalInsights';
|
||||
import {
|
||||
disable,
|
||||
enable,
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/ButtonDisabler';
|
||||
import { getCurrentPaymentMethod } from '../../../ppcp-button/resources/js/modules/Helper/CheckoutMethodState';
|
||||
|
||||
class AxoManager {
|
||||
|
||||
constructor( axoConfig, ppcpConfig ) {
|
||||
this.axoConfig = axoConfig;
|
||||
this.ppcpConfig = ppcpConfig;
|
||||
|
@ -39,36 +41,51 @@ class AxoManager {
|
|||
|
||||
this.el = new DomElementCollection();
|
||||
|
||||
this.emailInput = document.querySelector(this.el.fieldBillingEmail.selector + ' input');
|
||||
this.emailInput = document.querySelector(
|
||||
this.el.fieldBillingEmail.selector + ' input'
|
||||
);
|
||||
|
||||
this.styles = {
|
||||
root: {
|
||||
backgroundColorPrimary: '#ffffff'
|
||||
}
|
||||
backgroundColorPrimary: '#ffffff',
|
||||
},
|
||||
};
|
||||
|
||||
this.locale = 'en_us';
|
||||
|
||||
this.registerEventHandlers();
|
||||
|
||||
this.shippingView = new ShippingView(this.el.shippingAddressContainer.selector, this.el, this.states );
|
||||
this.billingView = new BillingView(this.el.billingAddressContainer.selector, this.el);
|
||||
this.cardView = new CardView(this.el.paymentContainer.selector + '-details', this.el, this);
|
||||
this.shippingView = new ShippingView(
|
||||
this.el.shippingAddressContainer.selector,
|
||||
this.el,
|
||||
this.states
|
||||
);
|
||||
this.billingView = new BillingView(
|
||||
this.el.billingAddressContainer.selector,
|
||||
this.el
|
||||
);
|
||||
this.cardView = new CardView(
|
||||
this.el.paymentContainer.selector + '-details',
|
||||
this.el,
|
||||
this
|
||||
);
|
||||
|
||||
document.axoDebugSetStatus = ( key, value ) => {
|
||||
this.setStatus( key, value );
|
||||
}
|
||||
};
|
||||
|
||||
document.axoDebugObject = () => {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
if (
|
||||
this.axoConfig?.insights?.enabled
|
||||
&& this.axoConfig?.insights?.client_id
|
||||
&& this.axoConfig?.insights?.session_id
|
||||
this.axoConfig?.insights?.enabled &&
|
||||
this.axoConfig?.insights?.client_id &&
|
||||
this.axoConfig?.insights?.session_id
|
||||
) {
|
||||
PayPalInsights.config(this.axoConfig?.insights?.client_id, { debug: true });
|
||||
PayPalInsights.config( this.axoConfig?.insights?.client_id, {
|
||||
debug: true,
|
||||
} );
|
||||
PayPalInsights.setSessionId( this.axoConfig?.insights?.session_id );
|
||||
PayPalInsights.trackJsLoad();
|
||||
|
||||
|
@ -79,7 +96,7 @@ class AxoManager {
|
|||
user_data: {
|
||||
country: 'US',
|
||||
is_store_member: false,
|
||||
}
|
||||
},
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
@ -88,19 +105,21 @@ class AxoManager {
|
|||
}
|
||||
|
||||
registerEventHandlers() {
|
||||
|
||||
this.$(document).on('change', 'input[name=payment_method]', (ev) => {
|
||||
this.$( document ).on(
|
||||
'change',
|
||||
'input[name=payment_method]',
|
||||
( ev ) => {
|
||||
const map = {
|
||||
'ppcp-axo-gateway': 'card',
|
||||
'ppcp-gateway': 'paypal',
|
||||
}
|
||||
};
|
||||
|
||||
PayPalInsights.trackSelectPaymentMethod( {
|
||||
payment_method_selected: map[ ev.target.value ] || 'other',
|
||||
page_type: 'checkout'
|
||||
page_type: 'checkout',
|
||||
} );
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
// Listen to Gateway Radio button changes.
|
||||
this.el.gatewayRadioButton.on( 'change', ( ev ) => {
|
||||
|
@ -111,20 +130,24 @@ class AxoManager {
|
|||
}
|
||||
} );
|
||||
|
||||
this.$(document).on('updated_checkout payment_method_selected', () => {
|
||||
this.$( document ).on(
|
||||
'updated_checkout payment_method_selected',
|
||||
() => {
|
||||
this.triggerGatewayChange();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// On checkout form submitted.
|
||||
this.el.submitButton.on( 'click', () => {
|
||||
this.onClickSubmitButton();
|
||||
return false;
|
||||
})
|
||||
} );
|
||||
|
||||
// Click change shipping address link.
|
||||
this.el.changeShippingAddressLink.on( 'click', async () => {
|
||||
if ( this.status.hasProfile ) {
|
||||
const { selectionChanged, selectedAddress } = await this.fastlane.profile.showShippingAddressSelector();
|
||||
const { selectionChanged, selectedAddress } =
|
||||
await this.fastlane.profile.showShippingAddressSelector();
|
||||
|
||||
if ( selectionChanged ) {
|
||||
this.setShipping( selectedAddress );
|
||||
|
@ -147,7 +170,8 @@ class AxoManager {
|
|||
if ( response.selectionChanged ) {
|
||||
this.setCard( response.selectedCard );
|
||||
this.setBilling( {
|
||||
address: response.selectedCard.paymentSource.card.billingAddress
|
||||
address:
|
||||
response.selectedCard.paymentSource.card.billingAddress,
|
||||
} );
|
||||
}
|
||||
} );
|
||||
|
@ -162,23 +186,38 @@ class AxoManager {
|
|||
|
||||
// Prevents sending checkout form when pressing Enter key on input field
|
||||
// and triggers customer lookup
|
||||
this.$('form.woocommerce-checkout input').on('keydown', async (ev) => {
|
||||
if(ev.key === 'Enter' && getCurrentPaymentMethod() === 'ppcp-axo-gateway' ) {
|
||||
this.$( 'form.woocommerce-checkout input' ).on(
|
||||
'keydown',
|
||||
async ( ev ) => {
|
||||
if (
|
||||
ev.key === 'Enter' &&
|
||||
getCurrentPaymentMethod() === 'ppcp-axo-gateway'
|
||||
) {
|
||||
ev.preventDefault();
|
||||
log(`Enter key attempt - emailInput: ${this.emailInput.value}`);
|
||||
log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`);
|
||||
log(
|
||||
`Enter key attempt - emailInput: ${ this.emailInput.value }`
|
||||
);
|
||||
log(
|
||||
`this.lastEmailCheckedIdentity: ${ this.lastEmailCheckedIdentity }`
|
||||
);
|
||||
this.validateEmail( this.el.fieldBillingEmail.selector );
|
||||
if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) {
|
||||
if (
|
||||
this.emailInput &&
|
||||
this.lastEmailCheckedIdentity !== this.emailInput.value
|
||||
) {
|
||||
await this.onChangeEmail();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
this.reEnableEmailInput();
|
||||
|
||||
// Clear last email checked identity when email field is focused.
|
||||
this.$( '#billing_email_field input' ).on( 'focus', ( ev ) => {
|
||||
log(`Clear the last email checked: ${this.lastEmailCheckedIdentity}`);
|
||||
log(
|
||||
`Clear the last email checked: ${ this.lastEmailCheckedIdentity }`
|
||||
);
|
||||
this.lastEmailCheckedIdentity = '';
|
||||
} );
|
||||
|
||||
|
@ -187,9 +226,14 @@ class AxoManager {
|
|||
const termsField = document.querySelector( "[name='terms-field']" );
|
||||
if ( termsField ) {
|
||||
const status = ev.detail;
|
||||
const shouldHide = status.active && status.validEmail === false && status.hasProfile === false;
|
||||
const shouldHide =
|
||||
status.active &&
|
||||
status.validEmail === false &&
|
||||
status.hasProfile === false;
|
||||
|
||||
termsField.parentElement.style.display = shouldHide ? 'none' : 'block';
|
||||
termsField.parentElement.style.display = shouldHide
|
||||
? 'none'
|
||||
: 'block';
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
@ -236,7 +280,11 @@ class AxoManager {
|
|||
|
||||
if ( scenario.defaultFormFields ) {
|
||||
this.el.customerDetails.show();
|
||||
this.toggleLoaderAndOverlay(this.el.customerDetails, 'loader', 'ppcp-axo-overlay');
|
||||
this.toggleLoaderAndOverlay(
|
||||
this.el.customerDetails,
|
||||
'loader',
|
||||
'ppcp-axo-overlay'
|
||||
);
|
||||
} else {
|
||||
this.el.customerDetails.hide();
|
||||
}
|
||||
|
@ -251,8 +299,14 @@ class AxoManager {
|
|||
this.el.watermarkContainer.show();
|
||||
|
||||
// Move watermark to after email.
|
||||
document.querySelector('#billing_email_field .woocommerce-input-wrapper').append(
|
||||
document.querySelector(this.el.watermarkContainer.selector)
|
||||
document
|
||||
.querySelector(
|
||||
'#billing_email_field .woocommerce-input-wrapper'
|
||||
)
|
||||
.append(
|
||||
document.querySelector(
|
||||
this.el.watermarkContainer.selector
|
||||
)
|
||||
);
|
||||
} else {
|
||||
this.el.emailWidgetContainer.hide();
|
||||
|
@ -262,7 +316,6 @@ class AxoManager {
|
|||
}
|
||||
|
||||
if ( scenario.axoProfileViews ) {
|
||||
|
||||
this.shippingView.activate();
|
||||
this.cardView.activate();
|
||||
|
||||
|
@ -283,13 +336,17 @@ class AxoManager {
|
|||
this.shippingView.deactivate();
|
||||
this.billingView.deactivate();
|
||||
this.cardView.deactivate();
|
||||
this.$(this.el.axoCustomerDetails.selector).removeClass('col-1');
|
||||
this.$( this.el.axoCustomerDetails.selector ).removeClass(
|
||||
'col-1'
|
||||
);
|
||||
}
|
||||
|
||||
if ( scenario.axoPaymentContainer ) {
|
||||
this.el.paymentContainer.show();
|
||||
this.el.gatewayDescription.hide();
|
||||
document.querySelector(this.el.billingEmailSubmitButton.selector).setAttribute('disabled', 'disabled');
|
||||
document
|
||||
.querySelector( this.el.billingEmailSubmitButton.selector )
|
||||
.setAttribute( 'disabled', 'disabled' );
|
||||
} else {
|
||||
this.el.paymentContainer.hide();
|
||||
}
|
||||
|
@ -305,7 +362,7 @@ class AxoManager {
|
|||
}
|
||||
|
||||
identifyScenario( active, validEmail, hasProfile ) {
|
||||
let response = {
|
||||
const response = {
|
||||
defaultSubmitButton: false,
|
||||
defaultEmailField: false,
|
||||
defaultFormFields: false,
|
||||
|
@ -314,7 +371,7 @@ class AxoManager {
|
|||
axoProfileViews: false,
|
||||
axoPaymentContainer: false,
|
||||
axoSubmitButton: false,
|
||||
}
|
||||
};
|
||||
|
||||
if ( active && validEmail && hasProfile ) {
|
||||
response.extraFormFields = true;
|
||||
|
@ -344,7 +401,9 @@ class AxoManager {
|
|||
}
|
||||
|
||||
ensureBillingFieldsConsistency() {
|
||||
const $billingFields = this.$('.woocommerce-billing-fields .form-row:visible');
|
||||
const $billingFields = this.$(
|
||||
'.woocommerce-billing-fields .form-row:visible'
|
||||
);
|
||||
const $billingHeaders = this.$( '.woocommerce-billing-fields h3' );
|
||||
if ( this.billingView.isActive() ) {
|
||||
if ( $billingFields.length ) {
|
||||
|
@ -358,7 +417,9 @@ class AxoManager {
|
|||
}
|
||||
|
||||
ensureShippingFieldsConsistency() {
|
||||
const $shippingFields = this.$('.woocommerce-shipping-fields .form-row:visible');
|
||||
const $shippingFields = this.$(
|
||||
'.woocommerce-shipping-fields .form-row:visible'
|
||||
);
|
||||
const $shippingHeaders = this.$( '.woocommerce-shipping-fields h3' );
|
||||
if ( this.shippingView.isActive() ) {
|
||||
if ( $shippingFields.length ) {
|
||||
|
@ -386,7 +447,9 @@ class AxoManager {
|
|||
|
||||
log( `Status updated: ${ JSON.stringify( this.status ) }` );
|
||||
|
||||
document.dispatchEvent(new CustomEvent("axo_status_updated", {detail: this.status}));
|
||||
document.dispatchEvent(
|
||||
new CustomEvent( 'axo_status_updated', { detail: this.status } )
|
||||
);
|
||||
|
||||
this.rerender();
|
||||
}
|
||||
|
@ -397,8 +460,13 @@ class AxoManager {
|
|||
this.setStatus( 'active', true );
|
||||
|
||||
log( `Attempt on activation - emailInput: ${ this.emailInput.value }` );
|
||||
log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`);
|
||||
if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) {
|
||||
log(
|
||||
`this.lastEmailCheckedIdentity: ${ this.lastEmailCheckedIdentity }`
|
||||
);
|
||||
if (
|
||||
this.emailInput &&
|
||||
this.lastEmailCheckedIdentity !== this.emailInput.value
|
||||
) {
|
||||
this.onChangeEmail();
|
||||
}
|
||||
}
|
||||
|
@ -412,9 +480,12 @@ class AxoManager {
|
|||
|
||||
// Customer details container.
|
||||
if ( ! document.querySelector( wrapper.selector ) ) {
|
||||
document.querySelector(wrapper.anchorSelector).insertAdjacentHTML('afterbegin', `
|
||||
document.querySelector( wrapper.anchorSelector ).insertAdjacentHTML(
|
||||
'afterbegin',
|
||||
`
|
||||
<div id="${ wrapper.id }" class="${ wrapper.className }"></div>
|
||||
`);
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
const wrapperElement = document.querySelector( wrapper.selector );
|
||||
|
@ -422,64 +493,94 @@ class AxoManager {
|
|||
// Billing view container.
|
||||
const bc = this.el.billingAddressContainer;
|
||||
if ( ! document.querySelector( bc.selector ) ) {
|
||||
wrapperElement.insertAdjacentHTML('beforeend', `
|
||||
wrapperElement.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<div id="${ bc.id }" class="${ bc.className }"></div>
|
||||
`);
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
// Shipping view container.
|
||||
const sc = this.el.shippingAddressContainer;
|
||||
if ( ! document.querySelector( sc.selector ) ) {
|
||||
wrapperElement.insertAdjacentHTML('beforeend', `
|
||||
wrapperElement.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<div id="${ sc.id }" class="${ sc.className }"></div>
|
||||
`);
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
// billingEmailFieldWrapper
|
||||
const befw = this.el.billingEmailFieldWrapper;
|
||||
if ( ! document.querySelector( befw.selector ) ) {
|
||||
document.querySelector('#billing_email_field .woocommerce-input-wrapper').insertAdjacentHTML('afterend', `
|
||||
document
|
||||
.querySelector(
|
||||
'#billing_email_field .woocommerce-input-wrapper'
|
||||
)
|
||||
.insertAdjacentHTML(
|
||||
'afterend',
|
||||
`
|
||||
<div id="${ befw.id }"></div>
|
||||
`);
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
// Watermark container
|
||||
const wc = this.el.watermarkContainer;
|
||||
if ( ! document.querySelector( wc.selector ) ) {
|
||||
document.querySelector(befw.selector).insertAdjacentHTML('beforeend', `
|
||||
document.querySelector( befw.selector ).insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<div class="${ wc.className }" id="${ wc.id }"></div>
|
||||
`);
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
// Payment container
|
||||
const pc = this.el.paymentContainer;
|
||||
if ( ! document.querySelector( pc.selector ) ) {
|
||||
const gatewayPaymentContainer = document.querySelector('.payment_method_ppcp-axo-gateway');
|
||||
gatewayPaymentContainer.insertAdjacentHTML('beforeend', `
|
||||
const gatewayPaymentContainer = document.querySelector(
|
||||
'.payment_method_ppcp-axo-gateway'
|
||||
);
|
||||
gatewayPaymentContainer.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<div id="${ pc.id }" class="${ pc.className } axo-hidden">
|
||||
<div id="${ pc.id }-form" class="${ pc.className }-form"></div>
|
||||
<div id="${ pc.id }-details" class="${ pc.className }-details"></div>
|
||||
</div>
|
||||
`);
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
if ( this.useEmailWidget() ) {
|
||||
|
||||
// Display email widget.
|
||||
const ec = this.el.emailWidgetContainer;
|
||||
if ( ! document.querySelector( ec.selector ) ) {
|
||||
wrapperElement.insertAdjacentHTML('afterbegin', `
|
||||
wrapperElement.insertAdjacentHTML(
|
||||
'afterbegin',
|
||||
`
|
||||
<div id="${ ec.id }" class="${ ec.className }">
|
||||
--- EMAIL WIDGET PLACEHOLDER ---
|
||||
</div>
|
||||
`);
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Move email to the AXO container.
|
||||
let emailRow = document.querySelector(this.el.fieldBillingEmail.selector);
|
||||
const emailRow = document.querySelector(
|
||||
this.el.fieldBillingEmail.selector
|
||||
);
|
||||
wrapperElement.prepend( emailRow );
|
||||
document.querySelector(this.el.billingEmailFieldWrapper.selector).prepend(document.querySelector('#billing_email_field .woocommerce-input-wrapper'));
|
||||
document
|
||||
.querySelector( this.el.billingEmailFieldWrapper.selector )
|
||||
.prepend(
|
||||
document.querySelector(
|
||||
'#billing_email_field .woocommerce-input-wrapper'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,7 +603,7 @@ class AxoManager {
|
|||
|
||||
await this.fastlane.connect( {
|
||||
locale: this.locale,
|
||||
styles: this.styles
|
||||
styles: this.styles,
|
||||
} );
|
||||
|
||||
this.fastlane.setLocale( 'en_us' );
|
||||
|
@ -513,49 +614,76 @@ class AxoManager {
|
|||
}
|
||||
|
||||
async renderWatermark( includeAdditionalInfo = true ) {
|
||||
(await this.fastlane.FastlaneWatermarkComponent({
|
||||
includeAdditionalInfo
|
||||
})).render(this.el.watermarkContainer.selector);
|
||||
(
|
||||
await this.fastlane.FastlaneWatermarkComponent( {
|
||||
includeAdditionalInfo,
|
||||
} )
|
||||
).render( this.el.watermarkContainer.selector );
|
||||
|
||||
this.toggleWatermarkLoading(this.el.watermarkContainer, 'ppcp-axo-watermark-loading', 'loader');
|
||||
this.toggleWatermarkLoading(
|
||||
this.el.watermarkContainer,
|
||||
'ppcp-axo-watermark-loading',
|
||||
'loader'
|
||||
);
|
||||
}
|
||||
|
||||
renderEmailSubmitButton() {
|
||||
const billingEmailSubmitButton = this.el.billingEmailSubmitButton;
|
||||
const billingEmailSubmitButtonSpinner = this.el.billingEmailSubmitButtonSpinner;
|
||||
const billingEmailSubmitButtonSpinner =
|
||||
this.el.billingEmailSubmitButtonSpinner;
|
||||
|
||||
if ( ! document.querySelector( billingEmailSubmitButton.selector ) ) {
|
||||
document.querySelector(this.el.billingEmailFieldWrapper.selector).insertAdjacentHTML('beforeend', `
|
||||
document
|
||||
.querySelector( this.el.billingEmailFieldWrapper.selector )
|
||||
.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`
|
||||
<button type="button" id="${ billingEmailSubmitButton.id }" class="${ billingEmailSubmitButton.className }">
|
||||
${ this.axoConfig.billing_email_button_text }
|
||||
<span id="${ billingEmailSubmitButtonSpinner.id }"></span>
|
||||
</button>
|
||||
`);
|
||||
`
|
||||
);
|
||||
|
||||
document.querySelector(this.el.billingEmailSubmitButton.selector).offsetHeight;
|
||||
document.querySelector(this.el.billingEmailSubmitButton.selector).classList.remove('ppcp-axo-billing-email-submit-button-hidden');
|
||||
document.querySelector(this.el.billingEmailSubmitButton.selector).classList.add('ppcp-axo-billing-email-submit-button-loaded');
|
||||
document.querySelector( this.el.billingEmailSubmitButton.selector )
|
||||
.offsetHeight;
|
||||
document
|
||||
.querySelector( this.el.billingEmailSubmitButton.selector )
|
||||
.classList.remove(
|
||||
'ppcp-axo-billing-email-submit-button-hidden'
|
||||
);
|
||||
document
|
||||
.querySelector( this.el.billingEmailSubmitButton.selector )
|
||||
.classList.add( 'ppcp-axo-billing-email-submit-button-loaded' );
|
||||
}
|
||||
}
|
||||
|
||||
watchEmail() {
|
||||
|
||||
if ( this.useEmailWidget() ) {
|
||||
|
||||
// TODO
|
||||
|
||||
} else {
|
||||
this.emailInput.addEventListener( 'change', async () => {
|
||||
log(`Change event attempt - emailInput: ${this.emailInput.value}`);
|
||||
log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`);
|
||||
if (this.emailInput && this.lastEmailCheckedIdentity !== this.emailInput.value) {
|
||||
log(
|
||||
`Change event attempt - emailInput: ${ this.emailInput.value }`
|
||||
);
|
||||
log(
|
||||
`this.lastEmailCheckedIdentity: ${ this.lastEmailCheckedIdentity }`
|
||||
);
|
||||
if (
|
||||
this.emailInput &&
|
||||
this.lastEmailCheckedIdentity !== this.emailInput.value
|
||||
) {
|
||||
this.validateEmail( this.el.fieldBillingEmail.selector );
|
||||
this.onChangeEmail();
|
||||
}
|
||||
} );
|
||||
|
||||
log(`Last, this.emailInput.value attempt - emailInput: ${this.emailInput.value}`);
|
||||
log(`this.lastEmailCheckedIdentity: ${this.lastEmailCheckedIdentity}`);
|
||||
log(
|
||||
`Last, this.emailInput.value attempt - emailInput: ${ this.emailInput.value }`
|
||||
);
|
||||
log(
|
||||
`this.lastEmailCheckedIdentity: ${ this.lastEmailCheckedIdentity }`
|
||||
);
|
||||
if ( this.emailInput.value ) {
|
||||
this.onChangeEmail();
|
||||
}
|
||||
|
@ -575,7 +703,11 @@ class AxoManager {
|
|||
return;
|
||||
}
|
||||
|
||||
log(`Email changed: ${this.emailInput ? this.emailInput.value : '<empty>'}`);
|
||||
log(
|
||||
`Email changed: ${
|
||||
this.emailInput ? this.emailInput.value : '<empty>'
|
||||
}`
|
||||
);
|
||||
|
||||
this.$( this.el.paymentContainer.selector + '-detail' ).html( '' );
|
||||
this.$( this.el.paymentContainer.selector + '-form' ).html( '' );
|
||||
|
@ -587,7 +719,11 @@ class AxoManager {
|
|||
|
||||
this.lastEmailCheckedIdentity = this.emailInput.value;
|
||||
|
||||
if (!this.emailInput.value || !this.emailInput.checkValidity() || !this.validateEmailFormat(this.emailInput.value)) {
|
||||
if (
|
||||
! this.emailInput.value ||
|
||||
! this.emailInput.checkValidity() ||
|
||||
! this.validateEmailFormat( this.emailInput.value )
|
||||
) {
|
||||
log( 'The email address is not valid.' );
|
||||
return;
|
||||
}
|
||||
|
@ -601,30 +737,49 @@ class AxoManager {
|
|||
}
|
||||
|
||||
PayPalInsights.trackSubmitCheckoutEmail( {
|
||||
page_type: 'checkout'
|
||||
page_type: 'checkout',
|
||||
} );
|
||||
|
||||
|
||||
this.disableGatewaySelection();
|
||||
this.spinnerToggleLoaderAndOverlay(this.el.billingEmailSubmitButtonSpinner, 'loader', 'ppcp-axo-overlay');
|
||||
this.spinnerToggleLoaderAndOverlay(
|
||||
this.el.billingEmailSubmitButtonSpinner,
|
||||
'loader',
|
||||
'ppcp-axo-overlay'
|
||||
);
|
||||
await this.lookupCustomerByEmail();
|
||||
this.spinnerToggleLoaderAndOverlay(this.el.billingEmailSubmitButtonSpinner, 'loader', 'ppcp-axo-overlay');
|
||||
this.spinnerToggleLoaderAndOverlay(
|
||||
this.el.billingEmailSubmitButtonSpinner,
|
||||
'loader',
|
||||
'ppcp-axo-overlay'
|
||||
);
|
||||
this.enableGatewaySelection();
|
||||
}
|
||||
|
||||
async lookupCustomerByEmail() {
|
||||
const lookupResponse = await this.fastlane.identity.lookupCustomerByEmail(this.emailInput.value);
|
||||
const lookupResponse =
|
||||
await this.fastlane.identity.lookupCustomerByEmail(
|
||||
this.emailInput.value
|
||||
);
|
||||
|
||||
log( `lookupCustomerByEmail: ${ JSON.stringify( lookupResponse ) }` );
|
||||
|
||||
if ( lookupResponse.customerContextId ) {
|
||||
// Email is associated with a Connect profile or a PayPal member.
|
||||
// Authenticate the customer to get access to their profile.
|
||||
log('Email is associated with a Connect profile or a PayPal member');
|
||||
log(
|
||||
'Email is associated with a Connect profile or a PayPal member'
|
||||
);
|
||||
|
||||
const authResponse = await this.fastlane.identity.triggerAuthenticationFlow(lookupResponse.customerContextId);
|
||||
const authResponse =
|
||||
await this.fastlane.identity.triggerAuthenticationFlow(
|
||||
lookupResponse.customerContextId
|
||||
);
|
||||
|
||||
log(`AuthResponse - triggerAuthenticationFlow: ${JSON.stringify(authResponse)}`);
|
||||
log(
|
||||
`AuthResponse - triggerAuthenticationFlow: ${ JSON.stringify(
|
||||
authResponse
|
||||
) }`
|
||||
);
|
||||
|
||||
if ( authResponse.authenticationState === 'succeeded' ) {
|
||||
const shippingData = authResponse.profileData.shippingAddress;
|
||||
|
@ -635,21 +790,27 @@ class AxoManager {
|
|||
if ( authResponse.profileData.card ) {
|
||||
this.setStatus( 'hasCard', true );
|
||||
} else {
|
||||
this.cardComponent = (await this.fastlane.FastlaneCardComponent(
|
||||
this.cardComponent = (
|
||||
await this.fastlane.FastlaneCardComponent(
|
||||
this.cardComponentData()
|
||||
)).render(this.el.paymentContainer.selector + '-form');
|
||||
)
|
||||
).render( this.el.paymentContainer.selector + '-form' );
|
||||
}
|
||||
|
||||
const cardBillingAddress = authResponse.profileData?.card?.paymentSource?.card?.billingAddress;
|
||||
const cardBillingAddress =
|
||||
authResponse.profileData?.card?.paymentSource?.card
|
||||
?.billingAddress;
|
||||
if ( cardBillingAddress ) {
|
||||
this.setCard( authResponse.profileData.card );
|
||||
|
||||
const billingData = {
|
||||
address: cardBillingAddress,
|
||||
};
|
||||
const phoneNumber = authResponse.profileData?.shippingAddress?.phoneNumber?.nationalNumber ?? '';
|
||||
const phoneNumber =
|
||||
authResponse.profileData?.shippingAddress?.phoneNumber
|
||||
?.nationalNumber ?? '';
|
||||
if ( phoneNumber ) {
|
||||
billingData.phoneNumber = phoneNumber
|
||||
billingData.phoneNumber = phoneNumber;
|
||||
}
|
||||
|
||||
this.setBilling( billingData );
|
||||
|
@ -665,22 +826,22 @@ class AxoManager {
|
|||
await this.renderWatermark( false );
|
||||
|
||||
this.rerender();
|
||||
|
||||
} else {
|
||||
// authentication failed or canceled by the customer
|
||||
// set status as guest customer
|
||||
log("Authentication Failed")
|
||||
log( 'Authentication Failed' );
|
||||
|
||||
this.setStatus( 'validEmail', true );
|
||||
this.setStatus( 'hasProfile', false );
|
||||
|
||||
await this.renderWatermark( true );
|
||||
|
||||
this.cardComponent = (await this.fastlane.FastlaneCardComponent(
|
||||
this.cardComponent = (
|
||||
await this.fastlane.FastlaneCardComponent(
|
||||
this.cardComponentData()
|
||||
)).render(this.el.paymentContainer.selector + '-form');
|
||||
)
|
||||
).render( this.el.paymentContainer.selector + '-form' );
|
||||
}
|
||||
|
||||
} else {
|
||||
// No profile found with this email address.
|
||||
// This is a guest customer.
|
||||
|
@ -691,9 +852,11 @@ class AxoManager {
|
|||
|
||||
await this.renderWatermark( true );
|
||||
|
||||
this.cardComponent = (await this.fastlane.FastlaneCardComponent(
|
||||
this.cardComponent = (
|
||||
await this.fastlane.FastlaneCardComponent(
|
||||
this.cardComponentData()
|
||||
)).render(this.el.paymentContainer.selector + '-form');
|
||||
)
|
||||
).render( this.el.paymentContainer.selector + '-form' );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -732,30 +895,34 @@ class AxoManager {
|
|||
onClickSubmitButton() {
|
||||
// TODO: validate data.
|
||||
|
||||
if (this.data.card) { // Ryan flow
|
||||
if ( this.data.card ) {
|
||||
// Ryan flow
|
||||
log( 'Starting Ryan flow.' );
|
||||
|
||||
this.$('#ship-to-different-address-checkbox').prop('checked', 'checked');
|
||||
this.$( '#ship-to-different-address-checkbox' ).prop(
|
||||
'checked',
|
||||
'checked'
|
||||
);
|
||||
|
||||
let data = {};
|
||||
const data = {};
|
||||
this.billingView.toSubmitData( data );
|
||||
this.shippingView.toSubmitData( data );
|
||||
this.cardView.toSubmitData( data );
|
||||
|
||||
this.ensureBillingPhoneNumber( data );
|
||||
|
||||
log(`Ryan flow - submitted nonce: ${this.data.card.id}` )
|
||||
log( `Ryan flow - submitted nonce: ${ this.data.card.id }` );
|
||||
|
||||
this.submit( this.data.card.id, data );
|
||||
|
||||
} else { // Gary flow
|
||||
} else {
|
||||
// Gary flow
|
||||
log( 'Starting Gary flow.' );
|
||||
|
||||
try {
|
||||
this.cardComponent.getPaymentToken(
|
||||
this.tokenizeData()
|
||||
).then((response) => {
|
||||
log(`Gary flow - submitted nonce: ${response.id}` )
|
||||
this.cardComponent
|
||||
.getPaymentToken( this.tokenizeData() )
|
||||
.then( ( response ) => {
|
||||
log( `Gary flow - submitted nonce: ${ response.id }` );
|
||||
this.submit( response.id );
|
||||
} );
|
||||
} catch ( e ) {
|
||||
|
@ -769,17 +936,19 @@ class AxoManager {
|
|||
return {
|
||||
fields: {
|
||||
cardholderName: {
|
||||
enabled: this.axoConfig.name_on_card === '1'
|
||||
}
|
||||
enabled: this.axoConfig.name_on_card === '1',
|
||||
},
|
||||
styles: this.deleteKeysWithEmptyString(this.axoConfig.style_options)
|
||||
}
|
||||
},
|
||||
styles: this.deleteKeysWithEmptyString(
|
||||
this.axoConfig.style_options
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
tokenizeData() {
|
||||
return {
|
||||
cardholderName: {
|
||||
fullName: this.billingView.fullName()
|
||||
fullName: this.billingView.fullName(),
|
||||
},
|
||||
billingAddress: {
|
||||
addressLine1: this.billingView.inputValue( 'street1' ),
|
||||
|
@ -788,14 +957,16 @@ class AxoManager {
|
|||
adminArea2: this.billingView.inputValue( 'city' ),
|
||||
postalCode: this.billingView.inputValue( 'postCode' ),
|
||||
countryCode: this.billingView.inputValue( 'countryCode' ),
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
submit( nonce, data ) {
|
||||
// Send the nonce and previously captured device data to server to complete checkout
|
||||
if ( ! this.el.axoNonceInput.get() ) {
|
||||
this.$('form.woocommerce-checkout').append(`<input type="hidden" id="${this.el.axoNonceInput.id}" name="axo_nonce" value="" />`);
|
||||
this.$( 'form.woocommerce-checkout' ).append(
|
||||
`<input type="hidden" id="${ this.el.axoNonceInput.id }" name="axo_nonce" value="" />`
|
||||
);
|
||||
}
|
||||
|
||||
this.el.axoNonceInput.get().value = nonce;
|
||||
|
@ -807,11 +978,10 @@ class AxoManager {
|
|||
user_data: {
|
||||
country: 'US',
|
||||
is_store_member: false,
|
||||
}
|
||||
},
|
||||
} );
|
||||
|
||||
if ( data ) {
|
||||
|
||||
// Ryan flow.
|
||||
const form = document.querySelector( 'form.woocommerce-checkout' );
|
||||
const formData = new FormData( form );
|
||||
|
@ -826,22 +996,31 @@ class AxoManager {
|
|||
// Set type of user (Ryan) to be received on WC gateway process payment request.
|
||||
formData.set( 'fastlane_member', true );
|
||||
|
||||
fetch(wc_checkout_params.checkout_url, { // TODO: maybe create a new endpoint to process_payment.
|
||||
method: "POST",
|
||||
body: formData
|
||||
fetch( wc_checkout_params.checkout_url, {
|
||||
// TODO: maybe create a new endpoint to process_payment.
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
} )
|
||||
.then(response => response.json())
|
||||
.then(responseData => {
|
||||
.then( ( response ) => response.json() )
|
||||
.then( ( responseData ) => {
|
||||
if ( responseData.result === 'failure' ) {
|
||||
if ( responseData.messages ) {
|
||||
const $notices = this.$('.woocommerce-notices-wrapper').eq(0);
|
||||
const $notices = this.$(
|
||||
'.woocommerce-notices-wrapper'
|
||||
).eq( 0 );
|
||||
$notices.html( responseData.messages );
|
||||
this.$('html, body').animate({
|
||||
scrollTop: $notices.offset().top
|
||||
}, 500);
|
||||
this.$( 'html, body' ).animate(
|
||||
{
|
||||
scrollTop: $notices.offset().top,
|
||||
},
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
log(`Error sending checkout form. ${responseData}`, 'error');
|
||||
log(
|
||||
`Error sending checkout form. ${ responseData }`,
|
||||
'error'
|
||||
);
|
||||
|
||||
this.hideLoading();
|
||||
return;
|
||||
|
@ -850,22 +1029,25 @@ class AxoManager {
|
|||
window.location.href = responseData.redirect;
|
||||
}
|
||||
} )
|
||||
.catch(error => {
|
||||
log(`Error sending checkout form. ${error.message}`, 'error');
|
||||
.catch( ( error ) => {
|
||||
log(
|
||||
`Error sending checkout form. ${ error.message }`,
|
||||
'error'
|
||||
);
|
||||
|
||||
this.hideLoading();
|
||||
} );
|
||||
|
||||
} else {
|
||||
// Gary flow.
|
||||
this.el.defaultSubmitButton.click();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
showLoading() {
|
||||
const submitContainerSelector = '.woocommerce-checkout-payment';
|
||||
jQuery('form.woocommerce-checkout').append('<div class="blockUI blockOverlay" style="z-index: 1000; border: medium; margin: 0px; padding: 0px; width: 100%; height: 100%; top: 0px; left: 0px; background: rgb(255, 255, 255); opacity: 0.6; cursor: default; position: absolute;"></div>');
|
||||
jQuery( 'form.woocommerce-checkout' ).append(
|
||||
'<div class="blockUI blockOverlay" style="z-index: 1000; border: medium; margin: 0px; padding: 0px; width: 100%; height: 100%; top: 0px; left: 0px; background: rgb(255, 255, 255); opacity: 0.6; cursor: default; position: absolute;"></div>'
|
||||
);
|
||||
disable( submitContainerSelector );
|
||||
}
|
||||
|
||||
|
@ -880,18 +1062,19 @@ class AxoManager {
|
|||
}
|
||||
|
||||
deleteKeysWithEmptyString = ( obj ) => {
|
||||
for(let key of Object.keys(obj)){
|
||||
for ( const key of Object.keys( obj ) ) {
|
||||
if ( obj[ key ] === '' ) {
|
||||
delete obj[ key ];
|
||||
}
|
||||
else if (typeof obj[key] === 'object'){
|
||||
} else if ( typeof obj[ key ] === 'object' ) {
|
||||
obj[ key ] = this.deleteKeysWithEmptyString( obj[ key ] );
|
||||
if (Object.keys(obj[key]).length === 0 ) delete obj[key];
|
||||
if ( Object.keys( obj[ key ] ).length === 0 ) {
|
||||
delete obj[ key ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Array.isArray(obj) ? obj.filter(val => val) : obj;
|
||||
}
|
||||
return Array.isArray( obj ) ? obj.filter( ( val ) => val ) : obj;
|
||||
};
|
||||
|
||||
ensureBillingPhoneNumber( data ) {
|
||||
if ( data.billing_phone === '' ) {
|
||||
|
@ -909,8 +1092,12 @@ class AxoManager {
|
|||
}
|
||||
|
||||
toggleLoaderAndOverlay( element, loaderClass, overlayClass ) {
|
||||
const loader = document.querySelector(`${element.selector} .${loaderClass}`);
|
||||
const overlay = document.querySelector(`${element.selector} .${overlayClass}`);
|
||||
const loader = document.querySelector(
|
||||
`${ element.selector } .${ loaderClass }`
|
||||
);
|
||||
const overlay = document.querySelector(
|
||||
`${ element.selector } .${ overlayClass }`
|
||||
);
|
||||
if ( loader ) {
|
||||
loader.classList.toggle( loaderClass );
|
||||
}
|
||||
|
@ -928,8 +1115,12 @@ class AxoManager {
|
|||
}
|
||||
|
||||
toggleWatermarkLoading( container, loadingClass, loaderClass ) {
|
||||
const watermarkLoading = document.querySelector(`${container.selector}.${loadingClass}`);
|
||||
const watermarkLoader = document.querySelector(`${container.selector}.${loaderClass}`);
|
||||
const watermarkLoading = document.querySelector(
|
||||
`${ container.selector }.${ loadingClass }`
|
||||
);
|
||||
const watermarkLoader = document.querySelector(
|
||||
`${ container.selector }.${ loaderClass }`
|
||||
);
|
||||
if ( watermarkLoading ) {
|
||||
watermarkLoading.classList.toggle( loadingClass );
|
||||
}
|
||||
|
@ -960,7 +1151,9 @@ class AxoManager {
|
|||
|
||||
reEnableEmailInput() {
|
||||
const reEnableInput = ( ev ) => {
|
||||
const submitButton = document.querySelector(this.el.billingEmailSubmitButton.selector);
|
||||
const submitButton = document.querySelector(
|
||||
this.el.billingEmailSubmitButton.selector
|
||||
);
|
||||
if ( submitButton.hasAttribute( 'disabled' ) ) {
|
||||
submitButton.removeAttribute( 'disabled' );
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class DomElement {
|
||||
|
||||
constructor( config ) {
|
||||
this.$ = jQuery;
|
||||
this.config = config;
|
||||
|
@ -33,7 +32,6 @@ class DomElement {
|
|||
get() {
|
||||
return document.querySelector( this.selector );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DomElement;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import DomElement from "./DomElement";
|
||||
import DomElement from './DomElement';
|
||||
|
||||
class DomElementCollection {
|
||||
|
||||
constructor() {
|
||||
this.gatewayRadioButton = new DomElement( {
|
||||
selector: '#payment_method_ppcp-axo-gateway',
|
||||
|
@ -18,46 +17,47 @@ class DomElementCollection {
|
|||
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( {
|
||||
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)'
|
||||
selector: '#customer_details > *:not(#ppcp-axo-customer-details)',
|
||||
} );
|
||||
|
||||
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( {
|
||||
id: 'ppcp-axo-email-widget',
|
||||
selector: '#ppcp-axo-email-widget',
|
||||
className: 'ppcp-axo-email-widget'
|
||||
className: 'ppcp-axo-email-widget',
|
||||
} );
|
||||
|
||||
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( {
|
||||
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'
|
||||
selector: '#billing_email_field',
|
||||
} );
|
||||
|
||||
this.billingEmailFieldWrapper = new DomElement( {
|
||||
|
@ -68,13 +68,14 @@ class DomElementCollection {
|
|||
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( {
|
||||
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( {
|
||||
|
@ -82,7 +83,7 @@ class DomElementCollection {
|
|||
} );
|
||||
|
||||
this.submitButton = new DomElement( {
|
||||
selector: '#ppcp-axo-submit-button-container button'
|
||||
selector: '#ppcp-axo-submit-button-container button',
|
||||
} );
|
||||
|
||||
this.changeShippingAddressLink = new DomElement( {
|
||||
|
@ -109,7 +110,6 @@ class DomElementCollection {
|
|||
id: 'ppcp-axo-nonce',
|
||||
selector: '#ppcp-axo-nonce',
|
||||
} );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
class FormFieldGroup {
|
||||
|
||||
constructor( config ) {
|
||||
this.data = {};
|
||||
|
||||
|
@ -32,7 +30,13 @@ class FormFieldGroup {
|
|||
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,7 +55,7 @@ class FormFieldGroup {
|
|||
}
|
||||
|
||||
refresh() {
|
||||
let content = document.querySelector(this.contentSelector);
|
||||
const content = document.querySelector( this.contentSelector );
|
||||
|
||||
if ( ! content ) {
|
||||
return;
|
||||
|
@ -89,21 +93,24 @@ class FormFieldGroup {
|
|||
}
|
||||
} );
|
||||
return isEmpty;
|
||||
}
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
showField( selector ) {
|
||||
const field = document.querySelector(this.baseSelector + ' ' + 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);
|
||||
const field = document.querySelector(
|
||||
this.baseSelector + ' ' + selector
|
||||
);
|
||||
if ( field ) {
|
||||
field.classList.add( 'ppcp-axo-field-hidden' );
|
||||
}
|
||||
|
@ -147,7 +154,6 @@ class FormFieldGroup {
|
|||
data[ inputElement.name ] = this.dataValue( fieldKey );
|
||||
} );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FormFieldGroup;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
class Fastlane {
|
||||
|
||||
construct() {
|
||||
this.connection = null;
|
||||
this.identity = null;
|
||||
|
@ -12,13 +10,14 @@ class Fastlane {
|
|||
|
||||
connect( config ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
window.paypal.Fastlane(config)
|
||||
window.paypal
|
||||
.Fastlane( config )
|
||||
.then( ( result ) => {
|
||||
this.init( result );
|
||||
resolve();
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
console.error(error)
|
||||
console.error( error );
|
||||
reject();
|
||||
} );
|
||||
} );
|
||||
|
@ -29,14 +28,15 @@ class Fastlane {
|
|||
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 );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Fastlane;
|
||||
|
|
|
@ -13,8 +13,8 @@ export function log(message, level = 'info') {
|
|||
log: {
|
||||
message,
|
||||
level,
|
||||
}
|
||||
})
|
||||
},
|
||||
} ),
|
||||
} ).then( () => {
|
||||
if ( wpDebug ) {
|
||||
switch ( level ) {
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
|
||||
class PayPalInsights {
|
||||
|
||||
constructor() {
|
||||
window.paypalInsightDataLayer = window.paypalInsightDataLayer || [];
|
||||
document.paypalInsight = () => {
|
||||
paypalInsightDataLayer.push( arguments );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {PayPalInsights}
|
||||
* @return {PayPalInsights}
|
||||
*/
|
||||
static init() {
|
||||
if ( ! PayPalInsights.instance ) {
|
||||
|
@ -52,7 +50,6 @@ class PayPalInsights {
|
|||
static trackEndCheckout( data ) {
|
||||
PayPalInsights.track( 'end_checkout', data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PayPalInsights;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import FormFieldGroup from "../Components/FormFieldGroup";
|
||||
import FormFieldGroup from '../Components/FormFieldGroup';
|
||||
|
||||
class BillingView {
|
||||
|
||||
constructor( selector, elements ) {
|
||||
this.el = elements;
|
||||
|
||||
|
@ -13,15 +12,18 @@ class BillingView {
|
|||
if ( ! key ) {
|
||||
return '';
|
||||
}
|
||||
const selectElement = document.querySelector(selectSelector);
|
||||
const selectElement =
|
||||
document.querySelector( selectSelector );
|
||||
|
||||
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() ) {
|
||||
return `
|
||||
|
@ -38,49 +40,49 @@ 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',
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -109,13 +111,14 @@ class BillingView {
|
|||
}
|
||||
|
||||
fullName() {
|
||||
return `${this.inputValue('firstName')} ${this.inputValue('lastName')}`.trim();
|
||||
return `${ this.inputValue( 'firstName' ) } ${ this.inputValue(
|
||||
'lastName'
|
||||
) }`.trim();
|
||||
}
|
||||
|
||||
toSubmitData( data ) {
|
||||
return this.group.toSubmitData( data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BillingView;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import FormFieldGroup from "../Components/FormFieldGroup";
|
||||
import FormFieldGroup from '../Components/FormFieldGroup';
|
||||
|
||||
class CardView {
|
||||
|
||||
constructor( selector, elements, manager ) {
|
||||
this.el = elements;
|
||||
this.manager = manager;
|
||||
|
@ -28,33 +27,44 @@ class CardView {
|
|||
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')]}"
|
||||
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 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="text-transform: uppercase">${ data.value(
|
||||
'name'
|
||||
) }</div>
|
||||
</div>
|
||||
${ selectOtherPaymentMethod() }
|
||||
</div>
|
||||
|
@ -62,18 +72,18 @@ class CardView {
|
|||
},
|
||||
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',
|
||||
},
|
||||
},
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -97,20 +107,20 @@ class CardView {
|
|||
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 );
|
||||
}
|
||||
|
||||
splitName( fullName ) {
|
||||
let nameParts = fullName.trim().split(' ');
|
||||
let firstName = nameParts[0];
|
||||
let lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : '';
|
||||
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,7 +1,6 @@
|
|||
import FormFieldGroup from "../Components/FormFieldGroup";
|
||||
import FormFieldGroup from '../Components/FormFieldGroup';
|
||||
|
||||
class ShippingView {
|
||||
|
||||
constructor( selector, elements, states ) {
|
||||
this.el = elements;
|
||||
this.states = states;
|
||||
|
@ -13,15 +12,18 @@ class ShippingView {
|
|||
if ( ! key ) {
|
||||
return '';
|
||||
}
|
||||
const selectElement = document.querySelector(selectSelector);
|
||||
const selectElement =
|
||||
document.querySelector( selectSelector );
|
||||
|
||||
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() ) {
|
||||
return `
|
||||
|
@ -36,11 +38,13 @@ class ShippingView {
|
|||
}
|
||||
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 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">
|
||||
|
@ -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( '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(
|
||||
'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 } `;
|
||||
}
|
||||
phone += number;
|
||||
return phone;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
hasEmptyValues( data, stateName ) {
|
||||
return !data.value('email')
|
||||
|| !data.value('firstName')
|
||||
|| !data.value('lastName')
|
||||
|| !data.value('street1')
|
||||
|| !data.value('city')
|
||||
|| !stateName;
|
||||
return (
|
||||
! data.value( 'email' ) ||
|
||||
! data.value( 'firstName' ) ||
|
||||
! data.value( 'lastName' ) ||
|
||||
! data.value( 'street1' ) ||
|
||||
! data.value( 'city' ) ||
|
||||
! stateName
|
||||
);
|
||||
}
|
||||
|
||||
isActive() {
|
||||
|
@ -164,7 +180,6 @@ class ShippingView {
|
|||
toSubmitData( data ) {
|
||||
return this.group.toSubmitData( data );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ShippingView;
|
||||
|
|
|
@ -1,20 +1,13 @@
|
|||
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 );
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
if (!typeof (PayPalCommerceGateway)) {
|
||||
document.addEventListener( 'DOMContentLoaded', () => {
|
||||
if ( ! typeof PayPalCommerceGateway ) {
|
||||
console.error( 'AXO could not be configured.' );
|
||||
return;
|
||||
}
|
||||
|
@ -23,11 +16,9 @@ import {loadPaypalScript} from "../../../ppcp-button/resources/js/modules/Helper
|
|||
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' } );
|
||||
|
||||
expect(element.selector).toBe('.foo')
|
||||
expect( element.selector ).toBe( '.foo' );
|
||||
} );
|
||||
|
||||
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,5 +1,5 @@
|
|||
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 ) {
|
||||
|
@ -13,9 +13,11 @@ class BlockCheckoutMessagesBootstrap {
|
|||
this._updateCartTotal();
|
||||
|
||||
if ( wp.data?.subscribe ) {
|
||||
wp.data.subscribe(debounce(() => {
|
||||
wp.data.subscribe(
|
||||
debounce( () => {
|
||||
this._updateCartTotal();
|
||||
}, 300));
|
||||
}, 300 )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,13 +29,16 @@ class BlockCheckoutMessagesBootstrap {
|
|||
return null;
|
||||
}
|
||||
|
||||
const cart = wp.data.select('wc/store/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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,7 +52,9 @@ class BlockCheckoutMessagesBootstrap {
|
|||
|
||||
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,
|
||||
] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,50 +4,55 @@ 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}) {
|
||||
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)
|
||||
}
|
||||
setCardFieldsForm( cardFieldsForm );
|
||||
};
|
||||
|
||||
const getSavePayment = ( savePayment ) => {
|
||||
localStorage.setItem( 'ppcp-save-card-payment', savePayment );
|
||||
}
|
||||
};
|
||||
|
||||
const hasSubscriptionProducts = cartHasSubscriptionProducts(config.scriptData);
|
||||
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( () => {
|
||||
async function handlePaymentProcessing() {
|
||||
await cardFieldsForm.submit()
|
||||
.catch((error) => {
|
||||
await cardFieldsForm.submit().catch( ( error ) => {
|
||||
return {
|
||||
type: responseTypes.ERROR,
|
||||
}
|
||||
};
|
||||
} );
|
||||
|
||||
return {
|
||||
type: responseTypes.SUCCESS,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return handlePaymentProcessing();
|
||||
|
@ -60,7 +65,7 @@ export function CardFields({config, eventRegistration, emitResponse, components}
|
|||
<PayPalScriptProvider
|
||||
options={ {
|
||||
clientId: config.scriptData.client_id,
|
||||
components: "card-fields",
|
||||
components: 'card-fields',
|
||||
dataNamespace: 'ppcp-block-card-fields',
|
||||
} }
|
||||
>
|
||||
|
@ -72,7 +77,10 @@ export function CardFields({config, eventRegistration, emitResponse, components}
|
|||
} }
|
||||
>
|
||||
<PayPalCardFieldsForm />
|
||||
<PaymentMethodIcons icons={config.card_icons} align="left" />
|
||||
<PaymentMethodIcons
|
||||
icons={ config.card_icons }
|
||||
align="left"
|
||||
/>
|
||||
<CheckoutHandler
|
||||
getCardFieldsForm={ getCardFieldsForm }
|
||||
getSavePayment={ getSavePayment }
|
||||
|
@ -83,5 +91,5 @@ export function CardFields({config, eventRegistration, emitResponse, components}
|
|||
</PayPalCardFieldsProvider>
|
||||
</PayPalScriptProvider>
|
||||
</>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,17 @@
|
|||
import { useEffect } from '@wordpress/element';
|
||||
import {usePayPalCardFields} from "@paypal/react-paypal-js";
|
||||
import { usePayPalCardFields } from '@paypal/react-paypal-js';
|
||||
|
||||
export const CheckoutHandler = ({getCardFieldsForm, getSavePayment, hasSubscriptionProducts, saveCardText, is_vaulting_enabled}) => {
|
||||
export const CheckoutHandler = ( {
|
||||
getCardFieldsForm,
|
||||
getSavePayment,
|
||||
hasSubscriptionProducts,
|
||||
saveCardText,
|
||||
is_vaulting_enabled,
|
||||
} ) => {
|
||||
const { cardFieldsForm } = usePayPalCardFields();
|
||||
|
||||
useEffect( () => {
|
||||
getCardFieldsForm(cardFieldsForm)
|
||||
getCardFieldsForm( cardFieldsForm );
|
||||
}, [] );
|
||||
|
||||
if ( ! is_vaulting_enabled ) {
|
||||
|
@ -24,5 +30,5 @@ export const CheckoutHandler = ({getCardFieldsForm, getSavePayment, hasSubscript
|
|||
/>
|
||||
<label htmlFor="save">{ saveCardText }</label>
|
||||
</>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
* @param {String} fullName
|
||||
* @returns {Array}
|
||||
* @param {string} fullName
|
||||
* @return {Array}
|
||||
*/
|
||||
export const splitFullName = ( fullName ) => {
|
||||
fullName = fullName.trim()
|
||||
fullName = fullName.trim();
|
||||
if ( ! fullName.includes( ' ' ) ) {
|
||||
return [ fullName, '' ];
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ export const splitFullName = (fullName) => {
|
|||
parts.shift();
|
||||
const lastName = parts.join( ' ' );
|
||||
return [ firstName, lastName ];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} address
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalAddressToWc = ( address ) => {
|
||||
let map = {
|
||||
|
@ -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',
|
||||
|
@ -56,24 +57,26 @@ export const paypalAddressToWc = (address) => {
|
|||
};
|
||||
|
||||
return { ...defaultAddress, ...result };
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} shipping
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalShippingToWc = ( shipping ) => {
|
||||
const [firstName, lastName] = (shipping.name ? splitFullName(shipping.name.full_name) : ['','']);
|
||||
const [ firstName, lastName ] = shipping.name
|
||||
? splitFullName( shipping.name.full_name )
|
||||
: [ '', '' ];
|
||||
return {
|
||||
...paypalAddressToWc( shipping.address ),
|
||||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} payer
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
export const paypalPayerToWc = ( payer ) => {
|
||||
const firstName = payer?.name?.given_name ?? '';
|
||||
|
@ -84,28 +87,30 @@ export const paypalPayerToWc = (payer) => {
|
|||
first_name: firstName,
|
||||
last_name: lastName,
|
||||
email: payer.email_address,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} subscriber
|
||||
* @returns {Object}
|
||||
* @return {Object}
|
||||
*/
|
||||
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;
|
||||
|
@ -118,19 +123,22 @@ export const paypalOrderToWcShippingAddress = (order) => {
|
|||
// 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 (
|
||||
`${ 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 );
|
||||
|
@ -140,7 +148,7 @@ export const paypalOrderToWcAddresses = (order) => {
|
|||
// no billing address, such as if billing address retrieval is not allowed in the merchant account
|
||||
if ( ! billingAddress.address_line_1 ) {
|
||||
// use only non empty values from payer address, otherwise it will override shipping address
|
||||
let payerAddress = Object.fromEntries(
|
||||
const payerAddress = Object.fromEntries(
|
||||
Object.entries( billingAddress ).filter(
|
||||
( [ key, value ] ) => value !== '' && key !== 'country'
|
||||
)
|
||||
|
@ -148,24 +156,24 @@ export const paypalOrderToWcAddresses = (order) => {
|
|||
|
||||
billingAddress = {
|
||||
...shippingAddress,
|
||||
...payerAddress
|
||||
...payerAddress,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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 ) {
|
||||
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 => {
|
||||
const address2WithoutEmpty = { ...address2 };
|
||||
Object.keys( address2 ).forEach( ( key ) => {
|
||||
if ( address2[ key ] === '' ) {
|
||||
delete address2WithoutEmpty[ key ];
|
||||
}
|
||||
} );
|
||||
|
||||
return { ...address1, ...address2WithoutEmpty };
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
/**
|
||||
* @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();
|
||||
}
|
||||
return str
|
||||
.replace( /[\w]([A-Z])/g, function ( m ) {
|
||||
return m[ 0 ] + '_' + m[ 1 ];
|
||||
} )
|
||||
.toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param obj
|
||||
* @returns {{}}
|
||||
* @return {{}}
|
||||
*/
|
||||
export const convertKeysToSnakeCase = ( obj ) => {
|
||||
const newObj = {};
|
||||
|
@ -19,4 +21,4 @@ export const convertKeysToSnakeCase = (obj) => {
|
|||
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;
|
||||
}
|
||||
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 ) => {
|
||||
return !! scriptData?.locations_with_subscription_product?.cart;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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' );
|
||||
|
||||
|
@ -9,9 +9,11 @@ registerPaymentMethod({
|
|||
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,
|
||||
},
|
||||
} );
|
||||
|
|
|
@ -2,15 +2,16 @@ export async function createOrder() {
|
|||
const config = wc.wcSettings.getSetting( 'ppcp-credit-card-gateway_data' );
|
||||
|
||||
return fetch( config.scriptData.ajax.create_order.endpoint, {
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
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',
|
||||
save_payment_method:
|
||||
localStorage.getItem( 'ppcp-save-card-payment' ) === 'true',
|
||||
} ),
|
||||
} )
|
||||
.then( ( response ) => response.json() )
|
||||
|
@ -26,9 +27,9 @@ 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",
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify( {
|
||||
order_id: data.orderID,
|
||||
|
|
|
@ -1,31 +1,26 @@
|
|||
import { useEffect, useState } from '@wordpress/element';
|
||||
import {registerExpressPaymentMethod, registerPaymentMethod} from '@woocommerce/blocks-registry';
|
||||
import {
|
||||
registerExpressPaymentMethod,
|
||||
registerPaymentMethod,
|
||||
} from '@woocommerce/blocks-registry';
|
||||
import {
|
||||
mergeWcAddress,
|
||||
paypalAddressToWc,
|
||||
paypalOrderToWcAddresses,
|
||||
paypalSubscriptionToWcAddresses
|
||||
} from "./Helper/Address";
|
||||
import {
|
||||
convertKeysToSnakeCase
|
||||
} from "./Helper/Helper";
|
||||
paypalSubscriptionToWcAddresses,
|
||||
} from './Helper/Address';
|
||||
import { convertKeysToSnakeCase } from './Helper/Helper';
|
||||
import {
|
||||
cartHasSubscriptionProducts,
|
||||
isPayPalSubscription
|
||||
} from "./Helper/Subscription";
|
||||
import {
|
||||
loadPaypalScriptPromise
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading'
|
||||
import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
|
||||
import {
|
||||
normalizeStyleForFundingSource
|
||||
} from '../../../ppcp-button/resources/js/modules/Helper/Style'
|
||||
import buttonModuleWatcher from "../../../ppcp-button/resources/js/modules/ButtonModuleWatcher";
|
||||
import BlockCheckoutMessagesBootstrap from "./Bootstrap/BlockCheckoutMessagesBootstrap";
|
||||
import {keysToCamelCase} from "../../../ppcp-button/resources/js/modules/Helper/Utils";
|
||||
import {
|
||||
handleShippingOptionsChange
|
||||
} from "../../../ppcp-button/resources/js/modules/Helper/ShippingHandler";
|
||||
isPayPalSubscription,
|
||||
} from './Helper/Subscription';
|
||||
import { loadPaypalScriptPromise } from '../../../ppcp-button/resources/js/modules/Helper/ScriptLoading';
|
||||
import { PayPalScriptProvider, PayPalButtons } from '@paypal/react-paypal-js';
|
||||
import { normalizeStyleForFundingSource } from '../../../ppcp-button/resources/js/modules/Helper/Style';
|
||||
import buttonModuleWatcher from '../../../ppcp-button/resources/js/modules/ButtonModuleWatcher';
|
||||
import BlockCheckoutMessagesBootstrap from './Bootstrap/BlockCheckoutMessagesBootstrap';
|
||||
import { keysToCamelCase } from '../../../ppcp-button/resources/js/modules/Helper/Utils';
|
||||
import { handleShippingOptionsChange } from '../../../ppcp-button/resources/js/modules/Helper/ShippingHandler';
|
||||
const config = wc.wcSettings.getSetting( 'ppcp-gateway_data' );
|
||||
|
||||
window.ppcpFundingSource = config.fundingSource;
|
||||
|
@ -46,36 +41,52 @@ const PayPalComponent = ({
|
|||
isEditing,
|
||||
fundingSource,
|
||||
} ) => {
|
||||
const {onPaymentSetup, onCheckoutFail, onCheckoutValidation} = eventRegistration;
|
||||
const { onPaymentSetup, onCheckoutFail, onCheckoutValidation } =
|
||||
eventRegistration;
|
||||
const { responseTypes } = emitResponse;
|
||||
|
||||
const [ paypalOrder, setPaypalOrder ] = useState( null );
|
||||
const [gotoContinuationOnError, setGotoContinuationOnError] = useState(false);
|
||||
const [ gotoContinuationOnError, setGotoContinuationOnError ] =
|
||||
useState( false );
|
||||
|
||||
const [ paypalScriptLoaded, setPaypalScriptLoaded ] = useState( false );
|
||||
|
||||
if ( ! paypalScriptLoaded ) {
|
||||
if ( ! paypalScriptPromise ) {
|
||||
// for editor, since canMakePayment was not called
|
||||
paypalScriptPromise = loadPaypalScriptPromise(config.scriptData)
|
||||
paypalScriptPromise = loadPaypalScriptPromise( config.scriptData );
|
||||
}
|
||||
paypalScriptPromise.then( () => setPaypalScriptLoaded( true ) );
|
||||
}
|
||||
|
||||
const methodId = fundingSource ? `${config.id}-${fundingSource}` : config.id;
|
||||
const methodId = fundingSource
|
||||
? `${ config.id }-${ fundingSource }`
|
||||
: config.id;
|
||||
|
||||
useEffect( () => {
|
||||
// fill the form if in continuation (for product or mini-cart buttons)
|
||||
if (!config.scriptData.continuation || !config.scriptData.continuation.order || window.ppcpContinuationFilled) {
|
||||
if (
|
||||
! config.scriptData.continuation ||
|
||||
! config.scriptData.continuation.order ||
|
||||
window.ppcpContinuationFilled
|
||||
) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const paypalAddresses = paypalOrderToWcAddresses(config.scriptData.continuation.order);
|
||||
const wcAddresses = wp.data.select('wc/store/cart').getCustomerData();
|
||||
const paypalAddresses = paypalOrderToWcAddresses(
|
||||
config.scriptData.continuation.order
|
||||
);
|
||||
const wcAddresses = wp.data
|
||||
.select( 'wc/store/cart' )
|
||||
.getCustomerData();
|
||||
const addresses = mergeWcAddress( wcAddresses, paypalAddresses );
|
||||
wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress);
|
||||
wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.setBillingAddress( addresses.billingAddress );
|
||||
if ( shippingData.needsShipping ) {
|
||||
wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress);
|
||||
wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.setShippingAddress( addresses.shippingAddress );
|
||||
}
|
||||
} catch ( err ) {
|
||||
// sometimes the PayPal address is missing, skip in this case.
|
||||
|
@ -83,7 +94,7 @@ const PayPalComponent = ({
|
|||
}
|
||||
// this useEffect should run only once, but adding this in case of some kind of full re-rendering
|
||||
window.ppcpContinuationFilled = true;
|
||||
}, [])
|
||||
}, [] );
|
||||
|
||||
const createOrder = async ( data, actions ) => {
|
||||
try {
|
||||
|
@ -94,20 +105,29 @@ const PayPalComponent = ({
|
|||
payment_method: 'ppcp-gateway',
|
||||
funding_source: window.ppcpFundingSource ?? 'paypal',
|
||||
createaccount: false,
|
||||
...(data?.paymentSource && { payment_source: data.paymentSource })
|
||||
...( data?.paymentSource && {
|
||||
payment_source: data.paymentSource,
|
||||
} ),
|
||||
};
|
||||
|
||||
const res = await fetch(config.scriptData.ajax.create_order.endpoint, {
|
||||
const res = await fetch(
|
||||
config.scriptData.ajax.create_order.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( requestBody ),
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if ( ! json.success ) {
|
||||
if ( json.data?.details?.length > 0 ) {
|
||||
throw new Error(json.data.details.map(d => `${d.issue} ${d.description}`).join('<br/>'));
|
||||
throw new Error(
|
||||
json.data.details
|
||||
.map( ( d ) => `${ d.issue } ${ d.description }` )
|
||||
.join( '<br/>' )
|
||||
);
|
||||
} else if ( json.data?.message ) {
|
||||
throw new Error( json.data.message );
|
||||
}
|
||||
|
@ -128,12 +148,17 @@ const PayPalComponent = ({
|
|||
|
||||
const createSubscription = async ( data, actions ) => {
|
||||
let planId = config.scriptData.subscription_plan_id;
|
||||
if (config.scriptData.variable_paypal_subscription_variation_from_cart !== '') {
|
||||
planId = config.scriptData.variable_paypal_subscription_variation_from_cart;
|
||||
if (
|
||||
config.scriptData
|
||||
.variable_paypal_subscription_variation_from_cart !== ''
|
||||
) {
|
||||
planId =
|
||||
config.scriptData
|
||||
.variable_paypal_subscription_variation_from_cart;
|
||||
}
|
||||
|
||||
return actions.subscription.create( {
|
||||
'plan_id': planId
|
||||
plan_id: planId,
|
||||
} );
|
||||
};
|
||||
|
||||
|
@ -142,9 +167,10 @@ const PayPalComponent = ({
|
|||
const subscription = await actions.subscription.get();
|
||||
|
||||
if ( subscription ) {
|
||||
const addresses = paypalSubscriptionToWcAddresses(subscription);
|
||||
const addresses =
|
||||
paypalSubscriptionToWcAddresses( subscription );
|
||||
|
||||
let promises = [
|
||||
const promises = [
|
||||
// save address on server
|
||||
wp.data.dispatch( 'wc/store/cart' ).updateCustomerData( {
|
||||
billing_address: addresses.billingAddress,
|
||||
|
@ -153,9 +179,17 @@ const PayPalComponent = ({
|
|||
];
|
||||
if ( shouldHandleShippingInPayPal() ) {
|
||||
// set address in UI
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress));
|
||||
promises.push(
|
||||
wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.setBillingAddress( addresses.billingAddress )
|
||||
);
|
||||
if ( shippingData.needsShipping ) {
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress))
|
||||
promises.push(
|
||||
wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.setShippingAddress( addresses.shippingAddress )
|
||||
);
|
||||
}
|
||||
}
|
||||
await Promise.all( promises );
|
||||
|
@ -163,27 +197,34 @@ const PayPalComponent = ({
|
|||
|
||||
setPaypalOrder( subscription );
|
||||
|
||||
const res = await fetch(config.scriptData.ajax.approve_subscription.endpoint, {
|
||||
const res = await fetch(
|
||||
config.scriptData.ajax.approve_subscription.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
nonce: config.scriptData.ajax.approve_subscription.nonce,
|
||||
nonce: config.scriptData.ajax.approve_subscription
|
||||
.nonce,
|
||||
order_id: data.orderID,
|
||||
subscription_id: data.subscriptionID
|
||||
})
|
||||
});
|
||||
subscription_id: data.subscriptionID,
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if ( ! json.success ) {
|
||||
if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {
|
||||
if (
|
||||
typeof actions !== 'undefined' &&
|
||||
typeof actions.restart !== 'undefined'
|
||||
) {
|
||||
return actions.restart();
|
||||
}
|
||||
if ( json.data?.message ) {
|
||||
throw new Error( json.data.message );
|
||||
}
|
||||
|
||||
throw new Error(config.scriptData.labels.error.generic)
|
||||
throw new Error( config.scriptData.labels.error.generic );
|
||||
}
|
||||
|
||||
if ( ! shouldHandleShippingInPayPal() ) {
|
||||
|
@ -207,9 +248,12 @@ const PayPalComponent = ({
|
|||
const checkoutUrl = new URL( config.scriptData.redirect );
|
||||
// sometimes some browsers may load some kind of cached version of the page,
|
||||
// so adding a parameter to avoid that
|
||||
checkoutUrl.searchParams.append('ppcp-continuation-redirect', (new Date()).getTime().toString());
|
||||
checkoutUrl.searchParams.append(
|
||||
'ppcp-continuation-redirect',
|
||||
new Date().getTime().toString()
|
||||
);
|
||||
return checkoutUrl.toString();
|
||||
}
|
||||
};
|
||||
|
||||
const handleApprove = async ( data, actions ) => {
|
||||
try {
|
||||
|
@ -218,7 +262,7 @@ const PayPalComponent = ({
|
|||
if ( order ) {
|
||||
const addresses = paypalOrderToWcAddresses( order );
|
||||
|
||||
let promises = [
|
||||
const promises = [
|
||||
// save address on server
|
||||
wp.data.dispatch( 'wc/store/cart' ).updateCustomerData( {
|
||||
billing_address: addresses.billingAddress,
|
||||
|
@ -227,9 +271,17 @@ const PayPalComponent = ({
|
|||
];
|
||||
if ( shouldHandleShippingInPayPal() ) {
|
||||
// set address in UI
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setBillingAddress(addresses.billingAddress));
|
||||
promises.push(
|
||||
wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.setBillingAddress( addresses.billingAddress )
|
||||
);
|
||||
if ( shippingData.needsShipping ) {
|
||||
promises.push(wp.data.dispatch('wc/store/cart').setShippingAddress(addresses.shippingAddress))
|
||||
promises.push(
|
||||
wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.setShippingAddress( addresses.shippingAddress )
|
||||
);
|
||||
}
|
||||
}
|
||||
await Promise.all( promises );
|
||||
|
@ -237,27 +289,33 @@ const PayPalComponent = ({
|
|||
|
||||
setPaypalOrder( order );
|
||||
|
||||
const res = await fetch(config.scriptData.ajax.approve_order.endpoint, {
|
||||
const res = await fetch(
|
||||
config.scriptData.ajax.approve_order.endpoint,
|
||||
{
|
||||
method: 'POST',
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
nonce: config.scriptData.ajax.approve_order.nonce,
|
||||
order_id: data.orderID,
|
||||
funding_source: window.ppcpFundingSource ?? 'paypal',
|
||||
})
|
||||
});
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const json = await res.json();
|
||||
|
||||
if ( ! json.success ) {
|
||||
if (typeof actions !== 'undefined' && typeof actions.restart !== 'undefined') {
|
||||
if (
|
||||
typeof actions !== 'undefined' &&
|
||||
typeof actions.restart !== 'undefined'
|
||||
) {
|
||||
return actions.restart();
|
||||
}
|
||||
if ( json.data?.message ) {
|
||||
throw new Error( json.data.message );
|
||||
}
|
||||
|
||||
throw new Error(config.scriptData.labels.error.generic)
|
||||
throw new Error( config.scriptData.labels.error.generic );
|
||||
}
|
||||
|
||||
if ( ! shouldHandleShippingInPayPal() ) {
|
||||
|
@ -282,7 +340,10 @@ const PayPalComponent = ({
|
|||
if ( config.scriptData.continuation ) {
|
||||
return true;
|
||||
}
|
||||
if (gotoContinuationOnError && wp.data.select('wc/store/validation').hasValidationErrors()) {
|
||||
if (
|
||||
gotoContinuationOnError &&
|
||||
wp.data.select( 'wc/store/validation' ).hasValidationErrors()
|
||||
) {
|
||||
location.href = getCheckoutRedirectUrl();
|
||||
return { type: responseTypes.ERROR };
|
||||
}
|
||||
|
@ -307,8 +368,11 @@ const PayPalComponent = ({
|
|||
return false;
|
||||
}
|
||||
|
||||
return window.ppcpFundingSource !== 'venmo' || !config.scriptData.vaultingEnabled;
|
||||
}
|
||||
return (
|
||||
window.ppcpFundingSource !== 'venmo' ||
|
||||
! config.scriptData.vaultingEnabled
|
||||
);
|
||||
};
|
||||
|
||||
let handleShippingOptionsChange = null;
|
||||
let handleShippingAddressChange = null;
|
||||
|
@ -320,7 +384,9 @@ const PayPalComponent = ({
|
|||
try {
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
if ( shippingOptionId ) {
|
||||
await wp.data.dispatch('wc/store/cart').selectShippingRate(shippingOptionId);
|
||||
await wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.selectShippingRate( shippingOptionId );
|
||||
await shippingData.setSelectedRates( shippingOptionId );
|
||||
}
|
||||
|
||||
|
@ -330,7 +396,7 @@ const PayPalComponent = ({
|
|||
body: JSON.stringify( {
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
} ),
|
||||
} );
|
||||
|
||||
const json = await res.json();
|
||||
|
@ -347,7 +413,9 @@ const PayPalComponent = ({
|
|||
|
||||
handleShippingAddressChange = async ( data, actions ) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
const address = paypalAddressToWc(
|
||||
convertKeysToSnakeCase( data.shippingAddress )
|
||||
);
|
||||
|
||||
await wp.data.dispatch( 'wc/store/cart' ).updateCustomerData( {
|
||||
shipping_address: address,
|
||||
|
@ -361,7 +429,7 @@ const PayPalComponent = ({
|
|||
body: JSON.stringify( {
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
} ),
|
||||
} );
|
||||
|
||||
const json = await res.json();
|
||||
|
@ -380,7 +448,9 @@ const PayPalComponent = ({
|
|||
try {
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
if ( shippingOptionId ) {
|
||||
await wp.data.dispatch('wc/store/cart').selectShippingRate(shippingOptionId);
|
||||
await wp.data
|
||||
.dispatch( 'wc/store/cart' )
|
||||
.selectShippingRate( shippingOptionId );
|
||||
await shippingData.setSelectedRates( shippingOptionId );
|
||||
}
|
||||
} catch ( e ) {
|
||||
|
@ -392,7 +462,9 @@ const PayPalComponent = ({
|
|||
|
||||
handleSubscriptionShippingAddressChange = async ( data, actions ) => {
|
||||
try {
|
||||
const address = paypalAddressToWc(convertKeysToSnakeCase(data.shippingAddress));
|
||||
const address = paypalAddressToWc(
|
||||
convertKeysToSnakeCase( data.shippingAddress )
|
||||
);
|
||||
|
||||
await wp.data.dispatch( 'wc/store/cart' ).updateCustomerData( {
|
||||
shipping_address: address,
|
||||
|
@ -406,7 +478,7 @@ const PayPalComponent = ({
|
|||
body: JSON.stringify( {
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
} ),
|
||||
} );
|
||||
|
||||
const json = await res.json();
|
||||
|
@ -414,7 +486,6 @@ const PayPalComponent = ({
|
|||
if ( ! json.success ) {
|
||||
throw new Error( json.data.message );
|
||||
}
|
||||
|
||||
} catch ( e ) {
|
||||
console.error( e );
|
||||
|
||||
|
@ -434,9 +505,11 @@ const PayPalComponent = ({
|
|||
type: responseTypes.SUCCESS,
|
||||
meta: {
|
||||
paymentMethodData: {
|
||||
'paypal_order_id': config.scriptData.continuation.order_id,
|
||||
'funding_source': window.ppcpFundingSource ?? 'paypal',
|
||||
}
|
||||
paypal_order_id:
|
||||
config.scriptData.continuation.order_id,
|
||||
funding_source:
|
||||
window.ppcpFundingSource ?? 'paypal',
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -447,8 +520,8 @@ const PayPalComponent = ({
|
|||
type: responseTypes.SUCCESS,
|
||||
meta: {
|
||||
paymentMethodData: {
|
||||
'paypal_order_id': paypalOrder.id,
|
||||
'funding_source': window.ppcpFundingSource ?? 'paypal',
|
||||
paypal_order_id: paypalOrder.id,
|
||||
funding_source: window.ppcpFundingSource ?? 'paypal',
|
||||
},
|
||||
...addresses,
|
||||
},
|
||||
|
@ -464,7 +537,7 @@ const PayPalComponent = ({
|
|||
return;
|
||||
}
|
||||
const unsubscribe = onCheckoutFail( ( { processingResponse } ) => {
|
||||
console.error(processingResponse)
|
||||
console.error( processingResponse );
|
||||
if ( onClose ) {
|
||||
onClose();
|
||||
}
|
||||
|
@ -481,31 +554,39 @@ const PayPalComponent = ({
|
|||
|
||||
if ( config.scriptData.continuation ) {
|
||||
return (
|
||||
<div dangerouslySetInnerHTML={{__html: config.scriptData.continuation.cancel.html}}>
|
||||
|
||||
</div>
|
||||
)
|
||||
<div
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: config.scriptData.continuation.cancel.html,
|
||||
} }
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! registeredContext ) {
|
||||
buttonModuleWatcher.registerContextBootstrap(config.scriptData.context, {
|
||||
buttonModuleWatcher.registerContextBootstrap(
|
||||
config.scriptData.context,
|
||||
{
|
||||
createOrder: () => {
|
||||
return createOrder();
|
||||
},
|
||||
onApprove: ( data, actions ) => {
|
||||
return handleApprove( data, actions );
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
registeredContext = true;
|
||||
}
|
||||
|
||||
const style = normalizeStyleForFundingSource(config.scriptData.button.style, fundingSource);
|
||||
const style = normalizeStyleForFundingSource(
|
||||
config.scriptData.button.style,
|
||||
fundingSource
|
||||
);
|
||||
|
||||
if ( ! paypalScriptLoaded ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const PayPalButton = paypal.Buttons.driver("react", { React, ReactDOM });
|
||||
const PayPalButton = paypal.Buttons.driver( 'react', { React, ReactDOM } );
|
||||
|
||||
const getOnShippingOptionsChange = ( fundingSource ) => {
|
||||
if ( fundingSource === 'venmo' ) {
|
||||
|
@ -517,7 +598,7 @@ const PayPalComponent = ({
|
|||
? handleShippingOptionsChange( data, actions )
|
||||
: null;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getOnShippingAddressChange = ( fundingSource ) => {
|
||||
if ( fundingSource === 'venmo' ) {
|
||||
|
@ -525,11 +606,13 @@ const PayPalComponent = ({
|
|||
}
|
||||
|
||||
return ( data, actions ) => {
|
||||
shouldHandleShippingInPayPal()
|
||||
let shippingAddressChange = shouldHandleShippingInPayPal()
|
||||
? handleShippingAddressChange( data, actions )
|
||||
: null;
|
||||
|
||||
return shippingAddressChange;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
if ( isPayPalSubscription( config.scriptData ) ) {
|
||||
return (
|
||||
|
@ -541,8 +624,12 @@ const PayPalComponent = ({
|
|||
onError={ onClose }
|
||||
createSubscription={ createSubscription }
|
||||
onApprove={ handleApproveSubscription }
|
||||
onShippingOptionsChange={getOnShippingOptionsChange(fundingSource)}
|
||||
onShippingAddressChange={getOnShippingAddressChange(fundingSource)}
|
||||
onShippingOptionsChange={ getOnShippingOptionsChange(
|
||||
fundingSource
|
||||
) }
|
||||
onShippingAddressChange={ getOnShippingAddressChange(
|
||||
fundingSource
|
||||
) }
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -556,32 +643,33 @@ const PayPalComponent = ({
|
|||
onError={ onClose }
|
||||
createOrder={ createOrder }
|
||||
onApprove={ handleApprove }
|
||||
onShippingOptionsChange={getOnShippingOptionsChange(fundingSource)}
|
||||
onShippingAddressChange={getOnShippingAddressChange(fundingSource)}
|
||||
onShippingOptionsChange={ getOnShippingOptionsChange(
|
||||
fundingSource
|
||||
) }
|
||||
onShippingAddressChange={ getOnShippingAddressChange(
|
||||
fundingSource
|
||||
) }
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const BlockEditorPayPalComponent = () => {
|
||||
|
||||
const urlParams = {
|
||||
clientId: 'test',
|
||||
...config.scriptData.url_params,
|
||||
dataNamespace: 'ppcp-blocks-editor-paypal-buttons',
|
||||
components: 'buttons',
|
||||
}
|
||||
};
|
||||
return (
|
||||
<PayPalScriptProvider
|
||||
options={urlParams}
|
||||
>
|
||||
<PayPalScriptProvider options={ urlParams }>
|
||||
<PayPalButtons
|
||||
onClick={ ( data, actions ) => {
|
||||
return false;
|
||||
} }
|
||||
/>
|
||||
</PayPalScriptProvider>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const features = [ 'products' ];
|
||||
let block_enabled = true;
|
||||
|
@ -589,26 +677,26 @@ let block_enabled = true;
|
|||
if ( cartHasSubscriptionProducts( config.scriptData ) ) {
|
||||
// Don't show buttons on block cart page if using vault v2 and user is not logged in
|
||||
if (
|
||||
! config.scriptData.user.is_logged
|
||||
&& config.scriptData.context === "cart-block"
|
||||
&& ! isPayPalSubscription(config.scriptData) // using vaulting
|
||||
&& ! config.scriptData?.save_payment_methods?.id_token // not vault v3
|
||||
! config.scriptData.user.is_logged &&
|
||||
config.scriptData.context === 'cart-block' &&
|
||||
! isPayPalSubscription( config.scriptData ) && // using vaulting
|
||||
! config.scriptData?.save_payment_methods?.id_token // not vault v3
|
||||
) {
|
||||
block_enabled = false;
|
||||
}
|
||||
|
||||
// Don't render if vaulting disabled and is in vault subscription mode
|
||||
if (
|
||||
! isPayPalSubscription(config.scriptData)
|
||||
&& ! config.scriptData.can_save_vault_token
|
||||
! isPayPalSubscription( config.scriptData ) &&
|
||||
! config.scriptData.can_save_vault_token
|
||||
) {
|
||||
block_enabled = false;
|
||||
}
|
||||
|
||||
// Don't render buttons if in subscription mode and product not associated with a PayPal subscription
|
||||
if (
|
||||
isPayPalSubscription(config.scriptData)
|
||||
&& !config.scriptData.subscription_product_allowed
|
||||
isPayPalSubscription( config.scriptData ) &&
|
||||
! config.scriptData.subscription_product_allowed
|
||||
) {
|
||||
block_enabled = false;
|
||||
}
|
||||
|
@ -617,13 +705,32 @@ if(cartHasSubscriptionProducts(config.scriptData)) {
|
|||
}
|
||||
|
||||
if ( block_enabled && config.enabled ) {
|
||||
if ((config.addPlaceOrderMethod || config.usePlaceOrder) && !config.scriptData.continuation) {
|
||||
let descriptionElement = <div dangerouslySetInnerHTML={{__html: config.description}}></div>;
|
||||
if (
|
||||
( config.addPlaceOrderMethod || config.usePlaceOrder ) &&
|
||||
! config.scriptData.continuation
|
||||
) {
|
||||
let descriptionElement = (
|
||||
<div
|
||||
dangerouslySetInnerHTML={ { __html: config.description } }
|
||||
></div>
|
||||
);
|
||||
if ( config.placeOrderButtonDescription ) {
|
||||
descriptionElement = <div>
|
||||
<p dangerouslySetInnerHTML={{__html: config.description}}></p>
|
||||
<p style={{textAlign: 'center'}} className={'ppcp-place-order-description'} dangerouslySetInnerHTML={{__html: config.placeOrderButtonDescription}}></p>
|
||||
</div>;
|
||||
descriptionElement = (
|
||||
<div>
|
||||
<p
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: config.description,
|
||||
} }
|
||||
></p>
|
||||
<p
|
||||
style={ { textAlign: 'center' } }
|
||||
className={ 'ppcp-place-order-description' }
|
||||
dangerouslySetInnerHTML={ {
|
||||
__html: config.placeOrderButtonDescription,
|
||||
} }
|
||||
></p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
registerPaymentMethod( {
|
||||
|
@ -637,7 +744,7 @@ if (block_enabled && config.enabled) {
|
|||
return config.enabled;
|
||||
},
|
||||
supports: {
|
||||
features: features,
|
||||
features,
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
@ -657,19 +764,34 @@ if (block_enabled && config.enabled) {
|
|||
},
|
||||
} );
|
||||
} else if ( ! config.usePlaceOrder ) {
|
||||
for (const fundingSource of ['paypal', ...config.enabledFundingSources]) {
|
||||
for ( const fundingSource of [
|
||||
'paypal',
|
||||
...config.enabledFundingSources,
|
||||
] ) {
|
||||
registerExpressPaymentMethod( {
|
||||
name: `${ config.id }-${ fundingSource }`,
|
||||
paymentMethodId: config.id,
|
||||
label: <div dangerouslySetInnerHTML={{__html: config.title}}/>,
|
||||
content: <PayPalComponent isEditing={false} fundingSource={fundingSource}/>,
|
||||
label: (
|
||||
<div dangerouslySetInnerHTML={ { __html: config.title } } />
|
||||
),
|
||||
content: (
|
||||
<PayPalComponent
|
||||
isEditing={ false }
|
||||
fundingSource={ fundingSource }
|
||||
/>
|
||||
),
|
||||
edit: <BlockEditorPayPalComponent />,
|
||||
ariaLabel: config.title,
|
||||
canMakePayment: async () => {
|
||||
if ( ! paypalScriptPromise ) {
|
||||
paypalScriptPromise = loadPaypalScriptPromise(config.scriptData);
|
||||
paypalScriptPromise = loadPaypalScriptPromise(
|
||||
config.scriptData
|
||||
);
|
||||
paypalScriptPromise.then( () => {
|
||||
const messagesBootstrap = new BlockCheckoutMessagesBootstrap(config.scriptData);
|
||||
const messagesBootstrap =
|
||||
new BlockCheckoutMessagesBootstrap(
|
||||
config.scriptData
|
||||
);
|
||||
messagesBootstrap.init();
|
||||
} );
|
||||
}
|
||||
|
@ -678,7 +800,7 @@ if (block_enabled && config.enabled) {
|
|||
return paypal.Buttons( { fundingSource } ).isEligible();
|
||||
},
|
||||
supports: {
|
||||
features: features,
|
||||
features,
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
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 () => {
|
||||
render(
|
||||
|
|
|
@ -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,32 +2,34 @@ 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 buttonsSpinner = new Spinner(
|
||||
document.querySelector( '.ppc-button-wrapper' )
|
||||
);
|
||||
const cardsSpinner = new Spinner( '#ppcp-hosted-fields' );
|
||||
|
||||
const bootstrap = () => {
|
||||
|
@ -37,39 +39,54 @@ 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 );
|
||||
|
||||
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 ) {
|
||||
|
@ -78,35 +95,61 @@ const bootstrap = () => {
|
|||
// 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'));
|
||||
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 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');
|
||||
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);
|
||||
label =
|
||||
PayPalCommerceGateway.labels.billing_field.replace(
|
||||
'%s',
|
||||
label
|
||||
);
|
||||
}
|
||||
if ( shippingFieldsContainer?.contains( el ) ) {
|
||||
label = PayPalCommerceGateway.labels.shipping_field.replace('%s', label);
|
||||
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 );
|
||||
} else {
|
||||
errorHandler.message(PayPalCommerceGateway.labels.error.required.generic);
|
||||
errorHandler.message(
|
||||
PayPalCommerceGateway.labels.error.required.generic
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -121,7 +164,9 @@ const bootstrap = () => {
|
|||
|
||||
const onSmartButtonClick = async ( data, actions ) => {
|
||||
window.ppcpFundingSource = data.fundingSource;
|
||||
const requiredFields = jQuery('form.woocommerce-checkout .validate-required:visible :input');
|
||||
const requiredFields = jQuery(
|
||||
'form.woocommerce-checkout .validate-required:visible :input'
|
||||
);
|
||||
requiredFields.each( ( i, input ) => {
|
||||
jQuery( input ).trigger( 'validate' );
|
||||
} );
|
||||
|
@ -136,15 +181,15 @@ const bootstrap = () => {
|
|||
form.insertAdjacentHTML(
|
||||
'beforeend',
|
||||
`<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();
|
||||
|
@ -164,47 +209,67 @@ const bootstrap = () => {
|
|||
buttonsSpinner.unblock();
|
||||
};
|
||||
|
||||
let creditCardRenderer = new HostedFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner);
|
||||
let creditCardRenderer = new HostedFieldsRenderer(
|
||||
PayPalCommerceGateway,
|
||||
errorHandler,
|
||||
spinner
|
||||
);
|
||||
if ( typeof paypal.CardFields !== 'undefined' ) {
|
||||
creditCardRenderer = new CardFieldsRenderer(PayPalCommerceGateway, errorHandler, spinner, onCardFieldsBeforeSubmit);
|
||||
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' ) {
|
||||
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' ) {
|
||||
const cartBootstrap = new CartBootstrap(
|
||||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
cartBootstrap.init();
|
||||
|
@ -216,11 +281,14 @@ const bootstrap = () => {
|
|||
PayPalCommerceGateway,
|
||||
renderer,
|
||||
spinner,
|
||||
errorHandler,
|
||||
errorHandler
|
||||
);
|
||||
|
||||
checkoutBootstap.init();
|
||||
buttonModuleWatcher.registerContextBootstrap('checkout', checkoutBootstap);
|
||||
buttonModuleWatcher.registerContextBootstrap(
|
||||
'checkout',
|
||||
checkoutBootstap
|
||||
);
|
||||
}
|
||||
|
||||
if ( context === 'pay-now' ) {
|
||||
|
@ -228,41 +296,44 @@ const bootstrap = () => {
|
|||
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 );
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
() => {
|
||||
if (!typeof (PayPalCommerceGateway)) {
|
||||
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,18 +342,26 @@ 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 ) {
|
||||
// stopped after the first rendering of the buttons, in onInit
|
||||
|
@ -296,7 +375,7 @@ document.addEventListener(
|
|||
} else {
|
||||
cardsSpinner.unblock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jQuery( document ).on( 'hosted_fields_loaded', () => {
|
||||
cardsSpinner.unblock();
|
||||
|
@ -307,24 +386,30 @@ document.addEventListener(
|
|||
|
||||
hideOrderButtonIfPpcpGateway();
|
||||
|
||||
jQuery(document.body).on('updated_checkout payment_method_selected', () => {
|
||||
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' );
|
||||
buttonsSpinner.unblock();
|
||||
cardsSpinner.unblock();
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
} );
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
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 ) {
|
||||
this.config = config;
|
||||
this.errorHandler = errorHandler;
|
||||
|
@ -13,7 +12,7 @@ class CartActionHandler {
|
|||
return {
|
||||
createSubscription: ( data, actions ) => {
|
||||
return actions.subscription.create( {
|
||||
'plan_id': subscription_plan_id
|
||||
plan_id: subscription_plan_id,
|
||||
} );
|
||||
},
|
||||
onApprove: ( data, actions ) => {
|
||||
|
@ -24,36 +23,45 @@ class CartActionHandler {
|
|||
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'
|
||||
should_create_wc_order:
|
||||
! context.config.vaultingEnabled ||
|
||||
data.paymentSource !== 'venmo',
|
||||
} ),
|
||||
} )
|
||||
}).then((res)=>{
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data) => {
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
if ( ! data.success ) {
|
||||
console.log(data)
|
||||
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 );
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
configuration() {
|
||||
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 ]
|
||||
: '';
|
||||
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( {
|
||||
|
@ -63,11 +71,13 @@ class CartActionHandler {
|
|||
funding_source: window.ppcpFundingSource,
|
||||
bn_code: bnCode,
|
||||
payer,
|
||||
context:this.config.context
|
||||
context: this.config.context,
|
||||
} ),
|
||||
}).then(function(res) {
|
||||
} )
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(function(data) {
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
if ( ! data.success ) {
|
||||
console.error( data );
|
||||
throw Error( data.data.message );
|
||||
|
@ -81,7 +91,7 @@ class CartActionHandler {
|
|||
onApprove: onApprove( this, this.errorHandler ),
|
||||
onError: ( error ) => {
|
||||
this.errorHandler.genericError();
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
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 ) {
|
||||
this.config = config;
|
||||
this.errorHandler = errorHandler;
|
||||
|
@ -22,7 +21,7 @@ class CheckoutActionHandler {
|
|||
}
|
||||
|
||||
return actions.subscription.create( {
|
||||
'plan_id': subscription_plan_id
|
||||
plan_id: subscription_plan_id,
|
||||
} );
|
||||
},
|
||||
onApprove: ( data, actions ) => {
|
||||
|
@ -32,43 +31,57 @@ class CheckoutActionHandler {
|
|||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.approve_subscription.nonce,
|
||||
order_id: data.orderID,
|
||||
subscription_id: data.subscriptionID
|
||||
subscription_id: data.subscriptionID,
|
||||
} ),
|
||||
} )
|
||||
}).then((res)=>{
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data) => {
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
document.querySelector( '#place_order' ).click();
|
||||
} );
|
||||
},
|
||||
onError: ( err ) => {
|
||||
console.error( err );
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
configuration() {
|
||||
const spinner = this.spinner;
|
||||
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, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
|
@ -81,39 +94,55 @@ class CheckoutActionHandler {
|
|||
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
|
||||
createaccount,
|
||||
save_payment_method: savePaymentMethod,
|
||||
} ),
|
||||
} )
|
||||
}).then(function (res) {
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(function (data) {
|
||||
} )
|
||||
.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')
|
||||
domParser
|
||||
.parseFromString(
|
||||
data.messages,
|
||||
'text/html'
|
||||
)
|
||||
.querySelector( 'ul' )
|
||||
);
|
||||
} else {
|
||||
errorHandler.clear();
|
||||
|
||||
if ( data.data.refresh ) {
|
||||
jQuery( document.body ).trigger( 'update_checkout' );
|
||||
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/>'));
|
||||
errorHandler.message(
|
||||
data.data.details
|
||||
.map(
|
||||
( d ) =>
|
||||
`${ d.issue } ${ d.description }`
|
||||
)
|
||||
.join( '<br/>' )
|
||||
);
|
||||
} else {
|
||||
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 };
|
||||
|
@ -125,7 +154,7 @@ class CheckoutActionHandler {
|
|||
document.querySelector( formSelector ).appendChild( input );
|
||||
return data.data.id;
|
||||
} );
|
||||
}
|
||||
};
|
||||
return {
|
||||
createOrder,
|
||||
onApprove: onApprove( this, this.errorHandler, this.spinner ),
|
||||
|
@ -141,56 +170,63 @@ class CheckoutActionHandler {
|
|||
}
|
||||
|
||||
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( {
|
||||
nonce: this.config.ajax.create_setup_token.nonce,
|
||||
})
|
||||
});
|
||||
} ),
|
||||
}
|
||||
);
|
||||
|
||||
const result = await response.json()
|
||||
const result = await response.json();
|
||||
if ( result.data.id ) {
|
||||
return result.data.id
|
||||
return result.data.id;
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
console.error( result );
|
||||
},
|
||||
onApprove: async ( { vaultSetupToken } ) => {
|
||||
const response = await fetch(this.config.ajax.create_payment_token_for_guest.endpoint, {
|
||||
method: "POST",
|
||||
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,
|
||||
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()
|
||||
document.querySelector( '#place_order' ).click();
|
||||
return;
|
||||
}
|
||||
|
||||
console.error(result)
|
||||
console.error( result );
|
||||
},
|
||||
onError: ( error ) => {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
console.error( error );
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,12 +23,13 @@ class FreeTrialHandler {
|
|||
this.errorHandler = errorHandler;
|
||||
}
|
||||
|
||||
async handle()
|
||||
{
|
||||
async handle() {
|
||||
this.spinner.block();
|
||||
|
||||
try {
|
||||
await this.formSaver.save(document.querySelector(this.formSelector));
|
||||
await this.formSaver.save(
|
||||
document.querySelector( this.formSelector )
|
||||
);
|
||||
} catch ( error ) {
|
||||
console.error( error );
|
||||
}
|
||||
|
@ -36,13 +37,17 @@ class FreeTrialHandler {
|
|||
try {
|
||||
if ( this.formValidator ) {
|
||||
try {
|
||||
const errors = await this.formValidator.validate(document.querySelector(this.formSelector));
|
||||
const errors = await this.formValidator.validate(
|
||||
document.querySelector( this.formSelector )
|
||||
);
|
||||
if ( errors.length > 0 ) {
|
||||
this.spinner.unblock();
|
||||
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;
|
||||
}
|
||||
|
@ -54,7 +59,7 @@ class FreeTrialHandler {
|
|||
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( {
|
||||
|
|
|
@ -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;
|
||||
|
@ -25,7 +19,7 @@ class SingleProductActionHandler {
|
|||
return {
|
||||
createSubscription: ( data, actions ) => {
|
||||
return actions.subscription.create( {
|
||||
'plan_id': subscription_plan
|
||||
plan_id: subscription_plan,
|
||||
} );
|
||||
},
|
||||
onApprove: ( data, actions ) => {
|
||||
|
@ -35,49 +29,51 @@ class SingleProductActionHandler {
|
|||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.approve_subscription.nonce,
|
||||
order_id: data.orderID,
|
||||
subscription_id: data.subscriptionID
|
||||
subscription_id: data.subscriptionID,
|
||||
} ),
|
||||
} )
|
||||
}).then((res)=>{
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then(() => {
|
||||
} )
|
||||
.then( () => {
|
||||
const products = this.getSubscriptionProducts();
|
||||
|
||||
fetch( this.config.ajax.change_cart.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
nonce: this.config.ajax.change_cart.nonce,
|
||||
products,
|
||||
} ),
|
||||
} )
|
||||
}).then((result) => {
|
||||
.then( ( result ) => {
|
||||
return result.json();
|
||||
}).then((result) => {
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
console.log(result)
|
||||
console.log( result );
|
||||
throw Error( result.data.message );
|
||||
}
|
||||
|
||||
location.href = this.config.redirect;
|
||||
})
|
||||
} );
|
||||
} );
|
||||
},
|
||||
onError: ( err ) => {
|
||||
console.error( err );
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
getSubscriptionProducts()
|
||||
{
|
||||
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 ),
|
||||
|
@ -99,37 +95,51 @@ class SingleProductActionHandler {
|
|||
} 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())];
|
||||
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) => {
|
||||
this.formElement
|
||||
.querySelectorAll( 'input[type="number"]' )
|
||||
.forEach( ( element ) => {
|
||||
if ( ! element.value ) {
|
||||
return;
|
||||
}
|
||||
const elementName = element.getAttribute('name').match(/quantity\[([\d]*)\]/);
|
||||
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()));
|
||||
})
|
||||
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() ) ];
|
||||
}
|
||||
}
|
||||
|
||||
extraFields() {
|
||||
return FormHelper.getFilteredFields(
|
||||
|
@ -139,23 +149,27 @@ class SingleProductActionHandler {
|
|||
);
|
||||
}
|
||||
|
||||
createOrder()
|
||||
{
|
||||
createOrder() {
|
||||
this.cartHelper = null;
|
||||
|
||||
return ( data, actions, options = {} ) => {
|
||||
this.errorHandler.clear();
|
||||
|
||||
const onResolve = ( purchase_units ) => {
|
||||
this.cartHelper = (new CartHelper()).addFromPurchaseUnits(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] : '';
|
||||
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( {
|
||||
|
@ -165,11 +179,13 @@ class SingleProductActionHandler {
|
|||
bn_code: bnCode,
|
||||
payment_method: PaymentMethods.PAYPAL,
|
||||
funding_source: window.ppcpFundingSource,
|
||||
context:this.config.context
|
||||
context: this.config.context,
|
||||
} ),
|
||||
} )
|
||||
}).then(function (res) {
|
||||
.then( function ( res ) {
|
||||
return res.json();
|
||||
}).then(function (data) {
|
||||
} )
|
||||
.then( function ( data ) {
|
||||
if ( ! data.success ) {
|
||||
console.error( data );
|
||||
throw Error( data.data.message );
|
||||
|
@ -178,45 +194,48 @@ class SingleProductActionHandler {
|
|||
} );
|
||||
};
|
||||
|
||||
return this.updateCart.update(onResolve, this.getProducts(), options.updateCartOptions || {});
|
||||
return this.updateCart.update(
|
||||
onResolve,
|
||||
this.getProducts(),
|
||||
options.updateCartOptions || {}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
variations()
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
);
|
||||
name: element.name,
|
||||
};
|
||||
} );
|
||||
}
|
||||
|
||||
hasVariations()
|
||||
{
|
||||
hasVariations() {
|
||||
return this.formElement.classList.contains( 'variations_form' );
|
||||
}
|
||||
|
||||
isGroupedProduct()
|
||||
{
|
||||
isGroupedProduct() {
|
||||
return this.formElement.classList.contains( 'grouped_form' );
|
||||
}
|
||||
|
||||
isBookingProduct()
|
||||
{
|
||||
isBookingProduct() {
|
||||
// detection for "woocommerce-bookings" plugin
|
||||
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();
|
||||
} );
|
||||
}
|
||||
|
@ -224,6 +243,5 @@ class SingleProductActionHandler {
|
|||
refreshMiniCart() {
|
||||
jQuery( document.body ).trigger( 'wc_fragment_refresh' );
|
||||
}
|
||||
|
||||
}
|
||||
export default SingleProductActionHandler;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
class ButtonModuleWatcher {
|
||||
|
||||
constructor() {
|
||||
this.contextBootstrapRegistry = {};
|
||||
this.contextBootstrapWatchers = [];
|
||||
|
@ -13,19 +11,19 @@ class ButtonModuleWatcher {
|
|||
|
||||
registerContextBootstrap( context, handler ) {
|
||||
this.contextBootstrapRegistry[ context ] = {
|
||||
context: context,
|
||||
handler: handler
|
||||
}
|
||||
context,
|
||||
handler,
|
||||
};
|
||||
|
||||
// Call registered watchers
|
||||
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,5 +1,5 @@
|
|||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import BootstrapHelper from '../Helper/BootstrapHelper';
|
||||
|
||||
class CartBootstrap {
|
||||
constructor( gateway, renderer, errorHandler ) {
|
||||
|
@ -7,9 +7,13 @@ class CartBootstrap {
|
|||
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() {
|
||||
|
@ -18,32 +22,35 @@ class CartBootstrap {
|
|||
this.handleButtonStatus();
|
||||
}
|
||||
|
||||
jQuery(document.body).on('updated_cart_totals updated_checkout', () => {
|
||||
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 => {
|
||||
} )
|
||||
.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 ) {
|
||||
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
|
||||
|
@ -59,10 +66,14 @@ class CartBootstrap {
|
|||
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 );
|
||||
|
@ -83,19 +94,26 @@ class CartBootstrap {
|
|||
|
||||
const actionHandler = new CartActionHandler(
|
||||
PayPalCommerceGateway,
|
||||
this.errorHandler,
|
||||
this.errorHandler
|
||||
);
|
||||
|
||||
if (
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
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 ) {
|
||||
this.gateway.button.is_disabled = true;
|
||||
|
@ -105,9 +123,7 @@ class CartBootstrap {
|
|||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(
|
||||
actionHandler.configuration()
|
||||
);
|
||||
this.renderer.render( actionHandler.configuration() );
|
||||
|
||||
jQuery( document.body ).trigger( 'ppcp_cart_rendered' );
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@ import CheckoutActionHandler from '../ActionHandler/CheckoutActionHandler';
|
|||
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 ) {
|
||||
|
@ -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,39 +34,48 @@ 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()
|
||||
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 => {
|
||||
} )
|
||||
.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', () => {
|
||||
this.updateUi();
|
||||
})
|
||||
} );
|
||||
} );
|
||||
|
||||
jQuery( document ).on( 'ppcp_should_show_messages', ( e, data ) => {
|
||||
|
@ -82,7 +96,11 @@ class CheckoutBootstap {
|
|||
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() {
|
||||
|
@ -93,8 +111,14 @@ class CheckoutBootstap {
|
|||
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,
|
||||
|
@ -103,14 +127,25 @@ class CheckoutBootstap {
|
|||
);
|
||||
|
||||
if (
|
||||
PayPalCommerceGateway.data_client_id.has_subscriptions
|
||||
&& PayPalCommerceGateway.data_client_id.paypal_subscriptions_enabled
|
||||
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 ) {
|
||||
this.gateway.button.is_disabled = true;
|
||||
|
@ -121,38 +156,71 @@ class CheckoutBootstap {
|
|||
}
|
||||
|
||||
if (
|
||||
PayPalCommerceGateway.is_free_trial_cart
|
||||
&& PayPalCommerceGateway.vault_v3_enabled
|
||||
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');
|
||||
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(
|
||||
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 );
|
||||
}
|
||||
|
||||
|
@ -164,14 +232,20 @@ class CheckoutBootstap {
|
|||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -180,30 +254,62 @@ class CheckoutBootstap {
|
|||
}
|
||||
|
||||
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,5 +1,5 @@
|
|||
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 ) {
|
||||
|
@ -15,29 +15,37 @@ class MessagesBootstrap {
|
|||
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 ) => {
|
||||
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) => {
|
||||
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 => {
|
||||
this.discoverBlocks().then( ( found ) => {
|
||||
if ( ! found && retries > 0 ) {
|
||||
setTimeout( () => {
|
||||
this.attemptDiscoverBlocks(retries - 1).then(resolve);
|
||||
this.attemptDiscoverBlocks( retries - 1 ).then(
|
||||
resolve
|
||||
);
|
||||
}, 2000 ); // Wait 2 seconds before retrying
|
||||
} else {
|
||||
resolve();
|
||||
|
@ -54,9 +62,11 @@ class MessagesBootstrap {
|
|||
return;
|
||||
}
|
||||
|
||||
Array.from(elements).forEach(blockElement => {
|
||||
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
|
||||
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' ) ) {
|
||||
|
@ -73,13 +83,16 @@ class MessagesBootstrap {
|
|||
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 => {
|
||||
this.renderers.forEach( ( renderer ) => {
|
||||
const shouldShow = this.shouldShow( renderer );
|
||||
setVisible( renderer.config.wrapper, shouldShow );
|
||||
if ( ! shouldShow ) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import CartActionHandler from '../ActionHandler/CartActionHandler';
|
||||
import BootstrapHelper from "../Helper/BootstrapHelper";
|
||||
import BootstrapHelper from '../Helper/BootstrapHelper';
|
||||
|
||||
class MiniCartBootstap {
|
||||
constructor( gateway, renderer, errorHandler ) {
|
||||
|
@ -10,39 +10,50 @@ 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, {
|
||||
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
|
||||
isDisabled: !! this.gateway.button.is_mini_cart_disabled,
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -51,15 +62,12 @@ class MiniCartBootstap {
|
|||
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)
|
||||
super( gateway, renderer, spinner, errorHandler );
|
||||
}
|
||||
|
||||
updateUi() {
|
||||
if ( isChangePaymentPage() ) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
super.updateUi();
|
||||
|
|
|
@ -1,29 +1,43 @@
|
|||
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 ) {
|
||||
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() {
|
||||
|
@ -31,7 +45,7 @@ class SingleProductBootstap {
|
|||
}
|
||||
|
||||
handleChange() {
|
||||
this.subscriptionButtonsLoaded = false
|
||||
this.subscriptionButtonsLoaded = false;
|
||||
|
||||
if ( ! this.shouldRender() ) {
|
||||
this.renderer.disableSmartButtons( this.gateway.button.wrapper );
|
||||
|
@ -49,7 +63,7 @@ class SingleProductBootstap {
|
|||
|
||||
handleButtonStatus( simulateCart = true ) {
|
||||
BootstrapHelper.handleButtonStatus( this, {
|
||||
formSelector: this.formSelector
|
||||
formSelector: this.formSelector,
|
||||
} );
|
||||
|
||||
if ( simulateCart ) {
|
||||
|
@ -65,15 +79,21 @@ class SingleProductBootstap {
|
|||
}
|
||||
|
||||
jQuery( document ).on( 'change', this.formSelector, () => {
|
||||
this.handleChange();
|
||||
this.debouncedHandleChange();
|
||||
} );
|
||||
this.mutationObserver.observe( form, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
} );
|
||||
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 });
|
||||
new MutationObserver(
|
||||
this.handleButtonStatus.bind( this )
|
||||
).observe( addToCartButton, { attributes: true } );
|
||||
}
|
||||
|
||||
jQuery( document ).on( 'ppcp_should_show_messages', ( e, data ) => {
|
||||
|
@ -91,37 +111,58 @@ 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 ) {
|
||||
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'));
|
||||
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' ) {
|
||||
return returnOnUndefined;
|
||||
|
@ -131,7 +172,9 @@ class SingleProductBootstap {
|
|||
return 0;
|
||||
}
|
||||
|
||||
return parseFloat(priceText.replace(/,/g, '.').replace(/([^\d,\.\s]*)/g, ''));
|
||||
return parseFloat(
|
||||
priceText.replace( /,/g, '.' ).replace( /([^\d,\.\s]*)/g, '' )
|
||||
);
|
||||
}
|
||||
|
||||
priceAmountIsZero() {
|
||||
|
@ -147,8 +190,14 @@ class SingleProductBootstap {
|
|||
|
||||
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() {
|
||||
|
@ -156,18 +205,22 @@ class SingleProductBootstap {
|
|||
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,45 +228,48 @@ 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
|
||||
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
|
||||
const subscription_plan =
|
||||
this.variations() !== null
|
||||
? getPlanIdFromVariation( this.variations() )
|
||||
: PayPalCommerceGateway.subscription_plan_id
|
||||
: 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 ),
|
||||
this.gateway.button.wrapper
|
||||
);
|
||||
|
||||
this.subscriptionButtonsLoaded = true
|
||||
this.subscriptionButtonsLoaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this.renderer.render(
|
||||
actionHandler.configuration()
|
||||
);
|
||||
this.renderer.render( actionHandler.configuration() );
|
||||
}
|
||||
|
||||
simulateCart() {
|
||||
|
@ -225,29 +281,35 @@ 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}});
|
||||
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}});
|
||||
newData = merge( newData, {
|
||||
messages: { is_hidden: data.messages.is_hidden },
|
||||
} );
|
||||
}
|
||||
if ( newData ) {
|
||||
BootstrapHelper.updateScriptData( this, newData );
|
||||
|
@ -260,27 +322,39 @@ class SingleProductBootstap {
|
|||
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)) {
|
||||
for ( const [ fundingSource, funding ] of Object.entries(
|
||||
data.funding
|
||||
) ) {
|
||||
if ( funding.enabled === true ) {
|
||||
enableFunding = strAddWord( enableFunding, fundingSource );
|
||||
disableFunding = strRemoveWord(disableFunding, fundingSource);
|
||||
disableFunding = strRemoveWord(
|
||||
disableFunding,
|
||||
fundingSource
|
||||
);
|
||||
} else if ( funding.enabled === false ) {
|
||||
enableFunding = strRemoveWord(enableFunding, fundingSource);
|
||||
disableFunding = strAddWord(disableFunding, fundingSource);
|
||||
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');
|
||||
jQuery( this.gateway.button.wrapper ).trigger(
|
||||
'ppcp-reload-buttons'
|
||||
);
|
||||
}
|
||||
|
||||
this.handleButtonStatus( false );
|
||||
|
||||
}, products );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {loadScript} from "@paypal/paypal-js";
|
||||
import { loadScript } from '@paypal/paypal-js';
|
||||
|
||||
const storageKey = 'ppcp-data-client-id';
|
||||
|
||||
|
@ -12,7 +12,7 @@ const validateToken = (token, user) => {
|
|||
const currentTime = new Date().getTime();
|
||||
const isExpired = currentTime >= token.expiration * 1000;
|
||||
return ! isExpired;
|
||||
}
|
||||
};
|
||||
|
||||
const storedTokenForUser = ( user ) => {
|
||||
const token = JSON.parse( sessionStorage.getItem( storageKey ) );
|
||||
|
@ -20,25 +20,32 @@ const storedTokenForUser = (user) => {
|
|||
return token.token;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const storeToken = ( token ) => {
|
||||
sessionStorage.setItem( storageKey, JSON.stringify( token ) );
|
||||
}
|
||||
};
|
||||
|
||||
const dataClientIdAttributeHandler = (scriptOptions, config, callback, errorCallback = null) => {
|
||||
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
|
||||
nonce: config.nonce,
|
||||
} ),
|
||||
} )
|
||||
}).then((res)=>{
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
} )
|
||||
.then( ( data ) => {
|
||||
const isValid = validateToken( data, config.user );
|
||||
if ( ! isValid ) {
|
||||
return;
|
||||
|
@ -47,16 +54,18 @@ const dataClientIdAttributeHandler = (scriptOptions, config, callback, errorCall
|
|||
|
||||
scriptOptions[ 'data-client-token' ] = data.token;
|
||||
|
||||
loadScript(scriptOptions).then((paypal) => {
|
||||
loadScript( scriptOptions )
|
||||
.then( ( paypal ) => {
|
||||
if ( typeof callback === 'function' ) {
|
||||
callback( paypal );
|
||||
}
|
||||
}).catch(err => {
|
||||
} )
|
||||
.catch( ( err ) => {
|
||||
if ( typeof errorCallback === 'function' ) {
|
||||
errorCallback( err );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
export default dataClientIdAttributeHandler;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import Product from "./Product";
|
||||
import Product from './Product';
|
||||
|
||||
class BookingProduct extends Product {
|
||||
|
||||
constructor( id, quantity, booking, extra ) {
|
||||
super( id, quantity, null, extra );
|
||||
this.booking = booking;
|
||||
|
@ -10,8 +9,8 @@ class BookingProduct extends Product {
|
|||
data() {
|
||||
return {
|
||||
...super.data(),
|
||||
booking: this.booking
|
||||
}
|
||||
booking: this.booking,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class Product {
|
||||
|
||||
constructor( id, quantity, variations, extra ) {
|
||||
this.id = id;
|
||||
this.quantity = quantity;
|
||||
|
@ -12,7 +11,7 @@ class Product {
|
|||
quantity: this.quantity,
|
||||
variations: this.variations,
|
||||
extra: this.extra,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,30 +1,26 @@
|
|||
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)
|
||||
{
|
||||
appendPreparedErrorMessageElement( errorMessageElement ) {
|
||||
this._getMessageContainer().replaceWith( errorMessageElement );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} text
|
||||
* @param {string} text
|
||||
*/
|
||||
message(text)
|
||||
{
|
||||
message( text ) {
|
||||
this._addMessage( text );
|
||||
|
||||
this._scrollToMessages();
|
||||
|
@ -33,51 +29,46 @@ 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)
|
||||
{
|
||||
_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);
|
||||
const messageNode = this._prepareMessageElement( text );
|
||||
messageContainer.appendChild( messageNode );
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_scrollToMessages()
|
||||
{
|
||||
_scrollToMessages() {
|
||||
jQuery.scroll_to_notices( jQuery( '.woocommerce-error' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_getMessageContainer()
|
||||
{
|
||||
_getMessageContainer() {
|
||||
let messageContainer = document.querySelector( 'ul.woocommerce-error' );
|
||||
if ( messageContainer === null ) {
|
||||
messageContainer = document.createElement( 'ul' );
|
||||
|
@ -89,18 +80,17 @@ class ErrorHandler {
|
|||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @private
|
||||
*/
|
||||
_prepareMessageElement(message)
|
||||
{
|
||||
_prepareMessageElement( message ) {
|
||||
const li = document.createElement( 'li' );
|
||||
li.innerHTML = message;
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
clear()
|
||||
{
|
||||
clear() {
|
||||
jQuery( '.woocommerce-error, .woocommerce-message' ).remove();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
export const apmButtonsInit = ( config, selector = '.ppcp-button-apm' ) => {
|
||||
let selectorInContainer = selector;
|
||||
|
||||
|
@ -7,10 +6,10 @@ export const apmButtonsInit = (config, selector = '.ppcp-button-apm') => {
|
|||
}
|
||||
|
||||
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-"]`;
|
||||
|
@ -19,10 +18,9 @@ export const apmButtonsInit = (config, selector = '.ppcp-button-apm') => {
|
|||
}
|
||||
|
||||
window.ppcpApmButtons = new ApmButtons( selector, selectorInContainer );
|
||||
}
|
||||
};
|
||||
|
||||
export class ApmButtons {
|
||||
|
||||
constructor( selector, selectorInContainer ) {
|
||||
this.selector = selector;
|
||||
this.selectorInContainer = selectorInContainer;
|
||||
|
@ -32,31 +30,39 @@ 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', () => {
|
||||
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 );
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 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';
|
||||
const observeSelector =
|
||||
this.selector +
|
||||
', .widget_shopping_cart, .widget_shopping_cart_content';
|
||||
|
||||
let shouldReload = false;
|
||||
for (let mutation of mutationsList) {
|
||||
for ( const mutation of mutationsList ) {
|
||||
if ( mutation.type === 'childList' ) {
|
||||
mutation.addedNodes.forEach(node => {
|
||||
mutation.addedNodes.forEach( ( node ) => {
|
||||
if ( node.matches && node.matches( observeSelector ) ) {
|
||||
shouldReload = true;
|
||||
}
|
||||
|
@ -68,12 +74,12 @@ export class ApmButtons {
|
|||
this.reloadContainers();
|
||||
this.refresh();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
reloadContainers() {
|
||||
jQuery( this.selector ).each( ( index, el ) => {
|
||||
const parent = jQuery( el ).parent();
|
||||
if (!this.containers.some($el => $el.is(parent))) {
|
||||
if ( ! this.containers.some( ( $el ) => $el.is( parent ) ) ) {
|
||||
this.containers.push( parent );
|
||||
}
|
||||
} );
|
||||
|
@ -86,7 +92,9 @@ export class ApmButtons {
|
|||
// 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' );
|
||||
|
@ -110,11 +118,12 @@ export class ApmButtons {
|
|||
|
||||
const minMargin = 11; // Minimum margin.
|
||||
const height = $el.height();
|
||||
const margin = Math.max(minMargin, Math.round(height * 0.3));
|
||||
const margin = Math.max(
|
||||
minMargin,
|
||||
Math.round( height * 0.3 )
|
||||
);
|
||||
$el.css( 'margin-top', `${ margin }px` );
|
||||
} );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
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 ) {
|
||||
options = options || {};
|
||||
options.wrapper = options.wrapper || bs.gateway.button.wrapper;
|
||||
|
@ -23,7 +22,9 @@ export default class BootstrapHelper {
|
|||
}
|
||||
|
||||
if ( wasDisabled !== ! shouldEnable ) {
|
||||
jQuery(options.wrapper).trigger('ppcp_buttons_enabled_changed', [shouldEnable]);
|
||||
jQuery( options.wrapper ).trigger( 'ppcp_buttons_enabled_changed', [
|
||||
shouldEnable,
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,19 +34,21 @@ export default class BootstrapHelper {
|
|||
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 );
|
||||
|
||||
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]);
|
||||
jQuery( document.body ).trigger( 'ppcp_script_data_changed', [
|
||||
newObj,
|
||||
] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
/**
|
||||
* @param selectorOrElement
|
||||
* @returns {Element}
|
||||
* @return {Element}
|
||||
*/
|
||||
const getElement = ( selectorOrElement ) => {
|
||||
if ( typeof selectorOrElement === 'string' ) {
|
||||
return document.querySelector( selectorOrElement );
|
||||
}
|
||||
return selectorOrElement;
|
||||
}
|
||||
};
|
||||
|
||||
const triggerEnabled = ( selectorOrElement, element ) => {
|
||||
jQuery( document ).trigger( 'ppcp-enabled', {
|
||||
'handler': 'ButtonsDisabler.setEnabled',
|
||||
'action': 'enable',
|
||||
'selector': selectorOrElement,
|
||||
'element': element
|
||||
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
|
||||
handler: 'ButtonsDisabler.setEnabled',
|
||||
action: 'disable',
|
||||
selector: selectorOrElement,
|
||||
element,
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
export const setEnabled = ( selectorOrElement, enable, form = null ) => {
|
||||
const element = getElement( selectorOrElement );
|
||||
|
@ -42,7 +42,6 @@ export const setEnabled = (selectorOrElement, enable, form = null) => {
|
|||
.css( 'pointer-events', '' );
|
||||
|
||||
triggerEnabled( selectorOrElement, element );
|
||||
|
||||
} else {
|
||||
jQuery( element )
|
||||
.addClass( 'ppcp-disabled' )
|
||||
|
@ -51,8 +50,12 @@ export const setEnabled = (selectorOrElement, enable, form = null) => {
|
|||
|
||||
if ( form ) {
|
||||
// Trigger form submit to show the error message
|
||||
let $form = jQuery(form);
|
||||
if ($form.find('.single_add_to_cart_button').hasClass('disabled')) {
|
||||
const $form = jQuery( form );
|
||||
if (
|
||||
$form
|
||||
.find( '.single_add_to_cart_button' )
|
||||
.hasClass( 'disabled' )
|
||||
) {
|
||||
$form.find( ':submit' ).trigger( 'click' );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,13 @@ export function setupButtonEvents(refresh) {
|
|||
|
||||
// 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);
|
||||
document.body.addEventListener(
|
||||
'wc_fragments_loaded',
|
||||
debouncedRefresh
|
||||
);
|
||||
document.body.addEventListener(
|
||||
'wc_fragments_refreshed',
|
||||
debouncedRefresh
|
||||
);
|
||||
}, miniCartInitDelay );
|
||||
}
|
||||
|
|
|
@ -47,4 +47,4 @@ export const cardFieldStyles = (field) => {
|
|||
} );
|
||||
|
||||
return styles;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -28,8 +29,7 @@ class CartHelper {
|
|||
return this;
|
||||
}
|
||||
|
||||
removeFromCart()
|
||||
{
|
||||
removeFromCart() {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
if ( ! this.cartItemKeys || ! this.cartItemKeys.length ) {
|
||||
resolve();
|
||||
|
@ -44,7 +44,7 @@ class CartHelper {
|
|||
if ( numResponses >= numRequests ) {
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
for ( const cartItemKey of this.cartItemKeys ) {
|
||||
const params = new URLSearchParams();
|
||||
|
@ -58,12 +58,15 @@ class CartHelper {
|
|||
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,6 +1,6 @@
|
|||
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 ) => {
|
||||
|
@ -11,38 +11,45 @@ const validateCheckoutForm = function (config) {
|
|||
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 ) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
formValidator.validate(document.querySelector(formSelector)).then((errors) => {
|
||||
formValidator
|
||||
.validate( document.querySelector( formSelector ) )
|
||||
.then( ( errors ) => {
|
||||
if ( errors.length > 0 ) {
|
||||
spinner.unblock();
|
||||
errorHandler.clear();
|
||||
errorHandler.messages( errors );
|
||||
|
||||
// fire WC event for other plugins
|
||||
jQuery( document.body ).trigger( 'checkout_error' , [ errorHandler.currentHtml() ] );
|
||||
jQuery( document.body ).trigger( 'checkout_error', [
|
||||
errorHandler.currentHtml(),
|
||||
] );
|
||||
|
||||
reject();
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
} );
|
||||
|
||||
} catch ( error ) {
|
||||
console.error( error );
|
||||
reject();
|
||||
}
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
export default validateCheckoutForm;
|
||||
|
|
|
@ -3,6 +3,7 @@ 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';
|
||||
|
|
|
@ -6,12 +6,16 @@ const dccInputFactory = (original) => {
|
|||
newElement.setAttribute( 'class', original.className );
|
||||
|
||||
Object.values( styles ).forEach( ( prop ) => {
|
||||
if (! styles[prop] || ! isNaN(prop) || prop === 'background-image' ) {
|
||||
if (
|
||||
! styles[ prop ] ||
|
||||
! isNaN( prop ) ||
|
||||
prop === 'background-image'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
newElement.style.setProperty( prop, '' + styles[ prop ] );
|
||||
} );
|
||||
return newElement;
|
||||
}
|
||||
};
|
||||
|
||||
export default dccInputFactory;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
|
||||
/**
|
||||
* Common Form utility methods
|
||||
*/
|
||||
export default class FormHelper {
|
||||
|
||||
static getPrefixedFields( formElement, prefix ) {
|
||||
const formData = new FormData( formElement );
|
||||
let fields = {};
|
||||
const fields = {};
|
||||
|
||||
for ( const [ name, value ] of formData.entries() ) {
|
||||
if ( ! prefix || name.startsWith( prefix ) ) {
|
||||
|
@ -19,11 +17,10 @@ export default class FormHelper {
|
|||
|
||||
static getFilteredFields( formElement, exactFilters, prefixFilters ) {
|
||||
const formData = new FormData( formElement );
|
||||
let fields = {};
|
||||
let counters = {};
|
||||
const fields = {};
|
||||
const counters = {};
|
||||
|
||||
for ( let [ name, value ] of formData.entries() ) {
|
||||
|
||||
// Handle array format
|
||||
if ( name.indexOf( '[]' ) !== -1 ) {
|
||||
const k = name;
|
||||
|
@ -35,10 +32,15 @@ export default class FormHelper {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ export default class FormSaver {
|
|||
const res = await fetch( this.url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
|
|
|
@ -10,7 +10,7 @@ export default class FormValidator {
|
|||
const res = await fetch( this.url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
|
|
|
@ -1,35 +1,39 @@
|
|||
/**
|
||||
* @param selectorOrElement
|
||||
* @returns {Element}
|
||||
* @return {Element}
|
||||
*/
|
||||
const getElement = ( selectorOrElement ) => {
|
||||
if ( typeof selectorOrElement === 'string' ) {
|
||||
return document.querySelector( selectorOrElement );
|
||||
}
|
||||
return selectorOrElement;
|
||||
}
|
||||
};
|
||||
|
||||
const triggerHidden = ( handler, selectorOrElement, element ) => {
|
||||
jQuery( document ).trigger( 'ppcp-hidden', {
|
||||
'handler': handler,
|
||||
'action': 'hide',
|
||||
'selector': selectorOrElement,
|
||||
'element': element
|
||||
handler,
|
||||
action: 'hide',
|
||||
selector: selectorOrElement,
|
||||
element,
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
const triggerShown = ( handler, selectorOrElement, element ) => {
|
||||
jQuery( document ).trigger( 'ppcp-shown', {
|
||||
'handler': handler,
|
||||
'action': 'show',
|
||||
'selector': selectorOrElement,
|
||||
'element': element
|
||||
handler,
|
||||
action: 'show',
|
||||
selector: selectorOrElement,
|
||||
element,
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
export const isVisible = ( element ) => {
|
||||
return !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
|
||||
}
|
||||
return !! (
|
||||
element.offsetWidth ||
|
||||
element.offsetHeight ||
|
||||
element.getClientRects().length
|
||||
);
|
||||
};
|
||||
|
||||
export const setVisible = ( selectorOrElement, show, important = false ) => {
|
||||
const element = getElement( selectorOrElement );
|
||||
|
@ -44,9 +48,12 @@ export const setVisible = (selectorOrElement, show, important = false) => {
|
|||
return;
|
||||
}
|
||||
|
||||
element.style.setProperty('display', 'none', important ? 'important' : '');
|
||||
element.style.setProperty(
|
||||
'display',
|
||||
'none',
|
||||
important ? 'important' : ''
|
||||
);
|
||||
triggerHidden( 'Hiding.setVisible', selectorOrElement, element );
|
||||
|
||||
} else {
|
||||
if ( currentValue === 'none' ) {
|
||||
element.style.removeProperty( 'display' );
|
||||
|
|
|
@ -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}
|
||||
|
@ -45,7 +44,8 @@ class MultistepCheckoutHelper {
|
|||
*/
|
||||
constructor( formSelector, triggerElementSelector = '' ) {
|
||||
this.#formSelector = formSelector;
|
||||
this.#triggerElementSelector = triggerElementSelector || DEFAULT_TRIGGER_ELEMENT_SELECTOR;
|
||||
this.#triggerElementSelector =
|
||||
triggerElementSelector || DEFAULT_TRIGGER_ELEMENT_SELECTOR;
|
||||
this.#intervalId = false;
|
||||
|
||||
/*
|
||||
|
@ -61,7 +61,7 @@ class MultistepCheckoutHelper {
|
|||
|
||||
/**
|
||||
* 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 );
|
||||
|
@ -69,7 +69,7 @@ class MultistepCheckoutHelper {
|
|||
|
||||
/**
|
||||
* 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 );
|
||||
|
@ -77,7 +77,7 @@ class MultistepCheckoutHelper {
|
|||
|
||||
/**
|
||||
* 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();
|
||||
|
@ -91,7 +91,10 @@ class MultistepCheckoutHelper {
|
|||
*/
|
||||
start() {
|
||||
this.stop();
|
||||
this.#intervalId = setInterval(() => this.checkElement(), this.#intervalTime);
|
||||
this.#intervalId = setInterval(
|
||||
() => this.checkElement(),
|
||||
this.#intervalTime
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,31 +4,56 @@ export const payerData = () => {
|
|||
return null;
|
||||
}
|
||||
|
||||
const phone = (document.querySelector('#billing_phone') || typeof payer.phone !== 'undefined') ?
|
||||
{
|
||||
phone_type:"HOME",
|
||||
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
|
||||
national_number: document.querySelector(
|
||||
'#billing_phone'
|
||||
)
|
||||
? document.querySelector( '#billing_phone' ).value
|
||||
: payer.phone.phone_number.national_number,
|
||||
},
|
||||
}
|
||||
} : null;
|
||||
: null;
|
||||
const payerData = {
|
||||
email_address:(document.querySelector('#billing_email')) ? document.querySelector('#billing_email').value : payer.email_address,
|
||||
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
|
||||
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
|
||||
}
|
||||
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 ) {
|
||||
payerData.phone = phone;
|
||||
}
|
||||
return payerData;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
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 ) => {
|
||||
// If PayPal is already loaded call the onLoaded callback and return.
|
||||
|
@ -36,7 +36,7 @@ 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 ) => {
|
||||
|
@ -47,14 +47,14 @@ export const loadPaypalScript = (config, onLoaded, onError = null) => {
|
|||
}
|
||||
|
||||
resetState();
|
||||
}
|
||||
};
|
||||
const errorCallback = ( err ) => {
|
||||
for ( const onErrorCallback of options.onErrorCallbacks ) {
|
||||
onErrorCallback( err );
|
||||
}
|
||||
|
||||
resetState();
|
||||
}
|
||||
};
|
||||
|
||||
// Build the PayPal script options.
|
||||
let scriptOptions = keysToCamelCase( config.url_params );
|
||||
|
@ -72,7 +72,12 @@ export const loadPaypalScript = (config, onLoaded, onError = null) => {
|
|||
|
||||
// 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);
|
||||
dataClientIdAttributeHandler(
|
||||
scriptOptions,
|
||||
config.data_client_id,
|
||||
callback,
|
||||
errorCallback
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -83,27 +88,23 @@ export const loadPaypalScript = (config, onLoaded, onError = null) => {
|
|||
}
|
||||
|
||||
// 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)
|
||||
loadPaypalScript( config, resolve, reject );
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
export const loadPaypalJsScript = ( options, buttons, container ) => {
|
||||
loadScript( options ).then( ( paypal ) => {
|
||||
paypal.Buttons( buttons ).render( container );
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
export const loadPaypalJsScriptPromise = ( options ) => {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
loadScript(options)
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
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,36 +7,41 @@ 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 ) => {
|
||||
try {
|
||||
const shippingOptionId = data.selectedShippingOption?.id;
|
||||
|
||||
if ( shippingOptionId ) {
|
||||
await fetch(config.ajax.update_customer_shipping.shipping_options.endpoint, {
|
||||
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( {
|
||||
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 ) {
|
||||
method.checked = true;
|
||||
}
|
||||
} );
|
||||
})
|
||||
} );
|
||||
}
|
||||
|
||||
if ( ! config.data_client_id.has_subscriptions ) {
|
||||
|
@ -46,7 +51,7 @@ export const handleShippingOptionsChange = async (data, actions, config) => {
|
|||
body: JSON.stringify( {
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
} ),
|
||||
} );
|
||||
|
||||
const json = await res.json();
|
||||
|
@ -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 ) => {
|
||||
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,22 +98,36 @@ 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( {
|
||||
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, {
|
||||
method: 'POST',
|
||||
|
@ -112,7 +135,7 @@ export const handleShippingAddressChange = async (data, actions, config) => {
|
|||
body: JSON.stringify( {
|
||||
nonce: config.ajax.update_shipping.nonce,
|
||||
order_id: data.orderID,
|
||||
})
|
||||
} ),
|
||||
} );
|
||||
|
||||
const json = await res.json();
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
class SimulateCart {
|
||||
|
||||
constructor(endpoint, nonce)
|
||||
{
|
||||
constructor( endpoint, nonce ) {
|
||||
this.endpoint = endpoint;
|
||||
this.nonce = nonce;
|
||||
}
|
||||
|
@ -10,29 +8,25 @@ class SimulateCart {
|
|||
*
|
||||
* @param onResolve
|
||||
* @param {Product[]} products
|
||||
* @returns {Promise<unknown>}
|
||||
* @return {Promise<unknown>}
|
||||
*/
|
||||
simulate(onResolve, products)
|
||||
{
|
||||
simulate( onResolve, products ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fetch(
|
||||
this.endpoint,
|
||||
{
|
||||
fetch( this.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
nonce: this.nonce,
|
||||
products,
|
||||
} ),
|
||||
} )
|
||||
}
|
||||
).then(
|
||||
(result) => {
|
||||
.then( ( result ) => {
|
||||
return result.json();
|
||||
}
|
||||
).then((result) => {
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
reject( result.data );
|
||||
return;
|
||||
|
@ -40,7 +34,7 @@ class SimulateCart {
|
|||
|
||||
const resolved = onResolve( result.data );
|
||||
resolve( resolved );
|
||||
})
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
class Spinner {
|
||||
|
||||
constructor( target = 'form.woocommerce-checkout' ) {
|
||||
this.target = target;
|
||||
}
|
||||
|
@ -9,18 +8,16 @@ class Spinner {
|
|||
}
|
||||
|
||||
block() {
|
||||
|
||||
jQuery( this.target ).block( {
|
||||
message: null,
|
||||
overlayCSS: {
|
||||
background: '#fff',
|
||||
opacity: 0.6
|
||||
}
|
||||
opacity: 0.6,
|
||||
},
|
||||
} );
|
||||
}
|
||||
|
||||
unblock() {
|
||||
|
||||
jQuery( this.target ).unblock();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export const normalizeStyleForFundingSource = ( style, fundingSource ) => {
|
||||
const commonProps = {};
|
||||
['shape', 'height'].forEach(prop => {
|
||||
[ 'shape', 'height' ].forEach( ( prop ) => {
|
||||
if ( style[ prop ] ) {
|
||||
commonProps[ prop ] = style[ prop ];
|
||||
}
|
||||
|
@ -12,9 +12,9 @@ export const normalizeStyleForFundingSource = (style, fundingSource) => {
|
|||
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)
|
||||
const urlParams = new URLSearchParams( window.location.search );
|
||||
return urlParams.has( 'change_payment_method' );
|
||||
}
|
||||
};
|
||||
|
||||
export const getPlanIdFromVariation = ( variation ) => {
|
||||
let subscription_plan = '';
|
||||
PayPalCommerceGateway.variable_paypal_subscription_variations.forEach((element) => {
|
||||
let obj = {};
|
||||
PayPalCommerceGateway.variable_paypal_subscription_variations.forEach(
|
||||
( element ) => {
|
||||
const obj = {};
|
||||
variation.forEach( ( { name, value } ) => {
|
||||
Object.assign(obj, {[name.replace('attribute_', '')]: value});
|
||||
})
|
||||
|
||||
if(JSON.stringify(obj) === JSON.stringify(element.attributes) && element.subscription_plan !== '') {
|
||||
subscription_plan = element.subscription_plan;
|
||||
}
|
||||
Object.assign( obj, {
|
||||
[ name.replace( 'attribute_', '' ) ]: value,
|
||||
} );
|
||||
} );
|
||||
|
||||
return 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,30 +10,26 @@ class UpdateCart {
|
|||
* @param onResolve
|
||||
* @param {Product[]} products
|
||||
* @param {Object} options
|
||||
* @returns {Promise<unknown>}
|
||||
* @return {Promise<unknown>}
|
||||
*/
|
||||
update(onResolve, products, options = {})
|
||||
{
|
||||
update( onResolve, products, options = {} ) {
|
||||
return new Promise( ( resolve, reject ) => {
|
||||
fetch(
|
||||
this.endpoint,
|
||||
{
|
||||
fetch( this.endpoint, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
credentials: 'same-origin',
|
||||
body: JSON.stringify( {
|
||||
nonce: this.nonce,
|
||||
products,
|
||||
...options
|
||||
...options,
|
||||
} ),
|
||||
} )
|
||||
}
|
||||
).then(
|
||||
(result) => {
|
||||
.then( ( result ) => {
|
||||
return result.json();
|
||||
}
|
||||
).then((result) => {
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
if ( ! result.success ) {
|
||||
reject( result.data );
|
||||
return;
|
||||
|
@ -43,7 +37,7 @@ class UpdateCart {
|
|||
|
||||
const resolved = onResolve( result.data );
|
||||
resolve( resolved );
|
||||
})
|
||||
} );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,20 +2,20 @@ export const toCamelCase = (str) => {
|
|||
return str.replace( /([-_]\w)/g, function ( match ) {
|
||||
return match[ 1 ].toUpperCase();
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
export const keysToCamelCase = ( obj ) => {
|
||||
let output = {};
|
||||
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);
|
||||
const arr = str.split( separator );
|
||||
if ( ! arr.includes( word ) ) {
|
||||
arr.push( word );
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ export const strAddWord = (str, word, separator = ',') => {
|
|||
};
|
||||
|
||||
export const strRemoveWord = ( str, word, separator = ',' ) => {
|
||||
let arr = str.split(separator);
|
||||
let index = arr.indexOf(word);
|
||||
const arr = str.split( separator );
|
||||
const index = arr.indexOf( word );
|
||||
if ( index !== -1 ) {
|
||||
arr.splice( index, 1 );
|
||||
}
|
||||
|
@ -56,14 +56,14 @@ export const throttle = (func, limit) => {
|
|||
lastContext = this;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const Utils = {
|
||||
toCamelCase,
|
||||
keysToCamelCase,
|
||||
strAddWord,
|
||||
strRemoveWord,
|
||||
throttle
|
||||
throttle,
|
||||
};
|
||||
|
||||
export default Utils;
|
||||
|
|
|
@ -3,32 +3,36 @@ const onApprove = (context, errorHandler) => {
|
|||
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( {
|
||||
nonce: context.config.ajax.approve_order.nonce,
|
||||
order_id: data.orderID,
|
||||
funding_source: window.ppcpFundingSource,
|
||||
should_create_wc_order: !context.config.vaultingEnabled || data.paymentSource !== 'venmo'
|
||||
should_create_wc_order:
|
||||
! context.config.vaultingEnabled ||
|
||||
data.paymentSource !== 'venmo',
|
||||
} ),
|
||||
} )
|
||||
}).then((res)=>{
|
||||
.then( ( res ) => {
|
||||
return res.json();
|
||||
}).then((data)=>{
|
||||
} )
|
||||
.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
|
||||
|
||||
location.href = orderReceivedUrl ? orderReceivedUrl : context.config.redirect;
|
||||
const orderReceivedUrl = data.data?.order_received_url;
|
||||
|
||||
location.href = orderReceivedUrl
|
||||
? orderReceivedUrl
|
||||
: context.config.redirect;
|
||||
} );
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default onApprove;
|
||||
|
|
|
@ -6,17 +6,19 @@ const onApprove = (context, errorHandler, spinner) => {
|
|||
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( {
|
||||
nonce: context.config.ajax.approve_order.nonce,
|
||||
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 ) {
|
||||
|
@ -24,15 +26,17 @@ const onApprove = (context, errorHandler, spinner) => {
|
|||
} 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 );
|
||||
}
|
||||
document.querySelector('#place_order').click()
|
||||
document.querySelector( '#place_order' ).click();
|
||||
} );
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default onApprove;
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
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;
|
||||
|
@ -16,21 +20,21 @@ class CardFieldsRenderer {
|
|||
|
||||
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');
|
||||
const gateWayBox = document.querySelector(
|
||||
'.payment_box.payment_method_ppcp-credit-card-gateway'
|
||||
);
|
||||
if ( ! gateWayBox ) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const oldDisplayStyle = gateWayBox.style.display;
|
||||
|
@ -43,69 +47,89 @@ class CardFieldsRenderer {
|
|||
|
||||
const cardField = paypal.CardFields( {
|
||||
createOrder: contextConfig.createOrder,
|
||||
onApprove: function (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');
|
||||
const nameField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-name'
|
||||
);
|
||||
if ( nameField ) {
|
||||
let styles = cardFieldStyles(nameField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
}
|
||||
const styles = cardFieldStyles( nameField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( nameField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder = 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');
|
||||
const numberField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-number'
|
||||
);
|
||||
if ( numberField ) {
|
||||
let styles = cardFieldStyles(numberField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
}
|
||||
const styles = cardFieldStyles( numberField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( numberField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder = 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');
|
||||
const expiryField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-expiry'
|
||||
);
|
||||
if ( expiryField ) {
|
||||
let styles = cardFieldStyles(expiryField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
}
|
||||
const styles = cardFieldStyles( expiryField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( expiryField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder = 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');
|
||||
const cvvField = document.getElementById(
|
||||
'ppcp-credit-card-gateway-card-cvc'
|
||||
);
|
||||
if ( cvvField ) {
|
||||
let styles = cardFieldStyles(cvvField);
|
||||
let fieldOptions = {
|
||||
style: { 'input': styles }
|
||||
}
|
||||
const styles = cardFieldStyles( cvvField );
|
||||
const fieldOptions = {
|
||||
style: { input: styles },
|
||||
};
|
||||
if ( cvvField.getAttribute( 'placeholder' ) ) {
|
||||
fieldOptions.placeholder = 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;
|
||||
|
@ -113,34 +137,44 @@ class CardFieldsRenderer {
|
|||
show( buttonSelector );
|
||||
|
||||
if ( this.defaultConfig.cart_contains_subscription ) {
|
||||
const saveToAccount = document.querySelector('#wc-ppcp-credit-card-gateway-new-payment-method');
|
||||
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
|
||||
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
|
||||
);
|
||||
} );
|
||||
} );
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
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 ) {
|
||||
this.defaultConfig = defaultConfig;
|
||||
this.errorHandler = errorHandler;
|
||||
|
@ -15,28 +14,36 @@ class HostedFieldsRenderer {
|
|||
|
||||
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}`));
|
||||
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');
|
||||
const gateWayBox = document.querySelector(
|
||||
'.payment_box.payment_method_ppcp-credit-card-gateway'
|
||||
);
|
||||
if ( ! gateWayBox ) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
const oldDisplayStyle = gateWayBox.style.display;
|
||||
gateWayBox.style.display = 'block';
|
||||
|
@ -46,10 +53,12 @@ class HostedFieldsRenderer {
|
|||
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 = {};
|
||||
const styles = {};
|
||||
Object.values( stylesRaw ).forEach( ( prop ) => {
|
||||
if ( ! stylesRaw[ prop ] ) {
|
||||
return;
|
||||
|
@ -58,47 +67,70 @@ class HostedFieldsRenderer {
|
|||
} );
|
||||
|
||||
const cardNumber = dccInputFactory( cardNumberField );
|
||||
cardNumberField.parentNode.replaceChild(cardNumber, cardNumberField);
|
||||
cardNumberField.parentNode.replaceChild(
|
||||
cardNumber,
|
||||
cardNumberField
|
||||
);
|
||||
|
||||
const cardExpiryField = document.querySelector('#ppcp-credit-card-gateway-card-expiry');
|
||||
const cardExpiryField = document.querySelector(
|
||||
'#ppcp-credit-card-gateway-card-expiry'
|
||||
);
|
||||
const cardExpiry = dccInputFactory( cardExpiryField );
|
||||
cardExpiryField.parentNode.replaceChild(cardExpiry, cardExpiryField);
|
||||
cardExpiryField.parentNode.replaceChild(
|
||||
cardExpiry,
|
||||
cardExpiryField
|
||||
);
|
||||
|
||||
const cardCodeField = document.querySelector('#ppcp-credit-card-gateway-card-cvc');
|
||||
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( {
|
||||
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', () => {
|
||||
|
@ -109,22 +141,34 @@ class HostedFieldsRenderer {
|
|||
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);
|
||||
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( '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._recreateElementClassAttribute(
|
||||
cardNumber,
|
||||
cardNumberField.className
|
||||
);
|
||||
this.emptyFields.add( event.emittedBy );
|
||||
} );
|
||||
hostedFields.on( 'notEmpty', ( event ) => {
|
||||
|
@ -133,25 +177,33 @@ class HostedFieldsRenderer {
|
|||
|
||||
show( buttonSelector );
|
||||
|
||||
if (document.querySelector(wrapper).getAttribute('data-ppcp-subscribed') !== true) {
|
||||
document.querySelector(buttonSelector).addEventListener(
|
||||
'click',
|
||||
event => {
|
||||
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( 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();
|
||||
}
|
||||
document
|
||||
.querySelector( '#payment_method_ppcp-credit-card-gateway' )
|
||||
.addEventListener( 'click', () => {
|
||||
document
|
||||
.querySelector(
|
||||
'label[for=ppcp-credit-card-gateway-card-number]'
|
||||
)
|
||||
.click();
|
||||
} );
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -164,16 +216,16 @@ class HostedFieldsRenderer {
|
|||
if ( this.currentHostedFieldsInstance ) {
|
||||
this.currentHostedFieldsInstance.setAttribute( {
|
||||
field: 'number',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.setAttribute( {
|
||||
field: 'cvv',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.setAttribute( {
|
||||
field: 'expirationDate',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -181,16 +233,16 @@ class HostedFieldsRenderer {
|
|||
if ( this.currentHostedFieldsInstance ) {
|
||||
this.currentHostedFieldsInstance.removeAttribute( {
|
||||
field: 'number',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.removeAttribute( {
|
||||
field: 'cvv',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
this.currentHostedFieldsInstance.removeAttribute( {
|
||||
field: 'expirationDate',
|
||||
attribute: 'disabled'
|
||||
})
|
||||
attribute: 'disabled',
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,42 +251,69 @@ class HostedFieldsRenderer {
|
|||
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;
|
||||
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 ( this.defaultConfig.payer ) {
|
||||
hostedFieldsData.cardholderName = this.defaultConfig.payer.name.given_name + ' ' + this.defaultConfig.payer.name.surname;
|
||||
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 : '';
|
||||
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 => {
|
||||
} )
|
||||
.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/>'));
|
||||
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/>'));
|
||||
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 ) {
|
||||
|
@ -252,9 +331,11 @@ class HostedFieldsRenderer {
|
|||
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;
|
||||
message =
|
||||
this.defaultConfig.hosted_fields.labels.card_not_supported;
|
||||
} else if ( ! this.formValid ) {
|
||||
message = this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
||||
message =
|
||||
this.defaultConfig.hosted_fields.labels.fields_not_valid;
|
||||
}
|
||||
|
||||
this.errorHandler.message( message );
|
||||
|
@ -262,11 +343,13 @@ class HostedFieldsRenderer {
|
|||
}
|
||||
|
||||
_cardNumberFiledCLassNameByCardType( cardType ) {
|
||||
return cardType === 'american-express' ? 'amex' : cardType.replace('-', '');
|
||||
return cardType === 'american-express'
|
||||
? 'amex'
|
||||
: cardType.replace( '-', '' );
|
||||
}
|
||||
|
||||
_recreateElementClassAttribute( element, newClassName ) {
|
||||
element.removeAttribute('class')
|
||||
element.removeAttribute( 'class' );
|
||||
element.setAttribute( 'class', newClassName );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import widgetBuilder from "./WidgetBuilder";
|
||||
import widgetBuilder from './WidgetBuilder';
|
||||
|
||||
class MessageRenderer {
|
||||
|
||||
constructor( config ) {
|
||||
this.config = config;
|
||||
this.optionsFingerprint = null;
|
||||
|
@ -24,7 +23,12 @@ class MessageRenderer {
|
|||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -52,8 +56,11 @@ 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 ) ) {
|
||||
|
|
|
@ -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 = {};
|
||||
|
@ -43,6 +40,7 @@ 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 ) {
|
||||
|
@ -53,6 +51,7 @@ class PreviewButton {
|
|||
/**
|
||||
* Sets server-side configuration for the button.
|
||||
*
|
||||
* @param config
|
||||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
setButtonConfig( config ) {
|
||||
|
@ -65,6 +64,7 @@ class PreviewButton {
|
|||
/**
|
||||
* Updates the button configuration with current details from the form.
|
||||
*
|
||||
* @param config
|
||||
* @return {this} Reference to self, for chaining.
|
||||
*/
|
||||
setPpcpConfig( config ) {
|
||||
|
@ -76,6 +76,8 @@ 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 ) {
|
||||
// Implement in derived class.
|
||||
|
@ -84,9 +86,12 @@ class PreviewButton {
|
|||
/**
|
||||
* 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');
|
||||
throw new Error(
|
||||
'The "createButton" method must be implemented by the derived class'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,7 +117,9 @@ class PreviewButton {
|
|||
|
||||
this.isVisible = true;
|
||||
const previewButtonConfig = merge( {}, this.buttonConfig );
|
||||
const previewPpcpConfig = this.isDynamic ? merge({}, this.ppcpConfig) : {};
|
||||
const previewPpcpConfig = this.isDynamic
|
||||
? merge( {}, this.ppcpConfig )
|
||||
: {};
|
||||
previewButtonConfig.button.wrapper = this.selector;
|
||||
|
||||
this.dynamicPreviewConfig( previewButtonConfig, previewPpcpConfig );
|
||||
|
@ -121,11 +128,16 @@ class PreviewButton {
|
|||
* 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 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}"`);
|
||||
throw new Error(
|
||||
`[APM Preview Button] Infinite loop detected. Provide different selectors for the button/ppcp wrapper elements! Selector: "#${ buttonWrapper }"`
|
||||
);
|
||||
}
|
||||
|
||||
this.createButton( previewButtonConfig );
|
||||
|
|
|
@ -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,7 +32,7 @@ class PreviewButtonManager {
|
|||
this.apiConfig = null;
|
||||
this.apiError = '';
|
||||
|
||||
this.#onInit = new Promise(resolve => {
|
||||
this.#onInit = new Promise( ( resolve ) => {
|
||||
this.#onInitResolver = resolve;
|
||||
} );
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -66,7 +65,9 @@ class PreviewButtonManager {
|
|||
* @return {Promise<{}>}
|
||||
*/
|
||||
async fetchConfig( payPal ) {
|
||||
throw new Error('The "fetchConfig" method must be implemented by the derived class');
|
||||
throw new Error(
|
||||
'The "fetchConfig" method must be implemented by the derived class'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,7 +78,9 @@ class PreviewButtonManager {
|
|||
* @return {PreviewButton}
|
||||
*/
|
||||
createButtonInstance( wrapperId ) {
|
||||
throw new Error('The "createButtonInstance" method must be implemented by the derived class');
|
||||
throw new Error(
|
||||
'The "createButtonInstance" method must be implemented by the derived class'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,7 +96,9 @@ class PreviewButtonManager {
|
|||
createDummy( wrapperId ) {
|
||||
const elButton = document.createElement( 'div' );
|
||||
elButton.classList.add( 'ppcp-button-apm', 'ppcp-button-dummy' );
|
||||
elButton.innerHTML = `<span>${this.apiError ?? 'Not Available'}</span>`;
|
||||
elButton.innerHTML = `<span>${
|
||||
this.apiError ?? 'Not Available'
|
||||
}</span>`;
|
||||
|
||||
document.querySelector( wrapperId ).appendChild( elButton );
|
||||
|
||||
|
@ -111,14 +116,22 @@ class PreviewButtonManager {
|
|||
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 );
|
||||
|
@ -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 }"]`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -153,14 +168,17 @@ class PreviewButtonManager {
|
|||
// not loaded.
|
||||
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');
|
||||
success
|
||||
? resolve()
|
||||
: reject( 'Timeout while waiting for widgetBuilder.paypal' );
|
||||
};
|
||||
|
||||
// Wait for the PayPal SDK to be ready.
|
||||
|
@ -178,14 +196,19 @@ class PreviewButtonManager {
|
|||
} );
|
||||
|
||||
// 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:
|
||||
|
@ -243,11 +266,13 @@ class PreviewButtonManager {
|
|||
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 ]
|
||||
|
@ -258,6 +283,7 @@ class PreviewButtonManager {
|
|||
|
||||
/**
|
||||
* Apples the provided configuration to all existing preview buttons.
|
||||
* @param ppcpConfig
|
||||
*/
|
||||
_configureAllButtons( ppcpConfig ) {
|
||||
Object.entries( this.buttons ).forEach( ( [ id, button ] ) => {
|
||||
|
@ -276,13 +302,17 @@ class PreviewButtonManager {
|
|||
|
||||
/**
|
||||
* Creates a new preview button, that is rendered once the bootstrapping Promise resolves.
|
||||
* @param id
|
||||
* @param ppcpConfig
|
||||
*/
|
||||
_addButton( id, ppcpConfig ) {
|
||||
const createButton = () => {
|
||||
if ( ! this.buttons[ id ] ) {
|
||||
let newInst;
|
||||
if ( this.apiConfig && 'object' === typeof this.apiConfig ) {
|
||||
newInst = this.createButtonInstance(id).setButtonConfig(this.buttonConfig);
|
||||
newInst = this.createButtonInstance( id ).setButtonConfig(
|
||||
this.buttonConfig
|
||||
);
|
||||
} else {
|
||||
newInst = this.createDummy( id );
|
||||
}
|
||||
|
@ -307,9 +337,13 @@ class PreviewButtonManager {
|
|||
*/
|
||||
renderButtons() {
|
||||
if ( this.isEnabled ) {
|
||||
Object.values(this.buttons).forEach(button => button.render());
|
||||
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;
|
||||
|
|
|
@ -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,13 +28,20 @@ class Renderer {
|
|||
this.reloadEventName = 'ppcp-reload-buttons';
|
||||
}
|
||||
|
||||
render(contextConfig, settingsOverride = {}, contextConfigOverride = () => {}) {
|
||||
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 ) {
|
||||
this.renderButtons(
|
||||
|
@ -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,
|
||||
|
@ -54,10 +71,15 @@ class Renderer {
|
|||
}
|
||||
|
||||
if ( this.creditCardRenderer ) {
|
||||
this.creditCardRenderer.render(settings.hosted_fields.wrapper, contextConfigOverride);
|
||||
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,8 +90,21 @@ 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 ] );
|
||||
return;
|
||||
|
@ -106,15 +141,33 @@ class Renderer {
|
|||
// 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)
|
||||
let shippingOptionsChange =
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingOptionsChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
return shippingOptionsChange
|
||||
};
|
||||
options.onShippingAddressChange = ( data, actions ) => {
|
||||
!this.isVenmoButtonClickedWhenVaultingIsEnabled(venmoButtonClicked)
|
||||
? handleShippingAddressChange(data, actions, this.defaultSettings)
|
||||
let shippingAddressChange =
|
||||
! this.isVenmoButtonClickedWhenVaultingIsEnabled(
|
||||
venmoButtonClicked
|
||||
)
|
||||
? handleShippingAddressChange(
|
||||
data,
|
||||
actions,
|
||||
this.defaultSettings
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
return shippingAddressChange
|
||||
};
|
||||
}
|
||||
|
||||
return options;
|
||||
|
@ -122,35 +175,57 @@ class Renderer {
|
|||
|
||||
jQuery( document )
|
||||
.off( this.reloadEventName, wrapper )
|
||||
.on(this.reloadEventName, wrapper, (event, settingsOverride = {}, triggeredFundingSource) => {
|
||||
|
||||
.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);
|
||||
const settings = merge(
|
||||
this.defaultSettings,
|
||||
settingsOverride
|
||||
);
|
||||
let scriptOptions = keysToCamelCase( settings.url_params );
|
||||
scriptOptions = merge(scriptOptions, settings.script_attributes);
|
||||
scriptOptions = merge(
|
||||
scriptOptions,
|
||||
settings.script_attributes
|
||||
);
|
||||
|
||||
loadScript( scriptOptions ).then( ( paypal ) => {
|
||||
widgetBuilder.setPaypal( paypal );
|
||||
widgetBuilder.registerButtons([wrapper, fundingSource], buttonsOptions());
|
||||
widgetBuilder.registerButtons(
|
||||
[ wrapper, fundingSource ],
|
||||
buttonsOptions()
|
||||
);
|
||||
widgetBuilder.renderAll();
|
||||
} );
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
this.renderedSources.add( wrapper + ( fundingSource ?? '' ) );
|
||||
|
||||
if (typeof paypal !== 'undefined' && typeof paypal.Buttons !== 'undefined') {
|
||||
widgetBuilder.registerButtons([wrapper, fundingSource], buttonsOptions());
|
||||
if (
|
||||
typeof paypal !== 'undefined' &&
|
||||
typeof paypal.Buttons !== 'undefined'
|
||||
) {
|
||||
widgetBuilder.registerButtons(
|
||||
[ wrapper, fundingSource ],
|
||||
buttonsOptions()
|
||||
);
|
||||
widgetBuilder.renderButtons( [ wrapper, fundingSource ] );
|
||||
}
|
||||
}
|
||||
|
||||
isVenmoButtonClickedWhenVaultingIsEnabled = ( venmoButtonClicked ) => {
|
||||
return venmoButtonClicked && this.defaultSettings.vaultingEnabled;
|
||||
}
|
||||
};
|
||||
|
||||
isAlreadyRendered( wrapper, fundingSource ) {
|
||||
return this.renderedSources.has( wrapper + ( fundingSource ?? '' ) );
|
||||
|
@ -165,23 +240,24 @@ class Renderer {
|
|||
}
|
||||
|
||||
onButtonsInit( wrapper, handler, reset ) {
|
||||
this.onButtonsInitListeners[wrapper] = reset ? [] : (this.onButtonsInitListeners[wrapper] || []);
|
||||
this.onButtonsInitListeners[ wrapper ] = reset
|
||||
? []
|
||||
: this.onButtonsInitListeners[ wrapper ] || [];
|
||||
this.onButtonsInitListeners[ wrapper ].push( handler );
|
||||
}
|
||||
|
||||
handleOnButtonsInit( wrapper, data, actions ) {
|
||||
|
||||
this.buttonsOptions[ wrapper ] = {
|
||||
data: data,
|
||||
actions: actions
|
||||
}
|
||||
data,
|
||||
actions,
|
||||
};
|
||||
|
||||
if ( this.onButtonsInitListeners[ wrapper ] ) {
|
||||
for (let handler of this.onButtonsInitListeners[wrapper]) {
|
||||
for ( const handler of this.onButtonsInitListeners[ wrapper ] ) {
|
||||
if ( typeof handler === 'function' ) {
|
||||
handler( {
|
||||
wrapper: wrapper,
|
||||
...this.buttonsOptions[wrapper]
|
||||
wrapper,
|
||||
...this.buttonsOptions[ wrapper ],
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
@ -16,7 +15,7 @@ class WidgetBuilder {
|
|||
buttons: this.buttons,
|
||||
messages: this.messages,
|
||||
} );
|
||||
}
|
||||
};
|
||||
|
||||
jQuery( document )
|
||||
.off( this.renderEventName )
|
||||
|
@ -34,8 +33,8 @@ class WidgetBuilder {
|
|||
wrapper = this.sanitizeWrapper( wrapper );
|
||||
|
||||
this.buttons.set( this.toKey( wrapper ), {
|
||||
wrapper: wrapper,
|
||||
options: options,
|
||||
wrapper,
|
||||
options,
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -58,7 +57,7 @@ class WidgetBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
let target = this.buildWrapperTarget(wrapper);
|
||||
const target = this.buildWrapperTarget( wrapper );
|
||||
|
||||
if ( ! target ) {
|
||||
return;
|
||||
|
@ -75,8 +74,8 @@ class WidgetBuilder {
|
|||
|
||||
registerMessages( wrapper, options ) {
|
||||
this.messages.set( wrapper, {
|
||||
wrapper: wrapper,
|
||||
options: options
|
||||
wrapper,
|
||||
options,
|
||||
} );
|
||||
}
|
||||
|
||||
|
@ -132,7 +131,7 @@ class WidgetBuilder {
|
|||
|
||||
sanitizeWrapper( wrapper ) {
|
||||
if ( Array.isArray( wrapper ) ) {
|
||||
wrapper = wrapper.filter(item => !!item);
|
||||
wrapper = wrapper.filter( ( item ) => !! item );
|
||||
if ( wrapper.length === 1 ) {
|
||||
wrapper = wrapper[ 0 ];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1521,11 +1526,13 @@ document.querySelector("#payment").before(document.querySelector(".ppcp-messages
|
|||
*/
|
||||
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 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 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 === '') {
|
||||
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 );
|
||||
} else {
|
||||
jQuery(orderTrackingContainerSelector).load(loadLocation, "", function(){
|
||||
jQuery( orderTrackingContainerSelector ).load(
|
||||
loadLocation,
|
||||
'',
|
||||
function () {
|
||||
toggleLoaderVisibility();
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (gzdSyncEnabled && typeof(gzdSaveButton) != 'undefined' && gzdSaveButton != null) {
|
||||
if (
|
||||
gzdSyncEnabled &&
|
||||
typeof gzdSaveButton !== 'undefined' &&
|
||||
gzdSaveButton != null
|
||||
) {
|
||||
gzdSaveButton.addEventListener( 'click', function ( event ) {
|
||||
toggleLoaderVisibility();
|
||||
waitForTrackingUpdate( jQuery( '#order-shipments-save' ) );
|
||||
})
|
||||
} );
|
||||
}
|
||||
|
||||
if (wcShipmentSyncEnabled && typeof(wcShipmentSaveButton) != 'undefined' && wcShipmentSaveButton != null) {
|
||||
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) {
|
||||
if (
|
||||
wcShippingTaxSyncEnabled &&
|
||||
typeof wcShippingTaxSyncEnabled !== 'undefined' &&
|
||||
wcShippingTaxSyncEnabled != null
|
||||
) {
|
||||
document.addEventListener( 'click', function ( event ) {
|
||||
const wcShipmentTaxBuyLabelButton = event.target.closest(wcShipmentTaxBuyLabelButtonSelector);
|
||||
const wcShipmentTaxBuyLabelButton = event.target.closest(
|
||||
wcShipmentTaxBuyLabelButtonSelector
|
||||
);
|
||||
|
||||
if ( wcShipmentTaxBuyLabelButton ) {
|
||||
toggleLoaderVisibility();
|
||||
setTimeout( function () {
|
||||
jQuery(orderTrackingContainerSelector).load(loadLocation, "", function(){
|
||||
jQuery( orderTrackingContainerSelector ).load(
|
||||
loadLocation,
|
||||
'',
|
||||
function () {
|
||||
toggleLoaderVisibility();
|
||||
});
|
||||
}
|
||||
);
|
||||
}, 10000 );
|
||||
}
|
||||
} );
|
||||
}
|
||||
},
|
||||
);
|
||||
} );
|
||||
|
|
|
@ -83,6 +83,9 @@ return array(
|
|||
'compat.wc_shipping_tax.is_supported_plugin_version_active' => function (): bool {
|
||||
return class_exists( 'WC_Connect_Loader' );
|
||||
},
|
||||
'compat.nyp.is_supported_plugin_version_active' => function (): bool {
|
||||
return function_exists( 'wc_nyp_init' );
|
||||
},
|
||||
|
||||
'compat.module.url' => static function ( ContainerInterface $container ): string {
|
||||
/**
|
||||
|
|
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