@nosto/nosto-react 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -2
- package/dist/{index.es.client.js → index.es.js} +123 -164
- package/dist/index.umd.js +9 -0
- package/package.json +15 -10
- package/src/components/Nosto404.tsx +47 -0
- package/src/components/{Category/index.client.tsx → NostoCategory.tsx} +18 -39
- package/src/components/NostoCheckout.tsx +47 -0
- package/src/components/{Home/index.client.tsx → NostoHome.tsx} +17 -36
- package/src/components/NostoOrder.tsx +55 -0
- package/src/components/NostoOther.tsx +46 -0
- package/src/components/{Placement/index.client.tsx → NostoPlacement.tsx} +5 -8
- package/src/components/{Product/index.client.tsx → NostoProduct.tsx} +37 -81
- package/src/components/NostoProvider.tsx +220 -0
- package/src/components/{Search/index.client.tsx → NostoSearch.tsx} +18 -39
- package/src/components/{Session/index.client.tsx → NostoSession.tsx} +14 -17
- package/src/components/context.ts +55 -0
- package/src/components/index.ts +14 -0
- package/src/index.ts +3 -0
- package/src/types.ts +112 -97
- package/src/utils/compare.ts +9 -9
- package/src/utils/hooks.ts +28 -8
- package/src/utils/object.ts +10 -11
- package/src/utils/snakeize.ts +11 -11
- package/dist/index.umd.client.js +0 -9
- package/src/components/Checkout/index.client.tsx +0 -66
- package/src/components/Fohofo/index.client.tsx +0 -66
- package/src/components/Order/index.client.tsx +0 -72
- package/src/components/Other/index.client.tsx +0 -64
- package/src/components/Provider/context.client.ts +0 -45
- package/src/components/Provider/index.client.tsx +0 -222
- package/src/index.client.ts +0 -33
package/src/utils/compare.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import { isPlainObject } from "./object"
|
|
1
|
+
import { isPlainObject } from "./object"
|
|
2
2
|
|
|
3
3
|
export function deepCompare(a: unknown, b: unknown): boolean {
|
|
4
4
|
if (a === b) {
|
|
5
|
-
return true
|
|
5
|
+
return true
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
if (a instanceof Date && b instanceof Date) {
|
|
9
|
-
return a.getTime() === b.getTime()
|
|
9
|
+
return a.getTime() === b.getTime()
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
if (a instanceof Array && b instanceof Array) {
|
|
13
13
|
if (a.length !== b.length) {
|
|
14
|
-
return false
|
|
14
|
+
return false
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
return a.every((v, i) => deepCompare(v, b[i]))
|
|
17
|
+
return a.every((v, i) => deepCompare(v, b[i]))
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
if (isPlainObject(a) && isPlainObject(b)) {
|
|
21
|
-
const entriesA = Object.entries(a)
|
|
21
|
+
const entriesA = Object.entries(a)
|
|
22
22
|
|
|
23
23
|
if (entriesA.length !== Object.keys(b).length) {
|
|
24
|
-
return false
|
|
24
|
+
return false
|
|
25
25
|
}
|
|
26
|
-
return entriesA.every(([k, v]) => deepCompare(v, b[k]))
|
|
26
|
+
return entriesA.every(([k, v]) => deepCompare(v, b[k]))
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
return false
|
|
29
|
+
return false
|
|
30
30
|
}
|
package/src/utils/hooks.ts
CHANGED
|
@@ -1,21 +1,41 @@
|
|
|
1
|
-
import { useEffect, useRef, useMemo } from "react"
|
|
2
|
-
import {
|
|
1
|
+
import { useEffect, useRef, useMemo } from "react"
|
|
2
|
+
import { useNostoContext } from "../components/context"
|
|
3
|
+
import { deepCompare } from "./compare"
|
|
4
|
+
import { NostoClient } from "../types"
|
|
3
5
|
|
|
4
6
|
export function useDeepCompareEffect(
|
|
5
7
|
callback: Parameters<typeof useEffect>[0],
|
|
6
8
|
dependencies: Parameters<typeof useEffect>[1]
|
|
7
9
|
): ReturnType<typeof useEffect> {
|
|
8
|
-
return useEffect(callback, useDeepCompareMemoize(dependencies))
|
|
10
|
+
return useEffect(callback, useDeepCompareMemoize(dependencies))
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
function useDeepCompareMemoize<T>(value: T) {
|
|
12
|
-
const ref = useRef<T>(value)
|
|
13
|
-
const signalRef = useRef<number>(0)
|
|
14
|
+
const ref = useRef<T>(value)
|
|
15
|
+
const signalRef = useRef<number>(0)
|
|
14
16
|
|
|
15
17
|
if (!deepCompare(value, ref.current)) {
|
|
16
|
-
ref.current = value
|
|
17
|
-
signalRef.current += 1
|
|
18
|
+
ref.current = value
|
|
19
|
+
signalRef.current += 1
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
return useMemo(() => ref.current, [signalRef.current])
|
|
22
|
+
return useMemo(() => ref.current, [signalRef.current])
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useNostoApi(
|
|
26
|
+
cb: (api: NostoClient) => void,
|
|
27
|
+
deps?: React.DependencyList,
|
|
28
|
+
flags?: { deep?: boolean }
|
|
29
|
+
): void {
|
|
30
|
+
const { clientScriptLoaded, currentVariation, responseMode } = useNostoContext()
|
|
31
|
+
const useEffectFn = flags?.deep ? useDeepCompareEffect : useEffect
|
|
32
|
+
|
|
33
|
+
useEffectFn(() => {
|
|
34
|
+
if (clientScriptLoaded) {
|
|
35
|
+
window.nostojs(api => {
|
|
36
|
+
api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode)
|
|
37
|
+
cb(api)
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
}, [clientScriptLoaded, currentVariation, responseMode, ...(deps ?? [])])
|
|
21
41
|
}
|
package/src/utils/object.ts
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
value: unknown
|
|
3
|
-
): value is T {
|
|
4
|
-
const isObject = (v: unknown): v is object => String(v) === "[object Object]";
|
|
1
|
+
const isObject = (v: unknown): v is object => String(v) === "[object Object]"
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
export function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
4
|
+
if (!isObject(value)) return false
|
|
7
5
|
|
|
8
|
-
const constructor = value.constructor
|
|
9
|
-
if (constructor === undefined) return true
|
|
6
|
+
const constructor = value.constructor
|
|
7
|
+
if (constructor === undefined) return true
|
|
10
8
|
|
|
11
|
-
const prototype = constructor.prototype
|
|
12
|
-
if (!isObject(prototype)) return false
|
|
9
|
+
const prototype = constructor.prototype
|
|
10
|
+
if (!isObject(prototype)) return false
|
|
13
11
|
|
|
14
12
|
// Checks if it is not a class
|
|
13
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
15
14
|
if (!prototype.hasOwnProperty("isPrototypeOf")) {
|
|
16
|
-
return false
|
|
15
|
+
return false
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
return true
|
|
18
|
+
return true
|
|
20
19
|
}
|
package/src/utils/snakeize.ts
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
export function snakeize<T>(obj: T): T {
|
|
2
2
|
if (!obj || typeof obj !== "object") {
|
|
3
|
-
return obj
|
|
3
|
+
return obj
|
|
4
4
|
}
|
|
5
5
|
if (isDate(obj) || isRegex(obj)) {
|
|
6
|
-
return obj
|
|
6
|
+
return obj
|
|
7
7
|
}
|
|
8
8
|
if (Array.isArray(obj)) {
|
|
9
|
-
return obj.map(snakeize) as T
|
|
9
|
+
return obj.map(snakeize) as T
|
|
10
10
|
}
|
|
11
11
|
return Object.keys(obj).reduce((acc, key) => {
|
|
12
|
-
|
|
12
|
+
const camel =
|
|
13
13
|
key[0].toLowerCase() +
|
|
14
14
|
key.slice(1).replace(/([A-Z]+)/g, (_, x) => {
|
|
15
|
-
return "_" + x.toLowerCase()
|
|
16
|
-
})
|
|
17
|
-
acc[camel as keyof typeof acc] = snakeize(obj[key as keyof typeof acc])
|
|
18
|
-
return acc
|
|
19
|
-
}, {} as T
|
|
15
|
+
return "_" + x.toLowerCase()
|
|
16
|
+
})
|
|
17
|
+
acc[camel as keyof typeof acc] = snakeize(obj[key as keyof typeof acc])
|
|
18
|
+
return acc
|
|
19
|
+
}, {}) as T
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
function isDate(obj: unknown) {
|
|
23
|
-
return Object.prototype.toString.call(obj) === "[object Date]"
|
|
23
|
+
return Object.prototype.toString.call(obj) === "[object Date]"
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function isRegex(obj: unknown) {
|
|
27
|
-
return Object.prototype.toString.call(obj) === "[object RegExp]"
|
|
27
|
+
return Object.prototype.toString.call(obj) === "[object RegExp]"
|
|
28
28
|
}
|
package/dist/index.umd.client.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
(function(f,u){typeof exports=="object"&&typeof module!="undefined"?u(exports,require("react"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react","react-dom/client"],u):(f=typeof globalThis!="undefined"?globalThis:f||self,u(f["@nosto/nosto-react"]={},f.React,f.ReactDOM))})(this,function(f,u,x){"use strict";function D(t){return t&&typeof t=="object"&&"default"in t?t:{default:t}}var R=D(u);const V=u.createContext({account:"",currentVariation:"",pageType:"",responseMode:"HTML",clientScriptLoaded:!1,useRenderCampaigns:()=>{}});function h(){const t=u.useContext(V);if(!t)throw new Error("No nosto context found");return t}var E={exports:{}},b={};/**
|
|
2
|
-
* @license React
|
|
3
|
-
* react-jsx-runtime.production.min.js
|
|
4
|
-
*
|
|
5
|
-
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
6
|
-
*
|
|
7
|
-
* This source code is licensed under the MIT license found in the
|
|
8
|
-
* LICENSE file in the root directory of this source tree.
|
|
9
|
-
*/var H=R.default,$=Symbol.for("react.element"),G=Symbol.for("react.fragment"),z=Object.prototype.hasOwnProperty,J=H.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,W={key:!0,ref:!0,__self:!0,__source:!0};function A(t,n,e){var r,i={},l=null,m=null;e!==void 0&&(l=""+e),n.key!==void 0&&(l=""+n.key),n.ref!==void 0&&(m=n.ref);for(r in n)z.call(n,r)&&!W.hasOwnProperty(r)&&(i[r]=n[r]);if(t&&t.defaultProps)for(r in n=t.defaultProps,n)i[r]===void 0&&(i[r]=n[r]);return{$$typeof:$,type:t,key:l,ref:m,props:i,_owner:J.current}}b.Fragment=G,b.jsx=A,b.jsxs=A,E.exports=b;const s=E.exports.jsx,w=E.exports.jsxs,_=E.exports.Fragment;function B(t){const{clientScriptLoaded:n,currentVariation:e,responseMode:r,recommendationComponent:i,useRenderCampaigns:l}=h(),{renderCampaigns:m,pageTypeUpdated:a}=l("404");return u.useEffect(()=>{n&&a&&window.nostojs(c=>{c.defaultSession().setVariation(e).setResponseMode(r).viewNotFound().setPlacements(t.placements||c.placements.getPlacements()).load().then(d=>{m(d,c)})})},[n,e,i,a]),s(_,{children:s("div",{className:"nosto_page_type",style:{display:"none"},children:"notfound"})})}function Y(t){const{clientScriptLoaded:n,currentVariation:e,responseMode:r,recommendationComponent:i,useRenderCampaigns:l}=h(),{renderCampaigns:m,pageTypeUpdated:a}=l("other");return u.useEffect(()=>{n&&a&&window.nostojs(c=>{c.defaultSession().setVariation(e).setResponseMode(r).viewOther().setPlacements(t.placements||c.placements.getPlacements()).load().then(d=>{m(d,c)})})},[n,e,i,a]),s(_,{children:s("div",{className:"nosto_page_type",style:{display:"none"},children:"other"})})}function Z(t){const{clientScriptLoaded:n,currentVariation:e,responseMode:r,recommendationComponent:i,useRenderCampaigns:l}=h(),{renderCampaigns:m,pageTypeUpdated:a}=l("checkout");return u.useEffect(()=>{n&&a&&window.nostojs(c=>{c.defaultSession().setVariation(e).setResponseMode(r).viewCart().setPlacements(t.placements||c.placements.getPlacements()).load().then(d=>{m(d,c)})})},[n,e,i,a]),s(_,{children:s("div",{className:"nosto_page_type",style:{display:"none"},children:"cart"})})}function F(t){const n=i=>String(i)==="[object Object]";if(!n(t))return!1;const e=t.constructor;if(e===void 0)return!0;const r=e.prototype;return!(!n(r)||!r.hasOwnProperty("isPrototypeOf"))}function U(t,n){if(t===n)return!0;if(t instanceof Date&&n instanceof Date)return t.getTime()===n.getTime();if(t instanceof Array&&n instanceof Array)return t.length!==n.length?!1:t.every((e,r)=>U(e,n[r]));if(F(t)&&F(n)){const e=Object.entries(t);return e.length!==Object.keys(n).length?!1:e.every(([r,i])=>U(i,n[r]))}return!1}function I(t,n){return u.useEffect(t,K(n))}function K(t){const n=u.useRef(t),e=u.useRef(0);return U(t,n.current)||(n.current=t,e.current+=1),u.useMemo(()=>n.current,[e.current])}function Q(t){const{product:n,tagging:e}=t,{clientScriptLoaded:r,currentVariation:i,responseMode:l,recommendationComponent:m,useRenderCampaigns:a}=h(),{renderCampaigns:c,pageTypeUpdated:d}=a("product");return I(()=>{r&&d&&window.nostojs(o=>{o.defaultSession().setResponseMode(l).viewProduct(n).setPlacements(t.placements||o.placements.getPlacements()).load().then(y=>{c(y,o)})})},[r,i,n,m,d]),w(_,{children:[s("div",{className:"nosto_page_type",style:{display:"none"},children:"product"}),w("div",{className:"nosto_product",style:{display:"none"},children:[(e==null?void 0:e.variationId)&&s("span",{className:"variation_id",children:e.variationId}),n&&s("span",{className:"product_id",children:n}),(e==null?void 0:e.name)&&s("span",{className:"name",children:e.name}),(e==null?void 0:e.url)&&s("span",{className:"url",children:e.url.toString()}),(e==null?void 0:e.imageUrl)&&s("span",{className:"image_url",children:e.imageUrl.toString()}),(e==null?void 0:e.availability)&&s("span",{className:"availability",children:e.availability}),(e==null?void 0:e.price)&&s("span",{className:"price",children:e.price}),(e==null?void 0:e.listPrice)&&s("span",{className:"list_price",children:e.listPrice}),(e==null?void 0:e.priceCurrencyCode)&&s("span",{className:"price_currency_code",children:e.priceCurrencyCode}),(e==null?void 0:e.brand)&&s("span",{className:"brand",children:e.brand}),(e==null?void 0:e.description)&&s("span",{className:"description",children:e.description}),(e==null?void 0:e.googleCategory)&&s("span",{className:"description",children:e.googleCategory}),(e==null?void 0:e.condition)&&s("span",{className:"condition",children:e.condition}),(e==null?void 0:e.gender)&&s("span",{className:"gender",children:e.gender}),(e==null?void 0:e.ageGroup)&&s("span",{className:"age_group",children:e.ageGroup}),(e==null?void 0:e.gtin)&&s("span",{className:"gtin",children:e.gtin}),(e==null?void 0:e.category)&&(e==null?void 0:e.category.map((o,y)=>s("span",{className:"category",children:o},y))),(e==null?void 0:e.tags1)&&e.tags1.map((o,y)=>s("span",{className:"tag1",children:o},y)),(e==null?void 0:e.tags2)&&e.tags2.map((o,y)=>s("span",{className:"tag2",children:o},y)),(e==null?void 0:e.tags3)&&e.tags3.map((o,y)=>s("span",{className:"tag3",children:o},y)),(e==null?void 0:e.ratingValue)&&s("span",{className:"rating_value",children:e.ratingValue}),(e==null?void 0:e.reviewCount)&&s("span",{className:"review_count",children:e.reviewCount}),(e==null?void 0:e.alternateImageUrls)&&e.alternateImageUrls.map((o,y)=>s("span",{className:"alternate_image_url",children:o.toString()},y)),(e==null?void 0:e.customFields)&&Object.keys(e.customFields).map((o,y)=>e.customFields&&e.customFields[o]&&s("span",{className:o,children:e.customFields[o]},y)),(e==null?void 0:e.skus)&&e.skus.map((o,y)=>w("span",{className:"nosto_sku",children:[(o==null?void 0:o.id)&&s("span",{className:"product_id",children:o.id}),(o==null?void 0:o.name)&&s("span",{className:"name",children:o.name}),(o==null?void 0:o.price)&&s("span",{className:"price",children:o.price}),(o==null?void 0:o.listPrice)&&s("span",{className:"list_price",children:o.listPrice}),(o==null?void 0:o.url)&&s("span",{className:"url",children:o.url.toString()}),(o==null?void 0:o.imageUrl)&&s("span",{className:"image_url",children:o.imageUrl.toString()}),(o==null?void 0:o.gtin)&&s("span",{className:"gtin",children:o.gtin}),(o==null?void 0:o.availability)&&s("span",{className:"availability",children:o.availability}),(o==null?void 0:o.customFields)&&Object.keys(o.customFields).map((j,O)=>o.customFields&&o.customFields[j]&&s("span",{className:j,children:o.customFields[j]},O))]},y))]})]})}function X(t){const{category:n}=t,{clientScriptLoaded:e,currentVariation:r,responseMode:i,recommendationComponent:l,useRenderCampaigns:m}=h(),{renderCampaigns:a,pageTypeUpdated:c}=m("home");return u.useEffect(()=>{e&&c&&window.nostojs(d=>{d.defaultSession().setVariation(r).setResponseMode(i).viewCategory(n).setPlacements(t.placements||d.placements.getPlacements()).load().then(o=>{a(o,d)})})},[e,n,r,l,c]),w(_,{children:[s("div",{className:"nosto_page_type",style:{display:"none"},children:"category"}),s("div",{className:"nosto_category",style:{display:"none"},children:n})]})}function g(t){const{query:n}=t,{clientScriptLoaded:e,currentVariation:r,responseMode:i,recommendationComponent:l,useRenderCampaigns:m}=h(),{renderCampaigns:a,pageTypeUpdated:c}=m("search");return u.useEffect(()=>{e&&c&&window.nostojs(d=>{d.defaultSession().setVariation(r).setResponseMode(i).viewSearch(n).setPlacements(t.placements||d.placements.getPlacements()).load().then(o=>{a(o,d)})})},[e,r,n,l,c]),w(_,{children:[s("div",{className:"nosto_page_type",style:{display:"none"},children:"search"}),s("div",{className:"nosto_search",style:{display:"none"},children:n})]})}function P(t){return!t||typeof t!="object"||k(t)||ee(t)?t:Array.isArray(t)?t.map(P):Object.keys(t).reduce((n,e)=>{var r=e[0].toLowerCase()+e.slice(1).replace(/([A-Z]+)/g,(i,l)=>"_"+l.toLowerCase());return n[r]=P(t[e]),n},{})}function k(t){return Object.prototype.toString.call(t)==="[object Date]"}function ee(t){return Object.prototype.toString.call(t)==="[object RegExp]"}function te(t){const{order:n}=t,{clientScriptLoaded:e,currentVariation:r,responseMode:i,recommendationComponent:l,useRenderCampaigns:m}=h(),{renderCampaigns:a,pageTypeUpdated:c}=m("order");return u.useEffect(()=>{e&&c&&window.nostojs(d=>{d.defaultSession().setVariation(r).setResponseMode(i).addOrder(P(n)).setPlacements(t.placements||d.placements.getPlacements()).load().then(o=>{a(o,d)})})},[e,r,l,c]),w(_,{children:[s("div",{className:"nosto_page_type",style:{display:"none"},children:"order"}),s("div",{className:"nosto_order",style:{display:"none"},children:n.purchase.number})]})}function ne(t){const{clientScriptLoaded:n,currentVariation:e,responseMode:r,recommendationComponent:i,useRenderCampaigns:l}=h(),{renderCampaigns:m,pageTypeUpdated:a}=l("home");return u.useEffect(()=>{n&&a&&window.nostojs(c=>{c.defaultSession().setVariation(e).setResponseMode(r).viewFrontPage().setPlacements(t.placements||c.placements.getPlacements()).load().then(d=>{m(d,c)})})},[n,e,i,a]),s(_,{children:s("div",{className:"nosto_page_type",style:{display:"none"},children:"front"})})}function oe(t){const{id:n,pageType:e}=t;return s("div",{className:"nosto_element",id:n},n+(e||""))}function se(t){let{account:n,currentVariation:e="",multiCurrency:r=!1,host:i,children:l,recommendationComponent:m,shopifyMarkets:a}=t;const[c,d]=R.default.useState(!1),o=R.default.useMemo(()=>c,[c]);e=r?e:"";const y=u.isValidElement(m)?"JSON_ORIGINAL":"HTML";function j(v){return R.default.cloneElement(m,{nostoRecommendation:v.nostoRecommendation})}const[O,ae]=u.useState(""),ce=function(v=""){const S=u.useRef({});u.useEffect(()=>{O!=v&&ae(v)},[]);const M=v==O;function p(N,C){if(y=="HTML")C.placements.injectCampaigns(N.recommendations);else{const L=N.campaigns.recommendations;for(const T in L){let ie=L[T],de="#"+T,q=()=>document.querySelector(de);q()&&(S.current[T]||(S.current[T]=x.createRoot(q())),S.current[T].render(s(j,{nostoRecommendation:ie})))}}}return{renderCampaigns:p,pageTypeUpdated:M}};return u.useEffect(()=>{var v,S,M;if(window.nostojs||(window.nostojs=p=>{(window.nostojs.q=window.nostojs.q||[]).push(p)},window.nostojs(p=>p.setAutoLoad(!1))),!document.querySelectorAll("[nosto-client-script]").length&&!a){const p=document.createElement("script");p.type="text/javascript",p.src="//"+(i||"connect.nosto.com")+"/include/"+n,p.async=!0,p.setAttribute("nosto-client-script",""),p.onload=()=>{var N;typeof jest!="undefined"&&((N=window.nosto)==null||N.reload({site:"localhost"})),d(!0)},document.body.appendChild(p)}if(a){const p=document.querySelector("[nosto-client-script]"),N=document.querySelector("#nosto-sandbox");if(!p||(p==null?void 0:p.getAttribute("nosto-language"))!=(a==null?void 0:a.language)||(p==null?void 0:p.getAttribute("nosto-market-id"))!=(a==null?void 0:a.marketId)){c&&d(!1),(v=p==null?void 0:p.parentNode)==null||v.removeChild(p),(S=N==null?void 0:N.parentNode)==null||S.removeChild(N);const C=document.createElement("script");C.type="text/javascript",C.src="//"+(i||"connect.nosto.com")+`/script/shopify/market/nosto.js?merchant=${n}&market=${a.marketId||""}&locale=${((M=a==null?void 0:a.language)==null?void 0:M.toLowerCase())||""}`,C.async=!0,C.setAttribute("nosto-client-script",""),C.setAttribute("nosto-language",(a==null?void 0:a.language)||""),C.setAttribute("nosto-market-id",String(a==null?void 0:a.marketId)),C.onload=()=>{var L;typeof jest!="undefined"&&((L=window.nosto)==null||L.reload({site:"localhost"})),d(!0)},document.body.appendChild(C)}}},[c,a]),s(V.Provider,{value:{account:n,clientScriptLoaded:o,currentVariation:e,responseMode:y,recommendationComponent:m,useRenderCampaigns:ce,pageType:O},children:l})}function re(t){const{cart:n,customer:e}=t,{clientScriptLoaded:r}=h();return I(()=>{const i=n?P(n):void 0,l=e?P(e):void 0;r&&window.nostojs(m=>{m.defaultSession().setResponseMode("HTML").setCart(i).setCustomer(l).viewOther().load()})},[r,n,e]),s(_,{})}f.Nosto404=B,f.NostoCategory=X,f.NostoCheckout=Z,f.NostoContext=V,f.NostoHome=ne,f.NostoOrder=te,f.NostoOther=Y,f.NostoPlacement=oe,f.NostoProduct=Q,f.NostoProvider=se,f.NostoSearch=g,f.NostoSession=re,f.useNostoContext=h,Object.defineProperties(f,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { useNostoContext } from "../Provider/context.client";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* You can personalise your cart and checkout pages by using the NostoCheckout component.
|
|
6
|
-
* The component does not require any props.
|
|
7
|
-
*
|
|
8
|
-
* By default, your account, when created, has two cart-page placements named `categorypage-nosto-1` and `categorypage-nosto-2`.
|
|
9
|
-
* You may omit these and use any identifier you need.
|
|
10
|
-
* The identifiers used here are simply provided to illustrate the example.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```
|
|
14
|
-
* <div className="checkout-page">
|
|
15
|
-
* <NostoPlacement id="checkout-nosto-1" />
|
|
16
|
-
* <NostoPlacement id="checkout-nosto-2" />
|
|
17
|
-
* <NostoCheckout />
|
|
18
|
-
* </div>
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @group Personalisation Components
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
export default function NostoCheckout(props: {
|
|
25
|
-
placements?: string[];
|
|
26
|
-
}): JSX.Element {
|
|
27
|
-
const {
|
|
28
|
-
clientScriptLoaded,
|
|
29
|
-
currentVariation,
|
|
30
|
-
responseMode,
|
|
31
|
-
recommendationComponent,
|
|
32
|
-
useRenderCampaigns,
|
|
33
|
-
} = useNostoContext();
|
|
34
|
-
|
|
35
|
-
const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("checkout");
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (clientScriptLoaded && pageTypeUpdated) {
|
|
39
|
-
window.nostojs((api) => {
|
|
40
|
-
api
|
|
41
|
-
.defaultSession()
|
|
42
|
-
.setVariation(currentVariation)
|
|
43
|
-
.setResponseMode(responseMode)
|
|
44
|
-
.viewCart()
|
|
45
|
-
.setPlacements(props.placements || api.placements.getPlacements())
|
|
46
|
-
.load()
|
|
47
|
-
.then((data) => {
|
|
48
|
-
renderCampaigns(data, api);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}, [
|
|
53
|
-
clientScriptLoaded,
|
|
54
|
-
currentVariation,
|
|
55
|
-
recommendationComponent,
|
|
56
|
-
pageTypeUpdated,
|
|
57
|
-
]);
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<>
|
|
61
|
-
<div className="nosto_page_type" style={{ display: "none" }}>
|
|
62
|
-
cart
|
|
63
|
-
</div>
|
|
64
|
-
</>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { useNostoContext } from "../Provider/context.client";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* You can personalise your cart and checkout pages by using the `Nosto404` component.
|
|
6
|
-
* The component does not require any props.
|
|
7
|
-
*
|
|
8
|
-
* By default, your account, when created, has three 404-page placements named `notfound-nosto-1`, `notfound-nosto-2` and `notfound-nosto-3`.
|
|
9
|
-
* You may omit these and use any identifier you need.
|
|
10
|
-
* The identifiers used here are simply provided to illustrate the example.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```
|
|
14
|
-
* <div className="notfound-page">
|
|
15
|
-
* <NostoPlacement id="notfound-nosto-1" />
|
|
16
|
-
* <NostoPlacement id="notfound-nosto-2" />
|
|
17
|
-
* <NostoPlacement id="notfound-nosto-3" />
|
|
18
|
-
* <Nosto404 />
|
|
19
|
-
* </div>
|
|
20
|
-
* ```
|
|
21
|
-
*
|
|
22
|
-
* @group Personalisation Components
|
|
23
|
-
*/
|
|
24
|
-
export default function Nosto404(props: {
|
|
25
|
-
placements?: string[];
|
|
26
|
-
}): JSX.Element {
|
|
27
|
-
const {
|
|
28
|
-
clientScriptLoaded,
|
|
29
|
-
currentVariation,
|
|
30
|
-
responseMode,
|
|
31
|
-
recommendationComponent,
|
|
32
|
-
useRenderCampaigns,
|
|
33
|
-
} = useNostoContext();
|
|
34
|
-
|
|
35
|
-
const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("404");
|
|
36
|
-
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
if (clientScriptLoaded && pageTypeUpdated) {
|
|
39
|
-
window.nostojs((api) => {
|
|
40
|
-
api
|
|
41
|
-
.defaultSession()
|
|
42
|
-
.setVariation(currentVariation)
|
|
43
|
-
.setResponseMode(responseMode)
|
|
44
|
-
.viewNotFound()
|
|
45
|
-
.setPlacements(props.placements || api.placements.getPlacements())
|
|
46
|
-
.load()
|
|
47
|
-
.then((data) => {
|
|
48
|
-
renderCampaigns(data, api);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
}, [
|
|
53
|
-
clientScriptLoaded,
|
|
54
|
-
currentVariation,
|
|
55
|
-
recommendationComponent,
|
|
56
|
-
pageTypeUpdated,
|
|
57
|
-
]);
|
|
58
|
-
|
|
59
|
-
return (
|
|
60
|
-
<>
|
|
61
|
-
<div className="nosto_page_type" style={{ display: "none" }}>
|
|
62
|
-
notfound
|
|
63
|
-
</div>
|
|
64
|
-
</>
|
|
65
|
-
);
|
|
66
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { Purchase } from "../../types";
|
|
2
|
-
import { useEffect } from "react";
|
|
3
|
-
import { useNostoContext } from "../Provider/context.client";
|
|
4
|
-
import { snakeize } from "../../utils/snakeize";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* You can personalise your order-confirmation/thank-you page by using the `NostoOrder` component.
|
|
8
|
-
* The component requires that you provide it with the details of the order.
|
|
9
|
-
*
|
|
10
|
-
* By default, your account, when created, has one other-page placement named `thankyou-nosto-1`.
|
|
11
|
-
* You may omit this and use any identifier you need. The identifier used here is simply provided to illustrate the example.
|
|
12
|
-
*
|
|
13
|
-
* The order prop requires a value that adheres to the type `Purchase`.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```
|
|
17
|
-
* <div className="thankyou-page">
|
|
18
|
-
* <NostoPlacement id="thankyou-nosto-1" />
|
|
19
|
-
* <NostoOrder order={{ purchase: toOrder(order) }} />
|
|
20
|
-
* </div>
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* @group Personalisation Components
|
|
24
|
-
*/
|
|
25
|
-
export default function NostoOrder(props: {
|
|
26
|
-
order: { purchase: Purchase };
|
|
27
|
-
placements?: string[];
|
|
28
|
-
}): JSX.Element {
|
|
29
|
-
const { order } = props;
|
|
30
|
-
const {
|
|
31
|
-
clientScriptLoaded,
|
|
32
|
-
currentVariation,
|
|
33
|
-
responseMode,
|
|
34
|
-
recommendationComponent,
|
|
35
|
-
useRenderCampaigns,
|
|
36
|
-
} = useNostoContext();
|
|
37
|
-
|
|
38
|
-
const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("order");
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
if (clientScriptLoaded && pageTypeUpdated) {
|
|
42
|
-
window.nostojs((api) => {
|
|
43
|
-
api
|
|
44
|
-
.defaultSession()
|
|
45
|
-
.setVariation(currentVariation)
|
|
46
|
-
.setResponseMode(responseMode)
|
|
47
|
-
.addOrder(snakeize(order))
|
|
48
|
-
.setPlacements(props.placements || api.placements.getPlacements())
|
|
49
|
-
.load()
|
|
50
|
-
.then((data) => {
|
|
51
|
-
renderCampaigns(data, api);
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
}, [
|
|
56
|
-
clientScriptLoaded,
|
|
57
|
-
currentVariation,
|
|
58
|
-
recommendationComponent,
|
|
59
|
-
pageTypeUpdated,
|
|
60
|
-
]);
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
<>
|
|
64
|
-
<div className="nosto_page_type" style={{ display: "none" }}>
|
|
65
|
-
order
|
|
66
|
-
</div>
|
|
67
|
-
<div className="nosto_order" style={{ display: "none" }}>
|
|
68
|
-
{order.purchase.number}
|
|
69
|
-
</div>
|
|
70
|
-
</>
|
|
71
|
-
);
|
|
72
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import React, { useEffect } from "react";
|
|
2
|
-
import { useNostoContext } from "../Provider/context.client";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* You can personalise your miscellaneous pages by using the NostoOther component.
|
|
6
|
-
* The component does not require any props.
|
|
7
|
-
*
|
|
8
|
-
* By default, your account, when created, has two other-page placements named `other-nosto-1` and `other-nosto-2`.
|
|
9
|
-
* You may omit these and use any identifier you need.
|
|
10
|
-
* The identifiers used here are simply provided to illustrate the example.
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```
|
|
14
|
-
* <div className="other-page">
|
|
15
|
-
* <NostoPlacement id="other-nosto-1" />
|
|
16
|
-
* <NostoPlacement id="other-nosto-2" />
|
|
17
|
-
* <NostoOther />
|
|
18
|
-
* </div>;
|
|
19
|
-
* ```
|
|
20
|
-
*
|
|
21
|
-
* @group Personalisation Components
|
|
22
|
-
*/
|
|
23
|
-
export default function NostoOther(props: {
|
|
24
|
-
placements?: string[];
|
|
25
|
-
}): JSX.Element {
|
|
26
|
-
const {
|
|
27
|
-
clientScriptLoaded,
|
|
28
|
-
currentVariation,
|
|
29
|
-
responseMode,
|
|
30
|
-
recommendationComponent,
|
|
31
|
-
useRenderCampaigns,
|
|
32
|
-
} = useNostoContext();
|
|
33
|
-
|
|
34
|
-
const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("other");
|
|
35
|
-
useEffect(() => {
|
|
36
|
-
if (clientScriptLoaded && pageTypeUpdated) {
|
|
37
|
-
window.nostojs((api) => {
|
|
38
|
-
api
|
|
39
|
-
.defaultSession()
|
|
40
|
-
.setVariation(currentVariation)
|
|
41
|
-
.setResponseMode(responseMode)
|
|
42
|
-
.viewOther()
|
|
43
|
-
.setPlacements(props.placements || api.placements.getPlacements())
|
|
44
|
-
.load()
|
|
45
|
-
.then((data) => {
|
|
46
|
-
renderCampaigns(data, api);
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
}, [
|
|
51
|
-
clientScriptLoaded,
|
|
52
|
-
currentVariation,
|
|
53
|
-
recommendationComponent,
|
|
54
|
-
pageTypeUpdated,
|
|
55
|
-
]);
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<>
|
|
59
|
-
<div className="nosto_page_type" style={{ display: "none" }}>
|
|
60
|
-
other
|
|
61
|
-
</div>
|
|
62
|
-
</>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { createContext, useContext } from "react";
|
|
2
|
-
import { Recommendation } from "../../types";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @group Types
|
|
6
|
-
*/
|
|
7
|
-
export interface NostoContextType {
|
|
8
|
-
account: string;
|
|
9
|
-
clientScriptLoaded: boolean;
|
|
10
|
-
currentVariation: string;
|
|
11
|
-
renderFunction?: Function;
|
|
12
|
-
responseMode: string;
|
|
13
|
-
recommendationComponent?: React.ReactElement<{
|
|
14
|
-
nostoRecommendation: Recommendation;
|
|
15
|
-
}>;
|
|
16
|
-
useRenderCampaigns: Function;
|
|
17
|
-
pageType: string;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @group Essential Functions
|
|
22
|
-
*/
|
|
23
|
-
export const NostoContext = createContext<NostoContextType>({
|
|
24
|
-
account: "",
|
|
25
|
-
currentVariation: "",
|
|
26
|
-
pageType: "",
|
|
27
|
-
responseMode: "HTML",
|
|
28
|
-
clientScriptLoaded: false,
|
|
29
|
-
useRenderCampaigns: () => undefined,
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* A hook that allows you to access the NostoContext and retrieve Nosto-related data from it in React components.
|
|
34
|
-
*
|
|
35
|
-
* @group Essential Functions
|
|
36
|
-
*/
|
|
37
|
-
export function useNostoContext(): NostoContextType {
|
|
38
|
-
const context = useContext(NostoContext);
|
|
39
|
-
|
|
40
|
-
if (!context) {
|
|
41
|
-
throw new Error("No nosto context found");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return context;
|
|
45
|
-
}
|