import React, { useState, useEffect, useRef, useCallback } from 'react'; import _ from 'lodash'; import NewChat from './NewChat'; import Spinner from '../svg/Spinner'; import Pages from '../Conversations/Pages'; import Conversations from '../Conversations'; import NavLinks from './NavLinks'; import { searchFetcher, swr } from '~/utils/fetchers'; import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'; import store from '~/store'; export default function Nav({ navVisible, setNavVisible }) { const [isHovering, setIsHovering] = useState(false); const containerRef = useRef(null); const scrollPositionRef = useRef(null); // const dispatch = useDispatch(); const [conversations, setConversations] = useState([]); // current page const [pageNumber, setPageNumber] = useState(1); // total pages const [pages, setPages] = useState(1); // search const searchQuery = useRecoilValue(store.searchQuery); const isSearchEnabled = useRecoilValue(store.isSearchEnabled); const isSearching = useRecoilValue(store.isSearching); const { newConversation } = store.useConversation(); // current conversation const conversation = useRecoilValue(store.conversation); const { conversationId } = conversation || {}; const setMessages = useSetRecoilState(store.messages); // refreshConversationsHint is used for other components to ask refresh of Nav const refreshConversationsHint = useRecoilValue(store.refreshConversationsHint); const { refreshConversations } = store.useConversations(); const [isFetching, setIsFetching] = useState(false); const onSuccess = (data, searchFetch = false) => { if (isSearching) { return; } let { conversations, pages } = data; if (pageNumber > pages) { setPageNumber(pages); } else { if (!searchFetch) conversations = conversations.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); setConversations(conversations); setPages(pages); } }; const onSearchSuccess = (data, expectedPage) => { const res = data; setConversations(res.conversations); if (expectedPage) { setPageNumber(expectedPage); } setPageNumber(res.pageNumber); setPages(res.pages); setIsFetching(false); if (res.messages?.length > 0) { setMessages(res.messages); // dispatch(setDisabled(true)); } }; // TODO: dont need this const fetch = useCallback( _.partialRight( searchFetcher.bind(null, () => setIsFetching(true)), onSearchSuccess ), [setIsFetching] ); const clearSearch = () => { setPageNumber(1); refreshConversations(); if (conversationId == 'search') { newConversation(); } // dispatch(setDisabled(false)); }; const { data, isLoading, mutate } = swr(`/api/convos?pageNumber=${pageNumber}`, onSuccess, { revalidateOnMount: false }); const nextPage = async () => { moveToTop(); if (!isSearching) { setPageNumber(prev => prev + 1); await mutate(); } else { await fetch(searchQuery, +pageNumber + 1); } }; const previousPage = async () => { moveToTop(); if (!isSearching) { setPageNumber(prev => prev - 1); await mutate(); } else { await fetch(searchQuery, +pageNumber - 1); } }; useEffect(() => { if (!isSearching) { mutate(); } }, [pageNumber, conversationId, refreshConversationsHint]); const moveToTop = () => { const container = containerRef.current; if (container) { scrollPositionRef.current = container.scrollTop; } }; const moveTo = () => { const container = containerRef.current; if (container && scrollPositionRef.current !== null) { const { scrollHeight, clientHeight } = container; const maxScrollTop = scrollHeight - clientHeight; container.scrollTop = Math.min(maxScrollTop, scrollPositionRef.current); } }; const toggleNavVisible = () => { setNavVisible(prev => !prev); }; useEffect(() => { moveTo(); }, [data]); useEffect(() => { setNavVisible(false); }, [conversationId]); const containerClasses = isLoading && pageNumber === 1 ? 'flex flex-col gap-2 text-gray-100 text-sm h-full justify-center items-center' : 'flex flex-col gap-2 text-gray-100 text-sm'; return ( <>
); }