@blockspark/chat-widget 1.0.21 → 1.0.22

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