|
|
@@ -2,12 +2,14 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|
|
|
|
|
import { useTranslation } from 'next-i18next';
|
|
|
import Link from 'next/link';
|
|
|
+import useSWRInfinite, { SWRInfiniteResponse } from 'swr/infinite';
|
|
|
|
|
|
import { apiv3Get } from '~/client/util/apiv3-client';
|
|
|
import { IPageHasId } from '~/interfaces/page';
|
|
|
import { useCurrentPagePath } from '~/stores/page';
|
|
|
import { useTimelineOptions } from '~/stores/renderer';
|
|
|
|
|
|
+import InfiniteScroll from './InfiniteScroll';
|
|
|
import { RevisionLoader } from './Page/RevisionLoader';
|
|
|
import PaginationWrapper from './PaginationWrapper';
|
|
|
|
|
|
@@ -42,30 +44,39 @@ const TimelineCard = ({ page }: TimelineCardProps): JSX.Element => {
|
|
|
);
|
|
|
};
|
|
|
|
|
|
+type PageTimelineResult = {
|
|
|
+ pages: IPageHasId[],
|
|
|
+ totalCount: number,
|
|
|
+ offset: number,
|
|
|
+}
|
|
|
+const useSWRINFxPageTimeline = (path: string, limit: number) : SWRInfiniteResponse<PageTimelineResult, Error> => {
|
|
|
+ return useSWRInfinite(
|
|
|
+ (pageIndex, previousPageData) => {
|
|
|
+ if (previousPageData != null && previousPageData.pages.length === 0) return null;
|
|
|
+
|
|
|
+ return ['/pages/list', path, pageIndex + 1, limit];
|
|
|
+ },
|
|
|
+ ([endpoint, path, page, limit]) => apiv3Get<PageTimelineResult>(endpoint, { path, page, limit }).then(response => response.data),
|
|
|
+ {
|
|
|
+ revalidateFirstPage: false,
|
|
|
+ revalidateAll: false,
|
|
|
+ },
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
|
|
|
export const PageTimeline = (): JSX.Element => {
|
|
|
- const [activePage, setActivePage] = useState(1);
|
|
|
- const [totalPageItems, setTotalPageItems] = useState(0);
|
|
|
- const [limit, setLimit] = useState(10);
|
|
|
- const [pages, setPages] = useState<IPageHasId[] | null>(null);
|
|
|
|
|
|
- const { data: currentPagePath } = useCurrentPagePath();
|
|
|
+ const PER_PAGE = 5;
|
|
|
const { t } = useTranslation();
|
|
|
+ const { data: currentPagePath } = useCurrentPagePath();
|
|
|
+ const swrInfinitexPageTimeline = useSWRINFxPageTimeline(currentPagePath, PER_PAGE);
|
|
|
+ const { data } = swrInfinitexPageTimeline;
|
|
|
|
|
|
- const handlePage = useCallback(async(selectedPage: number) => {
|
|
|
- if (currentPagePath == null) { return }
|
|
|
- const res = await apiv3Get('/pages/list', { path: currentPagePath, page: selectedPage });
|
|
|
- setTotalPageItems(res.data.totalCount);
|
|
|
- setPages(res.data.pages);
|
|
|
- setLimit(res.data.limit);
|
|
|
- setActivePage(selectedPage);
|
|
|
- }, [currentPagePath]);
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- handlePage(1);
|
|
|
- }, [handlePage]);
|
|
|
+ const isEmpty = data?.[0]?.pages.length === 0;
|
|
|
+ const isReachingEnd = isEmpty || (data != null && data[data.length - 1]?.pages.length < PER_PAGE);
|
|
|
|
|
|
- if (pages == null || pages.length === 0) {
|
|
|
+ if (data == null || isEmpty) {
|
|
|
return (
|
|
|
<div className="mt-2">
|
|
|
{/* eslint-disable-next-line react/no-danger */}
|
|
|
@@ -76,14 +87,16 @@ export const PageTimeline = (): JSX.Element => {
|
|
|
|
|
|
return (
|
|
|
<div>
|
|
|
- { pages.map(page => <TimelineCard key={page._id} page={page} />) }
|
|
|
- <PaginationWrapper
|
|
|
- activePage={activePage}
|
|
|
- changePage={handlePage}
|
|
|
- totalItemsCount={totalPageItems}
|
|
|
- pagingLimit={limit}
|
|
|
- align="center"
|
|
|
- />
|
|
|
+ <InfiniteScroll
|
|
|
+ swrInifiniteResponse={swrInfinitexPageTimeline}
|
|
|
+ isReachingEnd={isReachingEnd}
|
|
|
+ >
|
|
|
+ { data != null && data.map(apiResult => apiResult.pages).flat()
|
|
|
+ .map(page => (
|
|
|
+ <TimelineCard key={page._id} page={page} />
|
|
|
+ ))
|
|
|
+ }
|
|
|
+ </InfiniteScroll>
|
|
|
</div>
|
|
|
);
|
|
|
};
|