@nosto/nosto-react
Version:
Component library to simply implementing Nosto on React.
359 lines (358 loc) • 11.2 kB
JavaScript
import { cloneElement as e, createContext as t, isValidElement as n, useCallback as r, useContext as i, useEffect as a, useMemo as o, useRef as s, useState as c } from "react";
import { createPortal as l } from "react-dom";
import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
//#region src/context.ts
var p = t({
account: "",
currentVariation: "",
responseMode: "HTML",
clientScriptLoaded: !1
});
//#endregion
//#region src/hooks/useNostoContext.ts
function m() {
return i(p);
}
//#endregion
//#region src/utils/object.ts
var h = (e) => String(e) === "[object Object]";
function g(e) {
if (!h(e)) return !1;
let t = e.constructor;
if (t === void 0) return !0;
let n = t.prototype;
return !(!h(n) || !n.hasOwnProperty("isPrototypeOf"));
}
//#endregion
//#region src/utils/compare.ts
function _(e, t) {
if (e === t) return !0;
if (e instanceof Date && t instanceof Date) return e.getTime() === t.getTime();
if (e instanceof Array && t instanceof Array) return e.length === t.length ? e.every((e, n) => _(e, t[n])) : !1;
if (g(e) && g(t)) {
let n = Object.entries(e);
return n.length === Object.keys(t).length ? n.every(([e, n]) => _(n, t[e])) : !1;
}
return !1;
}
//#endregion
//#region src/hooks/useDeepCompareEffect.ts
function v(e, t) {
return a(e, y(t));
}
function y(e) {
let t = s(e), n = s(0);
return _(e, t.current) || (t.current = e, n.current += 1), o(() => t.current, [n.current]);
}
//#endregion
//#region node_modules/@nosto/nosto-js/dist/settings-DN0V2st5.js
function b() {
window.nostojs = window.nostojs ?? function(e) {
(window.nostojs.q = window.nostojs.q ?? []).push(e);
};
}
async function x(e) {
return window.nostojs(e);
}
typeof window < "u" && (b(), x((e) => {
e.internal.getSettings();
}));
//#endregion
//#region node_modules/@nosto/nosto-js/dist/index.es.js
function S() {
return typeof window.nosto < "u";
}
var ee = {
production: "https://connect.nosto.com/",
staging: "https://connect.staging.nosto.com/",
local: "https://connect.nosto.com/"
};
function C(e) {
return ee[e ?? "production"];
}
function w({ merchantId: e, env: t, options: n, shopifyInternational: r, scriptLoader: i }) {
let a = document.querySelector("script[nosto-language], script[nosto-market-id]"), o = String(r?.marketId || ""), s = r?.language || "", c = a?.getAttribute("nosto-language") !== s || a?.getAttribute("nosto-market-id") !== o;
if (!a || c) {
let r = document.querySelector("#nosto-sandbox");
a?.parentNode?.removeChild(a), r?.parentNode?.removeChild(r);
let c = new URL("/script/shopify/market/nosto.js", C(t));
c.searchParams.append("merchant", e), c.searchParams.append("market", o), c.searchParams.append("locale", s.toLowerCase());
let l = {
...n?.attributes,
"nosto-language": s,
"nosto-market-id": o
};
return (i ?? E)(c.toString(), {
...n,
attributes: l
});
}
return Promise.resolve();
}
function T(e) {
if (e.shopifyInternational) return w(e);
let { merchantId: t, env: n, options: r, scriptLoader: i } = e;
return (i ?? E)(new URL(`/include/${t}`, C(n)).toString(), r);
}
function E(e, t) {
return new Promise((n, r) => {
let i = document.createElement("script");
i.src = e, i.async = !0, i.type = "text/javascript", i.onload = () => n(), i.onerror = () => r(), Object.entries(t?.attributes ?? {}).forEach(([e, t]) => i.setAttribute(e, t)), t?.position === "head" ? document.head.appendChild(i) : document.body.appendChild(i);
});
}
typeof window < "u" && b();
//#endregion
//#region src/hooks/useNostoApi.ts
function D(e, t, n) {
let { clientScriptLoaded: r } = m();
(n?.deep ? v : a)(() => {
r && x(e);
}, [r, ...t ?? []]);
}
//#endregion
//#region src/hooks/useRenderCampaigns.tsx
function O(t) {
return e(t.recommendationComponent, { nostoRecommendation: t.nostoRecommendation });
}
function k(e) {
x((t) => t.placements.injectCampaigns(e));
}
function A(e) {
if (!window.nostojs) throw Error("Nosto has not yet been initialized");
k(e.recommendations);
}
function j() {
let { responseMode: e, recommendationComponent: t, setPortals: n } = m();
if (a(() => () => n?.([]), [n]), e == "HTML") return { renderCampaigns: A };
if (!t) throw Error("recommendationComponent is required for client-side rendering using hook");
function r(e) {
k(e.campaigns?.content ?? {});
let r = e.campaigns?.recommendations ?? {}, i = [];
for (let e in r) {
let n = r[e], a = "#" + e, o = document.querySelector(a);
o && i.push(l(/* @__PURE__ */ d(O, {
recommendationComponent: t,
nostoRecommendation: n
}), o, e));
}
n?.(i);
}
return { renderCampaigns: r };
}
//#endregion
//#region src/hooks/useNosto404.tsx
function M(e) {
let { renderCampaigns: t } = j();
D(async (n) => {
t(await n.defaultSession().viewNotFound().setPlacements(e?.placements || n.placements.getPlacements()).load());
});
}
//#endregion
//#region src/components/Nosto404.tsx
function te(e) {
return M(e), null;
}
//#endregion
//#region src/hooks/useNostoCategory.tsx
function N({ category: e, placements: t }) {
let { renderCampaigns: n } = j();
D(async (r) => {
n(await r.defaultSession().viewCategory(e).setPlacements(t || r.placements.getPlacements()).load());
}, [e]);
}
//#endregion
//#region src/components/NostoCategory.tsx
function P(e) {
return N(e), null;
}
//#endregion
//#region src/hooks/useNostoCheckout.tsx
function F(e) {
let { renderCampaigns: t } = j();
D(async (n) => {
t(await n.defaultSession().viewCart().setPlacements(e?.placements || n.placements.getPlacements()).load());
});
}
//#endregion
//#region src/components/NostoCheckout.tsx
function I(e) {
return F(e), null;
}
//#endregion
//#region src/hooks/useNostoHome.tsx
function L(e) {
let { renderCampaigns: t } = j();
D(async (n) => {
t(await n.defaultSession().viewFrontPage().setPlacements(e?.placements || n.placements.getPlacements()).load());
});
}
//#endregion
//#region src/components/NostoHome.tsx
function R(e) {
return L(e), null;
}
//#endregion
//#region src/utils/snakeize.ts
function z(e) {
return !e || typeof e != "object" || B(e) || V(e) ? e : Array.isArray(e) ? e.map(z) : Object.keys(e).reduce((t, n) => {
let r = n[0].toLowerCase() + n.slice(1).replace(/([A-Z]+)/g, (e, t) => "_" + t.toLowerCase());
return t[r] = z(e[n]), t;
}, {});
}
function B(e) {
return Object.prototype.toString.call(e) === "[object Date]";
}
function V(e) {
return Object.prototype.toString.call(e) === "[object RegExp]";
}
//#endregion
//#region src/hooks/useNostoOrder.tsx
function H({ order: e, placements: t }) {
let { renderCampaigns: n } = j();
D(async (r) => {
n(await r.defaultSession().addOrder(z(e)).setPlacements(t || r.placements.getPlacements()).load());
}, [e], { deep: !0 });
}
//#endregion
//#region src/components/NostoOrder.tsx
function U(e) {
return H(e), null;
}
//#endregion
//#region src/hooks/useNostoOther.tsx
function W(e) {
let { renderCampaigns: t } = j();
D(async (n) => {
t(await n.defaultSession().viewOther().setPlacements(e?.placements || n.placements.getPlacements()).load());
});
}
//#endregion
//#region src/components/NostoOther.tsx
function G(e) {
return W(e), null;
}
//#endregion
//#region src/components/NostoPlacement.tsx
function K({ id: e, pageType: t, children: n }) {
return /* @__PURE__ */ d("div", {
className: "nosto_element",
id: e,
children: n
}, e + (t || ""));
}
//#endregion
//#region src/hooks/useNostoProduct.tsx
function q({ product: e, tagging: t, placements: n, reference: r }) {
let { renderCampaigns: i } = j();
if (t && !t.product_id) throw Error("The product object must contain a product_id property");
let a = t?.product_id ?? e;
D(async (o) => {
let s = o.defaultSession().viewProduct(t ?? e).setPlacements(n || o.placements.getPlacements());
r && s.setRef(a, r), i(await s.load());
}, [a, t?.selected_sku_id]);
}
//#endregion
//#region src/components/NostoProduct.tsx
function J(e) {
return q(e), null;
}
//#endregion
//#region src/hooks/scriptLoader.ts
function Y(e, t) {
return new Promise((n, r) => {
let i = document.createElement("script");
i.type = "text/javascript", i.src = e, i.async = !0, i.onload = () => n(), i.onerror = () => r(), Object.entries(t?.attributes ?? {}).forEach(([e, t]) => i.setAttribute(e, t)), t?.position === "head" ? document.head.appendChild(i) : document.body.appendChild(i);
});
}
//#endregion
//#region src/hooks/useLoadClientScript.ts
var X = { "nosto-client-script": "" };
function Z(e) {
let { scriptLoader: t = Y, account: n, shopifyMarkets: r, loadScript: i = !0 } = e, [o, s] = c(!1);
return a(() => {
function e() {
s(!0);
}
if (b(), x((e) => e.setAutoLoad(!1)), !i) {
x(e);
return;
}
async function a() {
await T({
merchantId: n,
shopifyInternational: r,
options: { attributes: X },
scriptLoader: t
}), e();
}
(!S() || r) && a();
}, [r?.marketId, r?.language]), { clientScriptLoaded: o };
}
//#endregion
//#region src/components/NostoProvider.tsx
function ne({ setPortalsRef: e }) {
let [t, n] = c([]);
return e.current = n, /* @__PURE__ */ d(u, { children: t });
}
function re() {
let e = s(null);
return {
setPortalsRef: e,
setPortals: r((t) => {
e.current?.(t);
}, [])
};
}
function ie(e) {
let { account: t, multiCurrency: r = !1, children: i, recommendationComponent: a, renderMode: o } = e, { setPortalsRef: s, setPortals: c } = re(), l = r ? e.currentVariation : "";
if (a && !n(a)) throw Error("The recommendationComponent prop must be a valid React element. Please provide a valid React element.");
let u = o || (a ? "JSON_ORIGINAL" : "HTML"), { clientScriptLoaded: m } = Z(e);
return m && x((e) => {
e.defaultSession().setVariation(l).setResponseMode(u);
}), /* @__PURE__ */ f(p.Provider, {
value: {
account: t,
clientScriptLoaded: m,
currentVariation: l,
responseMode: u,
recommendationComponent: a,
setPortals: c
},
children: [i, /* @__PURE__ */ d(ne, { setPortalsRef: s })]
});
}
//#endregion
//#region src/hooks/useNostoSearch.tsx
function Q({ query: e, placements: t }) {
let { renderCampaigns: n } = j();
D(async (r) => {
n(await r.defaultSession().viewSearch(e).setPlacements(t || r.placements.getPlacements()).load());
}, [e]);
}
//#endregion
//#region src/components/NostoSearch.tsx
function ae(e) {
return Q(e), null;
}
//#endregion
//#region src/hooks/useNostoSession.tsx
function $({ cart: e, customer: t } = {}) {
let { clientScriptLoaded: n } = m();
v(() => {
let r = e ? z(e) : void 0, i = t ? z(t) : void 0;
n && x((e) => {
e.defaultSession().setCart(r).setCustomer(i).viewOther().load({ skipPageViews: !0 });
});
}, [
n,
e,
t
]);
}
//#endregion
//#region src/components/NostoSession.tsx
function oe(e) {
return $(e), null;
}
//#endregion
export { te as Nosto404, P as NostoCategory, I as NostoCheckout, p as NostoContext, R as NostoHome, U as NostoOrder, G as NostoOther, K as NostoPlacement, J as NostoProduct, ie as NostoProvider, ae as NostoSearch, oe as NostoSession, M as useNosto404, N as useNostoCategory, F as useNostoCheckout, m as useNostoContext, L as useNostoHome, H as useNostoOrder, W as useNostoOther, q as useNostoProduct, Q as useNostoSearch, $ as useNostoSession };