@nosto/nosto-react 0.1.2 → 0.1.5

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.
@@ -0,0 +1,34 @@
1
+ import React, { useEffect } from "react";
2
+ import { useNostoContext } from "../Provider/context.client";
3
+
4
+ const NostoCheckout: React.FC = () => {
5
+ const { clientScriptLoaded, currentVariation } = useNostoContext();
6
+ useEffect(() => {
7
+ // @ts-ignore
8
+ if (clientScriptLoaded) {
9
+ window.nostojs((api: any) => {
10
+ api
11
+ .defaultSession()
12
+ .setVariation(currentVariation)
13
+ .setResponseMode("HTML")
14
+ .viewCart()
15
+ .setPlacements(api.placements.getPlacements())
16
+ .load()
17
+ .then((data: object) => {
18
+ // @ts-ignore
19
+ api.placements.injectCampaigns(data.recommendations);
20
+ });
21
+ });
22
+ }
23
+ }, [clientScriptLoaded, currentVariation]);
24
+
25
+ return (
26
+ <>
27
+ <div className="nosto_page_type" style={{ display: "none" }}>
28
+ cart
29
+ </div>
30
+ </>
31
+ );
32
+ };
33
+
34
+ export default NostoCheckout;
@@ -0,0 +1,34 @@
1
+ import React, { useEffect } from "react";
2
+ import { useNostoContext } from "../Provider/context.client";
3
+
4
+ const NostoFohofo: React.FC = () => {
5
+ const { clientScriptLoaded, currentVariation } = useNostoContext();
6
+ useEffect(() => {
7
+ // @ts-ignore
8
+ if (clientScriptLoaded) {
9
+ window.nostojs((api: any) => {
10
+ api
11
+ .defaultSession()
12
+ .setVariation(currentVariation)
13
+ .setResponseMode("HTML")
14
+ .viewNotFound()
15
+ .setPlacements(api.placements.getPlacements())
16
+ .load()
17
+ .then((data: object) => {
18
+ // @ts-ignore
19
+ api.placements.injectCampaigns(data.recommendations);
20
+ });
21
+ });
22
+ }
23
+ }, [clientScriptLoaded, currentVariation]);
24
+
25
+ return (
26
+ <>
27
+ <div className="nosto_page_type" style={{ display: "none" }}>
28
+ notfound
29
+ </div>
30
+ </>
31
+ );
32
+ };
33
+
34
+ export default NostoFohofo;
@@ -0,0 +1,37 @@
1
+ import React, { useEffect } from "react";
2
+ import { useNostoContext } from "../Provider/context.client";
3
+
4
+ const NostoHome: React.FC = () => {
5
+ const { clientScriptLoaded, currentVariation } = useNostoContext();
6
+ useEffect(() => {
7
+ if (currentVariation) {
8
+ console.log("currentVariation: ", currentVariation);
9
+ }
10
+ // @ts-ignore
11
+ if (clientScriptLoaded) {
12
+ window.nostojs((api: any) => {
13
+ api
14
+ .defaultSession()
15
+ .setVariation(currentVariation)
16
+ .setResponseMode("HTML")
17
+ .viewFrontPage()
18
+ .setPlacements(api.placements.getPlacements())
19
+ .load()
20
+ .then((data: object) => {
21
+ // @ts-ignore
22
+ api.placements.injectCampaigns(data.recommendations);
23
+ });
24
+ });
25
+ }
26
+ }, [clientScriptLoaded, currentVariation]);
27
+
28
+ return (
29
+ <>
30
+ <div className="nosto_page_type" style={{ display: "none" }}>
31
+ front
32
+ </div>
33
+ </>
34
+ );
35
+ };
36
+
37
+ export default NostoHome;
@@ -0,0 +1,43 @@
1
+ import { Purchase } from "../../types";
2
+ import React, { useEffect } from "react";
3
+ import snakeize from "snakeize";
4
+ import { useNostoContext } from "../Provider/context.client";
5
+
6
+ export interface OrderProps {
7
+ purchase: Purchase;
8
+ }
9
+
10
+ const NostoOrder: React.FC<{ order: OrderProps }> = ({ order }) => {
11
+ const { clientScriptLoaded, currentVariation } = useNostoContext();
12
+ useEffect(() => {
13
+ // @ts-ignore
14
+ if (clientScriptLoaded) {
15
+ window.nostojs((api: any) => {
16
+ api
17
+ .defaultSession()
18
+ .setVariation(currentVariation)
19
+ .setResponseMode("HTML")
20
+ .addOrder(snakeize(order))
21
+ .setPlacements(api.placements.getPlacements())
22
+ .load()
23
+ .then((data: object) => {
24
+ // @ts-ignore
25
+ api.placements.injectCampaigns(data.recommendations);
26
+ });
27
+ });
28
+ }
29
+ }, [clientScriptLoaded, currentVariation]);
30
+
31
+ return (
32
+ <>
33
+ <div className="nosto_page_type" style={{ display: "none" }}>
34
+ order
35
+ </div>
36
+ <div className="nosto_order" style={{ display: "none" }}>
37
+ {order.purchase.number}
38
+ </div>
39
+ </>
40
+ );
41
+ };
42
+
43
+ export default NostoOrder;
@@ -0,0 +1,34 @@
1
+ import React, { useEffect } from "react";
2
+ import { useNostoContext } from "../Provider/context.client";
3
+
4
+ const NostoOther: React.FC = () => {
5
+ const { clientScriptLoaded, currentVariation } = useNostoContext();
6
+ useEffect(() => {
7
+ // @ts-ignore
8
+ if (clientScriptLoaded) {
9
+ window.nostojs((api: any) => {
10
+ api
11
+ .defaultSession()
12
+ .setVariation(currentVariation)
13
+ .setResponseMode("HTML")
14
+ .viewOther()
15
+ .setPlacements(api.placements.getPlacements())
16
+ .load()
17
+ .then((data: object) => {
18
+ // @ts-ignore
19
+ api.placements.injectCampaigns(data.recommendations);
20
+ });
21
+ });
22
+ }
23
+ }, [clientScriptLoaded, currentVariation]);
24
+
25
+ return (
26
+ <>
27
+ <div className="nosto_page_type" style={{ display: "none" }}>
28
+ other
29
+ </div>
30
+ </>
31
+ );
32
+ };
33
+
34
+ export default NostoOther;
@@ -1,27 +1,33 @@
1
1
  import { Product } from "../../types";
