@nosto/nosto-react 0.4.1 → 0.5.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.
Files changed (33) hide show
  1. package/README.md +5 -2
  2. package/dist/index.d.ts +519 -0
  3. package/dist/index.es.js +1117 -0
  4. package/dist/index.umd.js +25 -0
  5. package/package.json +20 -13
  6. package/src/components/Nosto404.tsx +47 -0
  7. package/src/components/{Category/index.client.tsx → NostoCategory.tsx} +18 -39
  8. package/src/components/NostoCheckout.tsx +47 -0
  9. package/src/components/{Home/index.client.tsx → NostoHome.tsx} +17 -36
  10. package/src/components/NostoOrder.tsx +55 -0
  11. package/src/components/NostoOther.tsx +46 -0
  12. package/src/components/{Placement/index.client.tsx → NostoPlacement.tsx} +5 -8
  13. package/src/components/{Product/index.client.tsx → NostoProduct.tsx} +37 -81
  14. package/src/components/NostoProvider.tsx +220 -0
  15. package/src/components/{Search/index.client.tsx → NostoSearch.tsx} +18 -39
  16. package/src/components/{Session/index.client.tsx → NostoSession.tsx} +14 -17
  17. package/src/components/context.ts +55 -0
  18. package/src/components/index.ts +14 -0
  19. package/src/index.ts +3 -0
  20. package/src/types.ts +112 -97
  21. package/src/utils/compare.ts +9 -9
  22. package/src/utils/hooks.ts +28 -8
  23. package/src/utils/object.ts +10 -11
  24. package/src/utils/snakeize.ts +11 -11
  25. package/dist/index.es.client.js +0 -660
  26. package/dist/index.umd.client.js +0 -9
  27. package/src/components/Checkout/index.client.tsx +0 -66
  28. package/src/components/Fohofo/index.client.tsx +0 -66
  29. package/src/components/Order/index.client.tsx +0 -72
  30. package/src/components/Other/index.client.tsx +0 -64
  31. package/src/components/Provider/context.client.ts +0 -45
  32. package/src/components/Provider/index.client.tsx +0 -222
  33. package/src/index.client.ts +0 -33
package/src/types.ts CHANGED
@@ -1,158 +1,173 @@
1
1
  declare global {
2
2
  interface Window {
3
3
  nosto?: {
4
- reload(settings: unknown): void;
5
- };
4
+ reload(settings: unknown): void
5
+ }
6
6
  nostojs: {
7
- (callback: (api: NostoClient) => void): void;
8
- q?: unknown[];
9
- };
7
+ (callback: (api: NostoClient) => void): void
8
+ q?: unknown[]
9
+ }
10
10
  }
11
11
  }
12
12
 
13
13
  /**
14
14
  * @group Types
15
15
  */
16
- export interface NostoClient {
17
- addOrder(order: { purchase: Purchase }): NostoClient;
18
- defaultSession(): NostoClient;
19
- setAutoLoad(autoload: boolean): NostoClient;
20
- setCart(cart?: Cart): NostoClient;
21
- setCustomer(customer?: Customer): NostoClient;
22
- setPlacements(placements: string[]): NostoClient;
23
- setResponseMode(mode: string): NostoClient;
24
- setVariation(variation: string): NostoClient;
25
- viewCategory(category: string): NostoClient;
26
- viewProduct(product: string): NostoClient;
27
- viewFrontPage(): NostoClient;
28
- viewNotFound(): NostoClient;
29
- viewOther(): NostoClient;
30
- viewSearch(query: string): NostoClient;
31
- viewCart(): NostoClient;
16
+ export interface Affinity {
17
+ name: string
18
+ score: number
19
+ }
20
+
21
+ /**
22
+ * @group Types
23
+ */
24
+ export interface SessionAction {
25
+ setPlacements(placements: string[]): SessionAction
32
26
  load(): Promise<{
33
- affinities: Record<
34
- string,
35
- {
36
- name: string;
37
- score: number;
38
- }[]
39
- >;
40
- geo_location?: string[];
41
- page_views: number;
42
- recommendations: Recommendation[];
43
- }>;
27
+ affinities: Record<string, Affinity[]>
28
+ geo_location?: string[]
29
+ page_views: number
30
+ recommendations: Recommendation[]
31
+ }>
32
+ }
33
+
34
+ /**
35
+ * @group Types
36
+ */
37
+ export interface NostoClientSession {
38
+ setCart(cart?: Cart): NostoClientSession
39
+ setCustomer(customer?: Customer): NostoClientSession
40
+ setResponseMode(mode: string): NostoClientSession
41
+ setVariation(variation?: string): NostoClientSession
42
+ addOrder(order: { purchase: Purchase }): SessionAction
43
+ viewCategory(category: string): SessionAction
44
+ viewProduct(product: string): SessionAction
45
+ viewFrontPage(): SessionAction
46
+ viewNotFound(): SessionAction
47
+ viewOther(): SessionAction
48
+ viewSearch(query: string): SessionAction
49
+ viewCart(): SessionAction
50
+ }
51
+
52
+ /**
53
+ * @group Types
54
+ */
55
+ export interface NostoClient {
56
+ setAutoLoad(autoload: boolean): NostoClient
57
+ defaultSession(): NostoClientSession
44
58
  placements: {
45
- getPlacements(): string[];
46
- };
59
+ getPlacements(): string[]
60
+ injectCampaigns(recommendations: Record<string, Recommendation>): void
61
+ }
47
62
  }
