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; this.catchFormSubmit = true; // Initialize Stripe JS this.stripe = Stripe(this.data.get("key")); this.stripeElement = this.stripe.elements({ locale: I18n.base_locale }).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() || !this.catchFormSubmit) { 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.catchFormSubmit = false; event.submitter.click(); } }); }; // 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; } }