File size: 3,896 Bytes
f0743f4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | 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);
// Track current page index and cursor history
const [currentPageIndex, setCurrentPageIndex] = useState(0);
const cursorHistoryRef = useRef<Array<string | null>>([null]); // Start with null for first page
const prevFiltersRef = useRef({ name, category });
const groupsQuery = usePromptGroupsInfiniteQuery(
{
name,
pageSize,
category,
},
{
enabled: hasAccess,
},
);
// Get the current page data
const currentPageData = useMemo(() => {
if (!hasAccess || !groupsQuery.data?.pages || groupsQuery.data.pages.length === 0) {
return null;
}
// Ensure we don't go out of bounds
const pageIndex = Math.min(currentPageIndex, groupsQuery.data.pages.length - 1);
return groupsQuery.data.pages[pageIndex];
}, [hasAccess, groupsQuery.data?.pages, currentPageIndex]);
// Get prompt groups for current page
const promptGroups = useMemo(() => {
return currentPageData?.promptGroups || [];
}, [currentPageData]);
// Calculate pagination state
const hasNextPage = useMemo(() => {
if (!currentPageData) return false;
// If we're not on the last loaded page, we have a next page
if (currentPageIndex < (groupsQuery.data?.pages?.length || 0) - 1) {
return true;
}
// If we're on the last loaded page, check if there are more from backend
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;
// Navigate to next page
const nextPage = useCallback(async () => {
if (!hasAccess || !hasNextPage) return;
const nextPageIndex = currentPageIndex + 1;
// Check if we need to load more data
if (nextPageIndex >= (groupsQuery.data?.pages?.length || 0)) {
// We need to fetch the next page
const result = await groupsQuery.fetchNextPage();
if (result.isSuccess && result.data?.pages) {
// Update cursor history with the cursor for the next page
const lastPage = result.data.pages[result.data.pages.length - 2]; // Get the page before the newly fetched one
if (lastPage?.after && !cursorHistoryRef.current.includes(lastPage.after)) {
cursorHistoryRef.current.push(lastPage.after);
}
}
}
setCurrentPageIndex(nextPageIndex);
}, [hasAccess, currentPageIndex, hasNextPage, groupsQuery]);
// Navigate to previous page
const prevPage = useCallback(() => {
if (!hasAccess || !hasPreviousPage) return;
setCurrentPageIndex(currentPageIndex - 1);
}, [hasAccess, currentPageIndex, hasPreviousPage]);
// Reset when filters change
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,
};
}
|