Files
stack/apps/web/src/app/chat/page.tsx
Jason Woltje d54714ea06 feat: add chat components from jarvis frontend
- Migrated Chat.tsx with message handling and UI structure
- Migrated ChatInput.tsx with character limits and keyboard shortcuts
- Migrated MessageList.tsx with thinking/reasoning display
- Migrated ConversationSidebar.tsx (simplified placeholder)
- Migrated BackendStatusBanner.tsx (simplified placeholder)
- Created components/chat/index.ts barrel export
- Created app/chat/page.tsx placeholder route

These components are adapted from jarvis-fe but not yet fully functional:
- API calls placeholder (need to wire up /api/brain/query)
- Auth hooks stubbed (need useAuth implementation)
- Project/conversation hooks stubbed (need implementation)
- Imports changed from @jarvis/* to @mosaic/*

Next steps:
- Implement missing hooks (useAuth, useProjects, useConversations, useApi)
- Wire up backend API endpoints
- Add proper TypeScript types
- Implement full conversation management
2026-01-29 21:47:00 -06:00

100 lines
3.3 KiB
TypeScript

"use client";
import { useRef, useState } from "react";
import { Chat, type ChatRef, ConversationSidebar, type ConversationSidebarRef } from "@/components/chat";
/**
* Chat Page
*
* Placeholder route for the chat interface migrated from jarvis-fe.
*
* TODO:
* - Integrate with authentication
* - Connect to brain API endpoints (/api/brain/query)
* - Implement conversation persistence
* - Add project/workspace integration
* - Wire up actual hooks (useAuth, useProjects, useConversations, useApi)
*/
export default function ChatPage() {
const chatRef = useRef<ChatRef>(null);
const sidebarRef = useRef<ConversationSidebarRef>(null);
const [sidebarOpen, setSidebarOpen] = useState(false);
const [currentConversationId, setCurrentConversationId] = useState<string | null>(null);
const handleConversationChange = (conversationId: string | null) => {
setCurrentConversationId(conversationId);
// TODO: Update sidebar when conversation changes
};
const handleSelectConversation = (conversationId: string | null) => {
// TODO: Load conversation from backend
console.log("Select conversation:", conversationId);
setCurrentConversationId(conversationId);
};
const handleNewConversation = (projectId?: string | null) => {
chatRef.current?.startNewConversation(projectId);
setCurrentConversationId(null);
};
return (
<div className="flex h-screen overflow-hidden" style={{ backgroundColor: "rgb(var(--color-background))" }}>
{/* Conversation Sidebar */}
<ConversationSidebar
ref={sidebarRef}
isOpen={sidebarOpen}
onClose={() => setSidebarOpen(!sidebarOpen)}
currentConversationId={currentConversationId}
onSelectConversation={handleSelectConversation}
onNewConversation={handleNewConversation}
/>
{/* Main Chat Area */}
<div className="flex flex-1 flex-col overflow-hidden">
{/* Header */}
<header
className="border-b px-4 py-3 flex items-center gap-3"
style={{
backgroundColor: "rgb(var(--surface-0))",
borderColor: "rgb(var(--border-default))",
}}
>
{/* Toggle Sidebar Button */}
<button
onClick={() => setSidebarOpen(!sidebarOpen)}
className="p-2 rounded-lg transition-colors hover:bg-[rgb(var(--surface-1))]"
aria-label="Toggle sidebar"
title="Toggle conversation history"
>
<svg
className="h-5 w-5"
style={{ color: "rgb(var(--text-muted))" }}
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={1.5}
>
<path d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
</button>
<div className="flex-1">
<h1 className="text-lg font-semibold" style={{ color: "rgb(var(--text-primary))" }}>
AI Chat
</h1>
<p className="text-xs" style={{ color: "rgb(var(--text-muted))" }}>
Migrated from Jarvis - Connect to brain API for full functionality
</p>
</div>
</header>
{/* Chat Component */}
<Chat
ref={chatRef}
onConversationChange={handleConversationChange}
/>
</div>
</div>
);
}