impact-chatbot 2.3.69 → 2.3.70

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
@@ -6742,6 +6742,7 @@ const SliderContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6742
6742
 
6743
6743
  const INITIAL_DISPLAY_COUNT = 100;
6744
6744
  const LOAD_MORE_COUNT = 100;
6745
+ const SEARCH_DISPLAY_LIMIT = 500;
6745
6746
  const formatOption = (option) => ({
6746
6747
  ...option,
6747
6748
  label: replaceSpecialCharacter(option.label.toString()),
@@ -6759,6 +6760,8 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6759
6760
  const [isAllSelected, setIsAllSelected] = useState(false);
6760
6761
  const [initialOptions, setInitialOptions] = useState([]);
6761
6762
  const allOptionsRef = useRef([]);
6763
+ const isSearchActiveRef = useRef(false);
6764
+ const searchTermRef = useRef("");
6762
6765
  const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
6763
6766
  const heirarchyKeyValuePairs = useSelector((state) => state.smartBotReducer.heirarchyKeyValuePairs);
6764
6767
  const dispatch = useDispatch();
@@ -6851,6 +6854,40 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6851
6854
  setCurrentOptions(initialSlice);
6852
6855
  }
6853
6856
  }, [isCascading]);
6857
+ // Custom search handler: searches ALL options (not just the loaded chunk)
6858
+ // Supports comma-separated values for multi-search
6859
+ const handleSearch = useCallback((event) => {
6860
+ const rawInput = event?.target?.value || "";
6861
+ searchTermRef.current = rawInput;
6862
+ const trimmed = rawInput.trim();
6863
+ if (!trimmed) {
6864
+ // Reset to initial lazy-loaded chunk
6865
+ isSearchActiveRef.current = false;
6866
+ const resetSlice = formatSlice(allOptionsRef.current, 0, INITIAL_DISPLAY_COUNT);
6867
+ setCurrentOptions(resetSlice);
6868
+ setInitialOptions(resetSlice);
6869
+ setIsAllSelected(false);
6870
+ return;
6871
+ }
6872
+ isSearchActiveRef.current = true;
6873
+ // Parse comma-separated terms
6874
+ const terms = trimmed
6875
+ .split(",")
6876
+ .map((t) => t.trim().toLowerCase())
6877
+ .filter(Boolean);
6878
+ // Search across ALL options, not just the loaded chunk
6879
+ const allRaw = allOptionsRef.current;
6880
+ const filtered = allRaw.filter((option) => {
6881
+ const labelLower = option.label?.toString().toLowerCase() || "";
6882
+ const valueLower = option.value?.toString().toLowerCase() || "";
6883
+ return terms.some((term) => labelLower.includes(term) || valueLower.includes(term));
6884
+ });
6885
+ // Format and cap the results to avoid UI freeze
6886
+ const formatted = filtered.slice(0, SEARCH_DISPLAY_LIMIT).map(formatOption);
6887
+ setCurrentOptions(formatted);
6888
+ setInitialOptions(formatted);
6889
+ setIsAllSelected(false);
6890
+ }, []);
6854
6891
  return (jsx("div", { style: { width: "100%", marginTop: "10px" }, children: jsx(Select, { currentOptions: currentOptions, setCurrentOptions: setCurrentOptions, label: heirarchyKeyValuePairs[paramName] || label, labelOrientation: labelOrientation,
6855
6892
  // inputPosition={inputPosition}
6856
6893
  // header={header}
@@ -6872,6 +6909,11 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6872
6909
  }
6873
6910
  }, handleChange: (selected) => onChange(selected), isCloseWhenClickOutside: true, setIsOpen: (open) => {
6874
6911
  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) {
6915
+ setIsAllSelected(false);
6916
+ }
6875
6917
  if (isCascading) {
6876
6918
  if (open) {
6877
6919
  // Lazy fetch: trigger cross-filter API call when dropdown opens for the first time
@@ -6898,7 +6940,10 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6898
6940
  }
6899
6941
  }
6900
6942
  }
6901
- }, 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: () => {
6943
+ }, 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, onSearch: handleSearch, onMenuScrollToBottom: () => {
6944
+ // Only allow scroll-to-load-more when NOT in search mode
6945
+ if (isSearchActiveRef.current)
6946
+ return;
6902
6947
  const allRaw = allOptionsRef.current;
6903
6948
  if (allRaw.length > 0 && currentOptions.length < allRaw.length) {
6904
6949
  const nextCount = Math.min(currentOptions.length + LOAD_MORE_COUNT, allRaw.length);
@@ -6912,33 +6957,53 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
6912
6957
  }
6913
6958
  }, onSelectAll: (e) => {
6914
6959
  if (e && e.target.checked) {
6915
- setCurrentSelectedOptions([...currentOptions]);
6960
+ // When search is active, select only the filtered/visible options
6961
+ // When no search is active, select ALL options from the full dataset
6962
+ let optionsToSelect;
6963
+ let valuesToDispatch;
6964
+ if (isSearchActiveRef.current) {
6965
+ optionsToSelect = [...currentOptions];
6966
+ valuesToDispatch = currentOptions.map((opt) => opt.value);
6967
+ }
6968
+ else {
6969
+ optionsToSelect = allOptionsRef.current.map(formatOption);
6970
+ valuesToDispatch = allOptionsRef.current.map((opt) => opt.value);
6971
+ }
6972
+ setCurrentSelectedOptions(optionsToSelect);
6916
6973
  setIsAllSelected(true);
6917
- const allValues = allOptionsRef.current.map((opt) => opt.value);
6918
6974
  dispatch(setChatbotContext({
6919
6975
  ...chatbotContext,
6920
6976
  [bodyText?.paramName]: {
6921
6977
  ...chatbotContext?.[bodyText?.paramName],
6922
- [bodyText?.paramName]: allValues,
6978
+ [bodyText?.paramName]: valuesToDispatch,
6923
6979
  updated: true,
6924
6980
  },
6925
6981
  }));
6926
- dispatch(setPersistedFormValues({ [formKey]: currentOptions }));
6982
+ dispatch(setPersistedFormValues({ [formKey]: optionsToSelect }));
6927
6983
  // Notify cross-filter context if cascading is active
6928
6984
  if (isCascading) {
6929
- crossFilterCtx.onFilterChange(paramName, allValues);
6985
+ crossFilterCtx.onFilterChange(paramName, valuesToDispatch);
6930
6986
  }
6931
6987
  }
6932
6988
  else {
6933
6989
  setCurrentSelectedOptions([]);
6934
6990
  setIsAllSelected(false);
6991
+ dispatch(setChatbotContext({
6992
+ ...chatbotContext,
6993
+ [bodyText?.paramName]: {
6994
+ ...chatbotContext?.[bodyText?.paramName],
6995
+ [bodyText?.paramName]: [],
6996
+ updated: true,
6997
+ },
6998
+ }));
6999
+ dispatch(setPersistedFormValues({ [formKey]: [] }));
6935
7000
  // Notify cross-filter context of deselection
6936
7001
  if (isCascading) {
6937
7002
  crossFilterCtx.onFilterChange(paramName, []);
6938
7003
  }
6939
7004
  }
6940
- }, customPlaceholderAfterSelect: isAllSelected && allOptionsRef.current.length > 0
6941
- ? allOptionsRef.current.length
7005
+ }, customPlaceholderAfterSelect: currentSelectedOptions.length > 0
7006
+ ? currentSelectedOptions.length
6942
7007
  : null }) }));
6943
7008
  };
6944
7009