@constructor-io/constructorio-ui-autocomplete 1.7.0 → 1.7.1

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.
@@ -5,11 +5,11 @@ const tslib_1 = require("tslib");
5
5
  const react_1 = require("react");
6
6
  const useCioClient_1 = tslib_1.__importDefault(require("./useCioClient"));
7
7
  const useDownShift_1 = tslib_1.__importDefault(require("./useDownShift"));
8
- const useDebouncedFetchSections_1 = tslib_1.__importDefault(require("./useDebouncedFetchSections"));
9
- const useFetchRecommendationPod_1 = tslib_1.__importDefault(require("./useFetchRecommendationPod"));
10
8
  const usePrevious_1 = tslib_1.__importDefault(require("./usePrevious"));
11
9
  const utils_1 = require("../utils");
12
- const typeGuards_1 = require("../typeGuards");
10
+ const useConsoleErrors_1 = tslib_1.__importDefault(require("./useConsoleErrors"));
11
+ const useSections_1 = tslib_1.__importDefault(require("./useSections"));
12
+ const useItems_1 = tslib_1.__importDefault(require("./useItems"));
13
13
  exports.defaultSections = [
14
14
  {
15
15
  identifier: 'Search Suggestions',
@@ -21,50 +21,18 @@ exports.defaultSections = [
21
21
  },
22
22
  ];
23
23
  const useCioAutocomplete = (options) => {
24
- const defaultPlaceholder = 'What can we help you find today?';
25
- const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, placeholder = defaultPlaceholder, sections = exports.defaultSections, zeroStateSections, autocompleteClassName = 'cio-autocomplete', advancedParameters = {}, } = options;
24
+ const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, placeholder = 'What can we help you find today?', sections = exports.defaultSections, zeroStateSections, autocompleteClassName = 'cio-autocomplete', advancedParameters = {}, } = options;
26
25
  const [query, setQuery] = (0, react_1.useState)('');
27
26
  const previousQuery = (0, usePrevious_1.default)(query);
28
27
  const cioClient = (0, useCioClient_1.default)({ apiKey, cioJsClient });
29
- const zeroStateSectionsActive = !query.length && zeroStateSections;
30
- let activeSections = zeroStateSectionsActive ? zeroStateSections : sections;
31
- if (sections && !Array.isArray(sections)) {
32
- // eslint-disable-next-line
33
- console.error('useCioAutocomplete expects sections to reference an array of section configuration objects');
34
- activeSections = [];
35
- }
36
- if (zeroStateSections && !Array.isArray(zeroStateSections)) {
37
- // eslint-disable-next-line
38
- console.error('useCioAutocomplete expects zeroStateSections to reference an array of section configuration objects');
39
- activeSections = [];
40
- }
41
- const autocompleteSections = activeSections === null || activeSections === void 0 ? void 0 : activeSections.filter((config) => config.type === 'autocomplete' || !config.type);
42
- const recommendationsSections = activeSections === null || activeSections === void 0 ? void 0 : activeSections.filter((config) => config.type === 'recommendations');
43
- const autocompleteResults = (0, useDebouncedFetchSections_1.default)(query, cioClient, autocompleteSections, advancedParameters);
44
- const recommendationsResults = (0, useFetchRecommendationPod_1.default)(cioClient, recommendationsSections);
45
- const sectionResults = Object.assign(Object.assign({}, autocompleteResults), recommendationsResults);
46
- const activeSectionsWithData = [];
47
- activeSections === null || activeSections === void 0 ? void 0 : activeSections.forEach((config) => {
48
- const { identifier } = config;
49
- let data;
50
- if ((0, typeGuards_1.isCustomSection)(config)) {
51
- data = config.data;
52
- }
53
- else {
54
- data = sectionResults[identifier];
55
- }
56
- if (Array.isArray(data)) {
57
- activeSectionsWithData.push(Object.assign(Object.assign({}, config), { data }));
58
- }
59
- });
60
- const items = [];
61
- activeSectionsWithData === null || activeSectionsWithData === void 0 ? void 0 : activeSectionsWithData.forEach((config) => {
62
- if (config === null || config === void 0 ? void 0 : config.data) {
63
- items.push(...config.data);
64
- }
65
- });
66
- const downshift = (0, useDownShift_1.default)({ setQuery, onChange, items, onSubmit, cioClient, previousQuery });
28
+ // Get autocomplete sections (autocomplete + recommendations + custom)
29
+ const { activeSections, activeSectionsWithData, zeroStateActiveSections } = (0, useSections_1.default)(query, cioClient, sections, zeroStateSections, advancedParameters);
30
+ // Get dropdown items array from active sections (autocomplete + recommendations + custom)
31
+ const items = (0, useItems_1.default)(activeSectionsWithData);
32
+ const downshift = (0, useDownShift_1.default)({ setQuery, items, onSubmit, cioClient, previousQuery });
67
33
  const { isOpen, getMenuProps, getLabelProps, openMenu, closeMenu, highlightedIndex } = downshift;
