@nosto/nosto-react 0.2.0 → 0.3.0

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.
@@ -1,8 +1,10 @@
1
1
  import * as React from "react";
2
- import React__default, { createContext, useContext, useEffect } from "react";
2
+ import React__default, { createContext, useContext, useEffect, isValidElement, useState, useRef } from "react";
3
+ import { createRoot } from "react-dom/client";
3
4
  const NostoContext = createContext({
4
5
  account: void 0,
5
- currentVariation: ""
6
+ currentVariation: "",
7
+ renderFunction: void 0
6
8
  });
7
9
  function useNostoContext() {
8
10
  const context = useContext(NostoContext);
@@ -47,17 +49,24 @@ const Fragment = jsxRuntime.exports.Fragment;
47
49
  const NostoFohofo = () => {
48
50
  const {
49
51
  clientScriptLoaded,
50
- currentVariation
52
+ currentVariation,
53
+ responseMode,
54
+ recommendationComponent,
55
+ useRenderCampaigns
51
56
  } = useNostoContext();
57
+ const {
58
+ renderCampaigns,
59
+ pageTypeUpdated
60
+ } = useRenderCampaigns("404");
52
61
  useEffect(() => {
53
- if (clientScriptLoaded) {
62
+ if (clientScriptLoaded && pageTypeUpdated) {
54
63
  window.nostojs((api) => {
55
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").viewNotFound().setPlacements(api.placements.getPlacements()).load().then((data) => {
56
- api.placements.injectCampaigns(data.recommendations);
64
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode).viewNotFound().setPlacements(api.placements.getPlacements()).load().then((data) => {
65
+ renderCampaigns(data, api);
57
66
  });
58
67
  });
59
68
  }
60
- }, [clientScriptLoaded, currentVariation]);
69
+ }, [clientScriptLoaded, currentVariation, recommendationComponent, pageTypeUpdated]);
61
70
  return /* @__PURE__ */ jsx(Fragment, {
62
71
  children: /* @__PURE__ */ jsx("div", {
63
72
  className: "nosto_page_type",
@@ -71,17 +80,24 @@ const NostoFohofo = () => {
71
80
  const NostoOther = () => {
72
81
  const {
73
82
  clientScriptLoaded,
74
- currentVariation
83
+ currentVariation,
84
+ responseMode,
85
+ recommendationComponent,
86
+ useRenderCampaigns
75
87
  } = useNostoContext();
88
+ const {
89
+ renderCampaigns,
90
+ pageTypeUpdated
91
+ } = useRenderCampaigns("other");
76
92
  useEffect(() => {
77
- if (clientScriptLoaded) {
93
+ if (clientScriptLoaded && pageTypeUpdated) {
78
94
  window.nostojs((api) => {
79
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").viewOther().setPlacements(api.placements.getPlacements()).load().then((data) => {
80
- api.placements.injectCampaigns(data.recommendations);
95
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode).viewOther().setPlacements(api.placements.getPlacements()).load().then((data) => {
96
+ renderCampaigns(data, api);
81
97
  });
82
98
  });
83
99
  }
84
- }, [clientScriptLoaded, currentVariation]);
100
+ }, [clientScriptLoaded, currentVariation, recommendationComponent, pageTypeUpdated]);
85
101
  return /* @__PURE__ */ jsx(Fragment, {
86
102
  children: /* @__PURE__ */ jsx("div", {
87
103
  className: "nosto_page_type",
@@ -95,17 +111,24 @@ const NostoOther = () => {
95
111
  const NostoCheckout = () => {
96
112
  const {
97
113
  clientScriptLoaded,
98
- currentVariation
114
+ currentVariation,
115
+ responseMode,
116
+ recommendationComponent,
117
+ useRenderCampaigns
99
118
  } = useNostoContext();
119
+ const {
120
+ renderCampaigns,
121
+ pageTypeUpdated
122
+ } = useRenderCampaigns("checkout");
100
123
  useEffect(() => {
101
- if (clientScriptLoaded) {
124
+ if (clientScriptLoaded && pageTypeUpdated) {
102
125
  window.nostojs((api) => {
103
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").viewCart().setPlacements(api.placements.getPlacements()).load().then((data) => {
104
- api.placements.injectCampaigns(data.recommendations);
126
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode).viewCart().setPlacements(api.placements.getPlacements()).load().then((data) => {
127
+ renderCampaigns(data, api);
105
128
  });
106
129
  });
107
130
  }
108
- }, [clientScriptLoaded, currentVariation]);
131
+ }, [clientScriptLoaded, currentVariation, recommendationComponent, pageTypeUpdated]);
109
132
  return /* @__PURE__ */ jsx(Fragment, {
110
133
  children: /* @__PURE__ */ jsx("div", {
111
134
  className: "nosto_page_type",
@@ -122,15 +145,22 @@ const NostoProduct = ({
122
145
  }) => {
123
146
  const {
124
147
  clientScriptLoaded,
125
- currentVariation
148
+ currentVariation,
149
+ responseMode,
150
+ recommendationComponent,
151
+ useRenderCampaigns
126
152
  } = useNostoContext();
153
+ const {
154
+ renderCampaigns,
155
+ pageTypeUpdated
156
+ } = useRenderCampaigns("product");
127
157
  useEffect(() => {
128
- if (clientScriptLoaded) {
158
+ if (clientScriptLoaded && pageTypeUpdated) {
129
159
  window.nostojs((api) => {
130
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").viewProduct(product).setPlacements(api.placements.getPlacements()).load().then((data) => {
131
- api.placements.injectCampaigns(data.recommendations);
160
+ api.defaultSession().setResponseMode(responseMode).viewProduct(product).setPlacements(api.placements.getPlacements()).load().then((data) => {
161
+ renderCampaigns(data, api);
132
162
  });
133
- }, [clientScriptLoaded, currentVariation, product]);
163
+ }, [clientScriptLoaded, currentVariation, product, recommendationComponent, pageTypeUpdated]);
134
164
  }
135
165
  });
136
166
  return /* @__PURE__ */ jsxs(Fragment, {
@@ -256,17 +286,24 @@ const NostoCategory = ({
256
286
  }) => {
257
287
  const {
258
288
  clientScriptLoaded,
259
- currentVariation
289
+ currentVariation,
290
+ responseMode,
291
+ recommendationComponent,
292
+ useRenderCampaigns
260
293
  } = useNostoContext();
294
+ const {
295
+ renderCampaigns,
296
+ pageTypeUpdated
297
+ } = useRenderCampaigns("home");
261
298
  useEffect(() => {
262
- if (clientScriptLoaded) {
299
+ if (clientScriptLoaded && pageTypeUpdated) {
263
300
  window.nostojs((api) => {
264
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").viewCategory(category).setPlacements(api.placements.getPlacements()).load().then((data) => {
265
- api.placements.injectCampaigns(data.recommendations);
301
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode).viewCategory(category).setPlacements(api.placements.getPlacements()).load().then((data) => {
302
+ renderCampaigns(data, api);
266
303
  });
267
304
  });
268
305
  }
269
- }, [clientScriptLoaded, category, currentVariation]);
306
+ }, [clientScriptLoaded, category, currentVariation, recommendationComponent, pageTypeUpdated]);
270
307
  return /* @__PURE__ */ jsxs(Fragment, {
271
308
  children: [/* @__PURE__ */ jsx("div", {
272
309
  className: "nosto_page_type",
@@ -288,17 +325,24 @@ const NostoSearch = ({
288
325
  }) => {
289
326
  const {
290
327
  clientScriptLoaded,
291
- currentVariation
328
+ currentVariation,
329
+ responseMode,
330
+ recommendationComponent,
331
+ useRenderCampaigns
292
332
  } = useNostoContext();
333
+ const {
334
+ renderCampaigns,
335
+ pageTypeUpdated
336
+ } = useRenderCampaigns("search");
293
337
  useEffect(() => {
294
- if (clientScriptLoaded) {
338
+ if (clientScriptLoaded && pageTypeUpdated) {
295
339
  window.nostojs((api) => {
296
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").viewSearch(query).setPlacements(api.placements.getPlacements()).load().then((data) => {
297
- api.placements.injectCampaigns(data.recommendations);
340
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode).viewSearch(query).setPlacements(api.placements.getPlacements()).load().then((data) => {
341
+ renderCampaigns(data, api);
298
342
  });
299
343
  });
300
344
  }
301
- }, [clientScriptLoaded, currentVariation, query]);
345
+ }, [clientScriptLoaded, currentVariation, query, recommendationComponent, pageTypeUpdated]);
302
346
  return /* @__PURE__ */ jsxs(Fragment, {
303
347
  children: [/* @__PURE__ */ jsx("div", {
304
348
  className: "nosto_page_type",
@@ -341,17 +385,24 @@ const NostoOrder = ({
341
385
  }) => {
342
386
  const {
343
387
  clientScriptLoaded,
344
- currentVariation
388
+ currentVariation,
389
+ responseMode,
390
+ recommendationComponent,
391
+ useRenderCampaigns
345
392
  } = useNostoContext();
393
+ const {
394
+ renderCampaigns,
395
+ pageTypeUpdated
396
+ } = useRenderCampaigns("order");
346
397
  useEffect(() => {
347
- if (clientScriptLoaded) {
398
+ if (clientScriptLoaded && pageTypeUpdated) {
348
399
  window.nostojs((api) => {
349
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").addOrder(snakeize(order)).setPlacements(api.placements.getPlacements()).load().then((data) => {
350
- api.placements.injectCampaigns(data.recommendations);
400
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode).addOrder(snakeize(order)).setPlacements(api.placements.getPlacements()).load().then((data) => {
401
+ renderCampaigns(data, api);
351
402
  });
352
403
  });
353
404
  }
354
- }, [clientScriptLoaded, currentVariation]);
405
+ }, [clientScriptLoaded, currentVariation, recommendationComponent, pageTypeUpdated]);
355
406
  return /* @__PURE__ */ jsxs(Fragment, {
356
407
  children: [/* @__PURE__ */ jsx("div", {
357
408
  className: "nosto_page_type",
@@ -371,20 +422,24 @@ const NostoOrder = ({
371
422
  const NostoHome = () => {
372
423
  const {
373
424
  clientScriptLoaded,
374
- currentVariation
425
+ currentVariation,
426
+ responseMode,
427
+ recommendationComponent,
428
+ useRenderCampaigns
375
429
  } = useNostoContext();
430
+ const {
431
+ renderCampaigns,
432
+ pageTypeUpdated
433
+ } = useRenderCampaigns("home");
376
434
  useEffect(() => {
377
- if (currentVariation) {
378
- console.log("currentVariation: ", currentVariation);
379
- }
380
- if (clientScriptLoaded) {
435
+ if (clientScriptLoaded && pageTypeUpdated) {
381
436
  window.nostojs((api) => {
382
- api.defaultSession().setVariation(currentVariation).setResponseMode("HTML").viewFrontPage().setPlacements(api.placements.getPlacements()).load().then((data) => {
383
- api.placements.injectCampaigns(data.recommendations);
437
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode).viewFrontPage().setPlacements(api.placements.getPlacements()).load().then((data) => {
438
+ renderCampaigns(data, api);
384
439
  });
385
440
  });
386
441
  }
387
- }, [clientScriptLoaded, currentVariation]);
442
+ }, [clientScriptLoaded, currentVariation, recommendationComponent, pageTypeUpdated]);
388
443
  return /* @__PURE__ */ jsx(Fragment, {
389
444
  children: /* @__PURE__ */ jsx("div", {
390
445
  className: "nosto_page_type",
@@ -396,23 +451,65 @@ const NostoHome = () => {
396
451
  });
397
452
  };
398
453
  const NostoPlacement = ({
399
- id
454
+ id,
455
+ pageType
400
456
  }) => {
401
457
  return /* @__PURE__ */ jsx("div", {
402
458
  className: "nosto_element",
403
459
  id
404
- });
460
+ }, id + pageType);
405
461
  };
406
462
  const NostoProvider = ({
407
463
  account,
408
464
  currentVariation = "",
409
465
  multiCurrency = false,
410
466
  host,
411
- children
467
+ children,
468
+ recommendationComponent
412
469
  }) => {
413
470
  const [clientScriptLoadedState, setClientScriptLoadedState] = React__default.useState(false);
414
471
  const clientScriptLoaded = React__default.useMemo(() => clientScriptLoadedState, [clientScriptLoadedState]);
415
472
  currentVariation = multiCurrency ? currentVariation : "";
473
+ const responseMode = isValidElement(recommendationComponent) ? "JSON_ORIGINAL" : "HTML";
474
+ function RecommendationComponentWrapper(props) {
475
+ return React__default.cloneElement(recommendationComponent, {
476
+ nostoRecommendation: props.nostoRecommendation
477
+ });
478
+ }
479
+ const [pageType, setPageType] = useState("");
480
+ const useRenderCampaigns = function(type = "") {
481
+ const placementRefs = useRef({});
482
+ useEffect(() => {
483
+ if (pageType != type) {
484
+ setPageType(type);
485
+ }
486
+ }, []);
487
+ const pageTypeUpdated = type == pageType;
488
+ function renderCampaigns(data, api) {
489
+ if (responseMode == "HTML") {
490
+ api.placements.injectCampaigns(data.recommendations);
491
+ } else {
492
+ const recommendations = data.campaigns.recommendations;
493
+ for (const key in recommendations) {
494
+ let recommendation = recommendations[key];
495
+ let placementSelector = "#" + key;
496
+ let placement = () => document.querySelector(placementSelector);
497
+ if (!!placement()) {
498
+ if (!placementRefs.current[key])
499
+ placementRefs.current[key] = createRoot(placement());
500
+ const root = placementRefs.current[key];
501
+ root.render(/* @__PURE__ */ jsx(RecommendationComponentWrapper, {
502
+ nostoRecommendation: recommendation
503
+ }));
504
+ }
505
+ }
506
+ }
507
+ }
508
+ return {
509
+ renderCampaigns,
510
+ pageTypeUpdated
511
+ };
512
+ };
416
513
  useEffect(() => {
417
514
  if (!document.querySelectorAll("[nosto-client-script]").length) {
418
515
  const script = document.createElement("script");
@@ -433,7 +530,11 @@ const NostoProvider = ({
433
530
  value: {
434
531
  account,
435
532
  clientScriptLoaded,
436
- currentVariation
533
+ currentVariation,
534
+ responseMode,
535
+ recommendationComponent,
536
+ useRenderCampaigns,
537
+ pageType
437
538
  },
438
539
  children
439
540
  });
@@ -1,4 +1,4 @@
1
- (function(l,i){typeof exports=="object"&&typeof module!="undefined"?i(exports,require("react")):typeof define=="function"&&define.amd?define(["exports","react"],i):(l=typeof globalThis!="undefined"?globalThis:l||self,i(l["@nosto/nosto-react"]={},l.React))})(this,function(l,i){"use strict";function L(t){return t&&typeof t=="object"&&"default"in t?t:{default:t}}function O(t){if(t&&t.__esModule)return t;var e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});return t&&Object.keys(t).forEach(function(n){if(n!=="default"){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r.get?r:{enumerable:!0,get:function(){return t[n]}})}}),e.default=t,Object.freeze(e)}var _=L(i),h=O(i);const v=i.createContext({account:void 0,currentVariation:""});function a(){const t=i.useContext(v);if(!t)throw new Error("No nosto context found");return t}var y={exports:{}},N={};/**
1
+ (function(m,p){typeof exports=="object"&&typeof module!="undefined"?p(exports,require("react"),require("react-dom/client")):typeof define=="function"&&define.amd?define(["exports","react","react-dom/client"],p):(m=typeof globalThis!="undefined"?globalThis:m||self,p(m["@nosto/nosto-react"]={},m.React,m.ReactDOM))})(this,function(m,p,A){"use strict";function D(t){return t&&typeof t=="object"&&"default"in t?t:{default:t}}function I(t){if(t&&t.__esModule)return t;var e=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});return t&&Object.keys(t).forEach(function(r){if(r!=="default"){var n=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,n.get?n:{enumerable:!0,get:function(){return t[r]}})}}),e.default=t,Object.freeze(e)}var w=D(p),S=I(p);const O=p.createContext({account:void 0,currentVariation:"",renderFunction:void 0});function h(){const t=p.useContext(O);if(!t)throw new Error("No nosto context found");return t}var P={exports:{}},j={};/**
2
2
  * @license React
3
3
  * react-jsx-runtime.production.min.js
4
4
  *
@@ -6,4 +6,4 @@
6
6
  *
7
7
  * This source code is licensed under the MIT license found in the
8
8
  * LICENSE file in the root directory of this source tree.
9
- */var M=_.default,E=Symbol.for("react.element"),V=Symbol.for("react.fragment"),T=Object.prototype.hasOwnProperty,F=M.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,x={key:!0,ref:!0,__self:!0,__source:!0};function j(t,e,n){var r,s={},c=null,d=null;n!==void 0&&(c=""+n),e.key!==void 0&&(c=""+e.key),e.ref!==void 0&&(d=e.ref);for(r in e)T.call(e,r)&&!x.hasOwnProperty(r)&&(s[r]=e[r]);if(t&&t.defaultProps)for(r in e=t.defaultProps,e)s[r]===void 0&&(s[r]=e[r]);return{$$typeof:E,type:t,key:c,ref:d,props:s,_owner:F.current}}N.Fragment=V,N.jsx=j,N.jsxs=j,y.exports=N;const o=y.exports.jsx,u=y.exports.jsxs,p=y.exports.Fragment,R=()=>{const{clientScriptLoaded:t,currentVariation:e}=a();return i.useEffect(()=>{t&&window.nostojs(n=>{n.defaultSession().setVariation(e).setResponseMode("HTML").viewNotFound().setPlacements(n.placements.getPlacements()).load().then(r=>{n.placements.injectCampaigns(r.recommendations)})})},[t,e]),o(p,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"notfound"})})},A=()=>{const{clientScriptLoaded:t,currentVariation:e}=a();return i.useEffect(()=>{t&&window.nostojs(n=>{n.defaultSession().setVariation(e).setResponseMode("HTML").viewOther().setPlacements(n.placements.getPlacements()).load().then(r=>{n.placements.injectCampaigns(r.recommendations)})})},[t,e]),o(p,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"other"})})},H=()=>{const{clientScriptLoaded:t,currentVariation:e}=a();return i.useEffect(()=>{t&&window.nostojs(n=>{n.defaultSession().setVariation(e).setResponseMode("HTML").viewCart().setPlacements(n.placements.getPlacements()).load().then(r=>{n.placements.injectCampaigns(r.recommendations)})})},[t,e]),o(p,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"cart"})})},D=({product:t,tagging:e})=>{const{clientScriptLoaded:n,currentVariation:r}=a();return i.useEffect(()=>{n&&window.nostojs(s=>{s.defaultSession().setVariation(r).setResponseMode("HTML").viewProduct(t).setPlacements(s.placements.getPlacements()).load().then(c=>{s.placements.injectCampaigns(c.recommendations)})},[n,r,t])}),u(p,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"product"}),u("div",{className:"nosto_product",style:{display:"none"},children:[(e==null?void 0:e.variationId)&&o("span",{className:"variation_id",children:e.variationId}),t&&o("span",{className:"product_id",children:t}),(e==null?void 0:e.name)&&o("span",{className:"name",children:e.name}),(e==null?void 0:e.url)&&o("span",{className:"url",children:e.url.toString()}),(e==null?void 0:e.imageUrl)&&o("span",{className:"image_url",children:e.imageUrl.toString()}),(e==null?void 0:e.availability)&&o("span",{className:"availability",children:e.availability}),(e==null?void 0:e.price)&&o("span",{className:"price",children:e.price}),(e==null?void 0:e.listPrice)&&o("span",{className:"list_price",children:e.listPrice}),(e==null?void 0:e.priceCurrencyCode)&&o("span",{className:"price_currency_code",children:e.priceCurrencyCode}),(e==null?void 0:e.brand)&&o("span",{className:"brand",children:e.brand}),(e==null?void 0:e.description)&&o("span",{className:"description",children:e.description}),(e==null?void 0:e.googleCategory)&&o("span",{className:"description",children:e.googleCategory}),(e==null?void 0:e.condition)&&o("span",{className:"condition",children:e.condition}),(e==null?void 0:e.gender)&&o("span",{className:"gender",children:e.gender}),(e==null?void 0:e.ageGroup)&&o("span",{className:"age_group",children:e.ageGroup}),(e==null?void 0:e.gtin)&&o("span",{className:"gtin",children:e.gtin}),(e==null?void 0:e.category)&&(e==null?void 0:e.category.map((s,c)=>o("span",{className:"category",children:s},c))),(e==null?void 0:e.tags1)&&e.tags1.map((s,c)=>o("span",{className:"tag1",children:s},c)),(e==null?void 0:e.tags2)&&e.tags2.map((s,c)=>o("span",{className:"tag2",children:s},c)),(e==null?void 0:e.tags3)&&e.tags3.map((s,c)=>o("span",{className:"tag3",children:s},c)),(e==null?void 0:e.ratingValue)&&o("span",{className:"rating_value",children:e.ratingValue}),(e==null?void 0:e.reviewCount)&&o("span",{className:"review_count",children:e.reviewCount}),(e==null?void 0:e.alternateImageUrls)&&e.alternateImageUrls.map((s,c)=>o("span",{className:"alternate_image_url",children:s.toString()},c)),(e==null?void 0:e.customFields)&&Object.keys(e.customFields).map((s,c)=>e.customFields&&e.customFields[s]&&o("span",{className:s,children:e.customFields[s]},c)),(e==null?void 0:e.skus)&&e.skus.map((s,c)=>u("span",{className:"nosto_sku",children:[(s==null?void 0:s.id)&&o("span",{className:"product_id",children:s.id}),(s==null?void 0:s.name)&&o("span",{className:"name",children:s.name}),(s==null?void 0:s.price)&&o("span",{className:"price",children:s.price}),(s==null?void 0:s.listPrice)&&o("span",{className:"list_price",children:s.listPrice}),(s==null?void 0:s.url)&&o("span",{className:"url",children:s.url.toString()}),(s==null?void 0:s.imageUrl)&&o("span",{className:"image_url",children:s.imageUrl.toString()}),(s==null?void 0:s.gtin)&&o("span",{className:"gtin",children:s.gtin}),(s==null?void 0:s.availability)&&o("span",{className:"availability",children:s.availability}),(s==null?void 0:s.customFields)&&Object.keys(s.customFields).map((d,S)=>s.customFields&&s.customFields[d]&&o("span",{className:d,children:s.customFields[d]},S))]},c))]})]})},U=({category:t})=>{const{clientScriptLoaded:e,currentVariation:n}=a();return i.useEffect(()=>{e&&window.nostojs(r=>{r.defaultSession().setVariation(n).setResponseMode("HTML").viewCategory(t).setPlacements(r.placements.getPlacements()).load().then(s=>{r.placements.injectCampaigns(s.recommendations)})})},[e,t,n]),u(p,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"category"}),o("div",{className:"nosto_category",style:{display:"none"},children:t})]})},b=({query:t})=>{const{clientScriptLoaded:e,currentVariation:n}=a();return i.useEffect(()=>{e&&window.nostojs(r=>{r.defaultSession().setVariation(n).setResponseMode("HTML").viewSearch(t).setPlacements(r.placements.getPlacements()).load().then(s=>{r.placements.injectCampaigns(s.recommendations)})})},[e,n,t]),u(p,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"search"}),o("div",{className:"nosto_search",style:{display:"none"},children:t})]})};var w=function t(e){return!e||typeof e!="object"||I(e)||z(e)?e:Array.isArray(e)?e.map(t):Object.keys(e).reduce(function(n,r){var s=r[0].toLowerCase()+r.slice(1).replace(/([A-Z]+)/g,function(c,d){return"_"+d.toLowerCase()});return n[s]=t(e[r]),n},{})},I=function(t){return Object.prototype.toString.call(t)==="[object Date]"},z=function(t){return Object.prototype.toString.call(t)==="[object RegExp]"};const q=({order:t})=>{const{clientScriptLoaded:e,currentVariation:n}=a();return i.useEffect(()=>{e&&window.nostojs(r=>{r.defaultSession().setVariation(n).setResponseMode("HTML").addOrder(w(t)).setPlacements(r.placements.getPlacements()).load().then(s=>{r.placements.injectCampaigns(s.recommendations)})})},[e,n]),u(p,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"order"}),o("div",{className:"nosto_order",style:{display:"none"},children:t.purchase.number})]})},B=()=>{const{clientScriptLoaded:t,currentVariation:e}=a();return i.useEffect(()=>{e&&console.log("currentVariation: ",e),t&&window.nostojs(n=>{n.defaultSession().setVariation(e).setResponseMode("HTML").viewFrontPage().setPlacements(n.placements.getPlacements()).load().then(r=>{n.placements.injectCampaigns(r.recommendations)})})},[t,e]),o(p,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"front"})})},G=({id:t})=>o("div",{className:"nosto_element",id:t}),$=({account:t,currentVariation:e="",multiCurrency:n=!1,host:r,children:s})=>{const[c,d]=_.default.useState(!1),S=_.default.useMemo(()=>c,[c]);return e=n?e:"",i.useEffect(()=>{if(!document.querySelectorAll("[nosto-client-script]").length){const m=document.createElement("script");m.type="text/javascript",m.src="//"+(r||"connect.nosto.com")+"/include/"+t,m.async=!0,m.setAttribute("nosto-client-script",""),m.onload=()=>{console.log("Nosto client script loaded"),d(!0)},document.head.appendChild(m)}window.nostojs=m=>(window.nostojs.q=window.nostojs.q||[]).push(m),window.nostojs(m=>m.setAutoLoad(!1))},[]),o(v.Provider,{value:{account:t,clientScriptLoaded:S,currentVariation:e},children:s})};var C=Object.prototype.hasOwnProperty;function P(t,e,n){for(n of t.keys())if(f(n,e))return n}function f(t,e){var n,r,s;if(t===e)return!0;if(t&&e&&(n=t.constructor)===e.constructor){if(n===Date)return t.getTime()===e.getTime();if(n===RegExp)return t.toString()===e.toString();if(n===Array){if((r=t.length)===e.length)for(;r--&&f(t[r],e[r]););return r===-1}if(n===Set){if(t.size!==e.size)return!1;for(r of t)if(s=r,s&&typeof s=="object"&&(s=P(e,s),!s)||!e.has(s))return!1;return!0}if(n===Map){if(t.size!==e.size)return!1;for(r of t)if(s=r[0],s&&typeof s=="object"&&(s=P(e,s),!s)||!f(r[1],e.get(s)))return!1;return!0}if(n===ArrayBuffer)t=new Uint8Array(t),e=new Uint8Array(e);else if(n===DataView){if((r=t.byteLength)===e.byteLength)for(;r--&&t.getInt8(r)===e.getInt8(r););return r===-1}if(ArrayBuffer.isView(t)){if((r=t.byteLength)===e.byteLength)for(;r--&&t[r]===e[r];);return r===-1}if(!n||typeof t=="object"){r=0;for(n in t)if(C.call(t,n)&&++r&&!C.call(e,n)||!(n in e)||!f(t[n],e[n]))return!1;return Object.keys(e).length===r}}return t!==t&&e!==e}function J(t){var e=h.useRef(t),n=h.useRef(0);return f(t,e.current)||(e.current=t,n.current+=1),h.useMemo(function(){return e.current},[n.current])}function W(t,e){return h.useEffect(t,J(e))}const Y=({cart:t,customer:e})=>{const{clientScriptLoaded:n}=a();return W(()=>{const r=t?w(t):void 0,s=e?w(e):void 0;n&&window.nostojs(c=>{c.defaultSession().setResponseMode("HTML").setCart(r).setCustomer(s).viewOther().load()})},[n,t||[],e||{}]),o(p,{})};l.Nosto404=R,l.NostoCategory=U,l.NostoCheckout=H,l.NostoContext=v,l.NostoHome=B,l.NostoOrder=q,l.NostoOther=A,l.NostoPlacement=G,l.NostoProduct=D,l.NostoProvider=$,l.NostoSearch=b,l.NostoSession=Y,l.useNostoContext=a,Object.defineProperties(l,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
9
+ */var b=w.default,z=Symbol.for("react.element"),q=Symbol.for("react.fragment"),H=Object.prototype.hasOwnProperty,B=b.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,G={key:!0,ref:!0,__self:!0,__source:!0};function E(t,e,r){var n,c={},a=null,d=null;r!==void 0&&(a=""+r),e.key!==void 0&&(a=""+e.key),e.ref!==void 0&&(d=e.ref);for(n in e)H.call(e,n)&&!G.hasOwnProperty(n)&&(c[n]=e[n]);if(t&&t.defaultProps)for(n in e=t.defaultProps,e)c[n]===void 0&&(c[n]=e[n]);return{$$typeof:z,type:t,key:a,ref:d,props:c,_owner:B.current}}j.Fragment=q,j.jsx=E,j.jsxs=E,P.exports=j;const o=P.exports.jsx,_=P.exports.jsxs,y=P.exports.Fragment,J=()=>{const{clientScriptLoaded:t,currentVariation:e,responseMode:r,recommendationComponent:n,useRenderCampaigns:c}=h(),{renderCampaigns:a,pageTypeUpdated:d}=c("404");return p.useEffect(()=>{t&&d&&window.nostojs(l=>{l.defaultSession().setVariation(e).setResponseMode(r).viewNotFound().setPlacements(l.placements.getPlacements()).load().then(i=>{a(i,l)})})},[t,e,n,d]),o(y,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"notfound"})})},W=()=>{const{clientScriptLoaded:t,currentVariation:e,responseMode:r,recommendationComponent:n,useRenderCampaigns:c}=h(),{renderCampaigns:a,pageTypeUpdated:d}=c("other");return p.useEffect(()=>{t&&d&&window.nostojs(l=>{l.defaultSession().setVariation(e).setResponseMode(r).viewOther().setPlacements(l.placements.getPlacements()).load().then(i=>{a(i,l)})})},[t,e,n,d]),o(y,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"other"})})},$=()=>{const{clientScriptLoaded:t,currentVariation:e,responseMode:r,recommendationComponent:n,useRenderCampaigns:c}=h(),{renderCampaigns:a,pageTypeUpdated:d}=c("checkout");return p.useEffect(()=>{t&&d&&window.nostojs(l=>{l.defaultSession().setVariation(e).setResponseMode(r).viewCart().setPlacements(l.placements.getPlacements()).load().then(i=>{a(i,l)})})},[t,e,n,d]),o(y,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"cart"})})},Y=({product:t,tagging:e})=>{const{clientScriptLoaded:r,currentVariation:n,responseMode:c,recommendationComponent:a,useRenderCampaigns:d}=h(),{renderCampaigns:l,pageTypeUpdated:i}=d("product");return p.useEffect(()=>{r&&i&&window.nostojs(s=>{s.defaultSession().setResponseMode(c).viewProduct(t).setPlacements(s.placements.getPlacements()).load().then(u=>{l(u,s)})},[r,n,t,a,i])}),_(y,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"product"}),_("div",{className:"nosto_product",style:{display:"none"},children:[(e==null?void 0:e.variationId)&&o("span",{className:"variation_id",children:e.variationId}),t&&o("span",{className:"product_id",children:t}),(e==null?void 0:e.name)&&o("span",{className:"name",children:e.name}),(e==null?void 0:e.url)&&o("span",{className:"url",children:e.url.toString()}),(e==null?void 0:e.imageUrl)&&o("span",{className:"image_url",children:e.imageUrl.toString()}),(e==null?void 0:e.availability)&&o("span",{className:"availability",children:e.availability}),(e==null?void 0:e.price)&&o("span",{className:"price",children:e.price}),(e==null?void 0:e.listPrice)&&o("span",{className:"list_price",children:e.listPrice}),(e==null?void 0:e.priceCurrencyCode)&&o("span",{className:"price_currency_code",children:e.priceCurrencyCode}),(e==null?void 0:e.brand)&&o("span",{className:"brand",children:e.brand}),(e==null?void 0:e.description)&&o("span",{className:"description",children:e.description}),(e==null?void 0:e.googleCategory)&&o("span",{className:"description",children:e.googleCategory}),(e==null?void 0:e.condition)&&o("span",{className:"condition",children:e.condition}),(e==null?void 0:e.gender)&&o("span",{className:"gender",children:e.gender}),(e==null?void 0:e.ageGroup)&&o("span",{className:"age_group",children:e.ageGroup}),(e==null?void 0:e.gtin)&&o("span",{className:"gtin",children:e.gtin}),(e==null?void 0:e.category)&&(e==null?void 0:e.category.map((s,u)=>o("span",{className:"category",children:s},u))),(e==null?void 0:e.tags1)&&e.tags1.map((s,u)=>o("span",{className:"tag1",children:s},u)),(e==null?void 0:e.tags2)&&e.tags2.map((s,u)=>o("span",{className:"tag2",children:s},u)),(e==null?void 0:e.tags3)&&e.tags3.map((s,u)=>o("span",{className:"tag3",children:s},u)),(e==null?void 0:e.ratingValue)&&o("span",{className:"rating_value",children:e.ratingValue}),(e==null?void 0:e.reviewCount)&&o("span",{className:"review_count",children:e.reviewCount}),(e==null?void 0:e.alternateImageUrls)&&e.alternateImageUrls.map((s,u)=>o("span",{className:"alternate_image_url",children:s.toString()},u)),(e==null?void 0:e.customFields)&&Object.keys(e.customFields).map((s,u)=>e.customFields&&e.customFields[s]&&o("span",{className:s,children:e.customFields[s]},u)),(e==null?void 0:e.skus)&&e.skus.map((s,u)=>_("span",{className:"nosto_sku",children:[(s==null?void 0:s.id)&&o("span",{className:"product_id",children:s.id}),(s==null?void 0:s.name)&&o("span",{className:"name",children:s.name}),(s==null?void 0:s.price)&&o("span",{className:"price",children:s.price}),(s==null?void 0:s.listPrice)&&o("span",{className:"list_price",children:s.listPrice}),(s==null?void 0:s.url)&&o("span",{className:"url",children:s.url.toString()}),(s==null?void 0:s.imageUrl)&&o("span",{className:"image_url",children:s.imageUrl.toString()}),(s==null?void 0:s.gtin)&&o("span",{className:"gtin",children:s.gtin}),(s==null?void 0:s.availability)&&o("span",{className:"availability",children:s.availability}),(s==null?void 0:s.customFields)&&Object.keys(s.customFields).map((N,L)=>s.customFields&&s.customFields[N]&&o("span",{className:N,children:s.customFields[N]},L))]},u))]})]})},Z=({category:t})=>{const{clientScriptLoaded:e,currentVariation:r,responseMode:n,recommendationComponent:c,useRenderCampaigns:a}=h(),{renderCampaigns:d,pageTypeUpdated:l}=a("home");return p.useEffect(()=>{e&&l&&window.nostojs(i=>{i.defaultSession().setVariation(r).setResponseMode(n).viewCategory(t).setPlacements(i.placements.getPlacements()).load().then(s=>{d(s,i)})})},[e,t,r,c,l]),_(y,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"category"}),o("div",{className:"nosto_category",style:{display:"none"},children:t})]})},K=({query:t})=>{const{clientScriptLoaded:e,currentVariation:r,responseMode:n,recommendationComponent:c,useRenderCampaigns:a}=h(),{renderCampaigns:d,pageTypeUpdated:l}=a("search");return p.useEffect(()=>{e&&l&&window.nostojs(i=>{i.defaultSession().setVariation(r).setResponseMode(n).viewSearch(t).setPlacements(i.placements.getPlacements()).load().then(s=>{d(s,i)})})},[e,r,t,c,l]),_(y,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"search"}),o("div",{className:"nosto_search",style:{display:"none"},children:t})]})};var M=function t(e){return!e||typeof e!="object"||Q(e)||X(e)?e:Array.isArray(e)?e.map(t):Object.keys(e).reduce(function(r,n){var c=n[0].toLowerCase()+n.slice(1).replace(/([A-Z]+)/g,function(a,d){return"_"+d.toLowerCase()});return r[c]=t(e[n]),r},{})},Q=function(t){return Object.prototype.toString.call(t)==="[object Date]"},X=function(t){return Object.prototype.toString.call(t)==="[object RegExp]"};const k=({order:t})=>{const{clientScriptLoaded:e,currentVariation:r,responseMode:n,recommendationComponent:c,useRenderCampaigns:a}=h(),{renderCampaigns:d,pageTypeUpdated:l}=a("order");return p.useEffect(()=>{e&&l&&window.nostojs(i=>{i.defaultSession().setVariation(r).setResponseMode(n).addOrder(M(t)).setPlacements(i.placements.getPlacements()).load().then(s=>{d(s,i)})})},[e,r,c,l]),_(y,{children:[o("div",{className:"nosto_page_type",style:{display:"none"},children:"order"}),o("div",{className:"nosto_order",style:{display:"none"},children:t.purchase.number})]})},g=()=>{const{clientScriptLoaded:t,currentVariation:e,responseMode:r,recommendationComponent:n,useRenderCampaigns:c}=h(),{renderCampaigns:a,pageTypeUpdated:d}=c("home");return p.useEffect(()=>{t&&d&&window.nostojs(l=>{l.defaultSession().setVariation(e).setResponseMode(r).viewFrontPage().setPlacements(l.placements.getPlacements()).load().then(i=>{a(i,l)})})},[t,e,n,d]),o(y,{children:o("div",{className:"nosto_page_type",style:{display:"none"},children:"front"})})},ee=({id:t,pageType:e})=>o("div",{className:"nosto_element",id:t},t+e),te=({account:t,currentVariation:e="",multiCurrency:r=!1,host:n,children:c,recommendationComponent:a})=>{const[d,l]=w.default.useState(!1),i=w.default.useMemo(()=>d,[d]);e=r?e:"";const s=p.isValidElement(a)?"JSON_ORIGINAL":"HTML";function u(f){return w.default.cloneElement(a,{nostoRecommendation:f.nostoRecommendation})}const[N,L]=p.useState(""),oe=function(f=""){const R=p.useRef({});p.useEffect(()=>{N!=f&&L(f)},[]);const ce=f==N;function le(V,de){if(s=="HTML")de.placements.injectCampaigns(V.recommendations);else{const F=V.campaigns.recommendations;for(const C in F){let ae=F[C],ie="#"+C,x=()=>document.querySelector(ie);x()&&(R.current[C]||(R.current[C]=A.createRoot(x())),R.current[C].render(o(u,{nostoRecommendation:ae})))}}}return{renderCampaigns:le,pageTypeUpdated:ce}};return p.useEffect(()=>{if(!document.querySelectorAll("[nosto-client-script]").length){const f=document.createElement("script");f.type="text/javascript",f.src="//"+(n||"connect.nosto.com")+"/include/"+t,f.async=!0,f.setAttribute("nosto-client-script",""),f.onload=()=>{console.log("Nosto client script loaded"),l(!0)},document.head.appendChild(f)}window.nostojs=f=>(window.nostojs.q=window.nostojs.q||[]).push(f),window.nostojs(f=>f.setAutoLoad(!1))},[]),o(O.Provider,{value:{account:t,clientScriptLoaded:i,currentVariation:e,responseMode:s,recommendationComponent:a,useRenderCampaigns:oe,pageType:N},children:c})};var T=Object.prototype.hasOwnProperty;function U(t,e,r){for(r of t.keys())if(v(r,e))return r}function v(t,e){var r,n,c;if(t===e)return!0;if(t&&e&&(r=t.constructor)===e.constructor){if(r===Date)return t.getTime()===e.getTime();if(r===RegExp)return t.toString()===e.toString();if(r===Array){if((n=t.length)===e.length)for(;n--&&v(t[n],e[n]););return n===-1}if(r===Set){if(t.size!==e.size)return!1;for(n of t)if(c=n,c&&typeof c=="object"&&(c=U(e,c),!c)||!e.has(c))return!1;return!0}if(r===Map){if(t.size!==e.size)return!1;for(n of t)if(c=n[0],c&&typeof c=="object"&&(c=U(e,c),!c)||!v(n[1],e.get(c)))return!1;return!0}if(r===ArrayBuffer)t=new Uint8Array(t),e=new Uint8Array(e);else if(r===DataView){if((n=t.byteLength)===e.byteLength)for(;n--&&t.getInt8(n)===e.getInt8(n););return n===-1}if(ArrayBuffer.isView(t)){if((n=t.byteLength)===e.byteLength)for(;n--&&t[n]===e[n];);return n===-1}if(!r||typeof t=="object"){n=0;for(r in t)if(T.call(t,r)&&++n&&!T.call(e,r)||!(r in e)||!v(t[r],e[r]))return!1;return Object.keys(e).length===n}}return t!==t&&e!==e}function se(t){var e=S.useRef(t),r=S.useRef(0);return v(t,e.current)||(e.current=t,r.current+=1),S.useMemo(function(){return e.current},[r.current])}function ne(t,e){return S.useEffect(t,se(e))}const re=({cart:t,customer:e})=>{const{clientScriptLoaded:r}=h();return ne(()=>{const n=t?M(t):void 0,c=e?M(e):void 0;r&&window.nostojs(a=>{a.defaultSession().setResponseMode("HTML").setCart(n).setCustomer(c).viewOther().load()})},[r,t||[],e||{}]),o(y,{})};m.Nosto404=J,m.NostoCategory=Z,m.NostoCheckout=$,m.NostoContext=O,m.NostoHome=g,m.NostoOrder=k,m.NostoOther=W,m.NostoPlacement=ee,m.NostoProduct=Y,m.NostoProvider=te,m.NostoSearch=K,m.NostoSession=re,m.useNostoContext=h,Object.defineProperties(m,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@nosto/nosto-react",
3
3
  "description": "Component library to simply implementing Nosto on React.",
4
- "version": "0.2.0",
4
+ "version": "0.3.0",
5
5
  "author": "Mridang Agarwalla, Dominik Gilg",
6
6
  "license": "ISC",
7
7
  "repository": {
@@ -2,25 +2,39 @@ import React, { useEffect } from "react";
2
2
  import { useNostoContext } from "../Provider/context.client";
3
3
 
4
4
  const NostoCategory: React.FC<{ category: string }> = ({ category }) => {
5
- const { clientScriptLoaded, currentVariation } = useNostoContext();
5
+ const {
6
+ clientScriptLoaded,
7
+ currentVariation,
8
+ responseMode,
9
+ recommendationComponent,
10
+ useRenderCampaigns,
11
+ } = useNostoContext();
12
+
13
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("home");
14
+
6
15
  useEffect(() => {
7
16
  // @ts-ignore
8
- if (clientScriptLoaded) {
17
+ if (clientScriptLoaded && pageTypeUpdated) {
9
18
  window.nostojs((api: any) => {
10
19
  api
11
20
  .defaultSession()
12
21
  .setVariation(currentVariation)
13
- .setResponseMode("HTML")
22
+ .setResponseMode(responseMode)
14
23
  .viewCategory(category)
15
24
  .setPlacements(api.placements.getPlacements())
16
25
  .load()
17
26
  .then((data: object) => {
18
- // @ts-ignore
19
- api.placements.injectCampaigns(data.recommendations);
27
+ renderCampaigns(data, api);
20
28
  });
21
29
  });
22
30
  }
23
- }, [clientScriptLoaded, category, currentVariation]);
31
+ }, [
32
+ clientScriptLoaded,
33
+ category,
34
+ currentVariation,
35
+ recommendationComponent,
36
+ pageTypeUpdated,
37
+ ]);
24
38
 
25
39
  return (
26
40
  <>
@@ -2,25 +2,38 @@ import React, { useEffect } from "react";
2
2
  import { useNostoContext } from "../Provider/context.client";
3
3
 
4
4
  const NostoCheckout: React.FC = () => {
5
- const { clientScriptLoaded, currentVariation } = useNostoContext();
5
+ const {
6
+ clientScriptLoaded,
7
+ currentVariation,
8
+ responseMode,
9
+ recommendationComponent,
10
+ useRenderCampaigns,
11
+ } = useNostoContext();
12
+
13
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("checkout");
14
+
6
15
  useEffect(() => {
7
16
  // @ts-ignore
8
- if (clientScriptLoaded) {
17
+ if (clientScriptLoaded && pageTypeUpdated) {
9
18
  window.nostojs((api: any) => {
10
19
  api
11
20
  .defaultSession()
12
21
  .setVariation(currentVariation)
13
- .setResponseMode("HTML")
22
+ .setResponseMode(responseMode)
14
23
  .viewCart()
15
24
  .setPlacements(api.placements.getPlacements())
16
25
  .load()
17
26
  .then((data: object) => {
18
- // @ts-ignore
19
- api.placements.injectCampaigns(data.recommendations);
27
+ renderCampaigns(data, api);
20
28
  });
21
29
  });
22
30
  }
23
- }, [clientScriptLoaded, currentVariation]);
31
+ }, [
32
+ clientScriptLoaded,
33
+ currentVariation,
34
+ recommendationComponent,
35
+ pageTypeUpdated,
36
+ ]);
24
37
 
25
38
  return (
26
39
  <>
@@ -2,25 +2,38 @@ import React, { useEffect } from "react";
2
2
  import { useNostoContext } from "../Provider/context.client";
3
3
 
4
4
  const NostoFohofo: React.FC = () => {
5
- const { clientScriptLoaded, currentVariation } = useNostoContext();
5
+ const {
6
+ clientScriptLoaded,
7
+ currentVariation,
8
+ responseMode,
9
+ recommendationComponent,
10
+ useRenderCampaigns,
11
+ } = useNostoContext();
12
+
13
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("404");
14
+
6
15
  useEffect(() => {
7
16
  // @ts-ignore
8
- if (clientScriptLoaded) {
17
+ if (clientScriptLoaded && pageTypeUpdated) {
9
18
  window.nostojs((api: any) => {
10
19
  api
11
20
  .defaultSession()
12
21
  .setVariation(currentVariation)
13
- .setResponseMode("HTML")
22
+ .setResponseMode(responseMode)
14
23
  .viewNotFound()
15
24
  .setPlacements(api.placements.getPlacements())
16
25
  .load()
17
26
  .then((data: object) => {
18
- // @ts-ignore
19
- api.placements.injectCampaigns(data.recommendations);
27
+ renderCampaigns(data, api);
20
28
  });
21
29
  });
22
30
  }
23
- }, [clientScriptLoaded, currentVariation]);
31
+ }, [
32
+ clientScriptLoaded,
33
+ currentVariation,
34
+ recommendationComponent,
35
+ pageTypeUpdated,
36
+ ]);
24
37
 
25
38
  return (
26
39
  <>
@@ -2,28 +2,38 @@ import React, { useEffect } from "react";
2
2
  import { useNostoContext } from "../Provider/context.client";
3
3
 
4
4
  const NostoHome: React.FC = () => {
5
- const { clientScriptLoaded, currentVariation } = useNostoContext();
5
+ const {
6
+ clientScriptLoaded,
7
+ currentVariation,
8
+ responseMode,
9
+ recommendationComponent,
10
+ useRenderCampaigns,
11
+ } = useNostoContext();
12
+
13
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("home");
14
+
6
15
  useEffect(() => {
7
- if (currentVariation) {
8
- console.log("currentVariation: ", currentVariation);
9
- }
10
16
  // @ts-ignore
11
- if (clientScriptLoaded) {
17
+ if (clientScriptLoaded && pageTypeUpdated) {
12
18
  window.nostojs((api: any) => {
13
19
  api
14
20
  .defaultSession()
15
21
  .setVariation(currentVariation)
16
- .setResponseMode("HTML")
22
+ .setResponseMode(responseMode)
17
23
  .viewFrontPage()
18
24
  .setPlacements(api.placements.getPlacements())
19
25
  .load()
20
26
  .then((data: object) => {
21
- // @ts-ignore
22
- api.placements.injectCampaigns(data.recommendations);
27
+ renderCampaigns(data, api);
23
28
  });
24
29
  });
25
30
  }
26
- }, [clientScriptLoaded, currentVariation]);
31
+ }, [
32
+ clientScriptLoaded,
33
+ currentVariation,
34
+ recommendationComponent,
35
+ pageTypeUpdated,
36
+ ]);
27
37
 
28
38
  return (
29
39
  <>
@@ -8,25 +8,38 @@ export interface OrderProps {
8
8
  }
9
9
 
10
10
  const NostoOrder: React.FC<{ order: OrderProps }> = ({ order }) => {
11
- const { clientScriptLoaded, currentVariation } = useNostoContext();
11
+ const {
12
+ clientScriptLoaded,
13
+ currentVariation,
14
+ responseMode,
15
+ recommendationComponent,
16
+ useRenderCampaigns,
17
+ } = useNostoContext();
18
+
19
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("order");
20
+
12
21
  useEffect(() => {
13
22
  // @ts-ignore
14
- if (clientScriptLoaded) {
23
+ if (clientScriptLoaded && pageTypeUpdated) {
15
24
  window.nostojs((api: any) => {
16
25
  api
17
26
  .defaultSession()
18
27
  .setVariation(currentVariation)
19
- .setResponseMode("HTML")
28
+ .setResponseMode(responseMode)
20
29
  .addOrder(snakeize(order))
21
30
  .setPlacements(api.placements.getPlacements())
22
31
  .load()
23
32
  .then((data: object) => {
24
- // @ts-ignore
25
- api.placements.injectCampaigns(data.recommendations);
33
+ renderCampaigns(data, api);
26
34
  });
27
35
  });
28
36
  }
29
- }, [clientScriptLoaded, currentVariation]);
37
+ }, [
38
+ clientScriptLoaded,
39
+ currentVariation,
40
+ recommendationComponent,
41
+ pageTypeUpdated,
42
+ ]);
30
43
 
31
44
  return (
32
45
  <>
@@ -2,25 +2,38 @@ import React, { useEffect } from "react";
2
2
  import { useNostoContext } from "../Provider/context.client";
3
3
 
4
4
  const NostoOther: React.FC = () => {
5
- const { clientScriptLoaded, currentVariation } = useNostoContext();
5
+ const {
6
+ clientScriptLoaded,
7
+ currentVariation,
8
+ responseMode,
9
+ recommendationComponent,
10
+ useRenderCampaigns,
11
+ } = useNostoContext();
12
+
13
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("other");
14
+
6
15
  useEffect(() => {
7
16
  // @ts-ignore
8
- if (clientScriptLoaded) {
17
+ if (clientScriptLoaded && pageTypeUpdated) {
9
18
  window.nostojs((api: any) => {
10
19
  api
11
20
  .defaultSession()
12
21
  .setVariation(currentVariation)
13
- .setResponseMode("HTML")
22
+ .setResponseMode(responseMode)
14
23
  .viewOther()
15
24
  .setPlacements(api.placements.getPlacements())
16
25
  .load()
17
26
  .then((data: object) => {
18
- // @ts-ignore
19
- api.placements.injectCampaigns(data.recommendations);
27
+ renderCampaigns(data, api);
20
28
  });
21
29
  });
22
30
  }
23
- }, [clientScriptLoaded, currentVariation]);
31
+ }, [
32
+ clientScriptLoaded,
33
+ currentVariation,
34
+ recommendationComponent,
35
+ pageTypeUpdated,
36
+ ]);
24
37
 
25
38
  return (
26
39
  <>
@@ -2,10 +2,11 @@ import React from "react";
2
2
 
3
3
  export interface PlacementProps {
4
4
  id: string;
5
+ pageType: string;
5
6
  }
6
7
 
7
- const NostoPlacement: React.FC<PlacementProps> = ({ id }) => {
8
- return <div className="nosto_element" id={id} />;
8
+ const NostoPlacement: React.FC<PlacementProps> = ({ id, pageType }) => {
9
+ return <div className="nosto_element" id={id} key={id + pageType} />;
9
10
  };
10
11
 
11
12
  export default NostoPlacement;
@@ -6,25 +6,38 @@ const NostoProduct: React.FC<{ product: string; tagging: Product }> = ({
6
6
  product,
7
7
  tagging,
8
8
  }) => {
9
- const { clientScriptLoaded, currentVariation } = useNostoContext();
9
+ const {
10
+ clientScriptLoaded,
11
+ currentVariation,
12
+ responseMode,
13
+ recommendationComponent,
14
+ useRenderCampaigns,
15
+ } = useNostoContext();
16
+
17
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("product");
18
+
10
19
  useEffect(() => {
11
20
  // @ts-ignore
12
- if (clientScriptLoaded) {
21
+ if (clientScriptLoaded && pageTypeUpdated) {
13
22
  window.nostojs(
14
23
  (api: any) => {
15
24
  api
16
25
  .defaultSession()
17
- .setVariation(currentVariation)
18
- .setResponseMode("HTML")
26
+ .setResponseMode(responseMode)
19
27
  .viewProduct(product)
20
28
  .setPlacements(api.placements.getPlacements())
21
29
  .load()
22
30
  .then((data: object) => {
23
- // @ts-ignore
24
- api.placements.injectCampaigns(data.recommendations);
31
+ renderCampaigns(data, api);
25
32
  });
26
33
  },
27
- [clientScriptLoaded, currentVariation, product]
34
+ [
35
+ clientScriptLoaded,
36
+ currentVariation,
37
+ product,
38
+ recommendationComponent,
39
+ pageTypeUpdated,
40
+ ]
28
41
  );
29
42
  }
30
43
  });
@@ -1,9 +1,14 @@
1
- import { createContext, useContext } from "react";
1
+ import { createContext, useContext, ReactComponentElement } from "react";
2
2
 
3
3
  export interface NostoInterface {
4
4
  account: string;
5
5
  clientScriptLoaded: boolean;
6
6
  currentVariation: string;
7
+ renderFunction?: Function;
8
+ responseMode: string;
9
+ recommendationComponent?: any;
10
+ useRenderCampaigns: Function;
11
+ pageType: string;
7
12
  }
8
13
 
9
14
  /* tslint:disable:no-empty */
@@ -11,6 +16,7 @@ export const NostoContext = createContext<NostoInterface>({
11
16
  // @ts-ignore
12
17
  account: undefined,
13
18
  currentVariation: "",
19
+ renderFunction: undefined,
14
20
  });
15
21
 
16
22
  /* tslint:enable:no-empty */
@@ -1,5 +1,6 @@
1
- import React, { useEffect } from "react";
1
+ import React, { useEffect, isValidElement, useState, useRef } from "react";
2
2
  import { NostoContext } from "./context.client";
3
+ import { createRoot } from "react-dom/client";
3
4
 
4
5
  interface NostoProviderProps {
5
6
  account: string;
@@ -7,6 +8,7 @@ interface NostoProviderProps {
7
8
  host: string;
8
9
  children: React.ReactElement;
9
10
  multiCurrency: boolean;
11
+ recommendationComponent?: any;
10
12
  }
11
13
 
12
14
  const NostoProvider: React.FC<NostoProviderProps> = ({
@@ -15,6 +17,7 @@ const NostoProvider: React.FC<NostoProviderProps> = ({
15
17
  multiCurrency = false,
16
18
  host,
17
19
  children,
20
+ recommendationComponent,
18
21
  }) => {
19
22
  const [clientScriptLoadedState, setClientScriptLoadedState] =
20
23
  React.useState(false);
@@ -26,6 +29,58 @@ const NostoProvider: React.FC<NostoProviderProps> = ({
26
29
  //Pass currentVariation as empty string if multiCurrency is disabled
27
30
  currentVariation = multiCurrency ? currentVariation : "";
28
31
 
32
+ // Set responseMode for loading campaigns:
33
+ const responseMode = isValidElement(recommendationComponent)
34
+ ? "JSON_ORIGINAL"
35
+ : "HTML";
36
+
37
+ // RecommendationComponent for client-side rendering:
38
+ function RecommendationComponentWrapper(props: any) {
39
+ return React.cloneElement(recommendationComponent, {
40
+ nostoRecommendation: props.nostoRecommendation,
41
+ });
42
+ }
43
+
44
+ // custom hook for rendering campaigns (CSR/SSR):
45
+ const [pageType, setPageType] = useState("");
46
+ const useRenderCampaigns: any = function (type: string = "") {
47
+ const placementRefs: any = useRef({});
48
+ useEffect(() => {
49
+ if (pageType != type) {
50
+ setPageType(type);
51
+ }
52
+ }, []);
53
+
54
+ const pageTypeUpdated = type == pageType;
55
+
56
+ function renderCampaigns(data: any, api: any) {
57
+ if (responseMode == "HTML") {
58
+ // inject content campaigns as usual:
59
+ api.placements.injectCampaigns(data.recommendations);
60
+ } else {
61
+ // render recommendation component into placements:
62
+ const recommendations = data.campaigns.recommendations;
63
+ for (const key in recommendations) {
64
+ let recommendation = recommendations[key];
65
+ let placementSelector = "#" + key;
66
+ let placement: Function = () =>
67
+ document.querySelector(placementSelector);
68
+ if (!!placement()) {
69
+ if (!placementRefs.current[key])
70
+ placementRefs.current[key] = createRoot(placement());
71
+ const root = placementRefs.current[key];
72
+ root.render(
73
+ <RecommendationComponentWrapper
74
+ nostoRecommendation={recommendation}
75
+ ></RecommendationComponentWrapper>
76
+ );
77
+ }
78
+ }
79
+ }
80
+ }
81
+ return { renderCampaigns, pageTypeUpdated };
82
+ };
83
+
29
84
  useEffect(() => {
30
85
  if (!document.querySelectorAll("[nosto-client-script]").length) {
31
86
  const script = document.createElement("script");
@@ -48,7 +103,15 @@ const NostoProvider: React.FC<NostoProviderProps> = ({
48
103
 
49
104
  return (
50
105
  <NostoContext.Provider
51
- value={{ account, clientScriptLoaded, currentVariation }}
106
+ value={{
107
+ account,
108
+ clientScriptLoaded,
109
+ currentVariation,
110
+ responseMode,
111
+ recommendationComponent,
112
+ useRenderCampaigns,
113
+ pageType,
114
+ }}
52
115
  >
53
116
  {children}
54
117
  </NostoContext.Provider>
@@ -2,25 +2,39 @@ import React, { useEffect } from "react";
2
2
  import { useNostoContext } from "../Provider/context.client";
3
3
 
4
4
  const NostoSearch: React.FC<{ query: string }> = ({ query }) => {
5
- const { clientScriptLoaded, currentVariation } = useNostoContext();
5
+ const {
6
+ clientScriptLoaded,
7
+ currentVariation,
8
+ responseMode,
9
+ recommendationComponent,
10
+ useRenderCampaigns,
11
+ } = useNostoContext();
12
+
13
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("search");
14
+
6
15
  useEffect(() => {
7
16
  // @ts-ignore
8
- if (clientScriptLoaded) {
17
+ if (clientScriptLoaded && pageTypeUpdated) {
9
18
  window.nostojs((api: any) => {
10
19
  api
11
20
  .defaultSession()
12
21
  .setVariation(currentVariation)
13
- .setResponseMode("HTML")
22
+ .setResponseMode(responseMode)
14
23
  .viewSearch(query)
15
24
  .setPlacements(api.placements.getPlacements())
16
25
  .load()
17
26
  .then((data: object) => {
18
- // @ts-ignore
19
- api.placements.injectCampaigns(data.recommendations);
27
+ renderCampaigns(data, api);
20
28
  });
21
29
  });
22
30
  }
23
- }, [clientScriptLoaded, currentVariation, query]);
31
+ }, [
32
+ clientScriptLoaded,
33
+ currentVariation,
34
+ query,
35
+ recommendationComponent,
36
+ pageTypeUpdated,
37
+ ]);
24
38
 
25
39
  return (
26
40
  <>
@@ -13,7 +13,7 @@ interface NostoSessionProps {
13
13
  const NostoSession: React.FC<NostoSessionProps> = ({ cart, customer }) => {
14
14
  const { clientScriptLoaded } = useNostoContext();
15
15
  useDeepCompareEffect(() => {
16
- const currentCart = cart ? snakeize(cart) : undefined;
16
+ const currentCart = cart ? snakeize(cart) : undefined;
17
17
  const currentCustomer = customer ? snakeize(customer) : undefined;
18
18
 
19
19
  // @ts-ignore
@@ -34,4 +34,3 @@ export {
34
34
  } from "./components/Provider/context.client";
35
35
  // noinspection JSUnusedGlobalSymbols
36
36
  export { default as NostoSession } from "./components/Session/index.client";
37
- //