@nosto/nosto-react 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/README.md +5 -2
  2. package/dist/{index.es.client.js → index.es.js} +123 -164
  3. package/dist/index.umd.js +9 -0
  4. package/package.json +15 -10
  5. package/src/components/Nosto404.tsx +47 -0
  6. package/src/components/{Category/index.client.tsx → NostoCategory.tsx} +18 -39
  7. package/src/components/NostoCheckout.tsx +47 -0
  8. package/src/components/{Home/index.client.tsx → NostoHome.tsx} +17 -36
  9. package/src/components/NostoOrder.tsx +55 -0
  10. package/src/components/NostoOther.tsx +46 -0
  11. package/src/components/{Placement/index.client.tsx → NostoPlacement.tsx} +5 -8
  12. package/src/components/{Product/index.client.tsx → NostoProduct.tsx} +37 -81
  13. package/src/components/NostoProvider.tsx +220 -0
  14. package/src/components/{Search/index.client.tsx → NostoSearch.tsx} +18 -39
  15. package/src/components/{Session/index.client.tsx → NostoSession.tsx} +14 -17
  16. package/src/components/context.ts +55 -0
  17. package/src/components/index.ts +14 -0
  18. package/src/index.ts +3 -0
  19. package/src/types.ts +112 -97
  20. package/src/utils/compare.ts +9 -9
  21. package/src/utils/hooks.ts +28 -8
  22. package/src/utils/object.ts +10 -11
  23. package/src/utils/snakeize.ts +11 -11
  24. package/dist/index.umd.client.js +0 -9
  25. package/src/components/Checkout/index.client.tsx +0 -66
  26. package/src/components/Fohofo/index.client.tsx +0 -66
  27. package/src/components/Order/index.client.tsx +0 -72
  28. package/src/components/Other/index.client.tsx +0 -64
  29. package/src/components/Provider/context.client.ts +0 -45
  30. package/src/components/Provider/index.client.tsx +0 -222
  31. package/src/index.client.ts +0 -33
@@ -1,5 +1,5 @@
1
- import { useEffect } from "react";
2
- import { useNostoContext } from "../Provider/context.client";
1
+ import { useNostoContext } from "./context"
2
+ import { useNostoApi } from "../utils/hooks"
3
3
 
4
4
  /**
5
5
  * You can personalise your category and collection pages by using the NostoCategory component.
@@ -21,45 +21,24 @@ import { useNostoContext } from "../Provider/context.client";
21
21
  * If the category being viewed is `Mens >> Jackets`, you must provide the name as `/Mens/Jackets`.
22
22
  * You must ensure that the category path provided here matches that of the categories tagged in your products.
23
23
  *
24
- * @group Personalisation Components
24
+ * @group Components
25
25
  */
