/* global wc_ppec_context */
;( function ( $, window, document ) {
'use strict';
// Use global 'paypal' object or namespaced 'paypal_sdk' as PayPal API (depends on legacy/SDK mode).
var paypal = wc_ppec_context.use_checkout_js ? window.paypal : window.paypal_sdk;
// Show error notice at top of checkout form, or else within button container
var showError = function( errorMessage, selector ) {
var $container = $( '.woocommerce-notices-wrapper, form.checkout' );
if ( ! $container || ! $container.length ) {
$( selector ).prepend( errorMessage );
return;
} else {
$container = $container.first();
}
// Adapted from https://github.com/woocommerce/woocommerce/blob/ea9aa8cd59c9fa735460abf0ebcb97fa18f80d03/assets/js/frontend/checkout.js#L514-L529
$( '.woocommerce-NoticeGroup-checkout, .woocommerce-error, .woocommerce-message' ).remove();
$container.prepend( '
' + errorMessage + '
' );
$container.find( '.input-text, select, input:checkbox' ).trigger( 'validate' ).trigger( 'blur' );
var scrollElement = $( '.woocommerce-NoticeGroup-checkout' );
if ( ! scrollElement.length ) {
scrollElement = $container;
}
if ( $.scroll_to_notices ) {
$.scroll_to_notices( scrollElement );
} else {
// Compatibility with WC <3.3
$( 'html, body' ).animate( {
scrollTop: ( $container.offset().top - 100 )
}, 1000 );
}
$( document.body ).trigger( 'checkout_error' );
}
// Map funding method settings to enumerated options provided by PayPal (checkout.js).
var getFundingMethods = function( methods ) {
if ( ! methods ) {
return undefined;
}
var paypal_funding_methods = [];
$.each( methods, function( index, method_name ) {
var method = paypal.FUNDING[ method_name.toUpperCase() ];
if ( method ) {
paypal_funding_methods.push( method );
}
} );
return paypal_funding_methods;
}
var renderCreditMessaging = function( buttonSelector ) {
if ( 'undefined' === typeof wc_ppec_context.credit_messaging || ! wc_ppec_context.credit_messaging || 'undefined' === typeof paypal.Messages ) {
return;
}
if ( 'undefined' != typeof paypal.isFundingEligible && ! paypal.isFundingEligible( paypal.FUNDING.CREDIT ) && ! paypal.isFundingEligible( paypal.FUNDING.PAYLATER ) ) {
return;
}
if ( 0 === $( buttonSelector ).length ) {
return;
}
// Add an element for messaging.
var messagingWrapper = $( '' ).prependTo( buttonSelector ).get( 0 );
paypal.Messages( wc_ppec_context.credit_messaging ).render( messagingWrapper );
}
var render = function( isMiniCart ) {
var prefix = isMiniCart ? 'mini_cart_' : '';
var button_size = wc_ppec_context[ prefix + 'button_size' ];
var button_layout = wc_ppec_context[ prefix + 'button_layout' ];
var button_label = ( 'undefined' !== wc_ppec_context[ prefix + 'button_label' ] ) ? wc_ppec_context[ prefix + 'button_label' ] : wc_ppec_context['button_label'];
var allowed = wc_ppec_context[ prefix + 'allowed_methods' ];
var disallowed = wc_ppec_context[ prefix + 'disallowed_methods' ];
var selector = isMiniCart ? '#woo_pp_ec_button_mini_cart' : '#woo_pp_ec_button_' + wc_ppec_context.page;
var fromCheckout = 'checkout' === wc_ppec_context.page && ! isMiniCart;
const return_url = wc_ppec_context['return_url'];
const cancel_url = wc_ppec_context['cancel_url'];
// Don't render if selector doesn't exist or is already rendered in DOM.
if ( ! $( selector ).length || $( selector ).children().length ) {
return;
}
var button_args = {
env: wc_ppec_context.environment,
locale: wc_ppec_context.locale,
commit: fromCheckout,
funding: {
allowed: getFundingMethods( allowed ),
disallowed: getFundingMethods( disallowed ),
},
style: {
color: wc_ppec_context.button_color,
shape: wc_ppec_context.button_shape,
label: button_label,
layout: button_layout,
size: button_size,
branding: true,
tagline: false,
},
validate: function( actions ) {
// Only enable on variable product page if purchasable variation selected.
$( '#woo_pp_ec_button_product' ).off( '.legacy' )
.on( 'enable', actions.enable )
.on( 'disable', actions.disable );
},
payment: function() {
// Clear any errors from previous attempt.
$( '.woocommerce-error', selector ).remove();
return new Promise( function( resolve, reject ) {
// First, generate cart if triggered from single product.
if ( 'product' === wc_ppec_context.page && ! isMiniCart ) {
window.wc_ppec_generate_cart( resolve );
} else {
resolve();
}
} ).then( function() {
// Make PayPal Checkout initialization request.
var data = $( selector ).closest( 'form' )
.add( $( ' ' )
.attr( 'value', wc_ppec_context.start_checkout_nonce )
)
.add( $( ' ' )
.attr( 'value', fromCheckout ? 'yes' : 'no' )
)
.serialize();
var request_callback = function( response ) {
if ( ! response.success ) {
// Error messages may be preformatted in which case response structure will differ
var messages = response.data ? response.data.messages : response.messages;
if ( 'string' === typeof messages ) {
showError( messages );
} else {
var messageItems = messages.map( function( message ) {
return '' + message + '';
} ).join( '' );
showError( '', selector );
}
return null;
}
return response.data.token;
};
if ( ! wc_ppec_context.use_checkout_js ) {
return fetch( wc_ppec_context.start_checkout_url, {
method: 'post',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: data
} ).then( function ( response ) {
return response.json();
} ).then( request_callback );
} else {
return paypal.request( {
method: 'post',
url: wc_ppec_context.start_checkout_url,
body: data,
} ).then( request_callback );
}
} );
},
onAuthorize: function( data, actions ) {
if ( fromCheckout ) {
// Pass data necessary for authorizing payment to back-end.
$( 'form.checkout' )
.append( $( ' ' ).attr( 'value', ! wc_ppec_context.use_checkout_js ? data.orderID : data.paymentToken ) )
.append( $( ' ' ).attr( 'value', data.payerID ) )
.trigger( 'submit' );
} else {
// Navigate to order confirmation URL specified in original request to PayPal from back-end.
if ( ! wc_ppec_context.use_checkout_js ) {
const query_args = '?woo-paypal-return=true&token=' + data.orderID + '&PayerID=' + data.payerID;
return actions.redirect( return_url + query_args );
}
return actions.redirect();
}
},
onCancel: function( data, actions ) {
if ( cancel_url && 'orderID' in data ) {
const query_args = '?woo-paypal-cancel=true&token=' + data.orderID;
return actions.redirect( cancel_url + query_args );
}
},
onError: function() {
jQuery( selector ).empty();
render();
},
};
if ( ! wc_ppec_context.use_checkout_js ) {
if ( ! isMiniCart ) {
renderCreditMessaging( selector );
}
// 'payment()' and 'onAuthorize()' callbacks from checkout.js are now 'createOrder()' and 'onApprove()'.
Object.defineProperty( button_args, 'createOrder', Object.getOwnPropertyDescriptor( button_args, 'payment' ) );
Object.defineProperty( button_args, 'onApprove', Object.getOwnPropertyDescriptor( button_args, 'onAuthorize' ) );
// 'style.size' is no longer supported in the JS SDK. See https://developer.paypal.com/docs/checkout/integration-features/customize-button/#size.
delete button_args['style']['size'];
// Add a class selector so the buttons can be styled via css.
$( selector ).addClass( 'wc_ppec_' + button_size + '_payment_buttons' );
// Drop other args no longer needed in the JS SDK.
var args_to_remove = [ 'env', 'locale', 'commit', 'funding', 'payment', 'onAuthorize' ];
args_to_remove.forEach( function( arg ) {
delete button_args[ arg ]
});
var disabledFundingSources = getFundingMethods( disallowed );
if ( 'undefined' === typeof( disabledFundingSources ) || ! disabledFundingSources || 0 === disabledFundingSources.length ) {
paypal.Buttons( button_args ).render( selector );
} else {
// Render context specific buttons.
paypal.getFundingSources().forEach( function( fundingSource ) {
if ( -1 !== disabledFundingSources.indexOf( fundingSource ) ) {
return;
}
var buttonSettings = {
createOrder: button_args.createOrder,
onApprove: button_args.onApprove,
onError: button_args.onError,
onCancel: button_args.onCancel,
fundingSource: fundingSource,
style: ( paypal.FUNDING.PAYPAL === fundingSource ) ? button_args.style : { layout: button_args.style.layout, shape: button_args.style.shape }
};
var button = paypal.Buttons( buttonSettings );
if ( button.isEligible() ) {
button.render( selector );
}
} );
}
} else {
paypal.Button.render( button_args, selector );
}
};
// Render cart, single product, or checkout buttons.
if ( wc_ppec_context.page ) {
if ( 'checkout' !== wc_ppec_context.page ) {
render();
}
$( document.body ).on( 'updated_cart_totals updated_checkout', render.bind( this, false ) );
}
// Render buttons in mini-cart if present.
$( document.body ).on( 'wc_fragments_loaded wc_fragments_refreshed', function() {
var $button = $( '.widget_shopping_cart #woo_pp_ec_button_mini_cart' );
if ( $button.length ) {
// Clear any existing button in container, and render.
$button.empty();
render( true );
}
} );
} )( jQuery, window, document );