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.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
2
2
  import { cloneDeep, isEmpty as isEmpty$1, isNull, isArray as isArray$1, isObject, throttle } from 'lodash';
3
3
  import * as React from 'react';
4
- import { useCallback, useState, useEffect, useRef, useMemo } from 'react';
4
+ import { useCallback, useState, useEffect, useRef, createContext, useContext, useMemo } from 'react';
5
5
  import { COMBINED_CROSS_DIMENSIONAL_API, BASE_API } from 'config/api';
6
6
  import axiosInstance from 'core/Utils/axios';
7
7
  import { tenantConfigApiCache } from 'core/actions/tenantConfigActions';
@@ -18,7 +18,7 @@ import remarkBreaks from 'remark-breaks';
18
18
  import remarkGfm from 'remark-gfm';
19
19
  import DOMPurify from 'dompurify';
20
20
  import { setSelectedFilters, setFilterConfiguration, getFilterUserConfiguration } from 'core/actions/filterAction';
21
- import { setChatbotContext, setStepFormStreamData, setMinimizedStreamData, setThinkingContext, setPersistedFormValues, clearPersistedFormValues, setCurrentAgentChatId, setHierarchyKeyValue, setSavedFilterSets } from 'core/actions/smartBotActions';
21
+ import { setChatbotContext, setStepFormStreamData, setMinimizedStreamData, setThinkingContext, setPersistedFormValues, clearPersistedFormValues, setCurrentAgentChatId, setHierarchyKeyValue, setChatbotFilterOptions, setSavedFilterSets } from 'core/actions/smartBotActions';
22
22
  import { useNavigate, useLocation } from 'react-router-dom-v5-compat';
23
23
  import RefreshIcon from '@mui/icons-material/Refresh';
24
24
  import styled from 'styled-components';
@@ -5751,7 +5751,7 @@ const TableContent = ({ bodyText }) => {
5751
5751
  }
5752
5752
  }, [table_config]);
