import { useState, useEffect } from "react"; import { motion, AnimatePresence } from "framer-motion"; import { Plus, MessageSquare, Trash2, Brain, FileText, Zap, X, Tag, } from "lucide-react"; import { getSessions, deleteSession, getMemories } from "../services/api"; import { format } from "date-fns"; export default function Sidebar({ currentSessionId, onNewChat, onSelectSession, onClose, isMobile = false, }) { const [sessions, setSessions] = useState([]); const [activeTab, setActiveTab] = useState("chats"); const [memories, setMemories] = useState([]); const [memoryCount, setMemoryCount] = useState(0); const [loadingMemories, setLoadingMemories] = useState(false); useEffect(() => { loadSessions(); }, [currentSessionId]); useEffect(() => { if (currentSessionId && activeTab === "memory") { loadMemories(); } }, [currentSessionId, activeTab]); const loadSessions = async () => { try { const data = await getSessions(); setSessions(data); } catch (err) { console.error("Failed to load sessions:", err); } }; const loadMemories = async () => { if (!currentSessionId) return; setLoadingMemories(true); try { const data = await getMemories(currentSessionId); setMemories(data.memories || []); setMemoryCount(data.total || 0); } catch (err) { console.error("Failed to load memories:", err); } finally { setLoadingMemories(false); } }; const handleDeleteSession = async (e, sessionId) => { e.stopPropagation(); try { await deleteSession(sessionId); setSessions((prev) => prev.filter((s) => s.session_id !== sessionId)); if (sessionId === currentSessionId) { onNewChat(); } } catch (err) { console.error("Failed to delete session:", err); } }; const categoryStyles = { technical: "text-blue-400 bg-blue-950/50 border-blue-800/40", preference: "text-purple-400 bg-purple-950/50 border-purple-800/40", professional: "text-emerald-400 bg-emerald-950/50 border-emerald-800/40", goal: "text-amber-400 bg-amber-950/50 border-amber-800/40", general: "text-slate-400 bg-slate-800/50 border-slate-700/40", }; return (
{/* ── Header ─────────────────────────────────────────── */}
Nexus Memory

Local AI Assistant

{isMobile && ( )}
{/* ── New Chat Button ─────────────────────────────────── */}
New Chat
{/* ── Tabs ───────────────────────────────────────────── */}
{[ { id: "chats", icon: MessageSquare, label: "Chats" }, { id: "memory", icon: Brain, label: memoryCount > 0 ? `Memory (${memoryCount})` : "Memory", }, ].map((tab) => ( ))}
{/* ── Scrollable Content ─────────────────────────────── */}
{/* Chats Tab */} {activeTab === "chats" && ( {sessions.length === 0 ? (

No conversations yet.

Start chatting below!

) : ( sessions.map((session, index) => ( onSelectSession(session.session_id)} className={`group flex items-start gap-2.5 px-3 py-2.5 rounded-lg cursor-pointer transition-all duration-150 ${ session.session_id === currentSessionId ? "bg-nexus-accent/10 border border-nexus-accent/30" : "hover:bg-nexus-card border border-transparent" }`} >

{session.title}

{format(new Date(session.updated_at), "MMM d, HH:mm")}

)) )}
)} {/* Memory Tab */} {activeTab === "memory" && ( {/* Refresh button */} {!currentSessionId ? (

Select a chat to view memories.

) : memories.length === 0 ? (

No memories yet.

Chat to build memory!

) : ( memories.map((memory, index) => (

{memory.fact}

{memory.category} {format(new Date(memory.created_at), "MMM d")}
)) )}
)}
{/* ── Footer Status ───────────────────────────────────── */}
Ollama connected
); }