Spaces:
Sleeping
Sleeping
File size: 8,113 Bytes
8421ec4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | import React, { useRef, useEffect } from 'react';
import { Message, Chat } from '../types';
import ChatMessage from './ChatMessage';
import ChatInput from './ChatInput';
interface ChatWindowProps {
activeChat: Chat | null;
messages: Message[];
onSendMessage: (content: string) => void;
isSending: boolean;
isLoading: boolean;
}
const ChatWindow: React.FC<ChatWindowProps> = ({
activeChat,
messages,
onSendMessage,
isSending,
isLoading,
}) => {
const messagesEndRef = useRef<HTMLDivElement>(null);
// Auto-scroll to bottom when new messages arrive
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
}, [messages]);
return (
<div className="flex-1 flex flex-col bg-gray-50 h-full">
{/* Header */}
<header className="bg-white border-b border-gray-200 px-6 py-4 flex items-center justify-between shadow-sm">
<div className="flex items-center gap-3">
<div className="bg-gradient-to-br from-indigo-500 to-purple-600 p-2 rounded-xl shadow-lg">
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
</div>
<div>
<h1 className="text-xl font-bold text-gray-900">
{activeChat ? activeChat.title : 'RAG Chat'}
</h1>
<p className="text-xs text-gray-500">Powered by AI + Document Retrieval</p>
</div>
</div>
{activeChat && (
<div className="flex items-center gap-2 text-xs text-gray-400">
<span className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></span>
Online
</div>
)}
</header>
{/* Messages Area */}
<div className="flex-1 overflow-y-auto px-6 py-6">
{!activeChat ? (
// No Chat Selected State
<div className="h-full flex flex-col items-center justify-center text-center">
<div className="bg-gradient-to-br from-indigo-100 to-purple-100 p-6 rounded-3xl mb-6">
<svg className="w-16 h-16 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
</div>
<h2 className="text-2xl font-bold text-gray-800 mb-2">Welcome to RAG Chat</h2>
<p className="text-gray-500 max-w-md mb-6">
Start a new conversation or select an existing chat from the sidebar to continue your discussion.
</p>
<div className="flex flex-wrap justify-center gap-3 text-sm">
<div className="bg-white px-4 py-2 rounded-full border border-gray-200 text-gray-600">
💡 Ask questions about your documents
</div>
<div className="bg-white px-4 py-2 rounded-full border border-gray-200 text-gray-600">
📚 Context-aware responses
</div>
<div className="bg-white px-4 py-2 rounded-full border border-gray-200 text-gray-600">
💬 Conversation history
</div>
</div>
</div>
) : isLoading ? (
// Loading Messages
<div className="h-full flex items-center justify-center">
<div className="flex flex-col items-center gap-4">
<div className="relative">
<div className="w-12 h-12 border-4 border-indigo-200 rounded-full animate-spin border-t-indigo-600"></div>
</div>
<span className="text-gray-500 text-sm">Loading messages...</span>
</div>
</div>
) : messages.length === 0 ? (
// Empty Chat State
<div className="h-full flex flex-col items-center justify-center text-center">
<div className="bg-gradient-to-br from-emerald-100 to-teal-100 p-5 rounded-2xl mb-4">
<svg className="w-12 h-12 text-emerald-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M7 8h10M7 12h4m1 8l-4-4H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v8a2 2 0 01-2 2h-3l-4 4z" />
</svg>
</div>
<h3 className="text-lg font-semibold text-gray-800 mb-1">Start the conversation</h3>
<p className="text-gray-500 text-sm max-w-sm">
Ask any question and I'll search through the documents to provide you with relevant answers.
</p>
</div>
) : (
// Messages List
<div className="max-w-4xl mx-auto space-y-6">
{messages.map((msg) => (
<ChatMessage key={msg.id} message={msg} />
))}
{/* Typing Indicator */}
{isSending && (
<div className="flex gap-4">
<div className="flex-shrink-0 w-10 h-10 rounded-full bg-gradient-to-br from-emerald-500 to-teal-600 flex items-center justify-center shadow-lg">
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
</svg>
</div>
<div className="bg-white border border-gray-100 px-4 py-3 rounded-2xl rounded-bl-md shadow-sm">
<div className="flex gap-1">
<span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '0ms' }}></span>
<span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '150ms' }}></span>
<span className="w-2 h-2 bg-gray-400 rounded-full animate-bounce" style={{ animationDelay: '300ms' }}></span>
</div>
</div>
</div>
)}
<div ref={messagesEndRef} />
</div>
)}
</div>
{/* Input Area */}
<ChatInput
onSendMessage={onSendMessage}
isSending={isSending}
disabled={!activeChat}
/>
</div>
);
};
export default ChatWindow;
|