5753
5753
  useEffect(() => {
5754
- if (!is_server_side && !isEmpty$1(rowData)) {
5754
+ if (!is_server_side && !isEmpty$1(row_data)) {
5755
5755
  setRowData(row_data);
5756
5756
  }
5757
5757
  }, [row_data]);
@@ -5809,12 +5809,12 @@ const TableContent = ({ bodyText }) => {
5809
5809
  const handleModalClose = () => {
5810
5810
  setIsModalOpen(false);
5811
5811
  };
5812
- return (jsxs(Fragment, { children: [jsx(Modal, { className: "test-modal", onClose: handleModalClose, onPrimaryButtonClick: () => { }, onSecondaryButtonClick: handleModalClose, open: isModalOpen, size: "large", title: "", children: jsx("div", { style: { width: '100%', height: '70vh' }, children: 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 && {
5812
+ return (jsxs(Fragment, { children: [jsx(Modal, { className: "test-modal", onClose: handleModalClose, onPrimaryButtonClick: () => { }, onSecondaryButtonClick: handleModalClose, open: isModalOpen, size: "large", title: "", children: jsx("div", { style: { width: '100%', height: '70vh' }, children: 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 && {
5813
5813
  manualCallBack: serverSideManualCallBack,
5814
5814
  rowModelType: "serverSide",
5815
5815
  serverSideStoreType: "partial",
5816
5816
  cacheBlockSize: page_size,
5817
- }) }) }) }), jsx("div", { style: { width: '100%', marginTop: '10px' }, children: 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 && {
5817
+ }) }) }) }), jsx("div", { style: { width: '100%', marginTop: '10px' }, children: 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 && {
5818
5818
  manualCallBack: serverSideManualCallBack,
5819
5819
  rowModelType: "serverSide",
5820
5820
  serverSideStoreType: "partial",
@@ -6044,6 +6044,563 @@ var SvgReasoningIcon = function SvgReasoningIcon(props) {
6044
6044
  })))));
6045
6045
  };
6046
6046
 
6047
+ /**
6048
+ * Generic hook for cross-filter cascading functionality.
6049
+ * When a filter's value changes, downstream filters' options are re-fetched
6050
+ * with the current selections of upstream filters included in the payload.
6051
+ *
6052
+ * @param {Object} config
6053
+ * @param {Array} config.filters - Array of filter configs. Each must have at minimum:
6054
+ * { paramName, dimension?, column_name?, attribute_name?, display_type?, ... }
6055
+ * The order in this array determines the cascading hierarchy (index 0 = most upstream).
6056
+ * @param {Function} config.fetchOptionsFn - Async function to fetch options for a filter.
6057
+ * Signature: (filterConfig, existingSelections, allFilters) => Promise<Array<{label, value}>>
6058
+ * - filterConfig: the config of the filter whose options we're fetching
6059
+ * - existingSelections: array of { attributeName, filterName, values, checkAll } for upstream filters
6060
+ * - allFilters: the full filters array (for reference/lookup)
6061
+ * @param {Object} config.initialSelections - Optional. { paramName: value[] } to preload selections.
6062
+ * @param {boolean} config.fetchOnMount - Whether to fetch initial options for all filters on mount. Default: true.
6063
+ * @param {Function} config.onSelectionChange - Optional callback fired after any filter value changes.
6064
+ * Signature: (paramName, selectedValues, allSelections) => void
6065
+ *
6066
+ * @returns {Object}
6067
+ * - optionsMap: { paramName: Array<{label, value}> } — current available options per filter
6068
+ * - loadingMap: { paramName: boolean } — loading state per filter
6069
+ * - selectionsMap: { paramName: value[] } — current selections per filter
6070
+ * - onFilterChange: (paramName, selectedValues) => void — call when user changes a filter
6071
+ * - resetAll: () => void — reset all selections and re-fetch initial options
6072
+ * - resetFilter: (paramName) => void — reset a single filter and its downstream filters
6073
+ */
6074
+ const useCrossFilterCascading = ({ filters = [], fetchOptionsFn, initialSelections = {}, fetchOnMount = true, onSelectionChange, }) => {
6075
+ // State maps
6076
+ const [optionsMap, setOptionsMap] = useState({});
6077
+ const [loadingMap, setLoadingMap] = useState({});
6078
+ const [selectionsMap, setSelectionsMap] = useState(() => {
6079
+ // Initialize from initialSelections
6080
+ const initial = {};
6081
+ filters.forEach((f) => {
6082
+ const paramName = f.paramName || f.param_name || f.column_name || f.attribute_name;
6083
+ initial[paramName] = initialSelections[paramName] || [];
6084
+ });
6085
+ return initial;
6086
+ });
6087
+ // Refs for latest state access in async operations
6088
+ const selectionsRef = useRef(selectionsMap);
6089
+ const filtersRef = useRef(filters);
6090
+ const fetchFnRef = useRef(fetchOptionsFn);
6091
+ const mountedRef = useRef(true);
6092
+ // Keep refs in sync
6093
+ useEffect(() => {
6094
+ selectionsRef.current = selectionsMap;
6095
+ }, [selectionsMap]);
6096
+ useEffect(() => {
6097
+ filtersRef.current = filters;
6098
+ }, [filters]);
6099
+ useEffect(() => {
6100
+ fetchFnRef.current = fetchOptionsFn;
6101
+ }, [fetchOptionsFn]);
6102
+ useEffect(() => {
6103
+ return () => {
6104
+ mountedRef.current = false;
6105
+ };
6106
+ }, []);
6107
+ /**
6108
+ * Get the paramName from a filter config object (supports multiple naming conventions)
6109
+ */
6110
+ const getParamName = useCallback((filter) => {
6111
+ return filter.paramName || filter.param_name || filter.column_name || filter.attribute_name;
6112
+ }, []);
6113
+ /**
6114
+ * Get the index of a filter in the hierarchy by its paramName
6115
+ */
6116
+ const getFilterIndex = useCallback((paramName) => {
6117
+ return filtersRef.current.findIndex((f) => getParamName(f) === paramName);
6118
+ }, [getParamName]);
6119
+ /**
6120
+ * Get all filters that are downstream (higher index) of a given filter
6121
+ */
6122
+ const getDownstreamFilters = useCallback((paramName) => {
6123
+ const index = getFilterIndex(paramName);
6124
+ if (index === -1)
6125
+ return [];
6126
+ return filtersRef.current.slice(index + 1);
6127
+ }, [getFilterIndex]);
6128
+ /**
6129
+ * Get all filters that are upstream (lower index) of a given filter
6130
+ */
6131
+ const getUpstreamFilters = useCallback((paramName) => {
6132
+ const index = getFilterIndex(paramName);
6133
+ if (index <= 0)
6134
+ return [];
6135
+ return filtersRef.current.slice(0, index);
6136
+ }, [getFilterIndex]);
6137
+ /**
6138
+ * Build the existing selections payload for upstream filters (for cascading API call)
6139
+ */
6140
+ const buildExistingSelections = useCallback((paramName) => {
6141
+ const upstreamFilters = getUpstreamFilters(paramName);
6142
+ const currentSelections = selectionsRef.current;
6143
+ return upstreamFilters
6144
+ .filter((f) => {
6145
+ const pName = getParamName(f);
6146
+ const vals = currentSelections[pName];
6147
+ return vals && vals.length > 0;
6148
+ })
6149
+ .map((f) => {
6150
+ const pName = getParamName(f);
6151
+ return {
6152
+ filterName: f.label || f.name || pName,
6153
+ attributeName: f.column_name || f.attribute_name || pName,
6154
+ values: currentSelections[pName] || [],
6155
+ checkAll: false,
6156
+ };
6157
+ });
6158
+ }, [getUpstreamFilters, getParamName]);
6159
+ /**
6160
+ * Fetch options for a single filter
6161
+ */
6162
+ const fetchOptionsForFilter = useCallback(async (filterConfig) => {
6163
+ const paramName = getParamName(filterConfig);
6164
+ if (!fetchFnRef.current)
6165
+ return;
6166
+ // Set loading
6167
+ setLoadingMap((prev) => ({ ...prev, [paramName]: true }));
6168
+ try {
6169
+ const existingSelections = buildExistingSelections(paramName);
6170
+ const options = await fetchFnRef.current(filterConfig, existingSelections, filtersRef.current);
6171
+ if (!mountedRef.current)
6172
+ return;
6173
+ // Check if the response contains extra options for other filters
6174
+ const extraOptionsMap = options?.__extraOptionsMap;
6175
+ if (extraOptionsMap && typeof extraOptionsMap === "object") {
6176
+ // Distribute extra options to matching filters
6177
+ setOptionsMap((prev) => {
6178
+ const updated = { ...prev, [paramName]: options || [] };
6179
+ Object.keys(extraOptionsMap).forEach((key) => {
6180
+ // Only populate if this key matches a known filter in our hierarchy
6181
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6182
+ if (matchingFilter) {
6183
+ const matchParamName = getParamName(matchingFilter);
6184
+ updated[matchParamName] = extraOptionsMap[key];
6185
+ }
6186
+ });
6187
+ return updated;
6188
+ });
6189
+ // Clear loading for extra filters that were populated
6190
+ setLoadingMap((prev) => {
6191
+ const updated = { ...prev, [paramName]: false };
6192
+ Object.keys(extraOptionsMap).forEach((key) => {
6193
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6194
+ if (matchingFilter) {
6195
+ updated[getParamName(matchingFilter)] = false;
6196
+ }
6197
+ });
6198
+ return updated;
6199
+ });
6200
+ }
6201
+ else {
6202
+ setOptionsMap((prev) => ({ ...prev, [paramName]: options || [] }));
6203
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6204
+ }
6205
+ }
6206
+ catch (error) {
6207
+ console.error(`[useCrossFilterCascading] Error fetching options for ${paramName}:`, error);
6208
+ if (mountedRef.current) {
6209
+ setOptionsMap((prev) => ({ ...prev, [paramName]: [] }));
6210
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6211
+ }
6212
+ }
6213
+ }, [getParamName, buildExistingSelections]);
6214
+ /**
6215
+ * Fetch options for multiple filters (used for initial load and cascade refresh)
6216
+ */
6217
+ const fetchOptionsForFilters = useCallback(async (filterConfigs) => {
6218
+ await Promise.all(filterConfigs.map((f) => fetchOptionsForFilter(f)));
6219
+ }, [fetchOptionsForFilter]);
6220
+ /**
6221
+ * Handle a filter value change — triggers cascading for downstream filters
6222
+ */
6223
+ const onFilterChange = useCallback((paramName, selectedValues) => {
6224
+ const values = Array.isArray(selectedValues) ? selectedValues : [selectedValues];
6225
+ // Update selections
6226
+ setSelectionsMap((prev) => {
6227
+ const updated = { ...prev, [paramName]: values };
6228
+ selectionsRef.current = updated;
6229
+ // Notify consumer
6230
+ if (onSelectionChange) {
6231
+ onSelectionChange(paramName, values, updated);
6232
+ }
6233
+ return updated;
6234
+ });
6235
+ // Only clear downstream if the filter is being emptied (user cleared the filter).
6236
+ // When a value is being selected/changed while downstream filters already have
6237
+ // selections, preserve them — the dropdown close handler will decide whether
6238
+ // to refetch downstream options.
6239
+ if (values.length === 0) {
6240
+ const downstreamFilters = getDownstreamFilters(paramName);
6241
+ if (downstreamFilters.length > 0) {
6242
+ // Clear downstream selections
6243
+ setSelectionsMap((prev) => {
6244
+ const updated = { ...prev };
6245
+ downstreamFilters.forEach((f) => {
6246
+ const pName = getParamName(f);
6247
+ updated[pName] = [];
6248
+ });
6249
+ selectionsRef.current = updated;
6250
+ return updated;
6251
+ });
6252
+ // Clear downstream options
6253
+ const downstreamParamNames = downstreamFilters.map(getParamName);
6254
+ setOptionsMap((prev) => {
6255
+ const updated = { ...prev };
6256
+ downstreamParamNames.forEach((pName) => {
6257
+ updated[pName] = [];
6258
+ });
6259
+ return updated;
6260
+ });
6261
+ }
6262
+ }
6263
+ }, [getDownstreamFilters, getParamName, fetchOptionsForFilter, onSelectionChange]);
6264
+ /**
6265
+ * Reset all filters — clears selections and re-fetches initial options
6266
+ */
6267
+ const resetAll = useCallback(() => {
6268
+ const initial = {};
6269
+ filtersRef.current.forEach((f) => {
6270
+ initial[getParamName(f)] = [];
6271
+ });
6272
+ setSelectionsMap(initial);
6273
+ selectionsRef.current = initial;
6274
+ setOptionsMap({});
6275
+ if (fetchFnRef.current && filtersRef.current.length > 0) {
6276
+ // Fetch options for the first filter (others will cascade)
6277
+ fetchOptionsForFilter(filtersRef.current[0]);
6278
+ }
6279
+ }, [getParamName, fetchOptionsForFilter]);
6280
+ /**
6281
+ * Reset a specific filter and all its downstream filters
6282
+ */
6283
+ const resetFilter = useCallback((paramName) => {
6284
+ const downstreamFilters = getDownstreamFilters(paramName);
6285
+ const allToReset = [paramName, ...downstreamFilters.map(getParamName)];
6286
+ setSelectionsMap((prev) => {
6287
+ const updated = { ...prev };
6288
+ allToReset.forEach((pName) => {
6289
+ updated[pName] = [];
6290
+ });
6291
+ selectionsRef.current = updated;
6292
+ return updated;
6293
+ });
6294
+ // Re-fetch options for the reset filter itself
6295
+ const filterConfig = filtersRef.current.find((f) => getParamName(f) === paramName);
6296
+ if (filterConfig) {
6297
+ fetchOptionsForFilter(filterConfig);
6298
+ }
6299
+ }, [getDownstreamFilters, getParamName, fetchOptionsForFilter]);
6300
+ /**
6301
+ * Fetch options for a specific filter on demand (e.g., when dropdown is opened)
6302
+ */
6303
+ const fetchOptions = useCallback((paramName) => {
6304
+ const filterConfig = filtersRef.current.find((f) => getParamName(f) === paramName);
6305
+ if (filterConfig) {
6306
+ fetchOptionsForFilter(filterConfig);
6307
+ }
6308
+ }, [getParamName, fetchOptionsForFilter]);
6309
+ /**
6310
+ * Fetch options for all downstream filters of a given filter.
6311
+ * Called when the user closes a dropdown after making a selection,
6312
+ * so downstream filters are pre-populated before the user opens them.
6313
+ */
6314
+ const fetchDownstreamOptions = useCallback((paramName) => {
6315
+ const downstreamFilters = getDownstreamFilters(paramName);
6316
+ if (downstreamFilters.length > 0) {
6317
+ fetchOptionsForFilters(downstreamFilters);
6318
+ }
6319
+ }, [getDownstreamFilters, fetchOptionsForFilters]);
6320
+ /**
6321
+ * Build selections payload that includes the triggering filter and all other
6322
+ * filters that have selections (used for upstream/reverse cascading).
6323
+ */
6324
+ const buildAllSelections = useCallback((excludeParamName) => {
6325
+ const currentSelections = selectionsRef.current;
6326
+ return filtersRef.current
6327
+ .filter((f) => {
6328
+ const pName = getParamName(f);
6329
+ if (pName === excludeParamName)
6330
+ return false;
6331
+ const vals = currentSelections[pName];
6332
+ return vals && vals.length > 0;
6333
+ })
6334
+ .map((f) => {
6335
+ const pName = getParamName(f);
6336
+ return {
6337
+ filterName: f.label || f.name || pName,
6338
+ attributeName: f.column_name || f.attribute_name || pName,
6339
+ values: currentSelections[pName] || [],
6340
+ checkAll: false,
6341
+ };
6342
+ });
6343
+ }, [getParamName]);
6344
+ /**
6345
+ * Fetch options for a single upstream filter using all current selections
6346
+ * (reverse cascading — the payload includes the triggering lower filter's values).
6347
+ */
6348
+ const fetchUpstreamFilterOptions = useCallback(async (filterConfig) => {
6349
+ const paramName = getParamName(filterConfig);
6350
+ if (!fetchFnRef.current)
6351
+ return;
6352
+ setLoadingMap((prev) => ({ ...prev, [paramName]: true }));
6353
+ try {
6354
+ const existingSelections = buildAllSelections(paramName);
6355
+ const options = await fetchFnRef.current(filterConfig, existingSelections, filtersRef.current);
6356
+ if (!mountedRef.current)
6357
+ return;
6358
+ // Handle extra options from multi-key response
6359
+ const extraOptionsMap = options?.__extraOptionsMap;
6360
+ if (extraOptionsMap && typeof extraOptionsMap === "object") {
6361
+ setOptionsMap((prev) => {
6362
+ const updated = { ...prev, [paramName]: options || [] };
6363
+ Object.keys(extraOptionsMap).forEach((key) => {
6364
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6365
+ if (matchingFilter) {
6366
+ updated[getParamName(matchingFilter)] = extraOptionsMap[key];
6367
+ }
6368
+ });
6369
+ return updated;
6370
+ });
6371
+ setLoadingMap((prev) => {
6372
+ const updated = { ...prev, [paramName]: false };
6373
+ Object.keys(extraOptionsMap).forEach((key) => {
6374
+ const matchingFilter = filtersRef.current.find((f) => getParamName(f) === key || f.column_name === key || f.attribute_name === key);
6375
+ if (matchingFilter) {
6376
+ updated[getParamName(matchingFilter)] = false;
6377
+ }
6378
+ });
6379
+ return updated;
6380
+ });
6381
+ }
6382
+ else {
6383
+ setOptionsMap((prev) => ({ ...prev, [paramName]: options || [] }));
6384
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6385
+ }
6386
+ }
6387
+ catch (error) {
6388
+ console.error(`[useCrossFilterCascading] Error fetching upstream options for ${paramName}:`, error);
6389
+ if (mountedRef.current) {
6390
+ setOptionsMap((prev) => ({ ...prev, [paramName]: [] }));
6391
+ setLoadingMap((prev) => ({ ...prev, [paramName]: false }));
6392
+ }
6393
+ }
6394
+ }, [getParamName, buildAllSelections]);
6395
+ /**
6396
+ * Fetch options for all upstream filters of a given filter.
6397
+ * Called on dropdown close to reverse-cascade — e.g., selecting Channel
6398
+ * triggers a fetch for Brand with Channel's selection in the payload.
6399
+ */
6400
+ const fetchUpstreamOptions = useCallback((paramName) => {
6401
+ const upstreamFilters = getUpstreamFilters(paramName);
6402
+ if (upstreamFilters.length > 0) {
6403
+ Promise.all(upstreamFilters.map((f) => fetchUpstreamFilterOptions(f)));
6404
+ }
6405
+ }, [getUpstreamFilters, fetchUpstreamFilterOptions]);
6406
+ // Fetch initial options on mount
6407
+ useEffect(() => {
6408
+ if (fetchOnMount && filters.length > 0 && fetchFnRef.current) {
6409
+ // Fetch options for the first filter (it has no upstream dependencies)
6410
+ fetchOptionsForFilter(filters[0]);
6411
+ }
6412
+ // eslint-disable-next-line react-hooks/exhaustive-deps
6413
+ }, []);
6414
+ return {
6415
+ optionsMap,
6416
+ loadingMap,
6417
+ selectionsMap,
6418
+ onFilterChange,
6419
+ resetAll,
6420
+ resetFilter,
6421
+ fetchOptions,
6422
+ fetchDownstreamOptions,
6423
+ fetchUpstreamOptions,
6424
+ getParamName,
6425
+ };
6426
+ };
6427
+
6428
+ /**
6429
+ * Context for cross-filter cascading.
6430
+ * Provides cascading state and actions to child select components.
6431
+ *
6432
+ * Shape:
6433
+ * {
6434
+ * optionsMap: { paramName: Array<{label, value}> },
6435
+ * loadingMap: { paramName: boolean },
6436
+ * selectionsMap: { paramName: value[] },
6437
+ * onFilterChange: (paramName, selectedValues) => void,
6438
+ * resetAll: () => void,
6439
+ * resetFilter: (paramName) => void,
6440
+ * fetchOptions: (paramName) => void,
6441
+ * getParamName: (filterConfig) => string,
6442
+ * isEnabled: boolean, // flag to know if cascading is active
6443
+ * }
6444
+ */
6445
+ const CrossFilterContext = createContext(null);
6446
+ /**
6447
+ * Hook to consume cross-filter cascading context.
6448
+ * Returns null if not inside a CrossFilterProvider (graceful fallback).
6449
+ */
6450
+ const useCrossFilterContext = () => {
6451
+ return useContext(CrossFilterContext);
6452
+ };
6453
+
6454
+ /**
6455
+ * Provider component that wraps a group of select components to enable
6456
+ * cross-filter cascading between them.
6457
+ *
6458
+ * @param {Object} props
6459
+ * @param {Array} props.filters - Array of filter configs (ordered by hierarchy)
6460
+ * @param {Function} props.fetchOptionsFn - Async function to fetch options for a filter
6461
+ * @param {Object} props.initialSelections - Optional preloaded selections { paramName: values[] }
6462
+ * @param {boolean} props.fetchOnMount - Whether to fetch initial options on mount (default: true)
6463
+ * @param {Function} props.onSelectionChange - Optional callback on any filter change
6464
+ * @param {React.ReactNode} props.children - Child components (selects) that will consume the context
6465
+ */
6466
+ const CrossFilterProvider = ({ filters, fetchOptionsFn, initialSelections = {}, fetchOnMount = true, onSelectionChange = null, children, }) => {
6467
+ const cascadingState = useCrossFilterCascading({
6468
+ filters,
6469
+ fetchOptionsFn,
6470
+ initialSelections,
6471
+ fetchOnMount,
6472
+ onSelectionChange,
6473
+ });
6474
+ const contextValue = useMemo(() => ({
6475
+ ...cascadingState,
6476
+ isEnabled: true,
6477
+ }), [cascadingState]);
6478
+ return (jsx(CrossFilterContext.Provider, { value: contextValue, children: children }));
6479
+ };
6480
+
6481
+ /**
6482
+ * Adapter function that bridges the generic useCrossFilterCascading hook
6483
+ * with the existing cross-filter API used by the chatbot.
6484
+ *
6485
+ * This is the `fetchOptionsFn` passed to the CrossFilterProvider.
6486
+ *
6487
+ * @param {Object} filterConfig - The filter config for which to fetch options
6488
+ * @param {Array} existingSelections - Upstream filter selections
6489
+ * Each item: { filterName, attributeName, values, checkAll }
6490
+ * @param {Array} allFilters - Full array of all filter configs
6491
+ * @returns {Promise<Array<{label, value}>>} - Formatted options
6492
+ */
6493
+ const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], allFilters = []) => {
6494
+ try {
6495
+ const attributeName = filterConfig.column_name ||
6496
+ filterConfig.attribute_name ||
6497
+ filterConfig.param_name ||
6498
+ filterConfig.paramName;
6499
+ if (!attributeName)
6500
+ return [];
6501
+ const dimension = filterConfig.dimension || "product";
6502
+ // Build filters array from existing selections (upstream filters with values)
6503
+ const filtersArray = existingSelections.map((selection) => {
6504
+ // Find full config for this upstream filter
6505
+ const fullConfig = allFilters.find((f) => (f.column_name || f.attribute_name || f.param_name || f.paramName) === selection.attributeName);
6506
+ const selAttrName = fullConfig?.column_name ||
6507
+ fullConfig?.attribute_name ||
6508
+ fullConfig?.param_name ||
6509
+ fullConfig?.paramName ||
6510
+ selection.attributeName;
6511
+ return {
6512
+ filter_name: selection.filterName || selAttrName,
6513
+ filter_id: selAttrName,
6514
+ filter_type: "cascaded",
6515
+ dimension: fullConfig?.dimension || dimension,
6516
+ display_type: fullConfig?.display_type || "dropdown",
6517
+ check_configuration: selection.checkAll ? [{ checkAll: true, meta: {} }] : [],
6518
+ is_mandatory: fullConfig?.is_mandatory || fullConfig?.isRequired || false,
6519
+ extra: {},
6520
+ values: selection.checkAll ? [] : (selection.values || []),
6521
+ attribute_name: selAttrName,
6522
+ operator: "in",
6523
+ display_order: fullConfig?.display_order || fullConfig?.ordering || 0,
6524
+ };
6525
+ });
6526
+ const payload = {
6527
+ attributes: [
6528
+ {
6529
+ attribute_name: attributeName,
6530
+ dimension: dimension,
6531
+ filter_type: "cascaded",
6532
+ },
6533
+ ],
6534
+ filter_type: "cascaded",
6535
+ filters: filtersArray,
6536
+ is_urm_filter: true,
6537
+ screen_name: "Chatbot",
6538
+ application_code: 1,
6539
+ };
6540
+ console.log("[crossFilterAdapter] Fetching options for:", attributeName, "payload:", JSON.stringify(payload, null, 2));
6541
+ const response = await getFilterOptions(payload)();
6542
+ console.log("[crossFilterAdapter] Response for:", attributeName, "data:", response?.data?.data);
6543
+ if (response?.data?.status && response?.data?.data) {
6544
+ const responseData = response.data.data;
6545
+ const primaryValues = responseData[attributeName];
6546
+ // Format the primary filter's options
6547
+ let primaryOptions = Array.isArray(primaryValues)
6548
+ ? primaryValues.map((value) => {
6549
+ const stringValue = String(value);
6550
+ return {
6551
+ label: replaceSpecialCharacter(stringValue),
6552
+ value: stringValue,
6553
+ };
6554
+ })
6555
+ : [];
6556
+ // Check if the response contains options for other filters (multi-key response)
6557
+ const extraOptionsMap = {};
6558
+ Object.keys(responseData).forEach((key) => {
6559
+ if (key !== attributeName && Array.isArray(responseData[key])) {
6560
+ extraOptionsMap[key] = responseData[key].map((value) => {
6561
+ const stringValue = String(value);
6562
+ return {
6563
+ label: replaceSpecialCharacter(stringValue),
6564
+ value: stringValue,
6565
+ };
6566
+ });
6567
+ }
6568
+ });
6569
+ // If primary options are empty but response has data under other keys,
6570
+ // include ALL response keys in extraOptionsMap so the hook can distribute
6571
+ // them to matching filters by column_name/attribute_name lookup.
6572
+ if (primaryOptions.length === 0 && Object.keys(extraOptionsMap).length > 0) {
6573
+ // Also check if any response key matches the paramName directly
6574
+ // (e.g., paramName is "brand" but column_name sent was different)
6575
+ const altKey = Object.keys(responseData).find((key) => {
6576
+ return Array.isArray(responseData[key]) && (key === attributeName ||
6577
+ key.toLowerCase() === attributeName.toLowerCase());
6578
+ });
6579
+ if (altKey) {
6580
+ primaryOptions = responseData[altKey].map((value) => {
6581
+ const stringValue = String(value);
6582
+ return {
6583
+ label: replaceSpecialCharacter(stringValue),
6584
+ value: stringValue,
6585
+ };
6586
+ });
6587
+ delete extraOptionsMap[altKey];
6588
+ }
6589
+ }
6590
+ // Return enriched result with extra options if available
6591
+ if (Object.keys(extraOptionsMap).length > 0) {
6592
+ primaryOptions.__extraOptionsMap = extraOptionsMap;
6593
+ }
6594
+ return primaryOptions;
6595
+ }
6596
+ return [];
6597
+ }
6598
+ catch (error) {
6599
+ console.error("[crossFilterAdapter] Error fetching options:", error);
6600
+ return [];
6601
+ }
6602
+ };
6603
+
6047
6604
  const SliderContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6048
6605
  const formKey = `${messageIndex}_${bodyText?.paramName}`;
6049
6606
  const { header, headerOrentiation, inputPosition, label, max, min, required, disabled, } = bodyText;
@@ -6093,6 +6650,10 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6093
6650
  const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
6094
6651
  const heirarchyKeyValuePairs = useSelector((state) => state.smartBotReducer.heirarchyKeyValuePairs);
6095
6652
  const dispatch = useDispatch();
6653
+ // Cross-filter cascading context (optional — graceful fallback when not wrapped)
6654
+ const crossFilterCtx = useCrossFilterContext();
6655
+ const isCascading = crossFilterCtx?.isEnabled && paramName;
6656
+ const isMountedRef = useRef(false);
6096
6657
  if (isEmpty$1(bodyText))
6097
6658
  return null;
6098
6659
  const onChange = (selectedOptions) => {
@@ -6116,6 +6677,10 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6116
6677
  // };
6117
6678
  dispatch(setChatbotContext(chatbotContext));
6118
6679
  dispatch(setPersistedFormValues({ [formKey]: Array.isArray(selectedOptions) ? selectedOptions : [selectedOptions] }));
6680
+ // Notify cross-filter context if cascading is active
6681
+ if (isCascading) {
6682
+ crossFilterCtx.onFilterChange(paramName, Array.isArray(value) ? value : [value]);
6683
+ }
6119
6684
  }
6120
6685
  catch (error) {
6121
6686
  console.error("Error in select handleChange", error);
@@ -6127,16 +6692,94 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6127
6692
  setCurrentSelectedOptions([]);
6128
6693
  }
6129
6694
  }, [persistedFormValues, formKey]);