34
+ // Log console errors
35
+ (0, useConsoleErrors_1.default)(sections, activeSections);
68
36
  return {
69
37
  query,
70
38
  sections: activeSectionsWithData,
@@ -78,12 +46,19 @@ const useCioAutocomplete = (options) => {
78
46
  const sectionItemTestId = `cio-item-${sectionId === null || sectionId === void 0 ? void 0 : sectionId.replace(' ', '')}`;
79
47
  return Object.assign(Object.assign({}, downshift.getItemProps({ item, index })), { className: `cio-item ${sectionItemTestId}`, 'data-testid': sectionItemTestId });
80
48
  },
81
- getInputProps: () => (Object.assign(Object.assign({}, downshift.getInputProps()), { value: query, onFocus: () => {
49
+ getInputProps: () => (Object.assign(Object.assign({}, downshift.getInputProps({
50
+ onChange: (e) => {
51
+ setQuery(e.target.value);
52
+ if (onChange) {
53
+ onChange(e.target.value);
54
+ }
55
+ },
56
+ })), { value: query, onFocus: () => {
82
57
  var _a;
83
58
  if (options.onFocus) {
84
59
  options.onFocus();
85
60
  }
86
- if (zeroStateSectionsActive && openOnFocus !== false) {
61
+ if (zeroStateActiveSections && openOnFocus !== false) {
87
62
  downshift.openMenu();
88
63
  }
89
64
  if (query === null || query === void 0 ? void 0 : query.length) {
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const react_1 = require("react");
4
+ const useConsoleErrors = (sections, zeroStateSections) => {
5
+ (0, react_1.useEffect)(() => {
6
+ if (sections && !Array.isArray(sections)) {
7
+ // eslint-disable-next-line
8
+ console.error('useCioAutocomplete expects sections to reference an array of section configuration objects');
9
+ }
10
+ if (zeroStateSections && !Array.isArray(zeroStateSections)) {
11
+ // eslint-disable-next-line
12
+ console.error('useCioAutocomplete expects zeroStateSections to reference an array of section configuration objects');
13
+ }
14
+ }, [sections, zeroStateSections]);
15
+ };
16
+ exports.default = useConsoleErrors;
@@ -45,18 +45,24 @@ const useDebouncedFetchSection = (query, cioClient, autocompleteSections, advanc
45
45
  autocompleteParameters.resultsPerSection = autocompleteSections.reduce((acc, sectionConfig) => (Object.assign(Object.assign({}, acc), { [sectionConfig.identifier]: (sectionConfig === null || sectionConfig === void 0 ? void 0 : sectionConfig.numResults) || 8 })), {});
46
46
  }
47
47
  (0, react_1.useEffect)(() => {
48
- if (debouncedSearchTerm) {
49
- cioClient === null || cioClient === void 0 ? void 0 : cioClient.autocomplete.getAutocompleteResults(debouncedSearchTerm, autocompleteParameters).then((response) => {
50
- const newSectionsData = transformResponse(response, {
51
- numTermsWithGroupSuggestions,
52
- numGroupsSuggestedPerTerm,
53
- });
54
- setSectionsData(newSectionsData);
55
- });
56
- }
57
- else if (!debouncedSearchTerm) {
58
- setSectionsData({});
59
- }
48
+ (() => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
49
+ if (debouncedSearchTerm.trim()) {
50
+ try {
51
+ const response = yield (cioClient === null || cioClient === void 0 ? void 0 : cioClient.autocomplete.getAutocompleteResults(debouncedSearchTerm, autocompleteParameters));
52
+ const newSectionsData = transformResponse(response, {
53
+ numTermsWithGroupSuggestions,
54
+ numGroupsSuggestedPerTerm,
55
+ });
56
+ setSectionsData(newSectionsData);
57
+ }
58
+ catch (error) {
59
+ console.log(error);
60
+ }
61
+ }
62
+ else if (!debouncedSearchTerm) {
63
+ setSectionsData({});
64
+ }
65
+ }))();
60
66
  }, [debouncedSearchTerm, cioClient, numTermsWithGroupSuggestions, numGroupsSuggestedPerTerm]);
61
67
  return sectionsData;
62
68
  };
@@ -1,18 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
3
  const downshift_1 = require("downshift");
5
4
  let idCounter = 0;
6
- const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = '', onChange, }) => (0, downshift_1.useCombobox)({
5
+ const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = '' }) => (0, downshift_1.useCombobox)({
7
6
  id: `cio-autocomplete-${idCounter++}`,
8
7
  items,
9
8
  itemToString: (item) => (item === null || item === void 0 ? void 0 : item.value) || '',
10
- onInputValueChange: ({ inputValue = '' }) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
11
- setQuery(inputValue);
12
- if (onChange) {
13
- onChange(inputValue);
14
- }
15
- }),
16
9
  onSelectedItemChange({ selectedItem }) {
17
10
  var _a;
18
11
  if (selectedItem) {
@@ -22,7 +22,12 @@ const useFetchRecommendationPod = (cioClient, recommendationPods) => {
22
22
  });
23
23
  }
24
24
  });
25
- setRecommendationResults(recommendationPodResults);
25
+ try {
26
+ setRecommendationResults(recommendationPodResults);
27
+ }
28
+ catch (error) {
29
+ console.log(error);
30
+ }
26
31
  });
27
32
  fetchRecommendationResults();
28
33
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const useItems = (activeSectionsWithData) => {
4
+ const items = [];
5
+ activeSectionsWithData === null || activeSectionsWithData === void 0 ? void 0 : activeSectionsWithData.forEach((config) => {
6
+ if (config === null || config === void 0 ? void 0 : config.data) {
7
+ items.push(...config.data);
8
+ }
9
+ });
10
+ return items;
11
+ };
12
+ exports.default = useItems;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = require("react");
5
+ const utils_1 = require("../utils");
6
+ const useDebouncedFetchSections_1 = tslib_1.__importDefault(require("./useDebouncedFetchSections"));
7
+ const useFetchRecommendationPod_1 = tslib_1.__importDefault(require("./useFetchRecommendationPod"));
8
+ function useSections(query, cioClient, sections, zeroStateSections, advancedParameters) {
9
+ const zeroStateActiveSections = !query.length && zeroStateSections;
10
+ const [activeSections, setActiveSections] = (0, react_1.useState)(zeroStateActiveSections ? zeroStateSections : sections);
11
+ const autocompleteSections = activeSections === null || activeSections === void 0 ? void 0 : activeSections.filter((config) => config.type === 'autocomplete' || !config.type);
12
+ const recommendationsSections = activeSections === null || activeSections === void 0 ? void 0 : activeSections.filter((config) => config.type === 'recommendations');
13
+ // Fetch Autocomplete Results
14
+ const autocompleteResults = (0, useDebouncedFetchSections_1.default)(query, cioClient, autocompleteSections, advancedParameters);
15
+ // Fetch Recommendations Results
16
+ const recommendationsResults = (0, useFetchRecommendationPod_1.default)(cioClient, recommendationsSections);
17
+ const sectionResults = Object.assign(Object.assign({}, autocompleteResults), recommendationsResults);
18
+ const activeSectionsWithData = (0, utils_1.getActiveSectionsWithData)(activeSections, sectionResults);
19
+ (0, react_1.useEffect)(() => {
20
+ setActiveSections(zeroStateActiveSections ? zeroStateSections : sections);
21
+ }, [query, sections, zeroStateSections, zeroStateActiveSections]);
22
+ (0, react_1.useEffect)(() => {
23
+ if (sections && !Array.isArray(sections)) {
24
+ setActiveSections([]);
25
+ }
26
+ if (zeroStateSections && !Array.isArray(zeroStateSections)) {
27
+ setActiveSections([]);
28
+ }
29
+ }, [sections, zeroStateSections]);
30
+ return {
31
+ activeSections,
32
+ activeSectionsWithData,
33
+ zeroStateActiveSections,
34
+ };
35
+ }
36
+ exports.default = useSections;
package/lib/cjs/utils.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCioClient = exports.disableStoryActions = exports.stringifyWithDefaults = exports.defaultArgumentsCode = exports.defaultOnSubmitCode = exports.getStoryParams = exports.sleep = exports.clearConstructorRequests = exports.isTrackingRequestSent = exports.camelToStartCase = exports.getItemPosition = void 0;
3
+ exports.getActiveSectionsWithData = exports.getCioClient = exports.disableStoryActions = exports.stringifyWithDefaults = exports.functionStrings = exports.getStoryParams = exports.sleep = exports.clearConstructorRequests = exports.isTrackingRequestSent = exports.camelToStartCase = exports.getItemPosition = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const constructorio_client_javascript_1 = tslib_1.__importDefault(require("@constructor-io/constructorio-client-javascript"));
6
+ const typeGuards_1 = require("./typeGuards");
6
7
  const getItemPosition = ({ item, items }) => {
7
8
  var _a;
8
9
  const index = items.findIndex((itemInFlatList) => (itemInFlatList === null || itemInFlatList === void 0 ? void 0 : itemInFlatList.id) === (item === null || item === void 0 ? void 0 : item.id));
@@ -57,23 +58,23 @@ ${templateCode}
57
58
  };
58
59
  };
59
60
  exports.getStoryParams = getStoryParams;
60
- exports.defaultOnSubmitCode = `"onSubmit": (submitEvent) => console.dir(submitEvent)`;
61
- const defaultArgumentsCode = (apiKey) => `"apiKey": "${apiKey}",
62
- ${exports.defaultOnSubmitCode}`;
63
- exports.defaultArgumentsCode = defaultArgumentsCode;
61
+ exports.functionStrings = {
62
+ onSubmit: `(submitEvent) => console.dir(submitEvent)`,
63
+ };
64
64
  const stringifyWithDefaults = (obj) => {
65
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
66
- const { apiKey, onSubmit } = obj, rest = tslib_1.__rest(obj, ["apiKey", "onSubmit"]);
67
- let res;
68
- if (Object.keys(rest).length > 0) {
69
- res = JSON.stringify(rest, null, ' ');
70
- }
71
- else {
72
- res = `{
73
- }`;
74
- }
75
- res = res.replace('{', `{
76
- ${(0, exports.defaultArgumentsCode)(apiKey)}`);
65
+ // Stringify non-function values normally. Add a template block for functions to be replaced later
66
+ let res = JSON.stringify(obj, (key, value) => (value instanceof Function ? `${key}_CODE` : value), ' ');
67
+ // Replace template blocks with function strings
68
+ Array.from(res.matchAll(/"(\w*)_CODE"/g)).forEach((match) => {
69
+ const [codePlaceholder, key] = match;
70
+ const functionString = exports.functionStrings[key];
71
+ if (functionString) {
72
+ res = res.replaceAll(codePlaceholder, functionString);
73
+ }
74
+ else {
75
+ console.error(`Function string for ${key} not found.`); // eslint-disable-line
76
+ }
77
+ });
77
78
  return res;
78
79
  };
79
80
  exports.stringifyWithDefaults = stringifyWithDefaults;
@@ -92,3 +93,21 @@ const getCioClient = (apiKey) => {
92
93
  return null;
93
94
  };
94
95
  exports.getCioClient = getCioClient;
96
+ const getActiveSectionsWithData = (activeSections, sectionResults) => {
97
+ const activeSectionsWithData = [];
98
+ activeSections === null || activeSections === void 0 ? void 0 : activeSections.forEach((config) => {
99
+ const { identifier } = config;
100
+ let data;
101
+ if ((0, typeGuards_1.isCustomSection)(config)) {
102
+ data = config.data;
103
+ }
104
+ else {
105
+ data = sectionResults[identifier];
106
+ }
107
+ if (Array.isArray(data)) {
108
+ activeSectionsWithData.push(Object.assign(Object.assign({}, config), { data }));
109
+ }
110
+ });
111
+ return activeSectionsWithData;
112
+ };
113
+ exports.getActiveSectionsWithData = getActiveSectionsWithData;
@@ -1,11 +1,11 @@
1
1
  import { useState } from 'react';
2
2
  import useCioClient from './useCioClient';
3
3
  import useDownShift from './useDownShift';
4
- import useDebouncedFetchSection from './useDebouncedFetchSections';
5
- import useFetchRecommendationPod from './useFetchRecommendationPod';
6
4
  import usePrevious from './usePrevious';
7
5
  import { getItemPosition } from '../utils';
8
- import { isCustomSection } from '../typeGuards';
6
+ import useConsoleErrors from './useConsoleErrors';
7
+ import useSections from './useSections';
8
+ import useItems from './useItems';
9
9
  export const defaultSections = [
10
10
  {
11
11
  identifier: 'Search Suggestions',
@@ -17,50 +17,18 @@ export const defaultSections = [
17
17
  },
18
18
  ];
19
19
  const useCioAutocomplete = (options) => {
20
- const defaultPlaceholder = 'What can we help you find today?';
21
- const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, placeholder = defaultPlaceholder, sections = defaultSections, zeroStateSections, autocompleteClassName = 'cio-autocomplete', advancedParameters = {}, } = options;
20
+ const { onSubmit, onChange, openOnFocus, apiKey, cioJsClient, placeholder = 'What can we help you find today?', sections = defaultSections, zeroStateSections, autocompleteClassName = 'cio-autocomplete', advancedParameters = {}, } = options;
22
21
  const [query, setQuery] = useState('');
23
22
  const previousQuery = usePrevious(query);
24
23
  const cioClient = useCioClient({ apiKey, cioJsClient });
25
- const zeroStateSectionsActive = !query.length && zeroStateSections;
26
- let activeSections = zeroStateSectionsActive ? zeroStateSections : sections;
27
- if (sections && !Array.isArray(sections)) {
28
- // eslint-disable-next-line
29
- console.error('useCioAutocomplete expects sections to reference an array of section configuration objects');
30
- activeSections = [];
31
- }
32
- if (zeroStateSections && !Array.isArray(zeroStateSections)) {
33
- // eslint-disable-next-line
34
- console.error('useCioAutocomplete expects zeroStateSections to reference an array of section configuration objects');
35
- activeSections = [];
36
- }
37
- const autocompleteSections = activeSections?.filter((config) => config.type === 'autocomplete' || !config.type);
38
- const recommendationsSections = activeSections?.filter((config) => config.type === 'recommendations');
39
- const autocompleteResults = useDebouncedFetchSection(query, cioClient, autocompleteSections, advancedParameters);
40
- const recommendationsResults = useFetchRecommendationPod(cioClient, recommendationsSections);
41
- const sectionResults = { ...autocompleteResults, ...recommendationsResults };
42
- const activeSectionsWithData = [];
43
- activeSections?.forEach((config) => {
44
- const { identifier } = config;
45
- let data;
46
- if (isCustomSection(config)) {
47
- data = config.data;
48
- }
49
- else {
50
- data = sectionResults[identifier];
51
- }
52
- if (Array.isArray(data)) {
53
- activeSectionsWithData.push({ ...config, data });
54
- }
55
- });
56
- const items = [];
57
- activeSectionsWithData?.forEach((config) => {
58
- if (config?.data) {
59
- items.push(...config.data);
60
- }
61
- });
62
- const downshift = useDownShift({ setQuery, onChange, items, onSubmit, cioClient, previousQuery });
24
+ // Get autocomplete sections (autocomplete + recommendations + custom)
25
+ const { activeSections, activeSectionsWithData, zeroStateActiveSections } = useSections(query, cioClient, sections, zeroStateSections, advancedParameters);
26
+ // Get dropdown items array from active sections (autocomplete + recommendations + custom)
27
+ const items = useItems(activeSectionsWithData);
28
+ const downshift = useDownShift({ setQuery, items, onSubmit, cioClient, previousQuery });
63
29
  const { isOpen, getMenuProps, getLabelProps, openMenu, closeMenu, highlightedIndex } = downshift;
30
+ // Log console errors
31
+ useConsoleErrors(sections, activeSections);
64
32
  return {
65
33
  query,
66
34
  sections: activeSectionsWithData,
@@ -83,13 +51,20 @@ const useCioAutocomplete = (options) => {
83
51
  };
84
52
  },
85
53
  getInputProps: () => ({
86
- ...downshift.getInputProps(),
54
+ ...downshift.getInputProps({
55
+ onChange: (e) => {
56
+ setQuery(e.target.value);
57
+ if (onChange) {
58
+ onChange(e.target.value);
59
+ }
60
+ },
61
+ }),
87
62
  value: query,
88
63
  onFocus: () => {
89
64
  if (options.onFocus) {
90
65
  options.onFocus();
91
66
  }
92
- if (zeroStateSectionsActive && openOnFocus !== false) {
67
+ if (zeroStateActiveSections && openOnFocus !== false) {
93
68
  downshift.openMenu();
94
69
  }
95
70
  if (query?.length) {
@@ -0,0 +1,14 @@
1
+ import { useEffect } from 'react';
2
+ const useConsoleErrors = (sections, zeroStateSections) => {
3
+ useEffect(() => {
4
+ if (sections && !Array.isArray(sections)) {
5
+ // eslint-disable-next-line
6
+ console.error('useCioAutocomplete expects sections to reference an array of section configuration objects');
7
+ }
8
+ if (zeroStateSections && !Array.isArray(zeroStateSections)) {
9
+ // eslint-disable-next-line
10
+ console.error('useCioAutocomplete expects zeroStateSections to reference an array of section configuration objects');
11
+ }
12
+ }, [sections, zeroStateSections]);
13
+ };
14
+ export default useConsoleErrors;
@@ -49,20 +49,24 @@ const useDebouncedFetchSection = (query, cioClient, autocompleteSections, advanc
49
49
  }), {});
50
50
  }
51
51
  useEffect(() => {
52
- if (debouncedSearchTerm) {
53
- cioClient?.autocomplete
54
- .getAutocompleteResults(debouncedSearchTerm, autocompleteParameters)
55
- .then((response) => {
56
- const newSectionsData = transformResponse(response, {
57
- numTermsWithGroupSuggestions,
58
- numGroupsSuggestedPerTerm,
59
- });
60
- setSectionsData(newSectionsData);
61
- });
62
- }
63
- else if (!debouncedSearchTerm) {
64
- setSectionsData({});
65
- }
52
+ (async () => {
53
+ if (debouncedSearchTerm.trim()) {
54
+ try {
55
+ const response = await cioClient?.autocomplete.getAutocompleteResults(debouncedSearchTerm, autocompleteParameters);
56
+ const newSectionsData = transformResponse(response, {
57
+ numTermsWithGroupSuggestions,
58
+ numGroupsSuggestedPerTerm,
59
+ });
60
+ setSectionsData(newSectionsData);
61
+ }
62
+ catch (error) {
63
+ console.log(error);
64
+ }
65
+ }
66
+ else if (!debouncedSearchTerm) {
67
+ setSectionsData({});
68
+ }
69
+ })();
66
70
  }, [debouncedSearchTerm, cioClient, numTermsWithGroupSuggestions, numGroupsSuggestedPerTerm]);
67
71
  return sectionsData;
68
72
  };
@@ -1,15 +1,9 @@
1
1
  import { useCombobox } from 'downshift';
2
2
  let idCounter = 0;
3
- const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = '', onChange, }) => useCombobox({
3
+ const useDownShift = ({ setQuery, items, onSubmit, cioClient, previousQuery = '' }) => useCombobox({
4
4
  id: `cio-autocomplete-${idCounter++}`,
5
5
  items,
6
6
  itemToString: (item) => item?.value || '',
7
- onInputValueChange: async ({ inputValue = '' }) => {
8
- setQuery(inputValue);
9
- if (onChange) {
10
- onChange(inputValue);
11
- }
12
- },
13
7
  onSelectedItemChange({ selectedItem }) {
14
8
  if (selectedItem) {
15
9
  setQuery(selectedItem.value || '');
@@ -17,7 +17,12 @@ const useFetchRecommendationPod = (cioClient, recommendationPods) => {
17
17
  }));
18
18
  }
19
19
  });
20
- setRecommendationResults(recommendationPodResults);
20
+ try {
21
+ setRecommendationResults(recommendationPodResults);
22
+ }
23
+ catch (error) {
24
+ console.log(error);
25
+ }
21
26
  };
22
27
  fetchRecommendationResults();
23
28
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -0,0 +1,10 @@
1
+ const useItems = (activeSectionsWithData) => {
2
+ const items = [];
3
+ activeSectionsWithData?.forEach((config) => {
4
+ if (config?.data) {
5
+ items.push(...config.data);
6
+ }
7
+ });
8
+ return items;
9
+ };
10
+ export default useItems;
@@ -0,0 +1,32 @@
1
+ import { useEffect, useState } from 'react';
2
+ import { getActiveSectionsWithData } from '../utils';
3
+ import useDebouncedFetchSection from './useDebouncedFetchSections';
4
+ import useFetchRecommendationPod from './useFetchRecommendationPod';
5
+ export default function useSections(query, cioClient, sections, zeroStateSections, advancedParameters) {
6
+ const zeroStateActiveSections = !query.length && zeroStateSections;
7
+ const [activeSections, setActiveSections] = useState(zeroStateActiveSections ? zeroStateSections : sections);
8
+ const autocompleteSections = activeSections?.filter((config) => config.type === 'autocomplete' || !config.type);
9
+ const recommendationsSections = activeSections?.filter((config) => config.type === 'recommendations');
10
+ // Fetch Autocomplete Results
11
+ const autocompleteResults = useDebouncedFetchSection(query, cioClient, autocompleteSections, advancedParameters);
12
+ // Fetch Recommendations Results
13
+ const recommendationsResults = useFetchRecommendationPod(cioClient, recommendationsSections);
14
+ const sectionResults = { ...autocompleteResults, ...recommendationsResults };
15
+ const activeSectionsWithData = getActiveSectionsWithData(activeSections, sectionResults);
16
+ useEffect(() => {
17
+ setActiveSections(zeroStateActiveSections ? zeroStateSections : sections);
18
+ }, [query, sections, zeroStateSections, zeroStateActiveSections]);
19
+ useEffect(() => {
20
+ if (sections && !Array.isArray(sections)) {
21
+ setActiveSections([]);
22
+ }
23
+ if (zeroStateSections && !Array.isArray(zeroStateSections)) {
24
+ setActiveSections([]);
25
+ }
26
+ }, [sections, zeroStateSections]);
27
+ return {
28
+ activeSections,
29
+ activeSectionsWithData,
30
+ zeroStateActiveSections,
31
+ };
32
+ }
package/lib/mjs/utils.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import ConstructorIOClient from '@constructor-io/constructorio-client-javascript';
2
+ import { isCustomSection } from './typeGuards';
2
3
  export const getItemPosition = ({ item, items }) => {
3
4
  const index = items.findIndex((itemInFlatList) => itemInFlatList?.id === item?.id);
4
5
  const sectionId = items[index]?.section;
@@ -44,22 +45,23 @@ ${templateCode}
44
45
  },
45
46
  };