48
63
 
49
64
  /**
50
65
  * @group Types
51
66
  */
52
67
  export interface Recommendation {
53
- result_id: string;
54
- products: Product[];
55
- result_type: string;
56
- title: string;
57
- div_id: string;
58
- source_product_ids: string[];
59
- params: unknown;
68
+ result_id: string
69
+ products: Product[]
70
+ result_type: string
71
+ title: string
72
+ div_id: string
73
+ source_product_ids: string[]
74
+ params: unknown
60
75
  }
61
76
 
62
77
  /**
63
78
  * @group Types
64
79
  */
65
80
  export interface Item {
66
- name: string;
67
- price_currency_code: string;
68
- product_id: string;
69
- quantity: number;
70
- sku_id: string;
71
- unit_price: number;
81
+ name: string
82
+ price_currency_code: string
83
+ product_id: string
84
+ quantity: number
85
+ sku_id: string
86
+ unit_price: number
72
87
  }
73
88
 
74
89
  /**
75
90
  * @group Types
76
91
  */
77
92
  export interface Cart {
78
- items: Item[];
93
+ items: Item[]
79
94
  }
80
95
 
81
96
  /**
82
97
  * @group Types
83
98
  */
84
99
  export interface Customer {
85
- customer_reference: string;
86
- email: string;
87
- first_name: string;
88
- last_name: string;
89
- newsletter: boolean;
100
+ customer_reference: string
101
+ email: string
102
+ first_name: string
103
+ last_name: string
104
+ newsletter: boolean
90
105
  }
91
106
 
92
107
  /**
93
108
  * @group Types
94
109
  */
95
110
  export interface Buyer {
96
- first_name: string;
97
- last_name: string;
98
- email: string;
99
- type: string;
100
- newsletter: boolean;
111
+ first_name: string
112
+ last_name: string
113
+ email: string
114
+ type: string
115
+ newsletter: boolean
101
116
  }
102
117
 
103
118
  /**
104
119
  * @group Types
105
120
  */
106
121
  export interface Purchase {
107
- number: string;
108
- info: Buyer;
109
- items: Item[];
122
+ number: string
123
+ info: Buyer
124
+ items: Item[]
110
125
  }
111
126
 
112
127
  /**
113
128
  * @group Types
114
129
  */
115
130
  export interface SKU {
116
- id: string;
117
- name: string;
118
- price: number;
119
- listPrice?: number;
120
- url: URL;
121
- imageUrl: URL;
122
- gtin?: string;
123
- availability: "InStock" | "OutOfStock";
124
- customFields?: { [key: string]: string };
131
+ id: string
132
+ name: string
133
+ price: number
134
+ listPrice?: number
135
+ url: URL
136
+ imageUrl: URL
137
+ gtin?: string
138
+ availability: "InStock" | "OutOfStock"
139
+ customFields?: { [key: string]: string }
125
140
  }
