Home Reference Source

src/contrib/stripe/checkout/StripeCheckout.js

/* globals StripeCheckout */
import _ from 'lodash';
import ButtonComponent from '../../../components/button/Button';
import { GlobalFormio as Formio } from '../../../Formio';

export default class StripeCheckoutComponent extends ButtonComponent {
  constructor(component, options, data) {
    super(component, options, data);

    // Get the source for Stripe API
    const src = 'https://checkout.stripe.com/checkout.js';

    /**
     * Promise when Stripe is ready.
     * @type {Promise}
     */
    this.stripeCheckoutReady = Formio.requireLibrary('stripeCheckout', 'StripeCheckout', src, true);

    /**
     * Keep initial component action
     * @type {String}
     */
    this.componentAction = this.component.action;

    // Force button to handle event action to build button
    this.component.action = 'event';
  }

  static get builderInfo() {
    return {
      group: false,
      schema: ButtonComponent.schema()
    };
  }

  getValue() {
    return this.dataValue;
  }

  setValue(value, flags = {}) {
    return this.updateValue(value, flags);
  }

  /**
   * Handle event dispatched by Stripe library
   * @param {Object} token - The token returned by Stripe.
   */
  onToken(token) {
    this.setValue(token.id);
    // In case of submit, submit the form
    if (this.componentAction === 'submit') {
      this.emit('submitButton');
    }
    else {
      this.addClass(this.element, 'btn-success');
      this.disabled = true;
    }
  }

  /**
   * Handle customEvent event on the button
   * @param {Object} event - The event returned by ButtonComponent.
   */
  onClickButton(event) {
    // Return if component call is not the current component
    if (this.component.key !== event.component.key) {
      return;
    }

    // Open Checkout with further options:
    const popupConfiguration = _.cloneDeep(this.component.stripe.popupConfiguration) || {};
    _.each(popupConfiguration, (value, key) => {
      popupConfiguration[key] = this.t(value);
    });

    if (this.componentAction === 'submit') {
      // In case of submit, validate the form before opening button
      if (this.root.isValid(event.data, true)) {
        this.handler.open(popupConfiguration);
      }
      else {
        // If the form is not valid, submit it to draw errors
        this.emit('submitButton');
      }
    }
    else {
      this.handler.open(popupConfiguration);
    }
  }

  build() {
    // Build button
    super.build();

    // In case of submit, add event listeners
    if (this.componentAction === 'submit') {
      this.on('submitButton', () => {
        this.loading = true;
        this.disabled = true;
      }, true);
      this.on('submitDone', () => {
        this.loading = false;
        this.disabled = false;
      }, true);
      this.on('change', (value) => {
        this.loading = false;
        this.disabled = (this.component.disableOnInvalid && !this.root.isValid(value.data, true));
      }, true);
      this.on('error', () => {
        this.loading = false;
      }, true);
    }

    // When stripe checkout is ready, create the handler and add event listeners
    this.stripeCheckoutReady.then(() => {
      const handlerConfiguration = _.cloneDeep(this.component.stripe.handlerConfiguration) || {};
      handlerConfiguration.key = this.component.stripe.apiKey;
      handlerConfiguration.token = this.onToken.bind(this);
      if (typeof handlerConfiguration.locale === 'undefined') {
        handlerConfiguration.locale = this.options.language;
      }
      this.handler = StripeCheckout.configure(handlerConfiguration);

      this.on('customEvent', this.onClickButton.bind(this));

      this.addEventListener(window, 'popstate', () => {
        this.handler.close();
      });
    });
  }
}

if (typeof global === 'object' && global.Formio && global.Formio.registerComponent) {
  global.Formio.registerComponent('stripeCheckout', StripeCheckoutComponent);
}