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