@nosto/nosto-react 0.4.0 → 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} +127 -168
- 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 -38
- package/src/components/NostoCheckout.tsx +47 -0
- package/src/components/{Home/index.client.tsx → NostoHome.tsx} +17 -34
- package/src/components/{Order/index.client.tsx → NostoOrder.tsx} +22 -38
- 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 -80
- package/src/components/NostoProvider.tsx +220 -0
- package/src/components/{Search/index.client.tsx → NostoSearch.tsx} +18 -36
- 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 -64
- package/src/components/Fohofo/index.client.tsx +0 -64
- package/src/components/Other/index.client.tsx +0 -63
- 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
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import React, { useEffect, isValidElement, useState, useRef } from "react"
|
|
2
|
+
import { NostoContext } from "./context"
|
|
3
|
+
import { createRoot, Root } from "react-dom/client"
|
|
4
|
+
import { NostoClient, Recommendation } from "../types"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @group Components
|
|
8
|
+
*/
|
|
9
|
+
export interface NostoProviderProps {
|
|
10
|
+
/**
|
|
11
|
+
* Indicates merchant id
|
|
12
|
+
*/
|
|
13
|
+
account: string
|
|
14
|
+
/**
|
|
15
|
+
* Indicates currency
|
|
16
|
+
*/
|
|
17
|
+
currentVariation?: string
|
|
18
|
+
/**
|
|
19
|
+
* Indicates an url of a server
|
|
20
|
+
*/
|
|
21
|
+
host?: string
|
|
22
|
+
children: React.ReactElement
|
|
23
|
+
/**
|
|
24
|
+
* Indicates if merchant uses multiple currencies
|
|
25
|
+
*/
|
|
26
|
+
multiCurrency?: boolean
|
|
27
|
+
/**
|
|
28
|
+
* Recommendation component which holds nostoRecommendation object
|
|
29
|
+
*/
|
|
30
|
+
recommendationComponent?: React.ReactElement<{
|
|
31
|
+
nostoRecommendation: Recommendation
|
|
32
|
+
}>
|
|
33
|
+
/**
|
|
34
|
+
* Enables Shopify markets with language and market id
|
|
35
|
+
*/
|
|
36
|
+
shopifyMarkets?: {
|
|
37
|
+
language?: string
|
|
38
|
+
marketId?: string | number
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* This widget is what we call the Nosto root widget, which is responsible for adding the actual Nosto script and the JS API stub.
|
|
44
|
+
* This widget wraps all other React Nosto widgets.
|
|
45
|
+
*
|
|
46
|
+
* ```
|
|
47
|
+
* <NostoProvider account="your-nosto-account-id" recommendationComponent={<NostoSlot />}>
|
|
48
|
+
* <App />
|
|
49
|
+
* </NostoProvider>
|
|
50
|
+
* ```
|
|
51
|
+
*
|
|
52
|
+
* **Note:** the component also accepts a prop to configure the host `host="connect.nosto.com"`.
|
|
53
|
+
* In advanced use-cases, the need to configure the host may surface.
|
|
54
|
+
*
|
|
55
|
+
* In order to implement client-side rendering, the requires a designated component to render the recommendations provided by Nosto.
|
|
56
|
+
* This component should be capable of processing the JSON response received from our backend.
|
|
57
|
+
* Notice the `recommendationComponent` prop passed to `<NostoProvider>` above.
|
|
58
|
+
*
|
|
59
|
+
* Learn more [here](https://github.com/Nosto/shopify-hydrogen/blob/main/README.md#client-side-rendering-for-recommendations) and see a [live example](https://github.com/Nosto/shopify-hydrogen-demo) on our demo store.
|
|
60
|
+
*
|
|
61
|
+
* @group Components
|
|
62
|
+
*/
|
|
63
|
+
export default function NostoProvider(props: NostoProviderProps) {
|
|
64
|
+
const {
|
|
65
|
+
account,
|
|
66
|
+
multiCurrency = false,
|
|
67
|
+
host,
|
|
68
|
+
children,
|
|
69
|
+
recommendationComponent,
|
|
70
|
+
shopifyMarkets,
|
|
71
|
+
} = props
|
|
72
|
+
const [clientScriptLoadedState, setClientScriptLoadedState] = React.useState(false)
|
|
73
|
+
const clientScriptLoaded = React.useMemo(() => clientScriptLoadedState, [clientScriptLoadedState])
|
|
74
|
+
|
|
75
|
+
// Pass currentVariation as empty string if multiCurrency is disabled
|
|
76
|
+
const currentVariation = multiCurrency ? props.currentVariation : ""
|
|
77
|
+
|
|
78
|
+
// Set responseMode for loading campaigns:
|
|
79
|
+
const responseMode = isValidElement(recommendationComponent) ? "JSON_ORIGINAL" : "HTML"
|
|
80
|
+
|
|
81
|
+
// RecommendationComponent for client-side rendering:
|
|
82
|
+
function RecommendationComponentWrapper(props: { nostoRecommendation: Recommendation }) {
|
|
83
|
+
return React.cloneElement(recommendationComponent!, {
|
|
84
|
+
// eslint-disable-next-line react/prop-types
|
|
85
|
+
nostoRecommendation: props.nostoRecommendation,
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// custom hook for rendering campaigns (CSR/SSR):
|
|
90
|
+
const [pageType, setPageType] = useState("")
|
|
91
|
+
function useRenderCampaigns(type: string = "") {
|
|
92
|
+
const placementRefs = useRef<Record<string, Root>>({})
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (pageType !== type) {
|
|
95
|
+
setPageType(type)
|
|
96
|
+
}
|
|
97
|
+
}, [])
|
|
98
|
+
|
|
99
|
+
const pageTypeUpdated = type === pageType
|
|
100
|
+
|
|
101
|
+
function renderCampaigns(
|
|
102
|
+
data: {
|
|
103
|
+
recommendations: Record<string, Recommendation>
|
|
104
|
+
campaigns: {
|
|
105
|
+
recommendations: Record<string, Recommendation>
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
api: NostoClient
|
|
109
|
+
) {
|
|
110
|
+
if (responseMode == "HTML") {
|
|
111
|
+
// inject content campaigns as usual:
|
|
112
|
+
api.placements.injectCampaigns(data.recommendations)
|
|
113
|
+
} else {
|
|
114
|
+
// render recommendation component into placements:
|
|
115
|
+
const recommendations = data.campaigns.recommendations
|
|
116
|
+
for (const key in recommendations) {
|
|
117
|
+
const recommendation = recommendations[key]
|
|
118
|
+
const placementSelector = "#" + key
|
|
119
|
+
const placement = () => document.querySelector(placementSelector)
|
|
120
|
+
|
|
121
|
+
if (placement()) {
|
|
122
|
+
if (!placementRefs.current[key]) placementRefs.current[key] = createRoot(placement()!)
|
|
123
|
+
const root = placementRefs.current[key]!
|
|
124
|
+
root.render(
|
|
125
|
+
<RecommendationComponentWrapper
|
|
126
|
+
nostoRecommendation={recommendation}
|
|
127
|
+
></RecommendationComponentWrapper>
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return { renderCampaigns, pageTypeUpdated }
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
if (!window.nostojs) {
|
|
138
|
+
window.nostojs = (cb: (api: NostoClient) => void) => {
|
|
139
|
+
(window.nostojs.q = window.nostojs.q || []).push(cb)
|
|
140
|
+
}
|
|
141
|
+
window.nostojs(api => api.setAutoLoad(false))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!document.querySelectorAll("[nosto-client-script]").length && !shopifyMarkets) {
|
|
145
|
+
const script = document.createElement("script")
|
|
146
|
+
script.type = "text/javascript"
|
|
147
|
+
script.src = "//" + (host || "connect.nosto.com") + "/include/" + account
|
|
148
|
+
script.async = true
|
|
149
|
+
script.setAttribute("nosto-client-script", "")
|
|
150
|
+
|
|
151
|
+
script.onload = () => {
|
|
152
|
+
if (typeof jest !== "undefined") {
|
|
153
|
+
window.nosto?.reload({
|
|
154
|
+
site: "localhost",
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
setClientScriptLoadedState(true)
|
|
158
|
+
}
|
|
159
|
+
document.body.appendChild(script)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Enable Shopify markets functionality:
|
|
163
|
+
if (shopifyMarkets) {
|
|
164
|
+
const existingScript = document.querySelector("[nosto-client-script]")
|
|
165
|
+
const nostoSandbox = document.querySelector("#nosto-sandbox")
|
|
166
|
+
|
|
167
|
+
if (
|
|
168
|
+
!existingScript ||
|
|
169
|
+
existingScript?.getAttribute("nosto-language") !== shopifyMarkets?.language ||
|
|
170
|
+
existingScript?.getAttribute("nosto-market-id") !== shopifyMarkets?.marketId
|
|
171
|
+
) {
|
|
172
|
+
if (clientScriptLoadedState) {
|
|
173
|
+
setClientScriptLoadedState(false)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
existingScript?.parentNode?.removeChild(existingScript)
|
|
177
|
+
nostoSandbox?.parentNode?.removeChild(nostoSandbox)
|
|
178
|
+
|
|
179
|
+
const script = document.createElement("script")
|
|
180
|
+
script.type = "text/javascript"
|
|
181
|
+
script.src =
|
|
182
|
+
"//" +
|
|
183
|
+
(host || "connect.nosto.com") +
|
|
184
|
+
`/script/shopify/market/nosto.js?merchant=${account}&market=${
|
|
185
|
+
shopifyMarkets.marketId || ""
|
|
186
|
+
}&locale=${shopifyMarkets?.language?.toLowerCase() || ""}`
|
|
187
|
+
script.async = true
|
|
188
|
+
script.setAttribute("nosto-client-script", "")
|
|
189
|
+
script.setAttribute("nosto-language", shopifyMarkets?.language || "")
|
|
190
|
+
script.setAttribute("nosto-market-id", String(shopifyMarkets?.marketId))
|
|
191
|
+
|
|
192
|
+
script.onload = () => {
|
|
193
|
+
if (typeof jest !== "undefined") {
|
|
194
|
+
window.nosto?.reload({
|
|
195
|
+
site: "localhost",
|
|
196
|
+
})
|
|
197
|
+
}
|
|
198
|
+
setClientScriptLoadedState(true)
|
|
199
|
+
}
|
|
200
|
+
document.body.appendChild(script)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}, [clientScriptLoadedState, shopifyMarkets])
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<NostoContext.Provider
|
|
207
|
+
value={{
|
|
208
|
+
account,
|
|
209
|
+
clientScriptLoaded,
|
|
210
|
+
currentVariation,
|
|
211
|
+
responseMode,
|
|
212
|
+
recommendationComponent,
|
|
213
|
+
useRenderCampaigns,
|
|
214
|
+
pageType,
|
|
215
|
+
}}
|
|
216
|
+
>
|
|
217
|
+
{children}
|
|
218
|
+
</NostoContext.Provider>
|
|
219
|
+
)
|
|
220
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { useNostoContext } from "./context"
|
|
2
|
+
import { useNostoApi } from "../utils/hooks"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* You can personalise your search pages by using the NostoSearch component.
|
|
@@ -22,42 +22,24 @@ import { useNostoContext } from "../Provider/context.client";
|
|
|
22
22
|
* A query for `black shoes` must be provided as-is and not as `black+shoes`.
|
|
23
23
|
* Doing so will lead to invalid results.
|
|
24
24
|
*
|
|
25
|
-
* @group
|
|
25
|
+
* @group Components
|
|
26
26
|
*/
|
|
27
|
-
export default function NostoSearch(props: { query: string })
|
|
28
|
-
const { query } = props
|
|
29
|
-
const {
|
|
30
|
-
clientScriptLoaded,
|
|
31
|
-
currentVariation,
|
|
32
|
-
responseMode,
|
|
33
|
-
recommendationComponent,
|
|
34
|
-
useRenderCampaigns,
|
|
35
|
-
} = useNostoContext();
|
|
27
|
+
export default function NostoSearch(props: { query: string; placements?: string[] }) {
|
|
28
|
+
const { query, placements } = props
|
|
29
|
+
const { recommendationComponent, useRenderCampaigns } = useNostoContext()
|
|
36
30
|
|
|
37
|
-
const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("search")
|
|
31
|
+
const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("search")
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.then((data) => {
|
|
50
|
-
renderCampaigns(data, api);
|
|
51
|
-
});
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}, [
|
|
55
|
-
clientScriptLoaded,
|
|
56
|
-
currentVariation,
|
|
57
|
-
query,
|
|
58
|
-
recommendationComponent,
|
|
59
|
-
pageTypeUpdated,
|
|
60
|
-
]);
|
|
33
|
+
useNostoApi(
|
|
34
|
+
async (api) => {
|
|
35
|
+
const data = await api.defaultSession()
|
|
36
|
+
.viewSearch(query)
|
|
37
|
+
.setPlacements(placements || api.placements.getPlacements())
|
|
38
|
+
.load()
|
|
39
|
+
renderCampaigns(data, api)
|
|
40
|
+
},
|
|
41
|
+
[query, recommendationComponent, pageTypeUpdated]
|
|
42
|
+
)
|
|
61
43
|
|
|
62
44
|
return (
|
|
63
45
|
<>
|
|
@@ -68,5 +50,5 @@ export default function NostoSearch(props: { query: string }): JSX.Element {
|
|
|
68
50
|
{query}
|
|
69
51
|
</div>
|
|
70
52
|
</>
|
|
71
|
-
)
|
|
53
|
+
)
|
|
72
54
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { useNostoContext } from "
|
|
2
|
-
import { Cart, Customer } from "
|
|
3
|
-
import { snakeize } from "
|
|
4
|
-
import { useDeepCompareEffect } from "
|
|
1
|
+
import { useNostoContext } from "./context"
|
|
2
|
+
import { Cart, Customer } from "../types"
|
|
3
|
+
import { snakeize } from "../utils/snakeize"
|
|
4
|
+
import { useDeepCompareEffect } from "../utils/hooks"
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Nosto React requires that you pass it the details of current cart contents and the details of the currently logged-in customer, if any, on every route change.
|
|
@@ -13,29 +13,26 @@ import { useDeepCompareEffect } from "../../utils/hooks";
|
|
|
13
13
|
*
|
|
14
14
|
* @group Essential Functions
|
|
15
15
|
*/
|
|
16
|
-
export default function NostoSession(props: {
|
|
17
|
-
cart
|
|
18
|
-
|
|
19
|
-
}): JSX.Element {
|
|
20
|
-
const { cart, customer } = props;
|
|
21
|
-
const { clientScriptLoaded } = useNostoContext();
|
|
16
|
+
export default function NostoSession(props: { cart: Cart; customer: Customer }) {
|
|
17
|
+
const { cart, customer } = props
|
|
18
|
+
const { clientScriptLoaded } = useNostoContext()
|
|
22
19
|
|
|
23
20
|
useDeepCompareEffect(() => {
|
|
24
|
-
const currentCart = cart ? snakeize(cart) : undefined
|
|
25
|
-
const currentCustomer = customer ? snakeize(customer) : undefined
|
|
21
|
+
const currentCart = cart ? snakeize(cart) : undefined
|
|
22
|
+
const currentCustomer = customer ? snakeize(customer) : undefined
|
|
26
23
|
|
|
27
24
|
if (clientScriptLoaded) {
|
|
28
|
-
window.nostojs(
|
|
25
|
+
window.nostojs(api => {
|
|
29
26
|
api
|
|
30
27
|
.defaultSession()
|
|
31
28
|
.setResponseMode("HTML")
|
|
32
29
|
.setCart(currentCart)
|
|
33
30
|
.setCustomer(currentCustomer)
|
|
34
31
|
.viewOther()
|
|
35
|
-
.load()
|
|
36
|
-
})
|
|
32
|
+
.load()
|
|
33
|
+
})
|
|
37
34
|
}
|
|
38
|
-
}, [clientScriptLoaded, cart, customer])
|
|
35
|
+
}, [clientScriptLoaded, cart, customer])
|
|
39
36
|
|
|
40
|
-
return
|
|
37
|
+
return <></>
|
|
41
38
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { createContext, useContext } from "react"
|
|
2
|
+
import { NostoClient, Recommendation } from "../types"
|
|
3
|
+
|
|
4
|
+
type AnyFunction = (...args: unknown[]) => unknown
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @group Types
|
|
8
|
+
*/
|
|
9
|
+
export interface NostoContextType {
|
|
10
|
+
account: string
|
|
11
|
+
clientScriptLoaded: boolean
|
|
12
|
+
currentVariation?: string
|
|
13
|
+
renderFunction?: AnyFunction
|
|
14
|
+
responseMode: string
|
|
15
|
+
recommendationComponent?: React.ReactElement<{
|
|
16
|
+
nostoRecommendation: Recommendation
|
|
17
|
+
}>
|
|
18
|
+
useRenderCampaigns(type: string): {
|
|
19
|
+
renderCampaigns(data: unknown, api: NostoClient): void
|
|
20
|
+
pageTypeUpdated: boolean
|
|
21
|
+
}
|
|
22
|
+
pageType: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @group Essential Functions
|
|
27
|
+
*/
|
|
28
|
+
export const NostoContext = createContext<NostoContextType>({
|
|
29
|
+
account: "",
|
|
30
|
+
currentVariation: "",
|
|
31
|
+
pageType: "",
|
|
32
|
+
responseMode: "HTML",
|
|
33
|
+
clientScriptLoaded: false,
|
|
34
|
+
useRenderCampaigns: () => {
|
|
35
|
+
return {
|
|
36
|
+
renderCampaigns: () => {},
|
|
37
|
+
pageTypeUpdated: false,
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A hook that allows you to access the NostoContext and retrieve Nosto-related data from it in React components.
|
|
44
|
+
*
|
|
45
|
+
* @group Essential Functions
|
|
46
|
+
*/
|
|
47
|
+
export function useNostoContext(): NostoContextType {
|
|
48
|
+
const context = useContext(NostoContext)
|
|
49
|
+
|
|
50
|
+
if (!context) {
|
|
51
|
+
throw new Error("No nosto context found")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return context
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { default as Nosto404 } from "./Nosto404"
|
|
2
|
+
export { default as NostoOther } from "./NostoOther"
|
|
3
|
+
export { default as NostoCheckout } from "./NostoCheckout"
|
|
4
|
+
export { default as NostoProduct } from "./NostoProduct"
|
|
5
|
+
export { default as NostoCategory } from "./NostoCategory"
|
|
6
|
+
export { default as NostoSearch } from "./NostoSearch"
|
|
7
|
+
export { default as NostoOrder } from "./NostoOrder"
|
|
8
|
+
export { default as NostoHome } from "./NostoHome"
|
|
9
|
+
export { default as NostoPlacement } from "./NostoPlacement"
|
|
10
|
+
export { default as NostoProvider } from "./NostoProvider"
|
|
11
|
+
|
|
12
|
+
export { NostoContext, useNostoContext } from "./context"
|
|
13
|
+
export type { NostoContextType } from "./context"
|
|
14
|
+
export { default as NostoSession } from "./NostoSession"
|
package/src/index.ts
ADDED
package/src/types.ts
CHANGED
|
@@ -1,158 +1,173 @@
|
|
|
1
1
|
declare global {
|
|
2
2
|
interface Window {
|
|
3
3
|
nosto?: {
|
|
4
|
-
reload(settings: unknown): void
|
|
5
|
-
}
|
|
4
|
+
reload(settings: unknown): void
|
|
5
|
+
}
|
|
6
6
|
nostojs: {
|
|
7
|
-
(callback: (api: NostoClient) => void): void
|
|
8
|
-
q?: unknown[]
|
|
9
|
-
}
|
|
7
|
+
(callback: (api: NostoClient) => void): void
|
|
8
|
+
q?: unknown[]
|
|
9
|
+
}
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* @group Types
|
|
15
15
|
*/
|
|
16
|
-
export interface
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
viewProduct(product: string): NostoClient;
|
|
27
|
-
viewFrontPage(): NostoClient;
|
|
28
|
-
viewNotFound(): NostoClient;
|
|
29
|
-
viewOther(): NostoClient;
|
|
30
|
-
viewSearch(query: string): NostoClient;
|
|
31
|
-
viewCart(): NostoClient;
|
|
16
|
+
export interface Affinity {
|
|
17
|
+
name: string
|
|
18
|
+
score: number
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @group Types
|
|
23
|
+
*/
|
|
24
|
+
export interface SessionAction {
|
|
25
|
+
setPlacements(placements: string[]): SessionAction
|
|
32
26
|
load(): Promise<{
|
|
33
|
-
affinities: Record<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
affinities: Record<string, Affinity[]>
|
|
28
|
+
geo_location?: string[]
|
|
29
|
+
page_views: number
|
|
30
|
+
recommendations: Recommendation[]
|
|
31
|
+
}>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @group Types
|
|
36
|
+
*/
|
|
37
|
+
export interface NostoSession {
|
|
38
|
+
setCart(cart?: Cart): NostoSession
|
|
39
|
+
setCustomer(customer?: Customer): NostoSession
|
|
40
|
+
setResponseMode(mode: string): NostoSession
|
|
41
|
+
setVariation(variation?: string): NostoSession
|
|
42
|
+
addOrder(order: { purchase: Purchase }): SessionAction
|
|
43
|
+
viewCategory(category: string): SessionAction
|
|
44
|
+
viewProduct(product: string): SessionAction
|
|
45
|
+
viewFrontPage(): SessionAction
|
|
46
|
+
viewNotFound(): SessionAction
|
|
47
|
+
viewOther(): SessionAction
|
|
48
|
+
viewSearch(query: string): SessionAction
|
|
49
|
+
viewCart(): SessionAction
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @group Types
|
|
54
|
+
*/
|
|
55
|
+
export interface NostoClient {
|
|
56
|
+
setAutoLoad(autoload: boolean): NostoClient
|
|
57
|
+
defaultSession(): NostoSession
|
|
44
58
|
placements: {
|
|
45
|
-
getPlacements(): string[]
|
|
46
|
-
|
|
59
|
+
getPlacements(): string[]
|
|
60
|
+
injectCampaigns(recommendations: Record<string, Recommendation>): void
|
|
61
|
+
}
|
|
47
62
|
}
|
|
48
63
|
|
|
49
64
|
/**
|
|
50
65
|
* @group Types
|
|
51
66
|
*/
|
|
52
67
|
export interface Recommendation {
|
|
53
|
-
result_id: string
|
|
54
|
-
products: Product[]
|
|
55
|
-
result_type: string
|
|
56
|
-
title: string
|
|
57
|
-
div_id: string
|
|
58
|
-
source_product_ids: string[]
|
|
59
|
-
params: unknown
|
|
68
|
+
result_id: string
|
|
69
|
+
products: Product[]
|
|
70
|
+
result_type: string
|
|
71
|
+
title: string
|
|
72
|
+
div_id: string
|
|
73
|
+
source_product_ids: string[]
|
|
74
|
+
params: unknown
|
|
60
75
|
}
|
|
61
76
|
|
|
62
77
|
/**
|
|
63
78
|
* @group Types
|
|
64
79
|
*/
|
|
65
80
|
export interface Item {
|
|
66
|
-
name: string
|
|
67
|
-
price_currency_code: string
|
|
68
|
-
product_id: string
|
|
69
|
-
quantity: number
|
|
70
|
-
sku_id: string
|
|
71
|
-
unit_price: number
|
|
81
|
+
name: string
|
|
82
|
+
price_currency_code: string
|
|
83
|
+
product_id: string
|
|
84
|
+
quantity: number
|
|
85
|
+
sku_id: string
|
|
86
|
+
unit_price: number
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
/**
|
|
75
90
|
* @group Types
|
|
76
91
|
*/
|
|
77
92
|
export interface Cart {
|
|
78
|
-
items: Item[]
|
|
93
|
+
items: Item[]
|
|
79
94
|
}
|
|
80
95
|
|
|
81
96
|
/**
|
|
82
97
|
* @group Types
|
|
83
98
|
*/
|
|
84
99
|
export interface Customer {
|
|
85
|
-
customer_reference: string
|
|
86
|
-
email: string
|
|
87
|
-
first_name: string
|
|
88
|
-
last_name: string
|
|
89
|
-
newsletter: boolean
|
|
100
|
+
customer_reference: string
|
|
101
|
+
email: string
|
|
102
|
+
first_name: string
|
|
103
|
+
last_name: string
|
|
104
|
+
newsletter: boolean
|
|
90
105
|
}
|
|
91
106
|
|
|
92
107
|
/**
|
|
93
108
|
* @group Types
|
|
94
109
|
*/
|
|
95
110
|
export interface Buyer {
|
|
96
|
-
first_name: string
|
|
97
|
-
last_name: string
|
|
98
|
-
email: string
|
|
99
|
-
type: string
|
|
100
|
-
newsletter: boolean
|
|
111
|
+
first_name: string
|
|
112
|
+
last_name: string
|
|
113
|
+
email: string
|
|
114
|
+
type: string
|
|
115
|
+
newsletter: boolean
|
|
101
116
|
}
|
|
102
117
|
|
|
103
118
|
/**
|
|
104
119
|
* @group Types
|
|
105
120
|
*/
|
|
106
121
|
export interface Purchase {
|
|
107
|
-
number: string
|
|
108
|
-
info: Buyer
|
|
109
|
-
items: Item[]
|
|
122
|
+
number: string
|
|
123
|
+
info: Buyer
|
|
124
|
+
items: Item[]
|
|
110
125
|
}
|
|
111
126
|
|
|
112
127
|
/**
|
|
113
128
|
* @group Types
|
|
114
129
|
*/
|
|
115
130
|
export interface SKU {
|
|
116
|
-
id: string
|
|
117
|
-
name: string
|
|
118
|
-
price: number
|
|
119
|
-
listPrice?: number
|
|
120
|
-
url: URL
|
|
121
|
-
imageUrl: URL
|
|
122
|
-
gtin?: string
|
|
123
|
-
availability: "InStock" | "OutOfStock"
|
|
124
|
-
customFields?: { [key: string]: string }
|
|
131
|
+
id: string
|
|
132
|
+
name: string
|
|
133
|
+
price: number
|
|
134
|
+
listPrice?: number
|
|
135
|
+
url: URL
|
|
136
|
+
imageUrl: URL
|
|
137
|
+
gtin?: string
|
|
138
|
+
availability: "InStock" | "OutOfStock"
|
|
139
|
+
customFields?: { [key: string]: string }
|
|
125
140
|
}
|
|
126
141
|
|
|
127
142
|
/**
|
|
128
143
|
* @group Types
|
|
129
144
|
*/
|
|
130
145
|
export interface Product {
|
|
131
|
-
alternateImageUrls?: URL[]
|
|
132
|
-
availability: "InStock" | "OutOfStock"
|
|
133
|
-
brand?: string
|
|
134
|
-
category: string[]
|
|
135
|
-
categoryIds?: string[]
|
|
136
|
-
description: string
|
|
137
|
-
googleCategory?: string
|
|
138
|
-
condition?: string
|
|
139
|
-
gender?: string
|
|
140
|
-
ageGroup?: string
|
|
141
|
-
gtin?: string
|
|
142
|
-
imageUrl: URL
|
|
143
|
-
listPrice?: number
|
|
144
|
-
name: string
|
|
145
|
-
price: number
|
|
146
|
-
ratingValue?: number
|
|
147
|
-
reviewCount?: number
|
|
148
|
-
priceCurrencyCode: string
|
|
149
|
-
productId: string
|
|
150
|
-
tags1?: string[]
|
|
151
|
-
tags2?: string[]
|
|
152
|
-
tags3?: string[]
|
|
153
|
-
thumbUrl?: URL
|
|
154
|
-
url: URL
|
|
155
|
-
customFields?: { [key: string]: string }
|
|
156
|
-
variationId?: string
|
|
157
|
-
skus?: SKU[]
|
|
146
|
+
alternateImageUrls?: URL[]
|
|
147
|
+
availability: "InStock" | "OutOfStock"
|
|
148
|
+
brand?: string
|
|
149
|
+
category: string[]
|
|
150
|
+
categoryIds?: string[]
|
|
151
|
+
description: string
|
|
152
|
+
googleCategory?: string
|
|
153
|
+
condition?: string
|
|
154
|
+
gender?: string
|
|
155
|
+
ageGroup?: string
|
|
156
|
+
gtin?: string
|
|
157
|
+
imageUrl: URL
|
|
158
|
+
listPrice?: number
|
|
159
|
+
name: string
|
|
160
|
+
price: number
|
|
161
|
+
ratingValue?: number
|
|
162
|
+
reviewCount?: number
|
|
163
|
+
priceCurrencyCode: string
|
|
164
|
+
productId: string
|
|
165
|
+
tags1?: string[]
|
|
166
|
+
tags2?: string[]
|
|
167
|
+
tags3?: string[]
|
|
168
|
+
thumbUrl?: URL
|
|
169
|
+
url: URL
|
|
170
|
+
customFields?: { [key: string]: string }
|
|
171
|
+
variationId?: string
|
|
172
|
+
skus?: SKU[]
|
|
158
173
|
}
|