1(function ($) { 2 $(document).ready(function () { 3 // registration form handler 4 $("#leaky-paywall-registration-next").click(function () { 5 $(this).text("Processing... Please Wait"); 6 $("#leaky-paywall-registration-errors").html(""); 7 8 const form_data = $("#leaky-paywall-payment-form").serialize(); 9 10 const data = { 11 action: "leaky_paywall_process_user_registration_validation", 12 form_data: form_data, 13 }; 14 15 $.post(leaky_paywall_script_ajax.ajaxurl, data, function (resp) { 16 if (resp.errors) { 17 $.each(resp.errors, function (i, value) { 18 console.log(value); 19 $("#leaky-paywall-registration-errors").append( 20 "<p class='leaky-paywall-registration-error'>" + 21 value.message + 22 "</p>" 23 ); 24 $("#leaky-paywall-registration-next").text("Next"); 25 $("#leaky-paywall-registration-errors").show(); 26 27 $("html, body").animate( 28 { 29 scrollTop: $(".leaky-paywall-registration-error").offset().top, 30 }, 31 1000 32 ); 33 }); 34 } else { 35 if (resp.pi_client) { 36 $("#payment-intent-client").val(resp.pi_client); 37 $("#payment-intent-id").val(resp.pi_id); 38 } else { 39 $("#stripe-customer-id").val(resp.customer_id); 40 } 41 42 if ( resp.session_id ) { 43 44 let stripe = Stripe(leaky_paywall_script_ajax.stripe_pk); 45 46 $('#checkout').click(function(e) { 47 e.preventDefault(); 48 49 stripe.redirectToCheckout({ 50 sessionId: resp.session_id 51 }); 52 }); 53 }; 54 55 setInterval(() => { 56 $("#leaky-paywall-registration-errors").hide(); 57 $("#leaky-paywall-registration-next").remove(); 58 $(".leaky-paywall-registration-user-container").hide(); 59 $(".leaky-paywall-form-payment-setup-step").addClass("active"); 60 $(".leaky-paywall-form-account-setup-step").removeClass("active"); 61 62 $(".leaky-paywall-registration-payment-container").slideDown(); 63 }, 500); 64 65 $("html, body").animate( 66 { 67 scrollTop: $(".leaky-paywall-form-steps").offset().top, 68 }, 69 1000 70 ); 71 } 72 }); 73 }); // registration next click 74 75 76 77 // only load on Stripe enabled payment gateways 78 if ( $('#card-element').length > 0 ) { 79 80 // stripe checkout 81 // reset on page load 82 localStorage.removeItem('latestInvoicePaymentIntentStatus'); 83 let stripe = Stripe(leaky_paywall_script_ajax.stripe_pk); 84 85 let paymentRequest; 86 let prButton; 87 let currency = $('input[name="currency"]').val().toLowerCase(); 88 89 if ( 'yes' == leaky_paywall_script_ajax.apple_pay) { 90 let apamount = $('input[name="level_price"]').val() * 100; 91 92 paymentRequest = stripe.paymentRequest({ 93 country: 'US', 94 currency: currency, 95 total: { 96 label: $('input[name="description"]').val(), 97 amount: Math.round(apamount), 98 }, 99 requestPayerName: true, 100 requestPayerEmail: true, 101 }); 102 103 console.log(paymentRequest); 104 105 } 106 107 let elements = stripe.elements(); 108 109 if ( 'yes' == leaky_paywall_script_ajax.apple_pay) { 110 prButton = elements.create('paymentRequestButton', { 111 paymentRequest: paymentRequest, 112 }); 113 } 114 115 116 117 let style = { 118 base: { 119 color: '#32325d', 120 lineHeight: '18px', 121 fontFamily: '"Helvetica Neue", Helvetica, sans-serif', 122 fontSmoothing: 'antialiased', 123 fontSize: '16px', 124 '::placeholder': { 125 color: '#aab7c4' 126 } 127 }, 128 invalid: { 129 color: '#fa755a', 130 iconColor: '#fa755a' 131 } 132 }; 133 134 let card = elements.create('card', { 135 style: style 136 }); 137 138 card.mount('#card-element'); 139 140 if ( 'yes' == leaky_paywall_script_ajax.apple_pay ) { 141 // Check the availability of the Payment Request API first. 142 paymentRequest.canMakePayment().then(function(result) { 143 if (result) { 144 prButton.mount('#payment-request-button'); 145 } else { 146 document.getElementById('payment-request-button').style.display = 'none'; 147 console.log('apple pay not available'); 148 } 149 }); 150 151 paymentRequest.on('paymentmethod', async function(ev) { 152 153 let data = new FormData(); 154 let level_id = $('#level-id').val(); 155 156 data.append('action', 'leaky_paywall_create_stripe_payment_intent'); 157 data.append('level_id', level_id); 158 data.append('paymentMethodType', 'card'); 159 160 // create paymentIntent 161 const {clientSecret} = await fetch(leaky_paywall_script_ajax.ajaxurl, { 162 method: 'post', 163 credentials: 'same-origin', 164 body: data 165 }).then(r => r.json()); 166 console.log('client secret returned'); 167 168 const{error, paymentIntent}
168 = await stripe.confirmCardPayment( 169 clientSecret, { 170 payment_method: ev.paymentMethod.id, 171 }, { 172 handleActions: false 173 } 174 ) 175 if(error) { 176 ev.complete('fail'); 177 console.log('payment failed'); 178 return; 179 } 180 ev.complete('success'); 181 console.log(`Success: ${paymentIntent.id}`); 182 if(paymentIntent.status === 'requires_action') { 183 stripe.confirmCardPayment(clientSecret).then(function(result) { 184 if (result.error) { 185 console.log('payment failed again'); 186 // The payment failed -- ask your customer for a new payment method. 187 } else { 188 // The payment has succeeded. 189 console.log('lp form submit apple pay success'); 190 let form$ = jQuery('#leaky-paywall-payment-form'); 191 form$.get(0).submit(); 192 } 193 }); 194 } else { 195 console.log('lp form submit apple pay success'); 196 let form$ = jQuery('#leaky-paywall-payment-form'); 197 form$.get(0).submit(); 198 } 199 200 }); 201 202 203 } 204 205 // Handle real-time validation errors from the card Element. 206 card.on('change', function(event) { 207 let displayError = document.getElementById('card-errors'); 208 if (event.error) { 209 displayError.textContent = event.error.message; 210 } else { 211 displayError.textContent = ''; 212 } 213 }); 214 215 // Handle form submission. 216 let form = document.getElementById('leaky-paywall-payment-form'); 217 218 form.addEventListener('submit', function(event) { 219 220 let method = $('#leaky-paywall-payment-form').find('input[name="payment_method"]:checked').val(); 221 222 if (method != 'stripe') { 223 return; 224 } 225 226 event.preventDefault(); 227 228 console.log('lp form submit 1'); 229 230 let subButton = document.getElementById('leaky-paywall-submit'); 231 let firstName = $('input[name="first_name"]').val(); 232 let lastName = $('input[name="last_name"]').val(); 233 let clientSecret = $('#payment-intent-client').val(); 234 let isRecurring = $('input[name="recurring"]').val(); 235 236 237 subButton.disabled = true; 238 subButton.innerHTML = 'Processing... Please Wait'; 239 240 // one time payment 241 if ( isRecurring != 'on') { 242 console.log('lp form submit one time'); 243 244 stripe.confirmCardPayment(clientSecret, { 245 payment_method: { 246 card: card, 247 billing_details: { 248 name: firstName + ' ' + lastName 249 }, 250 }, 251 setup_future_usage: 'off_session' 252 }).then(function(result) { 253 console.log('lp form submit one time result'); 254 if (result.error) { 255 // Show error to your customer (e.g., insufficient funds) 256 console.log(result.error.message); 257 $('#lp-card-errors').html('<p>' + result.error.message + '</p>'); 258 259 let subButton = document.getElementById('leaky-paywall-submit'); 260 subButton.disabled = false; 261 subButton.innerHTML = 'Subscribe'; 262 263 } else { 264 265 // The payment has been processed! 266 if (result.paymentIntent.status === 'succeeded') { 267 console.log('lp form submit one time success'); 268 269 let form$ = jQuery('#leaky-paywall-payment-form'); 270 271 form$.get(0).submit(); 272 273 } 274 } 275 }); 276 277 } // end one time payment 278 279 if ( isRecurring == 'on') { 280 console.log('lp form submit recurring'); 281 282 const latestInvoicePaymentIntentStatus = localStorage.getItem( 283 'latestInvoicePaymentIntentStatus' 284 ); 285 286 if (latestInvoicePaymentIntentStatus === 'requires_payment_method') { 287 const invoiceId = localStorage.getItem('latestInvoiceId'); 288 const isPaymentRetry = true; 289 // create new payment method & retry payment on invoice with new payment method 290 createPaymentMethod({ 291 card, 292 isPaymentRetry, 293 invoiceId, 294 }); 295 } else { 296 // create new payment method & create subscription 297 createPaymentMethod({ 298 card 299 }); 300 } 301 302 function createPaymentMethod({ 303 card, 304 isPaymentRetry, 305 invoiceId 306 }) { 307 // Set up payment method for recurring usage 308 let billingName = firstName + ' ' + lastName; 309 let customerId = $('#stripe-customer-id').val(); 310 let planId = $('#plan-id').val(); 311 312
313 stripe.createPaymentMethod({ 314 type: 'card', 315 card: card, 316 billing_details: { 317 name: billingName, 318 }, 319 }) 320 .then((result) => { 321 if (result.error) { 322 showCardError(result); 323 } else { 324 if (isPaymentRetry) { 325 // Update the payment method and retry invoice payment 326 retryInvoiceWithNewPaymentMethod({ 327 customerId: customerId, 328 paymentMethodId: result.paymentMethod.id, 329 invoiceId: invoiceId, 330 planId: planId, 331 }); 332 } else { 333 // Create the subscription 334 createSubscription({ 335 customerId: customerId, 336 paymentMethodId: result.paymentMethod.id, 337 planId: planId, 338 }); 339 } 340 } 341 }); 342 343 } // end createPaymentMethod 344 345 function retryInvoiceWithNewPaymentMethod({ 346 customerId, 347 paymentMethodId, 348 invoiceId, 349 planId 350 }) { 351 352 let level_id = $('#level-id').val(); 353 let data = new FormData(); 354 const form_data = $("#leaky-paywall-payment-form").serialize(); 355 356 data.append('action', 'leaky_paywall_create_stripe_checkout_subscription'); 357 data.append('level_id', level_id); 358 data.append('customerId', customerId); 359 data.append('paymentMethodId', paymentMethodId); 360 data.append('planId', planId); 361 data.append('invoiceId', invoiceId); 362 data.append('formData', form_data); 363 364 return ( 365 fetch(leaky_paywall_script_ajax.ajaxurl, { 366 method: 'post', 367 credentials: 'same-origin', 368 // headers: { 369 // 'Content-type': 'application/json', 370 // }, 371 body: data 372 }) 373 .then((response) => { 374 return response.json(); 375 }) 376 // If the card is declined, display an error to the user. 377 .then((result) => { 378 if (result.error) { 379 // The card had an error when trying to attach it to a customer. 380 throw result; 381 } 382 console.log('retry invoice result'); 383 console.log(result); 384 return result; 385 }) 386 // Normalize the result to contain the object returned by Stripe. 387 // Add the additional details we need. 388 .then((result) => { 389 return { 390 // Use the Stripe 'object' property on the 391 // returned result to understand what object is returned. 392 invoice: result.invoice, 393 paymentMethodId: paymentMethodId, 394 planId: planId, 395 isRetry: true, 396 }; 397 }) 398 // Some payment methods require a customer to be on session 399 // to complete the payment process. Check the status of the 400 // payment intent to handle these actions. 401 .then(handlePaymentThatRequiresCustomerAction) 402 // No more actions required. Provision your service for the user. 403 .then(onSubscriptionComplete) 404 .catch((error) => { 405 console.log('caught retry invoice error'); 406 console.log(error); 407 // An error has happened. Display the failure to the user here. 408 // We utilize the HTML element we created. 409 showCardError(error); 410 }) 411 ); 412 413 } // end retryInvoiceWithNewPaymentMethod 414 415 function createSubscription({ 416 customerId, 417 paymentMethodId, 418 planId 419 }) { 420 421 let level_id = $('#level-id').val(); 422 let data = new FormData(); 423 const form_data = $("#leaky-paywall-payment-form").serialize(); 424 425 data.append('action', 'leaky_paywall_create_stripe_checkout_subscription'); 426 data.append('level_id', level_id); 427 data.append('customerId', customerId); 428 data.append('paymentMethodId', paymentMethodId); 429 data.append('planId', planId); 430 data.append('formData', form_data); 431 432 return ( 433 fetch(leaky_paywall_script_ajax.ajaxurl, { 434 method: 'post', 435 credentials: 'same-origin', 436 // headers: { 437 // 'Content-type': 'application/json', 438 // }, 439 body: data 440 }) 441 .then((response) => { 442 return response.json(); 443 }) 444 // If the card is declined, display an error to the user. 445 .then((result) => { 446 if (result.error) { 447 // The card had an error when trying to attach it to a customer. 448 throw result; 449 } 450 console.log('result'); 451 console.log(result); 452 return result; 453 }) 454 // Normalize the result to contain the object returned by Stripe. 455 // Add the additional details we need. 456 .then((result) => { 457 return { 458 paymentMethodId: paymentMethodId, 459 planId: planId, 460 subscription: result.subscription, 461 }; 462 }) 463 // Some payment methods require a customer to be on session 464 // to complete the payment process. Check the status of the 465 // payment intent to handle these actions. 466 .then(handlePaymentThatRequiresCustomerAction) 467 // If attaching this card to a Customer object succeeds, 468 // but attempts to charge the customer fail, you 469 // get a requires_payment_method error. 470 .then(handleRequiresPaymentMethod) 471 // No more actions required. Provision your service for the user. 472 .then(onSubscriptionComplete) 473 .catch((error) => { 474 475 console.log('caught error'); 476 console.log(error); 477 // An error has happened. Display the failure to the user here. 478 // We utilize the HTML element we created. 479 showCardError(error); 480 }) 481 ) // end return 482 } // end createSubscription 483 484 485 function handlePaymentThatRequiresCustomerAction({ 486 subscription, 487 invoice, 488 planId, 489 paymentMethodId, 490 isRetry, 491 }) { 492 if (subscription && subscription.status === 'active') { 493 // Subscription is active, no customer actions required. 494 return { 495 subscription, 496 planId, 497 paymentMethodId 498 }; 499 } 500 if (subscription && subscription.status === 'trialing') { 501 // Subscription is trialing, no customer actions required. 502 return { 503 subscription, 504 planId, 505 paymentMethodId 506 }; 507 } 508 509 console.log('handle payment that requires customer action'); 510 console.log(subscription); 511 512 // If it's a first payment attempt, the payment intent is on the subscription latest invoice. 513 // If it's a retry, the payment intent will be on the invoice itself. 514 let paymentIntent = invoice ? invoice.payment_intent : subscription.latest_invoice.payment_intent; 515 // let paymentIntent = subscription.latest_invoice.payment_intent; 516 517 console.log('payment intent'); 518 console.log(paymentIntent); 519 520 if ( 521 paymentIntent.status === 'requires_action' || 522 (isRetry === true && paymentIntent.status === 'requires_payment_method') 523 ) { 524 return stripe 525 .confirmCardPayment(paymentIntent.client_secret, { 526 payment_method: paymentMethodId, 527 }) 528 .then((result) => { 529 if (result.error) { 530 // Start code flow to handle updating the payment details.
531 // Display error message in your UI. 532 // The card was declined (i.e. insufficient funds, card has expired, etc). 533 throw result; 534 } else { 535 if (result.paymentIntent.status === 'succeeded') { 536 // Show a success message to your customer. 537 // There's a risk of the customer closing the window before the callback. 538 // We recommend setting up webhook endpoints later in this guide. 539 return { 540 planId: planId, 541 subscription: subscription, 542 invoice: invoice, 543 paymentMethodId: paymentMethodId, 544 }; 545 } 546 } 547 }) 548 .catch((error) => { 549 showCardError(error); 550 }); 551 } else { 552 // No customer action needed. 553 return { 554 subscription, 555 planId, 556 paymentMethodId 557 }; 558 } 559 } // end handlePaymentThatRequiresCustomerAction 560 561 562 function handleRequiresPaymentMethod({ 563 subscription, 564 paymentMethodId, 565 planId, 566 }) { 567 568 console.log('handle requires payment method'); 569 if (subscription.status === 'active' || subscription.status === 'trialing') { 570 // subscription is active, no customer actions required. 571 return { 572 subscription, 573 planId, 574 paymentMethodId 575 }; 576 } else if ( 577 subscription.latest_invoice.payment_intent.status === 578 'requires_payment_method' 579 ) { 580 // Using localStorage to manage the state of the retry here, 581 // feel free to replace with what you prefer. 582 // Store the latest invoice ID and status. 583 localStorage.setItem('latestInvoiceId', subscription.latest_invoice.id); 584 localStorage.setItem( 585 'latestInvoicePaymentIntentStatus', 586 subscription.latest_invoice.payment_intent.status 587 ); 588 throw { 589 error: { 590 message: 'Your card was declined.' 591 } 592 }; 593 } else { 594 return { 595 subscription, 596 planId, 597 paymentMethodId 598 }; 599 } 600 } // end handleRequiresPaymentMethod 601 602 603 function onSubscriptionComplete(result) { 604 console.log('sub complete'); 605 console.log(result); 606 // Payment was successful. 607 if (result.subscription.status === 'active' || result.subscription.status === 'trialing') { 608 console.log('subscription complete!'); 609 var form$ = jQuery('#leaky-paywall-payment-form'); 610 611 form$.get(0).submit(); 612 // Change your UI to show a success message to your customer. 613 // Call your backend to grant access to your service based on 614 // `result.subscription.items.data[0].price.product` the customer subscribed to. 615 } else { 616 var form$ = jQuery('#leaky-paywall-payment-form'); 617 form$.get(0).submit(); 618 } 619 } // end onSubscriptionComplete 620 621 function showCardError(event) { 622 console.log('show card error - event'); 623 console.log(event); 624 console.log('show card error - event error message'); 625 626 let subButton = document.getElementById('leaky-paywall-submit'); 627 subButton.disabled = false; 628 subButton.innerHTML = 'Subscribe'; 629 630 let displayError = document.getElementById('card-errors'); 631 if (event.error) { 632 if (event.error.message) { 633 displayError.textContent = event.error.message; 634 } else { 635 displayError.textContent = event.error.error.message; 636 } 637 638 } else { 639 displayError.textContent = 'There was an error with your payment. Please try again.'; 640 } 641 } // end showCardError 642 643 } // end recurring payment processing 644 645 646 }); // form submit 647 648 } 649 650 651 652 653 }); 654})(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.