@nosto/nosto-react 0.2.1 → 0.4.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.
- package/README.md +66 -86
- package/dist/index.es.client.js +299 -248
- package/dist/index.umd.client.js +2 -2
- package/package.json +29 -13
- package/src/components/Category/index.client.tsx +48 -19
- package/src/components/Checkout/index.client.tsx +42 -19
- package/src/components/Fohofo/index.client.tsx +42 -19
- package/src/components/Home/index.client.tsx +45 -19
- package/src/components/Order/index.client.tsx +44 -23
- package/src/components/Other/index.client.tsx +40 -18
- package/src/components/Placement/index.client.tsx +18 -7
- package/src/components/Product/index.client.tsx +60 -34
- package/src/components/Provider/context.client.ts +25 -8
- package/src/components/Provider/index.client.tsx +184 -32
- package/src/components/Search/index.client.tsx +47 -19
- package/src/components/Session/index.client.tsx +20 -15
- package/src/index.client.ts +7 -11
- package/src/types.ts +84 -2
- package/src/utils/compare.ts +30 -0
- package/src/utils/hooks.ts +21 -0
- package/src/utils/object.ts +20 -0
- package/src/utils/snakeize.ts +28 -0
- package/src/snakeize.d.ts +0 -1
- package/src/utils/stringinate.ts +0 -16
package/src/types.ts
CHANGED
|
@@ -1,3 +1,67 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
interface Window {
|
|
3
|
+
nosto?: {
|
|
4
|
+
reload(settings: unknown): void;
|
|
5
|
+
};
|
|
6
|
+
nostojs: {
|
|
7
|
+
(callback: (api: NostoClient) => void): void;
|
|
8
|
+
q?: unknown[];
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @group Types
|
|
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;
|
|
32
|
+
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
|
+
}>;
|
|
44
|
+
placements: {
|
|
45
|
+
getPlacements(): string[];
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @group Types
|
|
51
|
+
*/
|
|
52
|
+
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;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @group Types
|
|
64
|
+
*/
|
|
1
65
|
export interface Item {
|
|
2
66
|
name: string;
|
|
3
67
|
price_currency_code: string;
|
|
@@ -7,10 +71,16 @@ export interface Item {
|
|
|
7
71
|
unit_price: number;
|
|
8
72
|
}
|
|
9
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @group Types
|
|
76
|
+
*/
|
|
10
77
|
export interface Cart {
|
|
11
78
|
items: Item[];
|
|
12
79
|
}
|
|
13
80
|
|
|
81
|
+
/**
|
|
82
|
+
* @group Types
|
|
83
|
+
*/
|
|
14
84
|
export interface Customer {
|
|
15
85
|
customer_reference: string;
|
|
16
86
|
email: string;
|
|
@@ -19,6 +89,9 @@ export interface Customer {
|
|
|
19
89
|
newsletter: boolean;
|
|
20
90
|
}
|
|
21
91
|
|
|
92
|
+
/**
|
|
93
|
+
* @group Types
|
|
94
|
+
*/
|
|
22
95
|
export interface Buyer {
|
|
23
96
|
first_name: string;
|
|
24
97
|
last_name: string;
|
|
@@ -27,12 +100,18 @@ export interface Buyer {
|
|
|
27
100
|
newsletter: boolean;
|
|
28
101
|
}
|
|
29
102
|
|
|
103
|
+
/**
|
|
104
|
+
* @group Types
|
|
105
|
+
*/
|
|
30
106
|
export interface Purchase {
|
|
31
107
|
number: string;
|
|
32
108
|
info: Buyer;
|
|
33
109
|
items: Item[];
|
|
34
110
|
}
|
|
35
111
|
|
|
112
|
+
/**
|
|
113
|
+
* @group Types
|
|
114
|
+
*/
|
|
36
115
|
export interface SKU {
|
|
37
116
|
id: string;
|
|
38
117
|
name: string;
|
|
@@ -41,13 +120,16 @@ export interface SKU {
|
|
|
41
120
|
url: URL;
|
|
42
121
|
imageUrl: URL;
|
|
43
122
|
gtin?: string;
|
|
44
|
-
availability:
|
|
123
|
+
availability: "InStock" | "OutOfStock";
|
|
45
124
|
customFields?: { [key: string]: string };
|
|
46
125
|
}
|
|
47
126
|
|
|
127
|
+
/**
|
|
128
|
+
* @group Types
|
|
129
|
+
*/
|
|
48
130
|
export interface Product {
|
|
49
131
|
alternateImageUrls?: URL[];
|
|
50
|
-
availability:
|
|
132
|
+
availability: "InStock" | "OutOfStock";
|
|
51
133
|
brand?: string;
|
|
52
134
|
category: string[];
|
|
53
135
|
categoryIds?: string[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { isPlainObject } from "./object";
|
|
2
|
+
|
|
3
|
+
export function deepCompare(a: unknown, b: unknown): boolean {
|
|
4
|
+
if (a === b) {
|
|
5
|
+
return true;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (a instanceof Date && b instanceof Date) {
|
|
9
|
+
return a.getTime() === b.getTime();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (a instanceof Array && b instanceof Array) {
|
|
13
|
+
if (a.length !== b.length) {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return a.every((v, i) => deepCompare(v, b[i]));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
21
|
+
const entriesA = Object.entries(a);
|
|
22
|
+
|
|
23
|
+
if (entriesA.length !== Object.keys(b).length) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return entriesA.every(([k, v]) => deepCompare(v, b[k]));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect, useRef, useMemo } from "react";
|
|
2
|
+
import { deepCompare } from "./compare";
|
|
3
|
+
|
|
4
|
+
export function useDeepCompareEffect(
|
|
5
|
+
callback: Parameters<typeof useEffect>[0],
|
|
6
|
+
dependencies: Parameters<typeof useEffect>[1]
|
|
7
|
+
): ReturnType<typeof useEffect> {
|
|
8
|
+
return useEffect(callback, useDeepCompareMemoize(dependencies));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function useDeepCompareMemoize<T>(value: T) {
|
|
12
|
+
const ref = useRef<T>(value);
|
|
13
|
+
const signalRef = useRef<number>(0);
|
|
14
|
+
|
|
15
|
+
if (!deepCompare(value, ref.current)) {
|
|
16
|
+
ref.current = value;
|
|
17
|
+
signalRef.current += 1;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return useMemo(() => ref.current, [signalRef.current]);
|
|
21
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
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]";
|
|
5
|
+
|
|
6
|
+
if (!isObject(value)) return false;
|
|
7
|
+
|
|
8
|
+
const constructor = value.constructor;
|
|
9
|
+
if (constructor === undefined) return true;
|
|
10
|
+
|
|
11
|
+
const prototype = constructor.prototype;
|
|
12
|
+
if (!isObject(prototype)) return false;
|
|
13
|
+
|
|
14
|
+
// Checks if it is not a class
|
|
15
|
+
if (!prototype.hasOwnProperty("isPrototypeOf")) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function snakeize<T>(obj: T): T {
|
|
2
|
+
if (!obj || typeof obj !== "object") {
|
|
3
|
+
return obj;
|
|
4
|
+
}
|
|
5
|
+
if (isDate(obj) || isRegex(obj)) {
|
|
6
|
+
return obj;
|
|
7
|
+
}
|
|
8
|
+
if (Array.isArray(obj)) {
|
|
9
|
+
return obj.map(snakeize) as T;
|
|
10
|
+
}
|
|
11
|
+
return Object.keys(obj).reduce((acc, key) => {
|
|
12
|
+
var camel =
|
|
13
|
+
key[0].toLowerCase() +
|
|
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);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isDate(obj: unknown) {
|
|
23
|
+
return Object.prototype.toString.call(obj) === "[object Date]";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isRegex(obj: unknown) {
|
|
27
|
+
return Object.prototype.toString.call(obj) === "[object RegExp]";
|
|
28
|
+
}
|
package/src/snakeize.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
declare module "snakeize";
|
package/src/utils/stringinate.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export default function stringinate(obj: {
|
|
2
|
-
[key: string]: any;
|
|
3
|
-
}): { [key: string]: any } {
|
|
4
|
-
Object.keys(obj).forEach((property) => {
|
|
5
|
-
if (obj[property] instanceof URL) {
|
|
6
|
-
obj[property] = obj[property].toString();
|
|
7
|
-
}
|
|
8
|
-
if (typeof obj[property] === "object") {
|
|
9
|
-
stringinate(obj[property]);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
obj[property] = obj[property];
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
return obj;
|
|
16
|
-
}
|