@om_patel_26/chat-widget 1.0.6 → 1.0.7

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 (48) hide show
  1. package/README.md +16 -102
  2. package/dist/components/ChatWidget.cjs.js +2 -0
  3. package/dist/components/ChatWidget.cjs.js.map +1 -0
  4. package/dist/components/ChatWidget.esm.js +1129 -0
  5. package/dist/components/ChatWidget.esm.js.map +1 -0
  6. package/dist/core/stateManager.cjs.js +1 -1
  7. package/dist/core/stateManager.cjs.js.map +1 -1
  8. package/dist/core/stateManager.d.ts.map +1 -1
  9. package/dist/core/stateManager.esm.js +38 -36
  10. package/dist/core/stateManager.esm.js.map +1 -1
  11. package/dist/entry/vanilla.cjs.js +2 -0
  12. package/dist/entry/vanilla.cjs.js.map +1 -0
  13. package/dist/entry/vanilla.esm.js +50 -0
  14. package/dist/entry/vanilla.esm.js.map +1 -0
  15. package/dist/entry/vue.d.ts +3 -2
  16. package/dist/entry/vue.d.ts.map +1 -1
  17. package/dist/hooks/useChatMode.cjs.js +2 -0
  18. package/dist/hooks/useChatMode.cjs.js.map +1 -0
  19. package/dist/hooks/useChatMode.esm.js +61 -0
  20. package/dist/hooks/useChatMode.esm.js.map +1 -0
  21. package/dist/index.cjs.js +1 -1
  22. package/dist/index.d.ts +18 -11
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.esm.js +9 -18
  25. package/dist/index.esm.js.map +1 -1
  26. package/dist/node_modules/jose/dist/browser/lib/check_key_type.cjs.js.map +1 -1
  27. package/dist/node_modules/react-dom/client.cjs.js +2 -0
  28. package/dist/node_modules/react-dom/client.cjs.js.map +1 -0
  29. package/dist/node_modules/react-dom/client.esm.js +21 -0
  30. package/dist/node_modules/react-dom/client.esm.js.map +1 -0
  31. package/dist/services/dialogflowClient.cjs.js.map +1 -1
  32. package/dist/services/dialogflowClient.d.ts.map +1 -1
  33. package/dist/services/dialogflowClient.esm.js.map +1 -1
  34. package/dist/styles.css +1 -0
  35. package/dist/utils/frameworkDetector.cjs.js +2 -0
  36. package/dist/utils/frameworkDetector.cjs.js.map +1 -0
  37. package/dist/utils/frameworkDetector.esm.js +125 -0
  38. package/dist/utils/frameworkDetector.esm.js.map +1 -0
  39. package/dist/utils/sanitize.cjs.js +1 -1
  40. package/dist/utils/sanitize.cjs.js.map +1 -1
  41. package/dist/utils/sanitize.esm.js +1 -6
  42. package/dist/utils/sanitize.esm.js.map +1 -1
  43. package/dist/vue.esm.js +3 -3
  44. package/package.json +20 -16
  45. package/dist/utils/ssr.cjs.js +0 -2
  46. package/dist/utils/ssr.cjs.js.map +0 -1
  47. package/dist/utils/ssr.esm.js +0 -48
  48. package/dist/utils/ssr.esm.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatWidget.esm.js","sources":["../../src/components/ChatWidget.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport {\n createDialogflowSession,\n sendDialogflowMessage,\n type DialogflowConfig,\n type SessionResponse,\n type ChatResponse,\n} from \"../services/dialogflowClient\";\nimport { useChatMode } from \"../hooks/useChatMode\";\nimport { ChatResolvedError, createChatService, type WebSocketMessage } from \"../services/chatService\";\nimport { linkifyText } from \"../utils/sanitize\";\nimport \"../styles/chatWidget.css\";\n\ninterface ChipOption {\n text: string;\n payload: string;\n}\n\ninterface RichContent {\n type?: string;\n options?: ChipOption[];\n}\n\ntype RichContentArray = RichContent | RichContent[];\n\ninterface Message {\n id: string;\n text: string;\n sender: \"user\" | \"bot\" | \"agent\";\n timestamp: Date;\n richContent?: RichContentArray[];\n}\n\nexport interface ChatWidgetProps {\n /** Custom title for the chat widget */\n title?: string;\n /** Custom subtitle for the chat widget */\n subtitle?: string;\n /** Welcome popup title */\n welcomeTitle?: string;\n /** Welcome popup message */\n welcomeMessage?: string;\n /** Welcome popup CTA text */\n welcomeCta?: string;\n /** Whether to show the welcome popup */\n showWelcomePopup?: boolean;\n /** Delay in milliseconds before showing welcome popup */\n welcomePopupDelay?: number;\n /** Fallback welcome message if API fails */\n fallbackWelcomeMessage?: string;\n /** Placeholder text for input field */\n inputPlaceholder?: string;\n /** Custom empty state message */\n emptyStateMessage?: string;\n /** Enable/disable debug logging */\n debug?: boolean;\n /** Dialogflow project ID */\n dfProjectId?: string;\n /** Dialogflow location (e.g., \"us-central1\") */\n dfLocation?: string;\n /** Dialogflow agent ID */\n dfAgentId?: string;\n /** Google Cloud service account key JSON object */\n serviceAccountKey?: any;\n /** Access token (alternative to serviceAccountKey) */\n accessToken?: string;\n /** Language code for Dialogflow */\n languageCode?: string;\n /** Backend API base URL (default: http://localhost:8012) */\n backendBaseUrl?: string;\n /** WebSocket URL (default: ws://localhost:8012) */\n backendWsUrl?: string;\n}\n\nexport default function ChatWidget({\n title = \"💬 BlockSpark AI Assistant\",\n subtitle = \"We're here to help\",\n welcomeTitle = \"👋 Welcome to Blockspark\",\n welcomeMessage = \"My name is BlockSpark AI Assistant and I'll guide you.\",\n welcomeCta = \"💬 Click here to start chatting!\",\n showWelcomePopup: enableWelcomePopup = true,\n welcomePopupDelay = 1500,\n fallbackWelcomeMessage = \"Hello! I'm BlockSpark AI Assistant. How can I help you today?\",\n inputPlaceholder = \"Type your message...\",\n emptyStateMessage = \"Hi! I'm BlockSpark AI Assistant. How can I help you today?\",\n debug = false,\n dfProjectId,\n dfLocation = \"us-central1\",\n dfAgentId,\n serviceAccountKey,\n accessToken,\n languageCode = \"en\",\n backendBaseUrl,\n backendWsUrl,\n}: ChatWidgetProps) {\n const [isOpen, setIsOpen] = useState(false);\n const [showWelcomePopup, setShowWelcomePopup] = useState(false);\n const [messages, setMessages] = useState<Message[]>([]);\n const [inputValue, setInputValue] = useState(\"\");\n const [isLoading, setIsLoading] = useState(false);\n const [sessionId, setSessionId] = useState<string | null>(null);\n const [isInitializing, setIsInitializing] = useState(false);\n const [isConnectingToAgent, setIsConnectingToAgent] = useState(false);\n const [wsConnected, setWsConnected] = useState(false);\n const [agentTyping, setAgentTyping] = useState(false);\n const [currentAgent, setCurrentAgent] = useState<{ name: string; id?: string }>({ name: \"Agent\" });\n const [collectingUserInfo, setCollectingUserInfo] = useState(false);\n const [chatResolved, setChatResolved] = useState(false);\n const [isStartingNewChat, setIsStartingNewChat] = useState(false);\n const [agentAccepted, setAgentAccepted] = useState(false);\n const [userInfoStep, setUserInfoStep] = useState<\"name\" | \"email\" | \"mobile\" | null>(null);\n const [collectedUserName, setCollectedUserName] = useState<string>(\"\");\n const [collectedUserEmail, setCollectedUserEmail] = useState<string>(\"\");\n const [collectedUserMobile, setCollectedUserMobile] = useState<string>(\"\");\n const collectedUserNameRef = useRef<string>(\"\");\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const agentTypingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n \n // Get backend URLs from props or environment variables\n const getBackendBaseUrl = () => {\n return backendBaseUrl || \n (typeof process !== 'undefined' && (process as any).env?.REACT_APP_BACKEND_BASE_URL)\n };\n \n const getBackendWsUrl = () => {\n return backendWsUrl || \n (typeof process !== 'undefined' && (process as any).env?.REACT_APP_BACKEND_WS_URL)\n };\n \n const chatServiceRef = useRef(\n createChatService({ \n baseUrl: getBackendBaseUrl(), \n wsUrl: getBackendWsUrl(),\n debug: debug\n })\n );\n const historyLoadedRef = useRef<string | null>(null);\n \n // Use chat mode hook\n const {\n currentMode,\n switchToHumanMode,\n switchToBotMode,\n chatId,\n sessionId: supportSessionId,\n setChatId,\n setSessionId: setSupportSessionId,\n } = useChatMode();\n\n const enterResolvedState = useCallback(\n (_resolvedChatId?: string | null) => {\n setChatResolved(true);\n setIsConnectingToAgent(false);\n setAgentAccepted(false);\n setAgentTyping(false);\n if (agentTypingTimeoutRef.current) {\n clearTimeout(agentTypingTimeoutRef.current);\n agentTypingTimeoutRef.current = null;\n }\n\n // Stop WS + prevent any reuse of the old chat_id\n chatServiceRef.current.disconnectWebSocket();\n setChatId(null);\n setSupportSessionId(null);\n \n // Add thank you message before reset\n const thankYouMessage: Message = {\n id: `resolved-${Date.now()}`,\n text: \"Thank you for contacting us!\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, thankYouMessage]);\n \n // Automatically reset to BOT mode after showing thank you message\n setTimeout(() => {\n switchToBotMode();\n setChatResolved(false);\n setMessages([]);\n setCollectingUserInfo(false);\n setUserInfoStep(null);\n setCollectedUserName(\"\");\n setCollectedUserEmail(\"\");\n setCollectedUserMobile(\"\");\n collectedUserNameRef.current = \"\";\n \n // Recreate Dialogflow session to start fresh\n createSession().catch(console.error);\n }, 2000); // 3 second delay to show thank you message\n },\n [setChatId, setSupportSessionId, switchToBotMode]\n );\n\n const handleStartNewChat = useCallback(async () => {\n if (isStartingNewChat) return;\n setIsStartingNewChat(true);\n try {\n const customerName = collectedUserNameRef.current || collectedUserName || null;\n const customerEmail = collectedUserEmail || null;\n const customerMobile = collectedUserMobile || null;\n\n const newSession = await chatServiceRef.current.startSupportChat(\n sessionId || null,\n customerName,\n customerEmail,\n customerMobile\n );\n\n switchToHumanMode();\n setChatId(newSession.chat_id);\n setSupportSessionId(newSession.session_id);\n setChatResolved(false);\n setInputValue(\"\");\n } catch (error: any) {\n console.error(\"Error starting new chat:\", error);\n setMessages((prev) => [\n ...prev,\n {\n id: `error-new-chat-${Date.now()}`,\n text: debug\n ? `Error: ${error?.message || \"Failed to start a new chat.\"}`\n : \"Sorry, I couldn't start a new chat. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n },\n ]);\n } finally {\n setIsStartingNewChat(false);\n }\n }, [\n collectedUserEmail,\n collectedUserMobile,\n collectedUserName,\n debug,\n isStartingNewChat,\n sessionId,\n setChatId,\n setSupportSessionId,\n switchToHumanMode,\n ]);\n\n // Helper function to build Dialogflow config from props\n const getDialogflowConfig = (): DialogflowConfig | undefined => {\n if (!dfProjectId || !dfAgentId) {\n return undefined;\n }\n \n return {\n dfProjectId,\n dfLocation: dfLocation || 'us-central1',\n dfAgentId,\n serviceAccountKey,\n accessToken,\n languageCode: languageCode || 'en',\n };\n };\n\n // Show welcome popup after page load\n useEffect(() => {\n if (!enableWelcomePopup) return;\n \n const timer = setTimeout(() => {\n setShowWelcomePopup(true);\n }, welcomePopupDelay);\n return () => clearTimeout(timer);\n }, [enableWelcomePopup, welcomePopupDelay]);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: \"smooth\" });\n }, [messages]);\n\n // Handle agent changed notification\n const handleAgentChanged = useCallback((message: WebSocketMessage) => {\n if (message.to_agent) {\n setCurrentAgent({\n id: message.to_agent_id,\n name: message.to_agent,\n });\n\n // Add system message to chat\n const systemMessage: Message = {\n id: `system-${Date.now()}`,\n text: message.from_agent\n ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}`\n : `Chat has been transferred to ${message.to_agent}`,\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, systemMessage]);\n\n if (debug) {\n console.log(\"Agent changed:\", {\n from: message.from_agent,\n to: message.to_agent,\n reason: message.reason,\n });\n }\n }\n }, [debug]);\n\n // Handle WebSocket messages\n const handleWebSocketMessage = useCallback((message: WebSocketMessage) => {\n switch (message.type) {\n case \"message\":\n if (message.content) {\n // Only display messages from agent, ignore customer messages (we already added them)\n if (message.sender_type === \"agent\" || !message.sender_type) {\n const agentMessage: Message = {\n id: message.id || `agent-${Date.now()}`,\n text: message.content,\n sender: \"agent\",\n timestamp: new Date(message.timestamp || Date.now()),\n };\n setMessages((prev) => {\n // Avoid duplicate messages by checking if message ID already exists\n const existingIds = new Set(prev.map(m => m.id));\n if (existingIds.has(agentMessage.id)) {\n return prev;\n }\n return [...prev, agentMessage];\n });\n // Hide typing indicator when message received\n setAgentTyping(false);\n if (agentTypingTimeoutRef.current) {\n clearTimeout(agentTypingTimeoutRef.current);\n agentTypingTimeoutRef.current = null;\n }\n } else if (debug && message.sender_type === \"customer\") {\n console.log(\"Ignoring customer message from WebSocket (already added)\");\n }\n // If sender_type is \"customer\", ignore it - we already added the user message\n } else if (debug) {\n console.warn(\"WebSocket message received without content:\", message);\n }\n break;\n\n case \"typing_start\":\n if (message.sender_type === \"agent\") {\n setAgentTyping(true);\n // Auto-hide after 3 seconds if no message received\n if (agentTypingTimeoutRef.current) {\n clearTimeout(agentTypingTimeoutRef.current);\n }\n agentTypingTimeoutRef.current = setTimeout(() => {\n setAgentTyping(false);\n }, 3000);\n }\n break;\n\n case \"typing_stop\":\n if (message.sender_type === \"agent\") {\n setAgentTyping(false);\n if (agentTypingTimeoutRef.current) {\n clearTimeout(agentTypingTimeoutRef.current);\n agentTypingTimeoutRef.current = null;\n }\n }\n break;\n\n case \"agent_changed\":\n handleAgentChanged(message);\n break;\n\n case \"chat_info\":\n if (debug) {\n console.log(\"Chat info:\", message);\n }\n // Update connection status based on chat info\n if (message.status === \"active\") {\n setIsConnectingToAgent(false);\n setAgentAccepted(true);\n } else if (message.status === \"resolved\" || message.status === \"ended\") {\n enterResolvedState(message.chat_id || null);\n }\n // Update agent info if provided\n if (message.agent_id) {\n setCurrentAgent((prev) => ({\n ...prev,\n id: message.agent_id,\n }));\n }\n break;\n\n case \"agent_accepted\":\n // Agent has accepted the chat request\n setAgentAccepted(true);\n setIsConnectingToAgent(false);\n const acceptedMessage: Message = {\n id: message.id || `agent-accepted-${message.chat_id || Date.now()}-${Date.now()}`,\n text: \"You can chat now, the agent has accepted your request.\",\n sender: \"bot\",\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n setMessages((prev) => {\n // Avoid duplicate messages\n const existingIds = new Set(prev.map(m => m.id));\n if (existingIds.has(acceptedMessage.id)) {\n return prev;\n }\n return [...prev, acceptedMessage];\n });\n // Update agent info if provided\n if (message.to_agent) {\n setCurrentAgent({\n name: message.to_agent,\n id: message.to_agent_id,\n });\n }\n if (debug) {\n console.log(\"Agent accepted chat:\", message);\n }\n break;\n\n case \"chat_resolved\":\n case \"chat_ended\":\n // Chat has been resolved/ended by agent (terminal state)\n enterResolvedState(message.chat_id || null);\n if (debug) {\n console.log(\"Chat resolved/ended:\", message);\n }\n break;\n\n case \"error\":\n console.error(\"WebSocket error:\", message.error);\n const errorMessage: Message = {\n id: `error-${Date.now()}`,\n text: message.error || \"An error occurred. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n break;\n\n case \"pong\":\n // Keep-alive response, no action needed\n break;\n\n default:\n if (debug) {\n console.log(\"Unknown message type:\", message.type);\n }\n }\n }, [debug, enterResolvedState, handleAgentChanged]);\n\n const handleWebSocketClose = useCallback(\n (event: CloseEvent) => {\n // Backend uses 4000 to indicate the chat is resolved, and then closes.\n if (event.code === 4000) {\n enterResolvedState(chatId);\n }\n },\n [chatId, enterResolvedState]\n );\n\n // Handle WebSocket connection changes\n const handleConnectionChange = useCallback((connected: boolean) => {\n setWsConnected(connected);\n if (connected) {\n setIsConnectingToAgent(false);\n }\n }, []);\n\n // Initialize WebSocket when switching to HUMAN mode\n useEffect(() => {\n if (currentMode === \"HUMAN\" && chatId && supportSessionId) {\n chatServiceRef.current.connectWebSocket(\n chatId,\n supportSessionId,\n handleWebSocketMessage,\n handleConnectionChange,\n handleWebSocketClose\n );\n\n return () => {\n chatServiceRef.current.disconnectWebSocket();\n };\n }\n }, [\n currentMode,\n chatId,\n supportSessionId,\n handleWebSocketMessage,\n handleConnectionChange,\n handleWebSocketClose,\n ]);\n\n // Load message history from backend\n const loadMessageHistory = useCallback(async (preserveExisting: boolean = true) => {\n if (!chatId || !supportSessionId) return;\n\n try {\n setIsLoading(true);\n const history = await chatServiceRef.current.loadMessageHistory(chatId, supportSessionId);\n \n const historyMessages: Message[] = history.map((msg) => ({\n id: msg.id || `msg-${Date.now()}-${Math.random()}`,\n text: msg.content,\n sender: msg.sender_type === \"agent\" ? \"agent\" : \"user\",\n timestamp: new Date(msg.timestamp),\n }));\n\n if (preserveExisting) {\n // Merge with existing messages, avoiding duplicates\n setMessages((prevMessages) => {\n const existingIds = new Set(prevMessages.map(m => m.id));\n const newMessages = historyMessages.filter(m => !existingIds.has(m.id));\n \n // Combine existing messages with new history messages\n // Sort by timestamp to maintain chronological order\n const combined = [...prevMessages, ...newMessages].sort((a, b) => \n a.timestamp.getTime() - b.timestamp.getTime()\n );\n \n return combined;\n });\n } else {\n // Replace all messages (only if explicitly requested)\n setMessages(historyMessages);\n }\n } catch (error: any) {\n console.error(\"Error loading message history:\", error);\n if (debug) {\n const errorMessage: Message = {\n id: `error-${Date.now()}`,\n text: `Failed to load chat history: ${error.message}`,\n sender: \"bot\",\n timestamp: new Date(),\n };\n // Only add error message, don't replace existing messages\n setMessages((prev) => [...prev, errorMessage]);\n }\n } finally {\n setIsLoading(false);\n }\n }, [chatId, supportSessionId, debug]);\n\n // Load message history when switching to HUMAN mode\n useEffect(() => {\n if (currentMode === \"HUMAN\" && chatId && supportSessionId) {\n // Only load if we haven't loaded history for this chat session yet\n const sessionKey = `${chatId}-${supportSessionId}`;\n if (historyLoadedRef.current !== sessionKey) {\n historyLoadedRef.current = sessionKey;\n // Check if we have existing messages (from bot conversation during handoff)\n // If yes, preserve them and don't load history\n // If no, load history for new chat\n // Access messages state via a ref or check in the next tick\n const checkAndLoad = () => {\n // Check messages length - if 0, load history; if > 0, preserve existing\n if (messages.length === 0) {\n // No existing messages, load history\n loadMessageHistory(false).catch(console.error);\n }\n // Has existing messages (bot conversation), keep them - don't load history\n };\n // Use setTimeout to ensure we check after state updates\n setTimeout(checkAndLoad, 0);\n }\n } else if (currentMode === \"BOT\") {\n // Reset history loaded flag when switching back to BOT mode\n historyLoadedRef.current = null;\n }\n }, [currentMode, chatId, supportSessionId, loadMessageHistory, messages.length]);\n\n // Handle handoff from Dialogflow\n const handleHandoff = async (customerName?: string, customerEmail?: string, customerMobile?: string) => {\n try {\n setIsConnectingToAgent(true);\n \n // Get Dialogflow session ID if available\n const dialogflowSessionId = sessionId;\n \n // STEP 1: Ensure chat is initialized (validates existing or creates new)\n const session = await chatServiceRef.current.ensureChatInitialized(\n chatId,\n supportSessionId,\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!session || !session.chat_id) {\n throw new Error(\"Failed to initialize chat session\");\n }\n \n const currentChatId = session.chat_id;\n const currentSupportSessionId = session.session_id;\n \n // Update state if chat was newly initialized\n if (currentChatId !== chatId) {\n setChatId(currentChatId);\n setSupportSessionId(currentSupportSessionId);\n if (debug) {\n console.log(\"✅ Chat initialized:\", { chatId: currentChatId, sessionId: currentSupportSessionId });\n }\n }\n\n // STEP 2: Request handoff with valid chat_id (include name/email/mobile to update existing chat)\n try {\n await chatServiceRef.current.requestHandoff(\n currentChatId,\n currentSupportSessionId,\n \"Customer requested human agent\",\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (debug) {\n console.log(\"✅ Handoff requested successfully\");\n }\n } catch (handoffError: any) {\n // Handle 401/404 or \"chat not found\" - clear chat_id and retry (but keep session logic)\n if (handoffError.message?.includes(\"Invalid chat_id\") || \n handoffError.message?.includes(\"Chat not found\") ||\n handoffError.message?.includes(\"unauthorized\") ||\n handoffError.message?.includes(\"400\") ||\n handoffError.message?.includes(\"401\") ||\n handoffError.message?.includes(\"404\") ||\n handoffError.message?.includes(\"expired\")) {\n if (debug) {\n console.log(\"⚠️ Chat expired or not found. Re-initializing chat...\");\n }\n \n // Clear old chat_id (but keep session logic - session_id is managed by sessionManager)\n setChatId(null);\n setSupportSessionId(null);\n \n // Create new chat session (session_id will be automatically included from session manager)\n const newSession = await chatServiceRef.current.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!newSession || !newSession.chat_id) {\n throw new Error(\"Failed to re-initialize chat session\");\n }\n \n const newChatId = newSession.chat_id;\n const newSessionId = newSession.session_id;\n setChatId(newChatId);\n setSupportSessionId(newSessionId);\n \n // Retry handoff with new chat_id\n await chatServiceRef.current.requestHandoff(\n newChatId,\n newSessionId,\n \"Customer requested human agent\",\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (debug) {\n console.log(\"✅ Handoff requested successfully after retry\");\n }\n \n // Update for message history loading\n const newSessionKey = `${newChatId}-${newSessionId}`;\n if (historyLoadedRef.current !== newSessionKey) {\n historyLoadedRef.current = newSessionKey;\n await loadMessageHistory(true);\n }\n } else {\n throw handoffError;\n }\n }\n\n // Switch to human mode\n switchToHumanMode();\n // Reset states for new handoff\n setChatResolved(false);\n setAgentAccepted(false);\n\n // Add connecting message (preserve existing messages)\n const connectingMessage: Message = {\n id: `connecting-${Date.now()}`,\n text: \"Connecting you to a human agent...\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, connectingMessage]);\n\n // Don't load history during handoff - preserve existing bot conversation\n // History will be loaded automatically via useEffect if needed for new sessions\n const sessionKey = `${currentChatId}-${currentSupportSessionId}`;\n historyLoadedRef.current = sessionKey;\n } catch (error: any) {\n console.error(\"Error handling handoff:\", error);\n const errorMessage: Message = {\n id: `error-${Date.now()}`,\n text: debug\n ? `Handoff error: ${error.message}`\n : \"Failed to connect to agent. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n setIsConnectingToAgent(false);\n }\n };\n\n // Create new session\n const createSession = async () => {\n if (sessionId) return sessionId;\n\n try {\n setIsInitializing(true);\n const dfConfig = getDialogflowConfig();\n if (!dfConfig) {\n throw new Error('Dialogflow configuration is missing. Please provide dfProjectId, dfAgentId, and either serviceAccountKey or accessToken.');\n }\n \n const data = await createDialogflowSession(dfConfig);\n setSessionId(data.session_id);\n\n // Add welcome message from backend\n if (data.message) {\n if (debug) {\n console.log('Session response richContent:', data.richContent);\n console.log('Full session response:', data);\n }\n \n const welcomeMessage: Message = {\n id: `welcome-${Date.now()}`,\n text: data.message,\n sender: \"bot\",\n timestamp: new Date(),\n richContent: data.richContent,\n };\n setMessages([welcomeMessage]);\n }\n\n return data.session_id;\n } catch (error: any) {\n console.error(\"Error creating session:\", error);\n if (debug) {\n console.error(\"Full error details:\", {\n message: error.message,\n stack: error.stack,\n config: getDialogflowConfig(),\n });\n }\n // Show error message to user\n const errorMessage: Message = {\n id: `error-${Date.now()}`,\n text: debug \n ? `Error: ${error.message || 'Failed to create session. Please check your Dialogflow configuration.'}`\n : fallbackWelcomeMessage,\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages([errorMessage]);\n return null;\n } finally {\n setIsInitializing(false);\n }\n };\n\n // Note: Dialogflow manages conversation history internally\n // History is maintained through the session, so we don't need to load it separately\n\n // Send message to backend API\n const sendMessage = async (text: string, displayText?: string, skipUserMessage: boolean = false) => {\n if (!text.trim()) return;\n\n // Handle user info collection for handoff\n if (collectingUserInfo) {\n if (userInfoStep === \"name\") {\n // Save name and ask for email\n const name = text.trim();\n setCollectedUserName(name);\n collectedUserNameRef.current = name;\n setUserInfoStep(\"email\");\n \n // Add user message\n const userMessage: Message = {\n id: Date.now().toString(),\n text: name,\n sender: \"user\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n \n // Ask for email\n const emailPrompt: Message = {\n id: (Date.now() + 1).toString(),\n text: \"Thank you! Now please provide your email address:\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, emailPrompt]);\n setInputValue(\"\");\n return;\n } else if (userInfoStep === \"email\") {\n // Validate email format (basic validation)\n const email = text.trim();\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n \n if (!emailRegex.test(email)) {\n // Invalid email, ask again\n const invalidEmailMessage: Message = {\n id: (Date.now() + 1).toString(),\n text: \"Please provide a valid email address:\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, invalidEmailMessage]);\n setInputValue(\"\");\n return;\n }\n \n // Save email and ask for mobile\n setCollectedUserEmail(email);\n setUserInfoStep(\"mobile\");\n \n // Add user message\n const userMessage: Message = {\n id: Date.now().toString(),\n text: email,\n sender: \"user\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n \n // Ask for mobile\n const mobilePrompt: Message = {\n id: (Date.now() + 1).toString(),\n text: \"Thank you! Now please provide your mobile number:\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, mobilePrompt]);\n setInputValue(\"\");\n return;\n } else if (userInfoStep === \"mobile\") {\n // Validate mobile format (basic validation - allows +, digits, spaces, dashes)\n const mobile = text.trim();\n const mobileRegex = /^[\\+]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[0-9]{1,9}$/;\n \n if (!mobileRegex.test(mobile) || mobile.length < 10) {\n // Invalid mobile, ask again\n const invalidMobileMessage: Message = {\n id: (Date.now() + 1).toString(),\n text: \"Please provide a valid mobile number (e.g., +1234567890):\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, invalidMobileMessage]);\n setInputValue(\"\");\n return;\n }\n \n // Save mobile and proceed with handoff\n setCollectedUserMobile(mobile);\n \n // Add user message\n const userMessage: Message = {\n id: Date.now().toString(),\n text: mobile,\n sender: \"user\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n \n // Get the collected info from ref and state (avoids state timing issues)\n const userName = collectedUserNameRef.current;\n const userEmail = collectedUserEmail;\n \n // Reset collection state\n setCollectingUserInfo(false);\n setUserInfoStep(null);\n collectedUserNameRef.current = \"\";\n \n // Proceed with handoff using collected info\n await handleHandoff(userName, userEmail, mobile);\n setInputValue(\"\");\n return;\n }\n }\n\n // Handle HUMAN mode\n if (currentMode === \"HUMAN\") {\n if (!chatId || !supportSessionId) {\n const errorMessage: Message = {\n id: Date.now().toString(),\n text: \"Chat session not initialized. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n return;\n }\n\n // Add user message unless skipped\n if (!skipUserMessage) {\n const userMessage: Message = {\n id: Date.now().toString(),\n text: displayText || text.trim(),\n sender: \"user\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n }\n\n // Send typing_stop before sending message\n chatServiceRef.current.sendTypingIndicator(\"typing_stop\");\n \n // Clear typing timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n typingTimeoutRef.current = null;\n }\n\n setInputValue(\"\");\n setIsLoading(true);\n\n try {\n // Try WebSocket first, fallback to REST API\n const sentViaWs = chatServiceRef.current.sendMessageViaWebSocket(text.trim());\n \n if (!sentViaWs) {\n // Fallback to REST API\n await chatServiceRef.current.sendMessageToAgent(chatId, supportSessionId, text.trim());\n }\n } catch (error: any) {\n // chat_resolved is a normal terminal success condition, not an error.\n if (\n error instanceof ChatResolvedError ||\n error?.name === \"ChatResolvedError\" ||\n error?.message === \"chat_resolved\"\n ) {\n enterResolvedState(chatId);\n return;\n }\n\n console.error(\"Error sending message to agent:\", error);\n \n // Handle 401/404 - clear chat_id and reinitialize (but keep session logic)\n if (error.message?.includes(\"Chat not found\") ||\n error.message?.includes(\"unauthorized\") ||\n error.message?.includes(\"401\") ||\n error.message?.includes(\"404\")) {\n if (debug) {\n console.log(\"⚠️ Chat expired. Re-initializing...\");\n }\n \n // Clear chat_id (session_id is managed by sessionManager)\n setChatId(null);\n setSupportSessionId(null);\n \n // Try to reinitialize chat\n try {\n const newSession = await chatServiceRef.current.startSupportChat(\n sessionId || null,\n null,\n null,\n null\n );\n setChatId(newSession.chat_id);\n setSupportSessionId(newSession.session_id);\n \n // Retry sending message\n try {\n await chatServiceRef.current.sendMessageToAgent(\n newSession.chat_id,\n newSession.session_id,\n text.trim()\n );\n } catch (retryError: any) {\n if (\n retryError instanceof ChatResolvedError ||\n retryError?.name === \"ChatResolvedError\" ||\n retryError?.message === \"chat_resolved\"\n ) {\n enterResolvedState(newSession.chat_id);\n return;\n }\n throw retryError;\n }\n return; // Success, exit early\n } catch (retryError: any) {\n if (\n retryError instanceof ChatResolvedError ||\n retryError?.name === \"ChatResolvedError\" ||\n retryError?.message === \"chat_resolved\"\n ) {\n enterResolvedState(chatId);\n return;\n }\n // If retry fails, show error\n const errorMessage: Message = {\n id: (Date.now() + 1).toString(),\n text: debug\n ? `Error: ${retryError.message || 'Failed to send message.'}`\n : \"Sorry, I'm having trouble sending your message. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n }\n } else {\n const errorMessage: Message = {\n id: (Date.now() + 1).toString(),\n text: debug\n ? `Error: ${error.message || 'Failed to send message to agent.'}`\n : \"Sorry, I'm having trouble sending your message. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n }\n } finally {\n setIsLoading(false);\n }\n return;\n }\n\n // Handle BOT mode (Dialogflow)\n // Ensure we have a session\n let currentSessionId = sessionId;\n if (!currentSessionId) {\n try {\n currentSessionId = await createSession();\n if (!currentSessionId) {\n const errorMessage: Message = {\n id: Date.now().toString(),\n text: debug \n ? \"Failed to create session. Please check the console for details.\"\n : \"Sorry, I'm having trouble connecting. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n return;\n }\n } catch (error: any) {\n console.error(\"Error in createSession:\", error);\n const errorMessage: Message = {\n id: Date.now().toString(),\n text: debug \n ? `Connection Error: ${error.message || 'Please check your Dialogflow configuration.'}`\n : \"Sorry, I'm having trouble connecting. Please check your configuration.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n return;\n }\n }\n\n // Add user message unless skipped (e.g., when chip button already added it)\n if (!skipUserMessage) {\n const userMessage: Message = {\n id: Date.now().toString(),\n text: displayText || text.trim(),\n sender: \"user\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n }\n \n setInputValue(\"\");\n setIsLoading(true);\n\n try {\n const dfConfig = getDialogflowConfig();\n if (!dfConfig) {\n throw new Error('Dialogflow configuration is missing. Please provide dfProjectId, dfAgentId, and either serviceAccountKey or accessToken.');\n }\n \n const data = await sendDialogflowMessage(text.trim(), currentSessionId, dfConfig);\n\n if (debug) {\n console.log('Chat response richContent:', data.richContent);\n console.log('Full chat response:', data);\n console.log('Handoff detected:', data.handoff);\n }\n \n // Check for handoff\n if (data.handoff === true) {\n // Add bot response first\n const botMessage: Message = {\n id: (Date.now() + 1).toString(),\n text: data.response,\n sender: \"bot\",\n timestamp: new Date(data.timestamp || Date.now()),\n richContent: data.richContent,\n };\n setMessages((prev) => [...prev, botMessage]);\n \n // Start collecting user info for handoff\n setCollectingUserInfo(true);\n setUserInfoStep(\"name\");\n setCollectedUserName(\"\");\n setCollectedUserEmail(\"\");\n collectedUserNameRef.current = \"\";\n \n // Ask for name\n const namePrompt: Message = {\n id: (Date.now() + 2).toString(),\n text: \"To connect you with a human agent, I'll need some information. Please provide your name:\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, namePrompt]);\n return;\n }\n \n const botMessage: Message = {\n id: (Date.now() + 1).toString(),\n text: data.response,\n sender: \"bot\",\n timestamp: new Date(data.timestamp || Date.now()),\n richContent: data.richContent,\n };\n\n setMessages((prev) => [...prev, botMessage]);\n } catch (error: any) {\n console.error(\"Error sending message:\", error);\n if (debug) {\n console.error(\"Full error details:\", {\n message: error.message,\n stack: error.stack,\n sessionId: currentSessionId,\n config: getDialogflowConfig(),\n });\n }\n const errorMessage: Message = {\n id: (Date.now() + 1).toString(),\n text: debug\n ? `Error: ${error.message || 'Failed to send message. Please check your Dialogflow configuration.'}`\n : error.message?.includes(\"Failed to fetch\") || error.message?.includes(\"CORS\")\n ? \"Unable to connect to Dialogflow. Please check your configuration and network.\"\n : \"Sorry, I'm having trouble processing your message. Please try again.\",\n sender: \"bot\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, errorMessage]);\n } finally {\n setIsLoading(false);\n }\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n sendMessage(inputValue);\n };\n\n // Handle input change - send typing indicators (only in HUMAN mode)\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n setInputValue(value);\n\n // Only send typing indicators in HUMAN mode with WebSocket connected\n if (currentMode === \"HUMAN\" && wsConnected) {\n // Send typing_start\n chatServiceRef.current.sendTypingIndicator(\"typing_start\");\n\n // Clear existing timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n // Send typing_stop after 2 seconds of inactivity\n typingTimeoutRef.current = setTimeout(() => {\n chatServiceRef.current.sendTypingIndicator(\"typing_stop\");\n typingTimeoutRef.current = null;\n }, 2000);\n }\n };\n\n // Cleanup typing timeouts on unmount\n useEffect(() => {\n return () => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (agentTypingTimeoutRef.current) {\n clearTimeout(agentTypingTimeoutRef.current);\n }\n };\n }, []);\n\n const openChat = async () => {\n setIsOpen(true);\n setShowWelcomePopup(false);\n\n // Create session when chat opens if it doesn't exist\n if (!sessionId) {\n await createSession();\n }\n // Note: Dialogflow maintains conversation history internally through the session\n };\n\n const closeChat = () => {\n setIsOpen(false);\n // Disconnect WebSocket when closing chat\n if (currentMode === \"HUMAN\") {\n chatServiceRef.current.disconnectWebSocket();\n }\n };\n\n // Check if message is a handoff message\n const isHandoffMessage = (text: string): boolean => {\n return (\n text.includes(\"👤\") ||\n text.includes(\"being connected\") ||\n text.includes(\"live support agent\") ||\n text.includes(\"transfer your conversation\") ||\n text.includes(\"✅\") ||\n text.includes(\"🔄\")\n );\n };\n\n // Cleanup WebSocket on unmount\n useEffect(() => {\n return () => {\n chatServiceRef.current.disconnectWebSocket();\n };\n }, []);\n\n return (\n <>\n {/* Welcome Popup */}\n {showWelcomePopup && !isOpen && (\n <div className=\"custom-welcome-popup\" onClick={openChat}>\n <div className=\"custom-welcome-header\">\n <div className=\"custom-welcome-title\">{welcomeTitle}</div>\n <button\n className=\"custom-close-popup\"\n onClick={(e) => {\n e.stopPropagation();\n setShowWelcomePopup(false);\n }}\n >\n ×\n </button>\n </div>\n <div className=\"custom-welcome-message\">\n {welcomeMessage}\n </div>\n <div className=\"custom-welcome-cta\">{welcomeCta}</div>\n </div>\n )}\n\n {/* Chat Toggle Button */}\n {!isOpen && (\n <button\n className=\"custom-chat-toggle-btn\"\n onClick={openChat}\n aria-label=\"Open chat\"\n >\n <svg\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </button>\n )}\n\n {/* Chat Window */}\n {isOpen && (\n <div className=\"custom-chat-window\">\n <div className=\"custom-chat-header\">\n <div className=\"custom-chat-header-content\">\n <div className=\"custom-chat-title\">{title}</div>\n <div className=\"custom-chat-subtitle\">\n {subtitle}\n {currentMode === \"HUMAN\" && (\n <span className=\"custom-mode-indicator\">\n {\" \"}\n • {wsConnected ? \"🟢 Connected\" : \"🟡 Connecting...\"}\n </span>\n )}\n </div>\n {currentMode === \"HUMAN\" && (\n <>\n <div className=\"custom-mode-badge\">Human Support Mode</div>\n <div className=\"custom-agent-info\">\n <span className=\"custom-agent-label\">Agent:</span>\n <span className=\"custom-agent-name\">{currentAgent.name}</span>\n </div>\n </>\n )}\n {currentMode === \"BOT\" && (\n <div className=\"custom-mode-badge\">Bot Mode</div>\n )}\n </div>\n <button\n className=\"custom-chat-close-btn\"\n onClick={closeChat}\n aria-label=\"Close chat\"\n >\n ×\n </button>\n </div>\n\n <div className=\"custom-chat-messages\">\n {isInitializing && messages.length === 0 && (\n <div className=\"custom-chat-empty\">\n <div className=\"custom-typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n <p>Initializing chat...</p>\n </div>\n )}\n {!isInitializing && messages.length === 0 && (\n <div className=\"custom-chat-empty\">\n <div className=\"custom-chat-empty-icon\">👋</div>\n <p>{emptyStateMessage}</p>\n </div>\n )}\n {messages.map((message) => (\n <div\n key={message.id}\n className={`custom-message custom-message-${message.sender} ${\n isHandoffMessage(message.text) ? \"custom-handoff-message\" : \"\"\n }`}\n >\n <div \n className={`custom-message-content ${\n isHandoffMessage(message.text) ? \"custom-handoff-content\" : \"\"\n }`}\n dangerouslySetInnerHTML={{ \n __html: linkifyText(message.text).replace(/\\n/g, \"<br>\") \n }}\n />\n {(() => {\n // Debug: Log rich content structure\n if (debug && message.richContent) {\n console.log('Rendering message with richContent:', message.richContent);\n console.log('richContent type:', typeof message.richContent);\n console.log('richContent is array:', Array.isArray(message.richContent));\n console.log('richContent length:', message.richContent?.length);\n }\n \n // Check if richContent exists and has data\n if (message.richContent && Array.isArray(message.richContent) && message.richContent.length > 0) {\n return (\n <div className=\"custom-chips-container\">\n {message.richContent.map((contentGroup, groupIndex) => {\n if (debug) {\n console.log(`Processing contentGroup ${groupIndex}:`, contentGroup);\n }\n if (!Array.isArray(contentGroup)) {\n // Handle case where contentGroup is not an array (single RichContent object)\n const content = contentGroup as RichContent;\n if (content && content.type === \"chips\" && content.options) {\n return (\n <div key={groupIndex} className=\"custom-chips-group\">\n {content.options.map((chip: ChipOption, chipIndex: number) => (\n <button\n key={chipIndex}\n className=\"custom-chip-button\"\n onClick={() => {\n const userMessage: Message = {\n id: Date.now().toString(),\n text: chip.text,\n sender: \"user\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n // Send the chip text instead of payload for better intent matching\n // Dialogflow will match the text to the intent\n sendMessage(chip.text, chip.text, true);\n }}\n type=\"button\"\n >\n {chip.text}\n </button>\n ))}\n </div>\n );\n }\n return null;\n }\n return contentGroup.map((content: RichContent, contentIndex: number) => {\n if (debug) {\n console.log(`Processing content ${groupIndex}-${contentIndex}:`, content);\n }\n if (content && content.type === \"chips\" && content.options) {\n return (\n <div key={`${groupIndex}-${contentIndex}`} className=\"custom-chips-group\">\n {content.options.map((chip: ChipOption, chipIndex: number) => (\n <button\n key={chipIndex}\n className=\"custom-chip-button\"\n onClick={() => {\n const userMessage: Message = {\n id: Date.now().toString(),\n text: chip.text,\n sender: \"user\",\n timestamp: new Date(),\n };\n setMessages((prev) => [...prev, userMessage]);\n // Send the chip text instead of payload for better intent matching\n sendMessage(chip.text, chip.text, true);\n }}\n type=\"button\"\n >\n {chip.text}\n </button>\n ))}\n </div>\n );\n }\n return null;\n });\n })}\n </div>\n );\n }\n return null;\n })()}\n <div className=\"custom-message-time\">\n {message.timestamp.toLocaleTimeString([], {\n hour: \"2-digit\",\n minute: \"2-digit\",\n })}\n </div>\n </div>\n ))}\n {isLoading && (\n <div className=\"custom-message custom-message-bot\">\n <div className=\"custom-typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n </div>\n )}\n {isConnectingToAgent && (\n <div className=\"custom-message custom-message-bot\">\n <div className=\"custom-typing-indicator\">\n <span></span>\n <span></span>\n <span></span>\n </div>\n <div className=\"custom-message-content\">\n Connecting to agent...\n </div>\n </div>\n )}\n {/* Agent Typing Indicator */}\n {currentMode === \"HUMAN\" && agentTyping && (\n <div className=\"custom-agent-typing-indicator\">\n <span className=\"custom-typing-dots\">\n <span></span>\n <span></span>\n <span></span>\n </span>\n <span className=\"custom-typing-text\">Agent is typing...</span>\n </div>\n )}\n <div ref={messagesEndRef} />\n </div>\n\n <form className=\"custom-chat-input-form\" onSubmit={handleSubmit}>\n <input\n type=\"text\"\n className=\"custom-chat-input\"\n value={inputValue}\n onChange={handleInputChange}\n placeholder={inputPlaceholder}\n disabled={isLoading || isInitializing || isStartingNewChat}\n />\n <button\n type=\"submit\"\n className=\"custom-chat-send-btn\"\n disabled={!inputValue.trim() || isLoading || isInitializing || isStartingNewChat}\n >\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </form>\n </div>\n )}\n </>\n );\n} "],"names":["ChatWidget","welcomeMessage","botMessage"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../services/dialogflowClient.cjs.js"),t=require("../services/chatService.cjs.js"),s=require("../utils/ssr.cjs.js");exports.WidgetStateManager=class{constructor(e){this.listeners=new Set,this.chatMode="ai",this.chatId=null,this.supportSessionId=null,this.chatService=null,this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.wsConnected=!1,this.agentTyping=!1,this.currentAgent={name:"Agent"},this.isConnectingToAgent=!1,this.agentAccepted=!1,this.chatResolved=!1,this.historyLoaded=null,this.typingTimeout=null,this.agentTypingTimeout=null,this.config=e,this.state={isOpen:!1,showWelcomePopup:!1,messages:[],inputValue:"",isLoading:!1,error:null,sessionId:null,chatMode:"ai"},this.chatService=t.createChatService({baseUrl:this.config.backendBaseUrl||"http://localhost:8012",wsUrl:this.config.backendWsUrl||"ws://localhost:8012",debug:this.config.debug||!1});const i=s.safeLocalStorage(),a=i.getItem("blockspark_chat_mode");a&&(this.chatMode="HUMAN"===a?"human":"ai",this.state.chatMode=this.chatMode),this.chatId=i.getItem("blockspark_chat_id"),this.supportSessionId=i.getItem("blockspark_session_id")}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}getState(){return{...this.state}}setState(e){this.state={...this.state,...e},this.listeners.forEach(e=>e(this.getState()))}updateConfig(e){this.config={...this.config,...e}}async openChat(){if(this.setState({isOpen:!0}),this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1}),"ai"===this.state.chatMode&&!this.state.sessionId&&this.config.dfProjectId&&this.config.dfAgentId)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}}closeChat(){this.setState({isOpen:!1})}closeWelcomePopup(){this.setState({showWelcomePopup:!1})}toggleChat(){const e=!this.state.isOpen;this.setState({isOpen:e}),e&&this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1})}setInputValue(e){this.setState({inputValue:e})}clearError(){this.setState({error:null})}async sendMessage(e,s=!1){if(e.trim()&&!this.state.isLoading){if(this.collectingUserInfo){const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};return this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!1,error:null}),void(await this.handleUserInfoCollection(e))}if(s)this.setState({inputValue:"",isLoading:!0,error:null});else{const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!0,error:null})}try{"human"===this.state.chatMode?await this.sendHumanMessage(e):await this.sendAIMessage(e)}catch(i){if(i instanceof t.ChatResolvedError||"ChatResolvedError"===i?.name||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);const e={id:`error-${Date.now()}`,text:this.config.debug?`Error: ${i.message||"Failed to send message"}`:i.message?.includes("CORS")||i.message?.includes("Failed to fetch")?"Unable to connect to Dialogflow. Please check your configuration and network.":"Sorry, I'm having trouble processing your message. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e],error:i.message||"Failed to send message",isLoading:!1})}}}async sendAIMessage(t){if(!this.config.dfProjectId||!this.config.dfAgentId)throw new Error("Dialogflow configuration is missing");const s={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"};if(!this.state.sessionId){const t=await e.createDialogflowSession(s);this.setState({sessionId:t.session_id})}this.config.debug;const i=await e.sendDialogflowMessage(t,this.state.sessionId,s);if(this.config.debug,!0===i.handoff){const e={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};return this.setState({messages:[...this.state.messages,e],isLoading:!1}),void this.startUserInfoCollection()}const a={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};this.setState({messages:[...this.state.messages,a],isLoading:!1})}async sendHumanMessage(e){if(!this.chatId||!this.supportSessionId){const e={id:`error-${Date.now()}`,text:"Chat session not initialized. Please try again.",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],isLoading:!1})}if(!this.chatService)throw new Error("Chat service not initialized");this.chatService.sendTypingIndicator("typing_stop"),this.typingTimeout&&(clearTimeout(this.typingTimeout),this.typingTimeout=null);try{this.chatService.sendMessageViaWebSocket(e.trim())||await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),this.setState({isLoading:!1})}catch(i){if(i instanceof t.ChatResolvedError||"ChatResolvedError"===i?.name||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);if(!(i.message?.includes("Chat not found")||i.message?.includes("unauthorized")||i.message?.includes("401")||i.message?.includes("404")))throw i;{this.config.debug,this.chatId=null,this.supportSessionId=null;const i=s.safeLocalStorage();i.removeItem("blockspark_chat_id"),i.removeItem("blockspark_session_id");try{const t=await this.chatService.startSupportChat(this.state.sessionId||null,null,null,null);this.chatId=t.chat_id,this.supportSessionId=t.session_id;const i=s.safeLocalStorage();return i.setItem("blockspark_chat_id",this.chatId),i.setItem("blockspark_session_id",this.supportSessionId),this.chatId&&this.supportSessionId&&await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),void this.setState({isLoading:!1})}catch(a){if(a instanceof t.ChatResolvedError||"chat_resolved"===a?.message)return void this.enterResolvedState(this.chatId);throw a}}}}switchToHumanMode(){this.chatMode="human",this.setState({chatMode:"human"}),s.safeLocalStorage().setItem("blockspark_chat_mode","HUMAN")}switchToBotMode(){this.chatMode="ai",this.setState({chatMode:"ai"}),s.safeLocalStorage().setItem("blockspark_chat_mode","BOT")}initializeWelcomePopup(){if(!1!==this.config.showWelcomePopup){const e=this.config.welcomePopupDelay||1500;setTimeout(()=>{this.state.isOpen||this.setState({showWelcomePopup:!0})},e)}}startUserInfoCollection(){this.collectingUserInfo=!0,this.userInfoStep="name",this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="";const e={id:`handoff-${Date.now()}`,text:"👤 You're being connected to a live support agent. Please wait while we transfer your conversation...",sender:"bot",timestamp:new Date},t={id:`prompt-${Date.now()}`,text:"To connect you with a human agent, I'll need some information.\n\nPlease provide your name:",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e,t]})}async handleUserInfoCollection(e){if("name"===this.userInfoStep){const t=e.trim();this.collectedUserName=t,this.userInfoStep="email";const s={id:`prompt-${Date.now()}`,text:"✅ Thank you! Now please provide your email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("email"===this.userInfoStep){const t=e.trim();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserEmail=t,this.userInfoStep="mobile";const s={id:`prompt-${Date.now()}`,text:"✅ Thank you! Now please provide your mobile number:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("mobile"===this.userInfoStep){const t=e.trim();if(!/^[\+]?[(]?[0-9]{1,4}[)]?[-\s\.]?[(]?[0-9]{1,4}[)]?[-\s\.]?[0-9]{1,9}$/.test(t)||t.length<10){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid mobile number (e.g., +1234567890):",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserMobile=t,this.collectingUserInfo=!1,this.userInfoStep=null,await this.handleHandoff(this.collectedUserName,this.collectedUserEmail,t),this.setState({inputValue:""})}}async handleHandoff(e,t,i){if(!this.chatService)throw new Error("Chat service not initialized");try{this.isConnectingToAgent=!0;const n=this.state.sessionId,o=await this.chatService.ensureChatInitialized(this.chatId,this.supportSessionId,n||null,e||null,t||null,i||null);if(!o||!o.chat_id)throw new Error("Failed to initialize chat session");const c=o.chat_id,h=o.session_id;if(c!==this.chatId){this.chatId=c,this.supportSessionId=h;const e=s.safeLocalStorage();e.setItem("blockspark_chat_id",this.chatId),e.setItem("blockspark_session_id",this.supportSessionId),this.config.debug}try{await this.chatService.requestHandoff(c,h,"Customer requested human agent",n||null,e||null,t||null,i||null),this.config.debug}catch(a){if(!(a.message?.includes("Invalid chat_id")||a.message?.includes("Chat not found")||a.message?.includes("unauthorized")||a.message?.includes("400")||a.message?.includes("401")||a.message?.includes("404")||a.message?.includes("expired")))throw a;{this.config.debug,this.chatId=null,this.supportSessionId=null;const a=s.safeLocalStorage();a.removeItem("blockspark_chat_id"),a.removeItem("blockspark_session_id");const o=await this.chatService.startSupportChat(n||null,e||null,t||null,i||null);if(!o||!o.chat_id)throw new Error("Failed to re-initialize chat session");this.chatId=o.chat_id,this.supportSessionId=o.session_id;const c=s.safeLocalStorage();c.setItem("blockspark_chat_id",this.chatId),c.setItem("blockspark_session_id",this.supportSessionId),await this.chatService.requestHandoff(this.chatId,this.supportSessionId,"Customer requested human agent",n||null,e||null,t||null,i||null),this.config.debug}}this.switchToHumanMode(),this.chatResolved=!1,this.agentAccepted=!1;const r={id:`connecting-${Date.now()}`,text:"Connecting you to a human agent...",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,r]}),c&&h&&this.chatService.connectWebSocket(c,h,e=>{this.handleWebSocketMessage(e)},e=>{this.wsConnected=e}),this.isConnectingToAgent=!1}catch(n){const e={id:`error-${Date.now()}`,text:this.config.debug?`Handoff error: ${n.message}`:"Failed to connect to agent. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]}),this.isConnectingToAgent=!1}}handleWebSocketMessage(e){switch(e.type){case"message":if(e.content&&("agent"===e.sender_type||!e.sender_type)){const t={id:e.id||`agent-${Date.now()}`,text:e.content,sender:"agent",timestamp:new Date(e.timestamp||Date.now())};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null)}break;case"typing_start":"agent"===e.sender_type&&(this.agentTyping=!0,this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=setTimeout(()=>{this.agentTyping=!1},3e3));break;case"typing_stop":"agent"===e.sender_type&&(this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null));break;case"agent_changed":if(e.to_agent){this.currentAgent={id:e.to_agent_id,name:e.to_agent};const t={id:`system-${Date.now()}`,text:e.from_agent?`Chat has been transferred from ${e.from_agent} to ${e.to_agent}`:`Chat has been transferred to ${e.to_agent}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,t]})}break;case"agent_accepted":this.agentAccepted=!0,this.isConnectingToAgent=!1;const t={id:e.id||`agent-accepted-${Date.now()}`,text:"You can chat now, the agent has accepted your request.",sender:"bot",timestamp:e.timestamp?new Date(e.timestamp):new Date};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),e.to_agent&&(this.currentAgent={name:e.to_agent,id:e.to_agent_id});break;case"chat_resolved":case"chat_ended":this.enterResolvedState(e.chat_id||null);break;case"chat_info":"active"===e.status?(this.isConnectingToAgent=!1,this.agentAccepted=!0):"resolved"!==e.status&&"ended"!==e.status||this.enterResolvedState(e.chat_id||null),e.agent_id&&(this.currentAgent={...this.currentAgent,id:e.agent_id});break;case"error":const s={id:`error-${Date.now()}`,text:e.error||"An error occurred. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,s]})}}enterResolvedState(t){this.chatResolved=!0,this.isConnectingToAgent=!1,this.agentAccepted=!1,this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null),this.chatService&&this.chatService.disconnectWebSocket(),this.chatId=null,this.supportSessionId=null;const i=s.safeLocalStorage();i.removeItem("blockspark_chat_id"),i.removeItem("blockspark_session_id");const a={id:`resolved-${Date.now()}`,text:"Thank you for contacting us!",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,a]}),setTimeout(async()=>{if(this.switchToBotMode(),this.chatResolved=!1,this.setState({messages:[],sessionId:null}),this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.config.dfProjectId&&this.config.dfAgentId&&this.state.isOpen)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}},2e3)}async loadMessageHistory(e=!1){if(this.chatService&&this.chatId&&this.supportSessionId)try{if(this.chatId&&this.supportSessionId){const t=(await this.chatService.loadMessageHistory(this.chatId,this.supportSessionId)).map(e=>({id:e.id||`history-${Date.now()}-${Math.random()}`,text:e.content,sender:"agent"===e.sender_type?"agent":"user",timestamp:new Date(e.timestamp)}));if(e){const e=new Set(this.state.messages.map(e=>e.id)),s=t.filter(t=>!e.has(t.id)),i=[...this.state.messages,...s].sort((e,t)=>e.timestamp.getTime()-t.timestamp.getTime());this.setState({messages:i})}else this.setState({messages:t})}}catch(t){if(this.config.debug){const e={id:`error-${Date.now()}`,text:`Failed to load chat history: ${t.message}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]})}}}getAdditionalState(){return{wsConnected:this.wsConnected,agentTyping:this.agentTyping,currentAgent:this.currentAgent,isConnectingToAgent:this.isConnectingToAgent,agentAccepted:this.agentAccepted,chatResolved:this.chatResolved}}destroy(){this.typingTimeout&&clearTimeout(this.typingTimeout),this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.chatService&&this.chatService.disconnectWebSocket(),this.listeners.clear()}};
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../services/dialogflowClient.cjs.js"),t=require("../services/chatService.cjs.js");exports.WidgetStateManager=class{constructor(e){if(this.listeners=new Set,this.chatMode="ai",this.chatId=null,this.supportSessionId=null,this.chatService=null,this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.wsConnected=!1,this.agentTyping=!1,this.currentAgent={name:"Agent"},this.isConnectingToAgent=!1,this.agentAccepted=!1,this.chatResolved=!1,this.historyLoaded=null,this.typingTimeout=null,this.agentTypingTimeout=null,this.config=e,this.state={isOpen:!1,showWelcomePopup:!1,messages:[],inputValue:"",isLoading:!1,error:null,sessionId:null,chatMode:"ai"},this.chatService=t.createChatService({baseUrl:this.config.backendBaseUrl||"http://localhost:8012",wsUrl:this.config.backendWsUrl||"ws://localhost:8012",debug:this.config.debug||!1}),"undefined"!=typeof window&&window.localStorage){const e=localStorage.getItem("blockspark_chat_mode");this.chatMode="HUMAN"===e?"human":"ai",this.state.chatMode=this.chatMode,this.chatId=localStorage.getItem("blockspark_chat_id"),this.supportSessionId=localStorage.getItem("blockspark_session_id")}}subscribe(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}getState(){return{...this.state}}setState(e){this.state={...this.state,...e},this.listeners.forEach(e=>e(this.getState()))}updateConfig(e){this.config={...this.config,...e}}async openChat(){if(this.setState({isOpen:!0}),this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1}),"ai"===this.state.chatMode&&!this.state.sessionId&&this.config.dfProjectId&&this.config.dfAgentId)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}}closeChat(){this.setState({isOpen:!1})}closeWelcomePopup(){this.setState({showWelcomePopup:!1})}toggleChat(){const e=!this.state.isOpen;this.setState({isOpen:e}),e&&this.state.showWelcomePopup&&this.setState({showWelcomePopup:!1})}setInputValue(e){this.setState({inputValue:e})}clearError(){this.setState({error:null})}async sendMessage(e,s=!1){if(e.trim()&&!this.state.isLoading){if(this.collectingUserInfo){const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};return this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!1,error:null}),void(await this.handleUserInfoCollection(e))}if(s)this.setState({inputValue:"",isLoading:!0,error:null});else{const t={id:`user-${Date.now()}`,text:e.trim(),sender:"user",timestamp:new Date};this.setState({messages:[...this.state.messages,t],inputValue:"",isLoading:!0,error:null})}try{"human"===this.state.chatMode?await this.sendHumanMessage(e):await this.sendAIMessage(e)}catch(i){if(i instanceof t.ChatResolvedError||"ChatResolvedError"===i?.name||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);const e={id:`error-${Date.now()}`,text:this.config.debug?`Error: ${i.message||"Failed to send message"}`:i.message?.includes("CORS")||i.message?.includes("Failed to fetch")?"Unable to connect to Dialogflow. Please check your configuration and network.":"Sorry, I'm having trouble processing your message. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e],error:i.message||"Failed to send message",isLoading:!1})}}}async sendAIMessage(t){if(!this.config.dfProjectId||!this.config.dfAgentId)throw new Error("Dialogflow configuration is missing");const s={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"};if(!this.state.sessionId){const t=await e.createDialogflowSession(s);this.setState({sessionId:t.session_id})}this.config.debug;const i=await e.sendDialogflowMessage(t,this.state.sessionId,s);if(this.config.debug,!0===i.handoff){const e={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};return this.setState({messages:[...this.state.messages,e],isLoading:!1}),void this.startUserInfoCollection()}const a={id:`bot-${Date.now()}`,text:i.response||this.config.fallbackWelcomeMessage||"No response",sender:"bot",timestamp:new Date,richContent:i.richContent};this.setState({messages:[...this.state.messages,a],isLoading:!1})}async sendHumanMessage(e){if(!this.chatId||!this.supportSessionId){const e={id:`error-${Date.now()}`,text:"Chat session not initialized. Please try again.",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],isLoading:!1})}if(!this.chatService)throw new Error("Chat service not initialized");this.chatService.sendTypingIndicator("typing_stop"),this.typingTimeout&&(clearTimeout(this.typingTimeout),this.typingTimeout=null);try{this.chatService.sendMessageViaWebSocket(e.trim())||await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),this.setState({isLoading:!1})}catch(s){if(s instanceof t.ChatResolvedError||"ChatResolvedError"===s?.name||"chat_resolved"===s?.message)return void this.enterResolvedState(this.chatId);if(!(s.message?.includes("Chat not found")||s.message?.includes("unauthorized")||s.message?.includes("401")||s.message?.includes("404")))throw s;this.config.debug,this.chatId=null,this.supportSessionId=null,"undefined"!=typeof window&&window.localStorage&&(localStorage.removeItem("blockspark_chat_id"),localStorage.removeItem("blockspark_session_id"));try{const t=await this.chatService.startSupportChat(this.state.sessionId||null,null,null,null);return this.chatId=t.chat_id,this.supportSessionId=t.session_id,"undefined"!=typeof window&&window.localStorage&&(localStorage.setItem("blockspark_chat_id",this.chatId),localStorage.setItem("blockspark_session_id",this.supportSessionId)),this.chatId&&this.supportSessionId&&await this.chatService.sendMessageToAgent(this.chatId,this.supportSessionId,e.trim()),void this.setState({isLoading:!1})}catch(i){if(i instanceof t.ChatResolvedError||"chat_resolved"===i?.message)return void this.enterResolvedState(this.chatId);throw i}}}switchToHumanMode(){this.chatMode="human",this.setState({chatMode:"human"}),"undefined"!=typeof window&&window.localStorage&&localStorage.setItem("blockspark_chat_mode","HUMAN")}switchToBotMode(){this.chatMode="ai",this.setState({chatMode:"ai"}),"undefined"!=typeof window&&window.localStorage&&localStorage.setItem("blockspark_chat_mode","BOT")}initializeWelcomePopup(){if(!1!==this.config.showWelcomePopup){const e=this.config.welcomePopupDelay||1500;setTimeout(()=>{this.state.isOpen||this.setState({showWelcomePopup:!0})},e)}}startUserInfoCollection(){this.collectingUserInfo=!0,this.userInfoStep="name",this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="";const e={id:`prompt-${Date.now()}`,text:"To connect you with a human agent, I'll need some information. Please provide your name:",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]})}async handleUserInfoCollection(e){if("name"===this.userInfoStep){const t=e.trim();this.collectedUserName=t,this.userInfoStep="email";const s={id:`prompt-${Date.now()}`,text:"Thank you! Now please provide your email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("email"===this.userInfoStep){const t=e.trim();if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t)){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid email address:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserEmail=t,this.userInfoStep="mobile";const s={id:`prompt-${Date.now()}`,text:"Thank you! Now please provide your mobile number:",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,s],inputValue:""})}if("mobile"===this.userInfoStep){const t=e.trim();if(!/^[\+]?[(]?[0-9]{1,4}[)]?[-\s\.]?[(]?[0-9]{1,4}[)]?[-\s\.]?[0-9]{1,9}$/.test(t)||t.length<10){const e={id:`prompt-${Date.now()}`,text:"Please provide a valid mobile number (e.g., +1234567890):",sender:"bot",timestamp:new Date};return void this.setState({messages:[...this.state.messages,e],inputValue:""})}this.collectedUserMobile=t,this.collectingUserInfo=!1,this.userInfoStep=null,await this.handleHandoff(this.collectedUserName,this.collectedUserEmail,t),this.setState({inputValue:""})}}async handleHandoff(e,t,s){if(!this.chatService)throw new Error("Chat service not initialized");try{this.isConnectingToAgent=!0;const a=this.state.sessionId,o=await this.chatService.ensureChatInitialized(this.chatId,this.supportSessionId,a||null,e||null,t||null,s||null);if(!o||!o.chat_id)throw new Error("Failed to initialize chat session");const n=o.chat_id,c=o.session_id;n!==this.chatId&&(this.chatId=n,this.supportSessionId=c,"undefined"!=typeof window&&window.localStorage&&(localStorage.setItem("blockspark_chat_id",this.chatId),localStorage.setItem("blockspark_session_id",this.supportSessionId)),this.config.debug);try{await this.chatService.requestHandoff(n,c,"Customer requested human agent",a||null,e||null,t||null,s||null),this.config.debug}catch(i){if(!(i.message?.includes("Invalid chat_id")||i.message?.includes("Chat not found")||i.message?.includes("unauthorized")||i.message?.includes("400")||i.message?.includes("401")||i.message?.includes("404")||i.message?.includes("expired")))throw i;{this.config.debug,this.chatId=null,this.supportSessionId=null,"undefined"!=typeof window&&window.localStorage&&(localStorage.removeItem("blockspark_chat_id"),localStorage.removeItem("blockspark_session_id"));const i=await this.chatService.startSupportChat(a||null,e||null,t||null,s||null);if(!i||!i.chat_id)throw new Error("Failed to re-initialize chat session");this.chatId=i.chat_id,this.supportSessionId=i.session_id,"undefined"!=typeof window&&window.localStorage&&(localStorage.setItem("blockspark_chat_id",this.chatId),localStorage.setItem("blockspark_session_id",this.supportSessionId)),await this.chatService.requestHandoff(this.chatId,this.supportSessionId,"Customer requested human agent",a||null,e||null,t||null,s||null),this.config.debug}}this.switchToHumanMode(),this.chatResolved=!1,this.agentAccepted=!1;const h={id:`connecting-${Date.now()}`,text:"Connecting you to a human agent...",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,h]}),n&&c&&this.chatService.connectWebSocket(n,c,e=>{this.handleWebSocketMessage(e)},e=>{this.wsConnected=e}),this.isConnectingToAgent=!1}catch(a){const e={id:`error-${Date.now()}`,text:this.config.debug?`Handoff error: ${a.message}`:"Failed to connect to agent. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]}),this.isConnectingToAgent=!1}}handleWebSocketMessage(e){switch(e.type){case"message":if(e.content&&("agent"===e.sender_type||!e.sender_type)){const t={id:e.id||`agent-${Date.now()}`,text:e.content,sender:"agent",timestamp:new Date(e.timestamp||Date.now())};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null)}break;case"typing_start":"agent"===e.sender_type&&(this.agentTyping=!0,this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=setTimeout(()=>{this.agentTyping=!1},3e3));break;case"typing_stop":"agent"===e.sender_type&&(this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null));break;case"agent_changed":if(e.to_agent){this.currentAgent={id:e.to_agent_id,name:e.to_agent};const t={id:`system-${Date.now()}`,text:e.from_agent?`Chat has been transferred from ${e.from_agent} to ${e.to_agent}`:`Chat has been transferred to ${e.to_agent}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,t]})}break;case"agent_accepted":this.agentAccepted=!0,this.isConnectingToAgent=!1;const t={id:e.id||`agent-accepted-${Date.now()}`,text:"You can chat now, the agent has accepted your request.",sender:"bot",timestamp:e.timestamp?new Date(e.timestamp):new Date};new Set(this.state.messages.map(e=>e.id)).has(t.id)||this.setState({messages:[...this.state.messages,t]}),e.to_agent&&(this.currentAgent={name:e.to_agent,id:e.to_agent_id});break;case"chat_resolved":case"chat_ended":this.enterResolvedState(e.chat_id||null);break;case"chat_info":"active"===e.status?(this.isConnectingToAgent=!1,this.agentAccepted=!0):"resolved"!==e.status&&"ended"!==e.status||this.enterResolvedState(e.chat_id||null),e.agent_id&&(this.currentAgent={...this.currentAgent,id:e.agent_id});break;case"error":const s={id:`error-${Date.now()}`,text:e.error||"An error occurred. Please try again.",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,s]})}}enterResolvedState(t){this.chatResolved=!0,this.isConnectingToAgent=!1,this.agentAccepted=!1,this.agentTyping=!1,this.agentTypingTimeout&&(clearTimeout(this.agentTypingTimeout),this.agentTypingTimeout=null),this.chatService&&this.chatService.disconnectWebSocket(),this.chatId=null,this.supportSessionId=null,"undefined"!=typeof window&&window.localStorage&&(localStorage.removeItem("blockspark_chat_id"),localStorage.removeItem("blockspark_session_id"));const s={id:`resolved-${Date.now()}`,text:"Thank you for contacting us!",sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,s]}),setTimeout(async()=>{if(this.switchToBotMode(),this.chatResolved=!1,this.setState({messages:[],sessionId:null}),this.collectingUserInfo=!1,this.userInfoStep=null,this.collectedUserName="",this.collectedUserEmail="",this.collectedUserMobile="",this.config.dfProjectId&&this.config.dfAgentId&&this.state.isOpen)try{this.setState({isLoading:!0});const t={dfProjectId:this.config.dfProjectId,dfLocation:this.config.dfLocation||"us-central1",dfAgentId:this.config.dfAgentId,serviceAccountKey:this.config.serviceAccountKey,accessToken:this.config.accessToken,languageCode:this.config.languageCode||"en"},s=await e.createDialogflowSession(t);if(this.setState({sessionId:s.session_id,isLoading:!1}),s.message){const e={id:`welcome-${Date.now()}`,text:s.message,sender:"bot",timestamp:new Date,richContent:s.richContent};this.setState({messages:[e]})}}catch(t){this.setState({isLoading:!1,error:t.message||"Failed to initialize chat"});const e={id:`fallback-${Date.now()}`,text:this.config.fallbackWelcomeMessage||"Hello! How can I help you today?",sender:"bot",timestamp:new Date};this.setState({messages:[e]})}},2e3)}async loadMessageHistory(e=!1){if(this.chatService&&this.chatId&&this.supportSessionId)try{if(this.chatId&&this.supportSessionId){const t=(await this.chatService.loadMessageHistory(this.chatId,this.supportSessionId)).map(e=>({id:e.id||`history-${Date.now()}-${Math.random()}`,text:e.content,sender:"agent"===e.sender_type?"agent":"user",timestamp:new Date(e.timestamp)}));if(e){const e=new Set(this.state.messages.map(e=>e.id)),s=t.filter(t=>!e.has(t.id)),i=[...this.state.messages,...s].sort((e,t)=>e.timestamp.getTime()-t.timestamp.getTime());this.setState({messages:i})}else this.setState({messages:t})}}catch(t){if(this.config.debug){const e={id:`error-${Date.now()}`,text:`Failed to load chat history: ${t.message}`,sender:"bot",timestamp:new Date};this.setState({messages:[...this.state.messages,e]})}}}getAdditionalState(){return{wsConnected:this.wsConnected,agentTyping:this.agentTyping,currentAgent:this.currentAgent,isConnectingToAgent:this.isConnectingToAgent,agentAccepted:this.agentAccepted,chatResolved:this.chatResolved}}destroy(){this.typingTimeout&&clearTimeout(this.typingTimeout),this.agentTypingTimeout&&clearTimeout(this.agentTypingTimeout),this.chatService&&this.chatService.disconnectWebSocket(),this.listeners.clear()}};
2
2
  //# sourceMappingURL=stateManager.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stateManager.cjs.js","sources":["../../src/core/stateManager.ts"],"sourcesContent":["/**\n * State Manager - Framework Agnostic\n * Manages widget state independently of framework\n */\n\nimport type { WidgetState, WidgetConfig, ChatMessage } from './types';\nimport {\n createDialogflowSession,\n sendDialogflowMessage,\n type DialogflowConfig,\n} from '../services/dialogflowClient';\nimport { \n createChatService, \n ChatResolvedError,\n type WebSocketMessage\n} from '../services/chatService';\nimport { safeLocalStorage } from '../utils/ssr';\n\nexport class WidgetStateManager {\n private state: WidgetState;\n private config: WidgetConfig;\n private listeners: Set<(state: WidgetState) => void> = new Set();\n private chatMode: 'ai' | 'human' = 'ai';\n private chatId: string | null = null;\n private supportSessionId: string | null = null;\n private chatService: ReturnType<typeof createChatService> | null = null;\n \n // User info collection for handoff\n private collectingUserInfo: boolean = false;\n private userInfoStep: 'name' | 'email' | 'mobile' | null = null;\n private collectedUserName: string = '';\n private collectedUserEmail: string = '';\n private collectedUserMobile: string = '';\n \n // Additional state for human support\n private wsConnected: boolean = false;\n private agentTyping: boolean = false;\n private currentAgent: { name: string; id?: string } = { name: 'Agent' };\n private isConnectingToAgent: boolean = false;\n private agentAccepted: boolean = false;\n private chatResolved: boolean = false;\n private historyLoaded: string | null = null;\n \n // Typing timeout refs (stored as class properties since we can't use refs)\n private typingTimeout: NodeJS.Timeout | null = null;\n private agentTypingTimeout: NodeJS.Timeout | null = null;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.state = {\n isOpen: false,\n showWelcomePopup: false,\n messages: [],\n inputValue: '',\n isLoading: false,\n error: null,\n sessionId: null,\n chatMode: 'ai',\n };\n \n // Initialize ChatService\n this.chatService = createChatService({\n baseUrl: this.config.backendBaseUrl || 'http://localhost:8012',\n wsUrl: this.config.backendWsUrl || 'ws://localhost:8012',\n debug: this.config.debug || false,\n });\n \n // Load chat mode and chat IDs from localStorage if available (SSR-safe)\n const storage = safeLocalStorage();\n const savedMode = storage.getItem('blockspark_chat_mode');\n if (savedMode) {\n this.chatMode = savedMode === 'HUMAN' ? 'human' : 'ai';\n this.state.chatMode = this.chatMode;\n }\n \n this.chatId = storage.getItem('blockspark_chat_id');\n this.supportSessionId = storage.getItem('blockspark_session_id');\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: (state: WidgetState) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return { ...this.state };\n }\n\n /**\n * Update state and notify listeners\n */\n private setState(updates: Partial<WidgetState>): void {\n this.state = { ...this.state, ...updates };\n this.listeners.forEach(listener => listener(this.getState()));\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<WidgetConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Open chat\n */\n async openChat(): Promise<void> {\n this.setState({ isOpen: true });\n if (this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n \n // Initialize Dialogflow session when chat opens (if in AI mode and no session exists)\n if (this.state.chatMode === 'ai' && !this.state.sessionId && this.config.dfProjectId && this.config.dfAgentId) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error initializing Dialogflow session:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }\n\n /**\n * Close chat\n */\n closeChat(): void {\n this.setState({ isOpen: false });\n }\n\n /**\n * Close welcome popup\n */\n closeWelcomePopup(): void {\n this.setState({ showWelcomePopup: false });\n }\n\n /**\n * Toggle chat\n */\n toggleChat(): void {\n const willBeOpen = !this.state.isOpen;\n this.setState({ isOpen: willBeOpen });\n if (willBeOpen && this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n }\n\n /**\n * Set input value\n */\n setInputValue(value: string): void {\n this.setState({ inputValue: value });\n }\n\n /**\n * Clear error\n */\n clearError(): void {\n this.setState({ error: null });\n }\n\n /**\n * Send message\n */\n async sendMessage(text: string, skipUserMessage: boolean = false): Promise<void> {\n if (!text.trim() || this.state.isLoading) {\n return;\n }\n\n // Handle user info collection for handoff\n if (this.collectingUserInfo) {\n // Add user message first so it appears in chat\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: false,\n error: null,\n });\n \n // Then handle the info collection\n await this.handleUserInfoCollection(text);\n return;\n }\n\n // Add user message unless skipped (e.g., when chip button already added it)\n if (!skipUserMessage) {\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: true,\n error: null,\n });\n } else {\n this.setState({\n inputValue: '',\n isLoading: true,\n error: null,\n });\n }\n\n try {\n if (this.state.chatMode === 'human') {\n // Human support mode\n await this.sendHumanMessage(text);\n } else {\n // AI mode (Dialogflow)\n await this.sendAIMessage(text);\n }\n } catch (error: any) {\n console.error('Error sending message:', error);\n \n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n \n // Add error message to chat\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug \n ? `Error: ${error.message || 'Failed to send message'}`\n : error.message?.includes('CORS') || error.message?.includes('Failed to fetch')\n ? 'Unable to connect to Dialogflow. Please check your configuration and network.'\n : 'Sorry, I\\'m having trouble processing your message. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, errorMessage],\n error: error.message || 'Failed to send message',\n isLoading: false,\n });\n }\n }\n\n /**\n * Send message to Dialogflow\n */\n private async sendAIMessage(text: string): Promise<void> {\n if (!this.config.dfProjectId || !this.config.dfAgentId) {\n throw new Error('Dialogflow configuration is missing');\n }\n\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId!,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId!,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n\n // Create session if needed\n if (!this.state.sessionId) {\n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ sessionId: session.session_id });\n }\n\n // Send message (correct parameter order: message, sessionId, config)\n if (this.config.debug) {\n console.log('Sending message to Dialogflow:', {\n message: text,\n sessionId: this.state.sessionId,\n hasConfig: !!dialogflowConfig,\n });\n }\n \n const response = await sendDialogflowMessage(\n text,\n this.state.sessionId!,\n dialogflowConfig\n );\n\n if (this.config.debug) {\n console.log('Dialogflow response:', {\n response: response.response,\n hasRichContent: !!response.richContent,\n richContent: response.richContent,\n });\n }\n\n // Check for handoff\n if (response.handoff === true) {\n // Add bot response first\n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n \n // Start collecting user info for handoff\n this.startUserInfoCollection();\n return;\n }\n \n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n }\n\n /**\n * Send message to human support\n */\n private async sendHumanMessage(text: string): Promise<void> {\n if (!this.chatId || !this.supportSessionId) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: 'Chat session not initialized. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n isLoading: false,\n });\n return;\n }\n\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n // Send typing_stop before sending message\n this.chatService.sendTypingIndicator('typing_stop');\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n\n try {\n // Try WebSocket first, fallback to REST API\n const sentViaWs = this.chatService.sendMessageViaWebSocket(text.trim());\n \n if (!sentViaWs) {\n // Fallback to REST API\n await this.chatService.sendMessageToAgent(this.chatId, this.supportSessionId, text.trim());\n }\n \n this.setState({ isLoading: false });\n } catch (error: any) {\n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n\n // Handle 401/404 - clear chat_id and reinitialize\n if (error.message?.includes('Chat not found') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('401') ||\n error.message?.includes('404')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired. Re-initializing...');\n }\n \n // Clear chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Try to reinitialize chat\n try {\n const newSession = await this.chatService.startSupportChat(\n this.state.sessionId || null,\n null,\n null,\n null\n );\n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage1 = safeLocalStorage();\n storage1.setItem('blockspark_chat_id', this.chatId);\n storage1.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry sending message\n if (this.chatId && this.supportSessionId) {\n await this.chatService.sendMessageToAgent(\n this.chatId,\n this.supportSessionId,\n text.trim()\n );\n }\n this.setState({ isLoading: false });\n return;\n } catch (retryError: any) {\n if (retryError instanceof ChatResolvedError || retryError?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n throw retryError;\n }\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Switch to human mode\n */\n switchToHumanMode(): void {\n this.chatMode = 'human';\n this.setState({ chatMode: 'human' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'HUMAN');\n }\n\n /**\n * Switch to AI mode\n */\n switchToBotMode(): void {\n this.chatMode = 'ai';\n this.setState({ chatMode: 'ai' });\n safeLocalStorage().setItem('blockspark_chat_mode', 'BOT');\n }\n\n /**\n * Initialize welcome popup\n */\n initializeWelcomePopup(): void {\n if (this.config.showWelcomePopup !== false) {\n const delay = this.config.welcomePopupDelay || 1500;\n setTimeout(() => {\n if (!this.state.isOpen) {\n this.setState({ showWelcomePopup: true });\n }\n }, delay);\n }\n }\n\n /**\n * Start user info collection for handoff\n */\n private startUserInfoCollection(): void {\n this.collectingUserInfo = true;\n this.userInfoStep = 'name';\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Add initial handoff message with better formatting\n const handoffMessage: ChatMessage = {\n id: `handoff-${Date.now()}`,\n text: '👤 You\\'re being connected to a live support agent. Please wait while we transfer your conversation...',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n // Ask for name\n const namePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'To connect you with a human agent, I\\'ll need some information.\\n\\nPlease provide your name:',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, handoffMessage, namePrompt],\n });\n }\n\n /**\n * Handle user info collection\n */\n private async handleUserInfoCollection(text: string): Promise<void> {\n if (this.userInfoStep === 'name') {\n // Save name and ask for email\n const name = text.trim();\n this.collectedUserName = name;\n this.userInfoStep = 'email';\n \n // Ask for email\n const emailPrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: '✅ Thank you! Now please provide your email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, emailPrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'email') {\n // Validate email format\n const email = text.trim();\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n \n if (!emailRegex.test(email)) {\n // Invalid email, ask again\n const invalidEmailMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidEmailMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save email and ask for mobile\n this.collectedUserEmail = email;\n this.userInfoStep = 'mobile';\n \n // Ask for mobile\n const mobilePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: '✅ Thank you! Now please provide your mobile number:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, mobilePrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'mobile') {\n // Validate mobile format\n const mobile = text.trim();\n const mobileRegex = /^[\\+]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[0-9]{1,9}$/;\n \n if (!mobileRegex.test(mobile) || mobile.length < 10) {\n // Invalid mobile, ask again\n const invalidMobileMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid mobile number (e.g., +1234567890):',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidMobileMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save mobile and proceed with handoff\n this.collectedUserMobile = mobile;\n \n // Reset collection state\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n \n // Proceed with handoff using collected info\n await this.handleHandoff(this.collectedUserName, this.collectedUserEmail, mobile);\n this.setState({ inputValue: '' });\n }\n }\n\n /**\n * Handle handoff from Dialogflow to human support\n */\n async handleHandoff(customerName?: string, customerEmail?: string, customerMobile?: string): Promise<void> {\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n try {\n this.isConnectingToAgent = true;\n \n // Get Dialogflow session ID if available\n const dialogflowSessionId = this.state.sessionId;\n \n // STEP 1: Ensure chat is initialized\n const session = await this.chatService.ensureChatInitialized(\n this.chatId,\n this.supportSessionId,\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!session || !session.chat_id) {\n throw new Error('Failed to initialize chat session');\n }\n \n const currentChatId = session.chat_id;\n const currentSupportSessionId = session.session_id;\n \n // Update state if chat was newly initialized\n if (currentChatId !== this.chatId) {\n this.chatId = currentChatId;\n this.supportSessionId = currentSupportSessionId;\n const storage = safeLocalStorage();\n storage.setItem('blockspark_chat_id', this.chatId);\n storage.setItem('blockspark_session_id', this.supportSessionId);\n if (this.config.debug) {\n console.log('✅ Chat initialized:', { chatId: currentChatId, sessionId: currentSupportSessionId });\n }\n }\n\n // STEP 2: Request handoff\n try {\n await this.chatService.requestHandoff(\n currentChatId,\n currentSupportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully');\n }\n } catch (handoffError: any) {\n // Handle 401/404 or \"chat not found\" - clear chat_id and retry\n if (handoffError.message?.includes('Invalid chat_id') || \n handoffError.message?.includes('Chat not found') ||\n handoffError.message?.includes('unauthorized') ||\n handoffError.message?.includes('400') ||\n handoffError.message?.includes('401') ||\n handoffError.message?.includes('404') ||\n handoffError.message?.includes('expired')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired or not found. Re-initializing chat...');\n }\n \n // Clear old chat_id\n this.chatId = null;\n this.supportSessionId = null;\n const storage2 = safeLocalStorage();\n storage2.removeItem('blockspark_chat_id');\n storage2.removeItem('blockspark_session_id');\n \n // Create new chat session\n const newSession = await this.chatService.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!newSession || !newSession.chat_id) {\n throw new Error('Failed to re-initialize chat session');\n }\n \n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n const storage4 = safeLocalStorage();\n storage4.setItem('blockspark_chat_id', this.chatId);\n storage4.setItem('blockspark_session_id', this.supportSessionId);\n \n // Retry handoff with new chat_id\n await this.chatService.requestHandoff(\n this.chatId,\n this.supportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully after retry');\n }\n } else {\n throw handoffError;\n }\n }\n\n // Switch to human mode\n this.switchToHumanMode();\n this.chatResolved = false;\n this.agentAccepted = false;\n\n // Add connecting message\n const connectingMessage: ChatMessage = {\n id: `connecting-${Date.now()}`,\n text: 'Connecting you to a human agent...',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, connectingMessage],\n });\n\n // Connect WebSocket with handlers\n if (currentChatId && currentSupportSessionId) {\n this.chatService.connectWebSocket(\n currentChatId,\n currentSupportSessionId,\n (message: WebSocketMessage) => {\n this.handleWebSocketMessage(message);\n },\n (connected: boolean) => {\n this.wsConnected = connected;\n }\n );\n }\n \n this.isConnectingToAgent = false;\n } catch (error: any) {\n console.error('Error handling handoff:', error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug\n ? `Handoff error: ${error.message}`\n : 'Failed to connect to agent. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n this.isConnectingToAgent = false;\n }\n }\n\n /**\n * Handle WebSocket messages\n */\n private handleWebSocketMessage(message: WebSocketMessage): void {\n switch (message.type) {\n case 'message':\n if (message.content) {\n // Only display messages from agent\n if (message.sender_type === 'agent' || !message.sender_type) {\n const agentMessage: ChatMessage = {\n id: message.id || `agent-${Date.now()}`,\n text: message.content,\n sender: 'agent',\n timestamp: new Date(message.timestamp || Date.now()),\n };\n \n // Avoid duplicate messages\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(agentMessage.id)) {\n this.setState({\n messages: [...this.state.messages, agentMessage],\n });\n }\n \n // Hide typing indicator when message received\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n }\n break;\n\n case 'typing_start':\n if (message.sender_type === 'agent') {\n this.agentTyping = true;\n // Auto-hide after 3 seconds if no message received\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n this.agentTypingTimeout = setTimeout(() => {\n this.agentTyping = false;\n }, 3000);\n }\n break;\n\n case 'typing_stop':\n if (message.sender_type === 'agent') {\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n break;\n\n case 'agent_changed':\n if (message.to_agent) {\n this.currentAgent = {\n id: message.to_agent_id,\n name: message.to_agent,\n };\n\n // Add system message to chat\n const systemMessage: ChatMessage = {\n id: `system-${Date.now()}`,\n text: message.from_agent\n ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}`\n : `Chat has been transferred to ${message.to_agent}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, systemMessage],\n });\n }\n break;\n\n case 'agent_accepted':\n this.agentAccepted = true;\n this.isConnectingToAgent = false;\n const acceptedMessage: ChatMessage = {\n id: message.id || `agent-accepted-${Date.now()}`,\n text: 'You can chat now, the agent has accepted your request.',\n sender: 'bot',\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(acceptedMessage.id)) {\n this.setState({\n messages: [...this.state.messages, acceptedMessage],\n });\n }\n if (message.to_agent) {\n this.currentAgent = {\n name: message.to_agent,\n id: message.to_agent_id,\n };\n }\n break;\n\n case 'chat_resolved':\n case 'chat_ended':\n this.enterResolvedState(message.chat_id || null);\n break;\n\n case 'chat_info':\n if (message.status === 'active') {\n this.isConnectingToAgent = false;\n this.agentAccepted = true;\n } else if (message.status === 'resolved' || message.status === 'ended') {\n this.enterResolvedState(message.chat_id || null);\n }\n if (message.agent_id) {\n this.currentAgent = {\n ...this.currentAgent,\n id: message.agent_id,\n };\n }\n break;\n\n case 'error':\n console.error('WebSocket error:', message.error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: message.error || 'An error occurred. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n break;\n }\n }\n\n /**\n * Enter resolved state\n */\n private enterResolvedState(resolvedChatId?: string | null): void {\n this.chatResolved = true;\n this.isConnectingToAgent = false;\n this.agentAccepted = false;\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n\n // Stop WS + prevent any reuse of the old chat_id\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.chatId = null;\n this.supportSessionId = null;\n const storage = safeLocalStorage();\n storage.removeItem('blockspark_chat_id');\n storage.removeItem('blockspark_session_id');\n \n // Add thank you message before reset\n const thankYouMessage: ChatMessage = {\n id: `resolved-${Date.now()}`,\n text: 'Thank you for contacting us!',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, thankYouMessage],\n });\n \n // Automatically reset to BOT mode after showing thank you message\n setTimeout(async () => {\n this.switchToBotMode();\n this.chatResolved = false;\n this.setState({\n messages: [],\n sessionId: null, // Clear session ID to force recreation\n });\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Recreate Dialogflow session to start fresh\n if (this.config.dfProjectId && this.config.dfAgentId && this.state.isOpen) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error recreating Dialogflow session after handoff:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }, 2000);\n }\n\n /**\n * Load message history\n */\n async loadMessageHistory(preserveExisting: boolean = false): Promise<void> {\n if (!this.chatService || !this.chatId || !this.supportSessionId) {\n return;\n }\n\n try {\n if (this.chatId && this.supportSessionId) {\n const history = await this.chatService.loadMessageHistory(this.chatId, this.supportSessionId);\n \n const historyMessages: ChatMessage[] = history.map((msg: any) => ({\n id: msg.id || `history-${Date.now()}-${Math.random()}`,\n text: msg.content,\n sender: msg.sender_type === 'agent' ? 'agent' : 'user',\n timestamp: new Date(msg.timestamp),\n }));\n\n if (preserveExisting) {\n // Merge with existing messages, avoiding duplicates\n const existingIds = new Set(this.state.messages.map(m => m.id));\n const newMessages = historyMessages.filter(m => !existingIds.has(m.id));\n \n // Combine existing messages with new history messages\n // Sort by timestamp to maintain chronological order\n const combined = [...this.state.messages, ...newMessages].sort((a, b) => \n a.timestamp.getTime() - b.timestamp.getTime()\n );\n \n this.setState({\n messages: combined,\n });\n } else {\n // Replace all messages\n this.setState({\n messages: historyMessages,\n });\n }\n }\n } catch (error: any) {\n console.error('Error loading message history:', error);\n if (this.config.debug) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: `Failed to load chat history: ${error.message}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n }\n }\n }\n\n /**\n * Get additional state for UI (not in WidgetState but needed by components)\n */\n getAdditionalState() {\n return {\n wsConnected: this.wsConnected,\n agentTyping: this.agentTyping,\n currentAgent: this.currentAgent,\n isConnectingToAgent: this.isConnectingToAgent,\n agentAccepted: this.agentAccepted,\n chatResolved: this.chatResolved,\n };\n }\n\n /**\n * Cleanup\n */\n destroy(): void {\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n }\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.listeners.clear();\n }\n}\n"],"names":["constructor","config","this","listeners","Set","chatMode","chatId","supportSessionId","chatService","collectingUserInfo","userInfoStep","collectedUserName","collectedUserEmail","collectedUserMobile","wsConnected","agentTyping","currentAgent","name","isConnectingToAgent","agentAccepted","chatResolved","historyLoaded","typingTimeout","agentTypingTimeout","state","isOpen","showWelcomePopup","messages","inputValue","isLoading","error","sessionId","createChatService","baseUrl","backendBaseUrl","wsUrl","backendWsUrl","debug","storage","safeLocalStorage","savedMode","getItem","subscribe","listener","add","delete","getState","setState","updates","forEach","updateConfig","openChat","dfProjectId","dfAgentId","dialogflowConfig","dfLocation","serviceAccountKey","accessToken","languageCode","session","createDialogflowSession","session_id","message","welcomeMessage","id","Date","now","text","sender","timestamp","richContent","fallbackMessage","fallbackWelcomeMessage","closeChat","closeWelcomePopup","toggleChat","willBeOpen","setInputValue","value","clearError","sendMessage","skipUserMessage","trim","userMessage","handleUserInfoCollection","sendHumanMessage","sendAIMessage","ChatResolvedError","enterResolvedState","errorMessage","includes","Error","response","sendDialogflowMessage","handoff","botMessage","startUserInfoCollection","sendTypingIndicator","clearTimeout","sendMessageViaWebSocket","sendMessageToAgent","removeItem","newSession","startSupportChat","chat_id","storage1","setItem","retryError","switchToHumanMode","switchToBotMode","initializeWelcomePopup","delay","welcomePopupDelay","setTimeout","handoffMessage","namePrompt","emailPrompt","email","test","invalidEmailMessage","mobilePrompt","mobile","length","invalidMobileMessage","handleHandoff","customerName","customerEmail","customerMobile","dialogflowSessionId","ensureChatInitialized","currentChatId","currentSupportSessionId","requestHandoff","handoffError","storage2","storage4","connectingMessage","connectWebSocket","handleWebSocketMessage","connected","type","content","sender_type","agentMessage","map","m","has","to_agent","to_agent_id","systemMessage","from_agent","acceptedMessage","status","agent_id","resolvedChatId","disconnectWebSocket","thankYouMessage","async","loadMessageHistory","preserveExisting","historyMessages","msg","Math","random","existingIds","newMessages","filter","combined","sort","a","b","getTime","getAdditionalState","destroy","clear"],"mappings":"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"}
1
+ {"version":3,"file":"stateManager.cjs.js","sources":["../../src/core/stateManager.ts"],"sourcesContent":["/**\n * State Manager - Framework Agnostic\n * Manages widget state independently of framework\n */\n\nimport type { WidgetState, WidgetConfig, ChatMessage } from './types';\nimport {\n createDialogflowSession,\n sendDialogflowMessage,\n type DialogflowConfig,\n} from '../services/dialogflowClient';\nimport { \n createChatService, \n ChatResolvedError,\n type WebSocketMessage\n} from '../services/chatService';\n\nexport class WidgetStateManager {\n private state: WidgetState;\n private config: WidgetConfig;\n private listeners: Set<(state: WidgetState) => void> = new Set();\n private chatMode: 'ai' | 'human' = 'ai';\n private chatId: string | null = null;\n private supportSessionId: string | null = null;\n private chatService: ReturnType<typeof createChatService> | null = null;\n \n // User info collection for handoff\n private collectingUserInfo: boolean = false;\n private userInfoStep: 'name' | 'email' | 'mobile' | null = null;\n private collectedUserName: string = '';\n private collectedUserEmail: string = '';\n private collectedUserMobile: string = '';\n \n // Additional state for human support\n private wsConnected: boolean = false;\n private agentTyping: boolean = false;\n private currentAgent: { name: string; id?: string } = { name: 'Agent' };\n private isConnectingToAgent: boolean = false;\n private agentAccepted: boolean = false;\n private chatResolved: boolean = false;\n private historyLoaded: string | null = null;\n \n // Typing timeout refs (stored as class properties since we can't use refs)\n private typingTimeout: NodeJS.Timeout | null = null;\n private agentTypingTimeout: NodeJS.Timeout | null = null;\n\n constructor(config: WidgetConfig) {\n this.config = config;\n this.state = {\n isOpen: false,\n showWelcomePopup: false,\n messages: [],\n inputValue: '',\n isLoading: false,\n error: null,\n sessionId: null,\n chatMode: 'ai',\n };\n \n // Initialize ChatService\n this.chatService = createChatService({\n baseUrl: this.config.backendBaseUrl || 'http://localhost:8012',\n wsUrl: this.config.backendWsUrl || 'ws://localhost:8012',\n debug: this.config.debug || false,\n });\n \n // Load chat mode and chat IDs from localStorage if available\n if (typeof window !== 'undefined' && window.localStorage) {\n const savedMode = localStorage.getItem('blockspark_chat_mode');\n this.chatMode = savedMode === 'HUMAN' ? 'human' : 'ai';\n this.state.chatMode = this.chatMode;\n \n this.chatId = localStorage.getItem('blockspark_chat_id');\n this.supportSessionId = localStorage.getItem('blockspark_session_id');\n }\n }\n\n /**\n * Subscribe to state changes\n */\n subscribe(listener: (state: WidgetState) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /**\n * Get current state\n */\n getState(): WidgetState {\n return { ...this.state };\n }\n\n /**\n * Update state and notify listeners\n */\n private setState(updates: Partial<WidgetState>): void {\n this.state = { ...this.state, ...updates };\n this.listeners.forEach(listener => listener(this.getState()));\n }\n\n /**\n * Update configuration\n */\n updateConfig(config: Partial<WidgetConfig>): void {\n this.config = { ...this.config, ...config };\n }\n\n /**\n * Open chat\n */\n async openChat(): Promise<void> {\n this.setState({ isOpen: true });\n if (this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n \n // Initialize Dialogflow session when chat opens (if in AI mode and no session exists)\n if (this.state.chatMode === 'ai' && !this.state.sessionId && this.config.dfProjectId && this.config.dfAgentId) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error initializing Dialogflow session:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }\n\n /**\n * Close chat\n */\n closeChat(): void {\n this.setState({ isOpen: false });\n }\n\n /**\n * Close welcome popup\n */\n closeWelcomePopup(): void {\n this.setState({ showWelcomePopup: false });\n }\n\n /**\n * Toggle chat\n */\n toggleChat(): void {\n const willBeOpen = !this.state.isOpen;\n this.setState({ isOpen: willBeOpen });\n if (willBeOpen && this.state.showWelcomePopup) {\n this.setState({ showWelcomePopup: false });\n }\n }\n\n /**\n * Set input value\n */\n setInputValue(value: string): void {\n this.setState({ inputValue: value });\n }\n\n /**\n * Clear error\n */\n clearError(): void {\n this.setState({ error: null });\n }\n\n /**\n * Send message\n */\n async sendMessage(text: string, skipUserMessage: boolean = false): Promise<void> {\n if (!text.trim() || this.state.isLoading) {\n return;\n }\n\n // Handle user info collection for handoff\n if (this.collectingUserInfo) {\n // Add user message first so it appears in chat\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: false,\n error: null,\n });\n \n // Then handle the info collection\n await this.handleUserInfoCollection(text);\n return;\n }\n\n // Add user message unless skipped (e.g., when chip button already added it)\n if (!skipUserMessage) {\n const userMessage: ChatMessage = {\n id: `user-${Date.now()}`,\n text: text.trim(),\n sender: 'user',\n timestamp: new Date(),\n };\n\n this.setState({\n messages: [...this.state.messages, userMessage],\n inputValue: '',\n isLoading: true,\n error: null,\n });\n } else {\n this.setState({\n inputValue: '',\n isLoading: true,\n error: null,\n });\n }\n\n try {\n if (this.state.chatMode === 'human') {\n // Human support mode\n await this.sendHumanMessage(text);\n } else {\n // AI mode (Dialogflow)\n await this.sendAIMessage(text);\n }\n } catch (error: any) {\n console.error('Error sending message:', error);\n \n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n \n // Add error message to chat\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug \n ? `Error: ${error.message || 'Failed to send message'}`\n : error.message?.includes('CORS') || error.message?.includes('Failed to fetch')\n ? 'Unable to connect to Dialogflow. Please check your configuration and network.'\n : 'Sorry, I\\'m having trouble processing your message. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n \n this.setState({\n messages: [...this.state.messages, errorMessage],\n error: error.message || 'Failed to send message',\n isLoading: false,\n });\n }\n }\n\n /**\n * Send message to Dialogflow\n */\n private async sendAIMessage(text: string): Promise<void> {\n if (!this.config.dfProjectId || !this.config.dfAgentId) {\n throw new Error('Dialogflow configuration is missing');\n }\n\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId!,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId!,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n\n // Create session if needed\n if (!this.state.sessionId) {\n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ sessionId: session.session_id });\n }\n\n // Send message (correct parameter order: message, sessionId, config)\n if (this.config.debug) {\n console.log('Sending message to Dialogflow:', {\n message: text,\n sessionId: this.state.sessionId,\n hasConfig: !!dialogflowConfig,\n });\n }\n \n const response = await sendDialogflowMessage(\n text,\n this.state.sessionId!,\n dialogflowConfig\n );\n\n if (this.config.debug) {\n console.log('Dialogflow response:', {\n response: response.response,\n hasRichContent: !!response.richContent,\n richContent: response.richContent,\n });\n }\n\n // Check for handoff\n if (response.handoff === true) {\n // Add bot response first\n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n \n // Start collecting user info for handoff\n this.startUserInfoCollection();\n return;\n }\n \n const botMessage: ChatMessage = {\n id: `bot-${Date.now()}`,\n text: response.response || this.config.fallbackWelcomeMessage || 'No response',\n sender: 'bot',\n timestamp: new Date(),\n richContent: response.richContent,\n };\n\n this.setState({\n messages: [...this.state.messages, botMessage],\n isLoading: false,\n });\n }\n\n /**\n * Send message to human support\n */\n private async sendHumanMessage(text: string): Promise<void> {\n if (!this.chatId || !this.supportSessionId) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: 'Chat session not initialized. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n isLoading: false,\n });\n return;\n }\n\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n // Send typing_stop before sending message\n this.chatService.sendTypingIndicator('typing_stop');\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n this.typingTimeout = null;\n }\n\n try {\n // Try WebSocket first, fallback to REST API\n const sentViaWs = this.chatService.sendMessageViaWebSocket(text.trim());\n \n if (!sentViaWs) {\n // Fallback to REST API\n await this.chatService.sendMessageToAgent(this.chatId, this.supportSessionId, text.trim());\n }\n \n this.setState({ isLoading: false });\n } catch (error: any) {\n // chat_resolved is a normal terminal condition, not an error\n if (error instanceof ChatResolvedError || error?.name === 'ChatResolvedError' || error?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n\n // Handle 401/404 - clear chat_id and reinitialize\n if (error.message?.includes('Chat not found') ||\n error.message?.includes('unauthorized') ||\n error.message?.includes('401') ||\n error.message?.includes('404')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired. Re-initializing...');\n }\n \n // Clear chat_id\n this.chatId = null;\n this.supportSessionId = null;\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.removeItem('blockspark_chat_id');\n localStorage.removeItem('blockspark_session_id');\n }\n \n // Try to reinitialize chat\n try {\n const newSession = await this.chatService.startSupportChat(\n this.state.sessionId || null,\n null,\n null,\n null\n );\n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.setItem('blockspark_chat_id', this.chatId);\n localStorage.setItem('blockspark_session_id', this.supportSessionId);\n }\n \n // Retry sending message\n if (this.chatId && this.supportSessionId) {\n await this.chatService.sendMessageToAgent(\n this.chatId,\n this.supportSessionId,\n text.trim()\n );\n }\n this.setState({ isLoading: false });\n return;\n } catch (retryError: any) {\n if (retryError instanceof ChatResolvedError || retryError?.message === 'chat_resolved') {\n this.enterResolvedState(this.chatId);\n return;\n }\n throw retryError;\n }\n } else {\n throw error;\n }\n }\n }\n\n /**\n * Switch to human mode\n */\n switchToHumanMode(): void {\n this.chatMode = 'human';\n this.setState({ chatMode: 'human' });\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.setItem('blockspark_chat_mode', 'HUMAN');\n }\n }\n\n /**\n * Switch to AI mode\n */\n switchToBotMode(): void {\n this.chatMode = 'ai';\n this.setState({ chatMode: 'ai' });\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.setItem('blockspark_chat_mode', 'BOT');\n }\n }\n\n /**\n * Initialize welcome popup\n */\n initializeWelcomePopup(): void {\n if (this.config.showWelcomePopup !== false) {\n const delay = this.config.welcomePopupDelay || 1500;\n setTimeout(() => {\n if (!this.state.isOpen) {\n this.setState({ showWelcomePopup: true });\n }\n }, delay);\n }\n }\n\n /**\n * Start user info collection for handoff\n */\n private startUserInfoCollection(): void {\n this.collectingUserInfo = true;\n this.userInfoStep = 'name';\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Ask for name\n const namePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'To connect you with a human agent, I\\'ll need some information. Please provide your name:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, namePrompt],\n });\n }\n\n /**\n * Handle user info collection\n */\n private async handleUserInfoCollection(text: string): Promise<void> {\n if (this.userInfoStep === 'name') {\n // Save name and ask for email\n const name = text.trim();\n this.collectedUserName = name;\n this.userInfoStep = 'email';\n \n // Ask for email\n const emailPrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Thank you! Now please provide your email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, emailPrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'email') {\n // Validate email format\n const email = text.trim();\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n \n if (!emailRegex.test(email)) {\n // Invalid email, ask again\n const invalidEmailMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid email address:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidEmailMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save email and ask for mobile\n this.collectedUserEmail = email;\n this.userInfoStep = 'mobile';\n \n // Ask for mobile\n const mobilePrompt: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Thank you! Now please provide your mobile number:',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, mobilePrompt],\n inputValue: '',\n });\n return;\n } else if (this.userInfoStep === 'mobile') {\n // Validate mobile format\n const mobile = text.trim();\n const mobileRegex = /^[\\+]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[(]?[0-9]{1,4}[)]?[-\\s\\.]?[0-9]{1,9}$/;\n \n if (!mobileRegex.test(mobile) || mobile.length < 10) {\n // Invalid mobile, ask again\n const invalidMobileMessage: ChatMessage = {\n id: `prompt-${Date.now()}`,\n text: 'Please provide a valid mobile number (e.g., +1234567890):',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, invalidMobileMessage],\n inputValue: '',\n });\n return;\n }\n \n // Save mobile and proceed with handoff\n this.collectedUserMobile = mobile;\n \n // Reset collection state\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n \n // Proceed with handoff using collected info\n await this.handleHandoff(this.collectedUserName, this.collectedUserEmail, mobile);\n this.setState({ inputValue: '' });\n }\n }\n\n /**\n * Handle handoff from Dialogflow to human support\n */\n async handleHandoff(customerName?: string, customerEmail?: string, customerMobile?: string): Promise<void> {\n if (!this.chatService) {\n throw new Error('Chat service not initialized');\n }\n\n try {\n this.isConnectingToAgent = true;\n \n // Get Dialogflow session ID if available\n const dialogflowSessionId = this.state.sessionId;\n \n // STEP 1: Ensure chat is initialized\n const session = await this.chatService.ensureChatInitialized(\n this.chatId,\n this.supportSessionId,\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!session || !session.chat_id) {\n throw new Error('Failed to initialize chat session');\n }\n \n const currentChatId = session.chat_id;\n const currentSupportSessionId = session.session_id;\n \n // Update state if chat was newly initialized\n if (currentChatId !== this.chatId) {\n this.chatId = currentChatId;\n this.supportSessionId = currentSupportSessionId;\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.setItem('blockspark_chat_id', this.chatId);\n localStorage.setItem('blockspark_session_id', this.supportSessionId);\n }\n if (this.config.debug) {\n console.log('✅ Chat initialized:', { chatId: currentChatId, sessionId: currentSupportSessionId });\n }\n }\n\n // STEP 2: Request handoff\n try {\n await this.chatService.requestHandoff(\n currentChatId,\n currentSupportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully');\n }\n } catch (handoffError: any) {\n // Handle 401/404 or \"chat not found\" - clear chat_id and retry\n if (handoffError.message?.includes('Invalid chat_id') || \n handoffError.message?.includes('Chat not found') ||\n handoffError.message?.includes('unauthorized') ||\n handoffError.message?.includes('400') ||\n handoffError.message?.includes('401') ||\n handoffError.message?.includes('404') ||\n handoffError.message?.includes('expired')) {\n if (this.config.debug) {\n console.log('⚠️ Chat expired or not found. Re-initializing chat...');\n }\n \n // Clear old chat_id\n this.chatId = null;\n this.supportSessionId = null;\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.removeItem('blockspark_chat_id');\n localStorage.removeItem('blockspark_session_id');\n }\n \n // Create new chat session\n const newSession = await this.chatService.startSupportChat(\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (!newSession || !newSession.chat_id) {\n throw new Error('Failed to re-initialize chat session');\n }\n \n this.chatId = newSession.chat_id;\n this.supportSessionId = newSession.session_id;\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.setItem('blockspark_chat_id', this.chatId);\n localStorage.setItem('blockspark_session_id', this.supportSessionId);\n }\n \n // Retry handoff with new chat_id\n await this.chatService.requestHandoff(\n this.chatId,\n this.supportSessionId,\n 'Customer requested human agent',\n dialogflowSessionId || null,\n customerName || null,\n customerEmail || null,\n customerMobile || null\n );\n \n if (this.config.debug) {\n console.log('✅ Handoff requested successfully after retry');\n }\n } else {\n throw handoffError;\n }\n }\n\n // Switch to human mode\n this.switchToHumanMode();\n this.chatResolved = false;\n this.agentAccepted = false;\n\n // Add connecting message\n const connectingMessage: ChatMessage = {\n id: `connecting-${Date.now()}`,\n text: 'Connecting you to a human agent...',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, connectingMessage],\n });\n\n // Connect WebSocket with handlers\n if (currentChatId && currentSupportSessionId) {\n this.chatService.connectWebSocket(\n currentChatId,\n currentSupportSessionId,\n (message: WebSocketMessage) => {\n this.handleWebSocketMessage(message);\n },\n (connected: boolean) => {\n this.wsConnected = connected;\n }\n );\n }\n \n this.isConnectingToAgent = false;\n } catch (error: any) {\n console.error('Error handling handoff:', error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: this.config.debug\n ? `Handoff error: ${error.message}`\n : 'Failed to connect to agent. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n this.isConnectingToAgent = false;\n }\n }\n\n /**\n * Handle WebSocket messages\n */\n private handleWebSocketMessage(message: WebSocketMessage): void {\n switch (message.type) {\n case 'message':\n if (message.content) {\n // Only display messages from agent\n if (message.sender_type === 'agent' || !message.sender_type) {\n const agentMessage: ChatMessage = {\n id: message.id || `agent-${Date.now()}`,\n text: message.content,\n sender: 'agent',\n timestamp: new Date(message.timestamp || Date.now()),\n };\n \n // Avoid duplicate messages\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(agentMessage.id)) {\n this.setState({\n messages: [...this.state.messages, agentMessage],\n });\n }\n \n // Hide typing indicator when message received\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n }\n break;\n\n case 'typing_start':\n if (message.sender_type === 'agent') {\n this.agentTyping = true;\n // Auto-hide after 3 seconds if no message received\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n this.agentTypingTimeout = setTimeout(() => {\n this.agentTyping = false;\n }, 3000);\n }\n break;\n\n case 'typing_stop':\n if (message.sender_type === 'agent') {\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n }\n break;\n\n case 'agent_changed':\n if (message.to_agent) {\n this.currentAgent = {\n id: message.to_agent_id,\n name: message.to_agent,\n };\n\n // Add system message to chat\n const systemMessage: ChatMessage = {\n id: `system-${Date.now()}`,\n text: message.from_agent\n ? `Chat has been transferred from ${message.from_agent} to ${message.to_agent}`\n : `Chat has been transferred to ${message.to_agent}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, systemMessage],\n });\n }\n break;\n\n case 'agent_accepted':\n this.agentAccepted = true;\n this.isConnectingToAgent = false;\n const acceptedMessage: ChatMessage = {\n id: message.id || `agent-accepted-${Date.now()}`,\n text: 'You can chat now, the agent has accepted your request.',\n sender: 'bot',\n timestamp: message.timestamp ? new Date(message.timestamp) : new Date(),\n };\n const existingIds = new Set(this.state.messages.map(m => m.id));\n if (!existingIds.has(acceptedMessage.id)) {\n this.setState({\n messages: [...this.state.messages, acceptedMessage],\n });\n }\n if (message.to_agent) {\n this.currentAgent = {\n name: message.to_agent,\n id: message.to_agent_id,\n };\n }\n break;\n\n case 'chat_resolved':\n case 'chat_ended':\n this.enterResolvedState(message.chat_id || null);\n break;\n\n case 'chat_info':\n if (message.status === 'active') {\n this.isConnectingToAgent = false;\n this.agentAccepted = true;\n } else if (message.status === 'resolved' || message.status === 'ended') {\n this.enterResolvedState(message.chat_id || null);\n }\n if (message.agent_id) {\n this.currentAgent = {\n ...this.currentAgent,\n id: message.agent_id,\n };\n }\n break;\n\n case 'error':\n console.error('WebSocket error:', message.error);\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: message.error || 'An error occurred. Please try again.',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n break;\n }\n }\n\n /**\n * Enter resolved state\n */\n private enterResolvedState(resolvedChatId?: string | null): void {\n this.chatResolved = true;\n this.isConnectingToAgent = false;\n this.agentAccepted = false;\n this.agentTyping = false;\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n this.agentTypingTimeout = null;\n }\n\n // Stop WS + prevent any reuse of the old chat_id\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.chatId = null;\n this.supportSessionId = null;\n if (typeof window !== 'undefined' && window.localStorage) {\n localStorage.removeItem('blockspark_chat_id');\n localStorage.removeItem('blockspark_session_id');\n }\n \n // Add thank you message before reset\n const thankYouMessage: ChatMessage = {\n id: `resolved-${Date.now()}`,\n text: 'Thank you for contacting us!',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, thankYouMessage],\n });\n \n // Automatically reset to BOT mode after showing thank you message\n setTimeout(async () => {\n this.switchToBotMode();\n this.chatResolved = false;\n this.setState({\n messages: [],\n sessionId: null, // Clear session ID to force recreation\n });\n this.collectingUserInfo = false;\n this.userInfoStep = null;\n this.collectedUserName = '';\n this.collectedUserEmail = '';\n this.collectedUserMobile = '';\n \n // Recreate Dialogflow session to start fresh\n if (this.config.dfProjectId && this.config.dfAgentId && this.state.isOpen) {\n try {\n this.setState({ isLoading: true });\n const dialogflowConfig: DialogflowConfig = {\n dfProjectId: this.config.dfProjectId,\n dfLocation: this.config.dfLocation || 'us-central1',\n dfAgentId: this.config.dfAgentId,\n serviceAccountKey: this.config.serviceAccountKey,\n accessToken: this.config.accessToken,\n languageCode: this.config.languageCode || 'en',\n };\n \n const session = await createDialogflowSession(dialogflowConfig);\n this.setState({ \n sessionId: session.session_id,\n isLoading: false,\n });\n \n // Add welcome message from Dialogflow if available\n if (session.message) {\n const welcomeMessage: ChatMessage = {\n id: `welcome-${Date.now()}`,\n text: session.message,\n sender: 'bot',\n timestamp: new Date(),\n richContent: session.richContent,\n };\n this.setState({\n messages: [welcomeMessage],\n });\n }\n } catch (error: any) {\n console.error('Error recreating Dialogflow session after handoff:', error);\n this.setState({ \n isLoading: false,\n error: error.message || 'Failed to initialize chat',\n });\n \n // Show fallback welcome message\n const fallbackMessage: ChatMessage = {\n id: `fallback-${Date.now()}`,\n text: this.config.fallbackWelcomeMessage || 'Hello! How can I help you today?',\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [fallbackMessage],\n });\n }\n }\n }, 2000);\n }\n\n /**\n * Load message history\n */\n async loadMessageHistory(preserveExisting: boolean = false): Promise<void> {\n if (!this.chatService || !this.chatId || !this.supportSessionId) {\n return;\n }\n\n try {\n if (this.chatId && this.supportSessionId) {\n const history = await this.chatService.loadMessageHistory(this.chatId, this.supportSessionId);\n \n const historyMessages: ChatMessage[] = history.map((msg: any) => ({\n id: msg.id || `history-${Date.now()}-${Math.random()}`,\n text: msg.content,\n sender: msg.sender_type === 'agent' ? 'agent' : 'user',\n timestamp: new Date(msg.timestamp),\n }));\n\n if (preserveExisting) {\n // Merge with existing messages, avoiding duplicates\n const existingIds = new Set(this.state.messages.map(m => m.id));\n const newMessages = historyMessages.filter(m => !existingIds.has(m.id));\n \n // Combine existing messages with new history messages\n // Sort by timestamp to maintain chronological order\n const combined = [...this.state.messages, ...newMessages].sort((a, b) => \n a.timestamp.getTime() - b.timestamp.getTime()\n );\n \n this.setState({\n messages: combined,\n });\n } else {\n // Replace all messages\n this.setState({\n messages: historyMessages,\n });\n }\n }\n } catch (error: any) {\n console.error('Error loading message history:', error);\n if (this.config.debug) {\n const errorMessage: ChatMessage = {\n id: `error-${Date.now()}`,\n text: `Failed to load chat history: ${error.message}`,\n sender: 'bot',\n timestamp: new Date(),\n };\n this.setState({\n messages: [...this.state.messages, errorMessage],\n });\n }\n }\n }\n\n /**\n * Get additional state for UI (not in WidgetState but needed by components)\n */\n getAdditionalState() {\n return {\n wsConnected: this.wsConnected,\n agentTyping: this.agentTyping,\n currentAgent: this.currentAgent,\n isConnectingToAgent: this.isConnectingToAgent,\n agentAccepted: this.agentAccepted,\n chatResolved: this.chatResolved,\n };\n }\n\n /**\n * Cleanup\n */\n destroy(): void {\n if (this.typingTimeout) {\n clearTimeout(this.typingTimeout);\n }\n if (this.agentTypingTimeout) {\n clearTimeout(this.agentTypingTimeout);\n }\n if (this.chatService) {\n this.chatService.disconnectWebSocket();\n }\n this.listeners.clear();\n }\n}\n"],"names":["constructor","config","this","listeners","Set","chatMode","chatId","supportSessionId","chatService","collectingUserInfo","userInfoStep","collectedUserName","collectedUserEmail","collectedUserMobile","wsConnected","agentTyping","currentAgent","name","isConnectingToAgent","agentAccepted","chatResolved","historyLoaded","typingTimeout","agentTypingTimeout","state","isOpen","showWelcomePopup","messages","inputValue","isLoading","error","sessionId","createChatService","baseUrl","backendBaseUrl","wsUrl","backendWsUrl","debug","window","localStorage","savedMode","getItem","subscribe","listener","add","delete","getState","setState","updates","forEach","updateConfig","openChat","dfProjectId","dfAgentId","dialogflowConfig","dfLocation","serviceAccountKey","accessToken","languageCode","session","createDialogflowSession","session_id","message","welcomeMessage","id","Date","now","text","sender","timestamp","richContent","fallbackMessage","fallbackWelcomeMessage","closeChat","closeWelcomePopup","toggleChat","willBeOpen","setInputValue","value","clearError","sendMessage","skipUserMessage","trim","userMessage","handleUserInfoCollection","sendHumanMessage","sendAIMessage","ChatResolvedError","enterResolvedState","errorMessage","includes","Error","response","sendDialogflowMessage","handoff","botMessage","startUserInfoCollection","sendTypingIndicator","clearTimeout","sendMessageViaWebSocket","sendMessageToAgent","removeItem","newSession","startSupportChat","chat_id","setItem","retryError","switchToHumanMode","switchToBotMode","initializeWelcomePopup","delay","welcomePopupDelay","setTimeout","namePrompt","emailPrompt","email","test","invalidEmailMessage","mobilePrompt","mobile","length","invalidMobileMessage","handleHandoff","customerName","customerEmail","customerMobile","dialogflowSessionId","ensureChatInitialized","currentChatId","currentSupportSessionId","requestHandoff","handoffError","connectingMessage","connectWebSocket","handleWebSocketMessage","connected","type","content","sender_type","agentMessage","map","m","has","to_agent","to_agent_id","systemMessage","from_agent","acceptedMessage","status","agent_id","resolvedChatId","disconnectWebSocket","thankYouMessage","async","loadMessageHistory","preserveExisting","historyMessages","msg","Math","random","existingIds","newMessages","filter","combined","sort","a","b","getTime","getAdditionalState","destroy","clear"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stateManager.d.ts","sourceRoot":"","sources":["../../src/core/stateManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAe,MAAM,SAAS,CAAC;AAatE,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAgD;IACjE,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,WAAW,CAAqD;IAGxE,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,mBAAmB,CAAc;IAGzC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,YAAY,CAAoD;IACxE,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,aAAa,CAAuB;IAG5C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAA+B;gBAE7C,MAAM,EAAE,YAAY;IAgChC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAO7D;;OAEG;IACH,QAAQ,IAAI,WAAW;IAIvB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAKhB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAIjD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D/B;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsFhF;;OAEG;YACW,aAAa;IA6E3B;;OAEG;YACW,gBAAgB;IAgG9B;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAMzB;;OAEG;IACH,eAAe,IAAI,IAAI;IAMvB;;OAEG;IACH,sBAAsB,IAAI,IAAI;IAW9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA4B/B;;OAEG;YACW,wBAAwB;IAwFtC;;OAEG;IACG,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgK1G;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAsI9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAmG1B;;OAEG;IACG,kBAAkB,CAAC,gBAAgB,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAqD1E;;OAEG;IACH,kBAAkB;;;;kBAliCY,MAAM;iBAAO,MAAM;;;;;;IA6iCjD;;OAEG;IACH,OAAO,IAAI,IAAI;CAYhB"}
1
+ {"version":3,"file":"stateManager.d.ts","sourceRoot":"","sources":["../../src/core/stateManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAe,MAAM,SAAS,CAAC;AAYtE,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAAc;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAgD;IACjE,OAAO,CAAC,QAAQ,CAAwB;IACxC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,WAAW,CAAqD;IAGxE,OAAO,CAAC,kBAAkB,CAAkB;IAC5C,OAAO,CAAC,YAAY,CAA4C;IAChE,OAAO,CAAC,iBAAiB,CAAc;IACvC,OAAO,CAAC,kBAAkB,CAAc;IACxC,OAAO,CAAC,mBAAmB,CAAc;IAGzC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,WAAW,CAAkB;IACrC,OAAO,CAAC,YAAY,CAAoD;IACxE,OAAO,CAAC,mBAAmB,CAAkB;IAC7C,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,YAAY,CAAkB;IACtC,OAAO,CAAC,aAAa,CAAuB;IAG5C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAA+B;gBAE7C,MAAM,EAAE,YAAY;IA+BhC;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAO7D;;OAEG;IACH,QAAQ,IAAI,WAAW;IAIvB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAKhB;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI;IAIjD;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IA2D/B;;OAEG;IACH,SAAS,IAAI,IAAI;IAIjB;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAIzB;;OAEG;IACH,UAAU,IAAI,IAAI;IAQlB;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIlC;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsFhF;;OAEG;YACW,aAAa;IA6E3B;;OAEG;YACW,gBAAgB;IAkG9B;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAQzB;;OAEG;IACH,eAAe,IAAI,IAAI;IAQvB;;OAEG;IACH,sBAAsB,IAAI,IAAI;IAW9B;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAmB/B;;OAEG;YACW,wBAAwB;IAwFtC;;OAEG;IACG,aAAa,CAAC,YAAY,CAAC,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmK1G;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAsI9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoG1B;;OAEG;IACG,kBAAkB,CAAC,gBAAgB,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAqD1E;;OAEG;IACH,kBAAkB;;;;kBAliCY,MAAM;iBAAO,MAAM;;;;;;IA6iCjD;;OAEG;IACH,OAAO,IAAI,IAAI;CAYhB"}