@noaignite/react-centra-checkout
Version:
React components and helpers for Centra checkout api
525 lines (524 loc) • 18.5 kB
JavaScript
;
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