UNPKG

@liberquack/utils

Version:
107 lines 4.36 kB
import { inlineErr } from "../inline-error.js"; /** * PaymentClient is the class for executing the checkout on front-end */ export class AbstractPaymentClient { inited = false; providers = []; providersInitializers; constructor(providers) { this.providersInitializers = providers; } init() { if (this.inited) return; this.providers = this.providersInitializers.map(it => it()); this.inited = true; } async buildUi(calculatedCheckout, opts) { this.checkInited(); const provider = this.getProvider(calculatedCheckout); const checkoutContainer = document.createElement("div"); checkoutContainer.setAttribute("style", "position: relative"); const overlay = document.createElement("div"); overlay.setAttribute("style", ` position: absolute; display: grid; align-items: center; justify-items: center; left: 0; right: 0; top: 0; bottom: 0; opacity: 0; transition: .3s; pointer-events: none; `); const overlayLoading = overlay.cloneNode(); overlayLoading.style.background = "#0008"; const loadingIndicator = document.createElement("div"); loadingIndicator.textContent = "Processing..."; overlayLoading.append(loadingIndicator); const overlaySuccess = overlay.cloneNode(); overlaySuccess.style.background = "#fff"; const successIndicator = document.createElement("div"); successIndicator.textContent = "Success!"; overlaySuccess.append(successIndicator); const providerElm = await provider.buildUi(calculatedCheckout, opts, async (calculatedCheckout) => { overlayLoading.style.opacity = "1"; overlayLoading.style.pointerEvents = ""; const [checkoutExecution, err] = await inlineErr(this.checkout(calculatedCheckout)); if (checkoutExecution?.success) { opts.onSuccess(checkoutExecution); overlaySuccess.style.opacity = "1"; overlaySuccess.style.pointerEvents = ""; } else { overlayLoading.style.opacity = "0"; overlayLoading.style.pointerEvents = "none"; const errorMessage = checkoutExecution?.errorMessage || err?.message || err; opts.onError(errorMessage || "Unexpected error", checkoutExecution); } }); checkoutContainer.append(providerElm); checkoutContainer.append(overlayLoading); checkoutContainer.append(overlaySuccess); return checkoutContainer; } async calculateCheckout(checkout) { const calculatedCheckout = this.sendCalculateCheckout(checkout); return calculatedCheckout; } async checkout(checkout) { this.checkInited(); const providerInstance = this.getProvider(checkout); let currentRoundTrip = 0; let maxRoundTrips = providerInstance.maxRoundTrips() ?? 0; let lastExecution; while (currentRoundTrip < maxRoundTrips) { const providerCheckout = await providerInstance.checkout(lastExecution ?? checkout); lastExecution = await this.sendCheckout(providerCheckout); if (lastExecution?.success) { return lastExecution; } if (lastExecution?.errorMessage) { break; } currentRoundTrip++; } throw lastExecution?.errorMessage ?? "Payment failed, try other payment method\nor contact support"; } getProvider(checkout) { const providerInstance = this.providers.find(it => it.provider === checkout.provider); if (!providerInstance) { throw `There's no provider ${checkout.provider} available, try one of [${this.providers.map(it => it.provider)}]`; } return providerInstance; } checkInited() { if (!this.inited) throw "Payment client instance has still not been initiated"; } async cancelCheckout(checkout, reason) { const nextCheckout = { ...checkout, reason }; return this.sendCancelCheckout(checkout); } } //# sourceMappingURL=abstract-payment-client.js.map