6695
+ // When cross-filter context provides new options for this filter, update local state
6130
6696
  useEffect(() => {
6131
- allOptionsRef.current = options;
6132
- const initialSlice = formatSlice(options, 0, INITIAL_DISPLAY_COUNT);
6133
- setInitialOptions(initialSlice);
6134
- setCurrentOptions(initialSlice);
6135
- }, []);
6697
+ if (isCascading && crossFilterCtx.optionsMap[paramName]) {
6698
+ const cascadedOptions = crossFilterCtx.optionsMap[paramName];
6699
+ allOptionsRef.current = cascadedOptions;
6700
+ const initialSlice = formatSlice(cascadedOptions, 0, INITIAL_DISPLAY_COUNT);
6701
+ setInitialOptions(initialSlice);
6702
+ setCurrentOptions(initialSlice);
6703
+ }
6704
+ }, [isCascading, crossFilterCtx?.optionsMap?.[paramName]]);
6705
+ // When cascading resets downstream selections, clear local selection
6706
+ // Skip on initial mount to avoid clearing persisted values when context reinitializes
6707
+ useEffect(() => {
6708
+ if (!isMountedRef.current) {
6709
+ isMountedRef.current = true;
6710
+ return;
6711
+ }
6712
+ if (isCascading) {
6713
+ const cascadedSelection = crossFilterCtx.selectionsMap[paramName];
6714
+ if (cascadedSelection && cascadedSelection.length === 0 && currentSelectedOptions.length > 0) {
6715
+ setCurrentSelectedOptions([]);
6716
+ setIsAllSelected(false);
6717
+ // Also clear from chatbotContext and persistedFormValues
6718
+ chatbotContext[bodyText?.paramName] = {
6719
+ ...chatbotContext?.[bodyText?.paramName],
6720
+ [bodyText?.paramName]: [],
6721
+ updated: true,
6722
+ };
6723
+ dispatch(setChatbotContext(chatbotContext));
6724
+ dispatch(setPersistedFormValues({ [formKey]: [] }));
6725
+ }
6726
+ }
6727
+ }, [isCascading, crossFilterCtx?.selectionsMap?.[paramName]]);
6728
+ useEffect(() => {
6729
+ // Only use static options from bodyText if NOT in cascading mode
6730
+ if (!isCascading) {
6731
+ allOptionsRef.current = options;
6732
+ const initialSlice = formatSlice(options, 0, INITIAL_DISPLAY_COUNT);
6733
+ setInitialOptions(initialSlice);
6734
+ setCurrentOptions(initialSlice);
6735
+ }
6736
+ }, [isCascading]);
6136
6737
  return (jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsx(Select, { currentOptions: currentOptions, setCurrentOptions: setCurrentOptions, label: heirarchyKeyValuePairs[paramName] || label, labelOrientation: labelOrientation,
6137
6738
  // inputPosition={inputPosition}
6138
6739
  // header={header}
6139
- 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: () => {
6740
+ isRequired: isRequired, isDisabled: isDisabled || isFormDisabled, isClearable: !(isDisabled || isFormDisabled), onClearAll: () => {
6741
+ setCurrentSelectedOptions([]);
6742
+ setIsAllSelected(false);
6743
+ chatbotContext[bodyText?.paramName] = {
6744
+ ...chatbotContext?.[bodyText?.paramName],
6745
+ [bodyText?.paramName]: [],
6746
+ updated: true,
6747
+ };
6748
+ dispatch(setChatbotContext(chatbotContext));
6749
+ dispatch(setPersistedFormValues({ [formKey]: [] }));
6750
+ // Notify cross-filter context to clear downstream filters
6751
+ if (isCascading) {
6752
+ crossFilterCtx.onFilterChange(paramName, []);
6753
+ }
6754
+ }, handleChange: (selected) => onChange(selected), isCloseWhenClickOutside: true, setIsOpen: (open) => {
6755
+ setIsOpen(open);
6756
+ if (isCascading) {
6757
+ if (open) {
6758
+ // Lazy fetch: trigger cross-filter API call when dropdown opens for the first time
6759
+ if ((!crossFilterCtx.optionsMap[paramName] || crossFilterCtx.optionsMap[paramName].length === 0) && !crossFilterCtx.loadingMap[paramName]) {
6760
+ crossFilterCtx.fetchOptions(paramName);
6761
+ }
6762
+ }
6763
+ else {
6764
+ // On dropdown close: if there's a selection, pre-fetch related filter options
6765
+ const currentSelection = crossFilterCtx.selectionsMap[paramName];
6766
+ if (currentSelection && currentSelection.length > 0) {
6767
+ // Only fetch downstream if no downstream filter already has selections
6768
+ // (avoids clearing user's existing lower-hierarchy choices)
6769
+ const hasDownstreamSelections = Object.keys(crossFilterCtx.selectionsMap).some((key) => {
6770
+ if (key === paramName)
6771
+ return false;
6772
+ const vals = crossFilterCtx.selectionsMap[key];
6773
+ return vals && vals.length > 0;
6774
+ });
6775
+ if (!hasDownstreamSelections) {
6776
+ crossFilterCtx.fetchDownstreamOptions(paramName);
6777
+ }
6778
+ crossFilterCtx.fetchUpstreamOptions(paramName);
6779
+ }
6780
+ }
6781
+ }
6782
+ }, 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: () => {
6140
6783
  const allRaw = allOptionsRef.current;
6141
6784
  if (allRaw.length > 0 && currentOptions.length < allRaw.length) {
6142
6785
  const nextCount = Math.min(currentOptions.length + LOAD_MORE_COUNT, allRaw.length);
@@ -6160,10 +6803,18 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6160
6803
  };
6161
6804
  dispatch(setChatbotContext(chatbotContext));
6162
6805
  dispatch(setPersistedFormValues({ [formKey]: currentOptions }));
6806
+ // Notify cross-filter context if cascading is active
6807
+ if (isCascading) {
6808
+ crossFilterCtx.onFilterChange(paramName, allValues);
6809
+ }
6163
6810
  }
6164
6811
  else {
6165
6812
  setCurrentSelectedOptions([]);
6166
6813
  setIsAllSelected(false);
6814
+ // Notify cross-filter context of deselection
6815
+ if (isCascading) {
6816
+ crossFilterCtx.onFilterChange(paramName, []);
6817
+ }
6167
6818
  }
6168
6819
  }, customPlaceholderAfterSelect: isAllSelected && allOptionsRef.current.length > 0
6169
6820
  ? allOptionsRef.current.length
@@ -6377,6 +7028,8 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
6377
7028
  const persistedFormValues = useSelector((state) => state.smartBotReducer.persistedFormValues);
6378
7029
  const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
6379
7030
  const stepFormStreamData = useSelector((state) => state.smartBotReducer.stepFormStreamData);
7031
+ const chatbotFilterOptions = useSelector((state) => state.smartBotReducer.chatbotFilterOptions);
7032
+ const dimensionHierarchies = useSelector((state) => state.userRoleManagementService?.dimensionHierarchies);
6380
7033
  const [isFormSubmitted, setIsFormSubmitted] = useState(false);
6381
7034
  useEffect(() => {
6382
7035
  if (stepFormStreamData?.status === "streaming_start") {
@@ -6483,6 +7136,77 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
6483
7136
  return false;
6484
7137
  });
6485
7138
  }, [formData, chatbotContext, persistedFormValues, messageIndex]);
7139
+ // Extract select-type filter configs from formData for cross-filter cascading
7140
+ // and sort them based on the filters_hierarchy_order from tenant config
7141
+ const crossFilterConfigs = useMemo(() => {
7142
+ if (!formData || !Array.isArray(formData))
7143
+ return [];
7144
+ const configs = formData
7145
+ .filter((item) => item?.type === "select" && item?.data?.param_name)
7146
+ .map((item) => {
7147
+ const data = item.data;
7148
+ const paramName = data.param_name;
7149
+ // Try to find full filter config from chatbotFilterOptions (Redux)
7150
+ const fullConfig = (chatbotFilterOptions || []).find((f) => f.column_name === paramName || f.attribute_name === paramName || f.name === paramName);
7151
+ return {
7152
+ paramName: paramName,
7153
+ param_name: paramName,
7154
+ column_name: fullConfig?.column_name || paramName,
7155
+ attribute_name: fullConfig?.attribute_name || paramName,
7156
+ dimension: fullConfig?.dimension || "product",
7157
+ display_type: fullConfig?.display_type || "dropdown",
7158
+ display_order: fullConfig?.display_order || item.ordering || 0,
7159
+ label: data.label,
7160
+ name: fullConfig?.name || data.label,
7161
+ is_mandatory: data.isRequired || false,
7162
+ };
7163
+ });
7164
+ // Sort configs based on dimensionHierarchies order.
7165
+ // Filters are sorted by their position in their dimension's hierarchy list.
7166
+ // This determines the cascading order (earlier = upstream/higher hierarchy).
7167
+ if (dimensionHierarchies && Object.keys(dimensionHierarchies).length > 0) {
7168
+ configs.sort((a, b) => {
7169
+ const aHierarchy = dimensionHierarchies[a.dimension] || [];
7170
+ const bHierarchy = dimensionHierarchies[b.dimension] || [];
7171
+ const aIndex = aHierarchy.indexOf(a.column_name) !== -1
7172
+ ? aHierarchy.indexOf(a.column_name)
7173
+ : aHierarchy.indexOf(a.attribute_name) !== -1
7174
+ ? aHierarchy.indexOf(a.attribute_name)
7175
+ : aHierarchy.indexOf(a.paramName) !== -1
7176
+ ? aHierarchy.indexOf(a.paramName)
7177
+ : 999;
7178
+ const bIndex = bHierarchy.indexOf(b.column_name) !== -1
7179
+ ? bHierarchy.indexOf(b.column_name)
7180
+ : bHierarchy.indexOf(b.attribute_name) !== -1
7181
+ ? bHierarchy.indexOf(b.attribute_name)
7182
+ : bHierarchy.indexOf(b.paramName) !== -1
7183
+ ? bHierarchy.indexOf(b.paramName)
7184
+ : 999;
7185
+ return aIndex - bIndex;
7186
+ });
7187
+ }
7188
+ return configs;
7189
+ }, [formData, chatbotFilterOptions, dimensionHierarchies]);
7190
+ // Build initial selections from chatbotContext and persistedFormValues (for restore on remount)
7191
+ const crossFilterInitialSelections = useMemo(() => {
7192
+ const selections = {};
7193
+ crossFilterConfigs.forEach((cfg) => {
7194
+ const ctx = chatbotContext?.[cfg.paramName];
7195
+ if (ctx && ctx.updated && ctx[cfg.paramName]) {
7196
+ const val = ctx[cfg.paramName];
7197
+ selections[cfg.paramName] = Array.isArray(val) ? val : [val];
7198
+ }
7199
+ else {
7200
+ // Fallback: check persistedFormValues for option objects
7201
+ const persistedKey = `${messageIndex}_${cfg.paramName}`;
7202
+ const persisted = persistedFormValues?.[persistedKey];
7203
+ if (persisted && Array.isArray(persisted) && persisted.length > 0) {
7204
+ selections[cfg.paramName] = persisted.map((opt) => opt.value || opt);
7205
+ }
7206
+ }
7207
+ });
7208
+ return selections;
7209
+ }, [crossFilterConfigs, chatbotContext, persistedFormValues, messageIndex]);
6486
7210
  if (!formData || !Array.isArray(formData) || formData.length === 0) {
6487
7211
  return null;
6488
7212
  }
@@ -6544,7 +7268,7 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
6544
7268
  return null;
6545
7269
  return (jsxs("div", { className: "step-form-content", children: [showSavedFilters && filterSetOptions.length > 0 && (jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsx(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 && (jsx("hr", { style: { border: "none", borderTop: "1px solid #E0E0E0", margin: "12px 0" } })), jsx("div", { style: {
6546
7270
  ...(isFilterSelected && !isFormDisabled ? { pointerEvents: "none", opacity: 0.5 } : {}),
6547
- }, children: formFields }), buttonItems] }));
7271
+ }, children: crossFilterConfigs.length > 1 ? (jsx(CrossFilterProvider, { filters: crossFilterConfigs, fetchOptionsFn: fetchCrossFilterOptions, initialSelections: crossFilterInitialSelections, fetchOnMount: false, children: formFields })) : (formFields) }), buttonItems] }));
6548
7272
  };
