import { useMemo, useState } from 'react' import useAppStore from '../store/appStore' import { useSession } from '../hooks/useSession' function bucketFor(updatedAt) { const now = new Date() const t = new Date(updatedAt) const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()) const startOfYesterday = new Date(startOfToday) startOfYesterday.setDate(startOfYesterday.getDate() - 1) const sevenDaysAgo = new Date(startOfToday) sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7) if (t >= startOfToday) return 'Today' if (t >= startOfYesterday) return 'Yesterday' if (t >= sevenDaysAgo) return 'Last 7 days' return 'Older' } const BUCKET_ORDER = ['Today', 'Yesterday', 'Last 7 days', 'Older'] export default function SessionSidebar() { const { sessions, activeSessionId, sidebarOpen } = useAppStore() const { createSession, openSession, deleteSession, renameSession } = useSession() const [renamingId, setRenamingId] = useState(null) const [renameValue, setRenameValue] = useState('') const [query, setQuery] = useState('') const grouped = useMemo(() => { const filtered = query.trim() ? sessions.filter((s) => s.name.toLowerCase().includes(query.trim().toLowerCase())) : sessions const buckets = { Today: [], Yesterday: [], 'Last 7 days': [], Older: [] } for (const s of filtered) buckets[bucketFor(s.updated_at)].push(s) return buckets }, [sessions, query]) if (!sidebarOpen) return null async function handleNew() { const session = await createSession('New Session') if (session) await openSession(session.id) } function startRename(s) { setRenamingId(s.id) setRenameValue(s.name) } async function submitRename(id) { if (renameValue.trim()) await renameSession(id, renameValue.trim()) setRenamingId(null) } return (
{/* Header */}
setQuery(e.target.value)} placeholder="Search sessions" className="w-full h-7 pl-7 pr-2 rounded-md text-[11.5px] outline-none transition-colors" style={{ background: 'var(--surface-2)', border: '1px solid var(--border)', color: 'var(--text)', }} onFocus={(e) => (e.target.style.borderColor = 'var(--accent)')} onBlur={(e) => (e.target.style.borderColor = 'var(--border)')} />
{/* Session list — grouped */}
{sessions.length === 0 && (
No sessions yet
)} {BUCKET_ORDER.map((bucket) => { const items = grouped[bucket] if (!items?.length) return null return (
{bucket}
{items.map((s) => { const isActive = s.id === activeSessionId return (
openSession(s.id)} className="group relative flex items-center justify-between mx-1 my-0.5 px-2.5 py-1.5 rounded-md cursor-pointer text-[12px] transition-colors" style={{ background: isActive ? 'var(--accent-bg)' : 'transparent', color: isActive ? 'var(--text)' : 'var(--text-dim)', }} onMouseEnter={(e) => { if (!isActive) e.currentTarget.style.background = 'var(--surface-2)' }} onMouseLeave={(e) => { if (!isActive) e.currentTarget.style.background = 'transparent' }} > {isActive && ( )} {renamingId === s.id ? ( setRenameValue(e.target.value)} onBlur={() => submitRename(s.id)} onKeyDown={(e) => { if (e.key === 'Enter') submitRename(s.id) if (e.key === 'Escape') setRenamingId(null) }} onClick={(e) => e.stopPropagation()} className="bg-transparent border-b outline-none w-full text-[12px]" style={{ borderColor: 'var(--accent)', color: 'var(--text)' }} /> ) : ( {s.name} )}
) })}
) })} {query && Object.values(grouped).every((arr) => arr.length === 0) && (
No sessions match "{query}"
)}
{sessions.length} session{sessions.length === 1 ? '' : 's'} ⌘K
) }