46
47
  };
47
- export const defaultOnSubmitCode = `"onSubmit": (submitEvent) => console.dir(submitEvent)`;
48
- export const defaultArgumentsCode = (apiKey) => `"apiKey": "${apiKey}",
49
- ${defaultOnSubmitCode}`;
48
+ export const functionStrings = {
49
+ onSubmit: `(submitEvent) => console.dir(submitEvent)`,
50
+ };
50
51
  export const stringifyWithDefaults = (obj) => {
51
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
52
- const { apiKey, onSubmit, ...rest } = obj;
53
- let res;
54
- if (Object.keys(rest).length > 0) {
55
- res = JSON.stringify(rest, null, ' ');
56
- }
57
- else {
58
- res = `{
59
- }`;
60
- }
61
- res = res.replace('{', `{
62
- ${defaultArgumentsCode(apiKey)}`);
52
+ // Stringify non-function values normally. Add a template block for functions to be replaced later
53
+ let res = JSON.stringify(obj, (key, value) => (value instanceof Function ? `${key}_CODE` : value), ' ');
54
+ // Replace template blocks with function strings
55
+ Array.from(res.matchAll(/"(\w*)_CODE"/g)).forEach((match) => {
56
+ const [codePlaceholder, key] = match;
57
+ const functionString = functionStrings[key];
58
+ if (functionString) {
59
+ res = res.replaceAll(codePlaceholder, functionString);
60
+ }
61
+ else {
62
+ console.error(`Function string for ${key} not found.`); // eslint-disable-line
63
+ }
64
+ });
63
65
  return res;
64
66
  };
