UNPKG

@candoa/chatbot

Version:

Headless React chatbot widget with TypeScript, TailwindCSS support. Customizable AI chat component with hooks for modern React applications.

1 lines 22.7 kB
{"version":3,"sources":["../src/components/ChatbotWidget.tsx","../src/hooks/useChatbot.ts"],"sourcesContent":["'use client'\nimport { Portal } from '@radix-ui/react-portal'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport { ComponentType } from 'react'\nimport { useChatbot } from '../hooks/useChatbot'\nimport type { Message } from '../hooks/useChatbot'\n\nexport interface ChatbotRenderProps {\n isOpen: boolean\n messages: Message[]\n error: string | null\n isTyping: boolean\n hasActiveConversation: boolean\n conversationId: string | null\n humanTakenOver: boolean\n hasUnreadMessages: boolean\n onSendMessage: (message: string) => Promise<void>\n onToggleOpen: () => void\n onClose: () => void\n onClearMessages: () => void\n onClearError: () => void\n onLoadConversation: (conversationId: string) => Promise<void>\n onMarkAsRead: () => void\n}\n\nexport type ChatbotWidgetProps = {\n projectId: string\n title?: string\n icon?: ComponentType<{ className?: string }>\n greetings?: string[]\n apiUrl?: string\n isDev?: boolean\n children: (props: ChatbotRenderProps) => React.ReactNode\n}\n\nexport const ChatbotWidget = ({\n projectId,\n title = 'Chat with us',\n icon,\n greetings,\n apiUrl,\n isDev,\n children,\n}: ChatbotWidgetProps) => {\n const { state, actions } = useChatbot(projectId, {\n title,\n greetings,\n icon,\n apiUrl,\n isDev,\n })\n\n const renderProps: ChatbotRenderProps = {\n isOpen: state.isOpen,\n messages: state.messages,\n error: state.error,\n isTyping: state.isTyping,\n hasActiveConversation: state.hasActiveConversation,\n conversationId: state.conversationId,\n humanTakenOver: state.humanTakenOver,\n hasUnreadMessages: state.hasUnreadMessages,\n onSendMessage: actions.sendMessage,\n onToggleOpen: () => actions.setIsOpen(!state.isOpen),\n onClose: () => actions.setIsOpen(false),\n onClearMessages: actions.clearMessages,\n onClearError: actions.clearError,\n onLoadConversation: actions.loadConversation,\n onMarkAsRead: actions.markAsRead,\n }\n\n return <Portal>{children(renderProps)}</Portal>\n}\n","import { useState, useCallback, useEffect, useRef } from 'react'\nimport { ComponentType } from 'react'\n\nexport type Message = {\n id: string\n text: string\n isUser: boolean\n timestamp: Date\n}\n\nexport type ChatbotState = {\n isOpen: boolean\n messages: Message[]\n error: string | null\n isTyping: boolean\n hasActiveConversation: boolean // Replace conversationId with a boolean indicator\n conversationId: string | null // Expose conversationId for development\n humanTakenOver: boolean // Add human takeover status\n hasUnreadMessages: boolean // Track unread messages\n}\n\nexport type ChatbotActions = {\n setIsOpen: (isOpen: boolean) => void\n sendMessage: (message: string) => Promise<void>\n clearMessages: () => void\n clearError: () => void\n loadConversation: (conversationId: string) => Promise<void> // Renamed for clarity\n markAsRead: () => void // Mark messages as read\n}\n\nexport function useChatbot(\n projectId: string,\n options: {\n title?: string\n greetings?: string[]\n icon?: ComponentType<{ className?: string }>\n initialConversationId?: string\n apiUrl?: string\n isDev?: boolean // Explicit development mode flag\n } = {},\n) {\n const {\n greetings = [],\n title,\n icon,\n initialConversationId,\n apiUrl,\n isDev,\n } = options\n\n // Auto-detect environment and set appropriate API URL\n const getApiUrl = () => {\n if (apiUrl) return apiUrl // Use provided URL if specified\n\n // Use development API only when explicitly set\n if (isDev) {\n return 'http://localhost:3000'\n }\n\n // Default to production URL for everyone\n return 'https://crm.candoa.app'\n }\n\n const baseApiUrl = getApiUrl()\n\n const [isOpen, setIsOpen] = useState(false)\n const [messages, setMessages] = useState<Message[]>([])\n const [error, setError] = useState<string | null>(null)\n const [isTyping, setIsTyping] = useState(false)\n const [conversationId, setConversationId] = useState<string | null>(\n initialConversationId || null,\n )\n const [humanTakenOver, setHumanTakenOver] = useState(false)\n const [hasUnreadMessages, setHasUnreadMessages] = useState(false)\n\n // Clear unread messages when chat is opened\n useEffect(() => {\n if (isOpen && hasUnreadMessages) {\n setHasUnreadMessages(false)\n }\n }, [isOpen, hasUnreadMessages])\n\n // Polling refs\n const pollingIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null)\n const lastMessageCountRef = useRef(0)\n\n // ✅ Retrieve stored conversationId from localStorage if not provided\n useEffect(() => {\n if (typeof window === 'undefined' || initialConversationId) return\n\n const storedConversationId = localStorage.getItem('conversationId')\n\n if (storedConversationId && !conversationId) {\n setConversationId(storedConversationId)\n }\n }, [initialConversationId, conversationId])\n\n // ✅ Store conversationId in localStorage when it changes\n useEffect(() => {\n if (typeof window === 'undefined' || !conversationId) return\n\n localStorage.setItem('conversationId', conversationId)\n }, [conversationId])\n\n // Polling function to check for new messages when human has taken over\n const pollForNewMessages = useCallback(async () => {\n if (!conversationId || !humanTakenOver) return\n\n try {\n const response = await fetch(\n `${baseApiUrl}/api/messages?conversationId=${conversationId}`,\n )\n\n if (!response.ok) return\n\n const data = await response.json()\n if (!data.success) return\n\n const serverMessages: Message[] = data.messages.map((msg: any) => ({\n id: msg.id,\n text: msg.content,\n isUser: msg.role === 'user',\n timestamp: new Date(msg.createdAt),\n }))\n\n // Check if there are new messages\n if (serverMessages.length > lastMessageCountRef.current) {\n // Check if there are new messages from human agent (not user messages)\n const newMessages = serverMessages.slice(lastMessageCountRef.current)\n const hasNewAgentMessages = newMessages.some((msg) => !msg.isUser)\n\n setMessages(serverMessages)\n lastMessageCountRef.current = serverMessages.length\n\n // If chat is closed and there are new agent messages, mark as unread\n if (!isOpen && hasNewAgentMessages) {\n setHasUnreadMessages(true)\n\n // Show browser notification if permission granted\n if (\n typeof window !== 'undefined' &&\n 'Notification' in window &&\n Notification.permission === 'granted'\n ) {\n const lastAgentMessage = newMessages\n .filter((msg) => !msg.isUser)\n .pop()\n if (lastAgentMessage) {\n new Notification('New message from support', {\n body:\n lastAgentMessage.text.length > 100\n ? lastAgentMessage.text.substring(0, 100) + '...'\n : lastAgentMessage.text,\n icon: '/favicon.ico',\n })\n }\n }\n }\n }\n } catch (err) {\n // Silently handle polling errors to avoid disrupting user experience\n console.warn('Polling error:', err)\n }\n }, [conversationId, humanTakenOver, baseApiUrl])\n\n // Start/stop polling based on human takeover status\n useEffect(() => {\n if (humanTakenOver && conversationId) {\n // Start polling every 3 seconds\n pollingIntervalRef.current = setInterval(pollForNewMessages, 3000)\n } else {\n // Stop polling\n if (pollingIntervalRef.current) {\n clearInterval(pollingIntervalRef.current)\n pollingIntervalRef.current = null\n }\n }\n\n // Cleanup on unmount\n return () => {\n if (pollingIntervalRef.current) {\n clearInterval(pollingIntervalRef.current)\n pollingIntervalRef.current = null\n }\n }\n }, [humanTakenOver, conversationId, pollForNewMessages])\n\n // Load message history from the server\n const loadConversation = useCallback(\n async (convoId: string) => {\n if (!convoId) return\n\n setIsTyping(true)\n setError(null)\n try {\n const response = await fetch(\n `${baseApiUrl}/api/messages?conversationId=${convoId}`,\n )\n\n if (!response.ok) {\n // If conversation not found (404), clear the stored ID\n if (response.status === 404) {\n if (typeof window !== 'undefined') {\n localStorage.removeItem('conversationId')\n }\n setConversationId(null)\n setMessages([])\n\n // Don't show greeting messages here - let the greeting effect handle it\n // when the conversationId is cleared\n\n setIsTyping(false)\n return\n }\n throw new Error('Failed to load message history')\n }\n\n const data = await response.json()\n\n if (!data.success) {\n throw new Error(data.message || 'Failed to load messages')\n }\n\n // Convert API message format to local message format\n const historyMessages: Message[] = data.messages.map((msg: any) => ({\n id: msg.id,\n text: msg.content,\n isUser: msg.role === 'user',\n timestamp: new Date(msg.createdAt),\n }))\n\n setMessages(historyMessages)\n setConversationId(convoId)\n lastMessageCountRef.current = historyMessages.length\n\n // Check if human has taken over by looking at conversation status\n if (data.conversation?.humanTakenOver) {\n setHumanTakenOver(true)\n }\n } catch (err) {\n setError(\n err instanceof Error ? err.message : 'Failed to load message history',\n )\n setMessages([]) // Clear messages on error\n } finally {\n setIsTyping(false)\n }\n },\n [projectId, baseApiUrl],\n )\n\n // ✅ Load conversation history when conversationId is set from localStorage\n useEffect(() => {\n if (conversationId && messages.length === 0 && !initialConversationId) {\n loadConversation(conversationId)\n }\n }, [conversationId, loadConversation, messages.length, initialConversationId])\n\n // Load initial conversation if provided\n useEffect(() => {\n if (initialConversationId && messages.length === 0) {\n loadConversation(initialConversationId)\n }\n }, [initialConversationId, loadConversation, messages.length])\n\n // Show greetings on first open if no history\n useEffect(() => {\n if (\n isOpen &&\n messages.length === 0 &&\n greetings.length > 0 &&\n !initialConversationId &&\n !conversationId // Don't show greetings if we have a stored conversationId\n ) {\n const greetingMessages: Message[] = greetings.map((greeting) => ({\n id: crypto.randomUUID(),\n text: greeting,\n isUser: false,\n timestamp: new Date(),\n }))\n setMessages(greetingMessages)\n }\n }, [\n isOpen,\n messages.length,\n greetings,\n initialConversationId,\n conversationId,\n ])\n\n const sendMessage = useCallback(\n async (text: string) => {\n if (!text.trim()) return\n\n const newMessage: Message = {\n id: crypto.randomUUID(),\n text: text.trim(),\n isUser: true,\n timestamp: new Date(),\n }\n\n const updatedMessages = [...messages, newMessage]\n setMessages(updatedMessages)\n // Only show typing indicator if human hasn't taken over\n if (!humanTakenOver) {\n setIsTyping(true)\n }\n setError(null)\n\n try {\n // Build request body - use conversationId if available, otherwise create new conversation\n const requestBody: {\n projectId: string\n access: 'AI_AGENT' | 'AI_COPILOT'\n messages: Array<{\n role: 'user' | 'assistant'\n content: string\n }>\n conversationId?: string\n greetingMessages?: string[]\n } = {\n projectId,\n access: 'AI_AGENT',\n messages: updatedMessages.map((m) => ({\n role: m.isUser ? 'user' : 'assistant',\n content: m.text,\n })),\n }\n\n if (conversationId) {\n // Use existing conversation\n requestBody.conversationId = conversationId\n } else {\n // Create new conversation\n requestBody.greetingMessages = greetings.length > 0 ? greetings : []\n }\n\n const response = await fetch(`${baseApiUrl}/api/chatbot`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n })\n\n if (!response.ok) throw new Error('Failed to send message')\n\n const data = await response.json()\n\n if (!data.success) {\n throw new Error(data.message || 'AI response failed')\n }\n\n // Store the conversationId if it's returned and we don't have one yet\n if (data.conversationId && !conversationId) {\n setConversationId(data.conversationId)\n }\n\n // Check if human has taken over\n if (data.humanTakenOver) {\n setHumanTakenOver(true)\n lastMessageCountRef.current = updatedMessages.length\n\n // Only add a bot message if there's actual content\n if (data.message && data.message.trim()) {\n const botMessage: Message = {\n id: crypto.randomUUID(),\n text: data.message,\n isUser: false,\n timestamp: new Date(),\n }\n setMessages((prev) => [...prev, botMessage])\n lastMessageCountRef.current = updatedMessages.length + 1\n }\n return // Don't show the normal AI response\n }\n\n const botMessage: Message = {\n id: crypto.randomUUID(),\n text: data.message,\n isUser: false,\n timestamp: new Date(),\n }\n\n setMessages((prev) => [...prev, botMessage])\n lastMessageCountRef.current = updatedMessages.length + 1\n } catch (err) {\n setError(err instanceof Error ? err.message : 'An error occurred')\n } finally {\n setIsTyping(false)\n }\n },\n [projectId, messages, conversationId, baseApiUrl, greetings],\n )\n\n const clearMessages = useCallback(() => {\n setMessages([])\n setConversationId(null)\n setHumanTakenOver(false)\n lastMessageCountRef.current = 0\n\n // Stop polling\n if (pollingIntervalRef.current) {\n clearInterval(pollingIntervalRef.current)\n pollingIntervalRef.current = null\n }\n\n // Clear the conversationId from localStorage\n if (typeof window !== 'undefined') {\n localStorage.removeItem('conversationId')\n }\n }, [])\n\n const clearError = useCallback(() => {\n setError(null)\n }, [])\n\n const markAsRead = useCallback(() => {\n setHasUnreadMessages(false)\n }, [])\n\n return {\n state: {\n isOpen,\n messages,\n error,\n isTyping,\n hasActiveConversation: !!conversationId,\n conversationId,\n humanTakenOver,\n hasUnreadMessages,\n },\n actions: {\n setIsOpen,\n sendMessage,\n clearMessages,\n clearError,\n loadConversation,\n markAsRead,\n },\n }\n}\n"],"mappings":"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","names":["botMessage"]}