mysociety/alaveteli

View on GitHub
app/assets/javascripts/alaveteli_pro/stripe.js

Summary

Maintainability
B
6 hrs
Test Coverage
(function() {
  'use strict';

  var subscriptionForm = document.getElementById('js-stripe-subscription-form');
  if (subscriptionForm) { stripeSubscriptionForm(subscriptionForm); }

  var updateForm = document.getElementById('js-stripe-update-form');
  if (updateForm) { stripeForm(updateForm, {}) }
})();

function stripeSubscriptionForm(form) {
  stripeForm(form, {
    submitViaAjax: true,
    submitConditions: { cardValid: false, termAccepted: false },
    setupCallback: function (that) {
      var terms = document.getElementById('js-pro-signup-terms');

      // Sync initial state for terms checkbox and submit button
      terms.checked = false;

      // Enable submit button if terms are accepted
      terms.addEventListener('click', function(event) {
        if (this.checked) {
          that.submitConditions.termAccepted = true;
        }    else {
          that.submitConditions.termAccepted = false;
        }
        that.updateSubmit();
      });
    }
  })
}

function stripeForm(form, options) {
  var that = Object.assign({
    stripe: Stripe(AlaveteliPro.stripe_publishable_key),
    form: form,
    submit: document.getElementById('js-stripe-submit'),

    // Conditions which must be met before we submit the form
    submitConditions: { cardValid: false },

    // Callback for customisation
    setupCallback: function() {},

    // Ajax form used for SCA confirmation
    submitViaAjax: false
  }, options);

  that.load = function() {
    var cardError = document.getElementById('card-errors');

    // Sync initial state for terms checkbox and submit button
    that.submit.setAttribute('disabled', 'true');

    // Initialise Stripe Elements
    var elements = that.stripe.elements({ locale: AlaveteliPro.stripe_locale });

    // Create an instance of the card Element.
    var style = { base: { fontSize: '16px' } };
    var card = elements.create('card', { style: style });

    // Add an instance of the card Element into the `card-element` <div>.
    card.mount('#card-element');

    // Call callback to allow addition setup
    that.setupCallback(that);

    // Listen to change events on the card Element and display any errors
    card.addEventListener('change', function(event) {
      if (event.error) {
        cardError.textContent = event.error.message;
      } else {
        cardError.textContent = '';
      }

      that.submitConditions.cardValid = !(event.error);
      that.updateSubmit();
    });

    // Create a token or display an error when the form is submitted
    that.form.addEventListener('submit', function(event) {
      event.preventDefault();

      // Ensure submit conditions are met
      if (!that.canSubmit()) { return false; }

      that.stripe.createToken(card).then(function(result) {
        if (result.error) {
          // Inform the customer that there was an error
          cardError.textContent = result.error.message;

          // Prevent re-submitting after error
          that.submitConditions.cardValid = false;
          that.updateSubmit();

          // Reset submit button value which was changed by Rails' UJS
          // disable-with option
          var text = $(that.submit).data('ujs:enable-with');
          if (text) { $(that.submit)['val'](text); }
        } else {
          // Send the token to your server.
          that.stripeTokenHandler(result.token);
        }
      });
    });
  };

  that.canSubmit = function() {
    for (var condition in that.submitConditions) {
      if(!that.submitConditions[condition]) { return false; }
    }
    return true;
  };

  that.updateSubmit = function() {
    if (that.canSubmit()) {
      that.submit.removeAttribute('disabled');
    } else {
      that.submit.setAttribute('disabled', 'true');
    }
  };

  that.stripeTokenHandler = function(token) {
    // Insert the token ID into the form so it gets submitted to the server
    var hiddenInput = document.createElement('input');
    hiddenInput.setAttribute('type', 'hidden');
    hiddenInput.setAttribute('name', 'stripe_token');
    hiddenInput.setAttribute('value', token.id);
    that.form.appendChild(hiddenInput);

    // Submit the form
    if (that.submitViaAjax) {
      $.ajax({
        type: 'POST',
        url: $(that.form).attr('action'),
        data: $(that.form).serialize(),
        dataType: 'json',
        complete: that.handleStripeCallback
      });
    } else {
      that.form.submit();
    }
  };

  that.handleStripeCallback = function(jqXHR, textStatus) {
    var data = jqXHR.responseJSON;
    if (data.url) {
      location.href = data.url;
    } else if (data.payment_intent) {
      that.stripePaymentIntent(data.payment_intent, data.callback_url);
    }
  };

  that.stripePaymentIntent = function(paymentIntent, callbackUrl) {
    that.stripe.handleCardPayment(
      paymentIntent
    ).then(function() {
      $.ajax({
        url: callbackUrl,
        dataType: 'json',
        complete: that.handleStripeCallback
      })
    });
  };

  that.load();
}