UNPKG

@liberquack/utils

Version:
148 lines 6.47 kB
import { loadStripe } from "@stripe/stripe-js"; import { AbstractPaymentClientProvider } from "./abstract-payment-client-provider.js"; import { dictionaryMapList } from "../../_/dictionary.js"; import { countries } from "../countries.js"; import { produce } from "immer"; /** * This stripe client provider */ export class PaymentStripeClientProvider extends AbstractPaymentClientProvider { provider = "stripe"; stripePromise; constructor(stripePublicKey) { super(); this.stripePromise = loadStripe(stripePublicKey); } async checkout(checkout) { const stripe = await this.stripePromise; if (!stripe) throw "Could not load stripe"; const { paymentMethodToken, clientSecret, intentStatus } = checkout.externalData.data; const cardElement = checkout.clientData?.cardElement; if (!cardElement) throw "Expected stripe elements instance on checkout.clientData"; if (!paymentMethodToken) { const tokenResult = await stripe.createToken(cardElement); if (tokenResult.error) { throw tokenResult.error.message; } const checkoutWithPaymentToken = produce(checkout, (it) => { it.externalData.data.paymentMethodToken = tokenResult.token; }); return { ...checkoutWithPaymentToken, success: false, externalId: false, }; } if (clientSecret && checkout.externalId) { if (intentStatus === "requires_action") { const result = await (checkout.externalId.startsWith("seti_") ? stripe.confirmCardSetup(clientSecret) : stripe.confirmCardPayment(clientSecret, undefined)); const setupIntent = "setupIntent" in result ? result.setupIntent : undefined; const payIntent = "paymentIntent" in result ? result.paymentIntent : undefined; const intent = setupIntent ?? payIntent; const intentId = intent?.id ?? (result.error?.payment_intent || result.error?.setup_intent)?.id; if (!intentId) { throw "Unexpected error"; } return { ...checkout, success: false, externalId: intentId, errorMessage: result.error?.message }; } } throw "Payment failed, unexpected checkout flow"; } async buildUi(checkout, opts, sendCheckoutToServer) { const { html, render } = await import("./stripe/dependencies.js"); let stripeFormTemplate = html ` <stripe-form .stripeClient="${await this.stripePromise}"> ${opts.htmlTemplate ?? html ` <stripe-submit-form> <form @submit="${(e) => e.preventDefault()}"> <div> <input type="email" placeholder="Email" name="email" required> </div> <div> <stripe-element .type="${"card"}" .opts="${{ hidePostalCode: true }}"></stripe-element> </div> <div> <stripe-submit-error></stripe-submit-error> </div> <div> <input type="text" placeholder="Cardholder Name" name="name" required> </div> <div> <select name="country" required> <option disabled selected>Country</option> ${dictionaryMapList(countries, (key, value) => html ` <option value="${key}">${value}</option> `)} </select> </div> <div> <input type="text" placeholder="Postal Code" name="postalCode" required> </div> <button> Pay </button> </form> </stripe-submit-form> `} </stripe-form> `; const container = document.createElement("div"); container.addEventListener("payment-method-token", (e) => { const formElm = container.querySelector("form"); const formData = formElm && Object.fromEntries(new FormData(formElm).entries()); const nextCheckout = { ...checkout, externalData: { provider: "stripe", data: { ...checkout.externalData.data, billingData: { //TODO: provide opts for including custom inputs email: getString(formData, "email"), name: getString(formData, "name"), phone: getString(formData, "phone"), address: { city: getString(formData, "city"), country: getString(formData, "country"), line1: getString(formData, "address1"), line2: getString(formData, "address2"), postal_code: getString(formData, "postalCode"), state: getString(formData, "state"), } } } }, clientData: { cardElement: e.detail.cardElement, } }; sendCheckoutToServer(nextCheckout); }); render(stripeFormTemplate, container); return container; } maxRoundTrips() { return 3; } } function getString(obj, key) { if (!obj) return undefined; const value = obj[key]; if (value && !(value instanceof File)) { return value; } else { return undefined; } } //# sourceMappingURL=payment-stripe-client-provider.js.map