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
{/* New Chat button */}
{/* Search */}
{/* 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}
)
}