@blockspark/chat-widget 1.0.21 → 1.0.23

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
@@ -77,6 +77,8 @@ function ChatWidget$1({
77
77
  backendBaseUrl,
78
78
  backendWsUrl
79
79
  }) {
80
+ const msgIdCounter = useRef(0);
81
+ const uid = (prefix = "msg") => `${prefix}-${Date.now()}-${++msgIdCounter.current}`;
80
82
  const [isOpen, setIsOpen] = useState(false);
81
83
  const [showWelcomePopup, setShowWelcomePopup] = useState(false);
82
84
  const [messages, setMessages] = useState([]);
@@ -92,9 +94,11 @@ function ChatWidget$1({
92
94
  const [isStartingNewChat, setIsStartingNewChat] = useState(false);
93
95
  const [agentAccepted, setAgentAccepted] = useState(false);
94
96
  const messagesEndRef = useRef(null);
97
+ const inputRef = useRef(null);
95
98
  const typingTimeoutRef = useRef(null);
96
99
  const agentTypingTimeoutRef = useRef(null);
97
100
  const creatingSessionRef = useRef(false);
101
+ const resolvedResetTimerRef = useRef(null);
98
102
  const createSessionRef = useRef(null);
99
103
  const getBackendBaseUrl = () => {
100
104
  return backendBaseUrl || "https://chartconnect.blockspark.in";
@@ -134,13 +138,15 @@ function ChatWidget$1({
134
138
  setSupportSessionId(null);
135
139
  setSessionId(null);
136
140
  const thankYouMessage = {
137
- id: `resolved-${Date.now()}`,
141
+ id: uid("resolved"),
138
142
  text: "Thank you for contacting us!",
139
143
  sender: "bot",
140
144
  timestamp: /* @__PURE__ */ new Date()
141
145
  };
142
146
  setMessages((prev) => [...prev, thankYouMessage]);
143
- setTimeout(() => {
147
+ if (resolvedResetTimerRef.current) clearTimeout(resolvedResetTimerRef.current);
148
+ resolvedResetTimerRef.current = setTimeout(() => {
149
+ resolvedResetTimerRef.current = null;
144
150
  switchToBotMode();
145
151
  setChatResolved(false);
146
152
  setMessages([]);
@@ -169,7 +175,7 @@ function ChatWidget$1({
169
175
  setMessages((prev) => [
170
176
  ...prev,
171
177
  {
172
- id: `error-new-chat-${Date.now()}`,
178
+ id: uid("error"),
173
179
  text: debug ? `Error: ${error?.message || "Failed to start a new chat."}` : "Sorry, I couldn't start a new chat. Please try again.",
174
180
  sender: "bot",
175
181
  timestamp: /* @__PURE__ */ new Date()
@@ -201,12 +207,21 @@ function ChatWidget$1({
201
207
  useEffect(() => {
202
208
  if (!enableWelcomePopup) return;
203
209
  const timer = setTimeout(() => {
204
- setShowWelcomePopup(true);
210
+ if (!isOpen) {
211
+ setShowWelcomePopup(true);
212
+ }
205
213
  }, welcomePopupDelay);
206
214
  return () => clearTimeout(timer);
207
- }, [enableWelcomePopup, welcomePopupDelay]);
215
+ }, [enableWelcomePopup, welcomePopupDelay, isOpen]);
216
+ const scrollTimeoutRef = useRef(null);
208
217
  useEffect(() => {
209
- messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
218
+ if (scrollTimeoutRef.current) clearTimeout(scrollTimeoutRef.current);
219
+ scrollTimeoutRef.current = setTimeout(() => {
220
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
221
+ }, 80);
222
+ return () => {
223
+ if (scrollTimeoutRef.current) clearTimeout(scrollTimeoutRef.current);
224
+ };
210
225
  }, [messages]);
211
226
  const handleAgentChanged = useCallback((message) => {
212
227
  if (message.to_agent) {
@@ -215,7 +230,7 @@ function ChatWidget$1({
215
230
  name: message.to_agent
216
231
  });
217
232
  const systemMessage = {
218
- id: `system-${Date.now()}`,
233
+ id: uid("system"),
219
234
  text: message.from_agent ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}` : `Chat has been transferred to ${message.to_agent}`,
220
235
  sender: "bot",
221
236
  timestamp: /* @__PURE__ */ new Date()
@@ -236,7 +251,7 @@ function ChatWidget$1({
236
251
  if (message.content) {
237
252
  if (message.sender_type === "agent" || !message.sender_type) {
238
253
  const agentMessage = {
239
- id: message.id || `agent-${Date.now()}`,
254
+ id: message.id || uid("agent"),
240
255
  text: message.content,
241
256
  sender: "agent",
242
257
  timestamp: new Date(message.timestamp || Date.now())
@@ -304,7 +319,7 @@ function ChatWidget$1({
304
319
  setAgentAccepted(true);
305
320
  setIsConnectingToAgent(false);
306
321
  const acceptedMessage = {
307
- id: message.id || `agent-accepted-${message.chat_id || Date.now()}-${Date.now()}`,
322
+ id: message.id || uid("agent-accepted"),
308
323
  text: "You can chat now, the agent has accepted your request.",
309
324
  sender: "bot",
310
325
  timestamp: message.timestamp ? new Date(message.timestamp) : /* @__PURE__ */ new Date()
@@ -336,7 +351,7 @@ function ChatWidget$1({
336
351
  case "error":
337
352
  console.error("WebSocket error:", message.error);
338
353
  const errorMessage = {
339
- id: `error-${Date.now()}`,
354
+ id: uid("error"),
340
355
  text: message.error || "An error occurred. Please try again.",
341
356
  sender: "bot",
342
357
  timestamp: /* @__PURE__ */ new Date()
@@ -392,7 +407,7 @@ function ChatWidget$1({
392
407
  setIsLoading(true);
393
408
  const history = await chatServiceRef.current.loadMessageHistory(chatId, supportSessionId);
394
409
  const historyMessages = history.map((msg) => ({
395
- id: msg.id || `msg-${Date.now()}-${Math.random()}`,
410
+ id: msg.id || uid("history"),
396
411
  text: msg.content,
397
412
  sender: msg.sender_type === "agent" ? "agent" : "user",
398
413
  timestamp: new Date(msg.timestamp)
@@ -413,7 +428,7 @@ function ChatWidget$1({
413
428
  console.error("Error loading message history:", error);
414
429
  if (debug) {
415
430
  const errorMessage = {
416
- id: `error-${Date.now()}`,
431
+ id: uid("error"),
417
432
  text: `Failed to load chat history: ${error.message}`,
418
433
  sender: "bot",
419
434
  timestamp: /* @__PURE__ */ new Date()
@@ -513,19 +528,12 @@ function ChatWidget$1({
513
528
  switchToHumanMode();
514
529
  setChatResolved(false);
515
530
  setAgentAccepted(false);
516
- const connectingMessage = {
517
- id: `connecting-${Date.now()}`,
518
- text: "Connecting you to a human agent...",
519
- sender: "bot",
520
- timestamp: /* @__PURE__ */ new Date()
521
- };
522
- setMessages((prev) => [...prev, connectingMessage]);
523
531
  const sessionKey = `${currentChatId}-${currentSupportSessionId}`;
524
532
  historyLoadedRef.current = sessionKey;
525
533
  } catch (error) {
526
534
  console.error("Error handling handoff:", error);
527
535
  const errorMessage = {
528
- id: `error-${Date.now()}`,
536
+ id: uid("error"),
529
537
  text: debug ? `Handoff error: ${error.message}` : "Failed to connect to agent. Please try again.",
530
538
  sender: "bot",
531
539
  timestamp: /* @__PURE__ */ new Date()
@@ -557,7 +565,7 @@ function ChatWidget$1({
557
565
  console.log("Full session response:", data);
558
566
  }
559
567
  const welcomeMessage2 = {
560
- id: `welcome-${Date.now()}`,
568
+ id: uid("welcome"),
561
569
  text: data.message,
562
570
  sender: "bot",
563
571
  timestamp: /* @__PURE__ */ new Date(),
@@ -581,7 +589,7 @@ function ChatWidget$1({
581
589
  });
582
590
  }
583
591
  const errorMessage = {
584
- id: `error-${Date.now()}`,
592
+ id: uid("error"),
585
593
  text: debug ? `Error: ${error.message || "Failed to create session. Please check your Dialogflow configuration."}` : fallbackWelcomeMessage,
586
594
  sender: "bot",
587
595
  timestamp: /* @__PURE__ */ new Date()
@@ -594,12 +602,22 @@ function ChatWidget$1({
594
602
  }
595
603
  };
596
604
  createSessionRef.current = createSession;
605
+ const sendingRef = useRef(false);
597
606
  const sendMessage = async (text, displayText, skipUserMessage = false) => {
607
+ if (!text.trim() || sendingRef.current) return;
608
+ sendingRef.current = true;
609
+ try {
610
+ await sendMessageInner(text, displayText, skipUserMessage);
611
+ } finally {
612
+ sendingRef.current = false;
613
+ }
614
+ };
615
+ const sendMessageInner = async (text, displayText, skipUserMessage = false) => {
598
616
  if (!text.trim()) return;
599
617
  if (currentMode === "HUMAN") {
600
618
  if (!chatId || !supportSessionId) {
601
619
  const errorMessage = {
602
- id: Date.now().toString(),
620
+ id: uid("msg"),
603
621
  text: "Chat session not initialized. Please try again.",
604
622
  sender: "bot",
605
623
  timestamp: /* @__PURE__ */ new Date()
@@ -609,7 +627,7 @@ function ChatWidget$1({
609
627
  }
610
628
  if (!skipUserMessage) {
611
629
  const userMessage = {
612
- id: Date.now().toString(),
630
+ id: uid("msg"),
613
631
  text: displayText || text.trim(),
614
632
  sender: "user",
615
633
  timestamp: /* @__PURE__ */ new Date()
@@ -666,7 +684,7 @@ function ChatWidget$1({
666
684
  return;
667
685
  }
668
686
  const errorMessage = {
669
- id: (Date.now() + 1).toString(),
687
+ id: uid("msg"),
670
688
  text: debug ? `Error: ${retryError.message || "Failed to send message."}` : "Sorry, I'm having trouble sending your message. Please try again.",
671
689
  sender: "bot",
672
690
  timestamp: /* @__PURE__ */ new Date()
@@ -675,7 +693,7 @@ function ChatWidget$1({
675
693
  }
676
694
  } else {
677
695
  const errorMessage = {
678
- id: (Date.now() + 1).toString(),
696
+ id: uid("msg"),
679
697
  text: debug ? `Error: ${error.message || "Failed to send message to agent."}` : "Sorry, I'm having trouble sending your message. Please try again.",
680
698
  sender: "bot",
681
699
  timestamp: /* @__PURE__ */ new Date()
@@ -693,7 +711,7 @@ function ChatWidget$1({
693
711
  currentSessionId = await createSession();
694
712
  if (!currentSessionId) {
695
713
  const errorMessage = {
696
- id: Date.now().toString(),
714
+ id: uid("msg"),
697
715
  text: debug ? "Failed to create session. Please check the console for details." : "Sorry, I'm having trouble connecting. Please try again.",
698
716
  sender: "bot",
699
717
  timestamp: /* @__PURE__ */ new Date()
@@ -704,7 +722,7 @@ function ChatWidget$1({
704
722
  } catch (error) {
705
723
  console.error("Error in createSession:", error);
706
724
  const errorMessage = {
707
- id: Date.now().toString(),
725
+ id: uid("msg"),
708
726
  text: debug ? `Connection Error: ${error.message || "Please check your Dialogflow configuration."}` : "Sorry, I'm having trouble connecting. Please check your configuration.",
709
727
  sender: "bot",
710
728
  timestamp: /* @__PURE__ */ new Date()
@@ -715,7 +733,7 @@ function ChatWidget$1({
715
733
  }
716
734
  if (!skipUserMessage) {
717
735
  const userMessage = {
718
- id: Date.now().toString(),
736
+ id: uid("msg"),
719
737
  text: displayText || text.trim(),
720
738
  sender: "user",
721
739
  timestamp: /* @__PURE__ */ new Date()
@@ -738,7 +756,7 @@ function ChatWidget$1({
738
756
  if (data.handoff === true) {
739
757
  if (data.response || data.richContent) {
740
758
  const botMessage = {
741
- id: (Date.now() + 1).toString(),
759
+ id: uid("msg"),
742
760
  text: data.response,
743
761
  sender: "bot",
744
762
  timestamp: new Date(data.timestamp || Date.now()),
@@ -751,7 +769,7 @@ function ChatWidget$1({
751
769
  }
752
770
  if (data.response || data.richContent) {
753
771
  const botMessage = {
754
- id: (Date.now() + 1).toString(),
772
+ id: uid("msg"),
755
773
  text: data.response,
756
774
  sender: "bot",
757
775
  timestamp: new Date(data.timestamp || Date.now()),
@@ -770,7 +788,7 @@ function ChatWidget$1({
770
788
  });
771
789
  }
772
790
  const errorMessage = {
773
- id: (Date.now() + 1).toString(),
791
+ id: uid("msg"),
774
792
  text: debug ? `Error: ${error.message || "Failed to send message. Please check your Dialogflow configuration."}` : error.message?.includes("Failed to fetch") || error.message?.includes("CORS") ? "Unable to connect to Dialogflow. Please check your configuration and network." : "Sorry, I'm having trouble processing your message. Please try again.",
775
793
  sender: "bot",
776
794
  timestamp: /* @__PURE__ */ new Date()
@@ -783,6 +801,7 @@ function ChatWidget$1({
783
801
  const handleSubmit = (e) => {
784
802
  e.preventDefault();
785
803
  sendMessage(inputValue);
804
+ inputRef.current?.focus();
786
805
  };
787
806
  const handleInputChange = (e) => {
788
807
  const value = e.target.value;
@@ -949,7 +968,7 @@ function ChatWidget$1({
949
968
  className: "custom-chip-button",
950
969
  onClick: () => {
951
970
  const userMessage = {
952
- id: Date.now().toString(),
971
+ id: uid("msg"),
953
972
  text: chip.text,
954
973
  sender: "user",
955
974
  timestamp: /* @__PURE__ */ new Date()
@@ -976,7 +995,7 @@ function ChatWidget$1({
976
995
  className: "custom-chip-button",
977
996
  onClick: () => {
978
997
  const userMessage = {
979
- id: Date.now().toString(),
998
+ id: uid("msg"),
980
999
  text: chip.text,
981
1000
  sender: "user",
982
1001
  timestamp: /* @__PURE__ */ new Date()
@@ -1009,28 +1028,23 @@ function ChatWidget$1({
1009
1028
  /* @__PURE__ */ jsx("span", {}),
1010
1029
  /* @__PURE__ */ jsx("span", {})
1011
1030
  ] }) }),
1012
- isConnectingToAgent && /* @__PURE__ */ jsxs("div", { className: "custom-message custom-message-bot", children: [
1013
- /* @__PURE__ */ jsxs("div", { className: "custom-typing-indicator", children: [
1014
- /* @__PURE__ */ jsx("span", {}),
1015
- /* @__PURE__ */ jsx("span", {}),
1016
- /* @__PURE__ */ jsx("span", {})
1017
- ] }),
1018
- /* @__PURE__ */ jsx("div", { className: "custom-message-content", children: "Connecting to agent..." })
1019
- ] }),
1020
- currentMode === "HUMAN" && agentTyping && /* @__PURE__ */ jsxs("div", { className: "custom-agent-typing-indicator", children: [
1021
- /* @__PURE__ */ jsxs("span", { className: "custom-typing-dots", children: [
1022
- /* @__PURE__ */ jsx("span", {}),
1023
- /* @__PURE__ */ jsx("span", {}),
1024
- /* @__PURE__ */ jsx("span", {})
1025
- ] }),
1026
- /* @__PURE__ */ jsx("span", { className: "custom-typing-text", children: "Agent is typing..." })
1027
- ] }),
1031
+ isConnectingToAgent && /* @__PURE__ */ jsx("div", { className: "custom-message custom-message-bot", children: /* @__PURE__ */ jsxs("div", { className: "custom-typing-indicator", children: [
1032
+ /* @__PURE__ */ jsx("span", {}),
1033
+ /* @__PURE__ */ jsx("span", {}),
1034
+ /* @__PURE__ */ jsx("span", {})
1035
+ ] }) }),
1036
+ currentMode === "HUMAN" && agentTyping && /* @__PURE__ */ jsx("div", { className: "custom-message custom-message-bot", children: /* @__PURE__ */ jsxs("div", { className: "custom-typing-indicator", children: [
1037
+ /* @__PURE__ */ jsx("span", {}),
1038
+ /* @__PURE__ */ jsx("span", {}),
1039
+ /* @__PURE__ */ jsx("span", {})
1040
+ ] }) }),
1028
1041
  /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
1029
1042
  ] }),
1030
1043
  /* @__PURE__ */ jsxs("form", { className: "custom-chat-input-form", onSubmit: handleSubmit, children: [
1031
1044
  /* @__PURE__ */ jsx(
1032
1045
  "input",
1033
1046
  {
1047
+ ref: inputRef,
1034
1048
  type: "text",
1035
1049
  className: "custom-chat-input",
1036
1050
  value: inputValue,