impact-chatbot 2.3.33 → 2.3.34

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
@@ -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, setPersistedFormValues, setCurrentAgentChatId, setThinkingContext, clearPersistedFormValues, setHierarchyKeyValue, setSavedFilterSets } from 'core/actions/smartBotActions';
21
+ import { setChatbotContext, setStepFormStreamData, setPersistedFormValues, clearPersistedFormValues, setCurrentAgentChatId, setThinkingContext, setHierarchyKeyValue, 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';
@@ -5076,7 +5076,8 @@ const sseevent = (message, messageToStoreRef) => {
5076
5076
  parsedData?.response_heading || "";
5077
5077
  }
5078
5078
  else if (parsedData?.message === "[DONE]" &&
5079
- !isEmpty$1(parsedData?.widget_data)) {
5079
+ !isEmpty$1(parsedData?.widget_data) &&
5080
+ parsedData?.status !== "step_form") {
5080
5081
  // Accumulate widget_data chunks like host app
5081
5082
  let finalWidgetData = isArray$1(parsedData.widget_data)
5082
5083
  ? parsedData.widget_data
@@ -5124,15 +5125,6 @@ const sseevent = (message, messageToStoreRef) => {
5124
5125
  if (currentIntent) {
5125
5126
  messageToStoreRef.current.stepFormData[currentIntent] = formWidgetData;
5126
5127
  }
5127
- let previousWidgetData = isArray$1(messageToStoreRef.current.appendedData)
5128
- ? messageToStoreRef.current.appendedData
5129
- : isEmpty$1(messageToStoreRef.current.appendedData)
5130
- ? []
5131
- : [messageToStoreRef.current.appendedData];
5132
- messageToStoreRef.current.appendedData = [
5133
- ...previousWidgetData,
5134
- ...formWidgetData,
5135
- ];
5136
5128
  messageToStoreRef.current.additionalArgs = parsedData?.additional_args
5137
5129
  ? parsedData.additional_args
5138
5130
  : {};
@@ -5271,7 +5263,7 @@ const useStyles$4 = makeStyles((theme) => ({
5271
5263
  marginTop: pxToRem(16),
5272
5264
  }
5273
5265
  }));
5274
- const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = false }) => {
5266
+ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = false, isFormValid = true }) => {
5275
5267
  const classes = useStyles$4();
5276
5268
  const dispatch = useDispatch();
5277
5269
  const sourceRef = useRef(null);
@@ -5377,7 +5369,7 @@ const ButtonContent = ({ bodyText, isFormDisabled = false, isStepFormSubmit = fa
5377
5369
  if (!Array.isArray(bodyText.buttons)) {
5378
5370
  return null;
5379
5371
  }
5380
- return bodyText.buttons.map((button, index) => (jsx("div", { children: jsx(Button, { variant: button.variant || "primary", size: button.size || "medium", onClick: () => handleButtonClick(), disabled: button.disabled || isFormDisabled, className: button.className, icon: button.icon, iconPlacement: button.iconPlacement || "left", children: button.label }) }, index)));
5372
+ return bodyText.buttons.map((button, index) => (jsx("div", { children: jsx(Button, { variant: button.variant || "primary", size: button.size || "medium", onClick: () => handleButtonClick(), disabled: button.disabled || isFormDisabled || (isStepFormSubmit && !isFormValid), className: button.className, icon: button.icon, iconPlacement: button.iconPlacement || "left", children: button.label }) }, index)));
5381
5373
  };
5382
5374
  return (jsxs("div", { className: classes.buttonContainer, children: [bodyText.message && (jsx("div", { className: classes.message, children: bodyText.message })), jsx("div", { className: classes.buttonRow, children: renderButtons() })] }));
5383
5375
  };
@@ -5758,6 +5750,12 @@ const SelectContent = ({ bodyText, isFormDisabled = false, messageIndex }) => {
5758
5750
  console.error("Error in select handleChange", error);
5759
5751
  }
5760
5752
  };