126
141
 
127
142
  /**
128
143
  * @group Types
129
144
  */
130
145
  export interface Product {
131
- alternateImageUrls?: URL[];
132
- availability: "InStock" | "OutOfStock";
133
- brand?: string;
134
- category: string[];
135
- categoryIds?: string[];
136
- description: string;
137
- googleCategory?: string;
138
- condition?: string;
139
- gender?: string;
140
- ageGroup?: string;
141
- gtin?: string;
142
- imageUrl: URL;
143
- listPrice?: number;
144
- name: string;
145
- price: number;
146
- ratingValue?: number;
147
- reviewCount?: number;
148
- priceCurrencyCode: string;
149
- productId: string;
150
- tags1?: string[];
151
- tags2?: string[];
152
- tags3?: string[];
153
- thumbUrl?: URL;
154
- url: URL;
155
- customFields?: { [key: string]: string };
156
- variationId?: string;
157
- skus?: SKU[];
146
+ alternateImageUrls?: URL[]
147
+ availability: "InStock" | "OutOfStock"
148
+ brand?: string
149
+ category: string[]
150
+ categoryIds?: string[]
151
+ description: string
152
+ googleCategory?: string
153
+ condition?: string
154
+ gender?: string
155
+ ageGroup?: string
156
+ gtin?: string
157
+ imageUrl: URL
158
+ listPrice?: number
159
+ name: string
160
+ price: number
161
+ ratingValue?: number
162
+ reviewCount?: number
163
+ priceCurrencyCode: string
164
+ productId: string
165
+ tags1?: string[]
166
+ tags2?: string[]
167
+ tags3?: string[]
168
+ thumbUrl?: URL
169
+ url: URL
170
+ customFields?: { [key: string]: string }
171
+ variationId?: string
172
+ skus?: SKU[]
158
173
  }
@@ -1,30 +1,30 @@
1
- import { isPlainObject } from "./object";
1
+ import { isPlainObject } from "./object"
2
2
 
3
3
  export function deepCompare(a: unknown, b: unknown): boolean {
4
4
  if (a === b) {
5
- return true;
5
+ return true
6
6
  }
7
7
 
8
8
  if (a instanceof Date && b instanceof Date) {
9
- return a.getTime() === b.getTime();
9
+ return a.getTime() === b.getTime()
10
10
  }
11
11
 
12
12
  if (a instanceof Array && b instanceof Array) {
13
13
  if (a.length !== b.length) {
14
- return false;
14
+ return false
15
15
  }
16
16
 
17
- return a.every((v, i) => deepCompare(v, b[i]));
17
+ return a.every((v, i) => deepCompare(v, b[i]))
18
18
  }
19
19
 
20
20
  if (isPlainObject(a) && isPlainObject(b)) {
21
- const entriesA = Object.entries(a);
21
+ const entriesA = Object.entries(a)
22
22
 
23
23
  if (entriesA.length !== Object.keys(b).length) {
24
- return false;
24
+ return false
25
25
  }
26
- return entriesA.every(([k, v]) => deepCompare(v, b[k]));
26
+ return entriesA.every(([k, v]) => deepCompare(v, b[k]))
27
27
  }
28
28
 
29
- return false;
29
+ return false
30
30
  }
@@ -1,21 +1,41 @@
1
- import { useEffect, useRef, useMemo } from "react";
2
- import { deepCompare } from "./compare";
1
+ import { useEffect, useRef, useMemo } from "react"
2
+ import { useNostoContext } from "../components/context"
3
+ import { deepCompare } from "./compare"
4
+ import { NostoClient } from "../types"
3
5
 
4
6
  export function useDeepCompareEffect(
5
7
  callback: Parameters<typeof useEffect>[0],
6
8
  dependencies: Parameters<typeof useEffect>[1]
7
9
  ): ReturnType<typeof useEffect> {
8
- return useEffect(callback, useDeepCompareMemoize(dependencies));
10
+ return useEffect(callback, useDeepCompareMemoize(dependencies))
9
11
  }
10
12
 
