UNPKG

@agentdao/core

Version:

Core functionality, skills, and ready-made UI components for AgentDAO - Web3 subscriptions, content generation, social media, help support, live chat, RSS fetching, web search, and agent pricing integration

334 lines (333 loc) 19.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LiveChatWidget = LiveChatWidget; const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = require("react"); const theme_1 = require("./theme"); function LiveChatWidget({ config, className, style }) { const [isOpen, setIsOpen] = (0, react_1.useState)(false); const [isMinimized, setIsMinimized] = (0, react_1.useState)(false); const [messages, setMessages] = (0, react_1.useState)([]); const [inputValue, setInputValue] = (0, react_1.useState)(''); const [isTyping, setIsTyping] = (0, react_1.useState)(false); const [isConnected, setIsConnected] = (0, react_1.useState)(false); const messagesEndRef = (0, react_1.useRef)(null); const inputRef = (0, react_1.useRef)(null); const theme = (0, theme_1.getTheme)(config.theme || 'auto'); (0, react_1.useEffect)(() => { // Inject CSS variables const styleElement = document.createElement('style'); styleElement.textContent = ` .agentdao-chat-widget { ${(0, theme_1.generateCSSVariables)(theme)} } `; document.head.appendChild(styleElement); // Add welcome message if (config.welcomeMessage) { setMessages([{ id: 'welcome', text: config.welcomeMessage, sender: 'agent', timestamp: new Date(), status: 'read' }]); } return () => { document.head.removeChild(styleElement); }; }, [theme, config.welcomeMessage]); (0, react_1.useEffect)(() => { // Auto-scroll to bottom when new messages arrive if (config.autoScroll !== false) { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); } }, [messages, config.autoScroll]); (0, react_1.useEffect)(() => { // Focus input when chat opens if (isOpen && !isMinimized) { inputRef.current?.focus(); } }, [isOpen, isMinimized]); const handleSendMessage = async () => { if (!inputValue.trim() || isTyping) return; const userMessage = { id: Date.now().toString(), text: inputValue.trim(), sender: 'user', timestamp: new Date(), status: 'sending' }; setMessages(prev => [...prev, userMessage]); setInputValue(''); setIsTyping(true); try { // Call real AI API instead of mock response const response = await fetch('/api/skills/live-chat-widget', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ message: userMessage.text, config: { agentName: config.agentName, ai: { model: 'gpt-3.5-turbo', maxTokens: 500, temperature: 0.7 } }, conversationHistory: messages.slice(-5) // Send last 5 messages for context }) }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to get AI response'); } const data = await response.json(); const agentMessage = { id: (Date.now() + 1).toString(), text: data.response, sender: 'agent', timestamp: new Date(), status: 'sent' }; setMessages(prev => [...prev, agentMessage]); // Update user message status setMessages(prev => prev.map(msg => msg.id === userMessage.id ? { ...msg, status: 'sent' } : msg)); if (config.onMessageReceived) { config.onMessageReceived(agentMessage); } } catch (error) { console.error('Live chat widget error:', error); // Show error message to user const errorMessage = { id: (Date.now() + 1).toString(), text: error instanceof Error ? error.message : 'Sorry, I encountered an error. Please try again.', sender: 'agent', timestamp: new Date(), status: 'error' }; setMessages(prev => [...prev, errorMessage]); // Update user message status to error setMessages(prev => prev.map(msg => msg.id === userMessage.id ? { ...msg, status: 'error' } : msg)); } finally { setIsTyping(false); } if (config.onMessageSent) { config.onMessageSent(userMessage); } }; const handleKeyPress = (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSendMessage(); } }; const getPositionStyles = () => { const baseStyles = { position: 'fixed', zIndex: 9999, ...style }; switch (config.position) { case 'bottom-right': return { ...baseStyles, bottom: '20px', right: '20px' }; case 'bottom-left': return { ...baseStyles, bottom: '20px', left: '20px' }; case 'top-right': return { ...baseStyles, top: '20px', right: '20px' }; case 'top-left': return { ...baseStyles, top: '20px', left: '20px' }; default: return { ...baseStyles, bottom: '20px', right: '20px' }; } }; const formatTime = (date) => { return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }; return ((0, jsx_runtime_1.jsxs)("div", { className: `agentdao-chat-widget ${className || ''}`, style: getPositionStyles(), children: [!isOpen && ((0, jsx_runtime_1.jsxs)("button", { onClick: () => { setIsOpen(true); setIsMinimized(false); if (config.onChatStarted) { config.onChatStarted(); } }, style: { width: '60px', height: '60px', borderRadius: '50%', backgroundColor: theme.colors.primary, color: 'white', border: 'none', cursor: 'pointer', boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)', fontSize: '24px', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative', }, children: ["\uD83D\uDCAC", messages.length > 1 && ((0, jsx_runtime_1.jsx)("div", { style: { position: 'absolute', top: '-5px', right: '-5px', backgroundColor: theme.colors.error, color: 'white', borderRadius: '50%', width: '20px', height: '20px', fontSize: '12px', display: 'flex', alignItems: 'center', justifyContent: 'center', }, children: messages.length - 1 }))] })), isOpen && ((0, jsx_runtime_1.jsxs)("div", { style: { width: '350px', height: isMinimized ? '60px' : '500px', backgroundColor: theme.colors.surface, borderRadius: theme.borderRadius.lg, boxShadow: '0 20px 25px -5px rgba(0, 0, 0, 0.1)', display: 'flex', flexDirection: 'column', overflow: 'hidden', transition: 'height 0.3s ease', }, children: [(0, jsx_runtime_1.jsxs)("div", { style: { backgroundColor: theme.colors.primary, color: 'white', padding: theme.spacing.md, display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer', }, onClick: () => setIsMinimized(!isMinimized), children: [(0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', alignItems: 'center', gap: theme.spacing.sm }, children: [config.showAvatar && ((0, jsx_runtime_1.jsx)("div", { style: { width: '32px', height: '32px', borderRadius: '50%', backgroundColor: 'rgba(255, 255, 255, 0.2)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '16px', }, children: "\uD83E\uDD16" })), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: 'bold', fontSize: theme.typography.fontSize.sm, fontFamily: theme.typography.fontFamily }, children: config.agentName }), (0, jsx_runtime_1.jsx)("div", { style: { fontSize: theme.typography.fontSize.xs, opacity: 0.8, fontFamily: theme.typography.fontFamily }, children: isConnected ? 'Online' : 'Connecting...' })] })] }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', gap: theme.spacing.xs }, children: [(0, jsx_runtime_1.jsx)("button", { onClick: (e) => { e.stopPropagation(); setIsMinimized(!isMinimized); }, style: { background: 'none', border: 'none', color: 'white', cursor: 'pointer', fontSize: '16px', padding: '4px', }, children: isMinimized ? '□' : '−' }), (0, jsx_runtime_1.jsx)("button", { onClick: (e) => { e.stopPropagation(); setIsOpen(false); if (config.onChatEnded) { config.onChatEnded(); } }, style: { background: 'none', border: 'none', color: 'white', cursor: 'pointer', fontSize: '16px', padding: '4px', }, children: "\u00D7" })] })] }), !isMinimized && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { style: { flex: 1, overflow: 'auto', padding: theme.spacing.md, display: 'flex', flexDirection: 'column', gap: theme.spacing.sm, }, children: [messages.slice(-(config.maxMessages || 50)).map((message) => ((0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', justifyContent: message.sender === 'user' ? 'flex-end' : 'flex-start', }, children: (0, jsx_runtime_1.jsxs)("div", { style: { maxWidth: '80%', padding: `${theme.spacing.sm} ${theme.spacing.md}`, borderRadius: theme.borderRadius.md, backgroundColor: message.sender === 'user' ? theme.colors.primary : theme.colors.background, color: message.sender === 'user' ? 'white' : theme.colors.text, fontSize: theme.typography.fontSize.sm, fontFamily: theme.typography.fontFamily, wordWrap: 'break-word', }, children: [(0, jsx_runtime_1.jsx)("div", { children: message.text }), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: theme.typography.fontSize.xs, opacity: 0.7, marginTop: '4px', textAlign: message.sender === 'user' ? 'right' : 'left', }, children: [formatTime(message.timestamp), message.status === 'sending' && ' • Sending...', message.status === 'sent' && ' • Sent', message.status === 'delivered' && ' • Delivered', message.status === 'read' && ' • Read'] })] }) }, message.id))), isTyping && config.showTypingIndicator && ((0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', justifyContent: 'flex-start' }, children: (0, jsx_runtime_1.jsx)("div", { style: { padding: `${theme.spacing.sm} ${theme.spacing.md}`, borderRadius: theme.borderRadius.md, backgroundColor: theme.colors.background, fontSize: theme.typography.fontSize.sm, fontFamily: theme.typography.fontFamily, }, children: (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', gap: '4px' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { width: '8px', height: '8px', borderRadius: '50%', backgroundColor: theme.colors.textSecondary, animation: 'typing 1.4s infinite ease-in-out', } }), (0, jsx_runtime_1.jsx)("div", { style: { width: '8px', height: '8px', borderRadius: '50%', backgroundColor: theme.colors.textSecondary, animation: 'typing 1.4s infinite ease-in-out 0.2s', } }), (0, jsx_runtime_1.jsx)("div", { style: { width: '8px', height: '8px', borderRadius: '50%', backgroundColor: theme.colors.textSecondary, animation: 'typing 1.4s infinite ease-in-out 0.4s', } })] }) }) })), (0, jsx_runtime_1.jsx)("div", { ref: messagesEndRef })] }), (0, jsx_runtime_1.jsx)("div", { style: { padding: theme.spacing.md, borderTop: `1px solid ${theme.colors.border}`, backgroundColor: theme.colors.surface, }, children: (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', gap: theme.spacing.sm }, children: [(0, jsx_runtime_1.jsx)("input", { ref: inputRef, type: "text", value: inputValue, onChange: (e) => setInputValue(e.target.value), onKeyPress: handleKeyPress, placeholder: "Type your message...", disabled: isTyping, style: { flex: 1, padding: theme.spacing.sm, border: `1px solid ${theme.colors.border}`, borderRadius: theme.borderRadius.sm, backgroundColor: theme.colors.background, color: theme.colors.text, fontSize: theme.typography.fontSize.sm, fontFamily: theme.typography.fontFamily, outline: 'none', } }), (0, jsx_runtime_1.jsx)("button", { onClick: handleSendMessage, disabled: !inputValue.trim() || isTyping, style: { padding: `${theme.spacing.sm} ${theme.spacing.md}`, border: 'none', borderRadius: theme.borderRadius.sm, backgroundColor: inputValue.trim() && !isTyping ? theme.colors.primary : theme.colors.secondary, color: 'white', cursor: inputValue.trim() && !isTyping ? 'pointer' : 'not-allowed', fontSize: theme.typography.fontSize.sm, fontFamily: theme.typography.fontFamily, }, children: "Send" })] }) })] }))] })), (0, jsx_runtime_1.jsx)("style", { children: ` @keyframes typing { 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; } 30% { transform: translateY(-10px); opacity: 1; } } ` })] })); }