UNPKG

bitsnap-checkout

Version:

This is Bitsnap Checkout React library for easy integration with any website which is using React framework

1,240 lines (1,215 loc) 55.7 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Bitsnap: () => Bitsnap, BitsnapCheckout: () => BitsnapCart_default, addProductToCart: () => addProductToCart, createCheckout: () => createCheckout, createPaymentURL: () => createPaymentURL, handleWebhook: () => handleWebhook, handleWebhookSignature: () => handleWebhookSignature, hideCart: () => hideCart, injectReferenceToRequestIfNeeded: () => injectReferenceToRequestIfNeeded, setCustomHost: () => setCustomHost, setProjectID: () => setProjectID, showCart: () => showCart }); module.exports = __toCommonJS(src_exports); // src/components/checkout/BitsnapCart.tsx var import_react7 = require("react"); var import_zod2 = __toESM(require("zod")); // src/components/checkout/CartComponent.tsx var import_react6 = require("@formkit/auto-animate/react"); var import_react_dom = require("react-dom"); // src/components/checkout/CartComponentContent.tsx var import_react4 = require("@formkit/auto-animate/react"); var import_react5 = __toESM(require("react")); var import_react_query2 = require("react-query"); // src/components/checkout/CartProvider.tsx var import_react = require("react"); var import_react_query = require("react-query"); var import_zod = __toESM(require("zod")); // src/components/checkout/constants.ts var HOST = "https://bitsnap.pl"; function setCustomHost(host) { HOST = host; } // src/components/checkout/helper.methods.ts function buildURL(projectID, path) { return `${HOST}/api/integrations/${projectID}/public-commerce${path}`; } // src/components/checkout/lib/err.ts function isErr(x) { return typeof x === "object" && x != null && "ERR" in x; } function Err(message, type) { return { ERR: true, error: message, type }; } // src/components/checkout/state.ts var import_zustand = require("zustand"); var useCheckoutStore = (0, import_zustand.create)((set) => ({ isCartVisible: false, showCart: () => set((state) => ({ ...state, isCartVisible: true })), hideCart: () => set((state) => ({ ...state, isCartVisible: false })) })); // src/components/checkout/methods.ts async function addProductToCart(id, quantity = 1, metadata) { return Bitsnap.addProductToCart(id, quantity, metadata); } function showCart() { return Bitsnap.showCart(); } function hideCart() { return Bitsnap.hideCart(); } var Bitsnap; ((Bitsnap2) => { async function addProductToCart2(id, quantity = 1, metadata) { const projectID = getProjectID(); if (projectID == null) { throw new Error("No project ID found"); } const methods = getCheckoutMethods(projectID); const err = await methods.addProduct({ productID: id, quantity, metadata }); if (err != null) { return err; } return void 0; } Bitsnap2.addProductToCart = addProductToCart2; function showCart2() { useCheckoutStore.setState({ isCartVisible: true }); } Bitsnap2.showCart = showCart2; function hideCart2() { useCheckoutStore.setState({ isCartVisible: false }); } Bitsnap2.hideCart = hideCart2; })(Bitsnap || (Bitsnap = {})); async function createPaymentURL(request) { const projectID = getProjectID(); if (projectID == null) { throw new Error("No project ID found"); } request = injectReferenceToRequestIfNeeded(request); const result = await fetch(buildURL(projectID, "/buy"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(request) }); if (result.status != 200) { console.warn( "result", await result.text(), result.status, result.statusText ); return Err("internal-error", "internal"); } const response = await result.json(); return { url: response.url }; } async function createCheckout(request) { const projectID = getProjectID(); if (projectID == null) { throw new Error("No project ID found"); } const headers = { "Content-Type": "application/json", ...request.apiKey != null ? { Authorization: `Bearer ${request.apiKey}` } : {} }; const path = request.testMode ? `/api/payment/link/auto/${projectID}/test` : `/api/payment/link/auto/${projectID}`; delete request.apiKey; delete request.testMode; const response = await fetch(HOST + path, { method: "POST", headers, body: JSON.stringify(request) }); const payload = await response.json(); return { status: "ok", redirectURL: payload.url }; } function getReferenceIfPossible() { if (typeof localStorage == "undefined") { return void 0; } const refLink = localStorage.getItem("bitsnap-ref"); if (refLink == null) { return void 0; } return refLink; } function injectReferenceToRequestIfNeeded(request) { const ref = getReferenceIfPossible(); if (ref == null) { return request; } if (request.metadata == null) { request.metadata = {}; } request.metadata["ref"] = ref; return request; } // src/components/checkout/CartProvider.tsx var import_jsx_runtime = require("react/jsx-runtime"); var MARKETING_AGREEMENT_ID = "__m_a"; var CartProviderContext = (0, import_react.createContext)(void 0); var bitsnapProjectID = void 0; function setProjectID(projectID) { bitsnapProjectID = projectID; } function getProjectID() { if (bitsnapProjectID != null) { return bitsnapProjectID; } const me = document.querySelector( 'script[data-id][data-name="internal-cart"]' ); const projectID = me == null ? void 0 : me.getAttribute("data-id"); return projectID != null ? projectID : void 0; } function getNewHostIfExist() { const me = document.querySelector( 'script[data-id][data-name="internal-cart"]' ); const customHost = me == null ? void 0 : me.getAttribute("data-custom-host"); return customHost != null ? customHost : void 0; } var CartProvider = ({ children }) => { const queryClient = new import_react_query.QueryClient(); const projectID = getProjectID(); if (projectID == null) { return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {}); } const checkoutMethods = getCheckoutMethods(projectID); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_query.QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CartProviderContext.Provider, { value: checkoutMethods, children }) }); }; var useCartProvider = () => { const context = (0, import_react.useContext)(CartProviderContext); if (context === void 0) { throw new Error("useCartProvider must be used within a CartProvider"); } return context; }; var CartProvider_default = CartProvider; var checkoutSchema = import_zod.default.object({ country: import_zod.default.string().optional(), products: import_zod.default.array( import_zod.default.object({ id: import_zod.default.string(), productID: import_zod.default.string(), quantity: import_zod.default.number(), metadata: import_zod.default.record(import_zod.default.string(), import_zod.default.string().optional()).optional() }) ).optional() }); var emptyCheckout = { country: void 0, products: [] }; var checkoutKey = "checkout"; function getCheckout() { try { const value = localStorage.getItem(checkoutKey); if (value == null) { return emptyCheckout; } return checkoutSchema.parse(JSON.parse(value)); } catch (e) { return emptyCheckout; } } function saveCheckout(model) { localStorage.setItem(checkoutKey, JSON.stringify(model)); } var getCheckoutMethods = (projectID) => { const newHost = getNewHostIfExist(); if (newHost != null) { setCustomHost(newHost); } return { async clearCart() { var _a; const empty = structuredClone(emptyCheckout); empty.country = (_a = getCheckout()) == null ? void 0 : _a.country; saveCheckout(empty); }, async getAvailableCountries() { const result = await fetch(buildURL(projectID, "/countries"), { method: "GET" }); if (result.status != 200) { return []; } try { return import_zod.default.array( import_zod.default.object({ name: import_zod.default.string(), code: import_zod.default.string() }) ).parse(await result.json()); } catch (e) { return Err(e.toString(), "internal"); } }, async getCountry() { var _a; let country = (_a = getCheckout()) == null ? void 0 : _a.country; if (country == null) { country = "PL"; const checkout = getCheckout(); checkout.country = country; saveCheckout(checkout); } return country; }, async getNumberOfElementsInCart() { var _a, _b, _c; return (_c = (_b = (_a = getCheckout()) == null ? void 0 : _a.products) == null ? void 0 : _b.reduce( (acc, product) => acc + product.quantity, 0 )) != null ? _c : 0; }, async getProducts() { var _a, _b; const products = (_b = (_a = getCheckout()) == null ? void 0 : _a.products) != null ? _b : []; const productIds = Array.from( new Set(products.map((product) => product.productID)) ); const params = new URLSearchParams(); params.set("ids", productIds.join(",")); const result = await fetch( buildURL(projectID, `/products?${params.toString()}`), { method: "GET" } ); if (result.status != 200) { return []; } const payload = await result.json(); products.forEach((product) => { var _a2; product["details"] = (_a2 = payload.result) == null ? void 0 : _a2.find((el) => { if (el.id === product.productID) { return true; } if (el.variants != null && el.variants.length > 0) { const index = el.variants.findIndex( (variant) => variant.id === product.productID ); return index !== -1; } return false; }); }); return products.filter((el) => "details" in el).map((el) => { el.details = resolveProductDetailsFromSingleProduct( el.productID, el.details ); return el; }); }, async removeProductFromCart(args) { var _a; const checkout = getCheckout(); const newCheckout = { ...checkout, products: (_a = checkout == null ? void 0 : checkout.products) == null ? void 0 : _a.filter( (product) => product.id !== args.id ) }; saveCheckout(newCheckout); }, async setCountry(country) { const checkout = getCheckout(); checkout.country = country; saveCheckout(checkout); }, async addProduct(args) { const checkout = getCheckout(); if (checkout.products == null) { checkout.products = []; } checkout.products.push({ id: Math.random().toString(36).substring(7), productID: args.productID, quantity: args.quantity, metadata: args.metadata }); saveCheckout(checkout); }, async updateQuantity(args) { var _a; const checkout = getCheckout(); checkout.products = (_a = checkout.products) == null ? void 0 : _a.map((product) => { if (product.id === args.id) { product.quantity = args.quantity; } return product; }); saveCheckout(checkout); }, async redirectToNextStep() { const checkout = getCheckout(); if (checkout.products == null || checkout.products.length == 0) { return Err("cart-is-empty", "badInput"); } const mergedMetadata = checkout.products.reduce( (acc, product) => { if (product.metadata != null) { Object.keys(product.metadata).forEach((key) => { var _a; const value = (_a = product.metadata) == null ? void 0 : _a[key]; if (value != null) { acc[key] = value; } }); } return acc; }, {} ); const payload = { items: checkout.products.map((el) => { return { id: el.productID, quantity: el.quantity }; }), askForNote: true, countries: checkout.country ? [checkout.country] : void 0, metadata: mergedMetadata }; const paymentResponse = await createPaymentURL(payload); if (isErr(paymentResponse)) { console.warn("cannot create payment URL", paymentResponse.error); return paymentResponse; } return { url: paymentResponse.url }; }, async justRedirectToPayment(args) { let payload = { items: [ { id: args.productID, quantity: 1 } ], askForNote: false, details: args.email || args.name ? { name: args.name, email: args.email } : void 0 }; payload = injectReferenceToRequestIfNeeded(payload); if (args.country == null) { args.country = "pl"; } if (payload.details == null) { payload.details = {}; } if (payload.details.address == null) { payload.details.address = {}; } payload.details.address.country = args.country; if (args.marketingAgreement === true) { payload.additionalAgreements = [ { id: MARKETING_AGREEMENT_ID, name: "", required: true, answer: true } ]; } const result = await fetch(buildURL(projectID, "/buy"), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) }); console.log("CODE", result.status); if (result.status != 200) { console.warn( "result", await result.text(), result.status, result.statusText ); return Err("internal-error", "internal"); } const response = await result.json(); console.log(response.url); return { url: response.url }; } }; }; function resolveProductDetailsFromSingleProduct(id, product) { var _a, _b; if (id == product.id) { return product; } const variant = (_a = product.variants) == null ? void 0 : _a.find((v) => v.id === id); if (variant == null) { return product; } return { ...product, id: variant.id, name: product.name + " " + variant.name, price: variant.price, currency: variant.currency, metadata: product.metadata, availableQuantity: variant.availableQuantity, isDeliverable: variant.isDeliverable, images: (_b = variant.images) != null ? _b : product.images }; } // src/components/checkout/CountrySelector.tsx var import_framer_motion = require("framer-motion"); var import_react2 = require("react"); var import_jsx_runtime2 = require("react/jsx-runtime"); function CountrySelector({ id, open, disabled = false, onToggle, onChange, selectedValue, countries }) { var _a; const ref = (0, import_react2.useRef)(null); (0, import_react2.useEffect)(() => { const mutableRef = ref; const handleClickOutside = (event) => { if (mutableRef.current && // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error !mutableRef.current.contains(event.target) && open) { onToggle(); setQuery(""); } }; window.document.addEventListener("mousedown", handleClickOutside); return () => { document.removeEventListener("mousedown", handleClickOutside); }; }, [ref]); (0, import_react2.useEffect)(() => { if (selectedValue == null && countries.length > 0) { onChange(countries[0].code); } }, []); const [query, setQuery] = (0, import_react2.useState)(""); return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { ref, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "relative", children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)( "button", { type: "button", className: `${disabled ? "ics-bg-neutral-100" : "ics-bg-extra-light-white"} ics-relative ics-w-full ics-rounded-2xl ics-shadow-sm ics-pl-8 ics-pr-10 ics-py-3 ics-text-left ics-cursor-default focus:ics-outline-none focus:ics-ring-1 focus:ics-ring-blue-500 focus:ics-border-blue-500 sm:ics-text-sm`, "aria-haspopup": "listbox", "aria-expanded": "true", "aria-labelledby": "listbox-label", onClick: onToggle, disabled, children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "ics-truncate ics-flex ics-items-center", children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "img", { alt: `${selectedValue}`, src: `https://purecatamphetamine.github.io/country-flag-icons/3x2/${selectedValue}.svg`, className: "ics-inline ics-mr-2 ics-h-4 ics-rounded-sm" } ), (_a = countries.find((el) => el.code === selectedValue)) == null ? void 0 : _a.name ] }), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "span", { className: `ics-absolute ics-inset-y-0 ics-right-0 ics-flex ics-items-center ics-pr-2 ics-pointer-events-none ${disabled ? "ics-hidden" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "svg", { className: "h-5 w-5 text-light-purple", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "path", { fillRule: "evenodd", d: "M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z", clipRule: "evenodd" } ) } ) } ) ] } ), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_framer_motion.AnimatePresence, { children: open && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)( import_framer_motion.motion.ul, { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, transition: { duration: 0.1 }, className: "ics-absolute ics-z-10 -ics-mt-80 ics-w-full dark:ics-bg-neutral-800 ics-bg-white ics-shadow-lg ics-max-h-80 ics-rounded-md ics-text-body-regular ics-ring-1 ics-ring-black ics-ring-opacity-5 focus:ics-outline-none sm:ics-text-body-regular", tabIndex: -1, role: "listbox", "aria-labelledby": "listbox-label", "aria-activedescendant": "listbox-option-3", children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ics-sticky ics-top-0 ics-z-10 ics-bg-white dark:ics-bg-neutral-800", children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "dark:ics-text-neutral-200 ics-text-neutral-900 ics-cursor-default ics-select-none ics-relative ics-py-2 ics-px-3", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "input", { type: "search", name: "search", autoComplete: "off", className: "ics-block ics-w-full ics-outline-none sm:ics-text-body-regular dark:ics-text-neutral-400 ics-text-dark-blue ics-bg-transparent ics-border-light-purple ics-rounded-md placeholder:ics-text-light-purple", placeholder: "Znajd\u017A kraj", onChange: (e) => setQuery(e.target.value) } ) }), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("hr", {}) ] }), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "div", { className: "ics-max-h-64 ics-scrollbar ics-scrollbar-track-gray-100 ics-scrollbar-thumb-gray-300 hover:ics-scrollbar-thumb-gray-600 ics-scrollbar-thumb-rounded ics-scrollbar-thin ics-overflow-y-scroll", children: countries.filter( (country) => country.name.toLowerCase().startsWith(query.toLowerCase()) ).length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("li", { className: "ics-text-light-purple ics-cursor-default ics-select-none ics-relative ics-py-2 ics-pl-3 ics-pr-9", children: "No countries found" }) : countries.filter( (country) => country.name.toLowerCase().startsWith(query.toLowerCase()) ).map((value, index) => { return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)( "li", { className: "ics-text-dark-blue ics-cursor-default ics-select-none ics-relative ics-py-2 ics-pl-3 ics-pr-9 ics-flex ics-items-center hover:ics-bg-extra-light-white ics-transition", id: "listbox-option-0", role: "option", onClick: () => { onChange(value.code); setQuery(""); onToggle(); }, children: [ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "img", { alt: `${value.code}`, src: `https://purecatamphetamine.github.io/country-flag-icons/3x2/${value.code}.svg`, className: "ics-inline ics-mr-2 ics-h-4 ics-rounded-sm" } ), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ics-font-normal ics-truncate", children: value.name }), value.code === selectedValue ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "span", { className: "ics-text-blue-600 ics-absolute ics-inset-y-0 ics-right-0 ics-flex ics-items-center ics-pr-8", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "svg", { className: "h-5 w-5", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)( "path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" } ) } ) } ) : null ] }, `${id}-${index}` ); }) } ) ] } ) }) ] }) }); } var CountrySelector_default = CountrySelector; // src/components/checkout/lib/round.number.ts function formatCurrency(amount, currency) { const formatter = Intl.NumberFormat(navigator.language, { style: "currency", currency, currencyDisplay: "symbol" }); return formatter.format(amount / 100); } // src/components/checkout/LoadingIndicator.tsx var import_jsx_runtime3 = require("react/jsx-runtime"); var LoadingIndicator = ({ className }) => { return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(LoadingSpinner, { className: className != null ? className : "" }); }; var LoadingIndicator_default = LoadingIndicator; var LoadingSpinner = ({ size, color, className }) => { const spinnerStyle = { borderTop: `4px solid ${color}`, borderLeft: `4px solid ${color}`, borderBottom: `4px solid ${color}`, borderRight: "4px solid transparent", width: size != null ? size : "30px", height: size != null ? size : "30px", borderRadius: "50%" }; return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: className + " animate-spin", style: spinnerStyle }); }; // src/components/checkout/SingleProduct.tsx var import_react3 = require("react"); var import_jsx_runtime4 = require("react/jsx-runtime"); var SingleProduct = ({ quantity, details, shouldUpdate }) => { var _a; return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ics-flex ics-items-center ics-gap-3", children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("img", { className: "ics-aspect-auto ics-max-w-[30%]", src: (_a = details.image_url) != null ? _a : "", alt: details.name }), /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ics-flex ics-flex-col", children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ics-font-medium", children: details.name }), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "ics-text-sm", children: formatCurrency(details.price, details.currency) }), /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ics-flex ics-justify-between", children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QuantityComponent, { className: "", quantity, shouldUpdate }), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "ics-text-sm ics-font-medium", onClick: () => shouldUpdate(0), children: "Usu\u0144" }) ] }) ] }) ] }); }; var SingleProduct_default = SingleProduct; var QuantityComponent = ({ quantity, shouldUpdate, className }) => { const [quantityString, setQuantityString] = (0, import_react3.useState)(quantity.toString()); const [quantityValue, setQuantityValue] = (0, import_react3.useState)(quantity); (0, import_react3.useEffect)(() => { shouldUpdate(quantityValue); }, [quantityValue]); function setNewQuantity(newQuantity) { setQuantityString(newQuantity); if (newQuantity.length == 0) { return; } const parsedInt = parseInt(newQuantity); if (isNaN(parsedInt)) { setQuantityValue(1); setQuantityString(""); return; } if (parsedInt == 0 || parsedInt < 0) { setQuantityValue(1); setQuantityString("1"); return; } setQuantityValue(parsedInt); setQuantityString(parsedInt.toString()); } function increaseQuantity() { setQuantityValue(quantity + 1); setQuantityString((quantity + 1).toString()); } function decreaseQuantity() { if (quantity > 1) { setQuantityString((quantity - 1).toString()); setQuantityValue(quantity - 1); return; } setQuantityString(quantity.toString()); setQuantityValue(quantity); } return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `ics-flex ${className} ics-items-center ics-border dark:ics-border-neutral-400 ics-border-neutral-700 ics-rounded-md ics-my-1`, children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: decreaseQuantity, className: "ics-px-2 ics-py-1", children: "-" }), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "input", { className: "ics-w-8 ics-bg-transparent ics-text-center", value: quantityString, onInput: (e) => { setNewQuantity(e.currentTarget.value); }, type: "text" } ), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: increaseQuantity, className: "ics-px-2 ics-py-1", children: "+" }) ] }); }; // src/components/checkout/CartComponentContent.tsx var import_jsx_runtime5 = require("react/jsx-runtime"); var CartComponentContent = ({ className }) => { var _a, _b, _c, _d, _e; const provider = useCartProvider(); const { mutateAsync: removeProduct } = (0, import_react_query2.useMutation)( provider.removeProductFromCart ); const { mutateAsync: updateQuantity } = (0, import_react_query2.useMutation)(provider.updateQuantity); const { mutateAsync: setCountryAsync } = (0, import_react_query2.useMutation)(provider.setCountry); const { mutateAsync: clearCart } = (0, import_react_query2.useMutation)(provider.clearCart); const [errMsg, setErrMsg] = import_react5.default.useState(""); const [isCountryOpen, setIsCountryOpen] = import_react5.default.useState(false); const { mutateAsync: continueToCheckoutAsync, isLoading: isContinueToCheckoutLoading } = (0, import_react_query2.useMutation)(provider.redirectToNextStep); const { data: availableCountries } = (0, import_react_query2.useQuery)( "cart-available-countries", provider.getAvailableCountries ); const { data, isLoading, refetch } = (0, import_react_query2.useQuery)("cart", provider.getProducts); const { data: countryData, refetch: refetchCountry } = (0, import_react_query2.useQuery)( "cart-country", provider.getCountry ); const [productsParent] = (0, import_react4.useAutoAnimate)( /* optional config */ ); const products = isErr(data) ? void 0 : data; const countries = isErr(availableCountries) ? [] : availableCountries; const sumOfProducts = (_a = products == null ? void 0 : products.reduce((prev, curr) => { if (curr.details == null) { return prev; } return prev + curr.details.price * curr.quantity; }, 0)) != null ? _a : 0; const currency = (_d = (_c = (_b = products == null ? void 0 : products[0]) == null ? void 0 : _b.details) == null ? void 0 : _c.currency) != null ? _d : "PLN"; const isSomeProductDeliverable = (_e = products == null ? void 0 : products.some((product) => { var _a2; return ((_a2 = product.details) == null ? void 0 : _a2.isDeliverable) === true; })) != null ? _e : false; const selectedCountry = countryData != null && !isErr(countryData) && countryData != "" ? countryData : void 0; async function shouldUpdate(id, newQuantity) { if (newQuantity != null) { if (newQuantity <= 0) { await removeProduct({ id }); await refetch(); return; } await updateQuantity({ id, quantity: newQuantity }); await refetch(); return; } } async function continueToCheckout() { try { setErrMsg(""); const response = await continueToCheckoutAsync(); if (isErr(response)) { setErrMsg(`${response.error}`); return; } await clearCart(); window.location.href = response.url; } catch (e) { setErrMsg(`${e}`); } } return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `${className} ics-flex ics-flex-col`, ref: productsParent, children: [ isLoading && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ics-flex ics-w-full ics-justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(LoadingIndicator_default, {}) }), !isLoading && (products == null || products.length == 0) && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ics-flex ics-flex-col ics-gap-4 ics-p-4", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "dark:ics-text-neutral-400 ics-text-neutral-700", children: "Brak produkt\xF3w w koszyku." }) }), /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "div", { className: "ics-max-h-[70vh] ics-overflow-clip ics-overflow-y-scroll", children: products != null && products.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "ics-mt-5", children: products.map((product) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_react5.default.Fragment, { children: product.details != null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { className: "mb-3", children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( SingleProduct_default, { quantity: product.quantity, details: product.details, shouldUpdate: (newQuantity) => { shouldUpdate(product.id, newQuantity).then().catch(); } } ), /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("hr", { className: "ics-h-1 dark:ics-border-neutral-700 ics-border-neutral-400" }) ] }) }, product.id)) }) } ), /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "grow" }), sumOfProducts > 0 && currency != null && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ics-mx-3 ics-flex ics-flex-col", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)( "div", { className: "ics-flex ics-flex-row ics-justify-between ics-text-lg", children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "p", { className: "dark:ics-text-neutral-200 ics-text-neutral-800 ics-text-xl", children: "Suma:" } ), /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ics-flex ics-flex-col ics-items-end", children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "p", { className: "dark:ics-text-neutral-200 ics-text-neutral-800 ics-font-medium", children: formatCurrency(sumOfProducts, currency) } ), isSomeProductDeliverable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ics-opacity-70 ics-text-right ics-text-base", children: "+ dostawa" }) ] }) ] } ) }), countries && (countries == null ? void 0 : countries.length) > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "h4", { className: "ics-ml-3 ics-text-sm dark:ics-text-neutral-400 ics-text-neutral-700", children: "Wybierz kraj" } ), /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( CountrySelector_default, { id: Math.random().toString(), open: isCountryOpen, onToggle: () => { setIsCountryOpen(!isCountryOpen); }, onChange: (newValue) => { setCountryAsync(newValue).then(() => { refetchCountry().then().catch(); }); }, selectedValue: selectedCountry != null ? selectedCountry : "", countries } ) ] }), /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ics-mb-3 ics-flex ics-flex-col", children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "button", { onClick: continueToCheckout, disabled: isLoading || isContinueToCheckoutLoading || selectedCountry == null, className: "ics-px-3 ics-py-2 ics-my-2 ics-mx-2 ics-rounded-md disabled:ics-opacity-40 disabled:ics-cursor-not-allowed dark:ics-bg-neutral-300 dark:hover:ics-bg-neutral-100 dark:ics-text-neutral-800 hover:ics-bg-neutral-900 ics-text-neutral-200 ics-bg-neutral-800 ics-transition ics-font-bold", children: isContinueToCheckoutLoading ? "\u0141adowanie..." : "Nast\u0119pny krok" } ), errMsg.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ics-text-red-500 ics-text-sm ics-text-center", children: errMsg }) ] }) ] }) ] }); }; var CartComponentContent_default = CartComponentContent; // src/components/checkout/CartComponent.tsx var import_jsx_runtime6 = require("react/jsx-runtime"); function CartComponent({ isVisible, shouldHide }) { const [parent] = (0, import_react6.useAutoAnimate)( /* optional config */ ); return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: parent, className: "ics-z-[999999]", children: isVisible && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( "div", { className: "ics-fixed ics-top-0 ics-right-0 ics-left-0 ics-bottom-0 ics-bg-black/30 ics-cursor-pointer", onClick: shouldHide } ), /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)( "div", { className: "ics-fixed ics-top-0 ics-right-0 ics-bottom-0 ics-w-full md:ics-w-[350px] xl:ics-w-[420px] dark:ics-bg-neutral-900 ics-bg-neutral-300 dark:ics-text-neutral-200 ics-text-neutral-900 ics-flex ics-flex-col", children: [ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)( "div", { className: "ics-mx-3 ics-mt-7 ics-flex ics-justify-between ics-items-center", children: [ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h1", { className: "text-2xl font-medium", children: "Koszyk" }), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)( "button", { className: "ics-rounded-full dark:hover:ics-bg-neutral-700 hover:ics-bg-neutral-400 ics-p-2 ics-transition", onClick: shouldHide, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)( "svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-x", children: [ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: "6", y1: "6", x2: "18", y2: "18" }) ] } ) } ) ] } ), /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CartComponentContent_default, { className: "grow" }) ] } ) ] }) }); } var WrapperCartComponent = (props) => { if (typeof window === "undefined") { return null; } return (0, import_react_dom.createPortal)( /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CartProvider_default, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(CartComponent, { ...props }) }), document.body ); }; var CartComponent_default = WrapperCartComponent; // src/components/checkout/BitsnapCart.tsx var import_jsx_runtime7 = require("react/jsx-runtime"); var cartAddToCartSchema = import_zod2.default.object({ id: import_zod2.default.string(), isSubscription: import_zod2.default.boolean().default(false), quantity: import_zod2.default.number(), metadata: import_zod2.default.record(import_zod2.default.string(), import_zod2.default.string().optional()).optional() }); function BitsnapCart({ projectID, children, onVisibleChange, className }) { const { isCartVisible, showCart: showCart2, hideCart: hideCart2 } = useCheckoutStore(); function sentPostMessageToIframe(msg) { const iframes = document.querySelectorAll("iframe"); iframes.forEach((iframe) => { var _a; (_a = iframe.contentWindow) == null ? void 0 : _a.postMessage(msg, "*"); }); } (0, import_react7.useEffect)(() => { onVisibleChange == null ? void 0 : onVisibleChange(isCartVisible); }, [isCartVisible]); (0, import_react7.useEffect)(() => { setProjectID(projectID); }, [projectID]); (0, import_react7.useEffect)(() => { if (!("cart" in window)) { const projectID2 = getProjectID(); if (projectID2 == null) { console.warn("There is no project ID configured."); return; } window["cart"] = { buyProduct: async (args) => { try { const payload = import_zod2.default.object({ productID: import_zod2.default.string(), email: import_zod2.default.string().optional(), name: import_zod2.default.string().optional(), country: import_zod2.default.string().optional(), marketingAgreement: import_zod2.default.boolean().optional() }).parse(args); const methods = getCheckoutMethods(projectID2); const result = await methods.justRedirectToPayment(payload); console.log("result", result); if (isErr(result) == false) { window.location.href = result.url; } else { alert( "Nie uda\u0142o si\u0119 przekierowa\u0107 do p\u0142atno\u015Bci. Spr\xF3buj ponownie p\xF3\u017Aniej." ); } } catch (e) { console.warn(e); } } }; } }, []); async function handleAddingToCart(id, payload) { const projectID2 = getProjectID(); if (projectID2 == null) { console.warn("There is no project ID configured."); return; } try { const data = cartAddToCartSchema.parse(payload); if (data.isSubscription) { await handleAddingSubscriptionToCart(projectID2, data); return; } const methods = getCheckoutMethods(projectID2); await methods.addProduct({ productID: data.id, quantity: data.quantity, metadata: data.metadata }); sentPostMessageToIframe({ id, type: "ADD_TO_CART" /* ADD_TO_CART */, success: true }); showCart2(); } catch (e) { console.warn("cannot add item to cart", e); } } async function handleAddingSubscriptionToCart(projectID2, event) { alert( `TODO, nie jest to jeszcze zrobione ${projectID2} ${event.id} ${event.quantity}` ); } function setupEventListener() { if ("__cart_is_listening" in window) { return; } window["__cart_is_listening"] = true; window.addEventListener("message", (event) => { if (typeof event.data["id"] != "undefined" && typeof event.data["type"] != "undefined") { const { id, type } = event.data; switch (type) { case "ADD_TO_CART" /* ADD_TO_CART */.toString(): handleAddingToCart(id, event.data["payload"]).then().catch(); break; default: break; } } }); } (0, import_react7.useEffect)(() => { var _a; setupEventListener(); if (typeof window !== "undefined") { try { const parsedParams = new URLSearchParams(window.location.search); const refLink = (_a = parsedParams.get("ref")) != null ? _a : parsedParams.get("utm-source"); if (typeof localStorage != "undefined" && refLink && refLink.length > 0) { localStorage.setItem("bitsnap-ref", refLink); } } catch (e) { return; } } }, []); return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( "button", { onClick: () => isCartVisible ? hideCart2() : showCart2(), className: className != null ? className : "ics-rounded-full hover:ics-bg-neutral-300 ics-transition ics-p-1", children: children ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)( "svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "lucide lucide-shopping-cart", children: [ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "8", cy: "21", r: "1" }), /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("circle", { cx: "19", cy: "21", r: "1" }), /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("path", { d: "M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12" }) ] } ) } ), /* @__PURE__ */ (0, import_jsx_runtime7.jsx)( CartComponent_default, { isVisible: isCartVisible, shouldHide: () => { hideCart2(); } } ) ] }); } var BitsnapCart_default = BitsnapCart; // src/components/webhook.handler.ts var import_protobuf = require("@bufbuild/protobuf"); var import_crypto = __toESM(require("crypto")); // src/gen/proto/jobs/v1/integration_event_job_pb.ts var import_codegenv15 = require("@bufbuild/protobuf/codegenv1"); // src/gen/proto/common/v1/environment_pb.ts var import_codegenv1 = require("@bufbuild/protobuf/codegenv1"); var file_common_v1_environment = /* @__PURE__ */ (0, import_codegenv1.fileDesc)("Chtjb21tb24vdjEvZW52aXJvbm1lbnQucHJvdG8SCWNvbW1vbi52MSonCgtFbnZpcm9ubWVudBIOCgpQUk9EVUNUSU9OEAASCAoEVEVTVBABQk5aTGdpdGh1Yi5jb20vZW1tZW1zL3N1cGVyLWNhcnQvYXBwcy9zcnYtd29ya2VyL3V0aWxzL21vZGVscy9jb21tb24vdjE7Y29tbW9udjFiBnByb3RvMw"); // src/gen/proto/integrations/v1/event_data_pb.ts var import_codegenv14 = require("@bufbuild/protobuf/codegenv1"); // src/gen/proto/integrations/v1/order_pb.ts var import_codegenv13 = require("@bufbuild/protobuf/codegenv1"); // src/gen/proto/common/v1/gateway_pb.ts var import_codegenv12 = require("@bufbuild/protobuf/codegenv1"); var file_common_v1_gateway = /* @__PURE__ */ (0, import_codegenv12.fileDesc)("Chdjb21tb24vdjEvZ2F0ZXdheS5wcm90bxIJY29tbW9uLnYxKokBCgdHYXRld2F5Eg8KC0dBVEVXQVlfQUxMEAASFwoTR0FURVdBWV9QUlpFTEVXWV8yNBABEhIKDkdBVEVXQVlfU1RSSVBFEAISEAoMR0FURVdBWV9UUEFZEAMSHAoYR0FURVdBWV9DQVNIX09OX0RFTElWRVJZEAQSEAoMR0FURVdBWV9GUkVFEAVCTlpMZ2l0aHViLmNvbS9lbW1lbXMvc3VwZXItY2FydC9hcHBzL3Nydi13b3JrZXIvdXRpbHMvbW9kZWxzL2NvbW1vbi92MTtjb21tb252MWIGcHJvdG8z"); // src/gen/proto/integrations/v1/order_pb.ts var import_wkt = require("@bufbuild/protobuf/wkt"); var file_integrations_v1_order = /* @__PURE__ */ (0, import_codegenv13.fileDesc)("ChtpbnRlZ3JhdGlvbnMvdjEvb3JkZXIucHJvdG8SD2ludGVncmF0aW9ucy52MSKHBAoFT3JkZXISCgoCaWQYASABKAkSLAoGc3RhdHVzGAIgASgOMhwuaW50ZWdyYXRpb25zLnYxLk9yZGVyU3RhdHVzEisKC2Vudmlyb25tZW50GAMgASgOMhYuY29tbW9uLnYxLkVudmlyb25tZW50EikKBWl0ZW1zGAQgAygLMhouaW50ZWdyYXRpb25zLnYxLk9yZGVySXRlbRIbChNhdmFpbGFibGVfY291bnRyaWVzGAUgAygJEj0KD2JpbGxpbmdfYWRkcmVzcxgGIAEoCzIfLmludGVncmF0aW9ucy52MS5CaWxsaW5nQWRkcmVzc0gAiAEBEjcKEHNoaXBwaW5nX2FkZHJlc3MYByABKAsyGC5pbnRlZ3JhdGlvbnMudjEuQWRkcmVzc0gBiAEBEjMKB2RldGFpbHMYCCABKAsyHS5pbnRlZ3JhdGlvbnMudjEuT3JkZXJEZXRhaWxzSAKIAQESMAoIY3VzdG9tZXIYCSABKAsyGS5pbnRlZ3JhdGlvbnMudjEuQ3VzdG9tZXJIA4gBARIuCgpjcmVhdGVkX2F0GAogASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEISChBfYmlsbGluZ19hZGRyZXNzQhMKEV9zaGlwcGluZ19hZGRyZXNzQgoKCF9kZXRhaWxzQgsKCV9jdXN0b21lciKLBwoMT3JkZXJEZXRhaWxzEiMKB2dhdGV3YXkYASABKA4yEi5jb21tb24udjEuR2F0ZXdheRI5ChBkZWxpdmVyeV9tZXRob2RzGAIgAygLMh8uaW50ZWdyYXRpb25zLnYxLkRlbGl2ZXJ5TWV0aG9kEiIKFWRlbGl2ZXJ5X21ldGhvZF9wcmljZRgDIAEoA0gAiAEBEhwKD2RlbGl2ZXJ5X21ldGhvZBgEIAEoCUgBiAEBEhUKDWFza19mb3JfcGhvbmUYBiABKAgSFAoMYXNrX2Zvcl9ub3RlGAcgASgIEhMKC2Fza19mb3JfbmlwGAggASgIEhgKC2NvdXBvbl9jb2RlGAkgASgJSAKIAQESIwoWY291cG9uX2Rpc2NvdW50X2Ftb3VudBgKIAEoA0gDiAEBEiUKGGNvdXBvbl9kaXNjb3VudF9jdXJyZW5jeRgLIAEoCUgEiAEBEiEKFGNvdXBvbl9kaXNjb3VudF90eXBlGAwgASgJSAWIAQESJQoYY291cG9uX2luY2x1ZGVzX2RlbGl2ZXJ5GA0gASgISAaIAQESGAoLc3VjY2Vzc191cmwYDiABKAlIB4gBARIXCgpjYW5jZWxfdXJsGA8gASgJSAiIAQESHwoScGF5bWVudF9nYXRld2F5X2lkGBAgASgJSAmIAQESPQoIbWV0YWRhdGEYESADKAsyKy5pbnRlZ3JhdGlvbnMudjEuT3JkZXJEZXRhaWxzLk1ldGFkYXRhRW50cnkSQQoVYWRkaXRpb25hbF9hZ3JlZW1lbnRzGBIgAygLMiIuaW50ZWdyYXRpb25zLnYxLkNoZWNrb3V0QWd