Spaces:
Running
Running
Rename client/src/components/examples/ChatInterface.tsx to client/src/components/ChatInterface.tsx
b1cd4da verified | import { useState, useRef, useEffect } from "react"; | |
| import { ChatMessage, type Message } from "./ChatMessage"; | |
| import { ChatInput } from "./ChatInput"; | |
| import { CodePanel } from "./CodePanel"; | |
| import { FileUploadZone } from "./FileUploadZone"; | |
| import { TypingIndicator } from "./TypingIndicator"; | |
| import { Button } from "@/components/ui/button"; | |
| import { SidebarTrigger } from "@/components/ui/sidebar"; | |
| import { Moon, Sun, Code2 } from "lucide-react"; | |
| import { useTheme } from "./ThemeProvider"; | |
| import { ScrollArea } from "@/components/ui/scroll-area"; | |
| type ChatInterfaceProps = { | |
| buddyName: string; | |
| onSettingsClick: () => void; | |
| }; | |
| export function ChatInterface({ buddyName, onSettingsClick }: ChatInterfaceProps) { | |
| const { theme, toggleTheme } = useTheme(); | |
| const [messages, setMessages] = useState<Message[]>([]); | |
| const [isTyping, setIsTyping] = useState(false); | |
| const [showFileUpload, setShowFileUpload] = useState(false); | |
| const [showCodePanel, setShowCodePanel] = useState(false); | |
| const scrollRef = useRef<HTMLDivElement>(null); | |
| useEffect(() => { | |
| if (scrollRef.current) { | |
| scrollRef.current.scrollTop = scrollRef.current.scrollHeight; | |
| } | |
| }, [messages, isTyping]); | |
| const handleSendMessage = (content: string) => { | |
| const userMessage: Message = { | |
| id: Date.now().toString(), | |
| role: "user", | |
| content, | |
| timestamp: new Date(), | |
| }; | |
| setMessages((prev) => [...prev, userMessage]); | |
| setIsTyping(true); | |
| setTimeout(() => { | |
| const aiMessage: Message = { | |
| id: (Date.now() + 1).toString(), | |
| role: "assistant", | |
| content: `I'm ${buddyName}, powered by Dolphin-Mistral! I'd be happy to help you with that. This is a demo response showing how I would assist you with coding, debugging, or any other development tasks.`, | |
| timestamp: new Date(), | |
| }; | |
| setMessages((prev) => [...prev, aiMessage]); | |
| setIsTyping(false); | |
| }, 2000); | |
| }; | |
| const handleFileUpload = () => { | |
| setShowFileUpload(!showFileUpload); | |
| }; | |
| const handleFilesSelected = (files: File[]) => { | |
| console.log('Files selected:', files); | |
| setShowFileUpload(false); | |
| setShowCodePanel(true); | |
| }; | |
| return ( | |
| <div className="flex flex-col h-screen"> | |
| <header className="flex items-center justify-between p-4 border-b border-border bg-card"> | |
| <div className="flex items-center gap-3"> | |
| <SidebarTrigger data-testid="button-sidebar-toggle" /> | |
| <div> | |
| <h2 className="font-semibold">{buddyName}</h2> | |
| <p className="text-xs text-muted-foreground">Online • Dolphin-Mistral 3.0</p> | |
| </div> | |
| </div> | |
| <div className="flex items-center gap-2"> | |
| <Button | |
| variant="outline" | |
| size="icon" | |
| onClick={() => setShowCodePanel(!showCodePanel)} | |
| data-testid="button-toggle-code-panel" | |
| > | |
| <Code2 className="h-5 w-5" /> | |
| </Button> | |
| <Button | |
| variant="outline" | |
| size="icon" | |
| onClick={toggleTheme} | |
| data-testid="button-theme-toggle" | |
| > | |
| {theme === "light" ? <Moon className="h-5 w-5" /> : <Sun className="h-5 w-5" />} | |
| </Button> | |
| </div> | |
| </header> | |
| <div className="flex flex-1 overflow-hidden"> | |
| <div className="flex-1 flex flex-col"> | |
| {showFileUpload ? ( | |
| <div className="flex-1 overflow-auto p-6"> | |
| <FileUploadZone | |
| onFilesSelected={handleFilesSelected} | |
| onClose={() => setShowFileUpload(false)} | |
| /> | |
| </div> | |
| ) : ( | |
| <> | |
| <div ref={scrollRef} className="flex-1 overflow-auto"> | |
| {messages.length === 0 ? ( | |
| <div className="h-full flex flex-col items-center justify-center p-8 text-center"> | |
| <div className="max-w-md space-y-4"> | |
| <h3 className="text-2xl font-semibold">Welcome to AI Buddy</h3> | |
| <p className="text-muted-foreground"> | |
| Start a conversation with your AI coding companion. I can help you with: | |
| </p> | |
| <ul className="text-sm text-muted-foreground space-y-2"> | |
| <li>• Code analysis and debugging</li> | |
| <li>• Multi-language support</li> | |
| <li>• File uploads and code modification</li> | |
| <li>• Best practices and optimization</li> | |
| </ul> | |
| </div> | |
| </div> | |
| ) : ( | |
| <div className="space-y-1"> | |
| {messages.map((message) => ( | |
| <ChatMessage key={message.id} message={message} buddyName={buddyName} /> | |
| ))} | |
| {isTyping && ( | |
| <div className="flex gap-3 py-3 px-4"> | |
| <div className="w-10 h-10 rounded-full bg-chart-2 flex items-center justify-center" /> | |
| <div className="flex flex-col gap-1"> | |
| <span className="text-xs text-muted-foreground px-1">{buddyName}</span> | |
| <div className="rounded-2xl px-4 py-3 bg-card border border-card-border"> | |
| <TypingIndicator /> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| <ChatInput | |
| onSend={handleSendMessage} | |
| onFileUpload={handleFileUpload} | |
| disabled={isTyping} | |
| /> | |
| </> | |
| )} | |
| </div> | |
| {showCodePanel && ( | |
| <div className="w-[480px] hidden lg:block"> | |
| <CodePanel | |
| fileName="example.js" | |
| language="JavaScript" | |
| code={`// Sample code uploaded by user | |
| function reverseString(str) { | |
| return str.split('').reverse().join(''); | |
| } | |
| console.log(reverseString("Hello"));`} | |
| onClose={() => setShowCodePanel(false)} | |
| onRun={() => console.log('Run code')} | |
| /> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |