@liberquack/utils
Version:
Quack utilities
148 lines • 6.47 kB
JavaScript
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