import React, { useState, useEffect, useRef } from 'react' import { ChevronLeft, ChevronDown, ChevronRight, Search, MessageSquare, Edit, Image, LayoutGrid, Folder, Settings, User, Pin, MoreHorizontal, Archive, Trash2, PanelLeft, PanelRight } from 'lucide-react' const pochiLogo = '/assets/pochi.jpeg' const Sidebar = ({ isOpen, toggleSidebar, conversations = [], currentConversationId, onSelectConversation, onNewChat, onDeleteConversation, onRenameConversation, onTogglePin, onToggleArchive, onSearchClick, onSettingsClick, darkMode, userProfile }) => { const sidebarRef = useRef(null) const [activeMenuId, setActiveMenuId] = React.useState(() => { return sessionStorage.getItem('activeMenuId') || null }) const [isHistoryCollapsed, setIsHistoryCollapsed] = useState(() => { return localStorage.getItem('isHistoryCollapsed') === 'true' }) const [editingId, setEditingId] = useState(() => { return sessionStorage.getItem('editingId') || null }) const [editTitle, setEditTitle] = useState(() => { return sessionStorage.getItem('editTitle') || '' }) const [menuPlacement, setMenuPlacement] = useState(() => { return sessionStorage.getItem('menuPlacement') || 'bottom' }) const pinnedChats = conversations.filter(c => c.isPinned && !c.isArchived) const activeChats = conversations.filter(c => !c.isPinned && !c.isArchived) const handleStartRename = (conv) => { setEditingId(conv.id) setEditTitle(conv.title || 'Đoạn chat mới') setActiveMenuId(null) sessionStorage.setItem('isNewRename', 'true') } const handleSaveRename = (id) => { if (editTitle.trim()) { onRenameConversation(id, editTitle.trim()) } setEditingId(null) } const handleCancelRename = () => { setEditingId(null) } // Close menu when clicking outside React.useEffect(() => { const handleClickOutside = () => setActiveMenuId(null) window.addEventListener('click', handleClickOutside) return () => window.removeEventListener('click', handleClickOutside) }, []) useEffect(() => { localStorage.setItem('isHistoryCollapsed', isHistoryCollapsed) }, [isHistoryCollapsed]) useEffect(() => { if (activeMenuId) { sessionStorage.setItem('activeMenuId', activeMenuId) sessionStorage.setItem('menuPlacement', menuPlacement) } else { sessionStorage.removeItem('activeMenuId') sessionStorage.removeItem('menuPlacement') } }, [activeMenuId, menuPlacement]) useEffect(() => { if (editingId) { sessionStorage.setItem('editingId', editingId) sessionStorage.setItem('editTitle', editTitle) } else { sessionStorage.removeItem('editingId') sessionStorage.removeItem('editTitle') } }, [editingId, editTitle]) const historyScrollRef = useRef(null) // Handle history scroll persistence const handleHistoryScroll = (e) => { if (!isOpen) return // Only save if open sessionStorage.setItem('sidebarScrollTop', e.target.scrollTop) } React.useLayoutEffect(() => { if (!isHistoryCollapsed && historyScrollRef.current) { const savedScroll = sessionStorage.getItem('sidebarScrollTop') if (savedScroll) { historyScrollRef.current.scrollTop = parseInt(savedScroll, 10) } } }, [isHistoryCollapsed, conversations]) // Restore when expanded or conversations change const renderChatItem = (conv) => (
onSelectConversation(conv.id)} >
{editingId === conv.id ? (
e.stopPropagation()}> setEditTitle(e.target.value)} onBlur={() => handleSaveRename(conv.id)} onKeyDown={(e) => { if (e.key === 'Enter') handleSaveRename(conv.id) if (e.key === 'Escape') handleCancelRename() }} autoFocus spellCheck="false" autoComplete="off" onFocus={e => { // Only select all if this is NOT a restored state from refresh const isRestored = !sessionStorage.getItem('isNewRename'); if (!isRestored) { e.target.select(); sessionStorage.removeItem('isNewRename'); } }} />
) : (
{conv.isPinned && } {conv.title || 'Đoạn chat mới'}
)} {/* Chat Actions Menu */} {!editingId && (
{activeMenuId === conv.id && (
e.stopPropagation()}>
)}
)}
) return (
{/* Header Actions */}
{isOpen && ( )}
Ảnh MỚI
Ứng dụng
Dự án
{/* Clickable area when sidebar is closed - from "Dự án" down to footer (but not including footer) */} {!isOpen && (
)}
setIsHistoryCollapsed(!isHistoryCollapsed)} id="tour-history-label" > Các đoạn chat của bạn {isHistoryCollapsed ? : }
{!isHistoryCollapsed && (
{pinnedChats.length > 0 && (
{pinnedChats.map(renderChatItem)}
)}
{activeChats.length > 0 ? ( activeChats.map(renderChatItem) ) : (
Chưa có cuộc trò chuyện nào
)}
)}
onSettingsClick('account')}>
{userProfile?.avatar ? ( Avatar ) : (
{userProfile?.name?.charAt(0) || 'U'}
)}
{userProfile?.name || 'Vô danh'}
Free
) } export default Sidebar