@usereactify/search 4.1.0-beta.3 → 4.1.0-beta.4
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/dist/filter/Filter.js +1 -1
- package/dist/hooks/reactivesearch/useReactiveFilterListProps.js +2 -2
- package/dist/hooks/reactivesearch/useReactiveReactProp.d.ts +1 -1
- package/dist/hooks/reactivesearch/useReactiveReactProp.js +6 -6
- package/dist/hooks/useLiveConfig.d.ts +1 -1
- package/dist/hooks/useLiveConfig.js +18 -11
- package/dist/hooks/useSort.d.ts +1 -1
- package/dist/hooks/useSort.js +3 -3
- package/dist/provider.d.ts +5 -4
- package/dist/provider.js +46 -30
- package/dist/types/firestore.d.ts +3 -0
- package/package.json +1 -1
package/dist/filter/Filter.js
CHANGED
|
@@ -30,7 +30,7 @@ const Filter = (props) => {
|
|
|
30
30
|
if ("multi" === filter.displayType) {
|
|
31
31
|
return (react_1.default.createElement(MultiList_1.default, Object.assign({ showCheckbox: false }, reactiveFilterListProps, { render: (reactivesearchFilterProps) => (react_1.default.createElement(FilterListInner, Object.assign({}, props, { reactivesearchFilterProps: reactivesearchFilterProps }))) })));
|
|
32
32
|
}
|
|
33
|
-
console.
|
|
33
|
+
console.log(`filter with display type "${filter.displayType}" not yet supported`);
|
|
34
34
|
return null;
|
|
35
35
|
};
|
|
36
36
|
exports.Filter = Filter;
|
|
@@ -7,7 +7,7 @@ exports.useReactiveFilterListProps = void 0;
|
|
|
7
7
|
const react_1 = __importDefault(require("react"));
|
|
8
8
|
const useReactiveReactProp_1 = require("./useReactiveReactProp");
|
|
9
9
|
const useReactiveFilterListProps = (filter) => {
|
|
10
|
-
const reactiveReactProp = (0, useReactiveReactProp_1.useReactiveReactProp)(filter.
|
|
10
|
+
const reactiveReactProp = (0, useReactiveReactProp_1.useReactiveReactProp)(filter.handle);
|
|
11
11
|
const nestedField = react_1.default.useMemo(() => {
|
|
12
12
|
const nestedFields = ["variants"];
|
|
13
13
|
const topField = filter.field.split(".")[0];
|
|
@@ -93,7 +93,7 @@ const useReactiveFilterListProps = (filter) => {
|
|
|
93
93
|
customQuery,
|
|
94
94
|
defaultQuery,
|
|
95
95
|
URLParams: true,
|
|
96
|
-
componentId: filter.
|
|
96
|
+
componentId: filter.handle,
|
|
97
97
|
dataField: filter.field,
|
|
98
98
|
filterLabel: filter.name,
|
|
99
99
|
react: reactiveReactProp,
|
|
@@ -8,18 +8,18 @@ const react_1 = __importDefault(require("react"));
|
|
|
8
8
|
const sensor_1 = require("../../sensor");
|
|
9
9
|
const useFilters_1 = require("../useFilters");
|
|
10
10
|
const provider_1 = require("../../provider");
|
|
11
|
-
const useReactiveReactProp = (
|
|
11
|
+
const useReactiveReactProp = (currentHandle) => {
|
|
12
12
|
const filters = (0, useFilters_1.useFilters)();
|
|
13
|
-
const {
|
|
13
|
+
const { additionalComponentHandles } = (0, provider_1.useContext)();
|
|
14
14
|
return react_1.default.useMemo(() => {
|
|
15
15
|
return {
|
|
16
16
|
and: [
|
|
17
17
|
"SearchInput",
|
|
18
18
|
...sensor_1.SENSOR_IDS,
|
|
19
|
-
...(
|
|
20
|
-
...filters.map((filter) => filter.
|
|
21
|
-
].filter((
|
|
19
|
+
...(additionalComponentHandles !== null && additionalComponentHandles !== void 0 ? additionalComponentHandles : []),
|
|
20
|
+
...filters.map((filter) => filter.handle),
|
|
21
|
+
].filter((handle) => handle !== currentHandle),
|
|
22
22
|
};
|
|
23
|
-
}, [filters,
|
|
23
|
+
}, [filters, currentHandle]);
|
|
24
24
|
};
|
|
25
25
|
exports.useReactiveReactProp = useReactiveReactProp;
|
|
@@ -41,22 +41,29 @@ function getCachedConfig() {
|
|
|
41
41
|
}
|
|
42
42
|
return;
|
|
43
43
|
}
|
|
44
|
-
const useLiveConfig = (shopifyPermanentDomain) => {
|
|
44
|
+
const useLiveConfig = (shopifyPermanentDomain, configId) => {
|
|
45
45
|
const [config, setConfig] = react_1.default.useState(getCachedConfig());
|
|
46
46
|
react_1.default.useEffect(() => {
|
|
47
47
|
const cachedConfig = getCachedConfig();
|
|
48
48
|
if (cachedConfig)
|
|
49
49
|
return;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
if (!!shopifyPermanentDomain) {
|
|
51
|
+
(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
52
|
+
debug("fetching fresh config");
|
|
53
|
+
const searchParams = new URLSearchParams();
|
|
54
|
+
searchParams.set("shop", shopifyPermanentDomain);
|
|
55
|
+
if (configId) {
|
|
56
|
+
searchParams.set("id", configId);
|
|
57
|
+
}
|
|
58
|
+
const json = yield fetch(`https://config.search.reactify.app/?${searchParams.toString()}`).then((response) => response.json());
|
|
59
|
+
setConfig(json.body);
|
|
60
|
+
window.sessionStorage.setItem("reactify-search:config", JSON.stringify({
|
|
61
|
+
expiresAt: new Date().getTime() + CACHE_EXPIRY,
|
|
62
|
+
config: json.body,
|
|
63
|
+
}));
|
|
64
|
+
}))();
|
|
65
|
+
}
|
|
66
|
+
}, [shopifyPermanentDomain, configId]);
|
|
60
67
|
return {
|
|
61
68
|
config,
|
|
62
69
|
};
|
package/dist/hooks/useSort.d.ts
CHANGED
package/dist/hooks/useSort.js
CHANGED
|
@@ -10,12 +10,12 @@ const hooks_1 = require("../hooks");
|
|
|
10
10
|
const useSort = () => {
|
|
11
11
|
const { track } = (0, hooks_1.useAnalytics)();
|
|
12
12
|
const { sortOption, sortOptions, setSortOption } = (0, provider_1.useContext)();
|
|
13
|
-
const handleSortChange = react_1.default.useCallback((
|
|
14
|
-
setSortOption(
|
|
13
|
+
const handleSortChange = react_1.default.useCallback((sortOptionHandle) => {
|
|
14
|
+
setSortOption(sortOptionHandle);
|
|
15
15
|
track({
|
|
16
16
|
eventName: "sortChange",
|
|
17
17
|
payload: {
|
|
18
|
-
type:
|
|
18
|
+
type: sortOptionHandle,
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
21
|
}, [track, setSortOption]);
|
package/dist/provider.d.ts
CHANGED
|
@@ -14,19 +14,20 @@ declare type Context = {
|
|
|
14
14
|
onRedirect?: (type: "redirect" | "search", url: string) => void;
|
|
15
15
|
submitSearch: (localSearchQuery?: string) => void;
|
|
16
16
|
setSearchQuery: (searchQuery: string) => void;
|
|
17
|
-
setSortOption: (
|
|
17
|
+
setSortOption: (sortOptionHandle: string) => void;
|
|
18
18
|
showInstantSearchResults: boolean;
|
|
19
19
|
setShowInstantSearchResults: (showInstantSearchResults: boolean) => void;
|
|
20
20
|
theme?: Theme;
|
|
21
21
|
curation?: ConfigCuration;
|
|
22
22
|
/** Array of additional component IDs managed outside of Reactify Search */
|
|
23
|
-
|
|
23
|
+
additionalComponentHandles?: string[];
|
|
24
24
|
};
|
|
25
25
|
declare const Context: React.Context<Context | undefined>;
|
|
26
26
|
declare type Props = {
|
|
27
27
|
index: string;
|
|
28
28
|
shopifyPermanentDomain: string;
|
|
29
|
-
|
|
29
|
+
configId?: string;
|
|
30
|
+
filterStackHandle?: string;
|
|
30
31
|
collection?: Collection;
|
|
31
32
|
noReactiveBase?: boolean;
|
|
32
33
|
instantSearch?: boolean;
|
|
@@ -34,7 +35,7 @@ declare type Props = {
|
|
|
34
35
|
credentials?: Credentials;
|
|
35
36
|
theme?: Theme;
|
|
36
37
|
/** Array of additional component IDs managed outside of Reactify Search */
|
|
37
|
-
|
|
38
|
+
additionalComponentHandles?: string[];
|
|
38
39
|
/**
|
|
39
40
|
* Optional render function to display a component when the config is loading.
|
|
40
41
|
*/
|
package/dist/provider.js
CHANGED
|
@@ -50,7 +50,7 @@ Sentry.init({
|
|
|
50
50
|
});
|
|
51
51
|
const Provider = (_a) => {
|
|
52
52
|
var { renderBooting } = _a, props = __rest(_a, ["renderBooting"]);
|
|
53
|
-
const { config } = (0, hooks_1.useLiveConfig)(props.shopifyPermanentDomain);
|
|
53
|
+
const { config } = (0, hooks_1.useLiveConfig)(props.shopifyPermanentDomain, props.configId);
|
|
54
54
|
if (!config) {
|
|
55
55
|
if (renderBooting)
|
|
56
56
|
return renderBooting();
|
|
@@ -61,17 +61,17 @@ const Provider = (_a) => {
|
|
|
61
61
|
scope.setTag("shop", props.shopifyPermanentDomain);
|
|
62
62
|
if (!!props.collection)
|
|
63
63
|
scope.setTag("collection", props.collection.handle);
|
|
64
|
-
if (!!props.
|
|
65
|
-
scope.setTag("
|
|
64
|
+
if (!!props.filterStackHandle)
|
|
65
|
+
scope.setTag("filter", props.filterStackHandle);
|
|
66
66
|
if (!!props.instantSearch)
|
|
67
|
-
scope.setTag("
|
|
67
|
+
scope.setTag("search", true);
|
|
68
68
|
} },
|
|
69
69
|
react_1.default.createElement(exports.ConfiguredProvider, Object.assign({}, props, { config: config }))));
|
|
70
70
|
};
|
|
71
71
|
exports.Provider = Provider;
|
|
72
72
|
const ConfiguredProvider = (props) => {
|
|
73
73
|
var _a, _b;
|
|
74
|
-
const { index, config, children, collection, instantSearch,
|
|
74
|
+
const { index, config, children, collection, instantSearch, filterStackHandle, noReactiveBase, shopifyPermanentDomain, additionalComponentHandles, onRedirect, } = props;
|
|
75
75
|
const credentials = (_a = props.credentials) !== null && _a !== void 0 ? _a : defaultCredentials;
|
|
76
76
|
const theme = (_b = props.theme) !== null && _b !== void 0 ? _b : {
|
|
77
77
|
typography: {
|
|
@@ -110,13 +110,13 @@ const ConfiguredProvider = (props) => {
|
|
|
110
110
|
setSearchQuery(searchQueryFromURL);
|
|
111
111
|
}, [searchQueryFromURL]);
|
|
112
112
|
react_1.default.useEffect(() => {
|
|
113
|
-
if (searchSortFromURL && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.
|
|
113
|
+
if (searchSortFromURL && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.handle) !== searchSortFromURL) {
|
|
114
114
|
setSortOption(searchSortFromURL, true);
|
|
115
115
|
}
|
|
116
116
|
}, [searchSortFromURL]);
|
|
117
117
|
react_1.default.useEffect(() => {
|
|
118
|
-
if (window.location.search === "" && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.
|
|
119
|
-
setSortOption(
|
|
118
|
+
if (window.location.search === "" && (sortOption === null || sortOption === void 0 ? void 0 : sortOption.handle)) {
|
|
119
|
+
setSortOption(sortOption.handle, true);
|
|
120
120
|
}
|
|
121
121
|
}, [window.location.href]);
|
|
122
122
|
const [showInstantSearchResults, setShowInstantSearchResults] = react_1.default.useState(false);
|
|
@@ -140,7 +140,7 @@ const ConfiguredProvider = (props) => {
|
|
|
140
140
|
// do not attempt to resolve a filter stack if in instantSearch mode
|
|
141
141
|
const filterStack = instantSearch
|
|
142
142
|
? undefined
|
|
143
|
-
: useFilterStack(config, collection,
|
|
143
|
+
: useFilterStack(config, collection, filterStackHandle);
|
|
144
144
|
const curation = useCuration(config, collection, searchQuery);
|
|
145
145
|
const contextValue = react_1.default.useMemo(() => ({
|
|
146
146
|
index,
|
|
@@ -159,7 +159,7 @@ const ConfiguredProvider = (props) => {
|
|
|
159
159
|
setShowInstantSearchResults,
|
|
160
160
|
theme,
|
|
161
161
|
curation,
|
|
162
|
-
|
|
162
|
+
additionalComponentHandles,
|
|
163
163
|
instantSearch: !!instantSearch,
|
|
164
164
|
showInstantSearchResults: !!showInstantSearchResults && !!searchQuery,
|
|
165
165
|
}), [
|
|
@@ -176,7 +176,7 @@ const ConfiguredProvider = (props) => {
|
|
|
176
176
|
onRedirect,
|
|
177
177
|
submitSearch,
|
|
178
178
|
instantSearch,
|
|
179
|
-
|
|
179
|
+
additionalComponentHandles,
|
|
180
180
|
showInstantSearchResults,
|
|
181
181
|
theme,
|
|
182
182
|
]);
|
|
@@ -200,15 +200,16 @@ const useSortState = (config, collection) => {
|
|
|
200
200
|
.sort((a, b) => `${a.position}`.localeCompare(`${b.position}`))
|
|
201
201
|
.filter(({ visibility }) => ["all", type].includes(visibility));
|
|
202
202
|
}, [config, collection]);
|
|
203
|
-
const [sortOptionState, setSortOptionState] = react_1.default.useState((_a = sortOptions[0]) === null || _a === void 0 ? void 0 : _a.
|
|
204
|
-
const sortOption = react_1.default.useMemo(() => sortOptions.find(({
|
|
205
|
-
|
|
206
|
-
|
|
203
|
+
const [sortOptionState, setSortOptionState] = react_1.default.useState((_a = sortOptions[0]) === null || _a === void 0 ? void 0 : _a.handle);
|
|
204
|
+
const sortOption = react_1.default.useMemo(() => sortOptions.find(({ handle }) => handle === sortOptionState) ||
|
|
205
|
+
sortOptions[0], [sortOptions, sortOptionState]);
|
|
206
|
+
const setSortOption = react_1.default.useCallback((sortOptionHandle, ignoreHistoryState = false) => {
|
|
207
|
+
setSortOptionState(sortOptionHandle);
|
|
207
208
|
if (!ignoreHistoryState) {
|
|
208
209
|
const url = new URL(window.location.href);
|
|
209
210
|
url.searchParams.has("sort")
|
|
210
|
-
? url.searchParams.set("sort",
|
|
211
|
-
: url.searchParams.append("sort",
|
|
211
|
+
? url.searchParams.set("sort", sortOptionHandle)
|
|
212
|
+
: url.searchParams.append("sort", sortOptionHandle);
|
|
212
213
|
window.history.pushState({}, "", url.toString());
|
|
213
214
|
}
|
|
214
215
|
}, [window.location.href]);
|
|
@@ -220,22 +221,37 @@ const useSortState = (config, collection) => {
|
|
|
220
221
|
// @todo we need a better name for the overall page like "Filter Stack" or something,
|
|
221
222
|
// each block is then called a filter so like Size would be a "Filter" and then each
|
|
222
223
|
// value within it is a "Filter Option"
|
|
223
|
-
const useFilterStack = (config, collection,
|
|
224
|
-
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
224
|
+
const useFilterStack = (config, collection, filterStackHandle) => react_1.default.useMemo(() => {
|
|
225
|
+
const type = !!collection ? "collection" : "search";
|
|
226
|
+
// select filters by type
|
|
227
|
+
const matchingFilterStacks = config.filters.filter((filter) => filter.type === type);
|
|
228
|
+
// select filter stack by handle if provided
|
|
229
|
+
if (filterStackHandle) {
|
|
230
|
+
const matchingFilterStack = matchingFilterStacks.find((filterStack) => filterStackHandle === filterStack.handle);
|
|
231
|
+
if (matchingFilterStack) {
|
|
232
|
+
return matchingFilterStack;
|
|
233
|
+
}
|
|
230
234
|
}
|
|
231
|
-
//
|
|
235
|
+
// select filter stack by collection if provided
|
|
232
236
|
if (collection === null || collection === void 0 ? void 0 : collection.handle) {
|
|
233
|
-
const
|
|
234
|
-
if (
|
|
235
|
-
return
|
|
237
|
+
const matchingFilterStack = matchingFilterStacks.find((filterStack) => { var _a; return (_a = filterStack.collections) === null || _a === void 0 ? void 0 : _a.includes(collection.handle); });
|
|
238
|
+
if (matchingFilterStack) {
|
|
239
|
+
return matchingFilterStack;
|
|
240
|
+
}
|
|
236
241
|
}
|
|
237
|
-
|
|
238
|
-
|
|
242
|
+
// select filter with "default" handle
|
|
243
|
+
let matchingFilterStack = matchingFilterStacks.find((filterStack) => filterStack.handle === "default");
|
|
244
|
+
if (matchingFilterStack) {
|
|
245
|
+
return matchingFilterStack;
|
|
246
|
+
}
|
|
247
|
+
// select any filter with "default" handle
|
|
248
|
+
matchingFilterStack = config.filters.find((filterStack) => filterStack.handle === "default");
|
|
249
|
+
if (matchingFilterStack) {
|
|
250
|
+
return matchingFilterStack;
|
|
251
|
+
}
|
|
252
|
+
// select any available filter as a last resort
|
|
253
|
+
matchingFilterStack = config.filters[0];
|
|
254
|
+
return matchingFilterStack;
|
|
239
255
|
}, [config, collection]);
|
|
240
256
|
const useCuration = (config, collection, searchQuery) => react_1.default.useMemo(() => {
|
|
241
257
|
debug("resolveCuration.start", { config, collection, searchQuery });
|
|
@@ -107,6 +107,7 @@ export interface DefinedField {
|
|
|
107
107
|
export interface Sort {
|
|
108
108
|
id: string;
|
|
109
109
|
name: string;
|
|
110
|
+
handle: string;
|
|
110
111
|
field: string;
|
|
111
112
|
position: number;
|
|
112
113
|
enabled: boolean;
|
|
@@ -116,6 +117,7 @@ export interface Sort {
|
|
|
116
117
|
export interface Filter {
|
|
117
118
|
id: string;
|
|
118
119
|
name: string;
|
|
120
|
+
handle: string;
|
|
119
121
|
enabled: boolean;
|
|
120
122
|
pageSize: number;
|
|
121
123
|
keywords: string[];
|
|
@@ -135,6 +137,7 @@ export interface FilterOption {
|
|
|
135
137
|
field: string;
|
|
136
138
|
id: string;
|
|
137
139
|
name: string;
|
|
140
|
+
handle: string;
|
|
138
141
|
position: number;
|
|
139
142
|
settingsCollapsedDesktop: boolean;
|
|
140
143
|
settingsCollapsedMobile: boolean;
|