'use client' import { useEffect, useState, useTransition } from 'react' import Link from 'next/link' import { usePathname, useRouter } from 'next/navigation' import { Pin, PinOff, Archive, Pencil, Search, X, PanelLeftOpen, PanelLeftClose } from 'lucide-react' import { cn } from '@/lib/utils' import { useAgentSheet } from './AgentSheetProvider' import AgentAvatar from './AgentAvatar' import { type ConversationRow, BUCKET_LABELS, relativeTime, intentLabel, } from './conversation-display' import { useConversationList } from './use-conversation-list' interface Props { initialConversations: ConversationRow[] } export default function ChatSidebar({ initialConversations }: Props) { const router = useRouter() const pathname = usePathname() const { openAgentSheet, identity } = useAgentSheet() const agentName = identity.displayName?.trim() || null // State + all three mutations live in the shared hook so this surface and the // in-sheet list cannot drift apart again. Pin/archive/rename here used to be // fire-and-forget with no rollback. const { conversations, query, setQuery, grouped, togglePin, archive: archiveConversation, editingId, editValue, setEditValue, startEdit, cancelEdit, commitEdit, } = useConversationList(initialConversations) const [, startTransition] = useTransition() // Collapsed by default; persisted across reloads so power users keep // their preference. Hidden behind a thin rail when collapsed so the // conversation pane runs nearly edge-to-edge. const [collapsed, setCollapsed] = useState(true) useEffect(() => { const stored = localStorage.getItem('Accounted:chat-sidebar-collapsed') if (stored === 'false') setCollapsed(false) }, []) const toggleCollapsed = () => { setCollapsed(c => { const next = !c try { localStorage.setItem('Accounted:chat-sidebar-collapsed', next ? 'true' : 'false') } catch {} return next }) } const activeId = pathname?.startsWith('/chat/') ? pathname.split('/')[2] : null const isConversationOpen = !!activeId async function archive(id: string) { const removed = await archiveConversation(id) if (removed && activeId === id) startTransition(() => router.push('/chat')) } // Collapsed rail (desktop only). Mobile keeps the existing behavior where // the sidebar IS the page when no conversation is open, so the rail is // hidden below md. On desktop the rail keeps a thin column with toggle // + new-chat buttons so the conversation pane runs near-edge-to-edge. const railAside = collapsed ? ( ) : null return ( <> {railAside} > ) }