@xcelsior/ui-chat 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ChatWidget.tsx","../src/hooks/useWebSocket.ts","../src/hooks/useMessages.ts","../src/utils/api.ts","../src/hooks/useFileUpload.ts","../src/hooks/useTypingIndicator.ts","../src/components/ChatHeader.tsx","../src/components/MessageList.tsx","../src/components/MessageItem.tsx","../src/components/ChatInput.tsx","../src/components/Chat.tsx","../src/components/PreChatForm.tsx","../src/hooks/useChatWidgetState.ts","../src/components/TypingIndicator.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useWebSocket } from '../hooks/useWebSocket';\nimport { useMessages } from '../hooks/useMessages';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useTypingIndicator } from '../hooks/useTypingIndicator';\nimport { ChatHeader } from './ChatHeader';\nimport { MessageList } from './MessageList';\nimport { ChatInput } from './ChatInput';\nimport type { IChatConfig, IMessage } from '../types';\n\nexport interface ChatWidgetProps {\n config: IChatConfig;\n className?: string;\n /**\n * Variant of the chat widget:\n * - 'popover': Fixed positioned floating widget (default)\n * - 'fullPage': Full page layout that fills the container\n */\n variant?: 'popover' | 'fullPage';\n /**\n * External WebSocket connection (for agents with global connection)\n */\n externalWebSocket?: WebSocket | null;\n /**\n * Callback when user wants to minimize the widget\n */\n onMinimize?: () => void;\n /**\n * Callback when user wants to close the widget\n */\n onClose?: () => void;\n}\n\nexport function ChatWidget({\n config,\n className = '',\n variant = 'popover',\n externalWebSocket,\n onMinimize,\n onClose,\n}: ChatWidgetProps) {\n const isFullPage = variant === 'fullPage';\n\n // Initialize WebSocket connection (or use external one)\n const websocket = useWebSocket(config, externalWebSocket);\n\n // Initialize messages\n const { messages, addMessage, isLoading, loadMore, hasMore, isLoadingMore } = useMessages(\n websocket,\n config\n );\n\n // Initialize file upload\n const fileUpload = useFileUpload(config.apiKey, config.fileUpload);\n\n // Initialize typing indicator\n const { isTyping, typingUsers } = useTypingIndicator(websocket);\n\n // Handle sending messages\n const handleSendMessage = useCallback(\n (content: string) => {\n if (!websocket.isConnected) {\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n // Create optimistic message\n const optimisticMessage: IMessage = {\n id: `temp-${Date.now()}`,\n conversationId: config.conversationId || '',\n senderId: config.currentUser.email,\n senderType: config.currentUser.type,\n content,\n messageType: 'text',\n createdAt: new Date().toISOString(),\n status: 'sent',\n };\n\n // Add to local state immediately (optimistic update)\n addMessage(optimisticMessage);\n\n // Send via WebSocket\n websocket.sendMessage('sendMessage', {\n conversationId: config.conversationId,\n content,\n messageType: 'text',\n });\n\n // Call callback\n config.onMessageSent?.(optimisticMessage);\n },\n [websocket, config, addMessage]\n );\n\n // Handle typing indicator\n const handleTyping = useCallback(\n (isTyping: boolean) => {\n if (!websocket.isConnected || config.enableTypingIndicator === false) {\n return;\n }\n\n websocket.sendMessage('typing', {\n conversationId: config.conversationId,\n isTyping,\n });\n },\n [websocket, config]\n );\n\n // Handle errors\n useEffect(() => {\n if (websocket.error) {\n config.toast?.error(websocket.error.message || 'An error occurred');\n }\n }, [websocket.error, config]);\n\n // Container styles based on variant\n const containerClasses = isFullPage\n ? `flex flex-col bg-white dark:bg-gray-900 h-full ${className}`\n : `fixed bottom-4 right-4 z-50 flex flex-col bg-white dark:bg-gray-900 rounded-lg shadow-2xl overflow-hidden ${className}`;\n\n const containerStyle = isFullPage\n ? undefined\n : {\n width: '400px',\n height: '600px',\n maxHeight: 'calc(100vh - 2rem)',\n };\n\n return (\n <div className={containerClasses} style={containerStyle}>\n {!isFullPage && (\n <ChatHeader\n agent={\n config.currentUser.type === 'customer'\n ? {\n email: 'contact@xcelsior.co',\n name: 'Support Agent',\n type: 'agent',\n status: websocket.isConnected ? 'online' : 'offline',\n }\n : undefined\n }\n onMinimize={onMinimize}\n onClose={onClose}\n />\n )}\n\n {/* Connection Status */}\n {!websocket.isConnected && (\n <div className=\"bg-yellow-50 dark:bg-yellow-900/30 border-b border-yellow-200 dark:border-yellow-800 px-4 py-2\">\n <div className=\"flex items-center gap-2\">\n <div className=\"w-2 h-2 rounded-full bg-yellow-500 animate-pulse\" />\n <span className=\"text-sm text-yellow-800 dark:text-yellow-200\">\n Reconnecting...\n </span>\n <button\n type=\"button\"\n onClick={websocket.reconnect}\n className=\"ml-auto text-xs text-yellow-700 dark:text-yellow-300 hover:underline\"\n >\n Retry\n </button>\n </div>\n </div>\n )}\n\n {/* Messages */}\n {isLoading ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <div className=\"text-center\">\n <div className=\"w-8 h-8 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-2\" />\n <p className=\"text-sm text-gray-600 dark:text-gray-400\">\n Loading messages...\n </p>\n </div>\n </div>\n ) : (\n <MessageList\n messages={messages}\n currentUser={config.currentUser}\n isTyping={isTyping}\n typingUser={typingUsers[0]}\n autoScroll={true}\n onLoadMore={loadMore}\n hasMore={hasMore}\n isLoadingMore={isLoadingMore}\n />\n )}\n\n {/* Input */}\n <ChatInput\n onSend={handleSendMessage}\n onTyping={handleTyping}\n config={config}\n fileUpload={fileUpload}\n disabled={!websocket.isConnected}\n />\n\n {/* Powered by footer - only for popover */}\n {!isFullPage && (\n <div className=\"bg-gray-50 dark:bg-gray-950 px-4 py-2 text-center border-t border-gray-200 dark:border-gray-700\">\n <p className=\"text-xs text-gray-500 dark:text-gray-400\">\n Powered by <span className=\"font-semibold\">Xcelsior Chat</span>\n </p>\n </div>\n )}\n </div>\n );\n}\n","import { useEffect, useRef, useState, useCallback } from 'react';\nimport type { IChatConfig, IWebSocketMessage } from '../types';\n\nexport interface UseWebSocketReturn {\n isConnected: boolean;\n sendMessage: (action: string, data: any) => void;\n lastMessage: IWebSocketMessage | null;\n error: Error | null;\n reconnect: () => void;\n}\n\n/**\n * Hook for WebSocket connection in chat widget.\n * Can use an external WebSocket connection (for agents) via the externalWebSocket prop.\n */\nexport function useWebSocket(\n config: IChatConfig,\n externalWebSocket?: WebSocket | null\n): UseWebSocketReturn {\n const [isConnected, setIsConnected] = useState(false);\n const [lastMessage, setLastMessage] = useState<IWebSocketMessage | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const wsRef = useRef<WebSocket | null>(null);\n const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const reconnectAttemptsRef = useRef(0);\n const messageHandlerRef = useRef<((event: MessageEvent) => void) | null>(null);\n const maxReconnectAttempts = 5;\n const reconnectDelay = 3000;\n\n // Use external WebSocket if provided (for agents)\n const isUsingExternalWs = !!externalWebSocket;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const subscribeToMessage = useCallback((webSocket: WebSocket) => {\n // Remove previous listener if it exists\n if (messageHandlerRef.current) {\n webSocket.removeEventListener('message', messageHandlerRef.current);\n }\n\n // Create new message handler\n const handler = (event: MessageEvent) => {\n try {\n const message: IWebSocketMessage = JSON.parse(event.data);\n setLastMessage(message);\n\n // Handle different message types\n if (message.type === 'message' && message.data) {\n config.onMessageReceived?.(message.data);\n } else if (message.type === 'error') {\n const err = new Error(message.data?.message || 'WebSocket error');\n setError(err);\n config.onError?.(err);\n }\n } catch (err) {\n console.error('Failed to parse WebSocket message:', err);\n }\n };\n\n // Add the new listener\n webSocket.addEventListener('message', handler);\n messageHandlerRef.current = handler;\n\n // Return cleanup function\n return () => {\n webSocket.removeEventListener('message', handler);\n if (messageHandlerRef.current === handler) {\n messageHandlerRef.current = null;\n }\n };\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const connect = useCallback(() => {\n console.log('connecting to WebSocket...', config.currentUser, config.conversationId);\n try {\n // Clean up existing connection\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close();\n }\n\n // Build WebSocket URL with query parameters\n const url = new URL(config.websocketUrl);\n url.searchParams.set('user', JSON.stringify(config.currentUser));\n if (config.conversationId) {\n url.searchParams.set('conversationId', config.conversationId);\n }\n if (config.apiKey) {\n url.searchParams.set('apiKey', config.apiKey);\n }\n\n const ws = new WebSocket(url.toString());\n\n ws.onopen = () => {\n console.log('WebSocket connected');\n setIsConnected(true);\n setError(null);\n reconnectAttemptsRef.current = 0;\n config.onConnectionChange?.(true);\n };\n\n ws.onerror = (event) => {\n console.error('WebSocket error:', event);\n const err = new Error('WebSocket connection error');\n setError(err);\n config.onError?.(err);\n };\n\n ws.onclose = (event) => {\n console.log('WebSocket closed:', event.code, event.reason);\n setIsConnected(false);\n config.onConnectionChange?.(false);\n wsRef.current = null;\n\n // Attempt to reconnect if not a normal closure\n if (event.code !== 1000 && reconnectAttemptsRef.current < maxReconnectAttempts) {\n reconnectAttemptsRef.current += 1;\n console.log(\n `Reconnecting... (${reconnectAttemptsRef.current}/${maxReconnectAttempts})`\n );\n reconnectTimeoutRef.current = setTimeout(() => {\n connect();\n }, reconnectDelay);\n }\n };\n\n subscribeToMessage(ws);\n wsRef.current = ws ?? null;\n } catch (err) {\n console.error('Failed to create WebSocket connection:', err);\n const error = err instanceof Error ? err : new Error('Failed to connect');\n setError(error);\n config.onError?.(error);\n }\n }, [JSON.stringify([config.currentUser, config.conversationId])]);\n\n const sendMessage = useCallback(\n (action: string, data: any) => {\n if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {\n console.error('WebSocket is not connected');\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n try {\n wsRef.current.send(\n JSON.stringify({\n action,\n data,\n })\n );\n } catch (err) {\n console.error('Failed to send message:', err);\n const error = err instanceof Error ? err : new Error('Failed to send message');\n setError(error);\n config.onError?.(error);\n }\n },\n [config]\n );\n\n const reconnect = useCallback(() => {\n reconnectAttemptsRef.current = 0;\n connect();\n }, [connect]);\n\n useEffect(() => {\n if (isUsingExternalWs) {\n setIsConnected(externalWebSocket?.readyState === WebSocket.OPEN || false);\n wsRef.current = externalWebSocket;\n const cleanup = subscribeToMessage(externalWebSocket);\n return cleanup;\n }\n\n connect();\n\n // Cleanup on unmount\n return () => {\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n }\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close(1000, 'Component unmounted');\n }\n };\n }, [connect, isUsingExternalWs, externalWebSocket, subscribeToMessage]);\n\n // Use external connection state if available\n const effectiveIsConnected = isUsingExternalWs\n ? externalWebSocket?.readyState === WebSocket.OPEN || false\n : isConnected;\n\n return {\n isConnected: effectiveIsConnected,\n sendMessage,\n lastMessage,\n error,\n reconnect,\n };\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { IMessage, IChatConfig } from '../types';\nimport type { UseWebSocketReturn } from './useWebSocket';\nimport { fetchMessages } from '../utils/api';\n\nexport interface UseMessagesReturn {\n messages: IMessage[];\n addMessage: (message: IMessage) => void;\n updateMessageStatus: (messageId: string, status: IMessage['status']) => void;\n clearMessages: () => void;\n isLoading: boolean;\n error: Error | null;\n loadMore: () => Promise<void>;\n hasMore: boolean;\n isLoadingMore: boolean;\n}\n\nexport function useMessages(websocket: UseWebSocketReturn, config: IChatConfig): UseMessagesReturn {\n const [messages, setMessages] = useState<IMessage[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [nextPageToken, setNextPageToken] = useState<string | undefined>(undefined);\n const [hasMore, setHasMore] = useState(true);\n const [isLoadingMore, setIsLoadingMore] = useState(false);\n\n // Extract stable references from config\n const { httpApiUrl, conversationId, headers, onError, toast } = config;\n\n const headersWithApiKey = useMemo(\n () => ({\n ...headers,\n 'x-api-key': config.apiKey,\n }),\n [headers, config.apiKey]\n );\n\n // Fetch existing messages when conversationId changes\n useEffect(() => {\n const loadMessages = async () => {\n // Only fetch if we have httpApiUrl and conversationId\n if (!httpApiUrl || !conversationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n { conversationId, limit: 20 },\n headersWithApiKey\n );\n\n setMessages(result.data);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load messages');\n setError(error);\n onError?.(error);\n toast?.error('Failed to load existing messages');\n } finally {\n setIsLoading(false);\n }\n };\n\n loadMessages();\n // Only re-run when conversationId or httpApiUrl changes\n }, [conversationId, httpApiUrl, headersWithApiKey, onError, toast]);\n\n // Extract onMessageReceived callback\n const { onMessageReceived } = config;\n\n // Listen for incoming messages from WebSocket\n useEffect(() => {\n if (websocket.lastMessage?.type === 'message' && websocket.lastMessage.data) {\n const newMessage: IMessage = websocket.lastMessage.data;\n\n if (conversationId && newMessage.conversationId !== conversationId) {\n // Ignore messages for other conversations\n return;\n }\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === newMessage.id)) {\n return prev;\n }\n return [...prev, newMessage];\n });\n\n // Notify parent component about new message\n onMessageReceived?.(newMessage);\n }\n }, [websocket.lastMessage, onMessageReceived, conversationId]);\n\n const addMessage = useCallback((message: IMessage) => {\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === message.id)) {\n return prev;\n }\n return [...prev, message];\n });\n }, []);\n\n const updateMessageStatus = useCallback((messageId: string, status: IMessage['status']) => {\n setMessages((prev) => prev.map((msg) => (msg.id === messageId ? { ...msg, status } : msg)));\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n }, []);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || isLoadingMore || !httpApiUrl || !conversationId || !nextPageToken) {\n return;\n }\n\n setIsLoadingMore(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n {\n conversationId,\n limit: 20,\n pageToken: nextPageToken,\n },\n headersWithApiKey\n );\n\n setMessages((prev) => [...result.data, ...prev]);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load more messages');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoadingMore(false);\n }\n }, [\n hasMore,\n isLoadingMore,\n httpApiUrl,\n conversationId,\n nextPageToken,\n headersWithApiKey,\n onError,\n ]);\n\n return {\n messages,\n addMessage,\n updateMessageStatus,\n clearMessages,\n isLoading,\n error,\n loadMore,\n hasMore,\n isLoadingMore,\n };\n}\n","import axios from 'axios';\nimport type { IMessage, IApiResponse } from '../types';\n\nexport interface FetchMessagesParams {\n conversationId: string;\n limit?: number;\n pageToken?: string;\n}\n\n/**\n * Fetch messages for a conversation from the REST API\n */\nexport async function fetchMessages(\n baseUrl: string,\n params: FetchMessagesParams,\n headers?: Record<string, string>\n) {\n try {\n const response = await axios.get<IApiResponse<IMessage[]>>(`${baseUrl}/messages`, {\n params: {\n conversationId: params.conversationId,\n limit: params.limit || 50,\n pageToken: params.pageToken,\n },\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n });\n\n return {\n data: response.data.data ?? [],\n nextPageToken: response.data.pagination?.nextPageToken,\n };\n } catch (error) {\n if (axios.isAxiosError(error)) {\n throw new Error(\n error.response?.data?.error?.message || error.message || 'Failed to fetch messages'\n );\n }\n throw error;\n }\n}\n","import { useState } from 'react';\nimport axios from 'axios';\nimport type { IFileUploadConfig, IUploadedFile } from '../types';\n\nexport interface UseFileUploadReturn {\n uploadFile: (file: File) => Promise<IUploadedFile | null>;\n isUploading: boolean;\n uploadProgress: number;\n error: Error | null;\n canUpload: boolean;\n}\n\nexport function useFileUpload(apiKey: string, config?: IFileUploadConfig): UseFileUploadReturn {\n const [isUploading, setIsUploading] = useState(false);\n const [uploadProgress, setUploadProgress] = useState(0);\n const [error, setError] = useState<Error | null>(null);\n\n const defaultConfig = {\n maxFileSize: 10 * 1024 * 1024, // 10MB default\n allowedTypes: [\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'text/plain',\n 'text/csv',\n ],\n };\n\n const finalConfig = { ...defaultConfig, ...config };\n const canUpload = !!config?.uploadUrl;\n\n const validateFile = (file: File): string | null => {\n if (!finalConfig.allowedTypes.includes(file.type)) {\n return `File type ${file.type} is not supported. Allowed types: ${finalConfig.allowedTypes.join(', ')}`;\n }\n\n if (file.size > finalConfig.maxFileSize) {\n return `File size ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds the maximum allowed size of ${(finalConfig.maxFileSize / 1024 / 1024).toFixed(2)}MB`;\n }\n\n return null;\n };\n\n const uploadFile = async (file: File): Promise<IUploadedFile | null> => {\n if (!config?.uploadUrl) {\n const err = new Error('File upload URL is not configured');\n setError(err);\n throw err;\n }\n\n const validationError = validateFile(file);\n if (validationError) {\n const err = new Error(validationError);\n setError(err);\n throw err;\n }\n\n setIsUploading(true);\n setUploadProgress(0);\n setError(null);\n\n try {\n // Step 1: Get presigned upload URL from the API\n const uploadUrlResponse = await axios.post(\n config.uploadUrl,\n {\n fileName: file.name,\n contentType: file.type,\n fileSize: file.size,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey || '',\n ...config.headers,\n },\n }\n );\n\n const { uploadUrl, attachmentUrl } =\n uploadUrlResponse.data.data || uploadUrlResponse.data;\n\n if (!uploadUrl || !attachmentUrl) {\n throw new Error('Failed to get upload URL from server');\n }\n\n // Step 2: Upload file directly to S3 using presigned URL\n await axios.put(uploadUrl, file, {\n headers: {\n 'Content-Type': file.type,\n },\n onUploadProgress: (progressEvent) => {\n if (progressEvent.total) {\n const progress = Math.round(\n (progressEvent.loaded * 100) / progressEvent.total\n );\n setUploadProgress(progress);\n }\n },\n });\n\n return {\n url: attachmentUrl,\n name: file.name,\n size: file.size,\n type: file.type,\n markdown: file.type.startsWith('image/')\n ? `![${file.name}](${attachmentUrl})`\n : `[${file.name}](${attachmentUrl})`,\n };\n } catch (err) {\n console.error('File upload failed:', err);\n const error = err instanceof Error ? err : new Error('Upload failed');\n setError(error);\n throw error;\n } finally {\n setIsUploading(false);\n setUploadProgress(0);\n }\n };\n\n return {\n uploadFile,\n isUploading,\n uploadProgress,\n error,\n canUpload,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { UseWebSocketReturn } from './useWebSocket';\n\nexport interface UseTypingIndicatorReturn {\n isTyping: boolean;\n typingUsers: string[];\n}\n\nexport function useTypingIndicator(websocket: UseWebSocketReturn): UseTypingIndicatorReturn {\n const [typingUsers, setTypingUsers] = useState<string[]>([]);\n\n useEffect(() => {\n if (websocket.lastMessage?.type === 'typing' && websocket.lastMessage.data) {\n const { userId, isTyping } = websocket.lastMessage.data;\n\n if (isTyping) {\n setTypingUsers((prev) => {\n if (!prev.includes(userId)) {\n return [...prev, userId];\n }\n return prev;\n });\n } else {\n setTypingUsers((prev) => prev.filter((id) => id !== userId));\n }\n }\n }, [websocket.lastMessage]);\n\n return {\n isTyping: typingUsers.length > 0,\n typingUsers,\n };\n}\n","import type { IUser } from '../types';\n\ninterface ChatHeaderProps {\n agent?: IUser;\n onClose?: () => void;\n onMinimize?: () => void;\n}\n\nexport function ChatHeader({ agent, onClose, onMinimize }: ChatHeaderProps) {\n return (\n <div className=\"bg-gradient-to-r from-blue-600 to-purple-600 text-white p-4 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"h-10 w-10 rounded-full bg-white/20 flex items-center justify-center text-lg font-medium\">\n {agent?.avatar ? (\n <img\n src={agent.avatar}\n alt={agent.name}\n className=\"h-10 w-10 rounded-full object-cover\"\n />\n ) : (\n '🎧'\n )}\n </div>\n {agent?.status === 'online' && (\n <div className=\"absolute bottom-0 right-0 h-3 w-3 rounded-full bg-green-500 border-2 border-white\" />\n )}\n </div>\n <div>\n <h3 className=\"font-semibold text-base\">{agent?.name || 'Support Team'}</h3>\n <p className=\"text-xs text-white/80\">\n {agent?.status === 'online'\n ? 'Online'\n : agent?.status === 'away'\n ? 'Away'\n : \"We'll reply as soon as possible\"}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n {onMinimize && (\n <button\n type=\"button\"\n onClick={onMinimize}\n className=\"p-2 hover:bg-white/10 rounded-full transition-colors\"\n aria-label=\"Minimize chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Minimize icon</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M20 12H4\"\n />\n </svg>\n </button>\n )}\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-2 hover:bg-white/10 rounded-full transition-colors\"\n aria-label=\"Close chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Close icon</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useCallback } from 'react';\nimport { Spinner } from '@xcelsior/design-system';\nimport { MessageItem } from './MessageItem';\nimport type { IMessage, IUser } from '../types';\n\ninterface MessageListProps {\n messages: IMessage[];\n currentUser: IUser;\n isLoading?: boolean;\n isTyping?: boolean;\n typingUser?: string;\n autoScroll?: boolean;\n onLoadMore?: () => void;\n hasMore?: boolean;\n isLoadingMore?: boolean;\n}\n\nexport function MessageList({\n messages,\n currentUser,\n isLoading = false,\n isTyping = false,\n typingUser,\n autoScroll = true,\n onLoadMore,\n hasMore = false,\n isLoadingMore = false,\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevLengthRef = useRef(messages.length);\n const loadMoreTriggerRef = useRef<HTMLDivElement>(null);\n const prevScrollHeightRef = useRef(0);\n const hasInitialScrolledRef = useRef(false);\n const isUserScrollingRef = useRef(false);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n if (autoScroll && messagesEndRef.current) {\n // Only auto-scroll if we're adding new messages (not loading older ones)\n // Skip auto-scroll if we're loading more (older messages)\n if (messages.length > prevLengthRef.current && !isLoadingMore) {\n messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });\n }\n prevLengthRef.current = messages.length;\n }\n }, [messages.length, autoScroll, isLoadingMore]);\n\n // Initial scroll to bottom when messages first load\n useEffect(() => {\n if (\n messages.length > 0 &&\n messagesEndRef.current &&\n !isLoading &&\n !hasInitialScrolledRef.current\n ) {\n // Use setTimeout to ensure DOM is fully rendered\n setTimeout(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'auto' });\n // Enable user scrolling after initial scroll completes\n setTimeout(() => {\n isUserScrollingRef.current = true;\n }, 200);\n }, 100);\n hasInitialScrolledRef.current = true;\n } else if (!isLoading && messages.length === 0 && !hasInitialScrolledRef.current) {\n // If there are no messages, enable user scrolling immediately\n isUserScrollingRef.current = true;\n hasInitialScrolledRef.current = true;\n }\n }, [isLoading, messages.length]);\n\n // Restore scroll position after loading more messages\n useEffect(() => {\n if (isLoadingMore) {\n prevScrollHeightRef.current = containerRef.current?.scrollHeight || 0;\n } else if (prevScrollHeightRef.current > 0 && containerRef.current) {\n const newScrollHeight = containerRef.current.scrollHeight;\n const scrollDiff = newScrollHeight - prevScrollHeightRef.current;\n containerRef.current.scrollTop = scrollDiff;\n prevScrollHeightRef.current = 0;\n }\n }, [isLoadingMore]);\n\n // Infinite scroll: detect when user scrolls near the top\n const handleScroll = useCallback(() => {\n if (!containerRef.current || !onLoadMore || !hasMore || isLoadingMore) return;\n\n // Only trigger load more if user has actually scrolled (prevents automatic trigger during initial load)\n if (!isUserScrollingRef.current) return;\n\n const { scrollTop } = containerRef.current;\n // Trigger load more when user scrolls within 100px of the top\n if (scrollTop < 100) {\n onLoadMore();\n }\n }, [onLoadMore, hasMore, isLoadingMore]);\n\n // Set up scroll event listener\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n if (messages.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full text-center p-8\">\n <div className=\"text-6xl mb-4\">💬</div>\n <h3 className=\"text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2\">\n No messages yet\n </h3>\n <p className=\"text-sm text-gray-600 dark:text-gray-400\">\n Start the conversation by sending a message below\n </p>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className=\"flex-1 overflow-y-auto p-4 space-y-2\"\n style={{ scrollBehavior: 'smooth' }}\n >\n {/* Loading indicator at the top for infinite scroll */}\n {isLoadingMore && (\n <div className=\"flex justify-center py-4\">\n <Spinner size=\"sm\" />\n </div>\n )}\n\n {/* Load more trigger point */}\n <div ref={loadMoreTriggerRef} />\n\n {messages.map((message) => (\n <MessageItem\n key={message.id}\n message={message}\n currentUser={currentUser}\n showAvatar={true}\n showTimestamp={true}\n />\n ))}\n\n {isTyping && (\n <div className=\"flex gap-2 mb-4\">\n <div className=\"flex-shrink-0\">\n <div className=\"h-8 w-8 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white text-sm font-medium\">\n 🎧\n </div>\n </div>\n <div className=\"flex flex-col items-start\">\n <div className=\"rounded-2xl px-4 py-3 bg-gray-100 dark:bg-gray-800\">\n <div className=\"flex gap-1\">\n <span className=\"w-2 h-2 bg-gray-400 rounded-full animate-bounce\" />\n <span\n className=\"w-2 h-2 bg-gray-400 rounded-full animate-bounce\"\n style={{ animationDelay: '0.1s' }}\n />\n <span\n className=\"w-2 h-2 bg-gray-400 rounded-full animate-bounce\"\n style={{ animationDelay: '0.2s' }}\n />\n </div>\n </div>\n {typingUser && (\n <span className=\"text-xs text-gray-500 dark:text-gray-400 mt-1 px-2\">\n {typingUser} is typing...\n </span>\n )}\n </div>\n </div>\n )}\n\n <div ref={messagesEndRef} />\n </div>\n );\n}\n","import { formatDistanceToNow } from 'date-fns';\nimport ReactMarkdown from 'react-markdown';\nimport type { IMessage, IUser } from '../types';\n\ninterface MessageItemProps {\n message: IMessage;\n currentUser: IUser;\n showAvatar?: boolean;\n showTimestamp?: boolean;\n}\n\nexport function MessageItem({\n message,\n currentUser,\n showAvatar = true,\n showTimestamp = true,\n}: MessageItemProps) {\n const isOwnMessage = message.senderType === currentUser.type;\n const isSystemMessage = message.senderType === 'system';\n const isAIMessage = message.metadata?.isAI === true;\n\n // System messages are centered and styled differently\n if (isSystemMessage) {\n return (\n <div className=\"flex justify-center my-4\">\n <div className=\"px-4 py-2 bg-gray-100 dark:bg-gray-800 rounded-full\">\n <p className=\"text-xs text-gray-600 dark:text-gray-400\">{message.content}</p>\n </div>\n </div>\n );\n }\n\n // Determine the avatar icon to display\n const getAvatarIcon = () => {\n if (isAIMessage) {\n return '🤖'; // Robot icon for AI messages\n }\n if (message.senderType === 'agent') {\n return '🎧'; // Headset icon for human agents\n }\n return '👤'; // User icon for customers\n };\n\n return (\n <div className={`flex gap-2 mb-4 ${!isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}>\n {showAvatar && (\n <div className=\"flex-shrink-0\">\n <div className=\"h-8 w-8 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white text-sm font-medium\">\n {getAvatarIcon()}\n </div>\n </div>\n )}\n\n <div\n className={`flex flex-col max-w-[70%] ${!isOwnMessage ? 'items-end' : 'items-start'}`}\n >\n <div\n className={`rounded-2xl px-4 py-2 ${\n isOwnMessage\n ? 'bg-blue-600 text-white'\n : 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100'\n }`}\n >\n {message.messageType === 'text' && (\n <ReactMarkdown\n components={{\n p: ({ children }) => <p className=\"mb-0\">{children}</p>,\n img: ({ src, alt, ...props }) => (\n <img\n {...props}\n src={src}\n alt={alt}\n className=\"max-w-full h-auto rounded-lg shadow-sm my-2\"\n loading=\"lazy\"\n />\n ),\n a: ({ href, children, ...props }) => (\n <a\n {...props}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`${isOwnMessage ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300'} underline`}\n >\n {children}\n </a>\n ),\n }}\n >\n {message.content}\n </ReactMarkdown>\n )}\n {message.messageType === 'image' && (\n <div>\n <img\n src={message.content}\n alt=\"Attachment\"\n className=\"max-w-full h-auto rounded-lg\"\n loading=\"lazy\"\n />\n </div>\n )}\n {message.messageType === 'file' && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-2xl\">📎</span>\n <a\n href={message.content}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`${isOwnMessage ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700 dark:text-blue-400'} underline`}\n >\n {(message.metadata?.fileName as any) || 'Download file'}\n </a>\n </div>\n )}\n </div>\n\n {showTimestamp && (\n <div\n className={`flex items-center gap-2 mt-1 px-2 ${isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}\n >\n <span className=\"text-xs text-gray-500 dark:text-gray-400\">\n {formatDistanceToNow(new Date(message.createdAt), {\n addSuffix: true,\n })}\n </span>\n {isOwnMessage && message.status && (\n <span className=\"text-xs\">\n {message.status === 'sent' && '✓'}\n {message.status === 'delivered' && '✓✓'}\n {message.status === 'read' && (\n <span className=\"text-blue-600\">✓✓</span>\n )}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Button, TextArea } from '@xcelsior/design-system';\nimport Picker from '@emoji-mart/react';\nimport type { IChatConfig } from '../types';\nimport type { UseFileUploadReturn } from '../hooks/useFileUpload';\n\ninterface ChatInputProps {\n onSend: (message: string) => void;\n onTyping?: (isTyping: boolean) => void;\n config: IChatConfig;\n fileUpload: UseFileUploadReturn;\n disabled?: boolean;\n}\n\nexport function ChatInput({\n onSend,\n onTyping,\n config,\n fileUpload,\n disabled = false,\n}: ChatInputProps) {\n const [message, setMessage] = useState('');\n const [showEmojiPicker, setShowEmojiPicker] = useState(false);\n const [emojiData, setEmojiData] = useState<any>();\n const [emojiPickerPosition, setEmojiPickerPosition] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const textAreaRef = useRef<HTMLTextAreaElement>(null);\n const emojiPickerRef = useRef<HTMLDivElement>(null);\n const emojiButtonRef = useRef<HTMLButtonElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const startTypingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const isTypingRef = useRef<boolean>(false);\n\n const enableEmoji = config.enableEmoji ?? true;\n const enableFileUpload = config.enableFileUpload ?? true;\n\n // Load emoji data\n useEffect(() => {\n if (!enableEmoji) return;\n (async () => {\n try {\n const response = await fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data');\n setEmojiData(await response.json());\n } catch (error) {\n console.error('Failed to load emoji data:', error);\n }\n })();\n }, [enableEmoji]);\n\n // Handle click outside emoji picker\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(event.target as Node)) {\n setShowEmojiPicker(false);\n }\n };\n\n if (showEmojiPicker) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [showEmojiPicker]);\n\n // Cleanup typing timeouts on unmount\n useEffect(() => {\n return () => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n };\n }, []);\n\n // Update emoji picker position on window resize/scroll\n useEffect(() => {\n if (!showEmojiPicker) return;\n\n const updatePosition = () => {\n if (emojiButtonRef.current) {\n const rect = emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 370,\n left: rect.left - 300,\n });\n }\n };\n\n window.addEventListener('resize', updatePosition);\n window.addEventListener('scroll', updatePosition, true);\n\n return () => {\n window.removeEventListener('resize', updatePosition);\n window.removeEventListener('scroll', updatePosition, true);\n };\n }, [showEmojiPicker]);\n\n const handleTyping = (value: string) => {\n setMessage(value);\n\n // Send typing indicator with debouncing\n if (onTyping && config.enableTypingIndicator !== false) {\n // Clear any pending \"start typing\" timeout\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n\n // Clear any pending \"stop typing\" timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n // If not already typing, debounce the start typing event\n if (!isTypingRef.current) {\n startTypingTimeoutRef.current = setTimeout(() => {\n onTyping(true);\n isTypingRef.current = true;\n }, 300); // 300ms debounce for start typing\n }\n\n // Set timeout to stop typing indicator after inactivity\n typingTimeoutRef.current = setTimeout(() => {\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }, 1500); // 1.5s of inactivity to stop typing\n }\n };\n\n const handleSend = () => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage || disabled) return;\n\n onSend(trimmedMessage);\n setMessage('');\n setShowEmojiPicker(false);\n\n // Stop typing indicator\n if (onTyping) {\n // Clear all typing-related timeouts\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n // Send stop typing event if currently typing\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }\n\n // Focus back on textarea\n textAreaRef.current?.focus();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const insertAtCursor = (text: string) => {\n const textarea = textAreaRef.current;\n if (!textarea) {\n setMessage((prev) => prev + text);\n return;\n }\n\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const newValue = message.slice(0, start) + text + message.slice(end);\n setMessage(newValue);\n\n // Set cursor position after inserted text\n setTimeout(() => {\n const newCursorPos = start + text.length;\n textarea.setSelectionRange(newCursorPos, newCursorPos);\n textarea.focus();\n }, 0);\n };\n\n const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (!files || files.length === 0) return;\n\n const file = files[0];\n try {\n config.toast?.info('Uploading file...');\n const uploadedFile = await fileUpload.uploadFile(file);\n if (uploadedFile?.markdown) {\n insertAtCursor(`\\n${uploadedFile.markdown}\\n`);\n config.toast?.success('File uploaded successfully');\n }\n } catch (error: any) {\n console.error('File upload failed:', error);\n config.toast?.error(error.message);\n } finally {\n // Clear the file input\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n }\n };\n\n return (\n <div className=\"border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 p-3\">\n <div className=\"relative flex-1\">\n <div className=\"relative\">\n <TextArea\n ref={textAreaRef}\n value={message}\n onChange={(e) => handleTyping(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a message...\"\n rows={1}\n className=\"resize-none pr-24 pl-4 py-3 rounded-full bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-sm leading-5 placeholder-gray-500 dark:placeholder-gray-400\"\n disabled={disabled}\n />\n\n {/* Actions inside the input on the right */}\n <div className=\"absolute right-12 top-1/2 -translate-y-1/2 flex items-center gap-1\">\n {enableEmoji && (\n <div className=\"relative\">\n <button\n ref={emojiButtonRef}\n type=\"button\"\n onClick={() => {\n if (!showEmojiPicker && emojiButtonRef.current) {\n const rect =\n emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 450,\n left: rect.left - 290,\n });\n }\n setShowEmojiPicker((v) => !v);\n }}\n className=\"p-1.5 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors\"\n disabled={disabled}\n aria-label=\"Add emoji\"\n >\n <span className=\"text-lg\">😊</span>\n </button>\n </div>\n )}\n\n {enableFileUpload && fileUpload.canUpload && (\n <>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n className=\"p-1.5 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors\"\n disabled={disabled || fileUpload.isUploading}\n aria-label=\"Attach file\"\n >\n {fileUpload.isUploading ? (\n <span className=\"text-lg animate-spin\">⏳</span>\n ) : (\n <span className=\"text-lg\">📎</span>\n )}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*,application/pdf,.doc,.docx\"\n className=\"hidden\"\n onChange={handleFileSelect}\n />\n </>\n )}\n </div>\n\n {/* Send button positioned inside the input at far right */}\n <div className=\"absolute right-2 top-1/2 -translate-y-1/2\">\n <Button\n onClick={handleSend}\n disabled={!message.trim() || disabled}\n variant=\"primary\"\n size=\"sm\"\n className=\"h-9 w-9 p-0 rounded-full flex items-center justify-center shadow-sm\"\n >\n <span className=\"flex items-center justify-center\">\n <svg\n className=\"w-4 h-4 rotate-90\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Send icon</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 19l9 2-9-18-9 18 9-2zm0 0v-8\"\n />\n </svg>\n </span>\n </Button>\n </div>\n </div>\n </div>\n\n {fileUpload.isUploading && (\n <div className=\"mt-2\">\n <div className=\"w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1.5\">\n <div\n className=\"bg-blue-600 h-1.5 rounded-full transition-all duration-300\"\n style={{ width: `${fileUpload.uploadProgress}%` }}\n />\n </div>\n <p className=\"text-xs text-gray-600 dark:text-gray-400 mt-1\">\n Uploading... {fileUpload.uploadProgress}%\n </p>\n </div>\n )}\n\n {/* Emoji picker portal */}\n {showEmojiPicker &&\n emojiData &&\n emojiPickerPosition &&\n typeof document !== 'undefined' &&\n createPortal(\n <div\n ref={emojiPickerRef}\n className=\"fixed rounded-lg border bg-white dark:bg-gray-800 dark:border-gray-700 shadow-xl\"\n style={{\n top: `${emojiPickerPosition.top}px`,\n left: `${emojiPickerPosition.left}px`,\n zIndex: 9999,\n }}\n >\n <Picker\n data={emojiData}\n onEmojiSelect={(emoji: any) => {\n insertAtCursor(emoji.native || emoji.shortcodes || '');\n setShowEmojiPicker(false);\n }}\n previewPosition=\"none\"\n skinTonePosition=\"none\"\n navPosition=\"bottom\"\n perLine={8}\n searchPosition=\"sticky\"\n theme=\"auto\"\n />\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { ChatWidget } from './ChatWidget';\nimport { PreChatForm } from './PreChatForm';\nimport type { IChatConfig, IUser } from '../types';\nimport { useChatWidgetState } from '../hooks/useChatWidgetState';\nimport type { ChatWidgetState } from '../hooks/useChatWidgetState';\n\ninterface ChatWidgetWrapperProps {\n /**\n * Base configuration for the chat widget (without user info and conversationId)\n */\n config: Omit<IChatConfig, 'currentUser' | 'conversationId' | 'userId'> & {\n currentUser?: Partial<IUser>;\n conversationId?: string;\n };\n /**\n * Custom className for the wrapper\n */\n className?: string;\n /**\n * Storage key prefix for persisting user data\n * Defaults to 'xcelsior_chat'\n */\n storageKeyPrefix?: string;\n /**\n * Callback when user submits the pre-chat form\n */\n onPreChatSubmit?: (user: IUser) => void;\n /**\n * Controlled state. When provided, the component is controlled.\n * - 'open': Fully open with chat interface\n * - 'minimized': Show bubble button only\n * - 'closed': Fully hidden\n */\n state?: ChatWidgetState;\n /**\n * Default state for uncontrolled mode\n * @default 'minimized'\n */\n defaultState?: ChatWidgetState;\n /**\n * Callback when state changes\n */\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\ninterface StoredUserData {\n name: string;\n email: string;\n conversationId: string;\n timestamp: number;\n}\n\n/**\n * Generates a unique session-based ID\n */\nfunction generateSessionId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\n/**\n * Chat component that handles:\n * - Automatic conversation ID generation\n * - Pre-chat form for collecting user information\n * - Session persistence in localStorage\n */\nexport function Chat({\n config,\n className = '',\n storageKeyPrefix = 'xcelsior_chat',\n onPreChatSubmit,\n state,\n defaultState = 'minimized',\n onStateChange,\n}: ChatWidgetWrapperProps) {\n const [userInfo, setUserInfo] = useState<IUser | null>(null);\n const [conversationId, setConversationId] = useState<string>('');\n const [isLoading, setIsLoading] = useState(true);\n\n // Centralized state management using the custom hook\n const { currentState, setState } = useChatWidgetState({\n state,\n defaultState,\n onStateChange,\n });\n\n // Initialize user data from localStorage or generate new session\n useEffect(() => {\n const initializeSession = () => {\n try {\n // Check if user provided initial data\n if (config.currentUser?.email && config.currentUser?.name) {\n const convId = config.conversationId || generateSessionId();\n\n const user: IUser = {\n name: config.currentUser.name,\n email: config.currentUser.email,\n avatar: config.currentUser.avatar,\n type: 'customer',\n status: config.currentUser.status,\n };\n\n setUserInfo(user);\n setConversationId(convId);\n setIsLoading(false);\n return;\n }\n\n // Try to load from localStorage\n const storedDataJson = localStorage.getItem(`${storageKeyPrefix}_user`);\n\n if (storedDataJson) {\n const storedData: StoredUserData = JSON.parse(storedDataJson);\n\n // Check if session is still valid (24 hours)\n const isExpired = Date.now() - storedData.timestamp > 24 * 60 * 60 * 1000;\n\n if (!isExpired && storedData.email && storedData.name) {\n // Restore session\n const user: IUser = {\n name: storedData.name,\n email: storedData.email,\n type: 'customer',\n status: 'online',\n };\n\n setUserInfo(user);\n setConversationId(storedData.conversationId);\n setIsLoading(false);\n return;\n }\n }\n\n const convId = config.conversationId || generateSessionId();\n setConversationId(convId);\n\n // If we have partial user info, use it\n if (config.currentUser?.email && config.currentUser?.name) {\n const user: IUser = {\n name: config.currentUser.name,\n email: config.currentUser.email,\n avatar: config.currentUser.avatar,\n type: 'customer',\n status: 'online',\n };\n setUserInfo(user);\n }\n } catch (error) {\n console.error('Error initializing chat session:', error);\n // Generate fallback IDs\n setConversationId(config.conversationId || generateSessionId());\n } finally {\n setIsLoading(false);\n }\n };\n\n initializeSession();\n }, [config, storageKeyPrefix]);\n\n // Handle pre-chat form submission\n const handlePreChatSubmit = useCallback(\n (name: string, email: string) => {\n const convId = conversationId || generateSessionId();\n\n const user: IUser = {\n name,\n email,\n type: 'customer',\n status: 'online',\n };\n\n // Store in localStorage\n const storageData: StoredUserData = {\n name,\n email,\n conversationId: convId,\n timestamp: Date.now(),\n };\n\n try {\n localStorage.setItem(`${storageKeyPrefix}_user`, JSON.stringify(storageData));\n } catch (error) {\n console.error('Error storing user data:', error);\n }\n\n setUserInfo(user);\n setConversationId(convId);\n onPreChatSubmit?.(user);\n },\n [conversationId, storageKeyPrefix, onPreChatSubmit]\n );\n\n // Show loading state\n if (isLoading) {\n return null; // Or you could show a loading spinner\n }\n\n // Handle closed state - fully hidden\n if (currentState === 'closed') {\n return null;\n }\n\n // Handle minimized state - show bubble button only\n if (currentState === 'minimized') {\n return (\n <div className={`fixed bottom-4 right-4 z-50 ${className}`}>\n <button\n type=\"button\"\n onClick={() => setState('open')}\n className=\"h-14 w-14 rounded-full bg-gradient-to-r from-blue-600 to-purple-600 text-white shadow-lg hover:shadow-xl transition-all flex items-center justify-center relative\"\n aria-label=\"Open chat\"\n >\n <span className=\"text-2xl\">💬</span>\n </button>\n </div>\n );\n }\n\n // Open state - show either pre-chat form or chat widget\n // Show pre-chat form if user info is not available\n if (!userInfo || !userInfo.email || !userInfo.name) {\n return (\n <PreChatForm\n onSubmit={handlePreChatSubmit}\n className={className}\n initialName={config.currentUser?.name}\n initialEmail={config.currentUser?.email}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n />\n );\n }\n\n // Show chat widget with complete config\n const fullConfig: IChatConfig = {\n ...config,\n conversationId,\n currentUser: userInfo,\n };\n\n return (\n <ChatWidget\n config={fullConfig}\n className={className}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n />\n );\n}\n","import { useState } from 'react';\n\ninterface PreChatFormProps {\n onSubmit: (name: string, email: string) => void;\n className?: string;\n initialName?: string;\n initialEmail?: string;\n /**\n * Callback when user wants to minimize the form\n */\n onMinimize: () => void;\n /**\n * Callback when user wants to close the form\n */\n onClose: () => void;\n}\n\n/**\n * PreChatForm component for collecting user information before starting chat\n */\nexport function PreChatForm({\n onSubmit,\n className = '',\n initialName = '',\n initialEmail = '',\n onMinimize,\n onClose,\n}: PreChatFormProps) {\n const [name, setName] = useState(initialName);\n const [email, setEmail] = useState(initialEmail);\n const [errors, setErrors] = useState<{ name?: string; email?: string }>({});\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const validateForm = (): boolean => {\n const newErrors: { name?: string; email?: string } = {};\n\n // Validate name\n if (!name.trim()) {\n newErrors.name = 'Name is required';\n } else if (name.trim().length < 2) {\n newErrors.name = 'Name must be at least 2 characters';\n }\n\n // Validate email\n if (!email.trim()) {\n newErrors.email = 'Email is required';\n } else {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n newErrors.email = 'Please enter a valid email address';\n }\n }\n\n setErrors(newErrors);\n return Object.keys(newErrors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) {\n return;\n }\n\n setIsSubmitting(true);\n try {\n onSubmit(name.trim(), email.trim());\n } catch (error) {\n console.error('Error submitting form:', error);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Show full form\n return (\n <div\n className={`fixed bottom-4 right-4 z-50 flex flex-col bg-white dark:bg-gray-900 rounded-lg shadow-2xl overflow-hidden ${className}`}\n style={{\n width: '400px',\n maxHeight: 'calc(100vh - 2rem)',\n }}\n >\n {/* Header */}\n <div className=\"bg-gradient-to-r from-blue-600 to-purple-600 text-white px-6 py-4\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <h2 className=\"text-lg font-semibold\">Start a Conversation</h2>\n <p className=\"text-sm text-blue-100 mt-1\">\n Please provide your details to continue\n </p>\n </div>\n <div className=\"flex gap-2 ml-2\">\n {/* Minimize Button */}\n <button\n type=\"button\"\n onClick={onMinimize}\n className=\"text-white hover:bg-white/20 rounded p-1 transition-colors\"\n aria-label=\"Minimize chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Minimize</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M20 12H4\"\n />\n </svg>\n </button>\n {/* Close Button */}\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-white hover:bg-white/20 rounded p-1 transition-colors\"\n aria-label=\"Close chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Close</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"p-6 space-y-5\">\n {/* Name Input */}\n <div>\n <label\n htmlFor=\"chat-name\"\n className=\"block mb-2 text-sm font-medium text-gray-900 dark:text-gray-200\"\n >\n Name <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"chat-name\"\n value={name}\n onChange={(e) => {\n setName(e.target.value);\n if (errors.name) {\n setErrors((prev) => ({ ...prev, name: undefined }));\n }\n }}\n className={`block w-full px-4 py-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border ${\n errors.name\n ? 'border-red-500 focus:ring-red-500 focus:border-red-500'\n : 'border-gray-300 focus:ring-blue-500 focus:border-blue-500'\n } dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500`}\n placeholder=\"John Doe\"\n disabled={isSubmitting}\n autoComplete=\"name\"\n />\n {errors.name && (\n <p className=\"mt-2 text-sm text-red-600 dark:text-red-500\" role=\"alert\">\n {errors.name}\n </p>\n )}\n </div>\n\n {/* Email Input */}\n <div>\n <label\n htmlFor=\"chat-email\"\n className=\"block mb-2 text-sm font-medium text-gray-900 dark:text-gray-200\"\n >\n Email <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"email\"\n id=\"chat-email\"\n value={email}\n onChange={(e) => {\n setEmail(e.target.value);\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }));\n }\n }}\n className={`block w-full px-4 py-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border ${\n errors.email\n ? 'border-red-500 focus:ring-red-500 focus:border-red-500'\n : 'border-gray-300 focus:ring-blue-500 focus:border-blue-500'\n } dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500`}\n placeholder=\"john@example.com\"\n disabled={isSubmitting}\n autoComplete=\"email\"\n />\n {errors.email && (\n <p className=\"mt-2 text-sm text-red-600 dark:text-red-500\" role=\"alert\">\n {errors.email}\n </p>\n )}\n </div>\n\n {/* Submit Button */}\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className=\"w-full px-5 py-2.5 text-sm font-medium text-white bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg hover:from-blue-700 hover:to-purple-700 focus:outline-none focus:ring-4 focus:ring-blue-300 disabled:opacity-50 disabled:cursor-not-allowed transition-all\"\n >\n {isSubmitting ? (\n <span className=\"flex items-center justify-center\">\n <svg\n className=\"animate-spin -ml-1 mr-3 h-5 w-5 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n >\n <title>Loading</title>\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n Starting Chat...\n </span>\n ) : (\n 'Start Chat'\n )}\n </button>\n\n {/* Privacy Notice */}\n <p className=\"text-xs text-gray-500 dark:text-gray-400 text-center\">\n We respect your privacy. Your information will only be used to assist you.\n </p>\n </form>\n\n {/* Footer */}\n <div className=\"bg-gray-50 dark:bg-gray-950 px-4 py-2 text-center border-t border-gray-200 dark:border-gray-700\">\n <p className=\"text-xs text-gray-500 dark:text-gray-400\">\n Powered by <span className=\"font-semibold\">Xcelsior Chat</span>\n </p>\n </div>\n </div>\n );\n}\n","import { useCallback, useState } from 'react';\n\nexport type ChatWidgetState = 'open' | 'minimized' | 'closed' | 'undefined';\n\nexport interface UseChatWidgetStateOptions {\n /**\n * Controlled state. When provided, the component is controlled.\n */\n state?: ChatWidgetState;\n /**\n * Default state for uncontrolled mode\n * @default 'minimized'\n */\n defaultState?: ChatWidgetState;\n /**\n * Callback when state changes\n */\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\nexport interface UseChatWidgetStateReturn {\n /**\n * Current state of the widget\n */\n currentState: ChatWidgetState;\n /**\n * Function to update the state\n */\n setState: (newState: ChatWidgetState) => void;\n /**\n * Whether the state is controlled\n */\n isControlled: boolean;\n}\n\n/**\n * Hook to manage chat widget state (controlled vs uncontrolled)\n * Encapsulates the logic for handling both controlled and uncontrolled state patterns\n */\nexport function useChatWidgetState({\n state: controlledState,\n defaultState = 'minimized',\n onStateChange,\n}: UseChatWidgetStateOptions): UseChatWidgetStateReturn {\n // Handle controlled vs uncontrolled state\n const [uncontrolledState, setUncontrolledState] = useState<ChatWidgetState>(defaultState);\n const isControlled = controlledState !== undefined && controlledState !== 'undefined';\n const currentState = isControlled ? controlledState : uncontrolledState;\n\n // State setter that works for both controlled and uncontrolled modes\n const setState = useCallback(\n (newValue: ChatWidgetState) => {\n // Update internal state if uncontrolled\n if (!isControlled) {\n setUncontrolledState(newValue);\n }\n // Always call the change handler if provided\n onStateChange?.(newValue);\n },\n [isControlled, onStateChange]\n );\n\n return {\n currentState,\n setState,\n isControlled,\n };\n}\n","interface TypingIndicatorProps {\n isTyping: boolean;\n userName?: string;\n}\n\nexport function TypingIndicator({ isTyping, userName }: TypingIndicatorProps) {\n if (!isTyping) {\n return null;\n }\n\n return (\n <div className=\"px-4 py-2 bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex gap-1\">\n <span className=\"w-2 h-2 bg-blue-500 rounded-full animate-bounce\" />\n <span\n className=\"w-2 h-2 bg-blue-500 rounded-full animate-bounce\"\n style={{ animationDelay: '0.1s' }}\n />\n <span\n className=\"w-2 h-2 bg-blue-500 rounded-full animate-bounce\"\n style={{ animationDelay: '0.2s' }}\n />\n </div>\n <span className=\"text-xs text-gray-600 dark:text-gray-400\">\n {userName ? `${userName} is typing...` : 'Someone is typing...'}\n </span>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","error","useCallback","useEffect","useState","useState","useEffect","error","useCallback","useState","axios","error","useEffect","useState","useEffect","useRef","useCallback","jsx","jsxs","jsx","jsxs","useRef","useEffect","useCallback","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useCallback","isTyping","useEffect","useCallback","useEffect","useState","useState","jsx","jsxs","useCallback","useState","jsx","useState","useEffect","convId","useCallback","jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/components/ChatWidget.tsx","../src/hooks/useWebSocket.ts","../src/hooks/useMessages.ts","../src/utils/api.ts","../src/hooks/useFileUpload.ts","../src/hooks/useTypingIndicator.ts","../src/components/ChatHeader.tsx","../src/components/MessageList.tsx","../src/components/MessageItem.tsx","../src/components/ChatInput.tsx","../src/components/Chat.tsx","../src/components/PreChatForm.tsx","../src/hooks/useChatWidgetState.ts","../src/components/TypingIndicator.tsx"],"sourcesContent":["import { useCallback, useEffect } from 'react';\nimport { useWebSocket } from '../hooks/useWebSocket';\nimport { useMessages } from '../hooks/useMessages';\nimport { useFileUpload } from '../hooks/useFileUpload';\nimport { useTypingIndicator } from '../hooks/useTypingIndicator';\nimport { ChatHeader } from './ChatHeader';\nimport { MessageList } from './MessageList';\nimport { ChatInput } from './ChatInput';\nimport type { IChatConfig, IMessage } from '../types';\n\nexport interface ChatWidgetProps {\n config: IChatConfig;\n className?: string;\n /**\n * Variant of the chat widget:\n * - 'popover': Fixed positioned floating widget (default)\n * - 'fullPage': Full page layout that fills the container\n */\n variant?: 'popover' | 'fullPage';\n /**\n * External WebSocket connection (for agents with global connection)\n */\n externalWebSocket?: WebSocket | null;\n /**\n * Callback when user wants to minimize the widget\n */\n onMinimize?: () => void;\n /**\n * Callback when user wants to close the widget\n */\n onClose?: () => void;\n}\n\nexport function ChatWidget({\n config,\n className = '',\n variant = 'popover',\n externalWebSocket,\n onMinimize,\n onClose,\n}: ChatWidgetProps) {\n const isFullPage = variant === 'fullPage';\n\n // Initialize WebSocket connection (or use external one)\n const websocket = useWebSocket(config, externalWebSocket);\n\n // Initialize messages\n const { messages, addMessage, isLoading, loadMore, hasMore, isLoadingMore } = useMessages(\n websocket,\n config\n );\n\n // Initialize file upload\n const fileUpload = useFileUpload(config.apiKey, config.fileUpload);\n\n // Initialize typing indicator\n const { isTyping, typingUsers } = useTypingIndicator(websocket);\n\n // Handle sending messages\n const handleSendMessage = useCallback(\n (content: string) => {\n if (!websocket.isConnected) {\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n // Create optimistic message\n const optimisticMessage: IMessage = {\n id: `temp-${Date.now()}`,\n conversationId: config.conversationId || '',\n senderId: config.currentUser.email,\n senderType: config.currentUser.type,\n content,\n messageType: 'text',\n createdAt: new Date().toISOString(),\n status: 'sent',\n };\n\n // Add to local state immediately (optimistic update)\n addMessage(optimisticMessage);\n\n // Send via WebSocket\n websocket.sendMessage('sendMessage', {\n conversationId: config.conversationId,\n content,\n messageType: 'text',\n });\n\n // Call callback\n config.onMessageSent?.(optimisticMessage);\n },\n [websocket, config, addMessage]\n );\n\n // Handle typing indicator\n const handleTyping = useCallback(\n (isTyping: boolean) => {\n if (!websocket.isConnected || config.enableTypingIndicator === false) {\n return;\n }\n\n websocket.sendMessage('typing', {\n conversationId: config.conversationId,\n isTyping,\n });\n },\n [websocket, config]\n );\n\n // Handle errors\n useEffect(() => {\n if (websocket.error) {\n config.toast?.error(websocket.error.message || 'An error occurred');\n }\n }, [websocket.error, config]);\n\n // Container styles based on variant\n const containerClasses = isFullPage\n ? `flex flex-col bg-white dark:bg-gray-900 h-full ${className}`\n : `fixed bottom-4 right-4 z-50 flex flex-col bg-white dark:bg-gray-900 rounded-lg shadow-2xl overflow-hidden ${className}`;\n\n const containerStyle = isFullPage\n ? undefined\n : {\n width: '400px',\n height: '600px',\n maxHeight: 'calc(100vh - 2rem)',\n };\n\n return (\n <div className={containerClasses} style={containerStyle}>\n {!isFullPage && (\n <ChatHeader\n agent={\n config.currentUser.type === 'customer'\n ? {\n email: 'contact@xcelsior.co',\n name: 'Support Agent',\n type: 'agent',\n status: websocket.isConnected ? 'online' : 'offline',\n }\n : undefined\n }\n onMinimize={onMinimize}\n onClose={onClose}\n />\n )}\n\n {/* Connection Status */}\n {!websocket.isConnected && (\n <div className=\"bg-yellow-50 dark:bg-yellow-900/30 border-b border-yellow-200 dark:border-yellow-800 px-4 py-2\">\n <div className=\"flex items-center gap-2\">\n <div className=\"w-2 h-2 rounded-full bg-yellow-500 animate-pulse\" />\n <span className=\"text-sm text-yellow-800 dark:text-yellow-200\">\n Reconnecting...\n </span>\n <button\n type=\"button\"\n onClick={websocket.reconnect}\n className=\"ml-auto text-xs text-yellow-700 dark:text-yellow-300 hover:underline\"\n >\n Retry\n </button>\n </div>\n </div>\n )}\n\n {/* Messages */}\n {isLoading ? (\n <div className=\"flex-1 flex items-center justify-center\">\n <div className=\"text-center\">\n <div className=\"w-8 h-8 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-2\" />\n <p className=\"text-sm text-gray-600 dark:text-gray-400\">\n Loading messages...\n </p>\n </div>\n </div>\n ) : (\n <MessageList\n messages={messages}\n currentUser={config.currentUser}\n isTyping={isTyping}\n typingUser={typingUsers[0]}\n autoScroll={true}\n onLoadMore={loadMore}\n hasMore={hasMore}\n isLoadingMore={isLoadingMore}\n />\n )}\n\n {/* Input */}\n <ChatInput\n onSend={handleSendMessage}\n onTyping={handleTyping}\n config={config}\n fileUpload={fileUpload}\n disabled={!websocket.isConnected}\n />\n\n {/* Powered by footer - only for popover */}\n {!isFullPage && (\n <div className=\"bg-gray-50 dark:bg-gray-950 px-4 py-2 text-center border-t border-gray-200 dark:border-gray-700\">\n <p className=\"text-xs text-gray-500 dark:text-gray-400\">\n Powered by <span className=\"font-semibold\">Xcelsior Chat</span>\n </p>\n </div>\n )}\n </div>\n );\n}\n","import { useEffect, useRef, useState, useCallback } from 'react';\nimport type { IChatConfig, IWebSocketMessage } from '../types';\n\nexport interface UseWebSocketReturn {\n isConnected: boolean;\n sendMessage: (action: string, data: any) => void;\n lastMessage: IWebSocketMessage | null;\n error: Error | null;\n reconnect: () => void;\n}\n\n/**\n * Hook for WebSocket connection in chat widget.\n * Can use an external WebSocket connection (for agents) via the externalWebSocket prop.\n */\nexport function useWebSocket(\n config: IChatConfig,\n externalWebSocket?: WebSocket | null\n): UseWebSocketReturn {\n const [isConnected, setIsConnected] = useState(false);\n const [lastMessage, setLastMessage] = useState<IWebSocketMessage | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const wsRef = useRef<WebSocket | null>(null);\n const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const reconnectAttemptsRef = useRef(0);\n const messageHandlerRef = useRef<((event: MessageEvent) => void) | null>(null);\n const maxReconnectAttempts = 5;\n const reconnectDelay = 3000;\n\n // Use external WebSocket if provided (for agents)\n const isUsingExternalWs = !!externalWebSocket;\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const subscribeToMessage = useCallback((webSocket: WebSocket) => {\n // Remove previous listener if it exists\n if (messageHandlerRef.current) {\n webSocket.removeEventListener('message', messageHandlerRef.current);\n }\n\n // Create new message handler\n const handler = (event: MessageEvent) => {\n try {\n const message: IWebSocketMessage = JSON.parse(event.data);\n setLastMessage(message);\n\n // Handle different message types\n if (message.type === 'message' && message.data) {\n config.onMessageReceived?.(message.data);\n } else if (message.type === 'error') {\n const err = new Error(message.data?.message || 'WebSocket error');\n setError(err);\n config.onError?.(err);\n }\n } catch (err) {\n console.error('Failed to parse WebSocket message:', err);\n }\n };\n\n // Add the new listener\n webSocket.addEventListener('message', handler);\n messageHandlerRef.current = handler;\n\n // Return cleanup function\n return () => {\n webSocket.removeEventListener('message', handler);\n if (messageHandlerRef.current === handler) {\n messageHandlerRef.current = null;\n }\n };\n }, []);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: dependencies managed manually\n const connect = useCallback(() => {\n console.log('connecting to WebSocket...', config.currentUser, config.conversationId);\n try {\n // Clean up existing connection\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close();\n }\n\n // Build WebSocket URL with query parameters\n const url = new URL(config.websocketUrl);\n url.searchParams.set('user', JSON.stringify(config.currentUser));\n if (config.conversationId) {\n url.searchParams.set('conversationId', config.conversationId);\n }\n if (config.apiKey) {\n url.searchParams.set('apiKey', config.apiKey);\n }\n\n const ws = new WebSocket(url.toString());\n\n ws.onopen = () => {\n console.log('WebSocket connected');\n setIsConnected(true);\n setError(null);\n reconnectAttemptsRef.current = 0;\n config.onConnectionChange?.(true);\n };\n\n ws.onerror = (event) => {\n console.error('WebSocket error:', event);\n const err = new Error('WebSocket connection error');\n setError(err);\n config.onError?.(err);\n };\n\n ws.onclose = (event) => {\n console.log('WebSocket closed:', event.code, event.reason);\n setIsConnected(false);\n config.onConnectionChange?.(false);\n wsRef.current = null;\n\n // Attempt to reconnect if not a normal closure\n if (event.code !== 1000 && reconnectAttemptsRef.current < maxReconnectAttempts) {\n reconnectAttemptsRef.current += 1;\n console.log(\n `Reconnecting... (${reconnectAttemptsRef.current}/${maxReconnectAttempts})`\n );\n reconnectTimeoutRef.current = setTimeout(() => {\n connect();\n }, reconnectDelay);\n }\n };\n\n subscribeToMessage(ws);\n wsRef.current = ws ?? null;\n } catch (err) {\n console.error('Failed to create WebSocket connection:', err);\n const error = err instanceof Error ? err : new Error('Failed to connect');\n setError(error);\n config.onError?.(error);\n }\n }, [JSON.stringify([config.currentUser, config.conversationId])]);\n\n const sendMessage = useCallback(\n (action: string, data: any) => {\n if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {\n console.error('WebSocket is not connected');\n config.toast?.error('Not connected to chat server');\n return;\n }\n\n try {\n wsRef.current.send(\n JSON.stringify({\n action,\n data,\n })\n );\n } catch (err) {\n console.error('Failed to send message:', err);\n const error = err instanceof Error ? err : new Error('Failed to send message');\n setError(error);\n config.onError?.(error);\n }\n },\n [config]\n );\n\n const reconnect = useCallback(() => {\n reconnectAttemptsRef.current = 0;\n connect();\n }, [connect]);\n\n useEffect(() => {\n if (isUsingExternalWs) {\n setIsConnected(externalWebSocket?.readyState === WebSocket.OPEN || false);\n wsRef.current = externalWebSocket;\n const cleanup = subscribeToMessage(externalWebSocket);\n return cleanup;\n }\n\n connect();\n\n // Cleanup on unmount\n return () => {\n if (reconnectTimeoutRef.current) {\n clearTimeout(reconnectTimeoutRef.current);\n }\n if (wsRef.current) {\n // Remove message listener before closing\n if (messageHandlerRef.current) {\n wsRef.current.removeEventListener('message', messageHandlerRef.current);\n messageHandlerRef.current = null;\n }\n wsRef.current.close(1000, 'Component unmounted');\n }\n };\n }, [connect, isUsingExternalWs, externalWebSocket, subscribeToMessage]);\n\n // Use external connection state if available\n const effectiveIsConnected = isUsingExternalWs\n ? externalWebSocket?.readyState === WebSocket.OPEN || false\n : isConnected;\n\n return {\n isConnected: effectiveIsConnected,\n sendMessage,\n lastMessage,\n error,\n reconnect,\n };\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { IMessage, IChatConfig } from '../types';\nimport type { UseWebSocketReturn } from './useWebSocket';\nimport { fetchMessages } from '../utils/api';\n\nexport interface UseMessagesReturn {\n messages: IMessage[];\n addMessage: (message: IMessage) => void;\n updateMessageStatus: (messageId: string, status: IMessage['status']) => void;\n clearMessages: () => void;\n isLoading: boolean;\n error: Error | null;\n loadMore: () => Promise<void>;\n hasMore: boolean;\n isLoadingMore: boolean;\n}\n\nexport function useMessages(websocket: UseWebSocketReturn, config: IChatConfig): UseMessagesReturn {\n const [messages, setMessages] = useState<IMessage[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [nextPageToken, setNextPageToken] = useState<string | undefined>(undefined);\n const [hasMore, setHasMore] = useState(true);\n const [isLoadingMore, setIsLoadingMore] = useState(false);\n\n // Extract stable references from config\n const { httpApiUrl, conversationId, headers, onError, toast } = config;\n\n const headersWithApiKey = useMemo(\n () => ({\n ...headers,\n 'x-api-key': config.apiKey,\n }),\n [headers, config.apiKey]\n );\n\n // Fetch existing messages when conversationId changes\n useEffect(() => {\n const loadMessages = async () => {\n // Only fetch if we have httpApiUrl and conversationId\n if (!httpApiUrl || !conversationId) {\n return;\n }\n\n setIsLoading(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n { conversationId, limit: 20 },\n headersWithApiKey\n );\n\n setMessages(result.data);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load messages');\n setError(error);\n onError?.(error);\n toast?.error('Failed to load existing messages');\n } finally {\n setIsLoading(false);\n }\n };\n\n loadMessages();\n // Only re-run when conversationId or httpApiUrl changes\n }, [conversationId, httpApiUrl, headersWithApiKey, onError, toast]);\n\n // Extract onMessageReceived callback\n const { onMessageReceived } = config;\n\n // Listen for incoming messages from WebSocket\n useEffect(() => {\n if (websocket.lastMessage?.type === 'message' && websocket.lastMessage.data) {\n const newMessage: IMessage = websocket.lastMessage.data;\n\n if (conversationId && newMessage.conversationId !== conversationId) {\n // Ignore messages for other conversations\n return;\n }\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === newMessage.id)) {\n return prev;\n }\n return [...prev, newMessage];\n });\n\n // Notify parent component about new message\n onMessageReceived?.(newMessage);\n }\n }, [websocket.lastMessage, onMessageReceived, conversationId]);\n\n const addMessage = useCallback((message: IMessage) => {\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((msg) => msg.id === message.id)) {\n return prev;\n }\n return [...prev, message];\n });\n }, []);\n\n const updateMessageStatus = useCallback((messageId: string, status: IMessage['status']) => {\n setMessages((prev) => prev.map((msg) => (msg.id === messageId ? { ...msg, status } : msg)));\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n }, []);\n\n const loadMore = useCallback(async () => {\n if (!hasMore || isLoadingMore || !httpApiUrl || !conversationId || !nextPageToken) {\n return;\n }\n\n setIsLoadingMore(true);\n setError(null);\n\n try {\n const result = await fetchMessages(\n httpApiUrl,\n {\n conversationId,\n limit: 20,\n pageToken: nextPageToken,\n },\n headersWithApiKey\n );\n\n setMessages((prev) => [...result.data, ...prev]);\n setNextPageToken(result.nextPageToken);\n setHasMore(!!result.nextPageToken);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to load more messages');\n setError(error);\n onError?.(error);\n } finally {\n setIsLoadingMore(false);\n }\n }, [\n hasMore,\n isLoadingMore,\n httpApiUrl,\n conversationId,\n nextPageToken,\n headersWithApiKey,\n onError,\n ]);\n\n return {\n messages,\n addMessage,\n updateMessageStatus,\n clearMessages,\n isLoading,\n error,\n loadMore,\n hasMore,\n isLoadingMore,\n };\n}\n","import axios from 'axios';\nimport type { IMessage, IApiResponse } from '../types';\n\nexport interface FetchMessagesParams {\n conversationId: string;\n limit?: number;\n pageToken?: string;\n}\n\n/**\n * Fetch messages for a conversation from the REST API\n */\nexport async function fetchMessages(\n baseUrl: string,\n params: FetchMessagesParams,\n headers?: Record<string, string>\n) {\n try {\n const response = await axios.get<IApiResponse<IMessage[]>>(`${baseUrl}/messages`, {\n params: {\n conversationId: params.conversationId,\n limit: params.limit || 50,\n pageToken: params.pageToken,\n },\n headers: {\n 'Content-Type': 'application/json',\n ...headers,\n },\n });\n\n return {\n data: response.data.data ?? [],\n nextPageToken: response.data.pagination?.nextPageToken,\n };\n } catch (error) {\n if (axios.isAxiosError(error)) {\n throw new Error(\n error.response?.data?.error?.message || error.message || 'Failed to fetch messages'\n );\n }\n throw error;\n }\n}\n","import { useState } from 'react';\nimport axios from 'axios';\nimport type { IFileUploadConfig, IUploadedFile } from '../types';\n\nexport interface UseFileUploadReturn {\n uploadFile: (file: File) => Promise<IUploadedFile | null>;\n isUploading: boolean;\n uploadProgress: number;\n error: Error | null;\n canUpload: boolean;\n}\n\nexport function useFileUpload(apiKey: string, config?: IFileUploadConfig): UseFileUploadReturn {\n const [isUploading, setIsUploading] = useState(false);\n const [uploadProgress, setUploadProgress] = useState(0);\n const [error, setError] = useState<Error | null>(null);\n\n const defaultConfig = {\n maxFileSize: 10 * 1024 * 1024, // 10MB default\n allowedTypes: [\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'text/plain',\n 'text/csv',\n ],\n };\n\n const finalConfig = { ...defaultConfig, ...config };\n const canUpload = !!config?.uploadUrl;\n\n const validateFile = (file: File): string | null => {\n if (!finalConfig.allowedTypes.includes(file.type)) {\n return `File type ${file.type} is not supported. Allowed types: ${finalConfig.allowedTypes.join(', ')}`;\n }\n\n if (file.size > finalConfig.maxFileSize) {\n return `File size ${(file.size / 1024 / 1024).toFixed(2)}MB exceeds the maximum allowed size of ${(finalConfig.maxFileSize / 1024 / 1024).toFixed(2)}MB`;\n }\n\n return null;\n };\n\n const uploadFile = async (file: File): Promise<IUploadedFile | null> => {\n if (!config?.uploadUrl) {\n const err = new Error('File upload URL is not configured');\n setError(err);\n throw err;\n }\n\n const validationError = validateFile(file);\n if (validationError) {\n const err = new Error(validationError);\n setError(err);\n throw err;\n }\n\n setIsUploading(true);\n setUploadProgress(0);\n setError(null);\n\n try {\n // Step 1: Get presigned upload URL from the API\n const uploadUrlResponse = await axios.post(\n config.uploadUrl,\n {\n fileName: file.name,\n contentType: file.type,\n fileSize: file.size,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': apiKey || '',\n ...config.headers,\n },\n }\n );\n\n const { uploadUrl, attachmentUrl } =\n uploadUrlResponse.data.data || uploadUrlResponse.data;\n\n if (!uploadUrl || !attachmentUrl) {\n throw new Error('Failed to get upload URL from server');\n }\n\n // Step 2: Upload file directly to S3 using presigned URL\n await axios.put(uploadUrl, file, {\n headers: {\n 'Content-Type': file.type,\n },\n onUploadProgress: (progressEvent) => {\n if (progressEvent.total) {\n const progress = Math.round(\n (progressEvent.loaded * 100) / progressEvent.total\n );\n setUploadProgress(progress);\n }\n },\n });\n\n return {\n url: attachmentUrl,\n name: file.name,\n size: file.size,\n type: file.type,\n markdown: file.type.startsWith('image/')\n ? `![${file.name}](${attachmentUrl})`\n : `[${file.name}](${attachmentUrl})`,\n };\n } catch (err) {\n console.error('File upload failed:', err);\n const error = err instanceof Error ? err : new Error('Upload failed');\n setError(error);\n throw error;\n } finally {\n setIsUploading(false);\n setUploadProgress(0);\n }\n };\n\n return {\n uploadFile,\n isUploading,\n uploadProgress,\n error,\n canUpload,\n };\n}\n","import { useEffect, useState } from 'react';\nimport type { UseWebSocketReturn } from './useWebSocket';\n\nexport interface UseTypingIndicatorReturn {\n isTyping: boolean;\n typingUsers: string[];\n}\n\nexport function useTypingIndicator(websocket: UseWebSocketReturn): UseTypingIndicatorReturn {\n const [typingUsers, setTypingUsers] = useState<string[]>([]);\n\n useEffect(() => {\n if (websocket.lastMessage?.type === 'typing' && websocket.lastMessage.data) {\n const { userId, isTyping } = websocket.lastMessage.data;\n\n if (isTyping) {\n setTypingUsers((prev) => {\n if (!prev.includes(userId)) {\n return [...prev, userId];\n }\n return prev;\n });\n } else {\n setTypingUsers((prev) => prev.filter((id) => id !== userId));\n }\n }\n }, [websocket.lastMessage]);\n\n return {\n isTyping: typingUsers.length > 0,\n typingUsers,\n };\n}\n","import type { IUser } from '../types';\n\ninterface ChatHeaderProps {\n agent?: IUser;\n onClose?: () => void;\n onMinimize?: () => void;\n}\n\nexport function ChatHeader({ agent, onClose, onMinimize }: ChatHeaderProps) {\n return (\n <div className=\"bg-gradient-to-r from-blue-600 to-purple-600 text-white p-4 flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"relative\">\n <div className=\"h-10 w-10 rounded-full bg-white/20 flex items-center justify-center text-lg font-medium\">\n {agent?.avatar ? (\n <img\n src={agent.avatar}\n alt={agent.name}\n className=\"h-10 w-10 rounded-full object-cover\"\n />\n ) : (\n '🎧'\n )}\n </div>\n {agent?.status === 'online' && (\n <div className=\"absolute bottom-0 right-0 h-3 w-3 rounded-full bg-green-500 border-2 border-white\" />\n )}\n </div>\n <div>\n <h3 className=\"font-semibold text-base\">{agent?.name || 'Support Team'}</h3>\n <p className=\"text-xs text-white/80\">\n {agent?.status === 'online'\n ? 'Online'\n : agent?.status === 'away'\n ? 'Away'\n : \"We'll reply as soon as possible\"}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n {onMinimize && (\n <button\n type=\"button\"\n onClick={onMinimize}\n className=\"p-2 hover:bg-white/10 rounded-full transition-colors\"\n aria-label=\"Minimize chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Minimize icon</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M20 12H4\"\n />\n </svg>\n </button>\n )}\n {onClose && (\n <button\n type=\"button\"\n onClick={onClose}\n className=\"p-2 hover:bg-white/10 rounded-full transition-colors\"\n aria-label=\"Close chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Close icon</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n )}\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useCallback } from 'react';\nimport { Spinner } from '@xcelsior/design-system';\nimport { MessageItem } from './MessageItem';\nimport type { IMessage, IUser } from '../types';\n\ninterface MessageListProps {\n messages: IMessage[];\n currentUser: IUser;\n isLoading?: boolean;\n isTyping?: boolean;\n typingUser?: string;\n autoScroll?: boolean;\n onLoadMore?: () => void;\n hasMore?: boolean;\n isLoadingMore?: boolean;\n}\n\nexport function MessageList({\n messages,\n currentUser,\n isLoading = false,\n isTyping = false,\n typingUser,\n autoScroll = true,\n onLoadMore,\n hasMore = false,\n isLoadingMore = false,\n}: MessageListProps) {\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const containerRef = useRef<HTMLDivElement>(null);\n const prevLengthRef = useRef(messages.length);\n const loadMoreTriggerRef = useRef<HTMLDivElement>(null);\n const prevScrollHeightRef = useRef(0);\n const hasInitialScrolledRef = useRef(false);\n const isUserScrollingRef = useRef(false);\n\n // Auto-scroll to bottom when new messages arrive\n useEffect(() => {\n if (autoScroll && messagesEndRef.current) {\n // Only auto-scroll if we're adding new messages (not loading older ones)\n // Skip auto-scroll if we're loading more (older messages)\n if (messages.length > prevLengthRef.current && !isLoadingMore) {\n messagesEndRef.current.scrollIntoView({ behavior: 'smooth' });\n }\n prevLengthRef.current = messages.length;\n }\n }, [messages.length, autoScroll, isLoadingMore]);\n\n // Initial scroll to bottom when messages first load\n useEffect(() => {\n if (\n messages.length > 0 &&\n messagesEndRef.current &&\n !isLoading &&\n !hasInitialScrolledRef.current\n ) {\n // Use setTimeout to ensure DOM is fully rendered\n setTimeout(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'auto' });\n // Enable user scrolling after initial scroll completes\n setTimeout(() => {\n isUserScrollingRef.current = true;\n }, 200);\n }, 100);\n hasInitialScrolledRef.current = true;\n } else if (!isLoading && messages.length === 0 && !hasInitialScrolledRef.current) {\n // If there are no messages, enable user scrolling immediately\n isUserScrollingRef.current = true;\n hasInitialScrolledRef.current = true;\n }\n }, [isLoading, messages.length]);\n\n // Restore scroll position after loading more messages\n useEffect(() => {\n if (isLoadingMore) {\n prevScrollHeightRef.current = containerRef.current?.scrollHeight || 0;\n } else if (prevScrollHeightRef.current > 0 && containerRef.current) {\n const newScrollHeight = containerRef.current.scrollHeight;\n const scrollDiff = newScrollHeight - prevScrollHeightRef.current;\n containerRef.current.scrollTop = scrollDiff;\n prevScrollHeightRef.current = 0;\n }\n }, [isLoadingMore]);\n\n // Infinite scroll: detect when user scrolls near the top\n const handleScroll = useCallback(() => {\n if (!containerRef.current || !onLoadMore || !hasMore || isLoadingMore) return;\n\n // Only trigger load more if user has actually scrolled (prevents automatic trigger during initial load)\n if (!isUserScrollingRef.current) return;\n\n const { scrollTop } = containerRef.current;\n // Trigger load more when user scrolls within 100px of the top\n if (scrollTop < 100) {\n onLoadMore();\n }\n }, [onLoadMore, hasMore, isLoadingMore]);\n\n // Set up scroll event listener\n useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [handleScroll]);\n\n if (isLoading) {\n return (\n <div className=\"flex items-center justify-center h-full\">\n <Spinner size=\"lg\" />\n </div>\n );\n }\n\n if (messages.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center h-full text-center p-8\">\n <div className=\"text-6xl mb-4\">💬</div>\n <h3 className=\"text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2\">\n No messages yet\n </h3>\n <p className=\"text-sm text-gray-600 dark:text-gray-400\">\n Start the conversation by sending a message below\n </p>\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className=\"flex-1 overflow-y-auto p-4 space-y-2\"\n style={{ scrollBehavior: 'smooth' }}\n >\n {/* Loading indicator at the top for infinite scroll */}\n {isLoadingMore && (\n <div className=\"flex justify-center py-4\">\n <Spinner size=\"sm\" />\n </div>\n )}\n\n {/* Load more trigger point */}\n <div ref={loadMoreTriggerRef} />\n\n {messages.map((message) => (\n <MessageItem\n key={message.id}\n message={message}\n currentUser={currentUser}\n showAvatar={true}\n showTimestamp={true}\n />\n ))}\n\n {isTyping && (\n <div className=\"flex gap-2 mb-4\">\n <div className=\"flex-shrink-0\">\n <div className=\"h-8 w-8 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white text-sm font-medium\">\n 🎧\n </div>\n </div>\n <div className=\"flex flex-col items-start\">\n <div className=\"rounded-2xl px-4 py-3 bg-gray-100 dark:bg-gray-800\">\n <div className=\"flex gap-1\">\n <span className=\"w-2 h-2 bg-gray-400 rounded-full animate-bounce\" />\n <span\n className=\"w-2 h-2 bg-gray-400 rounded-full animate-bounce\"\n style={{ animationDelay: '0.1s' }}\n />\n <span\n className=\"w-2 h-2 bg-gray-400 rounded-full animate-bounce\"\n style={{ animationDelay: '0.2s' }}\n />\n </div>\n </div>\n {typingUser && (\n <span className=\"text-xs text-gray-500 dark:text-gray-400 mt-1 px-2\">\n {typingUser} is typing...\n </span>\n )}\n </div>\n </div>\n )}\n\n <div ref={messagesEndRef} />\n </div>\n );\n}\n","import { formatDistanceToNow } from 'date-fns';\nimport ReactMarkdown from 'react-markdown';\nimport type { IMessage, IUser } from '../types';\n\ninterface MessageItemProps {\n message: IMessage;\n currentUser: IUser;\n showAvatar?: boolean;\n showTimestamp?: boolean;\n}\n\nexport function MessageItem({\n message,\n currentUser,\n showAvatar = true,\n showTimestamp = true,\n}: MessageItemProps) {\n const isOwnMessage = message.senderType === currentUser.type;\n const isSystemMessage = message.senderType === 'system';\n const isAIMessage = message.metadata?.isAI === true;\n\n // System messages are centered and styled differently\n if (isSystemMessage) {\n return (\n <div className=\"flex justify-center my-4\">\n <div className=\"px-4 py-2 bg-gray-100 dark:bg-gray-800 rounded-full\">\n <p className=\"text-xs text-gray-600 dark:text-gray-400\">{message.content}</p>\n </div>\n </div>\n );\n }\n\n // Determine the avatar icon to display\n const getAvatarIcon = () => {\n if (isAIMessage) {\n return '🤖'; // Robot icon for AI messages\n }\n if (message.senderType === 'agent') {\n return '🎧'; // Headset icon for human agents\n }\n return '👤'; // User icon for customers\n };\n\n return (\n <div className={`flex gap-2 mb-4 ${!isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}>\n {showAvatar && (\n <div className=\"flex-shrink-0\">\n <div className=\"h-8 w-8 rounded-full bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center text-white text-sm font-medium\">\n {getAvatarIcon()}\n </div>\n </div>\n )}\n\n <div\n className={`flex flex-col max-w-[70%] ${!isOwnMessage ? 'items-end' : 'items-start'}`}\n >\n <div\n className={`rounded-2xl px-4 py-2 ${\n isOwnMessage\n ? 'bg-blue-600 text-white'\n : 'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100'\n }`}\n >\n {message.messageType === 'text' && (\n <ReactMarkdown\n components={{\n p: ({ children }) => <p className=\"mb-0\">{children}</p>,\n img: ({ src, alt, ...props }) => (\n <img\n {...props}\n src={src}\n alt={alt}\n className=\"max-w-full h-auto rounded-lg shadow-sm my-2\"\n loading=\"lazy\"\n />\n ),\n a: ({ href, children, ...props }) => (\n <a\n {...props}\n href={href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`${isOwnMessage ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300'} underline`}\n >\n {children}\n </a>\n ),\n }}\n >\n {message.content}\n </ReactMarkdown>\n )}\n {message.messageType === 'image' && (\n <div>\n <img\n src={message.content}\n alt=\"Attachment\"\n className=\"max-w-full h-auto rounded-lg\"\n loading=\"lazy\"\n />\n </div>\n )}\n {message.messageType === 'file' && (\n <div className=\"flex items-center gap-2\">\n <span className=\"text-2xl\">📎</span>\n <a\n href={message.content}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className={`${isOwnMessage ? 'text-blue-200 hover:text-blue-100' : 'text-blue-600 hover:text-blue-700 dark:text-blue-400'} underline`}\n >\n {(message.metadata?.fileName as any) || 'Download file'}\n </a>\n </div>\n )}\n </div>\n\n {showTimestamp && (\n <div\n className={`flex items-center gap-2 mt-1 px-2 ${isOwnMessage ? 'flex-row-reverse' : 'flex-row'}`}\n >\n <span className=\"text-xs text-gray-500 dark:text-gray-400\">\n {formatDistanceToNow(new Date(message.createdAt), {\n addSuffix: true,\n })}\n </span>\n {isOwnMessage && message.status && (\n <span className=\"text-xs\">\n {message.status === 'sent' && '✓'}\n {message.status === 'delivered' && '✓✓'}\n {message.status === 'read' && (\n <span className=\"text-blue-600\">✓✓</span>\n )}\n </span>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n","import { useEffect, useRef, useState } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Button, TextArea } from '@xcelsior/design-system';\nimport Picker from '@emoji-mart/react';\nimport type { IChatConfig } from '../types';\nimport type { UseFileUploadReturn } from '../hooks/useFileUpload';\n\ninterface ChatInputProps {\n onSend: (message: string) => void;\n onTyping?: (isTyping: boolean) => void;\n config: IChatConfig;\n fileUpload: UseFileUploadReturn;\n disabled?: boolean;\n}\n\nexport function ChatInput({\n onSend,\n onTyping,\n config,\n fileUpload,\n disabled = false,\n}: ChatInputProps) {\n const [message, setMessage] = useState('');\n const [showEmojiPicker, setShowEmojiPicker] = useState(false);\n const [emojiData, setEmojiData] = useState<any>();\n const [emojiPickerPosition, setEmojiPickerPosition] = useState<{\n top: number;\n left: number;\n } | null>(null);\n const textAreaRef = useRef<HTMLTextAreaElement>(null);\n const emojiPickerRef = useRef<HTMLDivElement>(null);\n const emojiButtonRef = useRef<HTMLButtonElement>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const startTypingTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const isTypingRef = useRef<boolean>(false);\n\n const enableEmoji = config.enableEmoji ?? true;\n const enableFileUpload = config.enableFileUpload ?? true;\n\n // Load emoji data\n useEffect(() => {\n if (!enableEmoji) return;\n (async () => {\n try {\n const response = await fetch('https://cdn.jsdelivr.net/npm/@emoji-mart/data');\n setEmojiData(await response.json());\n } catch (error) {\n console.error('Failed to load emoji data:', error);\n }\n })();\n }, [enableEmoji]);\n\n // Handle click outside emoji picker\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (emojiPickerRef.current && !emojiPickerRef.current.contains(event.target as Node)) {\n setShowEmojiPicker(false);\n }\n };\n\n if (showEmojiPicker) {\n document.addEventListener('mousedown', handleClickOutside);\n }\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n };\n }, [showEmojiPicker]);\n\n // Cleanup typing timeouts on unmount\n useEffect(() => {\n return () => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n };\n }, []);\n\n // Update emoji picker position on window resize/scroll\n useEffect(() => {\n if (!showEmojiPicker) return;\n\n const updatePosition = () => {\n if (emojiButtonRef.current) {\n const rect = emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 370,\n left: rect.left - 300,\n });\n }\n };\n\n window.addEventListener('resize', updatePosition);\n window.addEventListener('scroll', updatePosition, true);\n\n return () => {\n window.removeEventListener('resize', updatePosition);\n window.removeEventListener('scroll', updatePosition, true);\n };\n }, [showEmojiPicker]);\n\n const handleTyping = (value: string) => {\n setMessage(value);\n\n // Send typing indicator with debouncing\n if (onTyping && config.enableTypingIndicator !== false) {\n // Clear any pending \"start typing\" timeout\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n\n // Clear any pending \"stop typing\" timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n // If not already typing, debounce the start typing event\n if (!isTypingRef.current) {\n startTypingTimeoutRef.current = setTimeout(() => {\n onTyping(true);\n isTypingRef.current = true;\n }, 300); // 300ms debounce for start typing\n }\n\n // Set timeout to stop typing indicator after inactivity\n typingTimeoutRef.current = setTimeout(() => {\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }, 1500); // 1.5s of inactivity to stop typing\n }\n };\n\n const handleSend = () => {\n const trimmedMessage = message.trim();\n if (!trimmedMessage || disabled) return;\n\n onSend(trimmedMessage);\n setMessage('');\n setShowEmojiPicker(false);\n\n // Stop typing indicator\n if (onTyping) {\n // Clear all typing-related timeouts\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n if (startTypingTimeoutRef.current) {\n clearTimeout(startTypingTimeoutRef.current);\n }\n // Send stop typing event if currently typing\n if (isTypingRef.current) {\n onTyping(false);\n isTypingRef.current = false;\n }\n }\n\n // Focus back on textarea\n textAreaRef.current?.focus();\n };\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const insertAtCursor = (text: string) => {\n const textarea = textAreaRef.current;\n if (!textarea) {\n setMessage((prev) => prev + text);\n return;\n }\n\n const start = textarea.selectionStart;\n const end = textarea.selectionEnd;\n const newValue = message.slice(0, start) + text + message.slice(end);\n setMessage(newValue);\n\n // Set cursor position after inserted text\n setTimeout(() => {\n const newCursorPos = start + text.length;\n textarea.setSelectionRange(newCursorPos, newCursorPos);\n textarea.focus();\n }, 0);\n };\n\n const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files;\n if (!files || files.length === 0) return;\n\n const file = files[0];\n try {\n config.toast?.info('Uploading file...');\n const uploadedFile = await fileUpload.uploadFile(file);\n if (uploadedFile?.markdown) {\n insertAtCursor(`\\n${uploadedFile.markdown}\\n`);\n config.toast?.success('File uploaded successfully');\n }\n } catch (error: any) {\n console.error('File upload failed:', error);\n config.toast?.error(error.message);\n } finally {\n // Clear the file input\n if (fileInputRef.current) {\n fileInputRef.current.value = '';\n }\n }\n };\n\n return (\n <div className=\"border-t border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 p-3\">\n <div className=\"relative flex-1\">\n <div className=\"relative\">\n <TextArea\n ref={textAreaRef}\n value={message}\n onChange={(e) => handleTyping(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"Type a message...\"\n rows={1}\n className=\"resize-none pr-24 pl-4 py-3 rounded-full bg-gray-100 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 text-sm leading-5 placeholder-gray-500 dark:placeholder-gray-400\"\n disabled={disabled}\n />\n\n {/* Actions inside the input on the right */}\n <div className=\"absolute right-12 top-1/2 -translate-y-1/2 flex items-center gap-1\">\n {enableEmoji && (\n <div className=\"relative\">\n <button\n ref={emojiButtonRef}\n type=\"button\"\n onClick={() => {\n if (!showEmojiPicker && emojiButtonRef.current) {\n const rect =\n emojiButtonRef.current.getBoundingClientRect();\n setEmojiPickerPosition({\n top: rect.top - 450,\n left: rect.left - 290,\n });\n }\n setShowEmojiPicker((v) => !v);\n }}\n className=\"p-1.5 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors\"\n disabled={disabled}\n aria-label=\"Add emoji\"\n >\n <span className=\"text-lg\">😊</span>\n </button>\n </div>\n )}\n\n {enableFileUpload && fileUpload.canUpload && (\n <>\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n className=\"p-1.5 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors\"\n disabled={disabled || fileUpload.isUploading}\n aria-label=\"Attach file\"\n >\n {fileUpload.isUploading ? (\n <span className=\"text-lg animate-spin\">⏳</span>\n ) : (\n <span className=\"text-lg\">📎</span>\n )}\n </button>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/*,application/pdf,.doc,.docx\"\n className=\"hidden\"\n onChange={handleFileSelect}\n />\n </>\n )}\n </div>\n\n {/* Send button positioned inside the input at far right */}\n <div className=\"absolute right-2 top-1/2 -translate-y-1/2\">\n <Button\n onClick={handleSend}\n disabled={!message.trim() || disabled}\n variant=\"primary\"\n size=\"sm\"\n className=\"h-9 w-9 p-0 rounded-full flex items-center justify-center shadow-sm\"\n >\n <span className=\"flex items-center justify-center\">\n <svg\n className=\"w-4 h-4 rotate-90\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n aria-hidden=\"true\"\n >\n <title>Send icon</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 19l9 2-9-18-9 18 9-2zm0 0v-8\"\n />\n </svg>\n </span>\n </Button>\n </div>\n </div>\n </div>\n\n {fileUpload.isUploading && (\n <div className=\"mt-2\">\n <div className=\"w-full bg-gray-200 dark:bg-gray-700 rounded-full h-1.5\">\n <div\n className=\"bg-blue-600 h-1.5 rounded-full transition-all duration-300\"\n style={{ width: `${fileUpload.uploadProgress}%` }}\n />\n </div>\n <p className=\"text-xs text-gray-600 dark:text-gray-400 mt-1\">\n Uploading... {fileUpload.uploadProgress}%\n </p>\n </div>\n )}\n\n {/* Emoji picker portal */}\n {showEmojiPicker &&\n emojiData &&\n emojiPickerPosition &&\n typeof document !== 'undefined' &&\n createPortal(\n <div\n ref={emojiPickerRef}\n className=\"fixed rounded-lg border bg-white dark:bg-gray-800 dark:border-gray-700 shadow-xl\"\n style={{\n top: `${emojiPickerPosition.top}px`,\n left: `${emojiPickerPosition.left}px`,\n zIndex: 9999,\n }}\n >\n <Picker\n data={emojiData}\n onEmojiSelect={(emoji: any) => {\n insertAtCursor(emoji.native || emoji.shortcodes || '');\n setShowEmojiPicker(false);\n }}\n previewPosition=\"none\"\n skinTonePosition=\"none\"\n navPosition=\"bottom\"\n perLine={8}\n searchPosition=\"sticky\"\n theme=\"auto\"\n />\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport { ChatWidget } from './ChatWidget';\nimport { PreChatForm } from './PreChatForm';\nimport type { IChatConfig, IUser } from '../types';\nimport { useChatWidgetState } from '../hooks/useChatWidgetState';\nimport type { ChatWidgetState } from '../hooks/useChatWidgetState';\n\ninterface ChatWidgetWrapperProps {\n /**\n * Base configuration for the chat widget (without user info and conversationId)\n */\n config: Omit<IChatConfig, 'currentUser' | 'conversationId' | 'userId'> & {\n currentUser?: Partial<IUser>;\n conversationId?: string;\n };\n /**\n * Custom className for the wrapper\n */\n className?: string;\n /**\n * Storage key prefix for persisting user data\n * Defaults to 'xcelsior_chat'\n */\n storageKeyPrefix?: string;\n /**\n * Callback when user submits the pre-chat form\n */\n onPreChatSubmit?: (user: IUser) => void;\n /**\n * Controlled state. When provided, the component is controlled.\n * - 'open': Fully open with chat interface\n * - 'minimized': Show bubble button only\n * - 'closed': Fully hidden\n */\n state?: ChatWidgetState;\n /**\n * Default state for uncontrolled mode\n * @default 'minimized'\n */\n defaultState?: ChatWidgetState;\n /**\n * Callback when state changes\n */\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\ninterface StoredUserData {\n name: string;\n email: string;\n conversationId: string;\n timestamp: number;\n}\n\n/**\n * Generates a unique session-based ID\n */\nfunction generateSessionId(): string {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\n return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}`;\n}\n\n/**\n * Chat component that handles:\n * - Automatic conversation ID generation\n * - Pre-chat form for collecting user information\n * - Session persistence in localStorage\n */\nexport function Chat({\n config,\n className = '',\n storageKeyPrefix = 'xcelsior_chat',\n onPreChatSubmit,\n state,\n defaultState = 'minimized',\n onStateChange,\n}: ChatWidgetWrapperProps) {\n const [userInfo, setUserInfo] = useState<IUser | null>(null);\n const [conversationId, setConversationId] = useState<string>('');\n const [isLoading, setIsLoading] = useState(true);\n\n // Centralized state management using the custom hook\n const { currentState, setState } = useChatWidgetState({\n state,\n defaultState,\n onStateChange,\n });\n\n // Initialize user data from localStorage or generate new session\n useEffect(() => {\n const initializeSession = () => {\n try {\n // Check if user provided initial data\n if (config.currentUser?.email && config.currentUser?.name) {\n const convId = config.conversationId || generateSessionId();\n\n const user: IUser = {\n name: config.currentUser.name,\n email: config.currentUser.email,\n avatar: config.currentUser.avatar,\n type: 'customer',\n status: config.currentUser.status,\n };\n\n setUserInfo(user);\n setConversationId(convId);\n setIsLoading(false);\n return;\n }\n\n // Try to load from localStorage\n const storedDataJson = localStorage.getItem(`${storageKeyPrefix}_user`);\n\n if (storedDataJson) {\n const storedData: StoredUserData = JSON.parse(storedDataJson);\n\n // Check if session is still valid (24 hours)\n const isExpired = Date.now() - storedData.timestamp > 24 * 60 * 60 * 1000;\n\n if (!isExpired && storedData.email && storedData.name) {\n // Restore session\n const user: IUser = {\n name: storedData.name,\n email: storedData.email,\n type: 'customer',\n status: 'online',\n };\n\n setUserInfo(user);\n setConversationId(storedData.conversationId);\n setIsLoading(false);\n return;\n }\n }\n\n const convId = config.conversationId || generateSessionId();\n setConversationId(convId);\n\n // If we have partial user info, use it\n if (config.currentUser?.email && config.currentUser?.name) {\n const user: IUser = {\n name: config.currentUser.name,\n email: config.currentUser.email,\n avatar: config.currentUser.avatar,\n type: 'customer',\n status: 'online',\n };\n setUserInfo(user);\n }\n } catch (error) {\n console.error('Error initializing chat session:', error);\n // Generate fallback IDs\n setConversationId(config.conversationId || generateSessionId());\n } finally {\n setIsLoading(false);\n }\n };\n\n initializeSession();\n }, [config, storageKeyPrefix]);\n\n // Handle pre-chat form submission\n const handlePreChatSubmit = useCallback(\n (name: string, email: string) => {\n const convId = conversationId || generateSessionId();\n\n const user: IUser = {\n name,\n email,\n type: 'customer',\n status: 'online',\n };\n\n // Store in localStorage\n const storageData: StoredUserData = {\n name,\n email,\n conversationId: convId,\n timestamp: Date.now(),\n };\n\n try {\n localStorage.setItem(`${storageKeyPrefix}_user`, JSON.stringify(storageData));\n } catch (error) {\n console.error('Error storing user data:', error);\n }\n\n setUserInfo(user);\n setConversationId(convId);\n onPreChatSubmit?.(user);\n },\n [conversationId, storageKeyPrefix, onPreChatSubmit]\n );\n\n // Show loading state\n if (isLoading) {\n return null; // Or you could show a loading spinner\n }\n\n // Handle closed state - fully hidden\n if (currentState === 'closed') {\n return null;\n }\n\n // Handle minimized state - show bubble button only\n if (currentState === 'minimized') {\n return (\n <div className={`fixed bottom-4 right-4 z-50 ${className}`}>\n <button\n type=\"button\"\n onClick={() => setState('open')}\n className=\"h-14 w-14 rounded-full bg-gradient-to-r from-blue-600 to-purple-600 text-white shadow-lg hover:shadow-xl transition-all flex items-center justify-center relative\"\n aria-label=\"Open chat\"\n >\n <span className=\"text-2xl\">💬</span>\n </button>\n </div>\n );\n }\n\n // Open state - show either pre-chat form or chat widget\n // Show pre-chat form if user info is not available\n if (!userInfo || !userInfo.email || !userInfo.name) {\n return (\n <PreChatForm\n onSubmit={handlePreChatSubmit}\n className={className}\n initialName={config.currentUser?.name}\n initialEmail={config.currentUser?.email}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n />\n );\n }\n\n // Show chat widget with complete config\n const fullConfig: IChatConfig = {\n ...config,\n conversationId,\n currentUser: userInfo,\n };\n\n return (\n <ChatWidget\n config={fullConfig}\n className={className}\n onClose={() => setState('closed')}\n onMinimize={() => setState('minimized')}\n />\n );\n}\n","import { useState } from 'react';\n\ninterface PreChatFormProps {\n onSubmit: (name: string, email: string) => void;\n className?: string;\n initialName?: string;\n initialEmail?: string;\n /**\n * Callback when user wants to minimize the form\n */\n onMinimize: () => void;\n /**\n * Callback when user wants to close the form\n */\n onClose: () => void;\n}\n\n/**\n * PreChatForm component for collecting user information before starting chat\n */\nexport function PreChatForm({\n onSubmit,\n className = '',\n initialName = '',\n initialEmail = '',\n onMinimize,\n onClose,\n}: PreChatFormProps) {\n const [name, setName] = useState(initialName);\n const [email, setEmail] = useState(initialEmail);\n const [errors, setErrors] = useState<{ name?: string; email?: string }>({});\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const validateForm = (): boolean => {\n const newErrors: { name?: string; email?: string } = {};\n\n // Validate name\n if (!name.trim()) {\n newErrors.name = 'Name is required';\n } else if (name.trim().length < 2) {\n newErrors.name = 'Name must be at least 2 characters';\n }\n\n // Validate email\n if (!email.trim()) {\n newErrors.email = 'Email is required';\n } else {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n newErrors.email = 'Please enter a valid email address';\n }\n }\n\n setErrors(newErrors);\n return Object.keys(newErrors).length === 0;\n };\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n\n if (!validateForm()) {\n return;\n }\n\n setIsSubmitting(true);\n try {\n onSubmit(name.trim(), email.trim());\n } catch (error) {\n console.error('Error submitting form:', error);\n } finally {\n setIsSubmitting(false);\n }\n };\n\n // Show full form\n return (\n <div\n className={`fixed bottom-4 right-4 z-50 flex flex-col bg-white dark:bg-gray-900 rounded-lg shadow-2xl overflow-hidden ${className}`}\n style={{\n width: '400px',\n maxHeight: 'calc(100vh - 2rem)',\n }}\n >\n {/* Header */}\n <div className=\"bg-gradient-to-r from-blue-600 to-purple-600 text-white px-6 py-4\">\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <h2 className=\"text-lg font-semibold\">Start a Conversation</h2>\n <p className=\"text-sm text-blue-100 mt-1\">\n Please provide your details to continue\n </p>\n </div>\n <div className=\"flex gap-2 ml-2\">\n {/* Minimize Button */}\n <button\n type=\"button\"\n onClick={onMinimize}\n className=\"text-white hover:bg-white/20 rounded p-1 transition-colors\"\n aria-label=\"Minimize chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Minimize</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M20 12H4\"\n />\n </svg>\n </button>\n {/* Close Button */}\n <button\n type=\"button\"\n onClick={onClose}\n className=\"text-white hover:bg-white/20 rounded p-1 transition-colors\"\n aria-label=\"Close chat\"\n >\n <svg\n className=\"w-5 h-5\"\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <title>Close</title>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n {/* Form */}\n <form onSubmit={handleSubmit} className=\"p-6 space-y-5\">\n {/* Name Input */}\n <div>\n <label\n htmlFor=\"chat-name\"\n className=\"block mb-2 text-sm font-medium text-gray-900 dark:text-gray-200\"\n >\n Name <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"chat-name\"\n value={name}\n onChange={(e) => {\n setName(e.target.value);\n if (errors.name) {\n setErrors((prev) => ({ ...prev, name: undefined }));\n }\n }}\n className={`block w-full px-4 py-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border ${\n errors.name\n ? 'border-red-500 focus:ring-red-500 focus:border-red-500'\n : 'border-gray-300 focus:ring-blue-500 focus:border-blue-500'\n } dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500`}\n placeholder=\"John Doe\"\n disabled={isSubmitting}\n autoComplete=\"name\"\n />\n {errors.name && (\n <p className=\"mt-2 text-sm text-red-600 dark:text-red-500\" role=\"alert\">\n {errors.name}\n </p>\n )}\n </div>\n\n {/* Email Input */}\n <div>\n <label\n htmlFor=\"chat-email\"\n className=\"block mb-2 text-sm font-medium text-gray-900 dark:text-gray-200\"\n >\n Email <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"email\"\n id=\"chat-email\"\n value={email}\n onChange={(e) => {\n setEmail(e.target.value);\n if (errors.email) {\n setErrors((prev) => ({ ...prev, email: undefined }));\n }\n }}\n className={`block w-full px-4 py-2.5 text-sm text-gray-900 bg-gray-50 rounded-lg border ${\n errors.email\n ? 'border-red-500 focus:ring-red-500 focus:border-red-500'\n : 'border-gray-300 focus:ring-blue-500 focus:border-blue-500'\n } dark:bg-gray-800 dark:border-gray-600 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500`}\n placeholder=\"john@example.com\"\n disabled={isSubmitting}\n autoComplete=\"email\"\n />\n {errors.email && (\n <p className=\"mt-2 text-sm text-red-600 dark:text-red-500\" role=\"alert\">\n {errors.email}\n </p>\n )}\n </div>\n\n {/* Submit Button */}\n <button\n type=\"submit\"\n disabled={isSubmitting}\n className=\"w-full px-5 py-2.5 text-sm font-medium text-white bg-gradient-to-r from-blue-600 to-purple-600 rounded-lg hover:from-blue-700 hover:to-purple-700 focus:outline-none focus:ring-4 focus:ring-blue-300 disabled:opacity-50 disabled:cursor-not-allowed transition-all\"\n >\n {isSubmitting ? (\n <span className=\"flex items-center justify-center\">\n <svg\n className=\"animate-spin -ml-1 mr-3 h-5 w-5 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-label=\"Loading\"\n >\n <title>Loading</title>\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n />\n </svg>\n Starting Chat...\n </span>\n ) : (\n 'Start Chat'\n )}\n </button>\n\n {/* Privacy Notice */}\n <p className=\"text-xs text-gray-500 dark:text-gray-400 text-center\">\n We respect your privacy. Your information will only be used to assist you.\n </p>\n </form>\n\n {/* Footer */}\n <div className=\"bg-gray-50 dark:bg-gray-950 px-4 py-2 text-center border-t border-gray-200 dark:border-gray-700\">\n <p className=\"text-xs text-gray-500 dark:text-gray-400\">\n Powered by <span className=\"font-semibold\">Xcelsior Chat</span>\n </p>\n </div>\n </div>\n );\n}\n","import { useCallback, useState } from 'react';\n\nexport type ChatWidgetState = 'open' | 'minimized' | 'closed' | 'undefined';\n\nexport interface UseChatWidgetStateOptions {\n /**\n * Controlled state. When provided, the component is controlled.\n */\n state?: ChatWidgetState;\n /**\n * Default state for uncontrolled mode\n * @default 'minimized'\n */\n defaultState?: ChatWidgetState;\n /**\n * Callback when state changes\n */\n onStateChange?: (state: ChatWidgetState) => void;\n}\n\nexport interface UseChatWidgetStateReturn {\n /**\n * Current state of the widget\n */\n currentState: ChatWidgetState;\n /**\n * Function to update the state\n */\n setState: (newState: ChatWidgetState) => void;\n /**\n * Whether the state is controlled\n */\n isControlled: boolean;\n}\n\n/**\n * Hook to manage chat widget state (controlled vs uncontrolled)\n * Encapsulates the logic for handling both controlled and uncontrolled state patterns\n */\nexport function useChatWidgetState({\n state: controlledState,\n defaultState = 'minimized',\n onStateChange,\n}: UseChatWidgetStateOptions): UseChatWidgetStateReturn {\n // Handle controlled vs uncontrolled state\n const [uncontrolledState, setUncontrolledState] = useState<ChatWidgetState>(defaultState);\n const isControlled = controlledState !== undefined && controlledState !== 'undefined';\n const currentState = isControlled ? controlledState : uncontrolledState;\n\n // State setter that works for both controlled and uncontrolled modes\n const setState = useCallback(\n (newValue: ChatWidgetState) => {\n // Update internal state if uncontrolled\n if (!isControlled) {\n setUncontrolledState(newValue);\n }\n // Always call the change handler if provided\n onStateChange?.(newValue);\n },\n [isControlled, onStateChange]\n );\n\n return {\n currentState,\n setState,\n isControlled,\n };\n}\n","interface TypingIndicatorProps {\n isTyping: boolean;\n userName?: string;\n}\n\nexport function TypingIndicator({ isTyping, userName }: TypingIndicatorProps) {\n if (!isTyping) {\n return null;\n }\n\n return (\n <div className=\"px-4 py-2 bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700\">\n <div className=\"flex items-center gap-2\">\n <div className=\"flex gap-1\">\n <span className=\"w-2 h-2 bg-blue-500 rounded-full animate-bounce\" />\n <span\n className=\"w-2 h-2 bg-blue-500 rounded-full animate-bounce\"\n style={{ animationDelay: '0.1s' }}\n />\n <span\n className=\"w-2 h-2 bg-blue-500 rounded-full animate-bounce\"\n style={{ animationDelay: '0.2s' }}\n />\n </div>\n <span className=\"text-xs text-gray-600 dark:text-gray-400\">\n {userName ? `${userName} is typing...` : 'Someone is typing...'}\n </span>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["useCallback","useEffect","error","useCallback","useEffect","useState","useState","useEffect","error","useCallback","useState","axios","error","useEffect","useState","useEffect","useRef","useCallback","jsx","jsxs","jsx","jsxs","useRef","useEffect","useCallback","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useCallback","isTyping","useEffect","useCallback","useEffect","useState","useState","jsx","jsxs","useCallback","useState","jsx","useState","useEffect","convId","useCallback","jsx","jsxs"]}