Spaces:
Sleeping
Sleeping
yuvrajsingh6
Initial commit: Analytical Finance Chatbot with Next.js frontend and FastAPI backend
c5b5cc8
| "use client"; | |
| import { useEffect, useState } from 'react'; | |
| import Link from 'next/link'; | |
| import { usePathname, useRouter } from 'next/navigation'; | |
| import { Plus, MessageSquare, ExternalLink, LogOut, User } from 'lucide-react'; | |
| import { api } from '@/lib/api'; | |
| export default function Sidebar() { | |
| const [conversations, setConversations] = useState([]); | |
| const [loading, setLoading] = useState(true); | |
| const router = useRouter(); | |
| const pathname = usePathname(); | |
| useEffect(() => { | |
| loadConversations(); | |
| // Listen for updates from ChatInterface | |
| const handleUpdate = () => loadConversations(); | |
| window.addEventListener('chat-update', handleUpdate); | |
| return () => window.removeEventListener('chat-update', handleUpdate); | |
| }, [pathname]); // Reload when path changes (e.g. new chat created) | |
| const loadConversations = async () => { | |
| try { | |
| const data = await api.getConversations(); | |
| // Sort by updated_at desc | |
| const sorted = (data || []).sort((a, b) => | |
| new Date(b.updated_at) - new Date(a.updated_at) | |
| ); | |
| setConversations(sorted); | |
| } catch (error) { | |
| console.error('Failed to load conversations', error); | |
| } finally { | |
| setLoading(false); | |
| } | |
| }; | |
| const handleNewChat = async () => { | |
| try { | |
| const newConv = await api.createConversation(); | |
| if (newConv && newConv.conversation_id) { | |
| router.push(`/c/${newConv.conversation_id}`); | |
| // loadConversations will trigger via useEffect | |
| } | |
| } catch (error) { | |
| console.error('Failed to create new chat', error); | |
| } | |
| }; | |
| return ( | |
| <div className="flex flex-col h-full w-[260px] bg-[var(--sidebar-bg)] text-[var(--sidebar-fg)] transition-all"> | |
| {/* New Chat Button */} | |
| <div className="p-3"> | |
| <button | |
| onClick={handleNewChat} | |
| className="flex items-center gap-3 w-full px-3 py-3 rounded-md border border-white/20 transition-colors duration-200 hover:bg-[var(--sidebar-hover)] text-sm text-white mb-1" | |
| > | |
| <Plus size={16} /> | |
| <span>New chat</span> | |
| </button> | |
| </div> | |
| {/* Conversation List */} | |
| <div className="flex-1 overflow-y-auto custom-scrollbar px-2"> | |
| <div className="flex flex-col gap-2 pb-2 text-sm text-gray-100"> | |
| {!loading && conversations.length === 0 && ( | |
| <div className="px-3 text-gray-400 text-xs">No conversations yet.</div> | |
| )} | |
| {conversations.map((conv) => { | |
| const isActive = pathname === `/c/${conv.conversation_id}`; | |
| // If alias is missing, show ID or fallback | |
| const label = conv.alias || conv.messages?.[0]?.content || "New conversation"; | |
| const truncatedLabel = label.length > 25 ? label.substring(0, 25) + '...' : label; | |
| return ( | |
| <Link | |
| key={conv.conversation_id} | |
| href={`/c/${conv.conversation_id}`} | |
| className={`group flex items-center gap-3 px-3 py-3 rounded-md transition-colors duration-200 hover:bg-[var(--sidebar-hover)] ${isActive ? 'bg-[var(--sidebar-hover)]' : '' | |
| }`} | |
| > | |
| <MessageSquare size={16} className="text-gray-300" /> | |
| <div className="flex-1 overflow-hidden relative truncate"> | |
| {truncatedLabel} | |
| </div> | |
| </Link> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| {/* Footer / User Profile section */} | |
| <div className="border-t border-white/20 p-3"> | |
| <button className="flex items-center gap-3 w-full px-3 py-3 rounded-md hover:bg-[var(--sidebar-hover)] transition-colors duration-200 text-sm text-white"> | |
| <User size={16} /> | |
| <div className="font-bold">Upgrade to Plus</div> | |
| </button> | |
| <div className="flex items-center gap-3 w-full px-3 py-3 rounded-md hover:bg-[var(--sidebar-hover)] transition-colors duration-200 text-sm text-white mt-1 cursor-pointer"> | |
| <div className="w-5 h-5 rounded-sm bg-purple-600 flex items-center justify-center text-xs">U</div> | |
| <span>User</span> | |
| </div> | |
| </div> | |
| </div> | |
| ); | |
| } | |