UNPKG

@jeanmemory/react

Version:

React SDK for Jean Memory - Build personalized AI chatbots in 5 lines of code

69 lines (68 loc) 12.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JeanChat = JeanChat; const jsx_runtime_1 = require("react/jsx-runtime"); /** * Jean Memory React SDK - Chat Component * Complete chat interface with authentication */ const react_1 = require("react"); const provider_1 = require("./provider"); const lucide_react_1 = require("lucide-react"); function JeanChat({ className = '', showHeader = true, placeholder = 'Type your message...', style }) { const agent = (0, provider_1.useJean)(); const [input, setInput] = (0, react_1.useState)(''); const messagesEndRef = (0, react_1.useRef)(null); const [isDark, setIsDark] = (0, react_1.useState)(false); const scrollToBottom = () => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); }; (0, react_1.useEffect)(() => { scrollToBottom(); }, [agent.messages]); (0, react_1.useEffect)(() => { if (typeof window !== 'undefined') { const storedTheme = localStorage.getItem('jean-chat-theme'); if (storedTheme === 'dark') { setIsDark(true); } } }, []); (0, react_1.useEffect)(() => { if (isDark) { document.documentElement.classList.add('dark'); localStorage.setItem('jean-chat-theme', 'dark'); } else { document.documentElement.classList.remove('dark'); localStorage.setItem('jean-chat-theme', 'light'); } }, [isDark]); const handleSubmit = async (e) => { e.preventDefault(); if (!input.trim() || agent.isLoading) return; const message = input.trim(); setInput(''); try { await agent.sendMessage(message); } catch (err) { console.error('Failed to send message:', err); } }; if (!agent.isAuthenticated) { return ((0, jsx_runtime_1.jsx)("div", { className: `flex items-center justify-center h-full ${className} bg-white dark:bg-gray-950`, style: style, children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center p-8 max-w-sm w-full", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-12 h-12 mx-auto mb-6 rounded-full bg-gray-50 dark:bg-gray-900 flex items-center justify-center border border-gray-100 dark:border-gray-800", children: (0, jsx_runtime_1.jsx)("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 2L13.09 8.26L20 9L13.09 15.74L12 22L10.91 15.74L4 9L10.91 8.26L12 2Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "text-gray-400 dark:text-gray-500" }) }) }), (0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-medium text-gray-900 dark:text-white mb-2", children: "Connect to Jean Memory" }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-500 dark:text-gray-400 text-sm mb-8 leading-relaxed", children: "Sign in to access your personalized AI assistant with persistent memory." }), (0, jsx_runtime_1.jsxs)("button", { onClick: agent.signIn, className: "inline-flex items-center justify-center gap-2 px-4 py-2.5 bg-gray-900 dark:bg-white text-white dark:text-gray-900 font-medium text-sm rounded-lg hover:bg-gray-800 dark:hover:bg-gray-100 transition-colors focus:outline-none focus:ring-2 focus:ring-gray-900 dark:focus:ring-gray-300 focus:ring-offset-2", children: [(0, jsx_runtime_1.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 2L13.09 8.26L20 9L13.09 15.74L12 22L10.91 15.74L4 9L10.91 8.26L12 2Z", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) }), (0, jsx_runtime_1.jsx)("span", { children: "Sign In" })] })] }) })); } return ((0, jsx_runtime_1.jsxs)("div", { className: `flex flex-col h-full bg-white dark:bg-gray-950 ${className}`, style: style, children: [showHeader && ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center px-5 py-4 border-b border-gray-100 dark:border-gray-800", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center space-x-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-8 h-8 rounded-full bg-gray-100 dark:bg-gray-900 flex items-center justify-center", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Bot, { size: 16, className: "text-gray-600 dark:text-gray-400" }) }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "font-medium text-gray-900 dark:text-white text-sm", children: "Jean Memory" }), (0, jsx_runtime_1.jsx)("p", { className: "text-xs text-gray-500 dark:text-gray-500", children: agent.user?.email })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center space-x-1", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setIsDark(!isDark), className: "p-2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-900 rounded-lg transition-colors", children: isDark ? (0, jsx_runtime_1.jsx)(lucide_react_1.Sun, { size: 16 }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Moon, { size: 16 }) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => window.location.reload(), disabled: agent.messages.length === 0, className: "p-2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-900 rounded-lg disabled:opacity-40 disabled:cursor-not-allowed transition-colors", title: "Clear Conversation", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Trash2, { size: 16 }) }), (0, jsx_runtime_1.jsx)("button", { onClick: agent.signOut, className: "p-2 text-gray-400 hover:text-red-500 hover:bg-gray-50 dark:hover:bg-gray-900 rounded-lg transition-colors", title: "Sign Out", children: (0, jsx_runtime_1.jsx)(lucide_react_1.LogOut, { size: 16 }) })] })] })), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 overflow-y-auto px-4 py-6", children: agent.messages.length === 0 ? ((0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-center justify-center h-full text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-16 h-16 rounded-full bg-gray-50 dark:bg-gray-900 flex items-center justify-center mb-4", children: (0, jsx_runtime_1.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", className: "text-gray-400 dark:text-gray-500", children: (0, jsx_runtime_1.jsx)("path", { d: "M12 2L13.09 8.26L20 9L13.09 15.74L12 22L10.91 15.74L4 9L10.91 8.26L12 2Z" }) }) }), (0, jsx_runtime_1.jsx)("h3", { className: "text-base font-medium text-gray-900 dark:text-white mb-2", children: "How can I help you today?" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-500 dark:text-gray-400 max-w-xs", children: "I have access to your personal context and can assist with a wide range of topics." })] })) : ((0, jsx_runtime_1.jsxs)("div", { className: "space-y-6 max-w-3xl mx-auto", children: [agent.messages.map((message) => ((0, jsx_runtime_1.jsxs)("div", { className: `flex items-start gap-3 ${message.role === 'user' ? 'flex-row-reverse' : ''}`, children: [(0, jsx_runtime_1.jsx)("div", { className: "w-7 h-7 rounded-full bg-gray-100 dark:bg-gray-900 flex items-center justify-center flex-shrink-0", children: message.role === 'user' ? ((0, jsx_runtime_1.jsx)(lucide_react_1.User, { size: 14, className: "text-gray-600 dark:text-gray-400" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Bot, { size: 14, className: "text-gray-600 dark:text-gray-400" })) }), (0, jsx_runtime_1.jsxs)("div", { className: `flex-1 max-w-[85%] ${message.role === 'user' ? 'text-right' : ''}`, children: [(0, jsx_runtime_1.jsx)("div", { className: `inline-block px-4 py-3 rounded-xl ${message.role === 'user' ? 'bg-gray-900 dark:bg-white text-white dark:text-gray-900' : 'bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100 border border-gray-100 dark:border-gray-800'}`, children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm whitespace-pre-wrap leading-relaxed", children: message.content }) }), (0, jsx_runtime_1.jsx)("div", { className: `mt-1.5 px-1 ${message.role === 'user' ? 'text-right' : 'text-left'}`, children: (0, jsx_runtime_1.jsx)("span", { className: "text-xs text-gray-400 dark:text-gray-500", children: message.timestamp.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }) }) })] })] }, message.id))), agent.isLoading && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-start gap-3 max-w-3xl mx-auto", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-7 h-7 rounded-full bg-gray-100 dark:bg-gray-900 flex items-center justify-center flex-shrink-0", children: (0, jsx_runtime_1.jsx)(lucide_react_1.Bot, { size: 14, className: "text-gray-600 dark:text-gray-400" }) }), (0, jsx_runtime_1.jsx)("div", { className: "bg-gray-50 dark:bg-gray-900 text-gray-900 dark:text-gray-100 px-4 py-3 rounded-xl border border-gray-100 dark:border-gray-800", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex items-center space-x-1", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-1.5 h-1.5 bg-gray-400 dark:bg-gray-500 rounded-full animate-bounce" }), (0, jsx_runtime_1.jsx)("div", { className: "w-1.5 h-1.5 bg-gray-400 dark:bg-gray-500 rounded-full animate-bounce", style: { animationDelay: '0.1s' } }), (0, jsx_runtime_1.jsx)("div", { className: "w-1.5 h-1.5 bg-gray-400 dark:bg-gray-500 rounded-full animate-bounce", style: { animationDelay: '0.2s' } })] }) })] })), (0, jsx_runtime_1.jsx)("div", { ref: messagesEndRef })] })) }), (0, jsx_runtime_1.jsxs)("div", { className: "border-t border-gray-100 dark:border-gray-800 p-4", children: [agent.error && ((0, jsx_runtime_1.jsxs)("div", { className: "mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800/50 rounded-lg flex items-start space-x-3", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-red-500 dark:text-red-400 mt-0.5", children: (0, jsx_runtime_1.jsxs)("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("circle", { cx: "12", cy: "12", r: "10" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), (0, jsx_runtime_1.jsx)("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1", children: (0, jsx_runtime_1.jsx)("p", { className: "text-red-600 dark:text-red-400 text-sm", children: agent.error }) }), (0, jsx_runtime_1.jsx)("button", { onClick: () => window.location.reload(), className: "p-1 text-red-500 hover:bg-red-100 dark:hover:bg-red-900/50 rounded", children: (0, jsx_runtime_1.jsx)(lucide_react_1.X, { size: 14 }) })] })), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleSubmit, className: "relative max-w-3xl mx-auto", children: [(0, jsx_runtime_1.jsx)("textarea", { value: input, onChange: (e) => setInput(e.target.value), onKeyDown: (e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSubmit(e); } }, placeholder: placeholder, disabled: agent.isLoading, className: "w-full px-4 py-3 pr-12 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-xl focus:outline-none focus:ring-1 focus:ring-gray-300 dark:focus:ring-gray-600 focus:border-transparent disabled:opacity-50 resize-none text-sm text-gray-900 dark:text-gray-100", rows: 1 }), (0, jsx_runtime_1.jsx)("button", { type: "submit", disabled: agent.isLoading || !input.trim(), className: "absolute right-2 top-1/2 -translate-y-1/2 w-8 h-8 bg-gray-900 dark:bg-white text-white dark:text-gray-900 rounded-lg hover:bg-gray-800 dark:hover:bg-gray-100 disabled:opacity-40 disabled:cursor-not-allowed flex items-center justify-center transition-colors", children: agent.isLoading ? ((0, jsx_runtime_1.jsx)("div", { className: "w-3 h-3 border-2 border-current border-t-transparent rounded-full animate-spin" })) : ((0, jsx_runtime_1.jsx)(lucide_react_1.Send, { size: 14 })) })] })] })] })); }