UNPKG

@noaignite/react-centra-checkout

Version:

React components and helpers for Centra checkout api

525 lines (524 loc) 18.5 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/Context.tsx var Context_exports = {}; __export(Context_exports, { CentraHandlersContext: () => CentraHandlersContext, CentraProvider: () => CentraProvider, CentraSelectionContext: () => CentraSelectionContext, SELECTION_INITIAL_VALUE: () => SELECTION_INITIAL_VALUE, useCentraEvents: () => useCentraEvents, useCentraHandlers: () => useCentraHandlers, useCentraOrders: () => useCentraOrders, useCentraReceipt: () => useCentraReceipt, useCentraSelection: () => useCentraSelection }); module.exports = __toCommonJS(Context_exports); var import_utils = require("@noaignite/utils"); var import_js_cookie = __toESM(require("js-cookie"), 1); var import_react = require("react"); var import_ApiClient = require("./ApiClient.cjs"); var import_CentraEvents = require("./internal/CentraEvents.cjs"); var import_jsx_runtime = require("react/jsx-runtime"); var defaultApiClient = import_ApiClient.ApiClient.default; var centraEvents = import_CentraEvents.CentraEvents.default; var SELECTION_INITIAL_VALUE = { countries: [], languages: [], location: {}, paymentFields: {}, paymentMethods: [], selection: { address: {}, discounts: {}, items: [], totals: {} }, shippingMethods: [] }; var CentraHandlersContext = (0, import_react.createContext)(null); var CentraSelectionContext = (0, import_react.createContext)(null); var onSelectionResponse = async (promise, callback) => { const results = await promise; if ((0, import_utils.isPlainObject)(results) && "selection" in results && Boolean(results.selection)) { return callback( // We have to cast it to `TPromise`, because there's not a way to create async type predicates without already passing the `Promise` as argument to a function. promise ); } return results; }; function CentraProvider(props) { const { apiClient: apiClientProp, apiUrl, children, disableInit = false, initialSelection, paymentFailedPage, paymentReturnPage, receiptPage, tokenExpires = 365, tokenName = "centra-checkout-token", tokenCookieOptions = null } = props; const apiClient = apiClientProp ?? defaultApiClient; const [selection, setSelection] = (0, import_react.useState)(initialSelection ?? SELECTION_INITIAL_VALUE); const centraCheckoutScript = "selection" in selection && selection.selection?.centraCheckoutScript; if (apiUrl) { apiClient.baseUrl = apiUrl; } if (initialSelection?.token) { apiClient.headers.set("api-token", initialSelection.token); } const selectionApiCall = (0, import_react.useCallback)( async (apiCall) => { window.CentraCheckout?.suspend(); const response = typeof apiCall === "function" ? await apiCall() : await apiCall; setSelection(response); window.CentraCheckout?.resume(); return response; }, [] ); const centraCheckoutCallback = (0, import_react.useCallback)( async (event) => { const response = await apiClient.request( "PUT", `payment-fields`, event.detail ); if ("selection" in response && response.selection) { setSelection(response); } window.CentraCheckout?.resume(event.detail.additionalFields?.suspendIgnore); centraEvents.dispatch("centra_checkout_callback", response); }, [apiClient] ); const init = (0, import_react.useCallback)( async (selectionData) => { let response; const apiToken = import_js_cookie.default.get(tokenName); if (apiToken) { apiClient.headers.set("api-token", apiToken); } if (!selectionData) { response = await apiClient.request( "GET", "selection" ); } else { response = selectionData; } if ("selection" in response && response.selection) { setSelection(response); if (response.token && response.token !== apiToken) { apiClient.headers.set("api-token", response.token); import_js_cookie.default.set(tokenName, response.token, { expires: tokenExpires, ...tokenCookieOptions }); } } }, [tokenName, apiClient, tokenExpires, tokenCookieOptions] ); const addItem = (0, import_react.useCallback)( (item, quantity = 1) => onSelectionResponse( apiClient.request("POST", `items/${item}/quantity/${quantity}`), selectionApiCall ), [apiClient, selectionApiCall] ); const addBundleItem = (0, import_react.useCallback)( (item, data) => onSelectionResponse( apiClient.request("POST", `items/bundles/${item}`, data), selectionApiCall ), [apiClient, selectionApiCall] ); const addGiftCertificate = (0, import_react.useCallback)( (giftCertificate) => onSelectionResponse( apiClient.request("POST", `items/gift-certificates/${giftCertificate}`), selectionApiCall ), [apiClient, selectionApiCall] ); const addCustomGiftCertificate = (0, import_react.useCallback)( (giftCertificate, amount) => onSelectionResponse( apiClient.request("POST", `items/gift-certificates/${giftCertificate}/amount/${amount}`), selectionApiCall ), [apiClient, selectionApiCall] ); const increaseCartItem = (0, import_react.useCallback)( (line) => onSelectionResponse(apiClient.request("POST", `lines/${line}/quantity/1`), selectionApiCall), [apiClient, selectionApiCall] ); const decreaseCartItem = (0, import_react.useCallback)( (line) => onSelectionResponse( apiClient.request("DELETE", `lines/${line}/quantity/1`), selectionApiCall ), [apiClient, selectionApiCall] ); const removeCartItem = (0, import_react.useCallback)( (line) => onSelectionResponse(apiClient.request("DELETE", `lines/${line}`), selectionApiCall), [apiClient, selectionApiCall] ); const updateCartItemQuantity = (0, import_react.useCallback)( (line, quantity) => onSelectionResponse( apiClient.request("PUT", `lines/${line}/quantity/${quantity}`), selectionApiCall ), [apiClient, selectionApiCall] ); const updateCartItemSize = (0, import_react.useCallback)( (cartItem, item) => selectionApiCall(async () => { await apiClient.request("DELETE", `lines/${cartItem.line}`); const response = await apiClient.request( "POST", `items/${item}/quantity/${cartItem.quantity}` ); return response; }), [apiClient, selectionApiCall] ); const addVoucher = (0, import_react.useCallback)( (voucher) => onSelectionResponse(apiClient.request("POST", "vouchers", { voucher }), selectionApiCall), [apiClient, selectionApiCall] ); const removeVoucher = (0, import_react.useCallback)( (voucher) => onSelectionResponse(apiClient.request("DELETE", `vouchers/${voucher}`), selectionApiCall), [apiClient, selectionApiCall] ); const updateCountry = (0, import_react.useCallback)( (country, data) => onSelectionResponse(apiClient.request("PUT", `countries/${country}`, data), selectionApiCall), [apiClient, selectionApiCall] ); const updateLanguage = (0, import_react.useCallback)( (language) => onSelectionResponse(apiClient.request("PUT", `languages/${language}`), selectionApiCall), [apiClient, selectionApiCall] ); const updateShippingMethod = (0, import_react.useCallback)( (shippingMethod) => onSelectionResponse( apiClient.request("PUT", `shipping-methods/${shippingMethod}`), selectionApiCall ), [apiClient, selectionApiCall] ); const updatePaymentMethod = (0, import_react.useCallback)( (paymentMethod) => onSelectionResponse( apiClient.request("PUT", `payment-methods/${paymentMethod}`), selectionApiCall ), [apiClient, selectionApiCall] ); const updatePaymentFields = (0, import_react.useCallback)( async (data) => onSelectionResponse(apiClient.request("PUT", `payment-fields`, data), selectionApiCall), [apiClient, selectionApiCall] ); const submitPayment = (0, import_react.useCallback)( async (data) => { const response = await apiClient.request("POST", "payment", { paymentReturnPage: typeof paymentReturnPage === "function" ? paymentReturnPage(selection) : paymentReturnPage, paymentFailedPage: typeof paymentFailedPage === "function" ? paymentFailedPage(selection) : paymentFailedPage, ...data }); if ("errors" in response) { throw new Error( Object.entries(response.errors).map((key, value) => `${key}: ${value}`).join(",") ); } switch (response.action) { case "redirect": if (response.url) { window.location.href = response.url; } break; case "success": window.location.href = `${receiptPage}/${response.token}`; break; case "javascript": if (response.code) { const script = document.createElement("script"); const text = document.createTextNode(response.code); script.appendChild(text); document.body.appendChild(script); } break; default: return response; } return response; }, [apiClient, paymentFailedPage, paymentReturnPage, receiptPage, selection] ); const addBackInStockSubscription = (0, import_react.useCallback)( (data) => onSelectionResponse( apiClient.request("POST", "back-in-stock-subscription", data), selectionApiCall ), [apiClient, selectionApiCall] ); const addNewsletterSubscription = (0, import_react.useCallback)( (data) => onSelectionResponse( apiClient.request("POST", "newsletter-subscription", data), selectionApiCall ), [apiClient, selectionApiCall] ); const loginCustomer = (0, import_react.useCallback)( (email, password) => onSelectionResponse( apiClient.request("POST", `login/${email}`, { password }), selectionApiCall ), [apiClient, selectionApiCall] ); const logoutCustomer = (0, import_react.useCallback)( () => onSelectionResponse(apiClient.request("POST", `logout`), selectionApiCall), [apiClient, selectionApiCall] ); const registerCustomer = (0, import_react.useCallback)( (data) => onSelectionResponse(apiClient.request("POST", `register`, data), selectionApiCall), [apiClient, selectionApiCall] ); const resetCustomerPassword = (0, import_react.useCallback)( (i, id, newPassword) => onSelectionResponse( apiClient.request("POST", `password-reset`, { i, id, newPassword }), selectionApiCall ), [apiClient, selectionApiCall] ); const resetSelection = (0, import_react.useCallback)(() => { apiClient.headers.delete("api-token"); import_js_cookie.default.remove(tokenName); return init(); }, [apiClient.headers, init, tokenName]); const sendCustomerResetPasswordEmail = (0, import_react.useCallback)( (email, linkUri) => onSelectionResponse( apiClient.request("POST", `password-reset-email/${email}`, { linkUri }), selectionApiCall ), [apiClient, selectionApiCall] ); const updateCustomer = (0, import_react.useCallback)( (data) => onSelectionResponse(apiClient.request("PUT", `customer/update`, data), selectionApiCall), [apiClient, selectionApiCall] ); const updateCustomerAddress = (0, import_react.useCallback)( (data) => onSelectionResponse(apiClient.request("PUT", `address`, data), selectionApiCall), [apiClient, selectionApiCall] ); const updateCustomerEmail = (0, import_react.useCallback)( (newEmail) => onSelectionResponse(apiClient.request("PUT", `email`, { newEmail }), selectionApiCall), [apiClient, selectionApiCall] ); const updateCustomerPassword = (0, import_react.useCallback)( (password, newPassword) => onSelectionResponse( apiClient.request("PUT", `password`, { password, newPassword }), selectionApiCall ), [apiClient, selectionApiCall] ); const updateCampaignSite = (0, import_react.useCallback)( (uri) => onSelectionResponse(apiClient.request("PUT", `campaign-site`, { uri }), selectionApiCall), [apiClient, selectionApiCall] ); (0, import_react.useEffect)(() => { if (!disableInit) { void init(); } document.addEventListener("centra_checkout_callback", centraCheckoutCallback); return () => { document.removeEventListener("centra_checkout_callback", centraCheckoutCallback); }; }, [disableInit, init, centraCheckoutCallback]); (0, import_react.useEffect)(() => { let script = null; if (centraCheckoutScript) { script = document.createElement("script"); script.innerHTML = centraCheckoutScript; script.id = "centra-checkout-script"; document.head.appendChild(script); } return () => { if (script) { document.head.removeChild(script); } }; }, [centraCheckoutScript]); const centraHandlersContext = (0, import_react.useMemo)( () => ({ addItem, addBundleItem, addGiftCertificate, addBackInStockSubscription, addCustomGiftCertificate, addNewsletterSubscription, addVoucher, decreaseCartItem, increaseCartItem, init, loginCustomer, logoutCustomer, registerCustomer, removeCartItem, removeVoucher, resetCustomerPassword, resetSelection, sendCustomerResetPasswordEmail, submitPayment, updateCartItemQuantity, updateCartItemSize, updateCountry, updateCustomer, updateCustomerAddress, updateCustomerEmail, updateCustomerPassword, updateLanguage, updatePaymentFields, updatePaymentMethod, updateShippingMethod, updateCampaignSite }), [ addItem, addBundleItem, addGiftCertificate, addBackInStockSubscription, addCustomGiftCertificate, addNewsletterSubscription, addVoucher, decreaseCartItem, increaseCartItem, init, loginCustomer, logoutCustomer, registerCustomer, removeCartItem, removeVoucher, resetCustomerPassword, resetSelection, sendCustomerResetPasswordEmail, submitPayment, updateCartItemQuantity, updateCartItemSize, updateCountry, updateCustomer, updateCustomerAddress, updateCustomerEmail, updateCustomerPassword, updateLanguage, updatePaymentFields, updatePaymentMethod, updateShippingMethod, updateCampaignSite ] ); const centraContext = (0, import_react.useMemo)( () => ({ ...selection, apiUrl, apiClient }), [selection, apiUrl, apiClient] ); return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CentraHandlersContext.Provider, { value: centraHandlersContext, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CentraSelectionContext.Provider, { value: centraContext, children }) }); } function useCentraSelection() { const context = (0, import_react.useContext)(CentraSelectionContext); if (context === null) { throw new Error( [ "@noaignite/react-centra-checkout: `useCentraSelection` may only be", "used inside the `CentraProvider` react tree, please declare it at a", "higher level." ].join(" ") ); } return context; } function useCentraHandlers() { const context = (0, import_react.useContext)(CentraHandlersContext); if (context === null) { throw new Error( [ "@noaignite/react-centra-checkout: `useCentraHandlers` may only be", "used inside the `CentraProvider` react tree, please declare it at a", "higher level." ].join(" ") ); } return context; } function useCentraReceipt(token) { const [result, setResult] = (0, import_react.useState)({}); const { apiUrl } = useCentraSelection(); if (!token) { console.error("@noaignite/react-centra-checkout: useReceipt requires a selection id"); } (0, import_react.useEffect)(() => { const tempApiClient = new import_ApiClient.ApiClient(apiUrl); tempApiClient.headers.set("api-token", token); void tempApiClient.request("GET", "receipt").then((response) => { setResult(response); }); }, [apiUrl, token]); return result; } function useCentraOrders(from, size, apiClient = defaultApiClient) { const [result, setResult] = (0, import_react.useState)({}); (0, import_react.useEffect)(() => { void apiClient.request("POST", "orders", { ...from && { from }, ...size && { size } }).then((response) => { setResult(response); }); }, [apiClient, from, size]); return result; } function useCentraEvents() { return import_CentraEvents.CentraEvents.default; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { CentraHandlersContext, CentraProvider, CentraSelectionContext, SELECTION_INITIAL_VALUE, useCentraEvents, useCentraHandlers, useCentraOrders, useCentraReceipt, useCentraSelection }); //# sourceMappingURL=Context.cjs.map