2
- import stringinate from "../../utils/stringinate";
3
2
  import React, { useEffect } from "react";
4
- import snakeize from "snakeize";
3
+ import { useNostoContext } from "../Provider/context.client";
5
4
 
6
5
  const NostoProduct: React.FC<{ product: string; tagging: Product }> = ({
7
6
  product,
8
7
  tagging,
9
8
  }) => {
9
+ const { clientScriptLoaded, currentVariation } = useNostoContext();
10
10
  useEffect(() => {
11
11
  // @ts-ignore
12
- window.nostojs((api) => {
13
- api
14
- .defaultSession()
15
- .setResponseMode("HTML")
16
- .viewProduct(snakeize(stringinate(tagging)))
17
- .setPlacements(api.placements.getPlacements())
18
- .load()
19
- .then((data: object) => {
20
- // @ts-ignore
21
- api.placements.injectCampaigns(data.recommendations);
22
- });
23
- });
24
- }, []);
12
+ if (clientScriptLoaded) {
13
+ window.nostojs(
14
+ (api: any) => {
15
+ api
16
+ .defaultSession()
17
+ .setVariation(currentVariation)
18
+ .setResponseMode("HTML")
19
+ .viewProduct(product)
20
+ .setPlacements(api.placements.getPlacements())
21
+ .load()
22
+ .then((data: object) => {
23
+ // @ts-ignore
24
+ api.placements.injectCampaigns(data.recommendations);
25
+ });
26
+ },
27
+ [clientScriptLoaded, currentVariation, product]
28
+ );
29
+ }
30
+ });
25
31
 
