0
votes

Using the new Stripe Payment Intent API and Stripe.js, I want to be able to do the following:

1) If the user's card is valid but requires authentication (SCA), do not submit the form until the user clicks "complete authentication" on the 3D secure popup.

2) If the user's card is valid but does not require authentication (SCA), submit the form.

Here is a video of my issue: https://streamable.com/797e5

As you can see from the video, the form submits itself with a card that requires authentication but the user does not have time to click "complete authentication" since the form refreshes the page immediately.

Stripe support says JavaScript is needed with e.preventDefault() and return false to do this and provided me a PHP example. https://glitch.com/edit/#!/stripe-php-sca-example?path=public/charge.php:9:0

However, I am using Django and not PHP. I am also not sure how to code this in JavaScript.

Any help would be greatly appreciated.

Html:

<form onsubmit="return false;" action="{{checkout}}" method="post" id="payment-form">{% csrf_token %}
  <div class="form-row">
    <label for="card-element">
      Credit or debit card
    </label>
    <div id="card-element">
      <!-- A Stripe Element will be inserted here. -->
    </div>

    <!-- Used to display form errors. -->
    <div id="card-errors" role="alert"></div>
  </div>

<button id="card-button" data-secret="{{ client_secret }}">
  Submit Payment
</button>
</form>
<script src="https://js.stripe.com/v3/"></script>

Stripe.js:

var stripe = Stripe('<KEY>');

var elements = stripe.elements();
var cardElement = elements.create('card');
cardElement.mount('#card-element');

var cardButton = document.getElementById('card-button');
var clientSecret = cardButton.dataset.secret;

stripe.createPaymentMethod('card', cardElement, {
}).then(function(result) {
  console.log(result.paymentMethod)
});


cardButton.addEventListener('click', function(ev) {
  stripe.handleCardPayment(
    clientSecret, cardElement
  ).then(function(result) {
    if (result.error) {
      console.log(result.error.message);
    } else {
      console.log(result.message);
    }
  });
});
1

1 Answers

0
votes

Your tip "Stripe support says JavaScript is needed with e.preventDefault() and return false to do this" saved me.

Try:

.
.
.
cardButton.addEventListener('click', function(ev) {
  ev.preventDefault(); // Required by Stripe.
  ev.stopPropagation(); // Not required but stops the click event from bubbling.

  stripe.handleCardPayment(
    clientSecret, cardElement
  ).then(function(result) {
    if (result.error) {
      console.log(result.error.message);
    } else {
      console.log(result.message);
    }
  });

  return false // Required by Stripe.
});

I was struggling with this same issue, the user would input all their credit card data and the page would refresh, causing them to have to input it in all again.

Hope this helps!