Spaces:
Sleeping
Sleeping
| import { useState, useEffect, useRef } from 'react'; | |
| import ChatMessage from './ChatMessage'; | |
| import ChatInput from './ChatInput'; | |
| import { motion } from 'framer-motion'; | |
| export default function ChatWindow() { | |
| const [messages, setMessages] = useState([]); | |
| const [isLoading, setIsLoading] = useState(false); | |
| const messagesEndRef = useRef(null); | |
| const scrollToBottom = () => { | |
| messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); | |
| }; | |
| useEffect(() => { | |
| scrollToBottom(); | |
| }, [messages]); | |
| const handleSendMessage = async (text) => { | |
| const userMessage = { | |
| text, | |
| timestamp: new Date().toISOString(), | |
| isUser: true, | |
| }; | |
| setMessages(prev => [...prev, userMessage]); | |
| setIsLoading(true); | |
| try { | |
| const response = await fetch('/api/chat', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ message: text }), | |
| }); | |
| if (!response.ok) throw new Error('Failed to get response'); | |
| const data = await response.json(); | |
| const botMessage = { | |
| text: data.response, | |
| timestamp: new Date().toISOString(), | |
| isUser: false, | |
| }; | |
| setMessages(prev => [...prev, botMessage]); | |
| } catch (error) { | |
| console.error('Error:', error); | |
| const errorMessage = { | |
| text: "Sorry, I'm having trouble responding right now. Please try again later.", | |
| timestamp: new Date().toISOString(), | |
| isUser: false, | |
| }; | |
| setMessages(prev => [...prev, errorMessage]); | |
| } finally { | |
| setIsLoading(false); | |
| } | |
| }; | |
| return ( | |
| <div className="flex flex-col h-screen bg-gray-50"> | |
| <div className="flex-1 overflow-y-auto p-4 space-y-4"> | |
| {messages.length === 0 ? ( | |
| <motion.div | |
| initial={{ opacity: 0 }} | |
| animate={{ opacity: 1 }} | |
| className="flex flex-col items-center justify-center h-full" | |
| > | |
| <div className="w-24 h-24 bg-primary rounded-full flex items-center justify-center mb-4"> | |
| <span className="text-white text-4xl font-bold">R</span> | |
| </div> | |
| <h2 className="text-2xl font-semibold text-gray-700 mb-2">Welcome to Replika Clone</h2> | |
| <p className="text-gray-500 text-center max-w-md"> | |
| Start chatting with your virtual companion. She's here to listen and talk about anything! | |
| </p> | |
| </motion.div> | |
| ) : ( | |
| messages.map((message, index) => ( | |
| <ChatMessage | |
| key={index} | |
| message={message} | |
| isUser={message.isUser} | |
| /> | |
| )) | |
| )} | |
| {isLoading && ( | |
| <div className="flex justify-start mb-4"> | |
| <div className="bg-gray-100 text-gray-800 rounded-lg p-3 rounded-bl-none max-w-xs"> | |
| <div className="flex space-x-2"> | |
| <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce"></div> | |
| <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0.2s' }}></div> | |
| <div className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0.4s' }}></div> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| <div ref={messagesEndRef} /> | |
| </div> | |
| <ChatInput onSendMessage={handleSendMessage} /> | |
| </div> | |
| ); | |
| } |