65
67
  export const disableStoryActions = (story) => {
@@ -75,3 +77,20 @@ export const getCioClient = (apiKey) => {
75
77
  }
76
78
  return null;
77
79
  };
80
+ export const getActiveSectionsWithData = (activeSections, sectionResults) => {
81
+ const activeSectionsWithData = [];
82
+ activeSections?.forEach((config) => {
83
+ const { identifier } = config;
84
+ let data;
85
+ if (isCustomSection(config)) {
86
+ data = config.data;
87
+ }
88
+ else {
89
+ data = sectionResults[identifier];
90
+ }
91
+ if (Array.isArray(data)) {
92
+ activeSectionsWithData.push({ ...config, data });
93
+ }
94
+ });
95
+ return activeSectionsWithData;
96
+ };
@@ -1,9 +1,9 @@
1
- import { CioAutocompleteProps, Item, Section, UserDefinedSection } from '../types';
1
+ import { CioAutocompleteProps, UserDefinedSection } from '../types';
2
2
  export declare const defaultSections: UserDefinedSection[];
3
3
  export type UseCioAutocompleteOptions = Omit<CioAutocompleteProps, 'children'>;
4
4
  declare const useCioAutocomplete: (options: UseCioAutocompleteOptions) => {
5
5
  query: string;
6
- sections: Section[];
6
+ sections: import("../types").Section[];
7
7
  isOpen: boolean;
8
8
  getMenuProps: () => any;
9
9
  getLabelProps: (options?: import("downshift").UseComboboxGetLabelPropsOptions | undefined) => any;
@@ -21,6 +21,6 @@ declare const useCioAutocomplete: (options: UseCioAutocompleteOptions) => {
21
21
  setQuery: import("react").Dispatch<import("react").SetStateAction<string>>;
22
22
  cioClient: import("@constructor-io/constructorio-client-javascript/lib/types/types").Nullable<import("@constructor-io/constructorio-client-javascript")>;
23
23
  autocompleteClassName: string;
24
- selectedItem: Item;
24
+ selectedItem: import("../types").Item;
25
25
  };
26
26
  export default useCioAutocomplete;
@@ -0,0 +1,2 @@
1
+ declare const useConsoleErrors: (sections: any, zeroStateSections: any) => void;
2
+ export default useConsoleErrors;
@@ -9,7 +9,6 @@ type UseDownShiftOptions = {
9
9
  onSubmit: OnSubmit;
10
10
  previousQuery?: string;
11
11
  cioClient: Nullable<ConstructorIOClient>;
12
- onChange?: (string: any) => void;
13
12
  };
14
13
  export type DownShift = UseComboboxReturnValue<Item>;
15
14
  type UseDownShift = (options: UseDownShiftOptions) => DownShift;