6549
7273
 
6550
7274
  const useStyles$4 = makeStyles$1((theme) => ({
@@ -9468,10 +10192,7 @@ function UploadModal(props) {
9468
10192
  setSelectedFile(file);
9469
10193
  }
9470
10194
  else {
9471
- displaySnackMessages({
9472
- message: 'Please select only PDF files',
9473
- variant: 'error'
9474
- });
10195
+ displaySnackMessages('Please select only PDF files', 'error');
9475
10196
  }
9476
10197
  };
9477
10198
  const handleFileUpload = async () => {
@@ -9512,10 +10233,7 @@ function UploadModal(props) {
9512
10233
  }
9513
10234
  catch (error) {
9514
10235
  console.error("File upload error:", error);
9515
- displaySnackMessages({
9516
- message: "File upload failed",
9517
- variant: "error",
9518
- });
10236
+ displaySnackMessages("File upload failed", "error");
9519
10237
  }
9520
10238
  finally {
9521
10239
  setIsLoading(false);
@@ -13315,6 +14033,7 @@ const SmartBot = (props) => {
13315
14033
  // Dispatch hierarchy key-value pairs to store
13316
14034
  dispatch(setHierarchyKeyValue(hierarchyKeyValuePairs));
13317
14035
  setFilterOptions(combinedOptions);
14036
+ dispatch(setChatbotFilterOptions(combinedOptions));
13318
14037
  // Fetch saved filter sets for the plus-button menu
13319
14038
  fetchSavedFilterSets();
13320
14039
  }