26
- export default function NostoCategory(props: {
27
- category: string;
28
- placements?: string[];
29
- }): JSX.Element {
30
- const { category } = props;
31
- const {
32
- clientScriptLoaded,
33
- currentVariation,
34
- responseMode,
35
- recommendationComponent,
36
- useRenderCampaigns,
37
- } = useNostoContext();
26
+ export default function NostoCategory(props: { category: string; placements?: string[] }) {
27
+ const { category, placements } = props
28
+ const { recommendationComponent, useRenderCampaigns } = useNostoContext()
38
29
 
39
- const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("home");
30
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("home")
40
31
 
41
- useEffect(() => {
42
- if (clientScriptLoaded && pageTypeUpdated) {
43
- window.nostojs((api) => {
44
- api
45
- .defaultSession()
46
- .setVariation(currentVariation)
47
- .setResponseMode(responseMode)
48
- .viewCategory(category)
49
- .setPlacements(props.placements || api.placements.getPlacements())
50
- .load()
51
- .then((data) => {
52
- renderCampaigns(data, api);
53
- });
54
- });
55
- }
56
- }, [
57
- clientScriptLoaded,
58
- category,
59
- currentVariation,
60
- recommendationComponent,
61
- pageTypeUpdated,
62
- ]);
32
+ useNostoApi(
33
+ async (api) => {
34
+ const data = await api.defaultSession()
35
+ .viewCategory(category)
36
+ .setPlacements(placements || api.placements.getPlacements())
37
+ .load()
38
+ renderCampaigns(data, api)
39
+ },
40
+ [category, recommendationComponent, pageTypeUpdated]
41
+ )
63
42
 
64
43
  return (
65
44
  <>
@@ -70,5 +49,5 @@ export default function NostoCategory(props: {
70
49
  {category}
71
50
  </div>
72
51
  </>
73
- );
52
+ )
74
53
  }
@@ -0,0 +1,47 @@
1
+ import { useNostoContext } from "./context"
2
+ import { useNostoApi } from "../utils/hooks"
3
+
4
+ /**
5
+ * You can personalise your cart and checkout pages by using the NostoCheckout component.
6
+ * The component does not require any props.
7
+ *
8
+ * By default, your account, when created, has two cart-page placements named `categorypage-nosto-1` and `categorypage-nosto-2`.
9
+ * You may omit these and use any identifier you need.
10
+ * The identifiers used here are simply provided to illustrate the example.
11
+ *
12
+ * @example
13
+ * ```
14
+ * <div className="checkout-page">
15
+ * <NostoPlacement id="checkout-nosto-1" />
16
+ * <NostoPlacement id="checkout-nosto-2" />
17
+ * <NostoCheckout />
18
+ * </div>
19
+ * ```
20
+ *
21
+ * @group Components
22
+ */
23
+
24
+ export default function NostoCheckout(props: { placements?: string[] }) {
25
+ const { recommendationComponent, useRenderCampaigns } = useNostoContext()
26
+
27
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("checkout")
28
+
29
+ useNostoApi(
30
+ async (api) => {
31
+ const data = await api.defaultSession()
32
+ .viewCart()
33
+ .setPlacements(props.placements || api.placements.getPlacements())
34
+ .load()
35
+ renderCampaigns(data, api)
36
+ },
37
+ [recommendationComponent, pageTypeUpdated]
38
+ )
39
+
40
+ return (
41
+ <>
42
+ <div className="nosto_page_type" style={{ display: "none" }}>
43
+ cart
44
+ </div>
45
+ </>
46
+ )
47
+ }
@@ -1,5 +1,5 @@
1
- import { useEffect } from "react";
2
- import { useNostoContext } from "../Provider/context.client";
1
+ import { useNostoContext } from "./context"
2
+ import { useNostoApi } from "../utils/hooks"
3
3
 
4
4
  /**
5
5
  * The `NostoHome` component must be used to personalise the home page. The component does not require any props.
@@ -22,42 +22,23 @@ import { useNostoContext } from "../Provider/context.client";
22
22
  * </div>
23
23
  * ```
24
24
  *
25
- * @group Personalisation Components
25
+ * @group Components
26
26
  */
27
- export default function NostoHome(props: {
28
- placements?: string[];
29
- }): JSX.Element {
30
- const {
31
- clientScriptLoaded,
32
- currentVariation,
33
- responseMode,
34
- recommendationComponent,
35
- useRenderCampaigns,
36
- } = useNostoContext();
27
+ export default function NostoHome(props: { placements?: string[] }) {
28
+ const { recommendationComponent, useRenderCampaigns } = useNostoContext()
37
29
 
38
- const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("home");
30
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("home")
39
31
 
40
- useEffect(() => {
41
- if (clientScriptLoaded && pageTypeUpdated) {
42
- window.nostojs((api) => {
43
- api
44
- .defaultSession()
45
- .setVariation(currentVariation)
46
- .setResponseMode(responseMode)
47
- .viewFrontPage()
48
- .setPlacements(props.placements || api.placements.getPlacements())
49
- .load()
50
- .then((data) => {
51
- renderCampaigns(data, api);
52
- });
53
- });
54
- }
55
- }, [
56
- clientScriptLoaded,
57
- currentVariation,
58
- recommendationComponent,
59
- pageTypeUpdated,
60
- ]);
32
+ useNostoApi(
33
+ async (api) => {
34
+ const data = await api.defaultSession()
35
+ .viewFrontPage()
36
+ .setPlacements(props.placements || api.placements.getPlacements())
37
+ .load()
38
+ renderCampaigns(data, api)
39
+ },
40
+ [recommendationComponent, pageTypeUpdated]
41
+ )
61
42
 
62
43
  return (
63
44
  <>
@@ -65,5 +46,5 @@ export default function NostoHome(props: {
65
46
  front
66
47
  </div>
67
48
  </>
68
- );
49
+ )
69
50
  }
@@ -0,0 +1,55 @@
1
+ import { Purchase } from "../types"
2
+ import { useNostoContext } from "./context"
3
+ import { snakeize } from "../utils/snakeize"
4
+ import { useNostoApi } from "../utils/hooks"
5
+
6
+ /**
7
+ * You can personalise your order-confirmation/thank-you page by using the `NostoOrder` component.
8
+ * The component requires that you provide it with the details of the order.
9
+ *
10
+ * By default, your account, when created, has one other-page placement named `thankyou-nosto-1`.
11
+ * You may omit this and use any identifier you need. The identifier used here is simply provided to illustrate the example.
12
+ *
13
+ * The order prop requires a value that adheres to the type `Purchase`.
14
+ *
15
+ * @example
16
+ * ```
17
+ * <div className="thankyou-page">
18
+ * <NostoPlacement id="thankyou-nosto-1" />
19
+ * <NostoOrder order={{ purchase: toOrder(order) }} />
20
+ * </div>
21
+ * ```
22
+ *
23
+ * @group Components
24
+ */
25
+ export default function NostoOrder(props: {
26
+ order: { purchase: Purchase }
27
+ placements?: string[]
28
+ }) {
29
+ const { order, placements } = props
30
+ const { recommendationComponent, useRenderCampaigns } = useNostoContext()
31
+
32
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("order")
33
+
34
+ useNostoApi(
35
+ async (api) => {
36
+ const data = await api.defaultSession()
37
+ .addOrder(snakeize(order))
38
+ .setPlacements(placements || api.placements.getPlacements())
39
+ .load()
40
+ renderCampaigns(data, api)
41
+ },
42
+ [recommendationComponent, pageTypeUpdated]
43
+ )
44
+
45
+ return (
46
+ <>
47
+ <div className="nosto_page_type" style={{ display: "none" }}>
48
+ order
49
+ </div>
50
+ <div className="nosto_order" style={{ display: "none" }}>
51
+ {order.purchase.number}
52
+ </div>
53
+ </>
54
+ )
55
+ }
@@ -0,0 +1,46 @@
1
+ import { useNostoContext } from "./context"
2
+ import { useNostoApi } from "../utils/hooks"
3
+
4
+ /**
5
+ * You can personalise your miscellaneous pages by using the NostoOther component.
6
+ * The component does not require any props.
7
+ *
8
+ * By default, your account, when created, has two other-page placements named `other-nosto-1` and `other-nosto-2`.
9
+ * You may omit these and use any identifier you need.
10
+ * The identifiers used here are simply provided to illustrate the example.
11
+ *
12
+ * @example
13
+ * ```
14
+ * <div className="other-page">
15
+ * <NostoPlacement id="other-nosto-1" />
16
+ * <NostoPlacement id="other-nosto-2" />
17
+ * <NostoOther />
18
+ * </div>;
19
+ * ```
20
+ *
21
+ * @group Components
22
+ */
23
+ export default function NostoOther(props: { placements?: string[] }) {
24
+ const { recommendationComponent, useRenderCampaigns } = useNostoContext()
25
+
26
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("other")
27
+
28
+ useNostoApi(
29
+ async (api) => {
30
+ const data = await api.defaultSession()
31
+ .viewOther()
32
+ .setPlacements(props.placements || api.placements.getPlacements())
33
+ .load()
34
+ renderCampaigns(data, api)
35
+ },
36
+ [recommendationComponent, pageTypeUpdated]
37
+ )
38
+
39
+ return (
40
+ <>
41
+ <div className="nosto_page_type" style={{ display: "none" }}>
42
+ other
43
+ </div>
44
+ </>
45
+ )
46
+ }
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ import React from "react"
2
2
 
3
3
  /**
4
4
  * Nosto React has a special component called NostoPlacement.
@@ -11,12 +11,9 @@ import React from "react";
11
11
  * <NostoPlacement id="frontpage-nosto-1" />
12
12
  * ```
13
13
  *
14
- * @group Personalisation Components
14
+ * @group Components
15
15
  */
16
- export default function NostoPlacement(props: {
17
- id: string;
18
- pageType?: string;
19
- }): JSX.Element {
20
- const { id, pageType } = props;
21
- return <div className="nosto_element" id={id} key={id + (pageType || "")} />;
16
+ export default function NostoPlacement(props: { id: string; pageType?: string }) {
17
+ const { id, pageType } = props
18
+ return <div className="nosto_element" id={id} key={id + (pageType || "")} />
22
19
  }
@@ -1,6 +1,6 @@
1
- import { Product } from "../../types";
2
- import { useNostoContext } from "../Provider/context.client";
3
- import { useDeepCompareEffect } from "../../utils/hooks";
1
+ import { Product } from "../types"
2
+ import { useNostoContext } from "./context"
3
+ import { useNostoApi } from "../utils/hooks"
4
4
 
5
5
  /**
6
6
  * The NostoProduct component must be used to personalise the product page.
@@ -24,45 +24,29 @@ import { useDeepCompareEffect } from "../../utils/hooks";
24
24
  * </div>
25
25
  * ```
26
26
  *
27
- * @group Personalisation Components
27
+ * @group Components
28
28
  */
29
29
  export default function NostoProduct(props: {
30
- product: string;
31
- tagging?: Product;
32
- placements?: string[];
33
- }): JSX.Element {
34
- const { product, tagging } = props;
35
- const {
36
- clientScriptLoaded,
37
- currentVariation,
38
- responseMode,
39
- recommendationComponent,
40
- useRenderCampaigns,
41
- } = useNostoContext();
30
+ product: string
31
+ tagging?: Product
32
+ placements?: string[]
33
+ }) {
34
+ const { product, tagging, placements } = props
35
+ const { recommendationComponent, useRenderCampaigns } = useNostoContext()
42
36
 
43
- const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("product");
37
+ const { renderCampaigns, pageTypeUpdated } = useRenderCampaigns("product")
44
38
 
45
- useDeepCompareEffect(() => {
46
- if (clientScriptLoaded && pageTypeUpdated) {
47
- window.nostojs((api) => {
48
- api
49
- .defaultSession()
50
- .setResponseMode(responseMode)
51
- .viewProduct(product)
52
- .setPlacements(props.placements || api.placements.getPlacements())
53
- .load()
54
- .then((data) => {
55
- renderCampaigns(data, api);
56
- });
57
- });
58
- }
59
- }, [
60
- clientScriptLoaded,
61
- currentVariation,
62
- product,
63
- recommendationComponent,
64
- pageTypeUpdated,
65
- ]);
39
+ useNostoApi(
40
+ async (api) => {
41
+ const data = await api.defaultSession()
42
+ .viewProduct(product)
43
+ .setPlacements(placements || api.placements.getPlacements())
44
+ .load()
45
+ renderCampaigns(data, api)
46
+ },
47
+ [product, recommendationComponent, pageTypeUpdated],
48
+ { deep: true }
49
+ )
66
50
 
67
51
  return (
68
52
  <>
@@ -70,41 +54,23 @@ export default function NostoProduct(props: {
70
54
  product
71
55
  </div>
72
56
  <div className="nosto_product" style={{ display: "none" }}>
73
- {tagging?.variationId && (
74
- <span className="variation_id">{tagging.variationId}</span>
75
- )}
57
+ {tagging?.variationId && <span className="variation_id">{tagging.variationId}</span>}
76
58
  {product && <span className="product_id">{product}</span>}
77
59
  {tagging?.name && <span className="name">{tagging.name}</span>}
78
60
  {tagging?.url && <span className="url">{tagging.url.toString()}</span>}
79
- {tagging?.imageUrl && (
80
- <span className="image_url">{tagging.imageUrl.toString()}</span>
81
- )}
82
- {tagging?.availability && (
83
- <span className="availability">{tagging.availability}</span>
84
- )}
61
+ {tagging?.imageUrl && <span className="image_url">{tagging.imageUrl.toString()}</span>}
62
+ {tagging?.availability && <span className="availability">{tagging.availability}</span>}
85
63
  {tagging?.price && <span className="price">{tagging.price}</span>}
86
- {tagging?.listPrice && (
87
- <span className="list_price">{tagging.listPrice}</span>
88
- )}
64
+ {tagging?.listPrice && <span className="list_price">{tagging.listPrice}</span>}
89
65
  {tagging?.priceCurrencyCode && (
90
- <span className="price_currency_code">
91
- {tagging.priceCurrencyCode}
92
- </span>
66
+ <span className="price_currency_code">{tagging.priceCurrencyCode}</span>
93
67
  )}
94
68
  {tagging?.brand && <span className="brand">{tagging.brand}</span>}
95
- {tagging?.description && (
96
- <span className="description">{tagging.description}</span>
97
- )}
98
- {tagging?.googleCategory && (
99
- <span className="description">{tagging.googleCategory}</span>
100
- )}
101
- {tagging?.condition && (
102
- <span className="condition">{tagging.condition}</span>
103
- )}
69
+ {tagging?.description && <span className="description">{tagging.description}</span>}
70
+ {tagging?.googleCategory && <span className="description">{tagging.googleCategory}</span>}
71
+ {tagging?.condition && <span className="condition">{tagging.condition}</span>}
104
72
  {tagging?.gender && <span className="gender">{tagging.gender}</span>}
105
- {tagging?.ageGroup && (
106
- <span className="age_group">{tagging.ageGroup}</span>
107
- )}
73
+ {tagging?.ageGroup && <span className="age_group">{tagging.ageGroup}</span>}
108
74
  {tagging?.gtin && <span className="gtin">{tagging.gtin}</span>}
109
75
  {tagging?.category &&
110
76
  tagging?.category.map((category, index) => (
@@ -130,12 +96,8 @@ export default function NostoProduct(props: {
130
96
  {tag}
131
97
  </span>
132
98
  ))}
133
- {tagging?.ratingValue && (
134
- <span className="rating_value">{tagging.ratingValue}</span>
135
- )}
136
- {tagging?.reviewCount && (
137
- <span className="review_count">{tagging.reviewCount}</span>
138
- )}
99
+ {tagging?.ratingValue && <span className="rating_value">{tagging.ratingValue}</span>}
100
+ {tagging?.reviewCount && <span className="review_count">{tagging.reviewCount}</span>}
139
101
  {tagging?.alternateImageUrls &&
140
102
  tagging.alternateImageUrls.map((url, index) => (
141
103
  <span className="alternate_image_url" key={index}>
@@ -158,17 +120,11 @@ export default function NostoProduct(props: {
158
120
  {sku?.id && <span className="product_id">{sku.id}</span>}
159
121
  {sku?.name && <span className="name">{sku.name}</span>}
160
122
  {sku?.price && <span className="price">{sku.price}</span>}
161
- {sku?.listPrice && (
162
- <span className="list_price">{sku.listPrice}</span>
163
- )}
123
+ {sku?.listPrice && <span className="list_price">{sku.listPrice}</span>}
164
124
  {sku?.url && <span className="url">{sku.url.toString()}</span>}
165
- {sku?.imageUrl && (
166
- <span className="image_url">{sku.imageUrl.toString()}</span>
167
- )}
125
+ {sku?.imageUrl && <span className="image_url">{sku.imageUrl.toString()}</span>}
168
126
  {sku?.gtin && <span className="gtin">{sku.gtin}</span>}
169
- {sku?.availability && (
170
- <span className="availability">{sku.availability}</span>
171
- )}
127
+ {sku?.availability && <span className="availability">{sku.availability}</span>}
172
128
  {sku?.customFields &&
173
129
  Object.keys(sku.customFields).map(
174
130
  (field, index) =>
@@ -183,5 +139,5 @@ export default function NostoProduct(props: {
183
139
  ))}
184
140
  </div>
185
141
  </>
186
- );
142
+ )
187
143
  }