@usereactify/search 3.0.0 → 3.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.
- package/README.md +5 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/reactivesearch/useReactiveDataSearchProps.js +7 -0
- package/dist/hooks/useAnalytics.d.ts +28 -0
- package/dist/hooks/useAnalytics.js +54 -0
- package/dist/provider.d.ts +2 -4
- package/dist/provider.js +3 -3
- package/dist/result/ResultCard.js +13 -1
- package/dist/result/ResultList.d.ts +8 -3
- package/dist/result/ResultList.js +13 -17
- package/package.json +2 -1
package/README.md
CHANGED
package/dist/hooks/index.d.ts
CHANGED
package/dist/hooks/index.js
CHANGED
|
@@ -17,6 +17,7 @@ __exportStar(require("./useConfig"), exports);
|
|
|
17
17
|
__exportStar(require("./useSearch"), exports);
|
|
18
18
|
__exportStar(require("./useFilters"), exports);
|
|
19
19
|
__exportStar(require("./useCuration"), exports);
|
|
20
|
+
__exportStar(require("./useAnalytics"), exports);
|
|
20
21
|
__exportStar(require("./useCollection"), exports);
|
|
21
22
|
__exportStar(require("./useFilterStack"), exports);
|
|
22
23
|
__exportStar(require("./useProductPrice"), exports);
|
|
@@ -33,8 +33,15 @@ const useReactiveDataSearchProps = (props = {}) => {
|
|
|
33
33
|
return;
|
|
34
34
|
submitSearch();
|
|
35
35
|
}, [submitSearch]);
|
|
36
|
+
const { track } = (0, __1.useAnalytics)();
|
|
37
|
+
const trackQuery = react_1.default.useCallback(() => {
|
|
38
|
+
if (!searchQuery)
|
|
39
|
+
return;
|
|
40
|
+
track({ eventName: "search", payload: { searchTerm: searchQuery } });
|
|
41
|
+
}, [searchQuery, track]);
|
|
36
42
|
const { run: runDebouncedTriggerQuery, cancel: cancelDebouncedTriggerQuery } = (0, ahooks_1.useDebounceFn)((triggerQuery) => {
|
|
37
43
|
triggerQuery();
|
|
44
|
+
trackQuery();
|
|
38
45
|
}, {
|
|
39
46
|
wait: debounce !== null && debounce !== void 0 ? debounce : 300,
|
|
40
47
|
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export declare const useAnalytics: () => {
|
|
2
|
+
track: (event: TrackEvent) => Promise<import("axios").AxiosResponse<any, any> | undefined>;
|
|
3
|
+
};
|
|
4
|
+
export declare type TrackEvent = TrackEvent.SearchEvent | TrackEvent.ClickProductEvent;
|
|
5
|
+
export declare namespace TrackEvent {
|
|
6
|
+
interface SearchEvent {
|
|
7
|
+
eventName: "search";
|
|
8
|
+
payload: SearchEvent.Payload;
|
|
9
|
+
}
|
|
10
|
+
namespace SearchEvent {
|
|
11
|
+
interface Payload {
|
|
12
|
+
searchTerm: string;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
interface ClickProductEvent {
|
|
16
|
+
eventName: "clickProduct";
|
|
17
|
+
payload: ClickProductEvent.Payload;
|
|
18
|
+
}
|
|
19
|
+
namespace ClickProductEvent {
|
|
20
|
+
interface Payload {
|
|
21
|
+
elasticProduct: ElasticProduct;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
interface ElasticProduct {
|
|
25
|
+
id: number;
|
|
26
|
+
title: string;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.useAnalytics = void 0;
|
|
16
|
+
const axios_1 = __importDefault(require("axios"));
|
|
17
|
+
const provider_1 = require("../provider");
|
|
18
|
+
const useAnalytics = () => {
|
|
19
|
+
const { shopifyPermanentDomain } = (0, provider_1.useContext)();
|
|
20
|
+
const url = "https://analytics.search.reactify.app/record/";
|
|
21
|
+
const track = (event) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
if (!shopifyPermanentDomain) {
|
|
23
|
+
console.warn(new Error('Unable to send tracking event, missing value for "shopifyPermanentDomain".'));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const events = getTrackEvents(event);
|
|
27
|
+
return axios_1.default.post(url, { events }, { headers: { "X-Reactify-Tenant": shopifyPermanentDomain } });
|
|
28
|
+
});
|
|
29
|
+
return { track };
|
|
30
|
+
};
|
|
31
|
+
exports.useAnalytics = useAnalytics;
|
|
32
|
+
function getTrackEvents(event) {
|
|
33
|
+
const { eventName } = event;
|
|
34
|
+
let events = [];
|
|
35
|
+
switch (eventName) {
|
|
36
|
+
case "search":
|
|
37
|
+
events = [
|
|
38
|
+
{
|
|
39
|
+
eventName,
|
|
40
|
+
payload: event.payload,
|
|
41
|
+
},
|
|
42
|
+
];
|
|
43
|
+
break;
|
|
44
|
+
case "clickProduct":
|
|
45
|
+
events = [
|
|
46
|
+
{
|
|
47
|
+
eventName,
|
|
48
|
+
payload: event.payload,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
return events;
|
|
54
|
+
}
|
package/dist/provider.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { Config, ConfigSort, ConfigFilter, ConfigCuration } from "./types/c
|
|
|
3
3
|
declare type Context = {
|
|
4
4
|
index: string;
|
|
5
5
|
config: Config;
|
|
6
|
+
shopifyPermanentDomain: string;
|
|
6
7
|
sortOption: ConfigSort;
|
|
7
8
|
sortOptions: ConfigSort[];
|
|
8
9
|
searchQuery?: string;
|
|
@@ -19,13 +20,12 @@ declare type Context = {
|
|
|
19
20
|
curation?: ConfigCuration;
|
|
20
21
|
/** Array of additional component IDs managed outside of Reactify Search */
|
|
21
22
|
additionalComponentIds?: string[];
|
|
22
|
-
/** Enable the new callouts feature */
|
|
23
|
-
enableCallouts?: boolean;
|
|
24
23
|
};
|
|
25
24
|
declare const Context: React.Context<Context | undefined>;
|
|
26
25
|
declare type Props = {
|
|
27
26
|
index: string;
|
|
28
27
|
config: Config;
|
|
28
|
+
shopifyPermanentDomain: string;
|
|
29
29
|
filterStackId?: string;
|
|
30
30
|
collection?: Collection;
|
|
31
31
|
noReactiveBase?: boolean;
|
|
@@ -34,8 +34,6 @@ declare type Props = {
|
|
|
34
34
|
theme?: Theme;
|
|
35
35
|
/** Array of additional component IDs managed outside of Reactify Search */
|
|
36
36
|
additionalComponentIds?: string[];
|
|
37
|
-
/** Enable the new callouts feature */
|
|
38
|
-
enableCallouts?: boolean;
|
|
39
37
|
};
|
|
40
38
|
export declare const Provider: React.FC<Props>;
|
|
41
39
|
export declare const useContext: () => Context;
|
package/dist/provider.js
CHANGED
|
@@ -15,7 +15,7 @@ const defaultCredentials = {
|
|
|
15
15
|
};
|
|
16
16
|
const Provider = (props) => {
|
|
17
17
|
var _a, _b;
|
|
18
|
-
const { index, config, children, collection, instantSearch, filterStackId, noReactiveBase,
|
|
18
|
+
const { index, config, shopifyPermanentDomain, children, collection, instantSearch, filterStackId, noReactiveBase, additionalComponentIds, } = props;
|
|
19
19
|
const credentials = (_a = props.credentials) !== null && _a !== void 0 ? _a : defaultCredentials;
|
|
20
20
|
const theme = (_b = props.theme) !== null && _b !== void 0 ? _b : {
|
|
21
21
|
typography: {
|
|
@@ -64,6 +64,7 @@ const Provider = (props) => {
|
|
|
64
64
|
const contextValue = react_1.default.useMemo(() => ({
|
|
65
65
|
index,
|
|
66
66
|
config,
|
|
67
|
+
shopifyPermanentDomain,
|
|
67
68
|
collection,
|
|
68
69
|
credentials,
|
|
69
70
|
searchQuery,
|
|
@@ -76,7 +77,6 @@ const Provider = (props) => {
|
|
|
76
77
|
setShowInstantSearchResults,
|
|
77
78
|
theme,
|
|
78
79
|
curation,
|
|
79
|
-
enableCallouts,
|
|
80
80
|
additionalComponentIds,
|
|
81
81
|
instantSearch: !!instantSearch,
|
|
82
82
|
showInstantSearchResults: !!showInstantSearchResults && !!searchQuery,
|
|
@@ -84,6 +84,7 @@ const Provider = (props) => {
|
|
|
84
84
|
index,
|
|
85
85
|
config,
|
|
86
86
|
curation,
|
|
87
|
+
shopifyPermanentDomain,
|
|
87
88
|
collection,
|
|
88
89
|
credentials,
|
|
89
90
|
searchQuery,
|
|
@@ -92,7 +93,6 @@ const Provider = (props) => {
|
|
|
92
93
|
sortOptions,
|
|
93
94
|
submitSearch,
|
|
94
95
|
instantSearch,
|
|
95
|
-
enableCallouts,
|
|
96
96
|
additionalComponentIds,
|
|
97
97
|
showInstantSearchResults,
|
|
98
98
|
theme,
|
|
@@ -24,8 +24,20 @@ const ResultCard = (_a) => {
|
|
|
24
24
|
if (render)
|
|
25
25
|
return render(Object.assign(Object.assign({}, props), productPrice));
|
|
26
26
|
const { formattedPrice, formattedCompareAtPrice, onSale } = productPrice;
|
|
27
|
+
const { track } = (0, hooks_1.useAnalytics)();
|
|
28
|
+
const handleClick = react_1.default.useCallback(() => {
|
|
29
|
+
track({
|
|
30
|
+
eventName: "clickProduct",
|
|
31
|
+
payload: {
|
|
32
|
+
elasticProduct: {
|
|
33
|
+
id: product.id,
|
|
34
|
+
title: product.title,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}, [track, product]);
|
|
27
39
|
return (react_1.default.createElement("article", null,
|
|
28
|
-
react_1.default.createElement("a", { href: `/products/${product.handle}` },
|
|
40
|
+
react_1.default.createElement("a", { onClick: handleClick, href: `/products/${product.handle}` },
|
|
29
41
|
product.image && react_1.default.createElement("img", { src: product.image, width: "100%" }),
|
|
30
42
|
product.title),
|
|
31
43
|
react_1.default.createElement("span", null, formattedPrice),
|
|
@@ -5,6 +5,11 @@ import { ResultCardCallout } from "./ResultCardCallout";
|
|
|
5
5
|
import { ResultLoadMoreButton } from "./ResultLoadMoreButton";
|
|
6
6
|
import { ResultPaginationNextPrev } from "./ResultPaginationNextPrev";
|
|
7
7
|
import { ReactivesearchError, ReactivesearchResultProps } from "../types/reactivesearch";
|
|
8
|
+
import { ElasticCallout, ElasticProduct } from "../types/elastic";
|
|
9
|
+
declare type ResultProps = ReactivesearchResultProps & {
|
|
10
|
+
callouts: ElasticCallout[];
|
|
11
|
+
products: ElasticProduct[];
|
|
12
|
+
};
|
|
8
13
|
declare type Props = {
|
|
9
14
|
pageSize?: number;
|
|
10
15
|
gridColumns?: number;
|
|
@@ -14,9 +19,9 @@ declare type Props = {
|
|
|
14
19
|
renderResultCard?: Parameters<typeof ResultCard>[0]["render"];
|
|
15
20
|
renderPagination?: Parameters<typeof ResultPagination>[0]["render"];
|
|
16
21
|
renderResultCardCallout?: Parameters<typeof ResultCardCallout>[0]["render"];
|
|
17
|
-
renderAfter?: (props:
|
|
18
|
-
renderBefore?: (props:
|
|
19
|
-
renderResults?: (props:
|
|
22
|
+
renderAfter?: (props: ResultProps) => JSX.Element | null;
|
|
23
|
+
renderBefore?: (props: ResultProps) => JSX.Element | null;
|
|
24
|
+
renderResults?: (props: ResultProps) => JSX.Element | null;
|
|
20
25
|
renderError?: (props: {
|
|
21
26
|
error: ReactivesearchError;
|
|
22
27
|
}) => JSX.Element | null;
|
|
@@ -11,7 +11,6 @@ const ResultPagination_1 = require("./ResultPagination");
|
|
|
11
11
|
const ResultCardCallout_1 = require("./ResultCardCallout");
|
|
12
12
|
const ResultLoadMoreButton_1 = require("./ResultLoadMoreButton");
|
|
13
13
|
const ResultPaginationNextPrev_1 = require("./ResultPaginationNextPrev");
|
|
14
|
-
const provider_1 = require("../provider");
|
|
15
14
|
const hooks_1 = require("../hooks");
|
|
16
15
|
const elastic_1 = require("../types/elastic");
|
|
17
16
|
const ResultList = (props) => {
|
|
@@ -24,18 +23,15 @@ const ResultList = (props) => {
|
|
|
24
23
|
exports.ResultList = ResultList;
|
|
25
24
|
const ResultListInner = (props) => {
|
|
26
25
|
const { gridColumns, renderError, renderAfter, renderBefore, renderLoading, listClassName, renderResults, renderNoResults, renderResultCard, renderLoadMoreButton, renderResultCardCallout, reactivesearchResultProps, } = props;
|
|
27
|
-
const curation = (0, hooks_1.useCuration)();
|
|
28
26
|
const filterStack = (0, hooks_1.useFilterStack)();
|
|
29
27
|
const { instantSearch } = (0, hooks_1.useSearch)();
|
|
30
|
-
const { enableCallouts } = (0, provider_1.useContext)();
|
|
31
28
|
const initialSearchHasRun = react_1.default.useMemo(() => "undefined" !==
|
|
32
29
|
typeof reactivesearchResultProps.resultStats.numberOfResults, [reactivesearchResultProps]);
|
|
33
|
-
const styleProp = react_1.default.useMemo(() =>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
: {}, [curation]);
|
|
30
|
+
const styleProp = react_1.default.useMemo(() => ({
|
|
31
|
+
display: "grid",
|
|
32
|
+
gridTemplateColumns: `repeat(${gridColumns !== null && gridColumns !== void 0 ? gridColumns : 4}, minmax(0, 1fr))`,
|
|
33
|
+
}), [gridColumns]);
|
|
34
|
+
const resultProps = react_1.default.useMemo(() => (Object.assign(Object.assign({}, reactivesearchResultProps), { products: reactivesearchResultProps.data.filter((document) => elastic_1.ElasticDocumentType.Product === document.type || !document.type), callouts: reactivesearchResultProps.data.filter((document) => elastic_1.ElasticDocumentType.Callout === document.type) })), [reactivesearchResultProps]);
|
|
39
35
|
if (reactivesearchResultProps.error) {
|
|
40
36
|
if (renderError)
|
|
41
37
|
return renderError({ error: reactivesearchResultProps.error });
|
|
@@ -54,22 +50,22 @@ const ResultListInner = (props) => {
|
|
|
54
50
|
return react_1.default.createElement("div", null, "No results");
|
|
55
51
|
}
|
|
56
52
|
if (renderResults) {
|
|
57
|
-
return renderResults(
|
|
53
|
+
return renderResults(resultProps);
|
|
58
54
|
}
|
|
59
55
|
return (react_1.default.createElement(react_1.default.Fragment, null,
|
|
60
|
-
renderBefore && renderBefore(
|
|
61
|
-
react_1.default.createElement("section", { className: listClassName, style: styleProp }, reactivesearchResultProps.data.map((
|
|
56
|
+
renderBefore && renderBefore(resultProps),
|
|
57
|
+
react_1.default.createElement("section", { className: listClassName, style: styleProp }, reactivesearchResultProps.data.map((document, key) => {
|
|
62
58
|
// @todo result.type is missing in v1 indexes, this check ensures that they are assumed to be products
|
|
63
|
-
if (elastic_1.ElasticDocumentType.Product ===
|
|
64
|
-
return (react_1.default.createElement(ResultCard_1.ResultCard, { key:
|
|
59
|
+
if (elastic_1.ElasticDocumentType.Product === document.type || !document.type) {
|
|
60
|
+
return (react_1.default.createElement(ResultCard_1.ResultCard, { key: document._id, product: document, document: document, pagePosition: key + 1, render: renderResultCard }));
|
|
65
61
|
}
|
|
66
|
-
if (
|
|
67
|
-
return (react_1.default.createElement(ResultCardCallout_1.ResultCardCallout, { key:
|
|
62
|
+
if (elastic_1.ElasticDocumentType.Callout === document.type) {
|
|
63
|
+
return (react_1.default.createElement(ResultCardCallout_1.ResultCardCallout, { key: document._id, document: document, pagePosition: key + 1, callout: document.callout, render: renderResultCardCallout }));
|
|
68
64
|
}
|
|
69
65
|
return null;
|
|
70
66
|
})),
|
|
71
67
|
!instantSearch && "load_more" === (filterStack === null || filterStack === void 0 ? void 0 : filterStack.paginationType) && (react_1.default.createElement(ResultLoadMoreButton_1.ResultLoadMoreButton, Object.assign({}, reactivesearchResultProps, { render: renderLoadMoreButton }))),
|
|
72
|
-
renderAfter && renderAfter(
|
|
68
|
+
renderAfter && renderAfter(resultProps)));
|
|
73
69
|
};
|
|
74
70
|
const ResultPaginationInner = (props) => {
|
|
75
71
|
const { renderPagination, renderPaginationNextPrev } = props;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usereactify/search",
|
|
3
3
|
"description": "React UI library for Reactify Search",
|
|
4
|
-
"version": "3.
|
|
4
|
+
"version": "3.3.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"ahooks": "2.10.11",
|
|
33
|
+
"axios": "0.26.1",
|
|
33
34
|
"currency.js": "2.0.4",
|
|
34
35
|
"debug": "4.3.2"
|
|
35
36
|
},
|