| import { useEffect, useMemo, useRef, useState, useCallback } from 'react'; |
| import { useRecoilState } from 'recoil'; |
| import { usePromptGroupsInfiniteQuery } from '~/data-provider'; |
| import store from '~/store'; |
|
|
| export default function usePromptGroupsNav(hasAccess = true) { |
| const [pageSize] = useRecoilState(store.promptsPageSize); |
| const [category] = useRecoilState(store.promptsCategory); |
| const [name, setName] = useRecoilState(store.promptsName); |
|
|
| |
| const [currentPageIndex, setCurrentPageIndex] = useState(0); |
| const cursorHistoryRef = useRef<Array<string | null>>([null]); |
|
|
| const prevFiltersRef = useRef({ name, category }); |
|
|
| const groupsQuery = usePromptGroupsInfiniteQuery( |
| { |
| name, |
| pageSize, |
| category, |
| }, |
| { |
| enabled: hasAccess, |
| }, |
| ); |
|
|
| |
| const currentPageData = useMemo(() => { |
| if (!hasAccess || !groupsQuery.data?.pages || groupsQuery.data.pages.length === 0) { |
| return null; |
| } |
| |
| const pageIndex = Math.min(currentPageIndex, groupsQuery.data.pages.length - 1); |
| return groupsQuery.data.pages[pageIndex]; |
| }, [hasAccess, groupsQuery.data?.pages, currentPageIndex]); |
|
|
| |
| const promptGroups = useMemo(() => { |
| return currentPageData?.promptGroups || []; |
| }, [currentPageData]); |
|
|
| |
| const hasNextPage = useMemo(() => { |
| if (!currentPageData) return false; |
|
|
| |
| if (currentPageIndex < (groupsQuery.data?.pages?.length || 0) - 1) { |
| return true; |
| } |
|
|
| |
| return currentPageData.has_more || false; |
| }, [currentPageData, currentPageIndex, groupsQuery.data?.pages?.length]); |
|
|
| const hasPreviousPage = currentPageIndex > 0; |
| const currentPage = currentPageIndex + 1; |
| const totalPages = hasNextPage ? currentPage + 1 : currentPage; |
|
|
| |
| const nextPage = useCallback(async () => { |
| if (!hasAccess || !hasNextPage) return; |
|
|
| const nextPageIndex = currentPageIndex + 1; |
|
|
| |
| if (nextPageIndex >= (groupsQuery.data?.pages?.length || 0)) { |
| |
| const result = await groupsQuery.fetchNextPage(); |
| if (result.isSuccess && result.data?.pages) { |
| |
| const lastPage = result.data.pages[result.data.pages.length - 2]; |
| if (lastPage?.after && !cursorHistoryRef.current.includes(lastPage.after)) { |
| cursorHistoryRef.current.push(lastPage.after); |
| } |
| } |
| } |
|
|
| setCurrentPageIndex(nextPageIndex); |
| }, [hasAccess, currentPageIndex, hasNextPage, groupsQuery]); |
|
|
| |
| const prevPage = useCallback(() => { |
| if (!hasAccess || !hasPreviousPage) return; |
| setCurrentPageIndex(currentPageIndex - 1); |
| }, [hasAccess, currentPageIndex, hasPreviousPage]); |
|
|
| |
| useEffect(() => { |
| if (!hasAccess) return; |
|
|
| const filtersChanged = |
| prevFiltersRef.current.name !== name || prevFiltersRef.current.category !== category; |
|
|
| if (filtersChanged) { |
| setCurrentPageIndex(0); |
| cursorHistoryRef.current = [null]; |
| prevFiltersRef.current = { name, category }; |
| } |
| }, [hasAccess, name, category]); |
|
|
| return { |
| promptGroups: hasAccess ? promptGroups : [], |
| groupsQuery, |
| currentPage, |
| totalPages, |
| hasNextPage: hasAccess && hasNextPage, |
| hasPreviousPage: hasAccess && hasPreviousPage, |
| nextPage, |
| prevPage, |
| isFetching: hasAccess ? groupsQuery.isFetching : false, |
| name, |
| setName, |
| }; |
| } |
|
|