import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "cardElement", "cardErrors", "expMonth", "expYear", "brand", "last4", "pmId" ];
  static styles = {
    base: {
      fontFamily: "Roboto, Arial, sans-serif",
      fontSize: "16px",
      color: "#5c5c5c",
      "::placeholder": {
        color: "#6c6c6c"
      }
    }
  };

  initialize() {
    this.parentForm = this.pmIdTarget.form;

    // Initialize Stripe JS
    this.stripe = Stripe(this.data.get("key"));
    this.stripeElement = this.stripe.elements().create("card", {
      style: this.constructor.styles,
      hidePostalCode: true
    });

    // Mount Stripe Elements JS to the form field
    this.stripeElement.mount(this.cardElementTarget);
  }

  connect() {
    this.parentForm.addEventListener("submit", this.stripeSubmit);
    this.stripeElement.addEventListener("change", this.updateErrors);
  }

  // Before the form is submitted we send the card details directly to Stripe (via StripeJS),
  // and receive a token which represents the card object, and add that token into the form.
  stripeSubmit = (event) => {
    if(!this.stripeSelected()) { return }

    event.preventDefault();
    event.stopPropagation();

    this.stripe.createPaymentMethod({type: "card", card: this.stripeElement}).then(response => {
      if (response.error) {
        this.updateErrors(response);
      } else {
        this.pmIdTarget.setAttribute("value", response.paymentMethod.id);
        this.expMonthTarget.setAttribute("value", response.paymentMethod.card.exp_month);
        this.expYearTarget.setAttribute("value", response.paymentMethod.card.exp_year);
        this.brandTarget.setAttribute("value", response.paymentMethod.card.brand);
        this.last4Target.setAttribute("value", response.paymentMethod.card.last4);

        this.parentForm.submit();
      }
    });
  }

  // Update validation messages from Stripe shown in the form
  updateErrors = (data) => {
    if (data.error) {
      this.cardErrorsTarget.textContent = data.error.message;
    } else {
      this.cardErrorsTarget.textContent = "";
    }
  }

  // Boolean; true if Stripe is shown / currently selected
  stripeSelected() {
    return !!this.cardElementTarget.offsetParent
  }
}

import { Controller } from "stimulus"

export default class extends Controller {
  static targets = [ "cardElement", "cardErrors", "expMonth", "expYear", "brand", "last4", "pmId" ];
  static styles = {
    base: {
      fontFamily: "Roboto, Arial, sans-serif",
      fontSize: "16px",
      color: "#5c5c5c",
      "::placeholder": {
        color: "#6c6c6c"
      }
    }
  };

  initialize() {
    this.parentForm = this.pmIdTarget.form;

    // Initialize Stripe JS
    this.stripe = Stripe(this.data.get("key"));
    this.stripeElement = this.stripe.elements().create("card", {
      style: this.constructor.styles,
      hidePostalCode: true
    });

    // Mount Stripe Elements JS to the form field
    this.stripeElement.mount(this.cardElementTarget);
  }

  connect() {
    this.parentForm.addEventListener("submit", this.stripeSubmit);
    this.stripeElement.addEventListener("change", this.updateErrors);
  }

  disconnect() {
    this.parentForm.removeEventListener("submit", this.stripeSubmit);
    this.stripeElement.removeEventListener("change", this.updateErrors);
  }

  // Before the form is submitted we send the card details directly to Stripe (via StripeJS),
  // and receive a token which represents the card object, and add that token into the form.
  stripeSubmit = (event) => {
    if(!this.stripeSelected()) { return }

    event.preventDefault();
    event.stopPropagation();

    this.stripe.createPaymentMethod({type: "card", card: this.stripeElement}).then(response => {
      if (response.error) {
        this.updateErrors(response);
      } else {
        this.pmIdTarget.setAttribute("value", response.paymentMethod.id);
        this.expMonthTarget.setAttribute("value", response.paymentMethod.card.exp_month);
        this.expYearTarget.setAttribute("value", response.paymentMethod.card.exp_year);
        this.brandTarget.setAttribute("value", response.paymentMethod.card.brand);
        this.last4Target.setAttribute("value", response.paymentMethod.card.last4);

        this.parentForm.submit();
      }
    });
  }

  // Update validation messages from Stripe shown in the form
  updateErrors = (data) => {
    if (data.error) {
      this.cardErrorsTarget.textContent = data.error.message;
    } else {
      this.cardErrorsTarget.textContent = "";
    }
  }

  // Boolean; true if Stripe is shown / currently selected
  stripeSelected() {
    return !!this.cardElementTarget.offsetParent
  }
}

Implement disconnect() to tidy up (remove) event listeners from the DOM when finished