26
32
  return (
27
33
  <>
@@ -29,81 +35,79 @@ const NostoProduct: React.FC<{ product: string; tagging: Product }> = ({
29
35
  product
30
36
  </div>
31
37
  <div className="nosto_product" style={{ display: "none" }}>
32
- {tagging.variationId && (
38
+ {tagging?.variationId && (
33
39
  <span className="variation_id">{tagging.variationId}</span>
34
40
  )}
35
- {tagging.productId && (
36
- <span className="product_id">{tagging.productId}</span>
37
- )}
38
- {tagging.name && <span className="name">{tagging.name}</span>}
39
- {tagging.url && <span className="url">{tagging.url.toString()}</span>}
40
- {tagging.imageUrl && (
41
+ {product && <span className="product_id">{product}</span>}
42
+ {tagging?.name && <span className="name">{tagging.name}</span>}
43
+ {tagging?.url && <span className="url">{tagging.url.toString()}</span>}
44
+ {tagging?.imageUrl && (
41
45
  <span className="image_url">{tagging.imageUrl.toString()}</span>
42
46
  )}
43
- {tagging.availability && (
47
+ {tagging?.availability && (
44
48
  <span className="availability">{tagging.availability}</span>
45
49
  )}
46
- {tagging.price && <span className="price">{tagging.price}</span>}
47
- {tagging.listPrice && (
50
+ {tagging?.price && <span className="price">{tagging.price}</span>}
51
+ {tagging?.listPrice && (
48
52
  <span className="list_price">{tagging.listPrice}</span>
49
53
  )}
50
- {tagging.priceCurrencyCode && (
54
+ {tagging?.priceCurrencyCode && (
51
55
  <span className="price_currency_code">
52
56
  {tagging.priceCurrencyCode}
53
57
  </span>
54
58
  )}
55
- {tagging.brand && <span className="brand">{tagging.brand}</span>}
56
- {tagging.description && (
59
+ {tagging?.brand && <span className="brand">{tagging.brand}</span>}
60
+ {tagging?.description && (
57
61
  <span className="description">{tagging.description}</span>
58
62
  )}
59
- {tagging.googleCategory && (
63
+ {tagging?.googleCategory && (
60
64
  <span className="description">{tagging.googleCategory}</span>
61
65
  )}
62
- {tagging.condition && (
66
+ {tagging?.condition && (
63
67
  <span className="condition">{tagging.condition}</span>
64
68
  )}
65
- {tagging.gender && <span className="gender">{tagging.gender}</span>}
66
- {tagging.ageGroup && (
69
+ {tagging?.gender && <span className="gender">{tagging.gender}</span>}
70
+ {tagging?.ageGroup && (
67
71
  <span className="age_group">{tagging.ageGroup}</span>
68
72
  )}
69
- {tagging.gtin && <span className="gtin">{tagging.gtin}</span>}
70
- {tagging.category &&
71
- tagging.category.map((category, index) => (
73
+ {tagging?.gtin && <span className="gtin">{tagging.gtin}</span>}
74
+ {tagging?.category &&
75
+ tagging?.category.map((category, index) => (
72
76
  <span className="category" key={index}>
73
77
  {category}
74
78
  </span>
75
79
  ))}
76
- {tagging.tags1 &&
80
+ {tagging?.tags1 &&
77
81
  tagging.tags1.map((tag, index) => (
78
82
  <span className="tag1" key={index}>
79
83
  {tag}
80
84
  </span>
81
85
  ))}
82
- {tagging.tags2 &&
86
+ {tagging?.tags2 &&
83
87
  tagging.tags2.map((tag, index) => (
84
88
  <span className="tag2" key={index}>
85
89
  {tag}
86
90
  </span>
87
91
  ))}
88
- {tagging.tags3 &&
92
+ {tagging?.tags3 &&
89
93
  tagging.tags3.map((tag, index) => (
90
94
  <span className="tag3" key={index}>
91
95
  {tag}
92
96
  </span>
93
97
  ))}
94
- {tagging.ratingValue && (
98
+ {tagging?.ratingValue && (
95
99
  <span className="rating_value">{tagging.ratingValue}</span>
96
100
  )}
97
- {tagging.reviewCount && (
101
+ {tagging?.reviewCount && (
98
102
  <span className="review_count">{tagging.reviewCount}</span>
99
103
  )}
100
- {tagging.alternateImageUrls &&
104
+ {tagging?.alternateImageUrls &&
101
105
  tagging.alternateImageUrls.map((url, index) => (
102
106
  <span className="alternate_image_url" key={index}>
103
107
  {url.toString()}
104
108
  </span>
105
109
  ))}
106
- {tagging.customFields &&
110
+ {tagging?.customFields &&
107
111
  Object.keys(tagging.customFields).map(
108
112
  (field, index) =>
109
113
  tagging.customFields &&
@@ -113,24 +117,24 @@ const NostoProduct: React.FC<{ product: string; tagging: Product }> = ({
113
117
  </span>
114
118
  )
115
119
  )}
116
- {tagging.skus &&
120
+ {tagging?.skus &&
117
121
  tagging.skus.map((sku, index) => (
118
122
  <span className="nosto_sku" key={index}>
119
- {sku.id && <span className="product_id">{sku.id}</span>}
120
- {sku.name && <span className="name">{sku.name}</span>}
121
- {sku.price && <span className="price">{sku.price}</span>}
122
- {sku.listPrice && (
123
+ {sku?.id && <span className="product_id">{sku.id}</span>}
124
+ {sku?.name && <span className="name">{sku.name}</span>}
125
+ {sku?.price && <span className="price">{sku.price}</span>}
126
+ {sku?.listPrice && (
123
127
  <span className="list_price">{sku.listPrice}</span>
124
128
  )}
125
- {sku.url && <span className="url">{sku.url.toString()}</span>}
126
- {sku.imageUrl && (
129
+ {sku?.url && <span className="url">{sku.url.toString()}</span>}
130
+ {sku?.imageUrl && (
127
131
  <span className="image_url">{sku.imageUrl.toString()}</span>
128
132
  )}
129
- {sku.gtin && <span className="gtin">{sku.gtin}</span>}
130
- {sku.availability && (
133
+ {sku?.gtin && <span className="gtin">{sku.gtin}</span>}
134
+ {sku?.availability && (
131
135
  <span className="availability">{sku.availability}</span>
132
136
  )}
133
- {sku.customFields &&
137
+ {sku?.customFields &&
134
138
  Object.keys(sku.customFields).map(
135
139
  (field, index) =>
136
140
  sku.customFields &&
@@ -0,0 +1,25 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ export interface NostoInterface {
4
+ account: string;
5
+ clientScriptLoaded: boolean;
6
+ currentVariation: string;
7
+ }
8
+
9
+ /* tslint:disable:no-empty */
10
+ export const NostoContext = createContext<NostoInterface>({
11
+ // @ts-ignore
12
+ account: undefined,
13
+ currentVariation: "",
14
+ });
15
+
16
+ /* tslint:enable:no-empty */
17
+ export function useNostoContext() {
18
+ const context = useContext(NostoContext);
19
+
20
+ if (!context) {
21
+ throw new Error("No nosto context found");
22
+ }
23
+
24
+ return context;
25
+ }
@@ -0,0 +1,58 @@
1
+ import React, { useEffect } from "react";
2
+ import { NostoContext } from "./context.client";
3
+
4
+ interface NostoProviderProps {
5
+ account: string;
6
+ currentVariation: string;
7
+ host: string;
8
+ children: React.ReactElement;
9
+ multiCurrency: boolean;
10
+ }
11
+
12
+ const NostoProvider: React.FC<NostoProviderProps> = ({
13
+ account,
14
+ currentVariation = "",
15
+ multiCurrency = false,
16
+ host,
17
+ children,
18
+ }) => {
19
+ const [clientScriptLoadedState, setClientScriptLoadedState] =
20
+ React.useState(false);
21
+ const clientScriptLoaded = React.useMemo(
22
+ () => clientScriptLoadedState,
23
+ [clientScriptLoadedState]
24
+ );
25
+
26
+ //Pass currentVariation as empty string if multiCurrency is disabled
27
+ currentVariation = multiCurrency ? currentVariation : "";
28
+
29
+ useEffect(() => {
30
+ if (!document.querySelectorAll("[nosto-client-script]").length) {
31
+ const script = document.createElement("script");
32
+ script.type = "text/javascript";
33
+ script.src = "//" + (host || "connect.nosto.com") + "/include/" + account;
34
+ script.async = true;
35
+ script.setAttribute("nosto-client-script", "");
36
+ script.onload = () => {
37
+ console.log("Nosto client script loaded");
38
+ setClientScriptLoadedState(true);
39
+ };
40
+ document.head.appendChild(script);
41
+ }
42
+
43
+ window.nostojs = (cb: Function) =>
44
+ (window.nostojs.q = window.nostojs.q || []).push(cb);
45
+ // @ts-ignore
46
+ window.nostojs((api) => api.setAutoLoad(false));
47
+ }, []);
48
+
49
+ return (
50
+ <NostoContext.Provider
51
+ value={{ account, clientScriptLoaded, currentVariation }}
52
+ >
53
+ {children}
54
+ </NostoContext.Provider>
55
+ );
56
+ };
57
+
58
+ export default NostoProvider;
@@ -0,0 +1,37 @@
1
+ import React, { useEffect } from "react";
2
+ import { useNostoContext } from "../Provider/context.client";
3
+
4
+ const NostoSearch: React.FC<{ query: string }> = ({ query }) => {
5
+ const { clientScriptLoaded, currentVariation } = useNostoContext();
6
+ useEffect(() => {
7
+ // @ts-ignore
8
+ if (clientScriptLoaded) {
9
+ window.nostojs((api: any) => {
10
+ api
11
+ .defaultSession()
12
+ .setVariation(currentVariation)
13
+ .setResponseMode("HTML")
14
+ .viewSearch(query)
15
+ .setPlacements(api.placements.getPlacements())
16
+ .load()
17
+ .then((data: object) => {
18
+ // @ts-ignore
19
+ api.placements.injectCampaigns(data.recommendations);
20
+ });
21
+ });
22
+ }
23
+ }, [clientScriptLoaded, currentVariation, query]);
24
+
25
+ return (
26
+ <>
27
+ <div className="nosto_page_type" style={{ display: "none" }}>
28
+ search
29
+ </div>
30
+ <div className="nosto_search" style={{ display: "none" }}>
31
+ {query}
32
+ </div>
33
+ </>
34
+ );
35
+ };
36
+
37
+ export default NostoSearch;
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import snakeize from "snakeize";
3
+ import { useNostoContext } from "../Provider/context.client";
3
4
 
4
5
  import useDeepCompareEffect from "use-deep-compare-effect";
5
6
  import { Cart, Customer } from "../../types";
@@ -10,24 +11,25 @@ interface NostoSessionProps {
10
11
  }
11
12
 
12
13
  const NostoSession: React.FC<NostoSessionProps> = ({ cart, customer }) => {
14
+ const { clientScriptLoaded } = useNostoContext();
13
15
  useDeepCompareEffect(() => {
14
- const currentUser = customer ? customer : undefined;
15
- console.debug(currentUser);
16
16
  const currentCart = cart ? cart : undefined;
17
17
  console.debug(currentCart);
18
18
 
19
19
  // @ts-ignore
20
- window.nostojs((api) => {
21
- api
22
- .defaultSession()
23
- .setResponseMode("HTML")
24
- .setCart(snakeize(currentCart))
25
- .viewOther()
26
- .load();
27
- });
28
- }, [cart || [], customer || {}]);
20
+ if (clientScriptLoaded) {
21
+ window.nostojs((api: any) => {
22
+ api
23
+ .defaultSession()
24
+ .setResponseMode("HTML")
25
+ .setCart(snakeize(currentCart))
26
+ .viewOther()
27
+ .load();
28
+ });
29
+ }
30
+ }, [clientScriptLoaded, cart || [], customer || {}]);
29
31
 
30
- return <div />;
32
+ return <></>;
31
33
  };
32
34
 
33
35
  export default NostoSession;
@@ -8,24 +8,30 @@ declare global {
8
8
 
9
9
  export * from "./types";
10
10
  // noinspection JSUnusedGlobalSymbols
11
- export { default as Nosto404 } from "./components/Fohofo";
11
+ export { default as Nosto404 } from "./components/Fohofo/index.client";
12
12
  // noinspection JSUnusedGlobalSymbols
13
- export { default as NostoOther } from "./components/Other";
13
+ export { default as NostoOther } from "./components/Other/index.client";
14
14
  // noinspection JSUnusedGlobalSymbols
15
- export { default as NostoCheckout } from "./components/Checkout";
15
+ export { default as NostoCheckout } from "./components/Checkout/index.client";
16
16
  // noinspection JSUnusedGlobalSymbols
17
- export { default as NostoProduct } from "./components/Product";
17
+ export { default as NostoProduct } from "./components/Product/index.client";
18
18
  // noinspection JSUnusedGlobalSymbols
19
- export { default as NostoCategory } from "./components/Category";
19
+ export { default as NostoCategory } from "./components/Category/index.client";
20
20
  // noinspection JSUnusedGlobalSymbols
21
- export { default as NostoSearch } from "./components/Search";
21
+ export { default as NostoSearch } from "./components/Search/index.client";
22
22
  // noinspection JSUnusedGlobalSymbols
23
- export { default as NostoOrder } from "./components/Order";
23
+ export { default as NostoOrder } from "./components/Order/index.client";
24
24
  // noinspection JSUnusedGlobalSymbols
25
- export { default as NostoHome } from "./components/Home";
25
+ export { default as NostoHome } from "./components/Home/index.client";
26
26
  // noinspection JSUnusedGlobalSymbols
27
- export { default as NostoPlacement } from "./components/Placement";
27
+ export { default as NostoPlacement } from "./components/Placement/index.client";
28
28
  // noinspection JSUnusedGlobalSymbols
29
- export { default as NostoProvider } from "./components/Provider";
29
+ export { default as NostoProvider } from "./components/Provider/index.client";
30
30
  // noinspection JSUnusedGlobalSymbols
31
- export { default as NostoSession } from "./components/Session";
31
+ export {
32
+ NostoContext,
33
+ useNostoContext,
34
+ } from "./components/Provider/context.client";
35
+ // noinspection JSUnusedGlobalSymbols
36
+ export { default as NostoSession } from "./components/Session/index.client";
37
+ //
@@ -1,32 +0,0 @@
1
- import React, { useEffect } from "react";
2
-
3
- const NostoCategory: React.FC<{ category: string }> = ({ category }) => {
4
- useEffect(() => {
5
- // @ts-ignore
6
- window.nostojs((api) => {
7
- api
8
- .defaultSession()
9
- .setResponseMode("HTML")
10
- .viewCategory(category)
11
- .setPlacements(api.placements.getPlacements())
12
- .load()
13
- .then((data: object) => {
14
- // @ts-ignore
15
- api.placements.injectCampaigns(data.recommendations);
16
- });
17
- });
18
- }, []);
19
-
20
- return (
21
- <>
22
- <div className="nosto_page_type" style={{ display: "none" }}>
23
- category
24
- </div>
25
- <div className="nosto_category" style={{ display: "none" }}>
26
- {category}
27
- </div>
28
- </>
29
- );
30
- };
31
-
32
- export default NostoCategory;
@@ -1,29 +0,0 @@
1
- import React, { useEffect } from "react";
2
-
3
- const NostoCheckout: React.FC = () => {
4
- useEffect(() => {
5
- // @ts-ignore
6
- window.nostojs((api) => {
7
- api
8
- .defaultSession()
9
- .setResponseMode("HTML")
10
- .viewCart()
11
- .setPlacements(api.placements.getPlacements())
12
- .load()
13
- .then((data: object) => {
14
- // @ts-ignore
15
- api.placements.injectCampaigns(data.recommendations);
16
- });
17
- });
18
- }, []);
19
-
20
- return (
21
- <>
22
- <div className="nosto_page_type" style={{ display: "none" }}>
23
- cart
24
- </div>
25
- </>
26
- );
27
- };
28
-
29
- export default NostoCheckout;