personal-dash-cl/claudash/src/components/ChatInterface.jsx
2026-02-12 03:26:10 -05:00

144 lines
No EOL
4 KiB
JavaScript

import { useState, useRef, useEffect } from 'react';
import { Box, TextField, IconButton, Paper, Typography } from '@mui/material';
import { Send, ExpandLess, ExpandMore } from '@mui/icons-material';
import { sendChatMessage } from '../services/claudeService';
function ChatInterface() {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const [isExpanded, setIsExpanded] = useState(false);
const messagesEndRef = useRef(null);
const handleSend = async () => {
if (!input.trim() || loading) return;
const userMessage = { role: 'user', content: input };
setMessages(prev => [...prev, userMessage]);
setInput('');
setLoading(true);
setIsExpanded(true); // Expand chat when sending a message
try {
const response = await sendChatMessage(input, messages);
setMessages(prev => [...prev, { role: 'assistant', content: response }]);
} catch (error) {
console.error('Chat error:', error);
setMessages(prev => [...prev, {
role: 'assistant',
content: 'Sorry, I encountered an error. Please try again.'
}]);
} finally {
setLoading(false);
}
};
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<Paper
elevation={8}
sx={{
position: 'fixed',
bottom: 0,
left: 0,
right: 0,
height: isExpanded ? '40vh' : '64px',
transition: 'height 0.3s ease',
display: 'flex',
flexDirection: 'column',
zIndex: 1000
}}
>
{/* Expand/Collapse Button */}
<Box sx={{
display: 'flex',
alignItems: 'center',
p: 1,
borderBottom: 1,
borderColor: 'divider'
}}>
<IconButton
onClick={() => setIsExpanded(!isExpanded)}
size="small"
>
{isExpanded ? <ExpandMore /> : <ExpandLess />}
</IconButton>
<Typography variant="body2" sx={{ ml: 1 }}>
Chat with Claude
</Typography>
</Box>
{/* Messages area - only visible when expanded */}
{isExpanded && (
<Box sx={{ flex: 1, overflow: 'auto', p: 2 }}>
{messages.length === 0 && (
<Typography color="text.secondary" variant="body2">
Ask me anything about your briefing or the news...
</Typography>
)}
{messages.map((msg, idx) => (
<Box
key={idx}
sx={{
mb: 2,
textAlign: msg.role === 'user' ? 'right' : 'left'
}}
>
<Typography
variant="body2"
sx={{
display: 'inline-block',
bgcolor: msg.role === 'user' ? 'primary.main' : 'grey.800',
color: 'white',
p: 1.5,
borderRadius: 2,
maxWidth: '70%'
}}
>
{msg.content}
</Typography>
</Box>
))}
<div ref={messagesEndRef} />
</Box>
)}
{/* Input area - always visible */}
<Box sx={{
p: 2,
borderTop: isExpanded ? 1 : 0,
borderColor: 'divider',
display: 'flex',
gap: 1,
backgroundColor: 'background.paper'
}}>
<TextField
fullWidth
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
}}
placeholder="Ask Claude anything..."
disabled={loading}
size="small"
/>
<IconButton
onClick={handleSend}
disabled={loading || !input.trim()}
color="primary"
>
<Send />
</IconButton>
</Box>
</Paper>
);
}
export default ChatInterface;