1(function($) { 2 'use strict'; 3 4 /** 5 * All of the code for your public-facing JavaScript source 6 * should reside in this file. 7 * 8 * Note: It has been assumed you will write jQuery code here, so the 9 * $ function reference has been prepared for usage within the scope 10 * of this function. 11 * 12 * This enables you to define handlers, for when the DOM is ready: 13 * 14 * $(function() { 15 * 16 * }); 17 * 18 * When the window is loaded: 19 * 20 * $( window ).load(function() { 21 * 22 * }); 23 * 24 * ...and/or other possibilities. 25 * 26 * Ideally, it is not considered best practise to attach more than a 27 * single DOM-ready or window-load handler for a particular page. 28 * Although scripts in the WordPress core, Plugins and Themes may be 29 * practising this, we should strive to set a better example in our own work. 30 */ 31 var regExPhone = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/, 32 regExEmail = /^([a-zA-Z0-9_.+-])+\@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/, 33 states = sc_country_select_states.sc_states, 34 sc_country = sc_country_select_states.sc_country, 35 $select_state, 36 $select_country; 37 38 $('.sc-open-modal').click(function (e) { 39 e.preventDefault(); 40 var modal = $(this).data('item-id'); 41 $('#' + modal).addClass('opened'); 42 }); 43 44 $('.closemodal').click(function (e) { 45 e.preventDefault(); 46 var el = $(this).closest('.opened'); 47 el.removeClass('opened'); 48 }); 49 50 /* <fs_premium_only> */ 51 52 /* It will redirect if anyone clicked on link before ready */ 53 $(document).on('click', 'a[href*="sc-upsell-offer=yes"]', function(e) { 54 55 e.preventDefault(); 56 57 if ('undefined' !== typeof studiocart.is_preview && '1' == studiocart.is_preview) { 58 e.stopPropagation(); 59 return; 60 } 61 62 //window.location.href = studiocart.upsell_accept; 63 64 return false; 65 }); 66 67 $(document).on('click', 'a[href*="sc-upsell-offer=no"]', function(e) { 68 69 e.preventDefault(); 70 71 if ('undefined' !== typeof studiocart.is_preview && '1' == studiocart.is_preview) { 72 e.stopPropagation(); 73 return; 74 } 75 76 window.location.href = studiocart.upsell_decline; 77 78 return false; 79 }); 80 81 /* Once the link is ready this will work to stop conditional propogation*/ 82 $(document).on('click', '.sc-accept-upsell-link, .sc-decline-upsell-link', function(e) { 83 84 if ('undefined' !== typeof studiocart.is_preview && '1' == studiocart.is_preview) { 85 e.preventDefault(); 86 e.stopPropagation(); 87 return false; 88 } 89 90 if ($(this).hasClass('sc-accept-upsell-link')) { 91 92 $(this).css({ "pointer-events": "none", 'opacity': 0.85 }).text(sc_translate_frontend.processing + '...'); 93 if (typeof studiocart.pay_method !== 'undefined' && studiocart.pay_method != 'stripe' && studiocart.pay_method != 'cod') { 94 $(this).trigger('studiocart/upsell/accept/' + studiocart.pay_method); 95 return false; 96 } 97 98 var url = $(this).attr('href'), 99 noUrl = $('.sc-decline-upsell-link').attr('href'), 100 urlVar = 'sc-oto', 101 data = { 102 'action': 'sc_process_upsell', 103 'sc-order': studiocart.sc_order, 104 'sc-nonce': studiocart.sc_nonce, 105 'step': studiocart.step, 106 }; 107 108 // flag for downsells 109 if ('undefined' !== typeof studiocart.is_downsell && '1' == studiocart.is_downsell) { 110 data['downsell'] = 1; 111 urlVar = 'sc-oto-2' 112 } 113 114 $.post(studiocart.ajax, data, function(order_id) { 115 if (!isNaN(order_id)) { // order created 116 url += '&' + urlVar + '=' + order_id; 117 window.location.href = url; 118 return false; 119 } else { 120 121 // if card was declined or other error, alert and redirect to decline url 122 var error = JSON.parse(order_id); 123 if ('undefined' !== typeof error.message) { 124 alert(error.message); 125 window.location.href = noUrl; 126 } 127 128 // Otherwise try to reauthenticate card in confirmCardPayment 129 var stripe = Stripe(stripe_key[0]), 130 intent_id = error.intentId; 131
132 stripe.confirmCardPayment(error.clientSecret, { 133 payment_method: error.paymentMethod 134 }).then(function(result) { 135 if (result.error) { 136 // Display error.message in your UI. 137 alert(result.error.message); 138 window.location.href = noUrl; 139 } else { 140 var data = { 141 'action': 'save_order_to_db', 142 'sc-order': studiocart.sc_order, 143 'sc-nonce': studiocart.sc_nonce, 144 'intent_id': intent_id, 145 'intent_status': result.paymentIntent.status 146 }; 147 148 // flag for downsells 149 if ('undefined' !== typeof studiocart.is_downsell && '1' == studiocart.is_downsell) { 150 data['downsell'] = 1; 151 urlVar = 'sc-oto-2' 152 } 153 154 $.post(studiocart.ajax, data, function(order_id) { 155 if (!isNaN(order_id)) { 156 url += '&' + urlVar + '=' + order_id; 157 window.location.href = url; 158 return false; 159 } else { 160 alert(order_id); 161 window.location.href = noUrl; 162 } 163 }); 164 } 165 }); 166 return false; 167 } 168 }); 169 return false; 170 171 } 172 173 }); 174 175 176 177 /* </fs_premium_only> */ 178 function key_value_pair_selectize(json_data) { 179 let format_data = []; 180 $.each(json_data, function(i, item) { 181 let json_state = { 'state_key': i, 'state_value': item }; 182 format_data.push(json_state); 183 }); 184 return format_data; 185 } 186 187 function isValidPhonenumber(value) { 188 return (/^\d{7,}$/).test(value.replace(/[\s()+\-\.]|ext/gi, '')); 189 } 190 191 function isValidPassword(value) { 192 var lowerCaseLetters = /[a-z]/g; 193 if (!value.match(lowerCaseLetters)) { 194 return false; 195 } 196 197 // Validate numbers 198 var numbers = /[0-9]/g; 199 if (!value.match(numbers)) { 200 return false; 201 } 202 203 // Validate length 204 if (!value.length >= 8) { 205 return false; 206 } 207 return true; 208 } 209 210 function country_selectize() { 211 $('.sc-form-wrap').each(function(){ 212 let current_country; 213 let current_state; 214 215 let form = $(this); 216 let form_id = '#'+form.attr('id'); 217 218 if ($('#state', form_id).length) { 219 current_state = $('#state', form_id).val(); 220 } 221 222 if ($('#country', form_id).length < 1) { 223 current_country = sc_country; 224 } else { 225 current_country = $('#country', form_id).val(); 226 $('#country', form_id).selectize()[0].selectize.destroy(); 227 $select_country = $('#country', form_id).selectize({ 228 onChange: function(value) { 229 if (!value.length) return; 230 if ($('#state', form_id).length > 0) { 231 $('#state', form_id).selectize()[0].selectize.clearOptions(); 232 $('#state', form_id).selectize()[0].selectize.destroy(); 233 let new_state_option = key_value_pair_selectize(states[value]); 234 let state_placeholder = $('#state', form_id).attr('placeholder'); 235 let $required = ""; 236 if (jQuery('#state', form_id).hasClass('required')) { 237 $required = "required"; 238 } 239 if ($('#state option', form_id).length > 0) { 240 state_placeholder = $('#state option[value=""]', form_id).text(); 241 } 242 if (new_state_option.length === 0) { 243 $('#state', form_id).replaceWith('<input id="state" name="state" type="text" class="form-control ' + $required + '" placeholder="' + state_placeholder + '" value="" aria-label="State">'); 244 } else { 245 $('#state', form_id).replaceWith('<select id="state" name="state" class="form-control ' + $required + '" style="display: block;"><option value="" selected>' + state_placeholder + '</option></select>'); 246 $select_state = $('#state', form_id).selectize({ 247 valueField: 'state_key', 248 labelField: 'state_value', 249 searchField: 'state_value', 250 options: new_state_option, 251 onChange: function(value) { 252 if (value.length >= 1) { 253 var $el = $('#state', form_id); 254 $el.removeClass('invalid').closest('.form-group').find('.error').remove(); 255 $el.closest('.form-group').find('.selectize-input').removeClass('invalid'); 256 } 257 } 258 }); 259 } 260 } 261 262 } 263 }); 264 $select_country[0].selectize.setValue(current_country); 265 } 266 if ($('#state', form_id).length > 0) { 267 let state_option = key_value_pair_selectize(states[current_country]); 268 if (state_option.length === 0) { 269 $('#state', form_id).replaceWith('<input id="state" name="state" type="text" class="form-control required" placeholder="State" value="'+current_state
269+'" aria-label="State">'); 270 } else { 271 $select_state = $('#state', form_id).selectize({ 272 valueField: 'state_key', 273 labelField: 'state_value', 274 searchField: 'state_value', 275 options: state_option 276 }); 277 $select_state[0].selectize.setValue(current_state); 278 } 279 } 280 }); 281 } 282 283 $(document).ready(function() { 284 285 var originalText; 286 287 var update_form = async function(wrap_id){ 288 289 wrap_id = wrap_id.replace('#', ''); 290 291 $(".sc-stripe-express",'#'+wrap_id).hide(); 292 293 var $item = $('input[name=sc_product_option]:checked', '#'+wrap_id); 294 if(!$item.closest('.item').hasClass('sc-selected')) { 295 $('input[name=sc_product_option]', '#'+wrap_id).each(function(){ 296 $(this).closest('.item').removeClass('sc-selected'); 297 }); 298 $item.closest('.item').addClass('sc-selected'); 299 } 300 301 let form = document.getElementById(wrap_id); 302 form = form.getElementsByTagName('form')[0]; 303 304 var paramObj = new FormData(form); 305 paramObj.set("action", "sc_update_cart_amount"); 306 307 if (typeof sc_tax_settings !== 'undefined' && $('select[name="country"]', '#'+wrap_id).val() != '') { 308 //$('#sc_card_button').addClass('running').attr("disabled", true); 309 var tax_obj = {}, 310 tax_rate_data = {}; 311 tax_obj.country = $('select[name="country"]', '#'+wrap_id).val() ? $('select[name="country"]', '#'+wrap_id).val() : ""; 312 tax_obj.city = $('input[name="city"]', '#'+wrap_id).val() ? $('input[name="city"]', '#'+wrap_id).val() : ""; 313 tax_obj.state = $('select[name="state"]', '#'+wrap_id).val() ? $('select[name="state"]', '#'+wrap_id).val() : ""; 314 tax_obj.zip = $('input[name="zip"]', '#'+wrap_id).val() ? $('input[name="zip"]', '#'+wrap_id).val() : ""; 315 tax_obj.vat_number = $('input[name="vat-number"]', '#'+wrap_id).val() ? $('input[name="vat-number"]', '#'+wrap_id).val() : ""; 316 tax_obj.nonce = sc_tax_settings.nonce; 317 tax_obj.action = 'get_match_tax_rate'; 318 $.ajax({ 319 type: "post", 320 dataType: "json", 321 url: studiocart.ajax, 322 data: tax_obj, 323 success: function(response) { 324 tax_rate_data = response.rates; 325 $('.vat_container', '#'+wrap_id).hide(); 326 let vat_error = "Invalid VAT Number"; 327 $('#vat_number', '#'+wrap_id).removeClass('valid invalid'); 328 $('#vat_number', '#'+wrap_id).parent().find('.error').remove(); 329 if (!response.is_valid_vat) { 330 $('#vat_number', '#'+wrap_id).addClass('invalid'); 331 if (response.vat_error != "") { 332 vat_error = response.vat_error; 333 } 334 if ($('#vat_number', '#'+wrap_id).parent().find('.error').length == 0) { 335 $('#vat_number', '#'+wrap_id).parent().append('<div class="error">' + vat_error + '</div>') 336 } else { 337 $('#vat_number', '#'+wrap_id).parent().find('.error').html(vat_error); 338 } 339 } else if(tax_obj.vat_number != '') { 340 $('#vat_number', '#'+wrap_id).addClass('valid'); 341 } 342 if (response.is_vat) { 343 $('.vat_container', '#'+wrap_id).show(); 344 } 345 346 } 347 }); 348 } 349 350 try { 351 const response = await fetch(studiocart.ajax, { 352 method: 'POST', 353 body:paramObj 354 }); 355 if (response.ok) { 356 const resp = await response.json(); 357 if (resp.order_summary_items) { 358 var container = $('#'+wrap_id).find('.summary-items'), 359 totalContainer = $('#'+wrap_id).find('.total'); 360 361 container.empty(); 362 totalContainer.empty(); 363 364 $('input[name="sc_amount"]', '#'+wrap_id ).val(resp.total); 365 366 if (resp.total == 0 && typeof resp.sub_summary == 'undefined') { 367 $('.pay-info', '#'+wrap_id).hide(); 368 } else { 369 $('.pay-info', '#'+wrap_id).show(); 370 } 371 372 if(resp.total != 0){ 373 $(".sc-stripe-express",'#'+wrap_id).show(); 374 } 375 376 if(resp.order_summary_items.length === 0) { 377 $('.sc-stripe-express', '#'+wrap_id).hide(); 378 $('#sc_card_button', '#'+wrap_id).hide(); 379 container.append('<div class="item"><span class="sc-label">'+resp.empty+'</span></div>'); 380 } else { 381 $('#sc_card_button', '#'+wrap_id).show();
382 resp.order_summary_items.forEach(item => { 383 if(Number(item.quantity) > 1) { 384 item.name += ' x ' + item.quantity; 385 } 386 container.append('<div class="item '+item.type+'"><span class="sc-label">'+item.name+'</span><span class="price">'+item.subtotal+'</span></div>'); 387 }); 388 389 totalContainer.append(resp.total_html); 390 391 if (typeof resp.sub_summary != 'undefined') { 392 totalContainer.append('<small>' + resp.sub_summary + '</small>'); 393 } 394 } 395 } 396 initialExpressPayment('#'+wrap_id); 397 return resp.success; 398 } else { 399 alert('Something went wrong.') 400 } 401 } catch (error) { 402 alert('Something went wrong.') 403 } 404 return false; 405 406 }; 407 408 $(document).on('click', ".studiocart .coupon-code input[type='button']", function(e) { 409 e.preventDefault(); 410 var form = '#'+$(this).closest('form').parent().attr('id'); 411 $(this).attr('disabled', 'disabled'); 412 clear_coupon(form); 413 if ($('#discount-code', form).val() == '') { 414 $(".coupon-code input[type='button']", form).removeAttr('disabled'); 415 } else { 416 try_coupon($('#discount-code', form).val(), form); 417 } 418 }); 419 420 $(document).on('change', "#sc-credit", function() { 421 var form = '#'+$(this).closest('form').parent().attr('id'); 422 if(!$(this).is(':checked')){ 423 clear_coupon(form); 424 $(".coupon-code input[type='button']", form).removeAttr('disabled'); 425 } else { 426 try_coupon('sc-credit', form); 427 } 428 }); 429 430 $(document).on('click', ".sc-password-toggle", function() { 431 var field = $(this).parent().prev('.sc-password'); 432 if ($(this).is(':checked')) { 433 field.attr('type', 'text'); 434 } else { 435 field.attr('type', 'password'); 436 } 437 }); 438 439 $(document).on('change', 'input[name="pay-method"]', function() { 440 var form = '#'+$(this).closest('form').parent().attr('id'); 441 togglePayMethods(form); 442 }); 443 444 $(document).on('click', '#sc-coupon-toggle', function() { 445 var form = '#'+$(this).closest('form').parent().attr('id'); 446 $('#sc-coupon-form', form).fadeToggle(); 447 return false; 448 }); 449 450 //function address_fields() { 451 452 if (typeof sc_popup == 'undefined' || !sc_popup.is_popup || sc_popup.is_popup == "false") { 453 country_selectize(); 454 } else { 455 jQuery(document).on('elementor/popup/show', () => { 456 country_selectize(); 457 }); 458 } 459 //address_fields(); 460 461 function togglePayMethods(form) { 462 var method = $('[name="pay-method"]:checked', form).val(); 463 if (method != 'stripe') { 464 $('.sc-stripe', form).fadeOut(); 465 //$('#paypal-button-container').fadeIn(); 466 } else { 467 $('.sc-stripe', form).fadeIn(); 468 $('#paypal-button-container', form).fadeOut(); 469 } 470 } 471 472 function numberWithThousandsSep(x) { 473 var parts = x.toString().split("."); 474 parts[0] = parts[0].replace(/\B(?=(\d{3)+(?!\d))/g, sc_currency.thousep); 475 return parts.join(sc_currency.decisep); 476 } 477 478 function format_price(amt) { 479 var price; 480 481 // left positioned currency 482 if (sc_currency.position != 'right' && sc_currency.position != 'right-space') { 483 price = sc_currency.symbol; 484 if (sc_currency.position == 'left-space') { 485 // with space 486 price += ' '; 487 } 488 489 // format price
490 price += numberWithThousandsSep(parseFloat(amt).toFixed(sc_currency.decinum)); 491 } 492 493 // right positioned currency 494 if (sc_currency.position == 'right' || sc_currency.position == 'right-space') { 495 496 // format price 497 price = numberWithThousandsSep(parseFloat(amt).toFixed(sc_currency.decinum)); 498 499 if (sc_currency.position == 'right-space') { 500 501 // with space 502 price += ' '; 503 504 } 505 506 // left positioned currency 507 price += sc_currency.symbol; 508 509 } 510 511 // return price 512 return price; 513 } 514 515 $(document).on('change', 'input[name=sc_product_option]', function() { 516 var form = '#'+$(this).closest('form').parent().attr('id'); 517 update_pwyw(form); 518 }); 519 520 function update_pwyw(form) { 521 var dataType = $('input[name=sc_product_option]:checked', form).attr('data-val'); 522 var dataPrice = $('input[name=sc_product_option]:checked', form).attr('data-price'); 523 var id = $('input[name=sc_product_option]:checked', form).attr('id'); 524 var value = $('input[name=sc_product_option]:checked', form).val(); 525 $('.pwyw-input', form).fadeOut(); 526 if (dataType && dataType == 'pwyw') { 527 $('#' + id, form).data('price', dataPrice); 528 $('#pwyw-amount-input-' + value, form).val(dataPrice); 529 $('#pwyw-input-block-' + value, form).fadeIn().focus(); 530 } else { 531 $('#pwyw-input-block-' + value, form).fadeOut(); 532 } 533 } 534 535 // Debounce function to limit how often the function runs 536 function debounce(func, delay) { 537 let debounceTimer; 538 return function() { 539 const context = this; 540 const args = arguments; 541 clearTimeout(debounceTimer); 542 debounceTimer = setTimeout(() => func.apply(context, args), delay); 543 }; 544 } 545 546 $(document).on('change blur focusout', 'input[name^="pwyw_amount"]', function() { 547 var value = $(this).val(); 548 var minvalue = $(this).attr('min'); 549 var id = $('input[name=sc_product_option]:checked').attr('id'); 550 var form = $(this).closest('form').parent().attr('id'); 551 if (parseFloat(value) < parseFloat(minvalue)) { 552 $(this).addClass('invalid'); 553 if ($(this).closest('.item').find('.error').length == 0) 554 $(this).closest('.item').append('<div class="error">Please enter an amount greater than or equal to ' + format_price(parseFloat(minvalue).toFixed(2)) + '</div>') 555 } 556 if (value) { 557 $(this).closest('.item').remove('.error'); 558 $("#" + id).attr('data-price', value); 559 $("#" + id).data('price', value); 560 $("#" + id).parent().find('.price').html('<span class="sc-Price-currencySymbol">$</span>' + parseFloat($("#" + id).attr('data-price')).toFixed(2)); 561 update_form(form); 562 } 563 }); 564 565 $(document).on('input', 'input[name^="pwyw_amount"]', debounce(function() { 566 var form = '#' + $(this).closest('form').parent().attr('id'); 567 // Check Express payment 568 initialExpressPayment(form); 569 }, 1000)); 570 571 $(document).on('change', '#sc_qty, .sc_qty, input[name=sc_product_option], #sc-orderbump, .sc_orderbump, input[data-scq-price],select[name="country"], select[name="state"], input[name="city"], input[name="zip"], input[name="vat-number"]', function() { 572 var form = $(this).closest('form').parent().attr('id'); 573 update_form(form); 574 }); 575 576 $("#discount-code").keydown(function() { 577 $("#coupon-status").text('').hide(); 578 }); 579 580 $(".coupon-code.applied").on("click", "button.coupon", function(e) { 581 var form = $(this).closest('form').parent(); 582 e.preventDefault(); 583 form.find(".coupon-code").show(); 584 }); 585 586 function clear_coupon(form) {
587 $('.coupon-code.applied, .cart-discount', form).hide(); 588 $('#sc-coupon-id', form).val('').removeData('type', 'amount', 'plans'); 589 $("#coupon-status", form).delay(3000).fadeOut(); 590 $('#sc-coupon-id', form).data('type') 591 592 $('#sc-payment-form .products .item', form).each(function() { 593 var $item = $(this).find('input[type="radio"]'), 594 price = $item.data('og-price'); 595 596 if (typeof $item.data('og-price') !== 'undefined') { 597 $(this).find('.price').html(format_price(price)); 598 $item.data('price', price); 599 } 600 $(this).find('.coup-confirm').remove(); 601 }); 602 update_form(form); 603 } 604 605 function try_coupon(coup_code, form) { 606 607 var nonce = $('input[name=sc-nonce]', form).val(), 608 prod_id = $('input[name=sc_product_id]', form).val(), 609 coupon_applied_text, 610 obj = { 611 action: "sc_validate_coupon", 612 prod_id: prod_id, 613 coup_code: coup_code, 614 nonce: nonce, 615 ip: sc_user[0], 616 email: $('#email', form).val(), 617 } 618 619 if (!$('#email').val() && typeof sc_user[1] !== 'undefined') { 620 obj.email = sc_user[1]; 621 } 622 623 $.ajax({ 624 type: "post", 625 dataType: "json", 626 url: studiocart.ajax, 627 data: obj, 628 success: function(response) { 629 if (!response.error) { 630 let coupon_applied = true; 631 if( $('#sc-payment-form .products .item', form).length) { 632 let coupon_applied = false; 633 $('#sc-payment-form .products .item', form).each(function(index) { 634 var new_price, 635 $item = $(this).find('input[type="radio"]'), 636 price = ($item.data('og-price')) ? $item.data('og-price') : $item.data('price'), 637 installments = $item.data('installments'), 638 discount = response.amount; 639 640 if (response.plan && !response.plan.includes($item.val())) { 641 return; 642 } 643 644 coupon_applied_text = format_price(response.amount); 645 646 if (price <= 0 && (response.type == 'percent' || response.type == 'fixed')) { 647 return; 648 } 649 650 coupon_applied = true; 651 652 if (response.type == 'percent' || response.type == 'cart-percent') { 653 coupon_applied_text = response.amount + '%'; 654 } 655 656 if (response.type == 'percent') { 657 discount = price * (discount / 100); 658 } else if (installments && response.amount_recurring) { 659 discount = response.amount_recurring; 660 } 661 662 new_price = (price - discount).toFixed(2); 663 if (new_price < 0) { 664 new_price = (0).toFixed(2); 665 } 666 667 if (response.type != 'cart-percent' && response.type != 'cart-fixed') { 668 if (typeof response.duration !== 'undefined' && installments) { 669 $item.data('duration', response.duration); 670 $item.data('discount', discount); 671 } else { 672 $item.removeData('duration'); 673 } 674 675 $(this).find('.price').html('<s>' + format_price(price) + '</s> ' + format_price(new_price)); 676 $item.data('price', new_price).data('og-price', price); 677 } 678 679 if (response.plan) { 680 var plan_discount;
681 if (response.type != 'cart-percent' && response.type != 'percent') { 682 plan_discount = format_price(discount); 683 } else { 684 plan_discount = response.amount + '%'; 685 } 686 coupon_applied_text = response.code + ' (-' + plan_discount + ')'; 687 $(this).find('coup-confirm').remove(); 688 $(this).find('label').append('<span class="coup-confirm">' + coupon_applied_text + '</span>'); 689 } else { 690 if (typeof response.success_text != 'undefined' && response.success_text != null) { 691 coupon_applied_text = response.success_text; 692 } else { 693 coupon_applied_text = sc_translate_frontend.you_got + ' ' + coupon_applied_text + ' ' + sc_translate_frontend.off; 694 } 695 $(".coupon-code.applied .coup-confirm", form).html(coupon_applied_text).parent().fadeIn(); 696 } 697 698 }); 699 } 700 701 if (coupon_applied) { 702 $('#sc-coupon-id', form).val(response.code); 703 if (response.type == 'cart-percent' || response.type == 'cart-fixed') { 704 $('#sc-coupon-id', form).data('type', response.type).data('amount', response.amount); 705 } 706 if (response.plan) { 707 $('#sc-coupon-id', form).data('plans', response.plan); 708 } 709 $('#sc-payment-form', form).trigger('studiocart/orderform/coupon_applied', [response]); 710 } 711 } else { 712 $("#coupon-status", form).text(response.error).fadeIn(); 713 $('#sc-coupon-id', form).val(''); 714 715 if ($(".coupon-code input[type='button']", form).length > 0) { 716 $(".coupon-code input[type='button']", form).show(); 717 } else { 718 $("#coupon-status", form).delay(3000).fadeOut('normal', function() { 719 $(this).remove(); 720 }); 721 } 722 clear_coupon(form); 723 $('#sc-payment-form', form).trigger('studiocart/orderform/coupon_rejected'); 724 } 725 $(".coupon-code input[type='button']", form).removeAttr('disabled'); 726 update_form(form); 727 } 728 }) 729 } 730 731 $(document).on('click', '.qty-dec, .qty-inc', function(e) { 732 e.preventDefault(); 733 var input = $(this).closest('.my-4').find('input'), 734 val = input.val(), 735 form = $(this).closest('form').parent().attr('id'); 736 737 if($(this).hasClass('qty-dec') && parseInt(val) > 0) { 738 input.val(parseInt(val)-1); 739 update_form(form); 740 } else if($(this).hasClass('qty-inc')) { 741 input.val(parseInt(val)+1); 742 update_form(form); 743 } 744 return false; 745 }); 746 747 /* Change Vat Customer Type */ 748 $(document).on('change', 'input[name="vat-number-available"]', function() { 749 if (this.checked) { 750 $('.vat_number_field').fadeIn(0); 751 } else { 752 $('.vat_number_field').fadeOut(0); 753 } 754 }); 755 756 // remove error message on focus 757 $(document).on('focus', '#sc-payment-form input, #sc-payment-form select', function() { 758 $(this).closest('.checkbox-wrap').removeClass('invalid').siblings('.error').remove(); 759 $(this).removeClass('invalid valid').siblings('.error').remove(); 760 $(this).closest('.form-group').find('input').removeClass('invalid') 761 $(this).closest('.form-group').find('.error').remove() 762 763 if ($(this).attr('id') == 'address1') { 764 $('.sc-address-2 .error').remove(); 765 } 766 767 if ($(this).hasClass('selectized')) { 768 $(this).next('.selectize-control').find('.selectize-input').removeClass('invalid'); 769 } 770 }); 771
772 function invalidate_field($field, message) { 773 $field.removeClass('invalid').siblings('.error').remove(); 774 775 if (($field.attr('type') == 'checkbox' && !$field.is(':checked'))) { 776 $field.closest('.checkbox-wrap').addClass('invalid').append('<div class="error">' + message + '</div>'); 777 } else { 778 var $el = $field; 779 if ($field.attr('id') == 'address1' && $('.single-sc_product').length > 0) { 780 $el = $('#sc-payment-form #address2'); 781 } 782 $field.addClass('invalid'); 783 $el.closest('.form-group').append('<div class="error">' + message + '</div>'); 784 if ($field.hasClass('selectized')) { 785 $field.next('.selectize-control').find('.selectize-input').addClass('invalid'); 786 } 787 if ($field.closest('#customer-details.sc-checkout-step').length > 0 && $('.step-two').hasClass('sc-current')) { 788 $('.steps.step-one a').click(); 789 } 790 } 791 } 792 793 // check required on blur 794 $(document).on('blur', '#sc-payment-form input.required', function() { 795 $(this).removeClass('invalid').siblings('.error').remove(); 796 797 if (($(this).attr('type') == 'checkbox' && !$(this).is(':checked'))) { 798 $(this).closest('.checkbox-wrap').addClass('invalid').append('<div class="error">' + sc_translate_frontend.field_required + '</div>'); 799 } else if (($(this).val().length < 1)) { 800 var $el = $(this); 801 if ($(this).attr('id') == 'address1' && $('.single-sc_product').length > 0) { 802 $el = $('#sc-payment-form #address2'); 803 } 804 $(this).addClass('invalid'); 805 $el.closest('.form-group').append('<div class="error">' + sc_translate_frontend.field_required + '</div>'); 806 } 807 }); 808 809 // check username on blur 810 $(document).on('blur', '#sc-wpuserid', function() { 811 $(this).removeClass('invalid valid').siblings('.error').remove(); 812 813 if (($(this).val().length > 0)) { 814 checkUsername($(this)); 815 } 816 }); 817 818 $(document).on('click', '.sc-checkout-form-steps .steps', async function(event) { 819 event.preventDefault(); 820 var form_wrapper = $(this).closest('.sc-form-wrap').attr('id'); 821 if ($(this).hasClass('step-two')) { 822 var errors = await sc_validate(form_wrapper); 823 if (errors) { 824 return false; 825 } else if (!$('[name="sc-lead-captured"]', '#'+form_wrapper).length) { 826 sc_do_lead_capture(form_wrapper); 827 } 828 } 829 830 if ($(this).hasClass('sc-current')) { 831 return false; 832 } 833 834 $('#sc-payment-form', '#'+form_wrapper).toggleClass('step-1 step-2'); 835 $('.sc-checkout-form-steps .steps', '#'+form_wrapper).toggleClass('sc-current'); 836 return false; 837 838 }); 839 840 async function checkUsername($el) { 841 $el.removeClass('valid'); 842 843 var paramObj = new FormData(); 844 paramObj.append('name', $el.val()); 845 paramObj.append('sc-nonce', $('input[name=sc-nonce]').val()); 846 paramObj.append('action', 'sc_check_username'); 847 848 try { 849 const response = await fetch(studiocart.ajax, { 850 method: 'POST', 851 body:paramObj 852 }); 853 if (response.ok) { 854 const resp = await response.json(); 855 if (resp.success) { 856 $el.addClass('valid'); 857 $('#sc_card_button, .sc-next-btn').removeAttr("disabled"); 858 } else{ 859 $el.addClass('invalid'); 860 $el.closest('.form-group').append('<div class="error">' + resp.data.error + '</div>'); 861 $('#sc_card_button, .sc-next-btn').attr("disabled", true); 862 } 863 return resp.success; 864 } else { 865 alert('Something went wrong.') 866 $el.addClass('invalid'); 867 $('#sc_card_button, .sc-next-btn').attr("disabled", true); 868 } 869 } catch (error) { 870 alert('Something went wrong.') 871 $el.addClass('invalid'); 872 $('#sc_card_button, .sc-next-btn').attr("disabled", true); 873 } 874 return false;
875 } 876 877 // check email address 878 $(document).on('blur', '#sc-payment-form input[type="email"]', function() { 879 if ($(this).val().length < 1) return; 880 881 var val = $(this).val(); 882 var validEmail = regExEmail.test(val); 883 if (!validEmail) { 884 $(this).addClass('invalid').closest('.form-group').append('<div class="error">' + sc_translate_frontend.invalid_email + '</div>'); 885 } 886 }); 887 888 // check phone number 889 $(document).on('blur', '#sc-payment-form input[type="tel"]', function() { 890 if ($(this).val().length < 1) return; 891 892 var val = $(this).val(); 893 var validPhone = isValidPhonenumber(val); 894 if (!validPhone) { 895 $(this).addClass('invalid').closest('.form-group').append('<div class="error">' + sc_translate_frontend.invalid_phone + '</div>'); 896 } 897 }); 898 899 // check password 900 $(document).on('blur', '#sc-payment-form input.sc-password', function() { 901 var val = $(this).val(); 902 if (val.length) { 903 var validPass = isValidPassword(val); 904 if (!validPass) { 905 $(this).addClass('invalid').closest('.form-group').append('<div class="error">' + sc_translate_frontend.invalid_pass + '</div>'); 906 } 907 } 908 }); 909 910 /* track any change to total amount due 911 $(document).on('change', '#sc-payment-form input', function() { 912 amount = false; 913 });*/ 914 915 /* <fs_premium_only> */ 916 917 /* Assign the class & link to specific button */ 918 var accept_links = $('a[href*="sc-upsell-offer=yes"]'); 919 920 if (accept_links.length > 0 && 'undefined' !== typeof studiocart.upsell_accept) { 921 accept_links.addClass('sc-accept-upsell-link'); 922 accept_links.attr('href', studiocart.upsell_accept); 923 $('.sc-accept-upsell-link').trigger('studiocart/upsell/ready/accept_link'); 924 } 925 926 var decline_links = $('a[href*="sc-upsell-offer=no"]'); 927 928 if (decline_links.length > 0 && 'undefined' !== typeof studiocart.upsell_decline) { 929 decline_links.addClass('sc-decline-upsell-link'); 930 decline_links.attr('href', studiocart.upsell_decline); 931 $('.sc-decline-upsell-link').trigger('studiocart/upsell/ready/decline_link'); 932 } 933 934 /* </fs_premium_only> */ 935 936 async function sc_validate(form_wrapper) { 937 var errors = false; 938 939 if ($('.elementor-editor-active').length > 0) { 940 return errors; 941 } 942 943 $(".error").remove(); 944 $('#'+form_wrapper+' input').removeClass('invalid'); 945 946 var fields = $('#'+form_wrapper+' input.required:visible, #'+form_wrapper+' select.required:visible, #'+form_wrapper+' select.required.selectized'); 947 fields.each(function () { 948 if ($(this).attr('type') == 'checkbox' && !$(this).is(':checked')) { 949 if($(this).attr('name').endsWith('[]')) { 950 if($('#'+form_wrapper+' input[name="'+$(this).attr('name')+'"]:checked').length < 1) { 951 $(this).addClass('invalid'); 952 if ($(this).closest('.form-group').find('.error').length == 0) 953 $(this).closest('.form-group').append('<div class="error">' + sc_translate_frontend.field_required + '</div>'); 954 errors = true; 955 } 956 } else { 957 $(this).closest('.checkbox-wrap').addClass('invalid').append('<div class="error">' + sc_translate_frontend.field_required + '</div>'); 958 errors = true; 959 } 960 } else if ($(this).attr('type') == 'radio' && !$(this).is(':checked') && $('#'+form_wrapper+' input[name="'+$(this).attr('name')+'"]:checked').length < 1) { 961 $(this).addClass('invalid'); 962 if ($(this).closest('.form-group').find('.error').length == 0) 963 $(this).closest('.form-group').append('<div class="error">' + sc_translate_frontend.field_required + '</div>'); 964 errors = true; 965 } else if ($(this).attr('name') == 'pwyw_amount') { 966 var value = $(this).val(); 967 var minvalue = $(this).attr('min'); 968 if (parseFloat(value) < parseFloat(minvalue)) { 969 $(this).addClass('invalid'); 970 if ($(this).closest('.form-group').find('.error').length == 0) 971 $(this).closest('.form-group').append('<div class="error">Please enter an amount greater thank or equal to <span class="sc-Price-currencySymbol">$</span>' + parseFloat(minvalue).toFixed(2) + '</div>') 972 errors = true; 973 } 974 } else if ($(this).val().length < 1) { 975 var $el = $(this); 976 if ($(this).attr('id') == 'address1' && $('.single-sc_product').length > 0) { 977 $el = $('#'+form_wrapper+' #address2'); 978 } 979 $(this).addClass('invalid'); 980 $el.closest('.form-group').append('<div class="error">' + sc_translate_frontend.field_required + '</div>'); 981 if ($(this).hasClass('selectized')) { 982 $(this).next('.selectize-control').find('.selectize-input').addClass('invalid'); 983 } 984 errors = true; 985 } 986 }); 987 988 // check username 989 if ($('#'+form_wrapper+' #sc-wpuserid').length > 0) { 990 var $username = $('#'+form_wrapper+' #sc-wpuserid'); 991 if (($username.val().length > 0)) { 992 var check = await checkUsername($username); 993 if (check == false) { 994 errors = true; 995 } 996 } 997 } 998 999 // check email address 1000 $('#'+form_wrapper+' input[type="email"]').each(function () { 1001 if ($(this).val().length) {
1002 var validEmail = regExEmail.test($(this).val()); 1003 if (!validEmail) { 1004 $(this).addClass('invalid').closest('.form-group').append('<div class="error">' + sc_translate_frontend.invalid_email + '</div>'); 1005 errors = true; 1006 } 1007 } 1008 }); 1009 1010 // check phone number 1011 $('#'+form_wrapper+' input[type="phone"]').each(function () { 1012 if ($(this).val().length) { 1013 var validPhone = isValidPhonenumber($(this).val()); 1014 if (!validPhone) { 1015 $(this).addClass('invalid').closest('.form-group').append('<div class="error">' + sc_translate_frontend.invalid_phone + '</div>'); 1016 errors = true; 1017 } 1018 } 1019 }); 1020 1021 1022 // check password 1023 $('#'+form_wrapper+' input.sc-password').each(function () { 1024 if ($(this).val().length) { 1025 var validPass = isValidPassword($(this).val()); 1026 if (!validPass) { 1027 $(this).addClass('invalid').closest('.form-group').append('<div class="error">' + sc_translate_frontend.invalid_pass + '</div>'); 1028 errors = true; 1029 } 1030 } 1031 }); 1032 1033 if($('#'+form_wrapper+' input').closest('.form-group').find('.error').length>0){ 1034 errors = true; 1035 } 1036 1037 return errors; 1038 } 1039 1040 // 2 step form 1041 $(document).on('click', '.sc-next-btn', async function () { 1042 var form_wrapper = $(this).data('form-wrapper'); 1043 var errors = await sc_validate(form_wrapper); 1044 if (errors) { 1045 return; 1046 } else { 1047 if (!$('[name="sc-lead-captured"]', '#'+form_wrapper).length) { 1048 sc_do_lead_capture(form_wrapper); 1049 } 1050 $('#sc-payment-form', '#'+form_wrapper).toggleClass('step-1 step-2'); 1051 $('.sc-checkout-form-steps .steps', '#'+form_wrapper).toggleClass('sc-current'); 1052 } 1053 }); 1054 1055 function sc_do_lead_capture(wrap_id) { 1056 var form = '#'+wrap_id; 1057 var paramObj = {}; 1058 $.each($('#sc-payment-form', form).serializeArray(), function(_, kv) { 1059 paramObj[kv.name] = kv.value; 1060 }); 1061 1062 paramObj['action'] = 'sc_capture_lead'; 1063 1064 $.post(studiocart.ajax, paramObj, function(response) { 1065 //console.log('capturing lead'); 1066 if (response == 'OK') { 1067 $('#sc-payment-form', form).trigger('studiocart/orderform/lead_captured'); 1068 var form = document.getElementById(wrap_id); 1069 form = form.getElementsByTagName('form')[0]; 1070 1071 var hiddenInput = document.createElement('input'); 1072 hiddenInput.setAttribute('type', 'hidden'); 1073 hiddenInput.setAttribute('name', 'sc-lead-captured'); 1074 hiddenInput.setAttribute('value', 1); 1075 form.appendChild(hiddenInput); 1076 } 1077 }); 1078 return true; 1079 } 1080 1081 // check pay info 1082 var $btn, 1083 $form, 1084 clientSecret, 1085 intent_id, 1086 amount, 1087 customer_id, 1088 sc_temp_order_id, 1089 prod_id, 1090 paymentMethodId; 1091 1092 if ($('.sc-stripe #card-element').length > 0 || $('.sc-stripe-express #express-pay-element').length > 0) { 1093 // Create a Stripe client. 1094 var stripe = Stripe(stripe_key[0]); 1095 var card = {}; 1096 } 1097 1098 $('.sc-form-wrap').each(function(){ 1099 1100 let form_id = $(this).attr('id'); 1101 let form = '#'+form_id; 1102 1103 // toggle pay methods 1104 togglePayMethods(form); 1105 1106 if (typeof sc_coupon !== 'undefined') { 1107 try_coupon(sc_coupon[0], form); 1108 } else { 1109 update_pwyw(form); 1110 update_form(form); 1111 } 1112 1113 // check pay info 1114 var $btn = $('#sc_card_button', form); 1115 $form = $('#sc-payment-form', form); 1116 1117 if ($('.sc-stripe #card-element', form).length > 0) { 1118 1119 $('.sc-stripe #card-element', form).each(function(){ 1120 1121 let form_wrapper = form_id; 1122 // Create an instance of Elements. 1123 var elements = stripe.elements();
1124 let $this = "#"+form_wrapper+" #card-element"; 1125 1126 // Custom styling can be passed to options when creating an Element. 1127 // (Note that this demo uses a wider set of styles than the guide below.) 1128 var style = { 1129 base: { 1130 color: '#32325d', 1131 fontFamily: '"Helvetica Neue", Helvetica, sans-serif', 1132 fontSmoothing: 'antialiased', 1133 fontSize: '16px', 1134 '::placeholder': { 1135 color: '#aab7c4' 1136 } 1137 }, 1138 invalid: { 1139 color: '#fa755a', 1140 iconColor: '#fa755a' 1141 } 1142 }; 1143 1144 // Create an instance of the card Element. 1145 card[form_wrapper] = elements.create('card', { style: style }); 1146 1147 // Add an instance of the card Element into the `card-element` <div>. 1148 1149 card[form_wrapper].mount($this); 1150 1151 // Handle real-time validation errors from the card Element. 1152 card[form_wrapper].addEventListener('change', function (event) { 1153 var displayError = document.querySelector("#"+form_wrapper+" #card-errors"); 1154 if (event.error) { 1155 displayError.textContent = event.error.message; 1156 } else { 1157 displayError.textContent = ''; 1158 } 1159 }); 1160 1161 // Reinitialize Stripe elements for forms inside Elementor popups 1162 jQuery(document).on('elementor/popup/show', () => { 1163 1164 card[form_wrapper].unmount($this); 1165 card[form_wrapper].mount($this); 1166 1167 // Handle real-time validation errors from the card Element. 1168 card[form_wrapper].addEventListener('change', function (event) { 1169 var displayError = document.querySelector("#"+form_wrapper+" #card-errors"); 1170 if (event.error) { 1171 displayError.textContent = event.error.message; 1172 } else { 1173 displayError.textContent = ''; 1174 } 1175 }); 1176 1177 // 100ms delay for open popup animation 1178 setTimeout(() => { 1179 if (typeof sc_coupon !== 'undefined') { 1180 try_coupon(sc_coupon[0], "#"+form_wrapper); 1181 } else { 1182 update_pwyw("#"+form_wrapper); 1183 update_form(form_wrapper); 1184 } 1185 }, 100); 1186 }); 1187 }); 1188 } 1189 1190 function onloadCallback() { 1191 grecaptcha.ready(function() { 1192 var gsitekey = $(".sc-grtoken").attr("data-sitekey"); 1193 grecaptcha.execute(gsitekey, { action: 'submit' }).then(function(token) { 1194 $(".sc-grtoken", form).val(token); 1195 }); 1196 }); 1197 } 1198 1199 // Handle form submission. 1200 $(document).on('click', form + ' #sc_card_button', async function(event) { 1201 1202 $btn = $(this); 1203 originalText = $btn.find('span.text').text(); 1204 $btn.addClass('running').attr("disabled", true); 1205 $btn.find('span.text').text(sc_translate_frontend.loading_processing); 1206 1207 event.preventDefault(); 1208 var form_wrapper = $btn.data('form-wrapper'); 1209 var errors = await sc_validate(form_wrapper); 1210 var form = '#'+form_wrapper; 1211 1212 if (errors) { 1213 alert(sc_translate_frontend.missing_required); 1214 $btn.removeClass('running').removeAttr("disabled"); 1215 $btn.find('span.text').text(originalText); 1216 return false;
1217 } 1218 1219 if(jQuery(".g-recaptcha", form).length>0){ 1220 var gcaptchasize = jQuery(".g-recaptcha", form).attr("data-size"); 1221 if (gcaptchasize == "invisible") { 1222 grecaptcha.ready(function() { 1223 grecaptcha.execute(); 1224 }); 1225 } 1226 } 1227 1228 if ($(".sc-grtoken", form).length > 0) { 1229 grecaptcha.ready(function() { 1230 var gsitekey = $(".sc-grtoken", form).attr("data-sitekey"); 1231 grecaptcha.execute(gsitekey, { action: 'submit' }).then(function(token) { 1232 $(".sc-grtoken", form).val(token); 1233 }); 1234 }); 1235 } 1236 1237 setTimeout(function() { 1238 1239 var is_subscription = $('.ob-sub:checked', form).length || ($('input[name="sc_product_option"]:checked', form).data('installments') && !$('.ob-replace:checked', form).length); 1240 1241 if ($('#sc-payment-form [name="pay-method"]', form).length > 0) { 1242 if ($('[name="pay-method"]:checked', form).val() != 'stripe' && ($('[name="sc_amount"]', form).val() != 0 || is_subscription) && $('[name="pay-method"]:checked', form).val() != 'cod') { 1243 $('#sc-payment-form', form).trigger('studiocart/orderform/submit'); 1244 return false; 1245 } 1246 } 1247 1248 var paramObj = $('#sc-payment-form', form).serializeArray(); 1249 1250 // process free payment, manual payment methods 1251 var manual = ($('#sc-payment-form [name="pay-method"]:checked', form).val() == 'cod'), 1252 plan = $('input[name=sc_product_option]:checked', form); 1253 1254 if ($('[name="sc_amount"]', form).val() == 0 && !is_subscription || manual) { 1255 paramObj.push( 1256 { name: "action", value: "save_order_to_db" }, 1257 { name: "pay-method", value: "cod" } // change method to "COD", otherwise order will get stuck in "pending" status 1258 ); 1259 1260 $.post(studiocart.ajax, paramObj, function(res) { 1261 var response = JSON.parse(res); 1262 if ('undefined' !== typeof response.error) { 1263 alert(response.error); 1264 1265 if ('undefined' !== typeof response.fields) { 1266 $.each(response.fields, function(i, item) { 1267 invalidate_field($('[name="' + item['field'] + '"]', form), item['message']) 1268 }); 1269 } 1270 1271 $btn = $('#sc_card_button', form); 1272 $btn.removeClass('running').removeAttr("disabled"); 1273 $btn.find('span.text').text(originalText); 1274 } else { 1275 if ('undefined' !== typeof response.redirect) { 1276 window.location.href = response.redirect; 1277 } else { 1278 // var formEl = document.getElementById(form_wrapper).firstChild; 1279 1280 if ('undefined' !== typeof response.formAction) { 1281 $form = $('#sc-payment-form', form); 1282 $form.attr('action', response.formAction); 1283 } 1284 var hiddenInput = document.createElement('input'); 1285 hiddenInput.setAttribute('type', 'hidden'); 1286 hiddenInput.setAttribute('name', 'sc_order_id'); 1287 hiddenInput.setAttribute('value', response.order_id); 1288 $form.append(hiddenInput); 1289 $form.submit(); 1290 } 1291 } 1292 }); 1293 return false;
1294 } 1295 1296 paramObj.push({name: "action", value: "create_payment_intent"}); 1297 1298 if (!intent_id) { 1299 1300 // create new intent if none found 1301 $.post(studiocart.ajax, paramObj, function(res) { 1302 1303 var response = JSON.parse(res); 1304 if ('undefined' !== typeof response.error) { 1305 alert(response.error); 1306 if ('undefined' !== typeof response.fields) { 1307 $.each(response.fields, function(i, item) { 1308 invalidate_field($('[name="' + item['field'] + '"]', form), item['message']) 1309 }); 1310 } 1311 $btn.removeClass('running').removeAttr("disabled"); 1312 $btn.find('span.text').text(originalText); 1313 return false; 1314 } else { 1315 if ('undefined' !== typeof response.redirect) { 1316 window.location.href = response.redirect; 1317 } else { 1318 clientSecret = response.clientSecret; 1319 intent_id = response.intent_id; 1320 customer_id = response.customer_id; 1321 amount = response.amount; 1322 sc_temp_order_id = response.sc_temp_order_id; 1323 prod_id = response.prod_id; 1324 1325 if (is_subscription) { 1326 confirmSubscription(response, false, false, form_wrapper); 1327 } else { 1328 // create new order in db then send to stripe 1329 saveThenConfirm(response, form_wrapper); 1330 } 1331 } 1332 } 1333 }); 1334 } else { 1335 1336 var intent = { 1337 'clientSecret': clientSecret, 1338 'intent_id': intent_id, 1339 'customer_id': customer_id, 1340 'amount': amount, 1341 'prod_id':prod_id, 1342 'sc_temp_order_id':sc_temp_order_id 1343 }; 1344 1345 if (is_subscription) { 1346 // If a previous payment was attempted, get the lastest invoice 1347 const latestInvoicePaymentIntentStatus = localStorage.getItem( 1348 'latestInvoicePaymentIntentStatus' 1349 ); 1350 1351 if ( 1352 latestInvoicePaymentIntentStatus === 'requires_payment_method' || 1353 latestInvoicePaymentIntentStatus === 'requires_action' 1354 ) { 1355 const invoiceId = localStorage.getItem('latestInvoiceId'); 1356 const isPaymentRetry = true; 1357 // create new payment method & retry payment on invoice with new payment method 1358 confirmSubscription( 1359 intent, 1360 isPaymentRetry, 1361 invoiceId, 1362 form_wrapper 1363 ); 1364 } else { 1365 confirmSubscription(intent, false, false, form_wrapper); 1366 } 1367 } else { 1368 if ($('input[name=order_id]').length == 0) { 1369 // create new order in db then send to stripe 1370 saveThenConfirm(intent, form_wrapper); 1371 } else { 1372 if (!amount) { 1373 paramObj['action'] = 'update_payment_intent_amt'; 1374 paramObj['intent_id'] = intent.intent_id; 1375 $.post(studiocart.ajax, paramObj, function(amt) { 1376 if (!isNaN(amt)) { 1377 amount = amt; 1378 intent.amount = amt; 1379 } 1380 }); 1381 } 1382 1383 // create new order in db then send to
1383stripe 1384 confirmCardPayment(intent, form_wrapper); 1385 } 1386 } 1387 } 1388 1389 }, 1000); 1390 1391 }); 1392 }); 1393 1394 $('.sc_cancel_sub').click(function() { 1395 1396 if (confirm(sc_translate_frontend.confirm_cancel_sub)) { 1397 var ajaxurl = studiocart.ajax; 1398 var _this = $(this); 1399 var id = _this.data('id'); 1400 var wp_nonce = jQuery("#sc_nonce").val(); 1401 var subscriber_id = (_this.data('item-id')) ? _this.data('item-id') : $("#sc_payment_intent").val(); 1402 var payment_method = jQuery("#sc_payment_method").val(); 1403 var prod_id = jQuery("#sc_product_id").val(); 1404 1405 var data = { 1406 'action': 'sc_unsubscribe_customer', 1407 'prod_id': prod_id, 1408 'subscription_id': subscriber_id, 1409 'nonce': wp_nonce, 1410 'id': id, 1411 'payment_method': payment_method, 1412 }; 1413 1414 // We can also pass the url value separately from ajaxurl for front end AJAX implementations 1415 jQuery.post(ajaxurl, data, function(response) { 1416 console.log(response); 1417 if (response == 'OK') { 1418 alert(sc_translate_frontend.sub_cancel); //custom message 1419 location.reload(); 1420 } else { 1421 alert(response); 1422 } 1423 }).fail(function() { 1424 alert(response.fail); 1425 }); 1426 } else { 1427 return false; 1428 } 1429 }); 1430 1431 /** 1432 * Pause Start Subscription 1433 */ 1434 $('.sc_pause_restart_sub').click(function(){ 1435 1436 var confirmMessage = sc_translate_frontend.confirm_pause_sub; 1437 var successMessage = sc_translate_frontend.sub_paused; 1438 var type = $(this).data('action'); 1439 1440 if(type == 'started'){ 1441 confirmMessage = sc_translate_frontend.confirm_activate_sub; 1442 successMessage = sc_translate_frontend.sub_started; 1443 } 1444 1445 if (confirm(confirmMessage)) { 1446 var ajaxurl = studiocart.ajax; 1447 var _this = $(this); 1448 var id = _this.data('id'); 1449 var wp_nonce = jQuery("#sc_nonce").val(); 1450 var payment_method = jQuery("#sc_payment_method").val(); 1451 var prod_id = jQuery("#sc_product_id").val(); 1452 1453 var data = { 1454 'action': 'sc_pause_restart_subscription', 1455 'prod_id': prod_id, 1456 'nonce': wp_nonce, 1457 'id': id, 1458 'payment_method': payment_method, 1459 'type':type, 1460 }; 1461 1462 // We can also pass the url value separately from ajaxurl for front end AJAX implementations 1463 jQuery.post(ajaxurl, data, function(response) { 1464 console.log(response); 1465 if( response == 'OK' ){ 1466 alert(successMessage); //custom message 1467 location.reload(); 1468 }else{ 1469 alert(response); 1470 } 1471 }).fail(function() { 1472 alert(response.fail); 1473 }); 1474 } else { 1475 return false; 1476 } 1477 }); 1478 1479 $('input.required, select.required, input[type="checkbox"].required').on('keyup change', async function () { 1480 var form = $(this).closest('form').parent().attr('id'); 1481 let $this = "#"+form+" #express-pay-element"; 1482 var errors = await sc_validate(form); 1483 if (errors) { 1484 $($this).css('pointer-events', 'none'); 1485 }else{ 1486 $($this).css('pointer-events', ''); 1487 } 1488 }); 1489 1490 // Express Payment Onload 1491 function initialExpressPayment(form_wrapper) { 1492 if ($('.sc-stripe-express #express-pay-element', form_wrapper).length > 0) { 1493 $('.sc-stripe-express #express-pay-element', form_wrapper).each(function(){ 1494 $(this).hide();
1495 let $this = form_wrapper+" #express-pay-element"; 1496 const elements = stripe.elements(); 1497 const form = form_wrapper.replace('#', ''); 1498 var product_name = $(form_wrapper + ' [name="sc_product_name"]').val(); 1499 var amount = Math.round(parseFloat($('input[name=sc_amount]', form_wrapper).val()) * 100); 1500 var country = $('input[name=sc_currency_country_code]', form_wrapper).val().toUpperCase(), 1501 currency = $('input[name=sc_currency_code]', form_wrapper).val().toLowerCase(); 1502 if(currency && country){ 1503 const paymentRequest = stripe.paymentRequest({ 1504 country: country, 1505 currency: currency, 1506 total: { 1507 label: product_name, 1508 amount: amount, 1509 }, 1510 requestPayerName: true, 1511 requestPayerEmail: true 1512 }); 1513 1514 $($this).css('pointer-events', 'none'); 1515 1516 card[form_wrapper] = elements.create('paymentRequestButton', { 1517 paymentRequest: paymentRequest, 1518 style: { 1519 paymentRequestButton: { 1520 type: 'default', 1521 theme: 'dark', 1522 height: '45px', 1523 }, 1524 }, 1525 }); 1526 paymentRequest.canMakePayment().then(result => { 1527 console.log('Can make payment result ::', result); 1528 if (result && result.link) { 1529 // Link is supported 1530 card[form_wrapper].mount($this); 1531 $($this).show(); 1532 } else { 1533 // Link is not supported (country issue) 1534 $($this).hide(); 1535 1536 // Show custom message or disable the button 1537 var message = "Sorry, Express Payment is not supported in your region."; 1538 // You can append this message to a specific element in your form or show it in a modal 1539 $('#payment-method-message', form_wrapper).text(message).show(); 1540 1541 // Optionally disable or hide other parts of the UI 1542 $('#sc_card_button', form_wrapper).prop('disabled', true); 1543 } 1544 }).catch(error => { 1545 console.error('Error checking payment capability:', error); 1546 $($this).hide(); 1547 1548 // Optional: Show a different message for error scenarios 1549 $('#payment-method-message', form_wrapper).text("An error occurred while processing your payment options. Please try again.").show(); 1550 }); 1551 paymentRequest.on('paymentmethod', async (ev) => { 1552 try { 1553 $($this).css('pointer-events', 'none'); 1554 $('#sc_card_button', form_wrapper).addClass('running').attr('disabled', 'disabled'); 1555 // Validation 1556 var errors = await sc_validate(form); 1557 if (errors) { 1558 $($this).css('pointer-events', ''); 1559 $('#sc_card_button', form_wrapper).removeClass('running').removeAttr("disabled"); 1560 alert(sc_translate_frontend.missing_required); 1561 return ev.complete('fail'); 1562 } 1563 if(jQuery(".g-recaptcha", form_wrapper).length>0){ 1564 var gcaptchasize = jQuery(".g-recaptcha", form_wrapper).attr("data-size"); 1565 if (gcaptchasize == "invisible") { 1566 grecaptcha.ready(function() { 1567 grecaptcha.execute(); 1568 }); 1569 } 1570 } 1571 if ($(".sc-grtoken", form_wrapper).length > 0) { 1572 grecaptcha.ready(function() { 1573 var gsitekey = $(".sc-grtoken", form_wrapper).attr("data-sitekey"); 1574 grecaptcha.execute(gsitekey, { action: 'submit' }).then(function(token) { 1575 $(".sc-grtoken", form_wrapper).val(token); 1576 }); 1577 }); 1578 } 1579 setTimeout(function() { 1580 var is_subscription = $('.ob-sub:checked', form_wrapper).length || ($('input[name="sc_product_option"]:checked', form_wrapper).data('installments') && !$('.ob-replace:checked', form_wrapper).length); 1581 var paramObj = $('#sc-payment-form', form_wrapper).serializeArray(); 1582 var paymentMethod = ev.paymentMethod; 1583 paymentMethodId = paymentMethod['id']; 1584 paramObj.push({name: "action", value: "create_payment_intent"}); 1585 paramObj.push({name: "sc_payment_method_id", value: paymentMethodId}); 1586 paramObj.find(input => input.name == 'pay-method').value = "stripe"; 1587 1588 if (!intent_id) { 1589 // create new intent if none found 1590 $.post(studiocart.ajax, paramObj, function(res) { 1591 var response = JSON.parse(res); 1592 response.paymentMethodId = paymentMethodId; 1593 if ('undefined' !== typeof response.redirect) { 1594 window.location.href = response.redirect; 1595 } else { 1596 clientSecret = response.clientSecret; 1597 intent_id = response.intent_id; 1598 customer_id = response.customer_id; 1599 amount = response.amount; 1600 sc_temp_order_id = response.sc_temp_order_id; 1601 prod_id = response.prod_id; 1602 if (is_subscription) { 1603 // Create the subscription 1604 createSubscription( 1605 customer_id, 1606 paymentMethodId, 1607 false, 1608 form, 1609 ev 1610 ); 1611 } else { 1612 // create new order in db then send to
1612stripe 1613 $btn = $(form_wrapper + ' #sc_card_button').data('form-wrapper'); 1614 saveThenConfirm(response, $btn, true, ev); 1615 } 1616 } 1617 }).fail(function(jqXHR, textStatus, errorThrown) { 1618 ev.complete('fail'); 1619 $($this).css('pointer-events', ''); 1620 $('#sc_card_button', form_wrapper).removeClass('running').removeAttr("disabled"); 1621 console.error('Error confirming the payment method:', textStatus, errorThrown); 1622 alert('An unexpected error occurred.'); 1623 }); 1624 } else { 1625 var intent = { 1626 'clientSecret': clientSecret, 1627 'intent_id': intent_id, 1628 'customer_id': customer_id, 1629 'amount': amount, 1630 'prod_id':prod_id, 1631 'sc_temp_order_id':sc_temp_order_id, 1632 'paymentMethodId' : paymentMethodId 1633 }; 1634 if (is_subscription) { 1635 // If a previous payment was attempted, get the lastest invoice 1636 const latestInvoicePaymentIntentStatus = localStorage.getItem( 1637 'latestInvoicePaymentIntentStatus' 1638 ); 1639 if ( 1640 latestInvoicePaymentIntentStatus === 'requires_payment_method' || 1641 latestInvoicePaymentIntentStatus === 'requires_action' 1642 ) { 1643 const invoiceId = localStorage.getItem('latestInvoiceId'); 1644 const isPaymentRetry = true; 1645 // create new payment method & retry payment on invoice with new payment method 1646 confirmSubscription( 1647 intent, 1648 isPaymentRetry, 1649 invoiceId, 1650 form, 1651 ev 1652 ); 1653 } else { 1654 confirmSubscription(intent, false, false, form, ev); 1655 } 1656 } else { 1657 if ($('input[name=order_id]').length == 0) { 1658 // create new order in db then send to stripe 1659 $btn = $(form_wrapper + ' #sc_card_button').data('form-wrapper'); 1660 saveThenConfirm(intent, $btn, true, ev); 1661 } else { 1662 if (!amount) { 1663 paramObj['action'] = 'update_payment_intent_amt'; 1664 paramObj['intent_id'] = intent.intent_id; 1665 $.post(studiocart.ajax, paramObj, function(amt) { 1666 if (!isNaN(amt)) { 1667 amount = amt; 1668 intent.amount = amt; 1669 } 1670 }); 1671 } 1672 // create new order in db then send to
1672stripe 1673 confirmCardPayment(intent, form, true, ev); 1674 } 1675 } 1676 } 1677 }, 1000); 1678 } catch (error) { 1679 console.error('Error confirming the payment method:', error); 1680 ev.complete('fail'); 1681 $($this).css('pointer-events', ''); 1682 $('#sc_card_button', form_wrapper).removeClass('running').removeAttr("disabled"); 1683 alert('An unexpected error occurred.'); 1684 } 1685 }); 1686 } 1687 }); 1688 } 1689 } 1690 1691 function saveThenConfirm(intent, form_wrapper, isExpresspayment, ev) { 1692 confirmCardPayment(intent, form_wrapper, isExpresspayment, ev); 1693 } 1694 1695 function createSubscription(customerId, paymentMethodId, invoiceId, wrap_id, ev) { 1696 var f = document.getElementById(wrap_id); 1697 f = f.getElementsByTagName('form')[0]; 1698 const form = new FormData(f); 1699 form.set('action', 'create_subscription'); 1700 form.set('customerId', customerId); 1701 form.set('paymentMethodId', paymentMethodId); 1702 if (invoiceId) { 1703 form.set('invoiceId', invoiceId); 1704 } 1705 const params = new URLSearchParams(form); 1706 return ( 1707 fetch(studiocart.ajax, { 1708 method: 'post', 1709 credentials: 'same-origin', 1710 headers: { 1711 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 1712 }, 1713 body: params 1714 }) 1715 .then((response) => { 1716 return response.json(); 1717 }) 1718 // If the card is declined, display an error to the user. 1719 .then((result) => { 1720 if (result.error) { 1721 // The card had an error when trying to attach it to a customer 1722 throw result.error; 1723 } 1724 return result; 1725 }) 1726 // Normalize the result to contain the object returned 1727 // by Stripe. Add the addional details we need. 1728 .then((result) => { 1729 // Insert the token ID into the form so it gets submitted to the server 1730 if ('undefined' !== typeof result.formAction) { 1731 f.setAttribute('action', result.formAction); 1732 } 1733 var hiddenInput = document.createElement('input'); 1734 hiddenInput.setAttribute('type', 'hidden'); 1735 hiddenInput.setAttribute('name', 'sc_order_id'); 1736 hiddenInput.setAttribute('value', result.sc_order_id); 1737 f.appendChild(hiddenInput); 1738 return { 1739 // Use the Stripe 'object' property on the 1740 // returned result to understand what object is returned. 1741 subscription: result, 1742 paymentMethodId: paymentMethodId, 1743 }; 1744 }) 1745 // Some payment methods require a customer to do additional 1746 // authentication with their financial institution. 1747 // Eg: 2FA for cards. 1748 .then(handlePaymentThatRequiresCustomerAction) 1749 // If attaching this card to a Customer object succeeds, 1750 // but attempts to charge the customer fail. You will 1751 // get a requires_payment_method error. 1752 .then(handleRequiresPaymentMethod) 1753 // No more actions required. Provision your service for the user. 1754 .then(function() { 1755 if(ev){ 1756 ev.complete('success'); 1757 } 1758 //console.log('result: ' + $('input[name=order_id]').val()); 1759 f.submit(); 1760 }) 1761 .catch((error) => { 1762 if(ev){ 1763 ev.complete('fail'); 1764 } 1765 // An error has happened. Display the failure to the user here. 1766 // We utilize the HTML element we created. 1767 displayError(error, wrap_id); 1768 }) 1769 ); 1770 } 1771 1772 function retryInvoiceWithNewPaymentMethod( 1773 customerId, 1774 paymentMethodId, 1775 invoiceId, 1776 wrap_id 1777 ) { 1778 var f = document.getElementById(wrap_id); 1779 f = f.getElementsByTagName('form')[0]; 1780 const form = new FormData(f); 1781 form.set('action', 'create_subscription'); 1782 form.set('customerId', customerId); 1783 form.set('paymentMethodId', paymentMethodId); 1784 if (invoiceId) { 1785 form.set('invoiceId', invoiceId); 1786 } 1787 const params = new URLSearchParams(form); 1788 return ( 1789 fetch(studiocart.ajax, { 1790 method: 'post', 1791 credentials: 'same-origin', 1792 headers: { 1793 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8', 1794 }, 1795 body: params 1796 }) 1797 .then((response) => { 1798 return response.json(); 1799 }) 1800 // If the card is declined, display an error to the user. 1801 .then((result) => { 1802 if (result.error) { 1803 // The card had an error when trying to attach it to a customer 1804 throw result; 1805 } 1806 return result; 1807 }) 1808 // Normalize the result to contain the object returned 1809 // by Stripe. Add the addional details we need. 1810 .then((result) => { 1811 return { 1812 // Use the Stripe 'object' property on the 1813 // returned result to understand what object is returned. 1814 invoice: result, 1815 paymentMethodId: paymentMethodId, 1816 isRetry: true, 1817 }; 1818 }) 1819 // Some payment methods require a customer to be on session 1820 // to complete the payment process. Check the status of the 1821 // payment intent to handle these actions. 1822 .then(handlePaymentThatRequiresCustomerAction) 1823 // No more actions required. Provision your service for the user. 1824 .then(function() { 1825 if(ev){ 1826 ev.complete('success'); 1827 } 1828 //console.log('result: ' + $('input[name=order_id]').val()); 1829 $form.submit(); 1830 }) 1831 .catch((error) => { 1832 if(ev){ 1833 ev.complete('fail'); 1834 } 1835 // An error has happened. Display the failure to the user here. 1836 // We utilize the HTML element we created. 1837 displayError(error, wrap_id); 1838 }) 1839 ); 1840 } 1841 1842 function handlePaymentThatRequiresCustomerAction({ 1843 subscription, 1844 invoice, 1845 priceId, 1846 paymentMethodId, 1847 isRetry, 1848 }) { 1849 // If it's a first payment attempt, the payment intent is on the subscription latest invoice. 1850 // If it's a retry, the payment intent will be on the invoice itself. 1851 let paymentIntent = invoice ? 1852 invoice.payment_intent : 1853 subscription.latest_invoice.payment_intent; 1854 1855 if (!paymentIntent) 1856 return { subscription, priceId, paymentMethodId }; 1857 1858 if ( 1859 paymentIntent.status === 'requires_action' || 1860 (isRetry === true && paymentIntent.status === 'requires_payment_method') 1861 ) { 1862 return stripe 1863 .confirmCardPayment(paymentIntent.client_secret, { 1864 payment_method: paymentMethodId, 1865 }) 1866 .then((result) => { 1867 if (result.error) { 1868 // start code flow to handle updating the payment details
1869 // Display error message in your UI. 1870 // The card was declined (i.e. insufficient funds, card has expired, etc) 1871 throw result; 1872 } else { 1873 if (result.paymentIntent.status === 'succeeded') { 1874 // There's a risk of the customer closing the window before callback 1875 // execution. To handle this case, set up a webhook endpoint and 1876 // listen to invoice.paid. This webhook endpoint returns an Invoice. 1877 return { 1878 priceId: priceId, 1879 subscription: subscription, 1880 invoice: invoice, 1881 paymentMethodId: paymentMethodId, 1882 }; 1883 } 1884 } 1885 }); 1886 } else { 1887 // No customer action needed 1888 return { subscription, priceId, paymentMethodId }; 1889 } 1890 } 1891 1892 function handleRequiresPaymentMethod({ 1893 subscription, 1894 paymentMethodId, 1895 priceId, 1896 }) { 1897 if (subscription.status === 'active' || subscription.status === 'trialing') { 1898 // subscription is active, no customer actions required. 1899 return { subscription, priceId, paymentMethodId }; 1900 } else if ( 1901 subscription.latest_invoice.payment_intent.status === 1902 'requires_payment_method' 1903 ) { 1904 // Using localStorage to store the state of the retry here 1905 // (feel free to replace with what you prefer) 1906 // Store the latest invoice ID and status 1907 localStorage.setItem('latestInvoiceId', subscription.latest_invoice.id); 1908 localStorage.setItem( 1909 'latestInvoicePaymentIntentStatus', 1910 subscription.latest_invoice.payment_intent.status 1911 ); 1912 throw { error: { message: 'Your card was declined.' } }; 1913 } else { 1914 return { subscription, priceId, paymentMethodId }; 1915 } 1916 } 1917 1918 function confirmSubscription(intent, isPaymentRetry = false, invoiceId = false, form_wrapper=false, ev) { 1919 var customer_name = $('#first_name', '#'.form_wrapper).val() + ' ' + $('#last_name', '#'.form_wrapper).val(), 1920 customer_email = $('#email', '#'.form_wrapper).val(); 1921 stripe.createPaymentMethod({ 1922 type: 'card', 1923 card: card[form_wrapper], 1924 billing_details: { 1925 name: customer_name, 1926 email: customer_email, 1927 }, 1928 }) 1929 .then((result) => { 1930 if (result.error) { 1931 displayError(result, form_wrapper); 1932 } else { 1933 if (isPaymentRetry) { 1934 // Update the payment method and retry invoice payment 1935 retryInvoiceWithNewPaymentMethod( 1936 intent.customer_id, 1937 result.paymentMethod.id, 1938 invoiceId, 1939 form_wrapper, 1940 ev 1941 ); 1942 } else { 1943 // Create the subscription 1944 createSubscription( 1945 intent.customer_id, 1946 result.paymentMethod.id, 1947 false, 1948 form_wrapper, 1949 ev 1950 ); 1951 } 1952 } 1953 }); 1954 } 1955 1956 function displayError(event, form_wrapper) { 1957 if (event.error) { 1958 alert(event.error.message); 1959 } else if (event) { 1960 alert(event); 1961 } 1962 $('#sc_card_button', '#'+form_wrapper).removeClass('running').removeAttr("disabled"); 1963 $('#express-pay-element', '#'+form_wrapper).css('pointer-events', ''); 1964 } 1965 1966 function confirmCardPayment(intent, wrap_id, isExpresspayment, ev) { 1967 var customer_name = $('#first_name').val() + ' ' + $('#last_name').val(), 1968 customer_email = $('#email').val(); 1969 var confirmCardPaymentCall; 1970 if(isExpresspayment){ 1971 confirmCardPaymentCall = stripe.confirmCardPayment( 1972 intent.clientSecret, 1973 {payment_method: intent.paymentMethodId}, 1974 {handleActions: false} 1975 ); 1976 }else{ 1977 confirmCardPaymentCall = stripe.confirmCardPayment(intent.clientSecret, { 1978 payment_method: { 1979 card: card[wrap_id], 1980 billing_details: { 1981 name: customer_name, 1982 email: customer_email, 1983 }, 1984 }, 1985 setup_future_usage: 'off_session' 1986 }) 1987 } 1988 confirmCardPaymentCall.then(function(result) { 1989 if (result.error) {
1990 // Display error.message in your UI. 1991 if(isExpresspayment){ 1992 ev.complete('fail'); 1993 $('#express-pay-element', '#'+wrap_id).css('pointer-events', ''); 1994 $('#sc_card_button', '#'+wrap_id).removeClass('running').removeAttr("disabled"); 1995 }else{ 1996 displayError(result, wrap_id); 1997 } 1998 } else { 1999 var paramObj = {}; 2000 $.each($('#sc-payment-form').serializeArray(), function(_, kv) { 2001 if (kv.name != 'sc-orderbump[]') { 2002 paramObj[kv.name] = kv.value; 2003 if (kv.name == 'pay-method') { 2004 if(isExpresspayment){ 2005 paramObj[kv.name] = "stripe"; 2006 } 2007 } 2008 } 2009 }); 2010 $('input[name="sc-orderbump[]"]').each(function(key, value) { 2011 if (this.checked) { 2012 paramObj['sc-orderbump[' + key + ']'] = $(this).val(); 2013 } 2014 }); 2015 if (intent.sc_temp_order_id) { 2016 paramObj['sc_temp_order_id'] = intent.sc_temp_order_id; 2017 } 2018 paramObj['customer_id'] = intent.customer_id; 2019 paramObj['intent_id'] = intent.intent_id; 2020 paramObj['amount'] = intent.amount; 2021 $.post(studiocart.ajax, paramObj, function(res) { 2022 var response = JSON.parse(res); 2023 if ('error' in response) { 2024 alert(response.error); 2025 if ('undefined' !== typeof response.fields) { 2026 $.each(response.fields, function(i, item) { 2027 invalidate_field($('[name="' + item['field'] + '"]'), item['message']) 2028 }); 2029 } 2030 if(isExpresspayment){ 2031 ev.complete('fail'); 2032 } 2033 $('#sc_card_button', '#'+wrap_id).find('span.text').text(originalText); 2034 $('#sc_card_button', '#'+wrap_id).removeClass('running').removeAttr("disabled"); 2035 return false; 2036 } else { 2037 if (result.paymentIntent) { 2038 var data = { 2039 'paymentIntent': result.paymentIntent, 2040 'action': 'update_stripe_order_status', 2041 'response': response, 2042 'intent_id': intent.intent_id, 2043 'sc-nonce': $('input[name=sc-nonce]').val(), 2044 }; 2045 if (jQuery('input[name="sc-auto-login"]').length == 1) { 2046 data['sc-auto-login'] = 1; 2047 } 2048 $.post(studiocart.ajax, data, function(res) { 2049 //if (!isNaN(order_id)) { 2050 // Insert the token ID into the form so it gets submitted to the server 2051 if(isExpresspayment){ 2052 ev.complete('success'); 2053 } 2054 var response = JSON.parse(res); 2055 var form = document.getElementById(wrap_id); 2056 form = form.getElementsByTagName('form')[0]; 2057 if ('undefined' !== typeof response.formAction) { 2058 form.setAttribute('action', response.formAction); 2059 } 2060 var hiddenInput = document.createElement('input'); 2061 hiddenInput.setAttribute('type', 'hidden'); 2062 hiddenInput.setAttribute('name', 'sc_order_id'); 2063 hiddenInput.setAttribute('value', response.order_id); 2064 form.appendChild(hiddenInput); 2065 var hiddenInput2 = document.createElement('input'); 2066 hiddenInput2.setAttribute('type', 'hidden'); 2067 hiddenInput2.setAttribute('name', 'intent_id'); 2068 hiddenInput2.setAttribute('value', intent.intent_id); 2069 form.appendChild(hiddenInput2); 2070 if (intent.amount == false) { 2071 intent.amount = response.amount 2072 } 2073 form.submit(); 2074 //} 2075 }); 2076 } 2077 } 2078 }); 2079 } 2080 }); 2081 } 2082 2083 /*--Added paypal Scripts--*/ 2084 if (studiocart.pay_method == 'paypal') { 2085 $(document).on('studiocart/upsell/ready/accept_link', '.sc-accept-upsell-link', function() { 2086 $('a[href*="sc-upsell-offer=yes"],.sc-accept-upsell-link').attr('href', '#'); 2087 }); 2088 2089 $(document).on('studiocart/upsell/ready/decline_link', '.sc-decline-upsell-link', function() { 2090 $('a[href*="sc-upsell-offer=no"],.sc-decline-upsell-link').attr('href', studiocart.upsell_decline + '&sc-pp=1'); 2091 }); 2092 } 2093 2094 $(document).on('studiocart/upsell/accept/paypal', '.sc-accept-upsell-link', function(event) { 2095 let us_data = { 2096 'action': 'paypal_process_upsell', 2097 'sc-order': studiocart.sc_order, 2098 'sc-nonce': studiocart.sc_nonce, 2099 'cancel_url': window.location.href, 2100 'return_url': studiocart.upsell_accept, 2101 }; 2102 // flag for downsells 2103 if ('undefined' !== typeof studiocart.is_downsell && '1' == studiocart.is_downsell) { 2104 us_data['downsell'] = 1; 2105 } 2106 2107 $.post(studiocart.ajax, us_data, function(res) { 2108 var response = JSON.parse(res); 2109 if ('undefined' !== typeof response.error) { 2110 alert(response.error); 2111 window.location.href = studiocart.upsell_decline + '&sc-pp=1'; 2112 } else { 2113 window.location.href = response.url; 2114 } 2115 }); 2116 return false;
2117 }); 2118 2119 // Handle paypal form submission. 2120 $(document).on('studiocart/orderform/submit', '#sc-payment-form', function(event) { 2121 2122 var form = '#' + $(this).parent().attr('id'); 2123 if ($('.pay-methods', form).length > 0 && $('[name="pay-method"]:checked', form).val() != 'paypal') { 2124 return false; 2125 } 2126 var paramObj = $('#sc-payment-form', form).serializeArray(); 2127 2128 paramObj.push( 2129 { name: "sc_page_id", value: studiocart.page_id }, 2130 { name: "action", value: "sc_paypal_request" }, 2131 { name: "cancel_url", value: window.location.href } 2132 ); 2133 2134 //var is_subscription = $('input[name="sc_product_option"]:checked').data('installments'); 2135 $.post(studiocart.ajax, paramObj, function(res) { 2136 var response = JSON.parse(res); 2137 if ('undefined' !== typeof response.error) { 2138 alert(response.error); 2139 $('#sc_card_button', form).removeClass('running').removeAttr("disabled"); 2140 } else { 2141 window.location.href = response.url; 2142 } 2143 }); 2144 }); 2145 }); 2146 2147 /** 2148 * My Account page tabs nested 2149 */ 2150 jQuery('.ncs-nav-tabs li a').click(function() { 2151 var tab_id = jQuery(this).attr('href'); 2152 2153 jQuery('.ncs-nav-tabs li a').removeClass('active'); 2154 jQuery('.tabcontent').removeClass('active'); 2155 2156 jQuery(this).addClass('active'); 2157 jQuery("#" + tab_id).addClass('active'); 2158 }) 2159 2160 /** 2161 * Tabs left aligned on my account page 2162 */ 2163 jQuery('ul.tabs-left li.tablinks').click(function() { 2164 var tab_id = jQuery(this).attr('data-tab'); 2165 2166 jQuery('ul.tabs-left li.tablinks').removeClass('active'); 2167 jQuery('.tabcontent').removeClass('active'); 2168 2169 jQuery(this).addClass('active'); 2170 jQuery("#" + tab_id).addClass('active'); 2171 }) 2172 2173 jQuery('.ncs-nav-tabs li a').click(function(event) { 2174 event.preventDefault(); 2175 var parents = jQuery(this).parents('.ncs-account-list'); 2176 parents.find('.ncs-nav-tabs li a').removeClass('active'); 2177 jQuery(this).addClass('active'); 2178 return false; 2179 }); 2180 2181 /** Edit profile in my account */ 2182 2183 jQuery("#editProfile").click(function(){ 2184 jQuery(".ep_disabled").prop('disabled',false); 2185 jQuery(".ep_disabled").addClass('enable-input'); 2186 jQuery("#editProfileCancel, #all-subscription-address-wrap").show(); 2187 jQuery("#newPasswordDiv, #confirmNewPasswordDiv").show(); 2188 jQuery(this).hide(); 2189 jQuery("#updateProfile").show(); 2190 }); 2191 2192 jQuery("#editProfileCancel").click(function(){ 2193 cancelEditProfile(); 2194 }); 2195 2196 jQuery("#updateProfile").click(function(){ 2197 jQuery("#sc-loader").show(); 2198 jQuery(this).prop('disabled',true); 2199 var formData = jQuery('#updateProfileForm').serialize(); 2200 2201 let paramObj = { 2202 'action': 'update_user_profile', 2203 'form_data':formData 2204 }; 2205 2206 $.post(studiocart.ajax, paramObj, function (res) { 2207 if ('undefined' !== typeof res.error) { 2208 jQuery("#p-alert").text(res.error).addClass('alert-error'); 2209 } else { 2210 jQuery("#p-alert").removeClass('alert-error'); 2211 jQuery("#p-alert").text(res.message).addClass('alert-success'); 2212 cancelEditProfile(); 2213 } 2214 jQuery("#updateProfile").prop('disabled',false); 2215 jQuery("#sc-loader").hide(); 2216 }); 2217 2218 }); 2219 2220 function cancelEditProfile(){ 2221 jQuery(".ep_disabled").removeClass('enable-input'); 2222 jQuery(".ep_disabled").prop('disabled',true); 2223 jQuery("#editProfileCancel, #all-subscription-address-wrap").hide(); 2224 jQuery("#editProfile").show(); 2225 jQuery("#newPasswordDiv, #confirmNewPasswordDiv").hide(); 2226 jQuery("#updateProfile").hide(); 2227 } 2228 2229})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.