impact-chatbot 2.3.59 → 2.3.61

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/index.cjs.js CHANGED
@@ -5773,7 +5773,7 @@ const TableContent = ({ bodyText }) => {
5773
5773
  }
5774
5774
  }, [table_config]);
5775
5775
  React.useEffect(() => {
5776
- if (!is_server_side && !lodash.isEmpty(rowData)) {
5776
+ if (!is_server_side && !lodash.isEmpty(row_data)) {
5777
5777
  setRowData(row_data);
5778
5778
  }
5779
5779
  }, [row_data]);
@@ -5831,12 +5831,12 @@ const TableContent = ({ bodyText }) => {
5831
5831
  const handleModalClose = () => {
5832
5832
  setIsModalOpen(false);
5833
5833
  };
5834
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(impactUiV3.Modal, { className: "test-modal", onClose: handleModalClose, onPrimaryButtonClick: () => { }, onSecondaryButtonClick: handleModalClose, open: isModalOpen, size: "large", title: "", children: jsxRuntime.jsx("div", { style: { width: '100%', height: '70vh' }, children: jsxRuntime.jsx(AgGridComponent, { columns: columns, rowdata: is_server_side ? undefined : rowData, pagination: true, paginationPageSize: is_server_side ? page_size : 20, suppressFieldDotNotation: true, domLayout: "normal", sizeColumnsToFitFlag: true, showSaveTableConfig: false, showSearchModalBtn: false, hideFormatSideBar: true, uniqueRowId: unique_id, selectAllHeaderComponent: select_all_component, onSelectionChanged: onSelectionChanged, hideTableSetting: hide_table_setting, downloadAsExcel: is_server_side ? false : true, tableHeader: display_name, ...(is_server_side && {
5834
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(impactUiV3.Modal, { className: "test-modal", onClose: handleModalClose, onPrimaryButtonClick: () => { }, onSecondaryButtonClick: handleModalClose, open: isModalOpen, size: "large", title: "", children: jsxRuntime.jsx("div", { style: { width: '100%', height: '70vh' }, children: jsxRuntime.jsx(AgGridComponent, { columns: columns, rowdata: is_server_side ? null : rowData, pagination: true, paginationPageSize: is_server_side ? page_size : 20, suppressFieldDotNotation: true, domLayout: "normal", sizeColumnsToFitFlag: true, showSaveTableConfig: false, showSearchModalBtn: false, hideFormatSideBar: true, uniqueRowId: unique_id, selectAllHeaderComponent: select_all_component, onSelectionChanged: onSelectionChanged, hideTableSetting: hide_table_setting, downloadAsExcel: is_server_side ? false : true, tableHeader: display_name, ...(is_server_side && {
5835
5835
  manualCallBack: serverSideManualCallBack,
5836
5836
  rowModelType: "serverSide",
5837
5837
  serverSideStoreType: "partial",
5838
5838
  cacheBlockSize: page_size,
5839
- }) }) }) }), jsxRuntime.jsx("div", { style: { width: '100%', marginTop: '10px' }, children: jsxRuntime.jsx(AgGridComponent, { columns: columns, rowdata: is_server_side ? undefined : rowData, pagination: true, paginationPageSize: is_server_side ? page_size : 10, suppressFieldDotNotation: true, domLayout: "autoHeight", customClass: "bot_table_auto_height", sizeColumnsToFitFlag: true, showSaveTableConfig: false, showSearchModalBtn: false, hideFormatSideBar: true, uniqueRowId: unique_id, selectAllHeaderComponent: select_all_component, onSelectionChanged: onSelectionChanged, hideTableSetting: hide_table_setting, customSystemButton: getTopRightOptions(), customSystemButtonWithDownload: !is_server_side, topRightOptions: null, downloadAsExcel: is_server_side ? false : true, tableHeader: display_name, ...(is_server_side && {
5839
+ }) }) }) }), jsxRuntime.jsx("div", { style: { width: '100%', marginTop: '10px' }, children: jsxRuntime.jsx(AgGridComponent, { columns: columns, rowdata: is_server_side ? null : rowData, pagination: true, paginationPageSize: is_server_side ? page_size : 10, suppressFieldDotNotation: true, domLayout: "autoHeight", customClass: "bot_table_auto_height", sizeColumnsToFitFlag: true, showSaveTableConfig: false, showSearchModalBtn: false, hideFormatSideBar: true, uniqueRowId: unique_id, selectAllHeaderComponent: select_all_component, onSelectionChanged: onSelectionChanged, hideTableSetting: hide_table_setting, customSystemButton: getTopRightOptions(), customSystemButtonWithDownload: !is_server_side, topRightOptions: null, downloadAsExcel: is_server_side ? false : true, tableHeader: display_name, ...(is_server_side && {
5840
5840
  manualCallBack: serverSideManualCallBack,
5841
5841
  rowModelType: "serverSide",
5842
5842
  serverSideStoreType: "partial",
@@ -6066,6 +6066,563 @@ var SvgReasoningIcon = function SvgReasoningIcon(props) {
6066
6066
  })))));
6067
6067
  };
6068
6068
 
6069
+ /**
6070
+ * Generic hook for cross-filter cascading functionality.
6071
+ * When a filter's value changes, downstream filters' options are re-fetched
6072
+ * with the current selections of upstream filters included in the payload.
6073
+ *
6074
+ * @param {Object} config
6075
+ * @param {Array} config.filters - Array of filter configs. Each must have at minimum:
6076
+ * { paramName, dimension?, column_name?, attribute_name?, display_type?, ... }
6077
+ * The order in this array determines the cascading hierarchy (index 0 = most upstream).
6078
+ * @param {Function} config.fetchOptionsFn - Async function to fetch options for a filter.
6079
+ * Signature: (filterConfig, existingSelections, allFilters) => Promise<Array<{label, value}>>
6080
+ * - filterConfig: the config of the filter whose options we're fetching
6081
+ * - existingSelections: array of { attributeName, filterName, values, checkAll } for upstream filters
6082
+ * - allFilters: the full filters array (for reference/lookup)
6083
+ * @param {Object} config.initialSelections - Optional. { paramName: value[] } to preload selections.
6084
+ * @param {boolean} config.fetchOnMount - Whether to fetch initial options for all filters on mount. Default: true.
6085
+ * @param {Function} config.onSelectionChange - Optional callback fired after any filter value changes.
6086
+ * Signature: (paramName, selectedValues, allSelections) => void
6087
+ *
6088
+ * @returns {Object}
6089
+ * - optionsMap: { paramName: Array<{label, value}> } — current available options per filter
6090
+ * - loadingMap: { paramName: boolean } — loading state per filter
6091
+ * - selectionsMap: { paramName: value[] } — current selections per filter
6092
+ * - onFilterChange: (paramName, selectedValues) => void — call when user changes a filter
6093
+ * - resetAll: () => void — reset all selections and re-fetch initial options
6094
+ * - resetFilter: (paramName) => void — reset a single filter and its downstream filters
6095
+ */
6096
+ const useCrossFilterCascading = ({ filters = [], fetchOptionsFn, initialSelections = {}, fetchOnMount = true, onSelectionChange, }) => {
6097
+ // State maps
6098
+ const [optionsMap, setOptionsMap] = React.useState({});
6099
+ const [loadingMap, setLoadingMap] = React.useState({});
6100
+ const [selectionsMap, setSelectionsMap] = React.useState(() => {
6101
+ // Initialize from initialSelections
6102
+ const initial = {};
6103
+ filters.forEach((f) => {
6104
+ const paramName = f.paramName || f.param_name || f.column_name || f.attribute_name;
6105
+ initial[paramName] = initialSelections[paramName] || [];
6106
+ });
6107
+ return initial;
6108
+ });
6109
+ // Refs for latest state access in async operations
6110
+ const selectionsRef = React.useRef(selectionsMap);
6111
+ const filtersRef = React.useRef(filters);
6112
+ const fetchFnRef = React.useRef(fetchOptionsFn);
6113
+ const mountedRef = React.useRef(true);
6114
+ // Keep refs in sync
6115
+ React.useEffect(() => {
6116
+ selectionsRef.current = selectionsMap;
6117
+ }, [selectionsMap]);
6118
+ React.useEffect(() => {
6119
+ filtersRef.current = filters;
6120
+ }, [filters]);
6121
+ React.useEffect(() => {
6122
+ fetchFnRef.current = fetchOptionsFn;
6123
+ }, [fetchOptionsFn]);
6124
+ React.useEffect(() => {
6125
+ return () => {
6126
+ mountedRef.current = false;
6127
+ };
6128
+ }, []);
6129
+ /**
6130
+ * Get the paramName from a filter config object (supports multiple naming conventions)
6131
+ */
6132
+ const getParamName = React.useCallback((filter) => {
6133
+ return filter.paramName || filter.param_name || filter.column_name || filter.attribute_name;
6134
+ }, []);
6135
+ /**
6136
+ * Get the index of a filter in the hierarchy by its paramName
6137
+ */
6138
+ const getFilterIndex = React.useCallback((paramName) => {
6139
+ return filtersRef.current.findIndex((f) => getParamName(f) === paramName);
6140
+ }, [getParamName]);
6141
+ /**
6142
+ * Get all filters that are downstream (higher index) of a given filter
6143
+ */
6144
+ const getDownstreamFilters = React.useCallback((paramName) => {
6145
+ const index = getFilterIndex(paramName);
6146
+ if (index === -1)
6147
+ return [];
6148
+ return filtersRef.current.slice(index + 1);
6149
+ }, [getFilterIndex]);
6150
+ /**
6151
+ * Get all filters that are upstream (lower index) of a given filter
6152
+ */
6153
+ const getUpstreamFilters = React.useCallback((paramName) => {
6154
+ const index = getFilterIndex(paramName);
6155
+ if (index <= 0)
6156
+ return [];
6157
+ return filtersRef.current.slice(0, index);
6158
+ }, [getFilterIndex]);
6159
+ /**
6160
+ * Build the existing selections payload for upstream filters (for cascading API call)
6161
+ */
6162
+ const buildExistingSelections = React.useCallback((paramName) => {
6163
+ const upstreamFilters = getUpstreamFilters(paramName);
6164
+ const currentSelections = selectionsRef.current;
6165
+ return upstreamFilters
6166
+ .filter((f) => {
6167
+ const pName = getParamName(f);
6168
+ const vals = currentSelections[pName];
6169
+ return vals && vals.length > 0;
6170
+ })
6171
+ .map((f) => {
6172
+ const pName = getParamName(f);
6173
+ return {
6174
+ filterName: f.label || f.name || pName,
6175
+ attributeName: f.column_name || f.attribute_name || pName,
6176
+ values: currentSelections[pName] || [],
6177
+ checkAll: false,
6178
+ };
6179
+ });
6180
+ }, [getUpstreamFilters, getParamName]);
6181
+ /**
6182
+ * Fetch options for a single filter
6183
+ */
6184
+ const fetchOptionsForFilter = React.useCallback(async (filterConfig) => {
6185
+ const paramName = getParamName(filterConfig);
6186
+ if (!fetchFnRef.current)
6187
+ return;
6188
+ // Set loading
6189
+ setLoadingMap((prev) => ({ ...prev, [paramName]: true }));
6190
+ try {
6191
+ const existingSelections = buildExistingSelections(paramName);
6192
+ const options = await fetchFnRef.current(filterConfig, existingSelections, filtersRef.current);
6193
+ if (!mountedRef.current)
6194
+ return;
6195
+ // Check if the response contains extra options for other filters
6196
+ const extraOptionsMap = options?.__extraOptionsMap;
6197
+ if (extraOptionsMap && typeof extraOptionsMap === "object") {
6198
+ // Distribute extra options to matching filters
6199
+ setOptionsMap((prev) => {
6200
+ const updated = { ...prev, [paramName]: options || [] };
6201
+ Object.keys(extraOptionsMap).forEach((key) => {
6202
+ // Only populate if this key matches a known filter in our hierarchy
6203
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6204
+ if (matchingFilter) {
6205
+ const matchParamName = getParamName(matchingFilter);
6206
+ updated[matchParamName] = extraOptionsMap[key];
6207
+ }
6208
+ });
6209
+ return updated;
6210
+ });
6211
+ // Clear loading for extra filters that were populated
6212
+ setLoadingMap((prev) => {
6213
+ const updated = { ...prev, [paramName]: false };
6214
+ Object.keys(extraOptionsMap).forEach((key) => {
6215
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6216
+ if (matchingFilter) {
6217
+ updated[getParamName(matchingFilter)] = false;
6218
+ }
6219
+ });
6220
+ return updated;
6221
+ });
6222
+ }
6223
+ else {
6224
+ setOptionsMap((prev) => ({ ...prev, [paramName]: options || [] }));
6225
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6226
+ }
6227
+ }
6228
+ catch (error) {
6229
+ console.error(`[useCrossFilterCascading] Error fetching options for ${paramName}:`, error);
6230
+ if (mountedRef.current) {
6231
+ setOptionsMap((prev) => ({ ...prev, [paramName]: [] }));
6232
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6233
+ }
6234
+ }
6235
+ }, [getParamName, buildExistingSelections]);
6236
+ /**
6237
+ * Fetch options for multiple filters (used for initial load and cascade refresh)
6238
+ */
6239
+ const fetchOptionsForFilters = React.useCallback(async (filterConfigs) => {
6240
+ await Promise.all(filterConfigs.map((f) => fetchOptionsForFilter(f)));
6241
+ }, [fetchOptionsForFilter]);
6242
+ /**
6243
+ * Handle a filter value change — triggers cascading for downstream filters
6244
+ */
6245
+ const onFilterChange = React.useCallback((paramName, selectedValues) => {
6246
+ const values = Array.isArray(selectedValues) ? selectedValues : [selectedValues];
6247
+ // Update selections
6248
+ setSelectionsMap((prev) => {
6249
+ const updated = { ...prev, [paramName]: values };
6250
+ selectionsRef.current = updated;
6251
+ // Notify consumer
6252
+ if (onSelectionChange) {
6253
+ onSelectionChange(paramName, values, updated);
6254
+ }
6255
+ return updated;
6256
+ });
6257
+ // Only clear downstream if the filter is being emptied (user cleared the filter).
6258
+ // When a value is being selected/changed while downstream filters already have
6259
+ // selections, preserve them — the dropdown close handler will decide whether
6260
+ // to refetch downstream options.
6261
+ if (values.length === 0) {
6262
+ const downstreamFilters = getDownstreamFilters(paramName);
6263
+ if (downstreamFilters.length > 0) {
6264
+ // Clear downstream selections
6265
+ setSelectionsMap((prev) => {
6266
+ const updated = { ...prev };
6267
+ downstreamFilters.forEach((f) => {
6268
+ const pName = getParamName(f);
6269
+ updated[pName] = [];
6270
+ });
6271
+ selectionsRef.current = updated;
6272
+ return updated;
6273
+ });
6274
+ // Clear downstream options
6275
+ const downstreamParamNames = downstreamFilters.map(getParamName);
6276
+ setOptionsMap((prev) => {
6277
+ const updated = { ...prev };
6278
+ downstreamParamNames.forEach((pName) => {
6279
+ updated[pName] = [];
6280
+ });
6281
+ return updated;
6282
+ });
6283
+ }
6284
+ }
6285
+ }, [getDownstreamFilters, getParamName, fetchOptionsForFilter, onSelectionChange]);
6286
+ /**
6287
+ * Reset all filters — clears selections and re-fetches initial options
6288
+ */
6289
+ const resetAll = React.useCallback(() => {
6290
+ const initial = {};
6291
+ filtersRef.current.forEach((f) => {
6292
+ initial[getParamName(f)] = [];
6293
+ });
6294
+ setSelectionsMap(initial);
6295
+ selectionsRef.current = initial;
6296
+ setOptionsMap({});
6297
+ if (fetchFnRef.current && filtersRef.current.length > 0) {
6298
+ // Fetch options for the first filter (others will cascade)
6299
+ fetchOptionsForFilter(filtersRef.current[0]);
6300
+ }
6301
+ }, [getParamName, fetchOptionsForFilter]);
6302
+ /**
6303
+ * Reset a specific filter and all its downstream filters
6304
+ */
6305
+ const resetFilter = React.useCallback((paramName) => {
6306
+ const downstreamFilters = getDownstreamFilters(paramName);
6307
+ const allToReset = [paramName, ...downstreamFilters.map(getParamName)];
6308
+ setSelectionsMap((prev) => {
6309
+ const updated = { ...prev };
6310
+ allToReset.forEach((pName) => {
6311
+ updated[pName] = [];
6312
+ });
6313
+ selectionsRef.current = updated;
6314
+ return updated;
6315
+ });
6316
+ // Re-fetch options for the reset filter itself
6317
+ const filterConfig = filtersRef.current.find((f) => getParamName(f) === paramName);
6318
+ if (filterConfig) {
6319
+ fetchOptionsForFilter(filterConfig);
6320
+ }
6321
+ }, [getDownstreamFilters, getParamName, fetchOptionsForFilter]);
6322
+ /**
6323
+ * Fetch options for a specific filter on demand (e.g., when dropdown is opened)
6324
+ */
6325
+ const fetchOptions = React.useCallback((paramName) => {
6326
+ const filterConfig = filtersRef.current.find((f) => getParamName(f) === paramName);
6327
+ if (filterConfig) {
6328
+ fetchOptionsForFilter(filterConfig);
6329
+ }
6330
+ }, [getParamName, fetchOptionsForFilter]);
6331
+ /**
6332
+ * Fetch options for all downstream filters of a given filter.
6333
+ * Called when the user closes a dropdown after making a selection,
6334
+ * so downstream filters are pre-populated before the user opens them.
6335
+ */
6336
+ const fetchDownstreamOptions = React.useCallback((paramName) => {
6337
+ const downstreamFilters = getDownstreamFilters(paramName);
6338
+ if (downstreamFilters.length > 0) {
6339
+ fetchOptionsForFilters(downstreamFilters);
6340
+ }
6341
+ }, [getDownstreamFilters, fetchOptionsForFilters]);
6342
+ /**
6343
+ * Build selections payload that includes the triggering filter and all other
6344
+ * filters that have selections (used for upstream/reverse cascading).
6345
+ */
6346
+ const buildAllSelections = React.useCallback((excludeParamName) => {
6347
+ const currentSelections = selectionsRef.current;
6348
+ return filtersRef.current
6349
+ .filter((f) => {
6350
+ const pName = getParamName(f);
6351
+ if (pName === excludeParamName)
6352
+ return false;
6353
+ const vals = currentSelections[pName];
6354
+ return vals && vals.length > 0;
6355
+ })
6356
+ .map((f) => {
6357
+ const pName = getParamName(f);
6358
+ return {
6359
+ filterName: f.label || f.name || pName,
6360
+ attributeName: f.column_name || f.attribute_name || pName,
6361
+ values: currentSelections[pName] || [],
6362
+ checkAll: false,
6363
+ };
6364
+ });
6365
+ }, [getParamName]);
6366
+ /**
6367
+ * Fetch options for a single upstream filter using all current selections
6368
+ * (reverse cascading — the payload includes the triggering lower filter's values).
6369
+ */
6370
+ const fetchUpstreamFilterOptions = React.useCallback(async (filterConfig) => {
6371
+ const paramName = getParamName(filterConfig);
6372
+ if (!fetchFnRef.current)
6373
+ return;
6374
+ setLoadingMap((prev) => ({ ...prev, [paramName]: true }));
6375
+ try {
6376
+ const existingSelections = buildAllSelections(paramName);
6377
+ const options = await fetchFnRef.current(filterConfig, existingSelections, filtersRef.current);
6378
+ if (!mountedRef.current)
6379
+ return;
6380
+ // Handle extra options from multi-key response
6381
+ const extraOptionsMap = options?.__extraOptionsMap;
6382
+ if (extraOptionsMap && typeof extraOptionsMap === "object") {
6383
+ setOptionsMap((prev) => {
6384
+ const updated = { ...prev, [paramName]: options || [] };
6385
+ Object.keys(extraOptionsMap).forEach((key) => {
6386
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6387
+ if (matchingFilter) {
6388
+ updated[getParamName(matchingFilter)] = extraOptionsMap[key];
6389
+ }
6390
+ });
6391
+ return updated;
6392
+ });
6393
+ setLoadingMap((prev) => {
6394
+ const updated = { ...prev, [paramName]: false };
6395
+ Object.keys(extraOptionsMap).forEach((key) => {
6396
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6397
+ if (matchingFilter) {
6398
+ updated[getParamName(matchingFilter)] = false;
6399
+ }
6400
+ });
6401
+ return updated;
6402
+ });
6403
+ }
6404
+ else {
6405
+ setOptionsMap((prev) => ({ ...prev, [paramName]: options || [] }));
6406
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6407
+ }
6408
+ }
6409
+ catch (error) {
6410
+ console.error(`[useCrossFilterCascading] Error fetching upstream options for ${paramName}:`, error);
6411
+ if (mountedRef.current) {
6412
+ setOptionsMap((prev) => ({ ...prev, [paramName]: [] }));
6413
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6414
+ }
6415
+ }
6416
+ }, [getParamName, buildAllSelections]);
6417
+ /**
6418
+ * Fetch options for all upstream filters of a given filter.
6419
+ * Called on dropdown close to reverse-cascade — e.g., selecting Channel
6420
+ * triggers a fetch for Brand with Channel's selection in the payload.
6421
+ */
6422
+ const fetchUpstreamOptions = React.useCallback((paramName) => {
6423
+ const upstreamFilters = getUpstreamFilters(paramName);
6424
+ if (upstreamFilters.length > 0) {
6425
+ Promise.all(upstreamFilters.map((f) => fetchUpstreamFilterOptions(f)));
6426
+ }
6427
+ }, [getUpstreamFilters, fetchUpstreamFilterOptions]);
6428
+ // Fetch initial options on mount
6429
+ React.useEffect(() => {
6430
+ if (fetchOnMount && filters.length > 0 && fetchFnRef.current) {
6431
+ // Fetch options for the first filter (it has no upstream dependencies)
6432
+ fetchOptionsForFilter(filters[0]);
6433
+ }
6434
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6435
+ }, []);
6436
+ return {
6437
+ optionsMap,
6438
+ loadingMap,
6439
+ selectionsMap,
6440
+ onFilterChange,
6441
+ resetAll,
6442
+ resetFilter,
6443
+ fetchOptions,
6444
+ fetchDownstreamOptions,
6445
+ fetchUpstreamOptions,
6446
+ getParamName,
6447
+ };
6448
+ };
6449
+
6450
+ /**
6451
+ * Context for cross-filter cascading.
6452
+ * Provides cascading state and actions to child select components.
6453
+ *
6454
+ * Shape:
6455
+ * {
6456
+ * optionsMap: { paramName: Array<{label, value}> },
6457
+ * loadingMap: { paramName: boolean },
6458
+ * selectionsMap: { paramName: value[] },
6459
+ * onFilterChange: (paramName, selectedValues) => void,
6460
+ * resetAll: () => void,
6461
+ * resetFilter: (paramName) => void,
6462
+ * fetchOptions: (paramName) => void,
6463
+ * getParamName: (filterConfig) => string,
6464
+ * isEnabled: boolean, // flag to know if cascading is active
6465
+ * }
6466
+ */
6467
+ const CrossFilterContext = React.createContext(null);
6468
+ /**
6469
+ * Hook to consume cross-filter cascading context.
6470
+ * Returns null if not inside a CrossFilterProvider (graceful fallback).
6471
+ */
6472
+ const useCrossFilterContext = () => {
6473
+ return React.useContext(CrossFilterContext);
6474
+ };
6475
+
6476
+ /**
6477
+ * Provider component that wraps a group of select components to enable
6478
+ * cross-filter cascading between them.
6479
+ *
6480
+ * @param {Object} props
6481
+ * @param {Array} props.filters - Array of filter configs (ordered by hierarchy)
6482
+ * @param {Function} props.fetchOptionsFn - Async function to fetch options for a filter
6483
+ * @param {Object} props.initialSelections - Optional preloaded selections { paramName: values[] }
6484
+ * @param {boolean} props.fetchOnMount - Whether to fetch initial options on mount (default: true)
6485
+ * @param {Function} props.onSelectionChange - Optional callback on any filter change
6486
+ * @param {React.ReactNode} props.children - Child components (selects) that will consume the context
6487
+ */
6488
+ const CrossFilterProvider = ({ filters, fetchOptionsFn, initialSelections = {}, fetchOnMount = true, onSelectionChange = null, children, }) => {
6489
+ const cascadingState = useCrossFilterCascading({
6490
+ filters,
6491
+ fetchOptionsFn,
6492
+ initialSelections,
6493
+ fetchOnMount,
6494
+ onSelectionChange,
6495
+ });
6496
+ const contextValue = React.useMemo(() => ({
6497
+ ...cascadingState,
6498
+ isEnabled: true,
6499
+ }), [cascadingState]);
6500
+ return (jsxRuntime.jsx(CrossFilterContext.Provider, { value: contextValue, children: children }));
6501
+ };
6502
+
6503
+ /**
6504
+ * Adapter function that bridges the generic useCrossFilterCascading hook
6505
+ * with the existing cross-filter API used by the chatbot.
6506
+ *
6507
+ * This is the `fetchOptionsFn` passed to the CrossFilterProvider.
6508
+ *
6509
+ * @param {Object} filterConfig - The filter config for which to fetch options
6510
+ * @param {Array} existingSelections - Upstream filter selections
6511
+ * Each item: { filterName, attributeName, values, checkAll }
6512
+ * @param {Array} allFilters - Full array of all filter configs
6513
+ * @returns {Promise<Array<{label, value}>>} - Formatted options
6514
+ */
6515
+ const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], allFilters = []) => {
6516
+ try {
6517
+ const attributeName = filterConfig.column_name ||
6518
+ filterConfig.attribute_name ||
6519
+ filterConfig.param_name ||
6520
+ filterConfig.paramName;
6521
+ if (!attributeName)
6522
+ return [];
6523
+ const dimension = filterConfig.dimension || "product";
6524
+ // Build filters array from existing selections (upstream filters with values)
6525
+ const filtersArray = existingSelections.map((selection) => {
6526
+ // Find full config for this upstream filter
6527
+ const fullConfig = allFilters.find((f) => (f.column_name || f.attribute_name || f.param_name || f.paramName) === selection.attributeName);
6528
+ const selAttrName = fullConfig?.column_name ||
6529
+ fullConfig?.attribute_name ||
6530
+ fullConfig?.param_name ||
6531
+ fullConfig?.paramName ||
6532
+ selection.attributeName;
6533
+ return {
6534
+ filter_name: selection.filterName || selAttrName,
6535
+ filter_id: selAttrName,
6536
+ filter_type: "cascaded",
6537
+ dimension: fullConfig?.dimension || dimension,
6538
+ display_type: fullConfig?.display_type || "dropdown",
6539
+ check_configuration: selection.checkAll ? [{ checkAll: true, meta: {} }] : [],
6540
+ is_mandatory: fullConfig?.is_mandatory || fullConfig?.isRequired || false,
6541
+ extra: {},
6542
+ values: selection.checkAll ? [] : (selection.values || []),
6543
+ attribute_name: selAttrName,
6544
+ operator: "in",
6545
+ display_order: fullConfig?.display_order || fullConfig?.ordering || 0,
6546
+ };
6547
+ });
6548
+ const payload = {
6549
+ attributes: [
6550
+ {
6551
+ attribute_name: attributeName,
6552
+ dimension: dimension,
6553
+ filter_type: "cascaded",
6554
+ },
6555
+ ],
6556
+ filter_type: "cascaded",
6557
+ filters: filtersArray,
6558
+ is_urm_filter: true,
6559
+ screen_name: "Chatbot",
6560
+ application_code: 1,
6561
+ };
6562
+ console.log("[crossFilterAdapter] Fetching options for:", attributeName, "payload:", JSON.stringify(payload, null, 2));
6563
+ const response = await getFilterOptions(payload)();
6564
+ console.log("[crossFilterAdapter] Response for:", attributeName, "data:", response?.data?.data);
6565
+ if (response?.data?.status && response?.data?.data) {
6566
+ const responseData = response.data.data;
6567
+ const primaryValues = responseData[attributeName];
6568
+ // Format the primary filter's options
6569
+ let primaryOptions = Array.isArray(primaryValues)
6570
+ ? primaryValues.map((value) => {
6571
+ const stringValue = String(value);
6572
+ return {
6573
+ label: replaceSpecialCharacter(stringValue),
6574
+ value: stringValue,
6575
+ };
6576
+ })
6577
+ : [];
6578
+ // Check if the response contains options for other filters (multi-key response)
6579
+ const extraOptionsMap = {};
6580
+ Object.keys(responseData).forEach((key) => {
6581
+ if (key !== attributeName && Array.isArray(responseData[key])) {
6582
+ extraOptionsMap[key] = responseData[key].map((value) => {
6583
+ const stringValue = String(value);
6584
+ return {
6585
+ label: replaceSpecialCharacter(stringValue),
6586
+ value: stringValue,
6587
+ };
6588
+ });
6589
+ }
6590
+ });
6591
+ // If primary options are empty but response has data under other keys,
6592
+ // include ALL response keys in extraOptionsMap so the hook can distribute
6593
+ // them to matching filters by column_name/attribute_name lookup.
6594
+ if (primaryOptions.length === 0 && Object.keys(extraOptionsMap).length > 0) {
6595
+ // Also check if any response key matches the paramName directly
6596
+ // (e.g., paramName is "brand" but column_name sent was different)
6597
+ const altKey = Object.keys(responseData).find((key) => {
6598
+ return Array.isArray(responseData[key]) && (key === attributeName ||
6599
+ key.toLowerCase() === attributeName.toLowerCase());
6600
+ });
6601
+ if (altKey) {
6602
+ primaryOptions = responseData[altKey].map((value) => {
6603
+ const stringValue = String(value);
6604
+ return {
6605
+ label: replaceSpecialCharacter(stringValue),
6606
+ value: stringValue,
6607
+ };
6608
+ });
6609
+ delete extraOptionsMap[altKey];
6610
+ }
6611
+ }
6612
+ // Return enriched result with extra options if available
6613
+ if (Object.keys(extraOptionsMap).length > 0) {
6614
+ primaryOptions.__extraOptionsMap = extraOptionsMap;
6615
+ }
6616
+ return primaryOptions;
6617
+ }
6618
+ return [];
6619
+ }
6620
+ catch (error) {
6621
+ console.error("[crossFilterAdapter] Error fetching options:", error);
6622
+ return [];
6623
+ }
6624
+ };
6625
+
6069
6626
  const SliderContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6070
6627
  const formKey = `${messageIndex}_${bodyText?.paramName}`;
6071
6628
  const { header, headerOrentiation, inputPosition, label, max, min, required, disabled, } = bodyText;
@@ -6115,6 +6672,10 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6115
6672
  const chatbotContext = reactRedux.useSelector((state) => state.smartBotReducer.chatbotContext);
6116
6673
  const heirarchyKeyValuePairs = reactRedux.useSelector((state) => state.smartBotReducer.heirarchyKeyValuePairs);
6117
6674
  const dispatch = reactRedux.useDispatch();
6675
+ // Cross-filter cascading context (optional — graceful fallback when not wrapped)
6676
+ const crossFilterCtx = useCrossFilterContext();
6677
+ const isCascading = crossFilterCtx?.isEnabled && paramName;
6678
+ const isMountedRef = React.useRef(false);
6118
6679
  if (lodash.isEmpty(bodyText))
6119
6680
  return null;
6120
6681
  const onChange = (selectedOptions) => {
@@ -6138,6 +6699,10 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6138
6699
  // };
6139
6700
  dispatch(smartBotActions.setChatbotContext(chatbotContext));
6140
6701
  dispatch(smartBotActions.setPersistedFormValues({ [formKey]: Array.isArray(selectedOptions) ? selectedOptions : [selectedOptions] }));
6702
+ // Notify cross-filter context if cascading is active
6703
+ if (isCascading) {
6704
+ crossFilterCtx.onFilterChange(paramName, Array.isArray(value) ? value : [value]);
6705
+ }
6141
6706
  }
6142
6707
  catch (error) {
6143
6708
  console.error("Error in select handleChange", error);
@@ -6149,16 +6714,94 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6149
6714
  setCurrentSelectedOptions([]);
6150
6715
  }
6151
6716
  }, [persistedFormValues, formKey]);
6717
+ // When cross-filter context provides new options for this filter, update local state
6152
6718
  React.useEffect(() => {
6153
- allOptionsRef.current = options;
6154
- const initialSlice = formatSlice(options, 0, INITIAL_DISPLAY_COUNT);
6155
- setInitialOptions(initialSlice);
6156
- setCurrentOptions(initialSlice);
6157
- }, []);
6719
+ if (isCascading && crossFilterCtx.optionsMap[paramName]) {
6720
+ const cascadedOptions = crossFilterCtx.optionsMap[paramName];
6721
+ allOptionsRef.current = cascadedOptions;
6722
+ const initialSlice = formatSlice(cascadedOptions, 0, INITIAL_DISPLAY_COUNT);
6723
+ setInitialOptions(initialSlice);
6724
+ setCurrentOptions(initialSlice);
6725
+ }
6726
+ }, [isCascading, crossFilterCtx?.optionsMap?.[paramName]]);
6727
+ // When cascading resets downstream selections, clear local selection
6728
+ // Skip on initial mount to avoid clearing persisted values when context reinitializes
6729
+ React.useEffect(() => {
6730
+ if (!isMountedRef.current) {
6731
+ isMountedRef.current = true;
6732
+ return;
6733
+ }
6734
+ if (isCascading) {
6735
+ const cascadedSelection = crossFilterCtx.selectionsMap[paramName];
6736
+ if (cascadedSelection && cascadedSelection.length === 0 && currentSelectedOptions.length > 0) {
6737
+ setCurrentSelectedOptions([]);
6738
+ setIsAllSelected(false);
6739
+ // Also clear from chatbotContext and persistedFormValues
6740
+ chatbotContext[bodyText?.paramName] = {
6741
+ ...chatbotContext?.[bodyText?.paramName],
6742
+ [bodyText?.paramName]: [],
6743
+ updated: true,
6744
+ };
6745
+ dispatch(smartBotActions.setChatbotContext(chatbotContext));
6746
+ dispatch(smartBotActions.setPersistedFormValues({ [formKey]: [] }));
6747
+ }
6748
+ }
6749
+ }, [isCascading, crossFilterCtx?.selectionsMap?.[paramName]]);
6750
+ React.useEffect(() => {
6751
+ // Only use static options from bodyText if NOT in cascading mode
6752
+ if (!isCascading) {
6753
+ allOptionsRef.current = options;
6754
+ const initialSlice = formatSlice(options, 0, INITIAL_DISPLAY_COUNT);
6755
+ setInitialOptions(initialSlice);
6756
+ setCurrentOptions(initialSlice);
6757
+ }
6758
+ }, [isCascading]);
6158
6759
  return (jsxRuntime.jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsxRuntime.jsx(impactUiV3.Select, { currentOptions: currentOptions, setCurrentOptions: setCurrentOptions, label: heirarchyKeyValuePairs[paramName] || label, labelOrientation: labelOrientation,
6159
6760
  // inputPosition={inputPosition}
6160
6761
  // header={header}
6161
- isRequired: isRequired, isDisabled: isDisabled || isFormDisabled, handleChange: (selected) => onChange(selected), isCloseWhenClickOutside: true, setIsOpen: setIsOpen, isOpen: isOpen, selectedOptions: currentSelectedOptions, setSelectedOptions: setCurrentSelectedOptions, initialOptions: initialOptions, isMulti: isMulti, isSelectAll: isAllSelected, setIsSelectAll: setIsAllSelected, toggleSelectAll: true, isWithSearch: isMulti ? true : false, onMenuScrollToBottom: () => {
6762
+ isRequired: isRequired, isDisabled: isDisabled || isFormDisabled, isClearable: !(isDisabled || isFormDisabled), onClearAll: () => {
6763
+ setCurrentSelectedOptions([]);
6764
+ setIsAllSelected(false);
6765
+ chatbotContext[bodyText?.paramName] = {
6766
+ ...chatbotContext?.[bodyText?.paramName],
6767
+ [bodyText?.paramName]: [],
6768
+ updated: true,
6769
+ };
6770
+ dispatch(smartBotActions.setChatbotContext(chatbotContext));
6771
+ dispatch(smartBotActions.setPersistedFormValues({ [formKey]: [] }));
6772
+ // Notify cross-filter context to clear downstream filters
6773
+ if (isCascading) {
6774
+ crossFilterCtx.onFilterChange(paramName, []);
6775
+ }
6776
+ }, handleChange: (selected) => onChange(selected), isCloseWhenClickOutside: true, setIsOpen: (open) => {
6777
+ setIsOpen(open);
6778
+ if (isCascading) {
6779
+ if (open) {
6780
+ // Lazy fetch: trigger cross-filter API call when dropdown opens for the first time
6781
+ if ((!crossFilterCtx.optionsMap[paramName] || crossFilterCtx.optionsMap[paramName].length === 0) && !crossFilterCtx.loadingMap[paramName]) {
6782
+ crossFilterCtx.fetchOptions(paramName);
6783
+ }
6784
+ }
6785
+ else {
6786
+ // On dropdown close: if there's a selection, pre-fetch related filter options
6787
+ const currentSelection = crossFilterCtx.selectionsMap[paramName];
6788
+ if (currentSelection && currentSelection.length > 0) {
6789
+ // Only fetch downstream if no downstream filter already has selections
6790
+ // (avoids clearing user's existing lower-hierarchy choices)
6791
+ const hasDownstreamSelections = Object.keys(crossFilterCtx.selectionsMap).some((key) => {
6792
+ if (key === paramName)
6793
+ return false;
6794
+ const vals = crossFilterCtx.selectionsMap[key];
6795
+ return vals && vals.length > 0;
6796
+ });
6797
+ if (!hasDownstreamSelections) {
6798
+ crossFilterCtx.fetchDownstreamOptions(paramName);
6799
+ }
6800
+ crossFilterCtx.fetchUpstreamOptions(paramName);
6801
+ }
6802
+ }
6803
+ }
6804
+ }, isOpen: isOpen, selectedOptions: currentSelectedOptions, setSelectedOptions: setCurrentSelectedOptions, initialOptions: initialOptions, isMulti: isMulti, isSelectAll: isAllSelected, setIsSelectAll: setIsAllSelected, toggleSelectAll: true, isLoading: isCascading ? crossFilterCtx.loadingMap[paramName] : false, emptyMessage: isCascading && crossFilterCtx.loadingMap[paramName] ? "Loading values..." : "No options available", isWithSearch: isMulti ? true : false, onMenuScrollToBottom: () => {
6162
6805
  const allRaw = allOptionsRef.current;
6163
6806
  if (allRaw.length > 0 && currentOptions.length < allRaw.length) {
6164
6807
  const nextCount = Math.min(currentOptions.length + LOAD_MORE_COUNT, allRaw.length);
@@ -6182,10 +6825,18 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6182
6825
  };
6183
6826
  dispatch(smartBotActions.setChatbotContext(chatbotContext));
6184
6827
  dispatch(smartBotActions.setPersistedFormValues({ [formKey]: currentOptions }));
6828
+ // Notify cross-filter context if cascading is active
6829
+ if (isCascading) {
6830
+ crossFilterCtx.onFilterChange(paramName, allValues);
6831
+ }
6185
6832
  }
6186
6833
  else {
6187
6834
  setCurrentSelectedOptions([]);
6188
6835
  setIsAllSelected(false);
6836
+ // Notify cross-filter context of deselection
6837
+ if (isCascading) {
6838
+ crossFilterCtx.onFilterChange(paramName, []);
6839
+ }
6189
6840
  }
6190
6841
  }, customPlaceholderAfterSelect: isAllSelected && allOptionsRef.current.length > 0
6191
6842
  ? allOptionsRef.current.length
@@ -6399,6 +7050,8 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
6399
7050
  const persistedFormValues = reactRedux.useSelector((state) => state.smartBotReducer.persistedFormValues);
6400
7051
  const chatbotContext = reactRedux.useSelector((state) => state.smartBotReducer.chatbotContext);
6401
7052
  const stepFormStreamData = reactRedux.useSelector((state) => state.smartBotReducer.stepFormStreamData);
7053
+ const chatbotFilterOptions = reactRedux.useSelector((state) => state.smartBotReducer.chatbotFilterOptions);
7054
+ const dimensionHierarchies = reactRedux.useSelector((state) => state.userRoleManagementService?.dimensionHierarchies);
6402
7055
  const [isFormSubmitted, setIsFormSubmitted] = React.useState(false);
6403
7056
  React.useEffect(() => {
6404
7057
  if (stepFormStreamData?.status === "streaming_start") {
@@ -6505,6 +7158,77 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
6505
7158
  return false;
6506
7159
  });
6507
7160
  }, [formData, chatbotContext, persistedFormValues, messageIndex]);
7161
+ // Extract select-type filter configs from formData for cross-filter cascading
7162
+ // and sort them based on the filters_hierarchy_order from tenant config
7163
+ const crossFilterConfigs = React.useMemo(() => {
7164
+ if (!formData || !Array.isArray(formData))
7165
+ return [];
7166
+ const configs = formData
7167
+ .filter((item) => item?.type === "select" && item?.data?.param_name)
7168
+ .map((item) => {
7169
+ const data = item.data;
7170
+ const paramName = data.param_name;
7171
+ // Try to find full filter config from chatbotFilterOptions (Redux)
7172
+ const fullConfig = (chatbotFilterOptions || []).find((f) => f.column_name === paramName || f.attribute_name === paramName || f.name === paramName);
7173
+ return {
7174
+ paramName: paramName,
7175
+ param_name: paramName,
7176
+ column_name: fullConfig?.column_name || paramName,
7177
+ attribute_name: fullConfig?.attribute_name || paramName,
7178
+ dimension: fullConfig?.dimension || "product",
7179
+ display_type: fullConfig?.display_type || "dropdown",
7180
+ display_order: fullConfig?.display_order || item.ordering || 0,
7181
+ label: data.label,
7182
+ name: fullConfig?.name || data.label,
7183
+ is_mandatory: data.isRequired || false,
7184
+ };
7185
+ });
7186
+ // Sort configs based on dimensionHierarchies order.
7187
+ // Filters are sorted by their position in their dimension's hierarchy list.
7188
+ // This determines the cascading order (earlier = upstream/higher hierarchy).
7189
+ if (dimensionHierarchies && Object.keys(dimensionHierarchies).length > 0) {
7190
+ configs.sort((a, b) => {
7191
+ const aHierarchy = dimensionHierarchies[a.dimension] || [];
7192
+ const bHierarchy = dimensionHierarchies[b.dimension] || [];
7193
+ const aIndex = aHierarchy.indexOf(a.column_name) !== -1
7194
+ ? aHierarchy.indexOf(a.column_name)
7195
+ : aHierarchy.indexOf(a.attribute_name) !== -1
7196
+ ? aHierarchy.indexOf(a.attribute_name)
7197
+ : aHierarchy.indexOf(a.paramName) !== -1
7198
+ ? aHierarchy.indexOf(a.paramName)
7199
+ : 999;
7200
+ const bIndex = bHierarchy.indexOf(b.column_name) !== -1
7201
+ ? bHierarchy.indexOf(b.column_name)
7202
+ : bHierarchy.indexOf(b.attribute_name) !== -1
7203
+ ? bHierarchy.indexOf(b.attribute_name)
7204
+ : bHierarchy.indexOf(b.paramName) !== -1
7205
+ ? bHierarchy.indexOf(b.paramName)
7206
+ : 999;
7207
+ return aIndex - bIndex;
7208
+ });
7209
+ }
7210
+ return configs;
7211
+ }, [formData, chatbotFilterOptions, dimensionHierarchies]);
7212
+ // Build initial selections from chatbotContext and persistedFormValues (for restore on remount)
7213
+ const crossFilterInitialSelections = React.useMemo(() => {
7214
+ const selections = {};
7215
+ crossFilterConfigs.forEach((cfg) => {
7216
+ const ctx = chatbotContext?.[cfg.paramName];
7217
+ if (ctx && ctx.updated && ctx[cfg.paramName]) {
7218
+ const val = ctx[cfg.paramName];
7219
+ selections[cfg.paramName] = Array.isArray(val) ? val : [val];
7220
+ }
7221
+ else {
7222
+ // Fallback: check persistedFormValues for option objects
7223
+ const persistedKey = `${messageIndex}_${cfg.paramName}`;
7224
+ const persisted = persistedFormValues?.[persistedKey];
7225
+ if (persisted && Array.isArray(persisted) && persisted.length > 0) {
7226
+ selections[cfg.paramName] = persisted.map((opt) => opt.value || opt);
7227
+ }
7228
+ }
7229
+ });
7230
+ return selections;
7231
+ }, [crossFilterConfigs, chatbotContext, persistedFormValues, messageIndex]);
6508
7232
  if (!formData || !Array.isArray(formData) || formData.length === 0) {
6509
7233
  return null;
6510
7234
  }
@@ -6566,7 +7290,7 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
6566
7290
  return null;
6567
7291
  return (jsxRuntime.jsxs("div", { className: "step-form-content", children: [showSavedFilters && filterSetOptions.length > 0 && (jsxRuntime.jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsxRuntime.jsx(impactUiV3.Select, { currentOptions: filterSetCurrentOptions, setCurrentOptions: setFilterSetCurrentOptions, label: "Saved Filter Sets", labelOrientation: "top", isRequired: false, isDisabled: savedFilterDisabled, handleChange: (selected) => onFilterSetChange(selected), isCloseWhenClickOutside: true, setIsOpen: setIsFilterSetOpen, isOpen: isFilterSetOpen, selectedOptions: selectedFilterSet, setSelectedOptions: setSelectedFilterSet, initialOptions: filterSetOptions, isMulti: false, isClearable: true }) })), showSavedFilters && filterSetOptions.length > 0 && (jsxRuntime.jsx("hr", { style: { border: "none", borderTop: "1px solid #E0E0E0", margin: "12px 0" } })), jsxRuntime.jsx("div", { style: {
6568
7292
  ...(isFilterSelected && !isFormDisabled ? { pointerEvents: "none", opacity: 0.5 } : {}),
6569
- }, children: formFields }), buttonItems] }));
7293
+ }, children: crossFilterConfigs.length > 1 ? (jsxRuntime.jsx(CrossFilterProvider, { filters: crossFilterConfigs, fetchOptionsFn: fetchCrossFilterOptions, initialSelections: crossFilterInitialSelections, fetchOnMount: false, children: formFields })) : (formFields) }), buttonItems] }));
6570
7294
  };
