impact-chatbot 2.3.70 → 2.3.71

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
@@ -6598,9 +6598,11 @@ const CrossFilterProvider = ({ filters, fetchOptionsFn, initialSelections = {},
6598
6598
  * @param {Array} existingSelections - Upstream filter selections
6599
6599
  * Each item: { filterName, attributeName, values, checkAll }
6600
6600
  * @param {Array} allFilters - Full array of all filter configs
6601
+ * @param {Object|null} preSelectedFilters - Optional pre-selected filters from init response
6602
+ * Format: { param_name: { values: [...], label, dimension, is_mandatory } }
6601
6603
  * @returns {Promise<Array<{label, value}>>} - Formatted options
6602
6604
  */
6603
- const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], allFilters = []) => {
6605
+ const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], allFilters = [], preSelectedFilters = null) => {
6604
6606
  try {
6605
6607
  const attributeName = filterConfig.column_name ||
6606
6608
  filterConfig.attribute_name ||
@@ -6633,6 +6635,39 @@ const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], al
6633
6635
  display_order: fullConfig?.display_order || fullConfig?.ordering || 0,
6634
6636
  };
6635
6637
  });
6638
+ // Build pre-selected filter entries from init response (if provided)
6639
+ // These are always included in the payload alongside user selections
6640
+ const preSelectedEntries = [];
6641
+ if (preSelectedFilters && typeof preSelectedFilters === "object") {
6642
+ Object.entries(preSelectedFilters).forEach(([key, config]) => {
6643
+ // Skip if this filter is the one we're fetching options for
6644
+ if (key === attributeName)
6645
+ return;
6646
+ // Skip if user has already selected values for this filter (user selection takes precedence)
6647
+ const userAlreadySelected = filtersArray.some((f) => f.attribute_name === key || f.filter_id === key);
6648
+ if (userAlreadySelected)
6649
+ return;
6650
+ const values = Array.isArray(config.values) ? config.values : [];
6651
+ if (values.length === 0)
6652
+ return;
6653
+ preSelectedEntries.push({
6654
+ filter_name: config.label || key,
6655
+ filter_id: key,
6656
+ filter_type: "cascaded",
6657
+ dimension: config.dimension || dimension,
6658
+ display_type: "dropdown",
6659
+ check_configuration: [],
6660
+ is_mandatory: config.is_mandatory || false,
6661
+ extra: {},
6662
+ values: values,
6663
+ attribute_name: key,
6664
+ operator: "in",
6665
+ display_order: 0,
6666
+ });
6667
+ });
6668
+ }
6669
+ // Merge: pre-selected filters first, then user selections
6670
+ const combinedFilters = [...preSelectedEntries, ...filtersArray];
6636
6671
  const payload = {
6637
6672
  attributes: [
6638
6673
  {
@@ -6642,7 +6677,7 @@ const fetchCrossFilterOptions = async (filterConfig, existingSelections = [], al
6642
6677
  },
6643
6678
  ],
6644
6679
  filter_type: "cascaded",
6645
- filters: filtersArray,
6680
+ filters: combinedFilters,
6646
6681
  is_urm_filter: true,
6647
6682
  screen_name: "Chatbot",
6648
6683
  application_code: 1,
@@ -6757,11 +6792,15 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6757
6792
  const [currentOptions, setCurrentOptions] = useState([]);
6758
6793
  const persistedFormValues = useSelector((state) => state.smartBotReducer.persistedFormValues);
6759
6794
  const [currentSelectedOptions, setCurrentSelectedOptions] = useState(persistedFormValues?.[formKey] || []);
6760
- const [isAllSelected, setIsAllSelected] = useState(false);
6795
+ const selectAllKey = `${formKey}__selectAllCount`;
6796
+ const [isAllSelected, setIsAllSelected] = useState(() => {
6797
+ return (persistedFormValues?.[selectAllKey] || 0) > 0;
6798
+ });
6761
6799
  const [initialOptions, setInitialOptions] = useState([]);
6762
6800
  const allOptionsRef = useRef([]);
6763
6801
  const isSearchActiveRef = useRef(false);
6764
6802
  const searchTermRef = useRef("");
6803
+ const selectAllCountRef = useRef(persistedFormValues?.[selectAllKey] || 0);
6765
6804
  const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
6766
6805
  const heirarchyKeyValuePairs = useSelector((state) => state.smartBotReducer.heirarchyKeyValuePairs);
6767
6806
  const dispatch = useDispatch();
@@ -6902,16 +6941,16 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6902
6941
  updated: true,
6903
6942
  },
6904
6943
  }));
