Skip to content

Commit

Permalink
Return pageSize and hasMorePages as part of usePaginatedAPIFetch resu…
Browse files Browse the repository at this point in the history
…lt (#6845)
  • Loading branch information
acelaya authored Nov 11, 2024
1 parent ebbcca9 commit 6057bf6
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
25 changes: 24 additions & 1 deletion lms/static/scripts/frontend_apps/utils/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,16 @@ export type PaginatedFetchResult<T> = Omit<FetchResult<T>, 'mutate'> & {
/** Determines if currently loading the first page */
isLoadingFirstPage: boolean;
loadNextPage: () => void;

/**
* The size of every page (maximum number of results returned per page).
* If the API indicates there is only one page, this will be undefined. You
* can trust `data.length` as the total number of items in that case.
*/
pageSize?: number;

/** Whether there are still more pages to load or not */
hasMorePages: boolean;
};

/**
Expand All @@ -338,6 +348,8 @@ export function usePaginatedAPIFetch<
): PaginatedFetchResult<ListType> {
const [nextPageURL, setNextPageURL] = useState<string>();
const [currentList, setCurrentList] = useState<ListType>();
const [pageSize, setPageSize] = useState<number>();
const [hasMorePages, setHasMorePages] = useState(false);

const fetchResult = useAPIFetch<FetchType>(
nextPageURL ?? path,
Expand All @@ -350,15 +362,24 @@ export function usePaginatedAPIFetch<
}
}, [fetchResult.data?.pagination.next, fetchResult.isLoading]);

// Every time data is loaded, append the result to the list
useEffect(() => {
// Every time data is loaded, append the result to the list
setCurrentList(prev => {
if (!fetchResult.data) {
return prev;
}

return [...(prev ?? []), ...fetchResult.data[prop]] as ListType;
});

const hasMorePages = !!fetchResult.data?.pagination.next;
setHasMorePages(hasMorePages);

// Set pageSize if the API indicated there are more pages.
// Once page size has been set, we keep the value, ignoring next page loads
if (hasMorePages) {
setPageSize(prev => prev ?? fetchResult.data?.[prop].length);
}
}, [prop, fetchResult.data]);

// Every time params change, discard previous pages and start from scratch
Expand All @@ -382,5 +403,7 @@ export function usePaginatedAPIFetch<
error: fetchResult.error,
retry: fetchResult.retry,
loadNextPage,
pageSize,
hasMorePages,
};
}
27 changes: 27 additions & 0 deletions lms/static/scripts/frontend_apps/utils/test/api-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,10 @@ describe('usePaginatedAPIFetch', () => {
{!result.isLoading &&
(result.data ? result.data.join(',') : 'No content')}
</div>
<div data-testid="page-size">{result.pageSize ?? 'No page size'}</div>
<div data-testid="has-more-pages">
{result.hasMorePages ? 'Yes' : 'No'}
</div>

<button
onClick={() => result.loadNextPage()}
Expand All @@ -589,6 +593,14 @@ describe('usePaginatedAPIFetch', () => {
return wrapper.find('[data-testid="main-content"]').text();
}

function getPageSize(wrapper) {
return wrapper.find('[data-testid="page-size"]').text();
}

function getHasMorePages(wrapper) {
return wrapper.find('[data-testid="has-more-pages"]').text();
}

function reRender(wrapper) {
// Setting the same props again will force the component to re-render
wrapper.setProps(wrapper.props());
Expand Down Expand Up @@ -652,6 +664,21 @@ describe('usePaginatedAPIFetch', () => {
});
assert.equal(getMainContent(wrapper), 'No content');
});

it('returns page size when API indicates there is a `next` page', () => {
const wrapper = createComponent();

assert.equal(getPageSize(wrapper), `${pageResults[0].items.length}`);
assert.equal(getHasMorePages(wrapper), 'Yes');
});

it('does not return page size when API indicates there is only one page', () => {
mockFetchResult(pageResults[2]);
const wrapper = createComponent();

assert.equal(getPageSize(wrapper), 'No page size');
assert.equal(getHasMorePages(wrapper), 'No');
});
});

describe('usePolledAPIFetch', () => {
Expand Down

0 comments on commit 6057bf6

Please sign in to comment.