import { useState, useRef, useEffect } from 'react' import { motion, AnimatePresence } from 'framer-motion' import { useChatStore, useAuthStore } from '../../store' import { Plus, MessageSquare, Trash2, Pencil, Check, X, Stethoscope, LogOut, Shield, ChevronRight, Search } from 'lucide-react' import { useNavigate } from 'react-router-dom' import toast from 'react-hot-toast' import clsx from 'clsx' function ConvItem({ conv, isActive, onSelect, onDelete, onRename }) { const [editing, setEditing] = useState(false) const [title, setTitle] = useState(conv.title) const [showActions, setShowActions] = useState(false) const inputRef = useRef() useEffect(() => { if (editing) inputRef.current?.focus() }, [editing]) const saveRename = async () => { if (title.trim() && title !== conv.title) await onRename(conv.id, title.trim()) setEditing(false) } const handleKey = (e) => { if (e.key === 'Enter') saveRename() if (e.key === 'Escape') { setTitle(conv.title); setEditing(false) } } return (
!editing && onSelect(conv.id)} onMouseEnter={() => setShowActions(true)} onMouseLeave={() => setShowActions(false)} > {editing ? ( setTitle(e.target.value)} onKeyDown={handleKey} onBlur={saveRename} onClick={e => e.stopPropagation()} className="flex-1 bg-surface-4 text-white text-sm px-2 py-0.5 rounded outline-none border border-accent/40 min-w-0" /> ) : ( {conv.title} )} {showActions && !editing && ( e.stopPropagation()} > )}
) } export default function Sidebar({ onClose }) { const { conversations, activeConvId, createConversation, selectConversation, deleteConversation, renameConversation, fetchConversations } = useChatStore() const { user, logout } = useAuthStore() const navigate = useNavigate() const [search, setSearch] = useState('') useEffect(() => { fetchConversations() }, []) const handleNew = async () => { await createConversation() onClose?.() } const handleDelete = async (id) => { if (!confirm('Delete this conversation?')) return try { await deleteConversation(id) } catch { toast.error('Could not delete conversation') } } const handleRename = async (id, title) => { try { await renameConversation(id, title) } catch { toast.error('Could not rename') } } const filtered = conversations.filter(c => c.title.toLowerCase().includes(search.toLowerCase()) ) // Group by date const now = new Date() const groups = { Today: [], 'Last 7 days': [], Older: [] } filtered.forEach(c => { const d = new Date(c.updated_at) const diffDays = (now - d) / 86400000 if (diffDays < 1) groups['Today'].push(c) else if (diffDays < 7) groups['Last 7 days'].push(c) else groups['Older'].push(c) }) return (
{/* Logo */}
MedRAG Logo MedRAG
{/* New Chat button */}
{/* Search */}
setSearch(e.target.value)} placeholder="Search chats…" className="bg-transparent text-sm text-white placeholder-gray-600 outline-none flex-1 min-w-0" />
{/* Conversation list */}
{Object.entries(groups).map(([label, convs]) => convs.length > 0 && (

{label}

{convs.map(c => ( { selectConversation(id) if (window.innerWidth < 768) { onClose?.() } }} onDelete={handleDelete} onRename={handleRename} /> ))}
) )} {filtered.length === 0 && (

{search ? 'No chats found' : 'No conversations yet'}

)}
{/* Bottom user area */}
{user?.role === 'admin' && ( )}
{user?.full_name?.[0]?.toUpperCase() ?? 'U'}

{user?.full_name}

{user?.email}

) }