Initial commit
diff --git a/assets/js/stripe-payment-request.js b/assets/js/stripe-payment-request.js
new file mode 100644
index 0000000..3b4fc54
--- /dev/null
+++ b/assets/js/stripe-payment-request.js
@@ -0,0 +1,825 @@
+/* global wc_stripe_payment_request_params, Stripe */
+jQuery( function( $ ) {
+ 'use strict';
+
+ var stripe = Stripe( wc_stripe_payment_request_params.stripe.key, {
+ locale: wc_stripe_payment_request_params.stripe.locale
+ } ),
+ paymentRequestType;
+
+ /**
+ * Object to handle Stripe payment forms.
+ */
+ var wc_stripe_payment_request = {
+ /**
+ * Get WC AJAX endpoint URL.
+ *
+ * @param {String} endpoint Endpoint.
+ * @return {String}
+ */
+ getAjaxURL: function( endpoint ) {
+ return wc_stripe_payment_request_params.ajax_url
+ .toString()
+ .replace( '%%endpoint%%', 'wc_stripe_' + endpoint );
+ },
+
+ getCartDetails: function() {
+ var data = {
+ security: wc_stripe_payment_request_params.nonce.payment
+ };
+
+ $.ajax( {
+ type: 'POST',
+ data: data,
+ url: wc_stripe_payment_request.getAjaxURL( 'get_cart_details' ),
+ success: function( response ) {
+ wc_stripe_payment_request.startPaymentRequest( response );
+ }
+ } );
+ },
+
+ getAttributes: function() {
+ var select = $( '.variations_form' ).find( '.variations select' ),
+ data = {},
+ count = 0,
+ chosen = 0;
+
+ select.each( function() {
+ var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
+ var value = $( this ).val() || '';
+
+ if ( value.length > 0 ) {
+ chosen ++;
+ }
+
+ count ++;
+ data[ attribute_name ] = value;
+ });
+
+ return {
+ 'count' : count,
+ 'chosenCount': chosen,
+ 'data' : data
+ };
+ },
+
+ processSource: function( source, paymentRequestType ) {
+ var data = wc_stripe_payment_request.getOrderData( source, paymentRequestType );
+
+ return $.ajax( {
+ type: 'POST',
+ data: data,
+ dataType: 'json',
+ url: wc_stripe_payment_request.getAjaxURL( 'create_order' )
+ } );
+ },
+
+ /**
+ * Get order data.
+ *
+ * @since 3.1.0
+ * @version 4.0.0
+ * @param {PaymentResponse} source Payment Response instance.
+ *
+ * @return {Object}
+ */
+ getOrderData: function( evt, paymentRequestType ) {
+ var source = evt.source;
+ var email = source.owner.email;
+ var phone = source.owner.phone;
+ var billing = source.owner.address;
+ var name = source.owner.name;
+ var shipping = evt.shippingAddress;
+ var data = {
+ _wpnonce: wc_stripe_payment_request_params.nonce.checkout,
+ billing_first_name: null !== name ? name.split( ' ' ).slice( 0, 1 ).join( ' ' ) : '',
+ billing_last_name: null !== name ? name.split( ' ' ).slice( 1 ).join( ' ' ) : '',
+ billing_company: '',
+ billing_email: null !== email ? email : evt.payerEmail,
+ billing_phone: null !== phone ? phone : evt.payerPhone && evt.payerPhone.replace( '/[() -]/g', '' ),
+ billing_country: null !== billing ? billing.country : '',
+ billing_address_1: null !== billing ? billing.line1 : '',
+ billing_address_2: null !== billing ? billing.line2 : '',
+ billing_city: null !== billing ? billing.city : '',
+ billing_state: null !== billing ? billing.state : '',
+ billing_postcode: null !== billing ? billing.postal_code : '',
+ shipping_first_name: '',
+ shipping_last_name: '',
+ shipping_company: '',
+ shipping_country: '',
+ shipping_address_1: '',
+ shipping_address_2: '',
+ shipping_city: '',
+ shipping_state: '',
+ shipping_postcode: '',
+ shipping_method: [ null === evt.shippingOption ? null : evt.shippingOption.id ],
+ order_comments: '',
+ payment_method: 'stripe',
+ ship_to_different_address: 1,
+ terms: 1,
+ stripe_source: source.id,
+ payment_request_type: paymentRequestType
+ };
+
+ if ( shipping ) {
+ data.shipping_first_name = shipping.recipient.split( ' ' ).slice( 0, 1 ).join( ' ' );
+ data.shipping_last_name = shipping.recipient.split( ' ' ).slice( 1 ).join( ' ' );
+ data.shipping_company = shipping.organization;
+ data.shipping_country = shipping.country;
+ data.shipping_address_1 = typeof shipping.addressLine[0] === 'undefined' ? '' : shipping.addressLine[0];
+ data.shipping_address_2 = typeof shipping.addressLine[1] === 'undefined' ? '' : shipping.addressLine[1];
+ data.shipping_city = shipping.city;
+ data.shipping_state = shipping.region;
+ data.shipping_postcode = shipping.postalCode;
+ }
+
+ return data;
+ },
+
+ /**
+ * Generate error message HTML.
+ *
+ * @since 3.1.0
+ * @version 4.0.0
+ * @param {String} message Error message.
+ * @return {Object}
+ */
+ getErrorMessageHTML: function( message ) {
+ return $( '<div class="woocommerce-error" />' ).text( message );
+ },
+
+ /**
+ * Display error messages.
+ *
+ * @since 4.8.0
+ * @param {Object} message DOM object with error message to display.
+ */
+ displayErrorMessage: function( message ) {
+ $( '.woocommerce-error' ).remove();
+
+ if ( wc_stripe_payment_request_params.is_product_page ) {
+ var element = $( '.product' ).first();
+ element.before( message );
+
+ $( 'html, body' ).animate({
+ scrollTop: element.prev( '.woocommerce-error' ).offset().top
+ }, 600 );
+ } else {
+ var $form = $( '.shop_table.cart' ).closest( 'form' );
+ $form.before( message );
+ $( 'html, body' ).animate({
+ scrollTop: $form.prev( '.woocommerce-error' ).offset().top
+ }, 600 );
+ }
+ },
+
+ /**
+ * Abort payment and display error messages.
+ *
+ * @since 3.1.0
+ * @version 4.8.0
+ * @param {PaymentResponse} payment Payment response instance.
+ * @param {Object} message DOM object with error message to display.
+ */
+ abortPayment: function( payment, message ) {
+ payment.complete( 'fail' );
+ wc_stripe_payment_request.displayErrorMessage( message );
+ },
+
+ /**
+ * Complete payment.
+ *
+ * @since 3.1.0
+ * @version 4.0.0
+ * @param {PaymentResponse} payment Payment response instance.
+ * @param {String} url Order thank you page URL.
+ */
+ completePayment: function( payment, url ) {
+ wc_stripe_payment_request.block();
+
+ payment.complete( 'success' );
+
+ // Success, then redirect to the Thank You page.
+ window.location = url;
+ },
+
+ block: function() {
+ $.blockUI( {
+ message: null,
+ overlayCSS: {
+ background: '#fff',
+ opacity: 0.6
+ }
+ } );
+ },
+
+ /**
+ * Update shipping options.
+ *
+ * @param {Object} details Payment details.
+ * @param {PaymentAddress} address Shipping address.
+ */
+ updateShippingOptions: function( details, address ) {
+ var data = {
+ security: wc_stripe_payment_request_params.nonce.shipping,
+ country: address.country,
+ state: address.region,
+ postcode: address.postalCode,
+ city: address.city,
+ address: typeof address.addressLine[0] === 'undefined' ? '' : address.addressLine[0],
+ address_2: typeof address.addressLine[1] === 'undefined' ? '' : address.addressLine[1],
+ payment_request_type: paymentRequestType,
+ is_product_page: wc_stripe_payment_request_params.is_product_page,
+ };
+
+ return $.ajax( {
+ type: 'POST',
+ data: data,
+ url: wc_stripe_payment_request.getAjaxURL( 'get_shipping_options' )
+ } );
+ },
+
+ /**
+ * Updates the shipping price and the total based on the shipping option.
+ *
+ * @param {Object} details The line items and shipping options.
+ * @param {String} shippingOption User's preferred shipping option to use for shipping price calculations.
+ */
+ updateShippingDetails: function( details, shippingOption ) {
+ var data = {
+ security: wc_stripe_payment_request_params.nonce.update_shipping,
+ shipping_method: [ shippingOption.id ],
+ payment_request_type: paymentRequestType,
+ is_product_page: wc_stripe_payment_request_params.is_product_page,
+ };
+
+ return $.ajax( {
+ type: 'POST',
+ data: data,
+ url: wc_stripe_payment_request.getAjaxURL( 'update_shipping_method' )
+ } );
+ },
+
+ /**
+ * Adds the item to the cart and return cart details.
+ *
+ */
+ addToCart: function() {
+ var product_id = $( '.single_add_to_cart_button' ).val();
+
+ // Check if product is a variable product.
+ if ( $( '.single_variation_wrap' ).length ) {
+ product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val();
+ }
+
+ var data = {
+ security: wc_stripe_payment_request_params.nonce.add_to_cart,
+ product_id: product_id,
+ qty: $( '.quantity .qty' ).val(),
+ attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : []
+ };
+
+ // add addons data to the POST body
+ var formData = $( 'form.cart' ).serializeArray();
+ $.each( formData, function( i, field ) {
+ if ( /^addon-/.test( field.name ) ) {
+ if ( /\[\]$/.test( field.name ) ) {
+ var fieldName = field.name.substring( 0, field.name.length - 2);
+ if ( data[ fieldName ] ) {
+ data[ fieldName ].push( field.value );
+ } else {
+ data[ fieldName ] = [ field.value ];
+ }
+ } else {
+ data[ field.name ] = field.value;
+ }
+ }
+ } );
+
+ return $.ajax( {
+ type: 'POST',
+ data: data,
+ url: wc_stripe_payment_request.getAjaxURL( 'add_to_cart' )
+ } );
+ },
+
+ clearCart: function() {
+ var data = {
+ 'security': wc_stripe_payment_request_params.nonce.clear_cart
+ };
+
+ return $.ajax( {
+ type: 'POST',
+ data: data,
+ url: wc_stripe_payment_request.getAjaxURL( 'clear_cart' ),
+ success: function( response ) {}
+ } );
+ },
+
+ getRequestOptionsFromLocal: function() {
+ return {
+ total: wc_stripe_payment_request_params.product.total,
+ currency: wc_stripe_payment_request_params.checkout.currency_code,
+ country: wc_stripe_payment_request_params.checkout.country_code,
+ requestPayerName: true,
+ requestPayerEmail: true,
+ requestPayerPhone: wc_stripe_payment_request_params.checkout.needs_payer_phone,
+ requestShipping: wc_stripe_payment_request_params.product.requestShipping,
+ displayItems: wc_stripe_payment_request_params.product.displayItems
+ };
+ },
+
+ /**
+ * Starts the payment request
+ *
+ * @since 4.0.0
+ * @version 4.8.0
+ */
+ startPaymentRequest: function( cart ) {
+ var paymentDetails,
+ options;
+
+ if ( wc_stripe_payment_request_params.is_product_page ) {
+ options = wc_stripe_payment_request.getRequestOptionsFromLocal();
+
+ paymentDetails = options;
+ } else {
+ options = {
+ total: cart.order_data.total,
+ currency: cart.order_data.currency,
+ country: cart.order_data.country_code,
+ requestPayerName: true,
+ requestPayerEmail: true,
+ requestPayerPhone: wc_stripe_payment_request_params.checkout.needs_payer_phone,
+ requestShipping: cart.shipping_required ? true : false,
+ displayItems: cart.order_data.displayItems
+ };
+
+ paymentDetails = cart.order_data;
+ }
+
+ // Puerto Rico (PR) is the only US territory/possession that's supported by Stripe.
+ // Since it's considered a US state by Stripe, we need to do some special mapping.
+ if ( 'PR' === options.country ) {
+ options.country = 'US';
+ }
+
+ // Handle errors thrown by Stripe, so we don't break the product page
+ try {
+ var paymentRequest = stripe.paymentRequest( options );
+
+ var elements = stripe.elements( { locale: wc_stripe_payment_request_params.button.locale } );
+ var prButton = wc_stripe_payment_request.createPaymentRequestButton( elements, paymentRequest );
+
+ // Check the availability of the Payment Request API first.
+ paymentRequest.canMakePayment().then( function( result ) {
+ if ( ! result ) {
+ return;
+ }
+ if ( result.applePay ) {
+ paymentRequestType = 'apple_pay';
+ } else if ( result.googlePay ) {
+ paymentRequestType = 'google_pay';
+ } else {
+ paymentRequestType = 'payment_request_api';
+ }
+
+ wc_stripe_payment_request.attachPaymentRequestButtonEventListeners( prButton, paymentRequest );
+ wc_stripe_payment_request.showPaymentRequestButton( prButton );
+ } );
+
+ // Possible statuses success, fail, invalid_payer_name, invalid_payer_email, invalid_payer_phone, invalid_shipping_address.
+ paymentRequest.on( 'shippingaddresschange', function( evt ) {
+ $.when( wc_stripe_payment_request.updateShippingOptions( paymentDetails, evt.shippingAddress ) ).then( function( response ) {
+ evt.updateWith( { status: response.result, shippingOptions: response.shipping_options, total: response.total, displayItems: response.displayItems } );
+ } );
+ } );
+
+ paymentRequest.on( 'shippingoptionchange', function( evt ) {
+ $.when( wc_stripe_payment_request.updateShippingDetails( paymentDetails, evt.shippingOption ) ).then( function( response ) {
+ if ( 'success' === response.result ) {
+ evt.updateWith( { status: 'success', total: response.total, displayItems: response.displayItems } );
+ }
+
+ if ( 'fail' === response.result ) {
+ evt.updateWith( { status: 'fail' } );
+ }
+ } );
+ } );
+
+ paymentRequest.on( 'source', function( evt ) {
+ // Check if we allow prepaid cards.
+ if ( 'no' === wc_stripe_payment_request_params.stripe.allow_prepaid_card && 'prepaid' === evt.source.card.funding ) {
+ wc_stripe_payment_request.abortPayment( evt, wc_stripe_payment_request.getErrorMessageHTML( wc_stripe_payment_request_params.i18n.no_prepaid_card ) );
+ } else {
+ $.when( wc_stripe_payment_request.processSource( evt, paymentRequestType ) ).then( function( response ) {
+ if ( 'success' === response.result ) {
+ wc_stripe_payment_request.completePayment( evt, response.redirect );
+ } else {
+ wc_stripe_payment_request.abortPayment( evt, response.messages );
+ }
+ } );
+ }
+ } );
+ } catch( e ) {
+ // Leave for troubleshooting
+ console.error( e );
+ }
+ },
+
+ getSelectedProductData: function() {
+ var product_id = $( '.single_add_to_cart_button' ).val();
+
+ // Check if product is a variable product.
+ if ( $( '.single_variation_wrap' ).length ) {
+ product_id = $( '.single_variation_wrap' ).find( 'input[name="product_id"]' ).val();
+ }
+
+ var addons = $( '#product-addons-total' ).data('price_data') || [];
+ var addon_value = addons.reduce( function ( sum, addon ) { return sum + addon.cost; }, 0 );
+
+ var data = {
+ security: wc_stripe_payment_request_params.nonce.get_selected_product_data,
+ product_id: product_id,
+ qty: $( '.quantity .qty' ).val(),
+ attributes: $( '.variations_form' ).length ? wc_stripe_payment_request.getAttributes().data : [],
+ addon_value: addon_value,
+ };
+
+ return $.ajax( {
+ type: 'POST',
+ data: data,
+ url: wc_stripe_payment_request.getAjaxURL( 'get_selected_product_data' )
+ } );
+ },
+
+ /**
+ * Creates a wrapper around a function that ensures a function can not
+ * called in rappid succesion. The function can only be executed once and then agin after
+ * the wait time has expired. Even if the wrapper is called multiple times, the wrapped
+ * function only excecutes once and then blocks until the wait time expires.
+ *
+ * @param {int} wait Milliseconds wait for the next time a function can be executed.
+ * @param {function} func The function to be wrapped.
+ * @param {bool} immediate Overriding the wait time, will force the function to fire everytime.
+ *
+ * @return {function} A wrapped function with execution limited by the wait time.
+ */
+ debounce: function( wait, func, immediate ) {
+ var timeout;
+ return function() {
+ var context = this, args = arguments;
+ var later = function() {
+ timeout = null;
+ if (!immediate) func.apply(context, args);
+ };
+ var callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) func.apply(context, args);
+ };
+ },
+
+ /**
+ * Creates stripe paymentRequest element or connects to custom button
+ *
+ * @param {object} elements Stripe elements instance.
+ * @param {object} paymentRequest Stripe paymentRequest object.
+ *
+ * @return {object} Stripe paymentRequest element or custom button jQuery element.
+ */
+ createPaymentRequestButton: function( elements, paymentRequest ) {
+ var button;
+ if ( wc_stripe_payment_request_params.button.is_custom ) {
+ button = $( wc_stripe_payment_request_params.button.css_selector );
+ if ( button.length ) {
+ // We fallback to default paymentRequest button if no custom button is found in the UI.
+ // Add flag to be sure that created button is custom button rather than fallback element.
+ button.data( 'isCustom', true );
+ return button;
+ }
+ }
+
+ if ( wc_stripe_payment_request_params.button.is_branded ) {
+ if ( wc_stripe_payment_request.shouldUseGooglePayBrand() ) {
+ button = wc_stripe_payment_request.createGooglePayButton();
+ // Add flag to be sure that created button is branded rather than fallback element.
+ button.data( 'isBranded', true );
+ return button;
+ } else {
+ // Not implemented branded buttons default to Stripe's button
+ // Apple Pay buttons can also fall back to Stripe's button, as it's already branded
+ // Set button type to default or buy, depending on branded type, to avoid issues with Stripe
+ wc_stripe_payment_request_params.button.type = 'long' === wc_stripe_payment_request_params.button.branded_type ? 'buy' : 'default';
+ }
+ }
+
+ return elements.create( 'paymentRequestButton', {
+ paymentRequest: paymentRequest,
+ style: {
+ paymentRequestButton: {
+ type: wc_stripe_payment_request_params.button.type,
+ theme: wc_stripe_payment_request_params.button.theme,
+ height: wc_stripe_payment_request_params.button.height + 'px',
+ },
+ },
+ } );
+ },
+
+ /**
+ * Checks if button is custom payment request button.
+ *
+ * @param {object} prButton Stripe paymentRequest element or custom jQuery element.
+ *
+ * @return {boolean} True when prButton is custom button jQuery element.
+ */
+ isCustomPaymentRequestButton: function ( prButton ) {
+ return prButton && 'function' === typeof prButton.data && prButton.data( 'isCustom' );
+ },
+
+ isBrandedPaymentRequestButton: function ( prButton ) {
+ return prButton && 'function' === typeof prButton.data && prButton.data( 'isBranded' );
+ },
+
+ shouldUseGooglePayBrand: function () {
+ var ua = window.navigator.userAgent.toLowerCase();
+ var isChrome = /chrome/.test( ua ) && ! /edge|edg|opr|brave\//.test( ua ) && 'Google Inc.' === window.navigator.vendor;
+ // newer versions of Brave do not have the userAgent string
+ var isBrave = isChrome && window.navigator.brave;
+ return isChrome && ! isBrave;
+ },
+
+ createGooglePayButton: function () {
+ var allowedThemes = [ 'dark', 'light', 'light-outline' ];
+ var allowedTypes = [ 'short', 'long' ];
+
+ var theme = wc_stripe_payment_request_params.button.theme;
+ var type = wc_stripe_payment_request_params.button.branded_type;
+ var locale = wc_stripe_payment_request_params.button.locale;
+ var height = wc_stripe_payment_request_params.button.height;
+ theme = allowedThemes.includes( theme ) ? theme : 'light';
+ var gpaySvgTheme = 'dark' === theme ? 'dark' : 'light';
+ type = allowedTypes.includes( type ) ? type : 'long';
+
+ var button = $( '<button type="button" id="wc-stripe-branded-button" aria-label="Google Pay" class="gpay-button"></button>' );
+ button.css( 'height', height + 'px' );
+ button.addClass( theme + ' ' + type );
+ if ( 'long' === type ) {
+ var url = 'https://www.gstatic.com/instantbuy/svg/' + gpaySvgTheme + '/' + locale + '.svg';
+ var fallbackUrl = 'https://www.gstatic.com/instantbuy/svg/' + gpaySvgTheme + '/en.svg';
+ // Check if locale GPay button exists, default to en if not
+ setBackgroundImageWithFallback( button, url, fallbackUrl );
+ }
+
+ return button;
+ },
+
+ attachPaymentRequestButtonEventListeners: function( prButton, paymentRequest ) {
+ // First, mark the body so we know a payment request button was used.
+ // This way error handling can any display errors in the most appropriate place.
+ prButton.on( 'click', function ( evt ) {
+ $( 'body' ).addClass( 'woocommerce-stripe-prb-clicked' );
+ });
+
+ // Then, attach specific handling for selected pages and button types
+ if ( wc_stripe_payment_request_params.is_product_page ) {
+ wc_stripe_payment_request.attachProductPageEventListeners( prButton, paymentRequest );
+ } else {
+ wc_stripe_payment_request.attachCartPageEventListeners( prButton, paymentRequest );
+ }
+ },
+
+ attachProductPageEventListeners: function( prButton, paymentRequest ) {
+ var paymentRequestError = [];
+ var addToCartButton = $( '.single_add_to_cart_button' );
+
+ prButton.on( 'click', function ( evt ) {
+ // If login is required for checkout, display redirect confirmation dialog.
+ if ( wc_stripe_payment_request_params.login_confirmation ) {
+ evt.preventDefault();
+ displayLoginConfirmation( paymentRequestType );
+ return;
+ }
+
+ // First check if product can be added to cart.
+ if ( addToCartButton.is( '.disabled' ) ) {
+ evt.preventDefault(); // Prevent showing payment request modal.
+ if ( addToCartButton.is( '.wc-variation-is-unavailable' ) ) {
+ window.alert( wc_add_to_cart_variation_params.i18n_unavailable_text );
+ } else if ( addToCartButton.is( '.wc-variation-selection-needed' ) ) {
+ window.alert( wc_add_to_cart_variation_params.i18n_make_a_selection_text );
+ }
+ return;
+ }
+
+ if ( 0 < paymentRequestError.length ) {
+ evt.preventDefault();
+ window.alert( paymentRequestError );
+ return;
+ }
+
+ wc_stripe_payment_request.addToCart();
+
+ if ( wc_stripe_payment_request.isCustomPaymentRequestButton( prButton ) || wc_stripe_payment_request.isBrandedPaymentRequestButton( prButton ) ) {
+ evt.preventDefault();
+ paymentRequest.show();
+ }
+ });
+
+ $( document.body ).on( 'wc_stripe_unblock_payment_request_button wc_stripe_enable_payment_request_button', function () {
+ wc_stripe_payment_request.unblockPaymentRequestButton();
+ } );
+
+ $( document.body ).on( 'wc_stripe_block_payment_request_button', function () {
+ wc_stripe_payment_request.blockPaymentRequestButton( 'wc_request_button_is_blocked' );
+ } );
+
+ $( document.body ).on( 'wc_stripe_disable_payment_request_button', function () {
+ wc_stripe_payment_request.blockPaymentRequestButton( 'wc_request_button_is_disabled' );
+ } );
+
+ $( document.body ).on( 'woocommerce_variation_has_changed', function () {
+ $( document.body ).trigger( 'wc_stripe_block_payment_request_button' );
+
+ $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function ( response ) {
+ $.when(
+ paymentRequest.update( {
+ total: response.total,
+ displayItems: response.displayItems,
+ } )
+ ).then( function () {
+ $( document.body ).trigger( 'wc_stripe_unblock_payment_request_button' );
+ } );
+ });
+ } );
+
+ // Block the payment request button as soon as an "input" event is fired, to avoid sync issues
+ // when the customer clicks on the button before the debounced event is processed.
+ $( '.quantity' ).on( 'input', '.qty', function() {
+ $( document.body ).trigger( 'wc_stripe_block_payment_request_button' );
+ } );
+
+ $( '.quantity' ).on( 'input', '.qty', wc_stripe_payment_request.debounce( 250, function() {
+ $( document.body ).trigger( 'wc_stripe_block_payment_request_button' );
+ paymentRequestError = [];
+
+ $.when( wc_stripe_payment_request.getSelectedProductData() ).then( function ( response ) {
+ if ( response.error ) {
+ paymentRequestError = [ response.error ];
+ $( document.body ).trigger( 'wc_stripe_unblock_payment_request_button' );
+ } else {
+ $.when(
+ paymentRequest.update( {
+ total: response.total,
+ displayItems: response.displayItems,
+ } )
+ ).then( function () {
+ $( document.body ).trigger( 'wc_stripe_unblock_payment_request_button' );
+ });
+ }
+ } );
+ }));
+
+ if ( $('.variations_form').length ) {
+ $( '.variations_form' ).on( 'found_variation.wc-variation-form', function ( evt, variation ) {
+ if ( variation.is_in_stock ) {
+ wc_stripe_payment_request.unhidePaymentRequestButton();
+ } else {
+ wc_stripe_payment_request.hidePaymentRequestButton();
+ }
+ } );
+ }
+ },
+
+ attachCartPageEventListeners: function ( prButton, paymentRequest ) {
+ prButton.on( 'click', function ( evt ) {
+ // If login is required for checkout, display redirect confirmation dialog.
+ if ( wc_stripe_payment_request_params.login_confirmation ) {
+ evt.preventDefault();
+ displayLoginConfirmation( paymentRequestType );
+ return;
+ }
+
+ if (
+ wc_stripe_payment_request.isCustomPaymentRequestButton(
+ prButton
+ ) ||
+ wc_stripe_payment_request.isBrandedPaymentRequestButton(
+ prButton
+ )
+ ) {
+ evt.preventDefault();
+ paymentRequest.show();
+ }
+ } );
+ },
+
+ showPaymentRequestButton: function( prButton ) {
+ if ( wc_stripe_payment_request.isCustomPaymentRequestButton( prButton ) ) {
+ prButton.addClass( 'is-active' );
+ $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).show();
+ } else if ( wc_stripe_payment_request.isBrandedPaymentRequestButton( prButton ) ) {
+ $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).show();
+ $( '#wc-stripe-payment-request-button' ).html( prButton );
+ } else if ( $( '#wc-stripe-payment-request-button' ).length ) {
+ $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).show();
+ prButton.mount( '#wc-stripe-payment-request-button' );
+ }
+ },
+
+ hidePaymentRequestButton: function () {
+ $( '#wc-stripe-payment-request-wrapper, #wc-stripe-payment-request-button-separator' ).hide();
+ },
+
+ unhidePaymentRequestButton: function () {
+ const stripe_wrapper = $( '#wc-stripe-payment-request-wrapper' );
+ const stripe_separator = $( '#wc-stripe-payment-request-button-separator' );
+ // If either element is hidden, ensure both show.
+ if ( stripe_wrapper.is(':hidden') || stripe_separator.is(':hidden') ) {
+ stripe_wrapper.show();
+ stripe_separator.show();
+ }
+ },
+
+ blockPaymentRequestButton: function( cssClassname ) {
+ // check if element isn't already blocked before calling block() to avoid blinking overlay issues
+ // blockUI.isBlocked is either undefined or 0 when element is not blocked
+ if ( $( '#wc-stripe-payment-request-button' ).data( 'blockUI.isBlocked' ) ) {
+ return;
+ }
+
+ $( '#wc-stripe-payment-request-button' )
+ .addClass( cssClassname )
+ .block( { message: null } );
+ },
+
+ unblockPaymentRequestButton: function() {
+ $( '#wc-stripe-payment-request-button' )
+ .removeClass( ['wc_request_button_is_blocked', 'wc_request_button_is_disabled'] )
+ .unblock();
+ },
+
+ /**
+ * Initialize event handlers and UI state
+ *
+ * @since 4.0.0
+ * @version 4.0.0
+ */
+ init: function() {
+ if ( wc_stripe_payment_request_params.is_product_page ) {
+ wc_stripe_payment_request.startPaymentRequest( '' );
+ } else {
+ wc_stripe_payment_request.getCartDetails();
+ }
+
+ },
+ };
+
+ wc_stripe_payment_request.init();
+
+ // We need to refresh payment request data when total is updated.
+ $( document.body ).on( 'updated_cart_totals', function() {
+ wc_stripe_payment_request.init();
+ } );
+
+ // We need to refresh payment request data when total is updated.
+ $( document.body ).on( 'updated_checkout', function() {
+ wc_stripe_payment_request.init();
+ } );
+
+ function setBackgroundImageWithFallback( element, background, fallback ) {
+ element.css( 'background-image', 'url(' + background + ')' );
+ // Need to use an img element to avoid CORS issues
+ var testImg = document.createElement("img");
+ testImg.onerror = function () {
+ element.css( 'background-image', 'url(' + fallback + ')' );
+ }
+ testImg.src = background;
+ }
+
+ // TODO: Replace this by `client/blocks/payment-request/login-confirmation.js`
+ // when we start using webpack to build this file.
+ function displayLoginConfirmation( paymentRequestType ) {
+ if ( ! wc_stripe_payment_request_params.login_confirmation ) {
+ return;
+ }
+
+ var message = wc_stripe_payment_request_params.login_confirmation.message;
+
+ // Replace dialog text with specific payment request type "Apple Pay" or "Google Pay".
+ if ( 'payment_request_api' !== paymentRequestType ) {
+ message = message.replace(
+ /\*\*.*?\*\*/,
+ 'apple_pay' === paymentRequestType ? 'Apple Pay' : 'Google Pay'
+ );
+ }
+
+ // Remove asterisks from string.
+ message = message.replace( /\*\*/g, '' );
+
+ if ( confirm( message ) ) {
+ // Redirect to my account page.
+ window.location.href = wc_stripe_payment_request_params.login_confirmation.redirect_url;
+ }
+ }
+} );