6905
- dispatch(setPersistedFormValues({ [formKey]: [] }));
6944
+ dispatch(setPersistedFormValues({ [formKey]: [], [selectAllKey]: 0 }));
6906
6945
  // Notify cross-filter context to clear downstream filters
6907
6946
  if (isCascading) {
6908
6947
  crossFilterCtx.onFilterChange(paramName, []);
6909
6948
  }
6910
6949
  }, handleChange: (selected) => onChange(selected), isCloseWhenClickOutside: true, setIsOpen: (open) => {
6911
6950
  setIsOpen(open);
6912
- // When dropdown closes after a filtered select-all on a subset,
6913
- // reset the isAllSelected flag so scroll-to-load-more doesn't auto-select more items
6914
- if (!open && isAllSelected && currentSelectedOptions.length < allOptionsRef.current.length) {
6951
+ // When dropdown closes after a search-filtered select-all on a subset,
6952
+ // reset the isAllSelected flag since only a subset was selected
6953
+ if (!open && isAllSelected && isSearchActiveRef.current) {
6915
6954
  setIsAllSelected(false);
6916
6955
  }
6917
6956
  if (isCascading) {
@@ -6951,6 +6990,8 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6951
6990
  const nextOptions = [...currentOptions, ...newBatch];
6952
6991
  setCurrentOptions(nextOptions);
6953
6992
  setInitialOptions(nextOptions);
6993
+ // When all are selected, mark newly loaded items as selected too
6994
+ // so they render with checkmarks in the dropdown
6954
6995
  if (isAllSelected) {
6955
6996
  setCurrentSelectedOptions(nextOptions);
6956
6997
  }
@@ -6959,17 +7000,20 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6959
7000
  if (e && e.target.checked) {
6960
7001
  // When search is active, select only the filtered/visible options
6961
7002
  // When no search is active, select ALL options from the full dataset
6962
- let optionsToSelect;
7003
+ // but only render the currently visible chunk to avoid 100k+ DOM nodes
6963
7004
  let valuesToDispatch;
6964
7005
  if (isSearchActiveRef.current) {
6965
- optionsToSelect = [...currentOptions];
7006
+ // Search-filtered select all: only select the visible filtered options
6966
7007
  valuesToDispatch = currentOptions.map((opt) => opt.value);
7008
+ setCurrentSelectedOptions([...currentOptions]);
7009
+ selectAllCountRef.current = currentOptions.length;
6967
7010
  }
6968
7011
  else {
6969
- optionsToSelect = allOptionsRef.current.map(formatOption);
7012
+ // Full select all: select all options but only render the visible chunk
6970
7013
  valuesToDispatch = allOptionsRef.current.map((opt) => opt.value);
7014
+ setCurrentSelectedOptions([...currentOptions]);
7015
+ selectAllCountRef.current = allOptionsRef.current.length;
6971
7016
  }
6972
- setCurrentSelectedOptions(optionsToSelect);
6973
7017
  setIsAllSelected(true);
6974
7018
  dispatch(setChatbotContext({
6975
7019
  ...chatbotContext,
@@ -6979,7 +7023,11 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6979
7023
  updated: true,
6980
7024
  },
6981
7025
  }));
6982
- dispatch(setPersistedFormValues({ [formKey]: optionsToSelect }));
7026
+ // Persist only the currently visible options (not all 100k+) to avoid Redux memory bloat
7027
+ dispatch(setPersistedFormValues({
7028
+ [formKey]: [...currentOptions],
7029
+ [selectAllKey]: selectAllCountRef.current,
7030
+ }));
6983
7031
  // Notify cross-filter context if cascading is active
6984
7032
  if (isCascading) {
6985
7033
  crossFilterCtx.onFilterChange(paramName, valuesToDispatch);
@@ -6996,15 +7044,17 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6996
7044
  updated: true,
6997
7045
  },
6998
7046
  }));
6999
- dispatch(setPersistedFormValues({ [formKey]: [] }));
7047
+ dispatch(setPersistedFormValues({ [formKey]: [], [selectAllKey]: 0 }));
7000
7048
  // Notify cross-filter context of deselection
7001
7049
  if (isCascading) {
7002
7050
  crossFilterCtx.onFilterChange(paramName, []);
7003
7051
  }
7004
7052
  }
7005
- }, customPlaceholderAfterSelect: currentSelectedOptions.length > 0
7006
- ? currentSelectedOptions.length
7007
- : null }) }));
7053
+ }, customPlaceholderAfterSelect: isAllSelected
7054
+ ? selectAllCountRef.current
7055
+ : currentSelectedOptions.length > 0
7056
+ ? currentSelectedOptions.length
7057
+ : null }) }));
7008
7058
  };
7009
7059
 
7010
7060
  const DatePickerContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
