impact-chatbot 2.3.85 → 2.3.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -1442,31 +1442,50 @@ const ThinkinHeaderInfo = (props) => {
1442
1442
  });
1443
1443
  const { streamStartTime, isStreamCompleted, finalElapsedSeconds, thinkingHeaderMessage } = thinkingContext;
1444
1444
  const [elapsed, setElapsed] = React.useState(0);
1445
+ const [frozenText, setFrozenText] = React.useState(null);
1445
1446
  const intervalRef = React.useRef(null);
1446
1447
  // Once this instance sees "completed", freeze it permanently so a future
1447
1448
  // chat's streamStartTime doesn't cause it to start ticking again.
1448
1449
  const frozenRef = React.useRef(false);
1449
1450
  const frozenTextRef = React.useRef(null);
1450
- const streamStartTimeRef = React.useRef(null); // Track streamStartTime changes to unfreeze
1451
+ // The streamStartTime this instance latched onto. Used to detect when a
1452
+ // different stream has taken over (e.g. the user asked a new question while
1453
+ // this message's step form was still waiting for input).
1454
+ const ownStartTimeRef = React.useRef(null);
1455
+ /**
1456
+ * Freezes this instance permanently on a final label and elapsed value.
1457
+ */
1458
+ const freeze = (text, seconds) => {
1459
+ frozenRef.current = true;
1460
+ frozenTextRef.current = text;
1461
+ setFrozenText(text);
1462
+ setElapsed(seconds);
1463
+ };
1451
1464
  React.useEffect(() => {
1452
1465
  // If already frozen (stream completed), NEVER unfreeze.
1453
1466
  // This prevents a new chat's streamStartTime from restarting this timer.
1454
1467
  if (frozenRef.current)
1455
1468
  return;
1456
- // Track streamStartTime changes for non-frozen instances
1457
- if (streamStartTimeRef.current !== streamStartTime) {
1458
- streamStartTimeRef.current = streamStartTime;
1469
+ // Adopt the first non-null streamStartTime we see as this instance's own
1470
+ if (ownStartTimeRef.current === null && streamStartTime) {
1471
+ ownStartTimeRef.current = streamStartTime;
1459
1472
  }
1473
+ const ownStartTime = ownStartTimeRef.current;
1460
1474
  // Clear any existing interval
1461
1475
  if (intervalRef.current) {
1462
1476
  clearInterval(intervalRef.current);
1463
1477
  intervalRef.current = null;
1464
1478
  }
1465
1479
  if (isStreamCompleted && typeof finalElapsedSeconds === 'number') {
1466
- // Freeze this instance it will never tick again
1467
- frozenRef.current = true;
1468
- frozenTextRef.current = `Completed in ${formatElapsedTime(finalElapsedSeconds)}`;
1469
- setElapsed(finalElapsedSeconds);
1480
+ // Freeze this instance - it will never tick again
1481
+ freeze(`Completed in ${formatElapsedTime(finalElapsedSeconds)}`, finalElapsedSeconds);
1482
+ }
1483
+ else if (ownStartTime !== null && streamStartTime !== ownStartTime) {
1484
+ // A different stream has started (new question) while this one never
1485
+ // completed - typically an abandoned step form. Freeze on this
1486
+ // instance's OWN elapsed time instead of following the new stream.
1487
+ const ownElapsed = Math.floor((Date.now() - ownStartTime) / 1000);
1488
+ freeze(`Completed in ${formatElapsedTime(ownElapsed)}`, ownElapsed);
1470
1489
  }
1471
1490
  else if (streamStartTime && !isStreamCompleted) {
1472
1491
  // Live timer — update every second
@@ -1487,8 +1506,8 @@ const ThinkinHeaderInfo = (props) => {
1487
1506
  }, [streamStartTime, isStreamCompleted, finalElapsedSeconds]);
1488
1507
  // Determine display text
1489
1508
  let displayText = thinkingHeaderMessage || '';
1490
- if (frozenRef.current && frozenTextRef.current) {
1491
- displayText = frozenTextRef.current;
1509
+ if (frozenText || (frozenRef.current && frozenTextRef.current)) {
1510
+ displayText = frozenText || frozenTextRef.current;
1492
1511
  }
1493
1512
  else if (streamStartTime && !isStreamCompleted) {
1494
1513
  displayText = `Working for ${formatElapsedTime(elapsed)}`;
@@ -2482,6 +2501,20 @@ const useChatFlow = (chatDataRef, setLoader, setFlowType, setScreenName, setUser
2482
2501
  }
2483
2502
  if (data.flow_type === "agent" && data.actionType === "direct") {
2484
2503
  data.baseUrl = baseUrl;
2504
+ // Reset the timer before the request goes out (same as index.jsx
2505
+ // handleSendMessage). Without this the new ThinkinHeaderInfo mounts while
2506
+ // the previous response's "completed" state is still in Redux and freezes
2507
+ // itself on that stale elapsed time.
2508
+ // streamStartTime stays null here: processStream sets it, so a question
2509
+ // has exactly one start time (two would make the new header look like a
2510
+ // superseded one and freeze it at 0m:00s).
2511
+ dispatch(smartBotActions.setThinkingContext({
2512
+ thinkingContent: "",
2513
+ thinkingHeaderMessage: "Working for 0m:00s",
2514
+ streamStartTime: null,
2515
+ isStreamCompleted: false,
2516
+ finalElapsedSeconds: null,
2517
+ }));
2485
2518
  prepareDataAndSendToAgent(data, false, {
2486
2519
  chatbotContext: chatbotContext,
2487
2520
  setChatbotContext: smartBotActions.setChatbotContext,
@@ -8695,7 +8728,7 @@ const StreamedContent = ({ botData, botProps }) => {
8695
8728
  const retryTimerRef = React.useRef(null); // Interval ref for countdown
8696
8729
  const retryCountdownRef = React.useRef(0); // Non-state countdown for interval callback
8697
8730
  const thinkingContentRef = React.useRef("");
8698
- reactRedux.useSelector((state) => {
8731
+ const thinkingContext = reactRedux.useSelector((state) => {
8699
8732
  return state.smartBotReducer.thinkingContext;
8700
8733
  });
8701
8734
  const stepRef = React.useRef(_isAbortedRemount
@@ -8718,7 +8751,10 @@ const StreamedContent = ({ botData, botProps }) => {
8718
8751
  const thinkingStartTimeRef = React.useRef(null);
8719
8752
  const thinkingTimeFinalRef = React.useRef(0);
8720
8753
  const thinkingHeaderMessageRef = React.useRef("Working for 0m:00s");
8721
- const streamStartTimeRef = React.useRef(null);
8754
+ // Inherit the in-flight start time so a remount (e.g. tab switch, where
8755
+ // processStream is not re-run) keeps the original one instead of resetting.
8756
+ // Null for a fresh question - processStream sets it.
8757
+ const streamStartTimeRef = React.useRef(thinkingContext?.isStreamCompleted ? null : thinkingContext?.streamStartTime || null);
8722
8758
  const thinkingDoneRef = React.useRef(false);
8723
8759
  const thinkingStartedRef = React.useRef(false);
8724
8760
  const setThinkingContentRef = React.useRef(setThinkingContent); // Store current setThinkingContent function
@@ -15878,10 +15914,14 @@ const SmartBot = (props) => {
15878
15914
  answerMode: answerMode,
15879
15915
  };
15880
15916
  // if(!isEmpty(userInput)) {
15917
+ // Clear the previous response's completed state so the incoming
15918
+ // ThinkinHeaderInfo doesn't freeze on it. streamStartTime stays null
15919
+ // here: processStream sets it, so a question has exactly one start
15920
+ // time (two would make the new header look like a superseded one).
15881
15921
  dispatch(smartBotActions.setThinkingContext({
15882
15922
  thinkingContent: "",
15883
15923
  thinkingHeaderMessage: "Working for 0m:00s",
15884
- streamStartTime: Date.now(),
15924
+ streamStartTime: null,
15885
15925
  isStreamCompleted: false,
15886
15926
  finalElapsedSeconds: null,
15887
15927
  }));