5753
+ useEffect(() => {
5754
+ const persisted = persistedFormValues?.[formKey];
5755
+ if (!persisted || (Array.isArray(persisted) && persisted.length === 0)) {
5756
+ setCurrentSelectedOptions([]);
5757
+ }
5758
+ }, [persistedFormValues, formKey]);
5761
5759
  useEffect(() => {
5762
5760
  let formattedOptions = options.map((option) => {
5763
5761
  return {
@@ -5980,6 +5978,13 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false })
5980
5978
  const savedFilterSets = useSelector((state) => state.smartBotReducer.savedFilterSets);
5981
5979
  const persistedFormValues = useSelector((state) => state.smartBotReducer.persistedFormValues);
5982
5980
  const chatbotContext = useSelector((state) => state.smartBotReducer.chatbotContext);
5981
+ const stepFormStreamData = useSelector((state) => state.smartBotReducer.stepFormStreamData);
5982
+ const [isFormSubmitted, setIsFormSubmitted] = useState(false);
5983
+ useEffect(() => {
5984
+ if (stepFormStreamData?.status === "streaming_start") {
5985
+ setIsFormSubmitted(true);
5986
+ }
5987
+ }, [stepFormStreamData]);
5983
5988
  const [isFilterSetOpen, setIsFilterSetOpen] = useState(false);
5984
5989
  const [selectedFilterSet, setSelectedFilterSet] = useState(() => {
5985
5990
  // Restore from chatbotContext if available (persists across tab switches)
@@ -6000,6 +6005,7 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false })
6000
6005
  const selectedValue = Array.isArray(selected) ? selected[0]?.value : selected?.value;
6001
6006
  if (!selectedValue) {
6002
6007
  dispatch(setChatbotContext({}));
6008
+ dispatch(clearPersistedFormValues());
6003
6009
  return;
6004
6010
  }
6005
6011
  const fullFilterObj = (savedFilterSets || []).find((f) => (f.fuc_code || f.name || f.label) === selectedValue);
@@ -6047,8 +6053,32 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false })
6047
6053
  return val && (Array.isArray(val) ? val.length > 0 : !!val);
6048
6054
  });
6049
6055
  }, [persistedFormValues, messageIndex]);
6050
- const formFieldsDisabled = isFormDisabled || isFilterSelected;
6051
- const savedFilterDisabled = isFormDisabled || isFormFieldUsed;
6056
+ const formFieldsDisabled = isFormDisabled || isFilterSelected || isFormSubmitted;
6057
+ const savedFilterDisabled = isFormDisabled || isFormFieldUsed || isFormSubmitted;
6058
+ const requiredFieldsFilled = useMemo(() => {
6059
+ if (!formData || !Array.isArray(formData))
6060
+ return false;
6061
+ const requiredParams = formData
6062
+ .filter((item) => item?.data?.isRequired)
6063
+ .map((item) => item.data.param_name);
6064
+ if (requiredParams.length === 0)
6065
+ return true;
6066
+ return requiredParams.every((param) => {
6067
+ // Check chatbotContext (populated by saved filters)
6068
+ const ctx = chatbotContext?.[param];
6069
+ if (ctx && ctx.updated) {
6070
+ const val = ctx[param];
6071
+ if (val && (Array.isArray(val) ? val.length > 0 : !!val))
6072
+ return true;
6073
+ }
6074
+ // Check persistedFormValues (populated by manual form field selection)
6075
+ const persistedKey = `${messageIndex}_${param}`;
6076
+ const persistedVal = persistedFormValues?.[persistedKey];
6077
+ if (persistedVal && (Array.isArray(persistedVal) ? persistedVal.length > 0 : !!persistedVal))
6078
+ return true;
6079
+ return false;
6080
+ });
6081
+ }, [formData, chatbotContext, persistedFormValues, messageIndex]);
6052
6082
  if (!formData || !Array.isArray(formData) || formData.length === 0) {
6053
6083
  return null;
6054
6084
  }
@@ -6076,7 +6106,7 @@ const StepFormContent = ({ formData, messageIndex = 0, isFormDisabled = false })
6076
6106
  case "radio":
6077
6107
  return jsx(RadioContent, { bodyText: parsedData.bodyText, isFormDisabled: formFieldsDisabled, messageIndex: messageIndex }, key);
6078
6108
  case "button":
6079
- return jsx(ButtonContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled, isStepFormSubmit: true }, key);
6109
+ return jsx(ButtonContent, { bodyText: parsedData.bodyText, isFormDisabled: isFormDisabled || isFormSubmitted, isStepFormSubmit: true, isFormValid: requiredFieldsFilled }, key);
6080
6110
  case "input":