@@ -7220,7 +7270,7 @@ const STEP_FORM_TIMEOUT_KEY = "__stepFormTimedOut";
7220
7270
  * @param {Array} props.formData - Array of raw widget_data items from step_form chunk
7221
7271
  * @param {number} props.messageIndex - Index for form state persistence keys
7222
7272
  */
7223
- const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true }) => {
7273
+ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, showSavedFilters = true, preSelectedFilters = null }) => {
7224
7274
  const dispatch = useDispatch();
7225
7275
  const savedFilterSets = useSelector((state) => state.smartBotReducer.savedFilterSets);
7226
7276
  const persistedFormValues = useSelector((state) => state.smartBotReducer.persistedFormValues);
@@ -7537,7 +7587,7 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false, s
7537
7587
  return null;
7538
7588
  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: {
7539
7589
  ...(isFilterSelected && !isFormDisabled ? { pointerEvents: "none", opacity: 0.5 } : {}),
7540
- }, children: crossFilterConfigs.length > 1 ? (jsx(CrossFilterProvider, { filters: crossFilterConfigs, fetchOptionsFn: fetchCrossFilterOptions, initialSelections: crossFilterInitialSelections, fetchOnMount: false, children: formFields })) : (formFields) }), buttonItems] }));
7590
+ }, children: crossFilterConfigs.length >= 1 ? (jsx(CrossFilterProvider, { filters: crossFilterConfigs, fetchOptionsFn: (filterConfig, existingSelections, allFilters) => fetchCrossFilterOptions(filterConfig, existingSelections, allFilters, preSelectedFilters), initialSelections: crossFilterInitialSelections, fetchOnMount: false, children: formFields })) : (formFields) }), buttonItems] }));
7541
7591
  };
7542
7592
  /** Reset the timeout flag (call when a new conversation/message starts) */
7543
7593
  const resetStepFormTimeoutFlag = () => {
@@ -7813,7 +7863,7 @@ const getQuestionStatus$1 = (questionSteps) => {
7813
7863
  /**
7814
7864
  * Renders a single progress bar item (main point + sub-items)
7815
7865
  */
7816
- const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, isFormDisabled, onAllSubItemsAnimated = undefined }) => {
7866
+ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData, showSavedFilters = true, preSelectedFilters = null, isFormDisabled, onAllSubItemsAnimated = undefined }) => {
7817
7867
  const status = getQuestionStatus$1(questionSteps);
7818
7868
  const animatedCountRef = useRef(0);
7819
7869
  const [isExpanded, setIsExpanded] = useState(true);
@@ -7846,7 +7896,7 @@ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData,
7846
7896
  if (animatedCountRef.current >= arr.length && onAllSubItemsAnimated) {
7847
7897
  onAllSubItemsAnimated();
7848
7898
  }
7849
- } }) }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }) }))] })] }));
7899
+ } }) }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters }) }))] })] }));
7850
7900
  };
