import { memo, useEffect, useRef, useState } from 'react'; import { ChevronDown, LoaderCircle, MoreHorizontal, PanelLeftClose, PanelLeftOpen, PencilLine, Plus, Trash2, } from 'lucide-react'; import type { ChatHistoryBucket } from './types'; import blueLogo from '../../assets/images/login/blue_logo.png'; import { useI18n } from '../../i18n'; type ChatHistoryPanelProps = { buckets: ChatHistoryBucket[]; selectedConversationId?: string; loading?: boolean; onNewChat?: () => void; onSelectConversation?: (conversationId: string) => void; onRenameConversation?: (conversationId: string) => void; onDeleteConversation?: (conversationId: string) => void; }; type MenuState = { conversationId: string; } | null; function cx(...classes: Array): string { return classes.filter(Boolean).join(' '); } function ChatHistoryPanel({ buckets, selectedConversationId, loading, onNewChat, onSelectConversation, onRenameConversation, onDeleteConversation, }: ChatHistoryPanelProps) { const { t } = useI18n(); const panelRef = useRef(null); const [collapsedBuckets, setCollapsedBuckets] = useState>({}); const [menuState, setMenuState] = useState(null); const [isCompact, setIsCompact] = useState(false); useEffect(() => { setCollapsedBuckets((current) => { const next: Record = {}; const currentKeys = Object.keys(current); let changed = currentKeys.length !== buckets.length; for (const bucket of buckets) { next[bucket.key] = current[bucket.key] ?? false; if (current[bucket.key] !== next[bucket.key]) { changed = true; } } return changed ? next : current; }); }, [buckets]); useEffect(() => { if (!menuState) { return; } const handlePointerDown = (event: PointerEvent) => { const target = event.target as HTMLElement | null; if (!target) { setMenuState(null); return; } if (target.closest('[data-chat-history-menu="true"]')) { return; } if (!panelRef.current?.contains(target)) { setMenuState(null); return; } if (!target.closest('[data-chat-history-menu-toggle="true"]')) { setMenuState(null); } }; const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') { setMenuState(null); } }; document.addEventListener('pointerdown', handlePointerDown); document.addEventListener('keydown', handleEscape); return () => { document.removeEventListener('pointerdown', handlePointerDown); document.removeEventListener('keydown', handleEscape); }; }, [menuState]); const panelWidthClass = isCompact ? 'md:w-[70px] lg:w-[70px]' : 'md:w-[240px] lg:w-[252px]'; const toggleSidebarLabel = isCompact ? t('conversation.historyPanel.expandSidebar') : t('conversation.historyPanel.collapseSidebar'); return ( ); } export default memo(ChatHistoryPanel);