6081
6111
  return jsx(InputContent, { bodyText: parsedData.bodyText, isFormDisabled: formFieldsDisabled, messageIndex: messageIndex }, key);
6082
6112
  case "image":
@@ -6137,12 +6167,10 @@ const useStyles$2 = makeStyles$1((theme) => ({
6137
6167
  "@keyframes slideDown": {
6138
6168
  "0%": {
6139
6169
  opacity: 0,
6140
- maxHeight: 0,
6141
6170
  transform: "translateY(-12px)",
6142
6171
  },
6143
6172
  "100%": {
6144
6173
  opacity: 1,
6145
- maxHeight: "2000px",
6146
6174
  transform: "translateY(0)",
6147
6175
  },
6148
6176
  },
@@ -6255,8 +6283,13 @@ const useStyles$2 = makeStyles$1((theme) => ({
6255
6283
  padding: `${pxToRem(8)} ${pxToRem(14)}`,
6256
6284
  background: colours.greys100,
6257
6285
  borderRadius: pxToRem(8),
6258
- overflow: "hidden",
6259
- transition: "max-height 0.3s ease, opacity 0.3s ease",
6286
+ transition: "opacity 0.3s ease",
6287
+ overflow: "auto",
6288
+ maxHeight: pxToRem(300),
6289
+ scrollbarWidth: "none",
6290
+ "&::-webkit-scrollbar": {
6291
+ display: "none",
6292
+ },
6260
6293
  },
6261
6294
  reasoningLabel: {
6262
6295
  display: "flex",
@@ -6309,8 +6342,10 @@ const useStyles$2 = makeStyles$1((theme) => ({
6309
6342
  * - "not-started": no steps or all pending
6310
6343
  */
6311
6344
  const getQuestionStatus$1 = (questionSteps) => {
6312
- if (!questionSteps || questionSteps.length === 0)
6345
+ if (!questionSteps)
6313
6346
  return "not-started";
6347
+ if (questionSteps.length === 0)
6348
+ return "completed";
6314
6349
  const hasError = questionSteps.some((s) => s.step_status === "error");
6315
6350
  if (hasError)
6316
6351
  return "error";
@@ -6351,8 +6386,11 @@ const ProgressBarItem$1 = ({ question, questionSteps, isLast, classes, formData,
6351
6386
  if (status === "in-progress" || status === "error" || formData) {
6352
6387
  setIsExpanded(true);
6353
6388
  }
6389
+ else if (status === "completed" && !formData) {
6390
+ setIsExpanded(false);
6391
+ }
6354
6392
  }, [status, formData]);
6355
- 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 }) }))] })] }));
6393
+ 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: { 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 }) }))] })] }));
6356
6394
  };