7851
7901
  const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, }) => {
7852
7902
  const classes = useStyles$4();
@@ -7929,8 +7979,9 @@ const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, s
7929
7979
  const formEntry = stepFormDataMap[question] || null;
7930
7980
  const formData = formEntry ? (Array.isArray(formEntry) ? formEntry : formEntry.widgets) : null;
7931
7981
  const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
7982
+ const preSelectedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.preSelectedFilters : null;
7932
7983
  const isLast = index === questions.length - 1;
7933
- return (jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: isLast && !showThinking, classes: classes, formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, onAllSubItemsAnimated: isLast && lastQuestionCompleted && !done
7984
+ return (jsx(ProgressBarItem$1, { question: question, questionSteps: questionSteps, isLast: isLast && !showThinking, classes: classes, formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters, onAllSubItemsAnimated: isLast && lastQuestionCompleted && !done
7934
7985
  ? () => setShowThinking(true)
7935
7986
  : undefined }, index));
7936
7987
  }), showThinking && !done && (jsx("div", { style: {
@@ -8748,6 +8799,7 @@ const StreamedContent = ({ botData }) => {
8748
8799
  stepFormDataMapRef.current[currentIntent] = {
8749
8800
  widgets: [...formWidgetData, stepFormSubmitButton],
8750
8801
  showSavedFilters: data.show_saved_filters !== false,
8802
+ preSelectedFilters: data.pre_selected_filters || null,
8751
8803
  };
8752
8804
  setStepFormDataMap({ ...stepFormDataMapRef.current });
8753
8805
  }
@@ -9686,7 +9738,7 @@ const getQuestionStatus = (questionSteps) => {
9686
9738
  /**
9687
9739
  * Renders a single progress bar item (main point + sub-items)
9688
9740
  */
9689
- const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, isFormDisabled, isRestreaming = false, showSavedFilters = true }) => {
9741
+ const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, isFormDisabled, isRestreaming = false, showSavedFilters = true, preSelectedFilters = null }) => {
9690
9742
  const baseStatus = getQuestionStatus(questionSteps);
9691
9743
  // When restreaming and this is the last item, show as in-progress
9692
9744
  const status = (isRestreaming && isLast) ? "in-progress" : baseStatus;
@@ -9715,7 +9767,7 @@ const ProgressBarItem = ({ question, questionSteps, isLast, classes, formData, i
9715
9767
  setIsExpanded(true);
9716
9768
  }
9717
9769
  }, [status, formData]);
9718
- return (jsxs("div", { className: classes.progressItem, children: [jsxs("div", { className: classes.progressTrack, children: [jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxs("div", { className: classes.progressContent, children: [jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxs("div", { className: classes.reasoningLabel, children: [jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters }) }))] })] }));
9770
+ return (jsxs("div", { className: classes.progressItem, children: [jsxs("div", { className: classes.progressTrack, children: [jsx("div", { className: `${classes.progressDot} ${dotClass}` }), !isLast && jsx("div", { className: `${classes.progressLine} ${lineClass}` })] }), jsxs("div", { className: classes.progressContent, children: [jsxs("div", { className: classes.progressHeader, onClick: handleToggle, children: [jsx("span", { className: `${classes.progressHeaderText} ${textClass}`, children: question }), hasSubItems && (jsx(ChevronRightIcon$1, { className: `${classes.progressChevron} ${textClass} ${isExpanded ? "expanded" : ""}` }))] }), hasSubItems && isExpanded && status === "in-progress" && (jsxs("div", { className: classes.reasoningLabel, children: [jsx(SvgReasoningIcon, {}), "Reasoning..."] })), hasSubItems && isExpanded && (jsx("div", { className: classes.progressSubItems, style: { maxHeight: isExpanded ? "500px" : "0", opacity: isExpanded ? 1 : 0 }, children: questionSteps.map((step, idx) => (jsxs("div", { className: classes.progressSubItem, children: [step.header, step.sub_header ? ` - ${step.sub_header}` : ""] }, idx))) })), formData && isExpanded && (jsx("div", { className: classes.stepFormContainer, children: jsx(StepFormContent, { formData: formData, isFormDisabled: isFormDisabled, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters }) }))] })] }));
9719
9771
  };
9720
9772
  const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, activeFormIntent = null, isRestreaming = false }) => {
9721
9773
  const classes = useStyles$3();
@@ -9741,11 +9793,12 @@ const Steps = ({ steps, questions = [], questionsStepsMap = {}, stepFormDataMap
9741
9793
  // Support both old array format and new object format { widgets, showSavedFilters }
9742
9794
  const formData = formEntry ? (Array.isArray(formEntry) ? formEntry : formEntry.widgets) : null;
9743
9795
  const showSavedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.showSavedFilters : true;
9796
+ const preSelectedFilters = formEntry && !Array.isArray(formEntry) ? formEntry.preSelectedFilters : null;
9744
9797
  // If activeFormIntent is set, only the matching form is enabled; all others stay disabled
9745
9798
  const formDisabledForThis = activeFormIntent
9746
9799
  ? question !== activeFormIntent
9747
9800
  : isFormDisabled;
9748
- return (jsx(ProgressBarItem, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: formDisabledForThis, isRestreaming: isRestreaming, showSavedFilters: showSavedFilters }, index));
9801
+ return (jsx(ProgressBarItem, { question: question, questionSteps: questionSteps, isLast: index === questions.length - 1, classes: classes, formData: formData, isFormDisabled: formDisabledForThis, isRestreaming: isRestreaming, showSavedFilters: showSavedFilters, preSelectedFilters: preSelectedFilters }, index));
9749
9802
  }) }));
9750
9803
  };
9751
9804
 
@@ -10004,6 +10057,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
10004
10057
  newStepFormDataMap[currentIntent] = {
10005
10058
  widgets: [...formWidgetData, submitButton],
10006
10059
  showSavedFilters: data.show_saved_filters !== false,
10060
+ preSelectedFilters: data.pre_selected_filters || null,
10007
10061
  };
10008
10062
  }
10009
10063
  }
@@ -10130,6 +10184,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
10130
10184
  newStepFormDataMap[currentIntent] = {
10131
10185
  widgets: [...formWidgetData, submitButton],
10132
10186
  showSavedFilters: data.show_saved_filters !== false,
10187
+ preSelectedFilters: data.pre_selected_filters || null,
10133
10188
  };
10134
10189
  }
10135
10190
  }