6571
7295
 
6572
7296
  const useStyles$4 = makeStyles((theme) => ({
@@ -9490,10 +10214,7 @@ function UploadModal(props) {
9490
10214
  setSelectedFile(file);
9491
10215
  }
9492
10216
  else {
9493
- displaySnackMessages({
9494
- message: 'Please select only PDF files',
9495
- variant: 'error'
9496
- });
10217
+ displaySnackMessages('Please select only PDF files', 'error');
9497
10218
  }
9498
10219
  };
9499
10220
  const handleFileUpload = async () => {
@@ -9534,10 +10255,7 @@ function UploadModal(props) {
9534
10255
  }
9535
10256
  catch (error) {
9536
10257
  console.error("File upload error:", error);
9537
- displaySnackMessages({
9538
- message: "File upload failed",
9539
- variant: "error",
9540
- });
10258
+ displaySnackMessages("File upload failed", "error");
9541
10259
  }
9542
10260
  finally {
9543
10261
  setIsLoading(false);
@@ -13337,6 +14055,7 @@ const SmartBot = (props) => {
13337
14055
  // Dispatch hierarchy key-value pairs to store
13338
14056
  dispatch(smartBotActions.setHierarchyKeyValue(hierarchyKeyValuePairs));
13339
14057
  setFilterOptions(combinedOptions);
14058
+ dispatch(smartBotActions.setChatbotFilterOptions(combinedOptions));
13340
14059
  // Fetch saved filter sets for the plus-button menu
13341
14060
  fetchSavedFilterSets();
13342
14061
  }