6357
6395
  const Steps$1 = ({ steps, setSteps, done, setTabValue, setDone, finalStepDone, setFinalStepDone, stepChange, currentMode, questions = [], questionsStepsMap = {}, stepFormDataMap = {}, isFormDisabled = false, }) => {
6358
6396
  const classes = useStyles$2();
@@ -6595,7 +6633,7 @@ const StreamedContent = ({ botData }) => {
6595
6633
  // }
6596
6634
  let endPoint = botData?.utilityObject?.endpoint
6597
6635
  ? `${BASE_API}${botData?.utilityObject?.endpoint}`
6598
- : `${BASE_API}/core/chatbot/navigation-v2`;
6636
+ : `${BASE_API}/core/chatbot/navigation-v3`;
6599
6637
  let method = botData?.utilityObject?.method
6600
6638
  ? botData?.utilityObject?.method
6601
6639
  : "PUT";
@@ -6723,17 +6761,48 @@ const StreamedContent = ({ botData }) => {
6723
6761
  }
6724
6762
  stepRef.current = newSteps;
6725
6763
  setSteps(newSteps);
6726
- if (currentIntent && questionsStepsMapRef.current[currentIntent]) {
6764
+ if (currentIntent) {
6765
+ // Auto-create entry if no questions chunk was received
6766
+ if (!questionsStepsMapRef.current[currentIntent]) {
6767
+ questionsStepsMapRef.current[currentIntent] = [
6768
+ {
6769
+ header: "Processing Request",
6770
+ sub_header: "Analyzing the current request",
6771
+ step_status: "not-completed",
6772
+ },
6773
+ ];
6774
+ // Add intent to questions list if not already present
6775
+ if (!questionsRef.current.includes(currentIntent)) {
6776
+ questionsRef.current = [...questionsRef.current, currentIntent];
6777
+ setQuestions([...questionsRef.current]);
6778
+ }
6779
+ }
6727
6780
  let intentSteps = cloneDeep(questionsStepsMapRef.current[currentIntent]);
6728
- if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
6729
- intentSteps[0].step_status = "completed";
6781
+ if (newStep.header) {
6782
+ // Only add/update sub-steps that have a non-empty header
6783
+ const existingIdx = intentSteps.findIndex((s) => s.header === newStep.header);
6784
+ if (existingIdx !== -1) {
6785
+ intentSteps[existingIdx] = newStep;
6786
+ }
6787
+ else {
6788
+ intentSteps.push(newStep);
6789
+ }
6730
6790
  }
6731
- const existingIdx = intentSteps.findIndex((s) => s.header === newStep.header);
6732
- if (existingIdx !== -1) {
6733
- intentSteps[existingIdx] = newStep;
6791
+ else if (newStep.step_status === "completed") {
6792
+ // Empty header + completed: remove the placeholder so no bullet shows
6793
+ const placeholderIdx = intentSteps.findIndex((s) => s.header === "Processing Request");
6794
+ if (placeholderIdx !== -1 && intentSteps.length === 1) {
6795
+ intentSteps.splice(placeholderIdx, 1);
6796
+ }
6797
+ else if (placeholderIdx !== -1) {
6798
+ intentSteps[placeholderIdx].step_status = "completed";
6799
+ }
6734
6800
  }
6735
- else {
6736
- intentSteps.push(newStep);
6801
+ // If the latest step for this intent is completed, mark all sub-steps as completed
6802
+ if (newStep.step_status === "completed") {
6803
+ intentSteps.forEach((s) => {
6804
+ s.step_status = "completed";
6805
+ });
6737
6806
  }
6738
6807
  questionsStepsMapRef.current[currentIntent] = intentSteps;
6739
6808
  setQuestionsStepsMap(cloneDeep(questionsStepsMapRef.current));
@@ -6766,6 +6835,18 @@ const StreamedContent = ({ botData }) => {
6766
6835
  setStepFormDataMap(cloneDeep(stepFormDataMapRef.current));
6767
6836
  }
6768
6837
  setStepChange((prev) => !prev);
6838
+ // Persist IDs immediately when step_form arrives (AxiosEventSource already set them)
6839
+ localStorage.setItem("stepForm_sessionId", messageToStoreRef.current.sessionId || "");
6840
+ localStorage.setItem("stepForm_chatId", messageToStoreRef.current.uniqueChatId || "");
6841
+ localStorage.setItem("stepForm_agentId", botData.inputBody?.agent_id || "");
6842
+ localStorage.setItem("stepForm_baseUrl", baseUrl || "");
6843
+ // If this is the [DONE] chunk, mark streaming as complete
6844
+ if (data.message === "[DONE]") {
6845
+ setIsStreamingDone(true);
6846
+ const doneState = streamStateMap.get(streamKey);
6847
+ if (doneState)
6848
+ doneState.completed = true;
6849
+ }
6769
6850
  }
6770
6851
  else if (data.message !== "[DONE]") {
6771
6852
  setStepsDone(true);
@@ -6928,7 +7009,9 @@ const StreamedContent = ({ botData }) => {
6928
7009
  let sendButton = document.getElementById("chat-input-send-button");
6929
7010
  // sendButton.disabled = false;
6930
7011
  let dummyButton = {};
7012
+ const hasStepForm = !isEmpty(messageToStoreRef.current.stepFormData);
6931
7013
  if (!wasStreamingAborted &&
7014
+ !hasStepForm &&
6932
7015
  (!messageToStoreRef.current.initValue ||
6933
7016
  messageToStoreRef.current.status === "follow-up")) {
6934
7017
  dummyButton = {
@@ -7335,8 +7418,13 @@ const useStyles$1 = makeStyles$1((theme) => ({
7335
7418
  padding: `${pxToRem(8)} ${pxToRem(14)}`,
7336
7419
  background: colours.greys100,
7337
7420
  borderRadius: pxToRem(8),
7338
- overflow: "hidden",
7339
7421
  transition: "max-height 0.3s ease, opacity 0.3s ease",
7422
+ overflow: "auto",
7423
+ maxHeight: pxToRem(300),
7424
+ scrollbarWidth: "none",
7425
+ "&::-webkit-scrollbar": {
7426
+ display: "none",
7427
+ },
7340
7428
  },
7341
7429
  reasoningLabel: {
7342
7430
  display: "flex",
@@ -7483,6 +7571,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7483
7571
  const [stepFormDataMapState, setStepFormDataMapState] = useState(cloneDeep(initialStepFormDataMap));
7484
7572
  const [widgetContent, setWidgetContent] = useState([]);
7485
7573
  const [isRestreaming, setIsRestreaming] = useState(false);
7574
+ const [stepFormSubmitted, setStepFormSubmitted] = useState(false);
7486
7575
  // Refs for accumulating state during streaming (avoids stale closures)
7487
7576
  const stepsRef = useRef(stepsState);
7488
7577
  const questionsRef = useRef(questionsState);
@@ -7523,6 +7612,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7523
7612
  dispatch(setStepFormStreamData(null));
7524
7613
  if (payload.status === "streaming_start") {
7525
7614
  setIsRestreaming(true);
7615
+ setStepFormSubmitted(true);
7526
7616
  setTabValue("steps");
7527
7617
  return;
7528
7618
  }
@@ -7563,7 +7653,18 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7563
7653
  newSteps.push(newStep);
7564
7654
  }
7565
7655
  // Update per-question steps map
7566
- if (currentIntent && newQuestionsStepsMap[currentIntent]) {
7656
+ if (currentIntent) {
7657
+ // If this is a new intent we haven't seen, add it to questions and map
7658
+ if (!newQuestionsStepsMap[currentIntent]) {
7659
+ newQuestions.push(currentIntent);
7660
+ newQuestionsStepsMap[currentIntent] = [
7661
+ {
7662
+ header: "Processing Request",
7663
+ sub_header: "Analyzing the current request",
7664
+ step_status: "not-completed",
7665
+ },
7666
+ ];
7667
+ }
7567
7668
  const intentSteps = newQuestionsStepsMap[currentIntent];
7568
7669
  if (intentSteps.length === 1 && intentSteps[0].header === "Processing Request") {
7569
7670
  intentSteps[0].step_status = "completed";
@@ -7575,6 +7676,10 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7575
7676
  else {
7576
7677
  intentSteps.push(newStep);
7577
7678
  }
7679
+ // Mark all sub-steps completed when the latest step is completed
7680
+ if (newStep.step_status === "completed") {
7681
+ intentSteps.forEach((s) => { s.step_status = "completed"; });
7682
+ }
7578
7683
  newQuestionsStepsMap[currentIntent] = intentSteps;
7579
7684
  }
7580
7685
  }
@@ -7638,7 +7743,7 @@ const TabularContent = ({ steps: initialSteps, currentTabValue, children, questi
7638
7743
  icon: jsx(PsychologyOutlinedIcon, { fontSize: "large" }),
7639
7744
  },
7640
7745
  ], tabPanels: [
7641
- jsx(Steps, { steps: stepsState, questions: questionsState, questionsStepsMap: questionsStepsMapState, stepFormDataMap: stepFormDataMapState, isFormDisabled: isFormDisabled && !isRestreaming, isRestreaming: isRestreaming }),
7746
+ jsx(Steps, { steps: stepsState, questions: questionsState, questionsStepsMap: questionsStepsMapState, stepFormDataMap: stepFormDataMapState, isFormDisabled: (isFormDisabled && !isRestreaming) || stepFormSubmitted, isRestreaming: isRestreaming }),
7642
7747
  jsxs(AgentResponse, { children: [children, renderedWidgets.length > 0 && (jsx("div", { className: "restream-widget-content", children: renderedWidgets }))] }),
7643
7748
  ], value: tabValue }) }));
7644
7749
  };