@blockspark/chat-widget 1.0.15 → 1.0.16

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.
Files changed (180) hide show
  1. package/dist/{core/stateManager.esm.js → ChatWidget-CFvb5g7s.js} +450 -4
  2. package/dist/ChatWidget-CFvb5g7s.js.map +1 -0
  3. package/dist/ChatWidget-CdA7TymM.cjs +2 -0
  4. package/dist/ChatWidget-CdA7TymM.cjs.map +1 -0
  5. package/dist/index.cjs.js +1 -1
  6. package/dist/index.cjs.js.map +1 -1
  7. package/dist/index.esm.js +1357 -7
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/nuxt.cjs.js +1 -1
  10. package/dist/nuxt.esm.js +4 -5
  11. package/dist/nuxt.esm.js.map +1 -1
  12. package/dist/sanitize-DRKcO9o5.cjs +4 -0
  13. package/dist/sanitize-DRKcO9o5.cjs.map +1 -0
  14. package/dist/sanitize-NEykcppO.js +2835 -0
  15. package/dist/sanitize-NEykcppO.js.map +1 -0
  16. package/dist/utils/frameworkDetector.d.ts.map +1 -1
  17. package/dist/utils/sanitize.d.ts.map +1 -1
  18. package/dist/vue.cjs.js +1 -1
  19. package/dist/vue.esm.js +4 -5
  20. package/dist/vue.esm.js.map +1 -1
  21. package/package.json +14 -49
  22. package/dist/_virtual/_plugin-vue_export-helper.cjs.js +0 -2
  23. package/dist/_virtual/_plugin-vue_export-helper.cjs.js.map +0 -1
  24. package/dist/_virtual/_plugin-vue_export-helper.esm.js +0 -11
  25. package/dist/_virtual/_plugin-vue_export-helper.esm.js.map +0 -1
  26. package/dist/components/ChatWidget.cjs.js +0 -2
  27. package/dist/components/ChatWidget.cjs.js.map +0 -1
  28. package/dist/components/ChatWidget.esm.js +0 -1129
  29. package/dist/components/ChatWidget.esm.js.map +0 -1
  30. package/dist/components/ChatWidget.vue.cjs.js +0 -2
  31. package/dist/components/ChatWidget.vue.cjs.js.map +0 -1
  32. package/dist/components/ChatWidget.vue.cjs2.js +0 -2
  33. package/dist/components/ChatWidget.vue.cjs2.js.map +0 -1
  34. package/dist/components/ChatWidget.vue.esm.js +0 -8
  35. package/dist/components/ChatWidget.vue.esm.js.map +0 -1
  36. package/dist/components/ChatWidget.vue.esm2.js +0 -374
  37. package/dist/components/ChatWidget.vue.esm2.js.map +0 -1
  38. package/dist/composables/useChatWidget.cjs.js +0 -2
  39. package/dist/composables/useChatWidget.cjs.js.map +0 -1
  40. package/dist/composables/useChatWidget.esm.js +0 -75
  41. package/dist/composables/useChatWidget.esm.js.map +0 -1
  42. package/dist/core/stateManager.cjs.js +0 -2
  43. package/dist/core/stateManager.cjs.js.map +0 -1
  44. package/dist/core/stateManager.esm.js.map +0 -1
  45. package/dist/entry/vanilla.cjs.js +0 -2
  46. package/dist/entry/vanilla.cjs.js.map +0 -1
  47. package/dist/entry/vanilla.esm.js +0 -50
  48. package/dist/entry/vanilla.esm.js.map +0 -1
  49. package/dist/hooks/useChatMode.cjs.js +0 -2
  50. package/dist/hooks/useChatMode.cjs.js.map +0 -1
  51. package/dist/hooks/useChatMode.esm.js +0 -61
  52. package/dist/hooks/useChatMode.esm.js.map +0 -1
  53. package/dist/node_modules/jose/dist/browser/jws/compact/sign.cjs.js +0 -2
  54. package/dist/node_modules/jose/dist/browser/jws/compact/sign.cjs.js.map +0 -1
  55. package/dist/node_modules/jose/dist/browser/jws/compact/sign.esm.js +0 -21
  56. package/dist/node_modules/jose/dist/browser/jws/compact/sign.esm.js.map +0 -1
  57. package/dist/node_modules/jose/dist/browser/jws/flattened/sign.cjs.js +0 -2
  58. package/dist/node_modules/jose/dist/browser/jws/flattened/sign.cjs.js.map +0 -1
  59. package/dist/node_modules/jose/dist/browser/jws/flattened/sign.esm.js +0 -84
  60. package/dist/node_modules/jose/dist/browser/jws/flattened/sign.esm.js.map +0 -1
  61. package/dist/node_modules/jose/dist/browser/jwt/produce.cjs.js +0 -2
  62. package/dist/node_modules/jose/dist/browser/jwt/produce.cjs.js.map +0 -1
  63. package/dist/node_modules/jose/dist/browser/jwt/produce.esm.js +0 -72
  64. package/dist/node_modules/jose/dist/browser/jwt/produce.esm.js.map +0 -1
  65. package/dist/node_modules/jose/dist/browser/jwt/sign.cjs.js +0 -2
  66. package/dist/node_modules/jose/dist/browser/jwt/sign.cjs.js.map +0 -1
  67. package/dist/node_modules/jose/dist/browser/jwt/sign.esm.js +0 -22
  68. package/dist/node_modules/jose/dist/browser/jwt/sign.esm.js.map +0 -1
  69. package/dist/node_modules/jose/dist/browser/key/import.cjs.js +0 -2
  70. package/dist/node_modules/jose/dist/browser/key/import.cjs.js.map +0 -1
  71. package/dist/node_modules/jose/dist/browser/key/import.esm.js +0 -11
  72. package/dist/node_modules/jose/dist/browser/key/import.esm.js.map +0 -1
  73. package/dist/node_modules/jose/dist/browser/lib/buffer_utils.cjs.js +0 -2
  74. package/dist/node_modules/jose/dist/browser/lib/buffer_utils.cjs.js.map +0 -1
  75. package/dist/node_modules/jose/dist/browser/lib/buffer_utils.esm.js +0 -18
  76. package/dist/node_modules/jose/dist/browser/lib/buffer_utils.esm.js.map +0 -1
  77. package/dist/node_modules/jose/dist/browser/lib/check_key_type.cjs.js +0 -2
  78. package/dist/node_modules/jose/dist/browser/lib/check_key_type.cjs.js.map +0 -1
  79. package/dist/node_modules/jose/dist/browser/lib/check_key_type.esm.js +0 -77
  80. package/dist/node_modules/jose/dist/browser/lib/check_key_type.esm.js.map +0 -1
  81. package/dist/node_modules/jose/dist/browser/lib/crypto_key.cjs.js +0 -2
  82. package/dist/node_modules/jose/dist/browser/lib/crypto_key.cjs.js.map +0 -1
  83. package/dist/node_modules/jose/dist/browser/lib/crypto_key.esm.js +0 -101
  84. package/dist/node_modules/jose/dist/browser/lib/crypto_key.esm.js.map +0 -1
  85. package/dist/node_modules/jose/dist/browser/lib/epoch.cjs.js +0 -2
  86. package/dist/node_modules/jose/dist/browser/lib/epoch.cjs.js.map +0 -1
  87. package/dist/node_modules/jose/dist/browser/lib/epoch.esm.js +0 -5
  88. package/dist/node_modules/jose/dist/browser/lib/epoch.esm.js.map +0 -1
  89. package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.cjs.js +0 -2
  90. package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.cjs.js.map +0 -1
  91. package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.esm.js +0 -32
  92. package/dist/node_modules/jose/dist/browser/lib/invalid_key_input.esm.js.map +0 -1
  93. package/dist/node_modules/jose/dist/browser/lib/is_disjoint.cjs.js +0 -2
  94. package/dist/node_modules/jose/dist/browser/lib/is_disjoint.cjs.js.map +0 -1
  95. package/dist/node_modules/jose/dist/browser/lib/is_disjoint.esm.js +0 -25
  96. package/dist/node_modules/jose/dist/browser/lib/is_disjoint.esm.js.map +0 -1
  97. package/dist/node_modules/jose/dist/browser/lib/is_jwk.cjs.js +0 -2
  98. package/dist/node_modules/jose/dist/browser/lib/is_jwk.cjs.js.map +0 -1
  99. package/dist/node_modules/jose/dist/browser/lib/is_jwk.esm.js +0 -20
  100. package/dist/node_modules/jose/dist/browser/lib/is_jwk.esm.js.map +0 -1
  101. package/dist/node_modules/jose/dist/browser/lib/is_object.cjs.js +0 -2
  102. package/dist/node_modules/jose/dist/browser/lib/is_object.cjs.js.map +0 -1
  103. package/dist/node_modules/jose/dist/browser/lib/is_object.esm.js +0 -20
  104. package/dist/node_modules/jose/dist/browser/lib/is_object.esm.js.map +0 -1
  105. package/dist/node_modules/jose/dist/browser/lib/secs.cjs.js +0 -2
  106. package/dist/node_modules/jose/dist/browser/lib/secs.cjs.js.map +0 -1
  107. package/dist/node_modules/jose/dist/browser/lib/secs.esm.js +0 -59
  108. package/dist/node_modules/jose/dist/browser/lib/secs.esm.js.map +0 -1
  109. package/dist/node_modules/jose/dist/browser/lib/validate_crit.cjs.js +0 -2
  110. package/dist/node_modules/jose/dist/browser/lib/validate_crit.cjs.js.map +0 -1
  111. package/dist/node_modules/jose/dist/browser/lib/validate_crit.esm.js +0 -34
  112. package/dist/node_modules/jose/dist/browser/lib/validate_crit.esm.js.map +0 -1
  113. package/dist/node_modules/jose/dist/browser/runtime/asn1.cjs.js +0 -2
  114. package/dist/node_modules/jose/dist/browser/runtime/asn1.cjs.js.map +0 -1
  115. package/dist/node_modules/jose/dist/browser/runtime/asn1.esm.js +0 -103
  116. package/dist/node_modules/jose/dist/browser/runtime/asn1.esm.js.map +0 -1
  117. package/dist/node_modules/jose/dist/browser/runtime/base64url.cjs.js +0 -2
  118. package/dist/node_modules/jose/dist/browser/runtime/base64url.cjs.js.map +0 -1
  119. package/dist/node_modules/jose/dist/browser/runtime/base64url.esm.js +0 -43
  120. package/dist/node_modules/jose/dist/browser/runtime/base64url.esm.js.map +0 -1
  121. package/dist/node_modules/jose/dist/browser/runtime/check_key_length.cjs.js +0 -2
  122. package/dist/node_modules/jose/dist/browser/runtime/check_key_length.cjs.js.map +0 -1
  123. package/dist/node_modules/jose/dist/browser/runtime/check_key_length.esm.js +0 -12
  124. package/dist/node_modules/jose/dist/browser/runtime/check_key_length.esm.js.map +0 -1
  125. package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.cjs.js +0 -2
  126. package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.cjs.js.map +0 -1
  127. package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.esm.js +0 -25
  128. package/dist/node_modules/jose/dist/browser/runtime/get_sign_verify_key.esm.js.map +0 -1
  129. package/dist/node_modules/jose/dist/browser/runtime/is_key_like.cjs.js +0 -2
  130. package/dist/node_modules/jose/dist/browser/runtime/is_key_like.cjs.js.map +0 -1
  131. package/dist/node_modules/jose/dist/browser/runtime/is_key_like.esm.js +0 -13
  132. package/dist/node_modules/jose/dist/browser/runtime/is_key_like.esm.js.map +0 -1
  133. package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.cjs.js +0 -2
  134. package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.cjs.js.map +0 -1
  135. package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.esm.js +0 -107
  136. package/dist/node_modules/jose/dist/browser/runtime/jwk_to_key.esm.js.map +0 -1
  137. package/dist/node_modules/jose/dist/browser/runtime/normalize_key.cjs.js +0 -2
  138. package/dist/node_modules/jose/dist/browser/runtime/normalize_key.cjs.js.map +0 -1
  139. package/dist/node_modules/jose/dist/browser/runtime/normalize_key.esm.js +0 -71
  140. package/dist/node_modules/jose/dist/browser/runtime/normalize_key.esm.js.map +0 -1
  141. package/dist/node_modules/jose/dist/browser/runtime/sign.cjs.js +0 -2
  142. package/dist/node_modules/jose/dist/browser/runtime/sign.cjs.js.map +0 -1
  143. package/dist/node_modules/jose/dist/browser/runtime/sign.esm.js +0 -14
  144. package/dist/node_modules/jose/dist/browser/runtime/sign.esm.js.map +0 -1
  145. package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.cjs.js +0 -2
  146. package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.cjs.js.map +0 -1
  147. package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.esm.js +0 -32
  148. package/dist/node_modules/jose/dist/browser/runtime/subtle_dsa.esm.js.map +0 -1
  149. package/dist/node_modules/jose/dist/browser/runtime/webcrypto.cjs.js +0 -2
  150. package/dist/node_modules/jose/dist/browser/runtime/webcrypto.cjs.js.map +0 -1
  151. package/dist/node_modules/jose/dist/browser/runtime/webcrypto.esm.js +0 -7
  152. package/dist/node_modules/jose/dist/browser/runtime/webcrypto.esm.js.map +0 -1
  153. package/dist/node_modules/jose/dist/browser/util/errors.cjs.js +0 -2
  154. package/dist/node_modules/jose/dist/browser/util/errors.cjs.js.map +0 -1
  155. package/dist/node_modules/jose/dist/browser/util/errors.esm.js +0 -131
  156. package/dist/node_modules/jose/dist/browser/util/errors.esm.js.map +0 -1
  157. package/dist/node_modules/react-dom/client.cjs.js +0 -2
  158. package/dist/node_modules/react-dom/client.cjs.js.map +0 -1
  159. package/dist/node_modules/react-dom/client.esm.js +0 -21
  160. package/dist/node_modules/react-dom/client.esm.js.map +0 -1
  161. package/dist/services/chatService.cjs.js +0 -2
  162. package/dist/services/chatService.cjs.js.map +0 -1
  163. package/dist/services/chatService.esm.js +0 -482
  164. package/dist/services/chatService.esm.js.map +0 -1
  165. package/dist/services/dialogflowClient.cjs.js +0 -2
  166. package/dist/services/dialogflowClient.cjs.js.map +0 -1
  167. package/dist/services/dialogflowClient.esm.js +0 -282
  168. package/dist/services/dialogflowClient.esm.js.map +0 -1
  169. package/dist/services/sessionManager.cjs.js +0 -2
  170. package/dist/services/sessionManager.cjs.js.map +0 -1
  171. package/dist/services/sessionManager.esm.js +0 -48
  172. package/dist/services/sessionManager.esm.js.map +0 -1
  173. package/dist/utils/frameworkDetector.cjs.js +0 -2
  174. package/dist/utils/frameworkDetector.cjs.js.map +0 -1
  175. package/dist/utils/frameworkDetector.esm.js +0 -125
  176. package/dist/utils/frameworkDetector.esm.js.map +0 -1
  177. package/dist/utils/sanitize.cjs.js +0 -2
  178. package/dist/utils/sanitize.cjs.js.map +0 -1
  179. package/dist/utils/sanitize.esm.js +0 -52
  180. package/dist/utils/sanitize.esm.js.map +0 -1
package/dist/index.esm.js CHANGED
@@ -1,14 +1,1364 @@
1
- import { default as default2, default as default3, default as default4 } from "./components/ChatWidget.esm.js";
2
- import { createDialogflowSession, sendDialogflowMessage } from "./services/dialogflowClient.esm.js";
3
- import { getFramework, setFramework } from "./utils/frameworkDetector.esm.js";
4
- import { ChatWidget, createChatWidget } from "./entry/vanilla.esm.js";
1
+ import { jsxs, Fragment, jsx } from "react/jsx-runtime";
2
+ import React, { useState, useEffect, useCallback, useRef } from "react";
3
+ import { c as createChatService, a as createDialogflowSession, l as linkifyText, C as ChatResolvedError, s as sendDialogflowMessage } from "./sanitize-NEykcppO.js";
4
+ import require$$0 from "react-dom";
5
+ const MODE_STORAGE_KEY = "blockspark_chat_mode";
6
+ const CHAT_ID_STORAGE_KEY = "blockspark_chat_id";
7
+ const SESSION_ID_STORAGE_KEY = "blockspark_session_id";
8
+ function useChatMode() {
9
+ const [currentMode, setCurrentMode] = useState(() => {
10
+ const savedMode = localStorage.getItem(MODE_STORAGE_KEY);
11
+ return savedMode === "HUMAN" ? "HUMAN" : "BOT";
12
+ });
13
+ const [chatId, setChatIdState] = useState(() => {
14
+ return localStorage.getItem(CHAT_ID_STORAGE_KEY);
15
+ });
16
+ const [sessionId, setSessionIdState] = useState(() => {
17
+ return localStorage.getItem(SESSION_ID_STORAGE_KEY);
18
+ });
19
+ useEffect(() => {
20
+ localStorage.setItem(MODE_STORAGE_KEY, currentMode);
21
+ }, [currentMode]);
22
+ const setChatId = useCallback((id) => {
23
+ setChatIdState(id);
24
+ if (id) {
25
+ localStorage.setItem(CHAT_ID_STORAGE_KEY, id);
26
+ } else {
27
+ localStorage.removeItem(CHAT_ID_STORAGE_KEY);
28
+ }
29
+ }, []);
30
+ const setSessionId = useCallback((id) => {
31
+ setSessionIdState(id);
32
+ if (id) {
33
+ localStorage.setItem(SESSION_ID_STORAGE_KEY, id);
34
+ } else {
35
+ localStorage.removeItem(SESSION_ID_STORAGE_KEY);
36
+ }
37
+ }, []);
38
+ const switchToHumanMode = useCallback(() => {
39
+ setCurrentMode("HUMAN");
40
+ }, []);
41
+ const switchToBotMode = useCallback(() => {
42
+ setCurrentMode("BOT");
43
+ }, []);
44
+ const isHandoffTriggered = useCallback(
45
+ (dialogflowResponse) => {
46
+ return false;
47
+ },
48
+ []
49
+ );
50
+ return {
51
+ currentMode,
52
+ switchToHumanMode,
53
+ switchToBotMode,
54
+ isHandoffTriggered,
55
+ chatId,
56
+ sessionId,
57
+ setChatId,
58
+ setSessionId
59
+ };
60
+ }
61
+ function ChatWidget$1({
62
+ title = "💬 BlockSpark AI Assistant",
63
+ subtitle = "We're here to help",
64
+ welcomeTitle = "👋 Welcome to Blockspark",
65
+ welcomeMessage = "My name is BlockSpark AI Assistant and I'll guide you.",
66
+ welcomeCta = "💬 Click here to start chatting!",
67
+ showWelcomePopup: enableWelcomePopup = true,
68
+ welcomePopupDelay = 1500,
69
+ fallbackWelcomeMessage = "Hello! I'm BlockSpark AI Assistant. How can I help you today?",
70
+ inputPlaceholder = "Type your message...",
71
+ emptyStateMessage = "Hi! I'm BlockSpark AI Assistant. How can I help you today?",
72
+ debug = false,
73
+ dfProjectId,
74
+ dfLocation = "us-central1",
75
+ dfAgentId,
76
+ serviceAccountKey,
77
+ accessToken,
78
+ languageCode = "en",
79
+ backendBaseUrl,
80
+ backendWsUrl
81
+ }) {
82
+ const [isOpen, setIsOpen] = useState(false);
83
+ const [showWelcomePopup, setShowWelcomePopup] = useState(false);
84
+ const [messages, setMessages] = useState([]);
85
+ const [inputValue, setInputValue] = useState("");
86
+ const [isLoading, setIsLoading] = useState(false);
87
+ const [sessionId, setSessionId] = useState(null);
88
+ const [isInitializing, setIsInitializing] = useState(false);
89
+ const [isConnectingToAgent, setIsConnectingToAgent] = useState(false);
90
+ const [wsConnected, setWsConnected] = useState(false);
91
+ const [agentTyping, setAgentTyping] = useState(false);
92
+ const [currentAgent, setCurrentAgent] = useState({ name: "Agent" });
93
+ const [collectingUserInfo, setCollectingUserInfo] = useState(false);
94
+ const [chatResolved, setChatResolved] = useState(false);
95
+ const [isStartingNewChat, setIsStartingNewChat] = useState(false);
96
+ const [agentAccepted, setAgentAccepted] = useState(false);
97
+ const [userInfoStep, setUserInfoStep] = useState(null);
98
+ const [collectedUserName, setCollectedUserName] = useState("");
99
+ const [collectedUserEmail, setCollectedUserEmail] = useState("");
100
+ const [collectedUserMobile, setCollectedUserMobile] = useState("");
101
+ const collectedUserNameRef = useRef("");
102
+ const messagesEndRef = useRef(null);
103
+ const typingTimeoutRef = useRef(null);
104
+ const agentTypingTimeoutRef = useRef(null);
105
+ const getBackendBaseUrl = () => {
106
+ return backendBaseUrl || typeof process !== "undefined" && process.env?.REACT_APP_BACKEND_BASE_URL;
107
+ };
108
+ const getBackendWsUrl = () => {
109
+ return backendWsUrl || typeof process !== "undefined" && process.env?.REACT_APP_BACKEND_WS_URL;
110
+ };
111
+ const chatServiceRef = useRef(
112
+ createChatService({
113
+ baseUrl: getBackendBaseUrl(),
114
+ wsUrl: getBackendWsUrl(),
115
+ debug
116
+ })
117
+ );
118
+ const historyLoadedRef = useRef(null);
119
+ const {
120
+ currentMode,
121
+ switchToHumanMode,
122
+ switchToBotMode,
123
+ chatId,
124
+ sessionId: supportSessionId,
125
+ setChatId,
126
+ setSessionId: setSupportSessionId
127
+ } = useChatMode();
128
+ const enterResolvedState = useCallback(
129
+ (_resolvedChatId) => {
130
+ setChatResolved(true);
131
+ setIsConnectingToAgent(false);
132
+ setAgentAccepted(false);
133
+ setAgentTyping(false);
134
+ if (agentTypingTimeoutRef.current) {
135
+ clearTimeout(agentTypingTimeoutRef.current);
136
+ agentTypingTimeoutRef.current = null;
137
+ }
138
+ chatServiceRef.current.disconnectWebSocket();
139
+ setChatId(null);
140
+ setSupportSessionId(null);
141
+ const thankYouMessage = {
142
+ id: `resolved-${Date.now()}`,
143
+ text: "Thank you for contacting us!",
144
+ sender: "bot",
145
+ timestamp: /* @__PURE__ */ new Date()
146
+ };
147
+ setMessages((prev) => [...prev, thankYouMessage]);
148
+ setTimeout(() => {
149
+ switchToBotMode();
150
+ setChatResolved(false);
151
+ setMessages([]);
152
+ setCollectingUserInfo(false);
153
+ setUserInfoStep(null);
154
+ setCollectedUserName("");
155
+ setCollectedUserEmail("");
156
+ setCollectedUserMobile("");
157
+ collectedUserNameRef.current = "";
158
+ createSession().catch(console.error);
159
+ }, 2e3);
160
+ },
161
+ [setChatId, setSupportSessionId, switchToBotMode]
162
+ );
163
+ useCallback(async () => {
164
+ if (isStartingNewChat) return;
165
+ setIsStartingNewChat(true);
166
+ try {
167
+ const customerName = collectedUserNameRef.current || collectedUserName || null;
168
+ const customerEmail = collectedUserEmail || null;
169
+ const customerMobile = collectedUserMobile || null;
170
+ const newSession = await chatServiceRef.current.startSupportChat(
171
+ sessionId || null,
172
+ customerName,
173
+ customerEmail,
174
+ customerMobile
175
+ );
176
+ switchToHumanMode();
177
+ setChatId(newSession.chat_id);
178
+ setSupportSessionId(newSession.session_id);
179
+ setChatResolved(false);
180
+ setInputValue("");
181
+ } catch (error) {
182
+ console.error("Error starting new chat:", error);
183
+ setMessages((prev) => [
184
+ ...prev,
185
+ {
186
+ id: `error-new-chat-${Date.now()}`,
187
+ text: debug ? `Error: ${error?.message || "Failed to start a new chat."}` : "Sorry, I couldn't start a new chat. Please try again.",
188
+ sender: "bot",
189
+ timestamp: /* @__PURE__ */ new Date()
190
+ }
191
+ ]);
192
+ } finally {
193
+ setIsStartingNewChat(false);
194
+ }
195
+ }, [
196
+ collectedUserEmail,
197
+ collectedUserMobile,
198
+ collectedUserName,
199
+ debug,
200
+ isStartingNewChat,
201
+ sessionId,
202
+ setChatId,
203
+ setSupportSessionId,
204
+ switchToHumanMode
205
+ ]);
206
+ const getDialogflowConfig = () => {
207
+ if (!dfProjectId || !dfAgentId) {
208
+ return void 0;
209
+ }
210
+ return {
211
+ dfProjectId,
212
+ dfLocation: dfLocation || "us-central1",
213
+ dfAgentId,
214
+ serviceAccountKey,
215
+ accessToken,
216
+ languageCode: languageCode || "en"
217
+ };
218
+ };
219
+ useEffect(() => {
220
+ if (!enableWelcomePopup) return;
221
+ const timer = setTimeout(() => {
222
+ setShowWelcomePopup(true);
223
+ }, welcomePopupDelay);
224
+ return () => clearTimeout(timer);
225
+ }, [enableWelcomePopup, welcomePopupDelay]);
226
+ useEffect(() => {
227
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
228
+ }, [messages]);
229
+ const handleAgentChanged = useCallback((message) => {
230
+ if (message.to_agent) {
231
+ setCurrentAgent({
232
+ id: message.to_agent_id,
233
+ name: message.to_agent
234
+ });
235
+ const systemMessage = {
236
+ id: `system-${Date.now()}`,
237
+ text: message.from_agent ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}` : `Chat has been transferred to ${message.to_agent}`,
238
+ sender: "bot",
239
+ timestamp: /* @__PURE__ */ new Date()
240
+ };
241
+ setMessages((prev) => [...prev, systemMessage]);
242
+ if (debug) {
243
+ console.log("Agent changed:", {
244
+ from: message.from_agent,
245
+ to: message.to_agent,
246
+ reason: message.reason
247
+ });
248
+ }
249
+ }
250
+ }, [debug]);
251
+ const handleWebSocketMessage = useCallback((message) => {
252
+ switch (message.type) {
253
+ case "message":
254
+ if (message.content) {
255
+ if (message.sender_type === "agent" || !message.sender_type) {
256
+ const agentMessage = {
257
+ id: message.id || `agent-${Date.now()}`,
258
+ text: message.content,
259
+ sender: "agent",
260
+ timestamp: new Date(message.timestamp || Date.now())
261
+ };
262
+ setMessages((prev) => {
263
+ const existingIds = new Set(prev.map((m2) => m2.id));
264
+ if (existingIds.has(agentMessage.id)) {
265
+ return prev;
266
+ }
267
+ return [...prev, agentMessage];
268
+ });
269
+ setAgentTyping(false);
270
+ if (agentTypingTimeoutRef.current) {
271
+ clearTimeout(agentTypingTimeoutRef.current);
272
+ agentTypingTimeoutRef.current = null;
273
+ }
274
+ } else if (debug && message.sender_type === "customer") {
275
+ console.log("Ignoring customer message from WebSocket (already added)");
276
+ }
277
+ } else if (debug) {
278
+ console.warn("WebSocket message received without content:", message);
279
+ }
280
+ break;
281
+ case "typing_start":
282
+ if (message.sender_type === "agent") {
283
+ setAgentTyping(true);
284
+ if (agentTypingTimeoutRef.current) {
285
+ clearTimeout(agentTypingTimeoutRef.current);
286
+ }
287
+ agentTypingTimeoutRef.current = setTimeout(() => {
288
+ setAgentTyping(false);
289
+ }, 3e3);
290
+ }
291
+ break;
292
+ case "typing_stop":
293
+ if (message.sender_type === "agent") {
294
+ setAgentTyping(false);
295
+ if (agentTypingTimeoutRef.current) {
296
+ clearTimeout(agentTypingTimeoutRef.current);
297
+ agentTypingTimeoutRef.current = null;
298
+ }
299
+ }
300
+ break;
301
+ case "agent_changed":
302
+ handleAgentChanged(message);
303
+ break;
304
+ case "chat_info":
305
+ if (debug) {
306
+ console.log("Chat info:", message);
307
+ }
308
+ if (message.status === "active") {
309
+ setIsConnectingToAgent(false);
310
+ setAgentAccepted(true);
311
+ } else if (message.status === "resolved" || message.status === "ended") {
312
+ enterResolvedState(message.chat_id || null);
313
+ }
314
+ if (message.agent_id) {
315
+ setCurrentAgent((prev) => ({
316
+ ...prev,
317
+ id: message.agent_id
318
+ }));
319
+ }
320
+ break;
321
+ case "agent_accepted":
322
+ setAgentAccepted(true);
323
+ setIsConnectingToAgent(false);
324
+ const acceptedMessage = {
325
+ id: message.id || `agent-accepted-${message.chat_id || Date.now()}-${Date.now()}`,
326
+ text: "You can chat now, the agent has accepted your request.",
327
+ sender: "bot",
328
+ timestamp: message.timestamp ? new Date(message.timestamp) : /* @__PURE__ */ new Date()
329
+ };
330
+ setMessages((prev) => {
331
+ const existingIds = new Set(prev.map((m2) => m2.id));
332
+ if (existingIds.has(acceptedMessage.id)) {
333
+ return prev;
334
+ }
335
+ return [...prev, acceptedMessage];
336
+ });
337
+ if (message.to_agent) {
338
+ setCurrentAgent({
339
+ name: message.to_agent,
340
+ id: message.to_agent_id
341
+ });
342
+ }
343
+ if (debug) {
344
+ console.log("Agent accepted chat:", message);
345
+ }
346
+ break;
347
+ case "chat_resolved":
348
+ case "chat_ended":
349
+ enterResolvedState(message.chat_id || null);
350
+ if (debug) {
351
+ console.log("Chat resolved/ended:", message);
352
+ }
353
+ break;
354
+ case "error":
355
+ console.error("WebSocket error:", message.error);
356
+ const errorMessage = {
357
+ id: `error-${Date.now()}`,
358
+ text: message.error || "An error occurred. Please try again.",
359
+ sender: "bot",
360
+ timestamp: /* @__PURE__ */ new Date()
361
+ };
362
+ setMessages((prev) => [...prev, errorMessage]);
363
+ break;
364
+ case "pong":
365
+ break;
366
+ default:
367
+ if (debug) {
368
+ console.log("Unknown message type:", message.type);
369
+ }
370
+ }
371
+ }, [debug, enterResolvedState, handleAgentChanged]);
372
+ const handleWebSocketClose = useCallback(
373
+ (event) => {
374
+ if (event.code === 4e3) {
375
+ enterResolvedState(chatId);
376
+ }
377
+ },
378
+ [chatId, enterResolvedState]
379
+ );
380
+ const handleConnectionChange = useCallback((connected) => {
381
+ setWsConnected(connected);
382
+ if (connected) {
383
+ setIsConnectingToAgent(false);
384
+ }
385
+ }, []);
386
+ useEffect(() => {
387
+ if (currentMode === "HUMAN" && chatId && supportSessionId) {
388
+ chatServiceRef.current.connectWebSocket(
389
+ chatId,
390
+ supportSessionId,
391
+ handleWebSocketMessage,
392
+ handleConnectionChange,
393
+ handleWebSocketClose
394
+ );
395
+ return () => {
396
+ chatServiceRef.current.disconnectWebSocket();
397
+ };
398
+ }
399
+ }, [
400
+ currentMode,
401
+ chatId,
402
+ supportSessionId,
403
+ handleWebSocketMessage,
404
+ handleConnectionChange,
405
+ handleWebSocketClose
406
+ ]);
407
+ const loadMessageHistory = useCallback(async (preserveExisting = true) => {
408
+ if (!chatId || !supportSessionId) return;
409
+ try {
410
+ setIsLoading(true);
411
+ const history = await chatServiceRef.current.loadMessageHistory(chatId, supportSessionId);
412
+ const historyMessages = history.map((msg) => ({
413
+ id: msg.id || `msg-${Date.now()}-${Math.random()}`,
414
+ text: msg.content,
415
+ sender: msg.sender_type === "agent" ? "agent" : "user",
416
+ timestamp: new Date(msg.timestamp)
417
+ }));
418
+ if (preserveExisting) {
419
+ setMessages((prevMessages) => {
420
+ const existingIds = new Set(prevMessages.map((m2) => m2.id));
421
+ const newMessages = historyMessages.filter((m2) => !existingIds.has(m2.id));
422
+ const combined = [...prevMessages, ...newMessages].sort(
423
+ (a, b) => a.timestamp.getTime() - b.timestamp.getTime()
424
+ );
425
+ return combined;
426
+ });
427
+ } else {
428
+ setMessages(historyMessages);
429
+ }
430
+ } catch (error) {
431
+ console.error("Error loading message history:", error);
432
+ if (debug) {
433
+ const errorMessage = {
434
+ id: `error-${Date.now()}`,
435
+ text: `Failed to load chat history: ${error.message}`,
436
+ sender: "bot",
437
+ timestamp: /* @__PURE__ */ new Date()
438
+ };
439
+ setMessages((prev) => [...prev, errorMessage]);
440
+ }
441
+ } finally {
442
+ setIsLoading(false);
443
+ }
444
+ }, [chatId, supportSessionId, debug]);
445
+ useEffect(() => {
446
+ if (currentMode === "HUMAN" && chatId && supportSessionId) {
447
+ const sessionKey = `${chatId}-${supportSessionId}`;
448
+ if (historyLoadedRef.current !== sessionKey) {
449
+ historyLoadedRef.current = sessionKey;
450
+ const checkAndLoad = () => {
451
+ if (messages.length === 0) {
452
+ loadMessageHistory(false).catch(console.error);
453
+ }
454
+ };
455
+ setTimeout(checkAndLoad, 0);
456
+ }
457
+ } else if (currentMode === "BOT") {
458
+ historyLoadedRef.current = null;
459
+ }
460
+ }, [currentMode, chatId, supportSessionId, loadMessageHistory, messages.length]);
461
+ const handleHandoff = async (customerName, customerEmail, customerMobile) => {
462
+ try {
463
+ setIsConnectingToAgent(true);
464
+ const dialogflowSessionId = sessionId;
465
+ const session = await chatServiceRef.current.ensureChatInitialized(
466
+ chatId,
467
+ supportSessionId,
468
+ dialogflowSessionId || null,
469
+ customerName || null,
470
+ customerEmail || null,
471
+ customerMobile || null
472
+ );
473
+ if (!session || !session.chat_id) {
474
+ throw new Error("Failed to initialize chat session");
475
+ }
476
+ const currentChatId = session.chat_id;
477
+ const currentSupportSessionId = session.session_id;
478
+ if (currentChatId !== chatId) {
479
+ setChatId(currentChatId);
480
+ setSupportSessionId(currentSupportSessionId);
481
+ if (debug) {
482
+ console.log("✅ Chat initialized:", { chatId: currentChatId, sessionId: currentSupportSessionId });
483
+ }
484
+ }
485
+ try {
486
+ await chatServiceRef.current.requestHandoff(
487
+ currentChatId,
488
+ currentSupportSessionId,
489
+ "Customer requested human agent",
490
+ dialogflowSessionId || null,
491
+ customerName || null,
492
+ customerEmail || null,
493
+ customerMobile || null
494
+ );
495
+ if (debug) {
496
+ console.log("✅ Handoff requested successfully");
497
+ }
498
+ } catch (handoffError) {
499
+ if (handoffError.message?.includes("Invalid chat_id") || handoffError.message?.includes("Chat not found") || handoffError.message?.includes("unauthorized") || handoffError.message?.includes("400") || handoffError.message?.includes("401") || handoffError.message?.includes("404") || handoffError.message?.includes("expired")) {
500
+ if (debug) {
501
+ console.log("⚠️ Chat expired or not found. Re-initializing chat...");
502
+ }
503
+ setChatId(null);
504
+ setSupportSessionId(null);
505
+ const newSession = await chatServiceRef.current.startSupportChat(
506
+ dialogflowSessionId || null,
507
+ customerName || null,
508
+ customerEmail || null,
509
+ customerMobile || null
510
+ );
511
+ if (!newSession || !newSession.chat_id) {
512
+ throw new Error("Failed to re-initialize chat session");
513
+ }
514
+ const newChatId = newSession.chat_id;
515
+ const newSessionId = newSession.session_id;
516
+ setChatId(newChatId);
517
+ setSupportSessionId(newSessionId);
518
+ await chatServiceRef.current.requestHandoff(
519
+ newChatId,
520
+ newSessionId,
521
+ "Customer requested human agent",
522
+ dialogflowSessionId || null,
523
+ customerName || null,
524
+ customerEmail || null,
525
+ customerMobile || null
526
+ );
527
+ if (debug) {
528
+ console.log("✅ Handoff requested successfully after retry");
529
+ }
530
+ const newSessionKey = `${newChatId}-${newSessionId}`;
531
+ if (historyLoadedRef.current !== newSessionKey) {
532
+ historyLoadedRef.current = newSessionKey;
533
+ await loadMessageHistory(true);
534
+ }
535
+ } else {
536
+ throw handoffError;
537
+ }
538
+ }
539
+ switchToHumanMode();
540
+ setChatResolved(false);
541
+ setAgentAccepted(false);
542
+ const connectingMessage = {
543
+ id: `connecting-${Date.now()}`,
544
+ text: "Connecting you to a human agent...",
545
+ sender: "bot",
546
+ timestamp: /* @__PURE__ */ new Date()
547
+ };
548
+ setMessages((prev) => [...prev, connectingMessage]);
549
+ const sessionKey = `${currentChatId}-${currentSupportSessionId}`;
550
+ historyLoadedRef.current = sessionKey;
551
+ } catch (error) {
552
+ console.error("Error handling handoff:", error);
553
+ const errorMessage = {
554
+ id: `error-${Date.now()}`,
555
+ text: debug ? `Handoff error: ${error.message}` : "Failed to connect to agent. Please try again.",
556
+ sender: "bot",
557
+ timestamp: /* @__PURE__ */ new Date()
558
+ };
559
+ setMessages((prev) => [...prev, errorMessage]);
560
+ setIsConnectingToAgent(false);
561
+ }
562
+ };
563
+ const createSession = async () => {
564
+ if (sessionId) return sessionId;
565
+ try {
566
+ setIsInitializing(true);
567
+ const dfConfig = getDialogflowConfig();
568
+ if (!dfConfig) {
569
+ throw new Error("Dialogflow configuration is missing. Please provide dfProjectId, dfAgentId, and either serviceAccountKey or accessToken.");
570
+ }
571
+ const data = await createDialogflowSession(dfConfig);
572
+ setSessionId(data.session_id);
573
+ if (data.message) {
574
+ if (debug) {
575
+ console.log("Session response richContent:", data.richContent);
576
+ console.log("Full session response:", data);
577
+ }
578
+ const welcomeMessage2 = {
579
+ id: `welcome-${Date.now()}`,
580
+ text: data.message,
581
+ sender: "bot",
582
+ timestamp: /* @__PURE__ */ new Date(),
583
+ richContent: data.richContent
584
+ };
585
+ setMessages([welcomeMessage2]);
586
+ }
587
+ return data.session_id;
588
+ } catch (error) {
589
+ console.error("Error creating session:", error);
590
+ if (debug) {
591
+ console.error("Full error details:", {
592
+ message: error.message,
593
+ stack: error.stack,
594
+ config: getDialogflowConfig()
595
+ });
596
+ }
597
+ const errorMessage = {
598
+ id: `error-${Date.now()}`,
599
+ text: debug ? `Error: ${error.message || "Failed to create session. Please check your Dialogflow configuration."}` : fallbackWelcomeMessage,
600
+ sender: "bot",
601
+ timestamp: /* @__PURE__ */ new Date()
602
+ };
603
+ setMessages([errorMessage]);
604
+ return null;
605
+ } finally {
606
+ setIsInitializing(false);
607
+ }
608
+ };
609
+ const sendMessage = async (text, displayText, skipUserMessage = false) => {
610
+ if (!text.trim()) return;
611
+ if (collectingUserInfo) {
612
+ if (userInfoStep === "name") {
613
+ const name = text.trim();
614
+ setCollectedUserName(name);
615
+ collectedUserNameRef.current = name;
616
+ setUserInfoStep("email");
617
+ const userMessage = {
618
+ id: Date.now().toString(),
619
+ text: name,
620
+ sender: "user",
621
+ timestamp: /* @__PURE__ */ new Date()
622
+ };
623
+ setMessages((prev) => [...prev, userMessage]);
624
+ const emailPrompt = {
625
+ id: (Date.now() + 1).toString(),
626
+ text: "Thank you! Now please provide your email address:",
627
+ sender: "bot",
628
+ timestamp: /* @__PURE__ */ new Date()
629
+ };
630
+ setMessages((prev) => [...prev, emailPrompt]);
631
+ setInputValue("");
632
+ return;
633
+ } else if (userInfoStep === "email") {
634
+ const email = text.trim();
635
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
636
+ if (!emailRegex.test(email)) {
637
+ const invalidEmailMessage = {
638
+ id: (Date.now() + 1).toString(),
639
+ text: "Please provide a valid email address:",
640
+ sender: "bot",
641
+ timestamp: /* @__PURE__ */ new Date()
642
+ };
643
+ setMessages((prev) => [...prev, invalidEmailMessage]);
644
+ setInputValue("");
645
+ return;
646
+ }
647
+ setCollectedUserEmail(email);
648
+ setUserInfoStep("mobile");
649
+ const userMessage = {
650
+ id: Date.now().toString(),
651
+ text: email,
652
+ sender: "user",
653
+ timestamp: /* @__PURE__ */ new Date()
654
+ };
655
+ setMessages((prev) => [...prev, userMessage]);
656
+ const mobilePrompt = {
657
+ id: (Date.now() + 1).toString(),
658
+ text: "Thank you! Now please provide your mobile number:",
659
+ sender: "bot",
660
+ timestamp: /* @__PURE__ */ new Date()
661
+ };
662
+ setMessages((prev) => [...prev, mobilePrompt]);
663
+ setInputValue("");
664
+ return;
665
+ } else if (userInfoStep === "mobile") {
666
+ const mobile = text.trim();
667
+ const mobileRegex = /^[\+]?[(]?[0-9]{1,4}[)]?[-\s\.]?[(]?[0-9]{1,4}[)]?[-\s\.]?[0-9]{1,9}$/;
668
+ if (!mobileRegex.test(mobile) || mobile.length < 10) {
669
+ const invalidMobileMessage = {
670
+ id: (Date.now() + 1).toString(),
671
+ text: "Please provide a valid mobile number (e.g., +1234567890):",
672
+ sender: "bot",
673
+ timestamp: /* @__PURE__ */ new Date()
674
+ };
675
+ setMessages((prev) => [...prev, invalidMobileMessage]);
676
+ setInputValue("");
677
+ return;
678
+ }
679
+ setCollectedUserMobile(mobile);
680
+ const userMessage = {
681
+ id: Date.now().toString(),
682
+ text: mobile,
683
+ sender: "user",
684
+ timestamp: /* @__PURE__ */ new Date()
685
+ };
686
+ setMessages((prev) => [...prev, userMessage]);
687
+ const userName = collectedUserNameRef.current;
688
+ const userEmail = collectedUserEmail;
689
+ setCollectingUserInfo(false);
690
+ setUserInfoStep(null);
691
+ collectedUserNameRef.current = "";
692
+ await handleHandoff(userName, userEmail, mobile);
693
+ setInputValue("");
694
+ return;
695
+ }
696
+ }
697
+ if (currentMode === "HUMAN") {
698
+ if (!chatId || !supportSessionId) {
699
+ const errorMessage = {
700
+ id: Date.now().toString(),
701
+ text: "Chat session not initialized. Please try again.",
702
+ sender: "bot",
703
+ timestamp: /* @__PURE__ */ new Date()
704
+ };
705
+ setMessages((prev) => [...prev, errorMessage]);
706
+ return;
707
+ }
708
+ if (!skipUserMessage) {
709
+ const userMessage = {
710
+ id: Date.now().toString(),
711
+ text: displayText || text.trim(),
712
+ sender: "user",
713
+ timestamp: /* @__PURE__ */ new Date()
714
+ };
715
+ setMessages((prev) => [...prev, userMessage]);
716
+ }
717
+ chatServiceRef.current.sendTypingIndicator("typing_stop");
718
+ if (typingTimeoutRef.current) {
719
+ clearTimeout(typingTimeoutRef.current);
720
+ typingTimeoutRef.current = null;
721
+ }
722
+ setInputValue("");
723
+ setIsLoading(true);
724
+ try {
725
+ const sentViaWs = chatServiceRef.current.sendMessageViaWebSocket(text.trim());
726
+ if (!sentViaWs) {
727
+ await chatServiceRef.current.sendMessageToAgent(chatId, supportSessionId, text.trim());
728
+ }
729
+ } catch (error) {
730
+ if (error instanceof ChatResolvedError || error?.name === "ChatResolvedError" || error?.message === "chat_resolved") {
731
+ enterResolvedState(chatId);
732
+ return;
733
+ }
734
+ console.error("Error sending message to agent:", error);
735
+ if (error.message?.includes("Chat not found") || error.message?.includes("unauthorized") || error.message?.includes("401") || error.message?.includes("404")) {
736
+ if (debug) {
737
+ console.log("⚠️ Chat expired. Re-initializing...");
738
+ }
739
+ setChatId(null);
740
+ setSupportSessionId(null);
741
+ try {
742
+ const newSession = await chatServiceRef.current.startSupportChat(
743
+ sessionId || null,
744
+ null,
745
+ null,
746
+ null
747
+ );
748
+ setChatId(newSession.chat_id);
749
+ setSupportSessionId(newSession.session_id);
750
+ try {
751
+ await chatServiceRef.current.sendMessageToAgent(
752
+ newSession.chat_id,
753
+ newSession.session_id,
754
+ text.trim()
755
+ );
756
+ } catch (retryError) {
757
+ if (retryError instanceof ChatResolvedError || retryError?.name === "ChatResolvedError" || retryError?.message === "chat_resolved") {
758
+ enterResolvedState(newSession.chat_id);
759
+ return;
760
+ }
761
+ throw retryError;
762
+ }
763
+ return;
764
+ } catch (retryError) {
765
+ if (retryError instanceof ChatResolvedError || retryError?.name === "ChatResolvedError" || retryError?.message === "chat_resolved") {
766
+ enterResolvedState(chatId);
767
+ return;
768
+ }
769
+ const errorMessage = {
770
+ id: (Date.now() + 1).toString(),
771
+ text: debug ? `Error: ${retryError.message || "Failed to send message."}` : "Sorry, I'm having trouble sending your message. Please try again.",
772
+ sender: "bot",
773
+ timestamp: /* @__PURE__ */ new Date()
774
+ };
775
+ setMessages((prev) => [...prev, errorMessage]);
776
+ }
777
+ } else {
778
+ const errorMessage = {
779
+ id: (Date.now() + 1).toString(),
780
+ text: debug ? `Error: ${error.message || "Failed to send message to agent."}` : "Sorry, I'm having trouble sending your message. Please try again.",
781
+ sender: "bot",
782
+ timestamp: /* @__PURE__ */ new Date()
783
+ };
784
+ setMessages((prev) => [...prev, errorMessage]);
785
+ }
786
+ } finally {
787
+ setIsLoading(false);
788
+ }
789
+ return;
790
+ }
791
+ let currentSessionId = sessionId;
792
+ if (!currentSessionId) {
793
+ try {
794
+ currentSessionId = await createSession();
795
+ if (!currentSessionId) {
796
+ const errorMessage = {
797
+ id: Date.now().toString(),
798
+ text: debug ? "Failed to create session. Please check the console for details." : "Sorry, I'm having trouble connecting. Please try again.",
799
+ sender: "bot",
800
+ timestamp: /* @__PURE__ */ new Date()
801
+ };
802
+ setMessages((prev) => [...prev, errorMessage]);
803
+ return;
804
+ }
805
+ } catch (error) {
806
+ console.error("Error in createSession:", error);
807
+ const errorMessage = {
808
+ id: Date.now().toString(),
809
+ text: debug ? `Connection Error: ${error.message || "Please check your Dialogflow configuration."}` : "Sorry, I'm having trouble connecting. Please check your configuration.",
810
+ sender: "bot",
811
+ timestamp: /* @__PURE__ */ new Date()
812
+ };
813
+ setMessages((prev) => [...prev, errorMessage]);
814
+ return;
815
+ }
816
+ }
817
+ if (!skipUserMessage) {
818
+ const userMessage = {
819
+ id: Date.now().toString(),
820
+ text: displayText || text.trim(),
821
+ sender: "user",
822
+ timestamp: /* @__PURE__ */ new Date()
823
+ };
824
+ setMessages((prev) => [...prev, userMessage]);
825
+ }
826
+ setInputValue("");
827
+ setIsLoading(true);
828
+ try {
829
+ const dfConfig = getDialogflowConfig();
830
+ if (!dfConfig) {
831
+ throw new Error("Dialogflow configuration is missing. Please provide dfProjectId, dfAgentId, and either serviceAccountKey or accessToken.");
832
+ }
833
+ const data = await sendDialogflowMessage(text.trim(), currentSessionId, dfConfig);
834
+ if (debug) {
835
+ console.log("Chat response richContent:", data.richContent);
836
+ console.log("Full chat response:", data);
837
+ console.log("Handoff detected:", data.handoff);
838
+ }
839
+ if (data.handoff === true) {
840
+ const botMessage2 = {
841
+ id: (Date.now() + 1).toString(),
842
+ text: data.response,
843
+ sender: "bot",
844
+ timestamp: new Date(data.timestamp || Date.now()),
845
+ richContent: data.richContent
846
+ };
847
+ setMessages((prev) => [...prev, botMessage2]);
848
+ setCollectingUserInfo(true);
849
+ setUserInfoStep("name");
850
+ setCollectedUserName("");
851
+ setCollectedUserEmail("");
852
+ collectedUserNameRef.current = "";
853
+ const namePrompt = {
854
+ id: (Date.now() + 2).toString(),
855
+ text: "To connect you with a human agent, I'll need some information. Please provide your name:",
856
+ sender: "bot",
857
+ timestamp: /* @__PURE__ */ new Date()
858
+ };
859
+ setMessages((prev) => [...prev, namePrompt]);
860
+ return;
861
+ }
862
+ const botMessage = {
863
+ id: (Date.now() + 1).toString(),
864
+ text: data.response,
865
+ sender: "bot",
866
+ timestamp: new Date(data.timestamp || Date.now()),
867
+ richContent: data.richContent
868
+ };
869
+ setMessages((prev) => [...prev, botMessage]);
870
+ } catch (error) {
871
+ console.error("Error sending message:", error);
872
+ if (debug) {
873
+ console.error("Full error details:", {
874
+ message: error.message,
875
+ stack: error.stack,
876
+ sessionId: currentSessionId,
877
+ config: getDialogflowConfig()
878
+ });
879
+ }
880
+ const errorMessage = {
881
+ id: (Date.now() + 1).toString(),
882
+ 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.",
883
+ sender: "bot",
884
+ timestamp: /* @__PURE__ */ new Date()
885
+ };
886
+ setMessages((prev) => [...prev, errorMessage]);
887
+ } finally {
888
+ setIsLoading(false);
889
+ }
890
+ };
891
+ const handleSubmit = (e) => {
892
+ e.preventDefault();
893
+ sendMessage(inputValue);
894
+ };
895
+ const handleInputChange = (e) => {
896
+ const value = e.target.value;
897
+ setInputValue(value);
898
+ if (currentMode === "HUMAN" && wsConnected) {
899
+ chatServiceRef.current.sendTypingIndicator("typing_start");
900
+ if (typingTimeoutRef.current) {
901
+ clearTimeout(typingTimeoutRef.current);
902
+ }
903
+ typingTimeoutRef.current = setTimeout(() => {
904
+ chatServiceRef.current.sendTypingIndicator("typing_stop");
905
+ typingTimeoutRef.current = null;
906
+ }, 2e3);
907
+ }
908
+ };
909
+ useEffect(() => {
910
+ return () => {
911
+ if (typingTimeoutRef.current) {
912
+ clearTimeout(typingTimeoutRef.current);
913
+ }
914
+ if (agentTypingTimeoutRef.current) {
915
+ clearTimeout(agentTypingTimeoutRef.current);
916
+ }
917
+ };
918
+ }, []);
919
+ const openChat = async () => {
920
+ setIsOpen(true);
921
+ setShowWelcomePopup(false);
922
+ if (!sessionId) {
923
+ await createSession();
924
+ }
925
+ };
926
+ const closeChat = () => {
927
+ setIsOpen(false);
928
+ if (currentMode === "HUMAN") {
929
+ chatServiceRef.current.disconnectWebSocket();
930
+ }
931
+ };
932
+ const isHandoffMessage = (text) => {
933
+ return text.includes("👤") || text.includes("being connected") || text.includes("live support agent") || text.includes("transfer your conversation") || text.includes("✅") || text.includes("🔄");
934
+ };
935
+ useEffect(() => {
936
+ return () => {
937
+ chatServiceRef.current.disconnectWebSocket();
938
+ };
939
+ }, []);
940
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
941
+ showWelcomePopup && !isOpen && /* @__PURE__ */ jsxs("div", { className: "custom-welcome-popup", onClick: openChat, children: [
942
+ /* @__PURE__ */ jsxs("div", { className: "custom-welcome-header", children: [
943
+ /* @__PURE__ */ jsx("div", { className: "custom-welcome-title", children: welcomeTitle }),
944
+ /* @__PURE__ */ jsx(
945
+ "button",
946
+ {
947
+ className: "custom-close-popup",
948
+ onClick: (e) => {
949
+ e.stopPropagation();
950
+ setShowWelcomePopup(false);
951
+ },
952
+ children: "×"
953
+ }
954
+ )
955
+ ] }),
956
+ /* @__PURE__ */ jsx("div", { className: "custom-welcome-message", children: welcomeMessage }),
957
+ /* @__PURE__ */ jsx("div", { className: "custom-welcome-cta", children: welcomeCta })
958
+ ] }),
959
+ !isOpen && /* @__PURE__ */ jsx(
960
+ "button",
961
+ {
962
+ className: "custom-chat-toggle-btn",
963
+ onClick: openChat,
964
+ "aria-label": "Open chat",
965
+ children: /* @__PURE__ */ jsx(
966
+ "svg",
967
+ {
968
+ width: "24",
969
+ height: "24",
970
+ viewBox: "0 0 24 24",
971
+ fill: "none",
972
+ stroke: "currentColor",
973
+ strokeWidth: "2",
974
+ strokeLinecap: "round",
975
+ strokeLinejoin: "round",
976
+ children: /* @__PURE__ */ jsx("path", { d: "M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" })
977
+ }
978
+ )
979
+ }
980
+ ),
981
+ isOpen && /* @__PURE__ */ jsxs("div", { className: "custom-chat-window", children: [
982
+ /* @__PURE__ */ jsxs("div", { className: "custom-chat-header", children: [
983
+ /* @__PURE__ */ jsxs("div", { className: "custom-chat-header-content", children: [
984
+ /* @__PURE__ */ jsx("div", { className: "custom-chat-title", children: title }),
985
+ /* @__PURE__ */ jsxs("div", { className: "custom-chat-subtitle", children: [
986
+ subtitle,
987
+ currentMode === "HUMAN" && /* @__PURE__ */ jsxs("span", { className: "custom-mode-indicator", children: [
988
+ " ",
989
+ "• ",
990
+ wsConnected ? "🟢 Connected" : "🟡 Connecting..."
991
+ ] })
992
+ ] }),
993
+ currentMode === "HUMAN" && /* @__PURE__ */ jsxs(Fragment, { children: [
994
+ /* @__PURE__ */ jsx("div", { className: "custom-mode-badge", children: "Human Support Mode" }),
995
+ /* @__PURE__ */ jsxs("div", { className: "custom-agent-info", children: [
996
+ /* @__PURE__ */ jsx("span", { className: "custom-agent-label", children: "Agent:" }),
997
+ /* @__PURE__ */ jsx("span", { className: "custom-agent-name", children: currentAgent.name })
998
+ ] })
999
+ ] }),
1000
+ currentMode === "BOT" && /* @__PURE__ */ jsx("div", { className: "custom-mode-badge", children: "Bot Mode" })
1001
+ ] }),
1002
+ /* @__PURE__ */ jsx(
1003
+ "button",
1004
+ {
1005
+ className: "custom-chat-close-btn",
1006
+ onClick: closeChat,
1007
+ "aria-label": "Close chat",
1008
+ children: "×"
1009
+ }
1010
+ )
1011
+ ] }),
1012
+ /* @__PURE__ */ jsxs("div", { className: "custom-chat-messages", children: [
1013
+ isInitializing && messages.length === 0 && /* @__PURE__ */ jsxs("div", { className: "custom-chat-empty", children: [
1014
+ /* @__PURE__ */ jsxs("div", { className: "custom-typing-indicator", children: [
1015
+ /* @__PURE__ */ jsx("span", {}),
1016
+ /* @__PURE__ */ jsx("span", {}),
1017
+ /* @__PURE__ */ jsx("span", {})
1018
+ ] }),
1019
+ /* @__PURE__ */ jsx("p", { children: "Initializing chat..." })
1020
+ ] }),
1021
+ !isInitializing && messages.length === 0 && /* @__PURE__ */ jsxs("div", { className: "custom-chat-empty", children: [
1022
+ /* @__PURE__ */ jsx("div", { className: "custom-chat-empty-icon", children: "👋" }),
1023
+ /* @__PURE__ */ jsx("p", { children: emptyStateMessage })
1024
+ ] }),
1025
+ messages.map((message) => /* @__PURE__ */ jsxs(
1026
+ "div",
1027
+ {
1028
+ className: `custom-message custom-message-${message.sender} ${isHandoffMessage(message.text) ? "custom-handoff-message" : ""}`,
1029
+ children: [
1030
+ /* @__PURE__ */ jsx(
1031
+ "div",
1032
+ {
1033
+ className: `custom-message-content ${isHandoffMessage(message.text) ? "custom-handoff-content" : ""}`,
1034
+ dangerouslySetInnerHTML: {
1035
+ __html: linkifyText(message.text).replace(/\n/g, "<br>")
1036
+ }
1037
+ }
1038
+ ),
1039
+ (() => {
1040
+ if (debug && message.richContent) {
1041
+ console.log("Rendering message with richContent:", message.richContent);
1042
+ console.log("richContent type:", typeof message.richContent);
1043
+ console.log("richContent is array:", Array.isArray(message.richContent));
1044
+ console.log("richContent length:", message.richContent?.length);
1045
+ }
1046
+ if (message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0) {
1047
+ return /* @__PURE__ */ jsx("div", { className: "custom-chips-container", children: message.richContent.map((contentGroup, groupIndex) => {
1048
+ if (debug) {
1049
+ console.log(`Processing contentGroup ${groupIndex}:`, contentGroup);
1050
+ }
1051
+ if (!Array.isArray(contentGroup)) {
1052
+ const content = contentGroup;
1053
+ if (content && content.type === "chips" && content.options) {
1054
+ return /* @__PURE__ */ jsx("div", { className: "custom-chips-group", children: content.options.map((chip, chipIndex) => /* @__PURE__ */ jsx(
1055
+ "button",
1056
+ {
1057
+ className: "custom-chip-button",
1058
+ onClick: () => {
1059
+ const userMessage = {
1060
+ id: Date.now().toString(),
1061
+ text: chip.text,
1062
+ sender: "user",
1063
+ timestamp: /* @__PURE__ */ new Date()
1064
+ };
1065
+ setMessages((prev) => [...prev, userMessage]);
1066
+ sendMessage(chip.text, chip.text, true);
1067
+ },
1068
+ type: "button",
1069
+ children: chip.text
1070
+ },
1071
+ chipIndex
1072
+ )) }, groupIndex);
1073
+ }
1074
+ return null;
1075
+ }
1076
+ return contentGroup.map((content, contentIndex) => {
1077
+ if (debug) {
1078
+ console.log(`Processing content ${groupIndex}-${contentIndex}:`, content);
1079
+ }
1080
+ if (content && content.type === "chips" && content.options) {
1081
+ return /* @__PURE__ */ jsx("div", { className: "custom-chips-group", children: content.options.map((chip, chipIndex) => /* @__PURE__ */ jsx(
1082
+ "button",
1083
+ {
1084
+ className: "custom-chip-button",
1085
+ onClick: () => {
1086
+ const userMessage = {
1087
+ id: Date.now().toString(),
1088
+ text: chip.text,
1089
+ sender: "user",
1090
+ timestamp: /* @__PURE__ */ new Date()
1091
+ };
1092
+ setMessages((prev) => [...prev, userMessage]);
1093
+ sendMessage(chip.text, chip.text, true);
1094
+ },
1095
+ type: "button",
1096
+ children: chip.text
1097
+ },
1098
+ chipIndex
1099
+ )) }, `${groupIndex}-${contentIndex}`);
1100
+ }
1101
+ return null;
1102
+ });
1103
+ }) });
1104
+ }
1105
+ return null;
1106
+ })(),
1107
+ /* @__PURE__ */ jsx("div", { className: "custom-message-time", children: message.timestamp.toLocaleTimeString([], {
1108
+ hour: "2-digit",
1109
+ minute: "2-digit"
1110
+ }) })
1111
+ ]
1112
+ },
1113
+ message.id
1114
+ )),
1115
+ isLoading && /* @__PURE__ */ jsx("div", { className: "custom-message custom-message-bot", children: /* @__PURE__ */ jsxs("div", { className: "custom-typing-indicator", children: [
1116
+ /* @__PURE__ */ jsx("span", {}),
1117
+ /* @__PURE__ */ jsx("span", {}),
1118
+ /* @__PURE__ */ jsx("span", {})
1119
+ ] }) }),
1120
+ isConnectingToAgent && /* @__PURE__ */ jsxs("div", { className: "custom-message custom-message-bot", children: [
1121
+ /* @__PURE__ */ jsxs("div", { className: "custom-typing-indicator", children: [
1122
+ /* @__PURE__ */ jsx("span", {}),
1123
+ /* @__PURE__ */ jsx("span", {}),
1124
+ /* @__PURE__ */ jsx("span", {})
1125
+ ] }),
1126
+ /* @__PURE__ */ jsx("div", { className: "custom-message-content", children: "Connecting to agent..." })
1127
+ ] }),
1128
+ currentMode === "HUMAN" && agentTyping && /* @__PURE__ */ jsxs("div", { className: "custom-agent-typing-indicator", children: [
1129
+ /* @__PURE__ */ jsxs("span", { className: "custom-typing-dots", children: [
1130
+ /* @__PURE__ */ jsx("span", {}),
1131
+ /* @__PURE__ */ jsx("span", {}),
1132
+ /* @__PURE__ */ jsx("span", {})
1133
+ ] }),
1134
+ /* @__PURE__ */ jsx("span", { className: "custom-typing-text", children: "Agent is typing..." })
1135
+ ] }),
1136
+ /* @__PURE__ */ jsx("div", { ref: messagesEndRef })
1137
+ ] }),
1138
+ /* @__PURE__ */ jsxs("form", { className: "custom-chat-input-form", onSubmit: handleSubmit, children: [
1139
+ /* @__PURE__ */ jsx(
1140
+ "input",
1141
+ {
1142
+ type: "text",
1143
+ className: "custom-chat-input",
1144
+ value: inputValue,
1145
+ onChange: handleInputChange,
1146
+ placeholder: inputPlaceholder,
1147
+ disabled: isLoading || isInitializing || isStartingNewChat
1148
+ }
1149
+ ),
1150
+ /* @__PURE__ */ jsx(
1151
+ "button",
1152
+ {
1153
+ type: "submit",
1154
+ className: "custom-chat-send-btn",
1155
+ disabled: !inputValue.trim() || isLoading || isInitializing || isStartingNewChat,
1156
+ children: /* @__PURE__ */ jsxs(
1157
+ "svg",
1158
+ {
1159
+ width: "20",
1160
+ height: "20",
1161
+ viewBox: "0 0 24 24",
1162
+ fill: "none",
1163
+ stroke: "currentColor",
1164
+ strokeWidth: "2",
1165
+ strokeLinecap: "round",
1166
+ strokeLinejoin: "round",
1167
+ children: [
1168
+ /* @__PURE__ */ jsx("line", { x1: "22", y1: "2", x2: "11", y2: "13" }),
1169
+ /* @__PURE__ */ jsx("polygon", { points: "22 2 15 22 11 13 2 9 22 2" })
1170
+ ]
1171
+ }
1172
+ )
1173
+ }
1174
+ )
1175
+ ] })
1176
+ ] })
1177
+ ] });
1178
+ }
1179
+ function detectFramework() {
1180
+ const isSSR = typeof window === "undefined";
1181
+ if (typeof process !== "undefined" && typeof process.env !== "undefined") {
1182
+ const env = process.env;
1183
+ if (env?.NEXT_RUNTIME) {
1184
+ return {
1185
+ name: "next",
1186
+ version: env.NEXT_VERSION,
1187
+ isSSR
1188
+ };
1189
+ }
1190
+ }
1191
+ if (typeof process !== "undefined" && typeof process.env !== "undefined") {
1192
+ const env = process.env;
1193
+ if (env?.NUXT || globalThis.__NUXT__) {
1194
+ return {
1195
+ name: "nuxt",
1196
+ version: env.NUXT_VERSION,
1197
+ isSSR
1198
+ };
1199
+ }
1200
+ }
1201
+ if (globalThis.__NUXT__) {
1202
+ return {
1203
+ name: "nuxt",
1204
+ version: void 0,
1205
+ isSSR
1206
+ };
1207
+ }
1208
+ if (typeof import.meta !== "undefined") {
1209
+ const meta = import.meta;
1210
+ if (meta.env?.DEV) {
1211
+ return {
1212
+ name: "vite",
1213
+ version: meta.env?.VITE_VERSION,
1214
+ isSSR
1215
+ };
1216
+ }
1217
+ }
1218
+ if (detectReact()) {
1219
+ return {
1220
+ name: "react",
1221
+ version: getReactVersion(),
1222
+ isSSR
1223
+ };
1224
+ }
1225
+ if (detectVue()) {
1226
+ return {
1227
+ name: "vue",
1228
+ version: getVueVersion(),
1229
+ isSSR
1230
+ };
1231
+ }
1232
+ return {
1233
+ name: "vanilla",
1234
+ isSSR
1235
+ };
1236
+ }
1237
+ function detectReact() {
1238
+ if (typeof window !== "undefined") {
1239
+ if (window.React || window.react) {
1240
+ return true;
1241
+ }
1242
+ }
1243
+ if (typeof document !== "undefined") {
1244
+ if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
1245
+ return true;
1246
+ }
1247
+ }
1248
+ return false;
1249
+ }
1250
+ function getReactVersion() {
1251
+ try {
1252
+ if (typeof window !== "undefined" && window.React?.version) {
1253
+ return window.React.version;
1254
+ }
1255
+ if (typeof window !== "undefined" && window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
1256
+ const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
1257
+ if (hook.renderers && hook.renderers.size > 0) {
1258
+ const renderer = Array.from(hook.renderers.values())[0];
1259
+ return renderer.version;
1260
+ }
1261
+ }
1262
+ } catch {
1263
+ }
1264
+ return void 0;
1265
+ }
1266
+ function detectVue() {
1267
+ if (typeof window !== "undefined") {
1268
+ if (window.Vue || window.vue) {
1269
+ return true;
1270
+ }
1271
+ }
1272
+ if (typeof window !== "undefined") {
1273
+ if (window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
1274
+ return true;
1275
+ }
1276
+ }
1277
+ return false;
1278
+ }
1279
+ function getVueVersion() {
1280
+ try {
1281
+ if (typeof window !== "undefined" && window.Vue?.version) {
1282
+ return window.Vue.version;
1283
+ }
1284
+ if (typeof window !== "undefined" && window.__VUE_DEVTOOLS_GLOBAL_HOOK__) {
1285
+ const hook = window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
1286
+ if (hook.apps && hook.apps.length > 0) {
1287
+ const app = hook.apps[0];
1288
+ return app.version;
1289
+ }
1290
+ }
1291
+ } catch {
1292
+ }
1293
+ return void 0;
1294
+ }
1295
+ let forcedFramework = null;
1296
+ function setFramework(framework) {
1297
+ forcedFramework = framework;
1298
+ }
1299
+ function getFramework() {
1300
+ if (forcedFramework) {
1301
+ return {
1302
+ name: forcedFramework,
1303
+ isSSR: typeof window === "undefined"
1304
+ };
1305
+ }
1306
+ return detectFramework();
1307
+ }
1308
+ var createRoot;
1309
+ var m = require$$0;
1310
+ {
1311
+ createRoot = m.createRoot;
1312
+ m.hydrateRoot;
1313
+ }
1314
+ class ChatWidget {
1315
+ constructor(container, config) {
1316
+ this.root = null;
1317
+ this.config = config;
1318
+ if (typeof container === "string") {
1319
+ const element = document.querySelector(container);
1320
+ if (!element) {
1321
+ throw new Error(`Container element "${container}" not found`);
1322
+ }
1323
+ this.container = element;
1324
+ } else {
1325
+ this.container = container;
1326
+ }
1327
+ this.root = createRoot(this.container);
1328
+ this.render();
1329
+ }
1330
+ render() {
1331
+ if (this.root) {
1332
+ this.root.render(React.createElement(ChatWidget$1, this.config));
1333
+ }
1334
+ }
1335
+ /**
1336
+ * Update configuration
1337
+ */
1338
+ updateConfig(config) {
1339
+ this.config = { ...this.config, ...config };
1340
+ this.render();
1341
+ }
1342
+ /**
1343
+ * Destroy the widget
1344
+ */
1345
+ destroy() {
1346
+ if (this.root) {
1347
+ this.root.unmount();
1348
+ this.root = null;
1349
+ }
1350
+ }
1351
+ }
1352
+ function createChatWidget(container, config) {
1353
+ return new ChatWidget(container, config);
1354
+ }
5
1355
  export {
6
- default2 as ChatWidget,
7
- default3 as ReactChatWidget,
1356
+ ChatWidget$1 as ChatWidget,
1357
+ ChatWidget$1 as ReactChatWidget,
8
1358
  ChatWidget as VanillaChatWidget,
9
1359
  createChatWidget,
10
1360
  createDialogflowSession,
11
- default4 as default,
1361
+ ChatWidget$1 as default,
12
1362
  getFramework,
13
1363
  sendDialogflowMessage,
14
1364
  setFramework