import { useCallback, useEffect, useState, useMemo, memo } from 'react'; import { useRecoilValue } from 'recoil'; import { useParams } from 'react-router-dom'; import type { ConversationListResponse } from 'librechat-data-provider'; import { useMediaQuery, useAuthContext, useConversation, useLocalStorage, useNavScrolling, useConversations, useLocalize, } from '~/hooks'; import { useConversationsInfiniteQuery } from '~/data-provider'; import { TooltipProvider, Tooltip } from '~/components/ui'; import { Conversations } from '~/components/Conversations'; import BookmarkNav from './Bookmarks/BookmarkNav'; import AccountSettings from './AccountSettings'; import { useSearchContext } from '~/Providers'; import { Spinner } from '~/components/svg'; import SearchBar from './SearchBar'; import NavToggle from './NavToggle'; import NewChat from './NewChat'; import { cn } from '~/utils'; import store from '~/store'; const Nav = ({ navVisible, setNavVisible, }: { navVisible: boolean; setNavVisible: React.Dispatch>; }) => { const localize = useLocalize(); const { conversationId } = useParams(); const { isAuthenticated } = useAuthContext(); const [navWidth, setNavWidth] = useState('260px'); const [isHovering, setIsHovering] = useState(false); const isSmallScreen = useMediaQuery('(max-width: 768px)'); const [newUser, setNewUser] = useLocalStorage('newUser', true); const [isToggleHovering, setIsToggleHovering] = useState(false); const handleMouseEnter = useCallback(() => { setIsHovering(true); }, []); const handleMouseLeave = useCallback(() => { setIsHovering(false); }, []); useEffect(() => { if (isSmallScreen) { const savedNavVisible = localStorage.getItem('navVisible'); if (savedNavVisible === null) { toggleNavVisible(); } setNavWidth('320px'); } else { setNavWidth('260px'); } }, [isSmallScreen]); const { newConversation } = useConversation(); const [showLoading, setShowLoading] = useState(false); const isSearchEnabled = useRecoilValue(store.isSearchEnabled); const { refreshConversations } = useConversations(); const { pageNumber, searchQuery, setPageNumber, searchQueryRes } = useSearchContext(); const [tags, setTags] = useState([]); const { data, fetchNextPage, hasNextPage, isFetchingNextPage, refetch } = useConversationsInfiniteQuery( { pageNumber: pageNumber.toString(), isArchived: false, tags: tags.length === 0 ? undefined : tags, }, { enabled: isAuthenticated }, ); useEffect(() => { // When a tag is selected, refetch the list of conversations related to that tag refetch(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [tags]); const { containerRef, moveToTop } = useNavScrolling({ setShowLoading, hasNextPage: searchQuery ? searchQueryRes?.hasNextPage : hasNextPage, fetchNextPage: searchQuery ? searchQueryRes?.fetchNextPage : fetchNextPage, isFetchingNextPage: searchQuery ? searchQueryRes?.isFetchingNextPage ?? false : isFetchingNextPage, }); const conversations = useMemo( () => (searchQuery ? searchQueryRes?.data : data)?.pages.flatMap((page) => page.conversations) || [], [data, searchQuery, searchQueryRes?.data], ); const clearSearch = () => { setPageNumber(1); refreshConversations(); if (conversationId == 'search') { newConversation(); } }; const toggleNavVisible = () => { setNavVisible((prev: boolean) => { localStorage.setItem('navVisible', JSON.stringify(!prev)); return !prev; }); if (newUser) { setNewUser(false); } }; const itemToggleNav = () => { if (isSmallScreen) { toggleNavVisible(); } }; return (
{ if (e.key === 'Enter' || e.key === ' ') { toggleNavVisible(); } }} aria-label="Toggle navigation" /> ); }; export default memo(Nav);