@theonexai/chartsconnect-chat-widget 1.0.18

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