OmniHelper / client /src /components /ChatInterface.tsx
hotboxxgenn's picture
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>
);
}