11
13
  function useDeepCompareMemoize<T>(value: T) {
12
- const ref = useRef<T>(value);
13
- const signalRef = useRef<number>(0);
14
+ const ref = useRef<T>(value)
15
+ const signalRef = useRef<number>(0)
14
16
 
15
17
  if (!deepCompare(value, ref.current)) {
16
- ref.current = value;
17
- signalRef.current += 1;
18
+ ref.current = value
19
+ signalRef.current += 1
18
20
  }
19
21
 
20
- return useMemo(() => ref.current, [signalRef.current]);
22
+ return useMemo(() => ref.current, [signalRef.current])
23
+ }
24
+
25
+ export function useNostoApi(
26
+ cb: (api: NostoClient) => void,
27
+ deps?: React.DependencyList,
28
+ flags?: { deep?: boolean }
29
+ ): void {
30
+ const { clientScriptLoaded, currentVariation, responseMode } = useNostoContext()
31
+ const useEffectFn = flags?.deep ? useDeepCompareEffect : useEffect
32
+
33
+ useEffectFn(() => {
34
+ if (clientScriptLoaded) {
35
+ window.nostojs(api => {
36
+ api.defaultSession().setVariation(currentVariation).setResponseMode(responseMode)
37
+ cb(api)
38
+ })
39
+ }
40
+ }, [clientScriptLoaded, currentVariation, responseMode, ...(deps ?? [])])
21
41
  }
@@ -1,20 +1,19 @@
1
- export function isPlainObject<T = Record<keyof any, unknown>>(
2
- value: unknown
3
- ): value is T {
4
- const isObject = (v: unknown): v is object => String(v) === "[object Object]";
1
+ const isObject = (v: unknown): v is object => String(v) === "[object Object]"
5
2
 
6
- if (!isObject(value)) return false;
3
+ export function isPlainObject(value: unknown): value is Record<string, unknown> {
4
+ if (!isObject(value)) return false
7
5
 
8
- const constructor = value.constructor;
9
- if (constructor === undefined) return true;
6
+ const constructor = value.constructor
7
+ if (constructor === undefined) return true
10
8
 
11
- const prototype = constructor.prototype;
12
- if (!isObject(prototype)) return false;
9
+ const prototype = constructor.prototype
10
+ if (!isObject(prototype)) return false
13
11
 
14
12
  // Checks if it is not a class
13
+ // eslint-disable-next-line no-prototype-builtins
15
14
  if (!prototype.hasOwnProperty("isPrototypeOf")) {
16
- return false;
15
+ return false
17
16
  }
18
17
 
19
- return true;
18
+ return true
20
19
  }
@@ -1,28 +1,28 @@
1
1
  export function snakeize<T>(obj: T): T {
2
2
  if (!obj || typeof obj !== "object") {
3
- return obj;
3
+ return obj
4
4
  }
5
5
  if (isDate(obj) || isRegex(obj)) {
6
- return obj;
6
+ return obj
7
7
  }
8
8
  if (Array.isArray(obj)) {
9
- return obj.map(snakeize) as T;
9
+ return obj.map(snakeize) as T
10
10
  }
11
11
  return Object.keys(obj).reduce((acc, key) => {
12
- var camel =
12
+ const camel =
13
13
  key[0].toLowerCase() +
14
14
  key.slice(1).replace(/([A-Z]+)/g, (_, x) => {
15
- return "_" + x.toLowerCase();
16
- });
17
- acc[camel as keyof typeof acc] = snakeize(obj[key as keyof typeof acc]);
18
- return acc;
19
- }, {} as T);
15
+ return "_" + x.toLowerCase()
16
+ })
17
+ acc[camel as keyof typeof acc] = snakeize(obj[key as keyof typeof acc])
18
+ return acc
19
+ }, {}) as T
20
20
  }
21
21
 
22
22
  function isDate(obj: unknown) {
23
- return Object.prototype.toString.call(obj) === "[object Date]";
23
+ return Object.prototype.toString.call(obj) === "[object Date]"
24
24
  }
25
25
 
26
26
  function isRegex(obj: unknown) {
27
- return Object.prototype.toString.call(obj) === "[object RegExp]";
27
+ return Object.prototype.toString.call(obj) === "[object RegExp]"
28
28
  }