1import { Controller } from '@hotwired/stimulus'; 2 3export default class extends Controller { 4 static targets = ['paymentInput', 'errorMessage', 'submitButton'] 5 6 static values = { 7 publishableKey: String, 8 returnUrl: String, 9 clientSecret: String, 10 stripeAccountId: String 11 } 12 13 connect() { 14 this.setupStripe(); 15 } 16 17 setupStripe(){ 18 const stripeOptions = this.stripeAccountIdValue !== "" ? { stripeAccount: this.stripeAccountIdValue } : {}; 19 this.stripe = Stripe(this.publishableKeyValue, stripeOptions); 20 21 // Stripe mounts in an iframe and can't inherit our CSS custom properties, 22 // so the design system token has to be resolved and passed as a literal. 23 const appearance = { 24 theme: 'stripe', 25 26 variables: { 27 colorBackground: getComputedStyle(this.element).getPropertyValue('--color-gray-50').trim(), 28 fontSizeBase: '14px', 29 } 30 }; 31 32 this.elements = this.stripe.elements({ appearance, clientSecret: this.clientSecretValue }); 33 34 const paymentElementOptions = { 35 layout: "tabs", 36 }; 37 38 const paymentElement = this.elements.create("payment", paymentElementOptions); 39 paymentElement.mount("#payment-element"); 40 } 41 42 async collectPayment(e) { 43 e.preventDefault(); 44 this.setLoading(true); 45 46 const { error } = await this.stripe.confirmPayment({ 47 elements: this.elements, 48 confirmParams: { 49 return_url: this.returnUrlValue, 50 }, 51 }); 52 53 // This point will only be reached if there is an immediate error when 54 // confirming the payment. Otherwise, the customer will be redirected to 55 // submitReturnRequest page. 56 if (error.type === "card_error" || error.type === "validation_error") { 57 this.showMessage(error.message); 58 } else { 59 this.showMessage("An unexpected error occurred. Try again or contact [email protected]"); 60 } 61 62 this.setLoading(false); 63 } 64 65 showMessage(messageText) { 66 const messageContainer = document.querySelector("#payment-message"); 67 68 messageContainer.classList.remove("hidden"); 69 messageContainer.textContent = messageText; 70 71 setTimeout(function () { 72 messageContainer.classList.add("hidden"); 73 messageContainer.textContent = ""; 74 }, 4000); 75 } 76 77 // Show a spinner on payment submission 78 setLoading(isLoading) { 79 if (isLoading) { 80 // Disable the button and show a spinner 81 document.querySelector("#submit").disabled = true; 82 document.querySelector("#spinner").classList.remove("hidden"); 83 } else { 84 document.querySelector("#submit").disabled = false; 85 document.querySelector("#spinner").classList.add("hidden"); 86 } 87 } 88}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.