mirror of https://github.com/usememos/memos
refactor: paged memo list container
parent
41976cb894
commit
339c38750f
@ -0,0 +1,81 @@
|
|||||||
|
import { Button } from "@mui/joy";
|
||||||
|
import { ArrowDownIcon } from "lucide-react";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts";
|
||||||
|
import { useMemoList, useMemoStore } from "@/store/v1";
|
||||||
|
import { Memo } from "@/types/proto/api/v1/memo_service";
|
||||||
|
import { useTranslate } from "@/utils/i18n";
|
||||||
|
import Empty from "../Empty";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
renderer: (memo: Memo) => JSX.Element;
|
||||||
|
listSort?: (list: Memo[]) => Memo[];
|
||||||
|
filter?: string;
|
||||||
|
pageSize?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
isRequesting: boolean;
|
||||||
|
nextPageToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PagedMemoList = (props: Props) => {
|
||||||
|
const t = useTranslate();
|
||||||
|
const memoStore = useMemoStore();
|
||||||
|
const memoList = useMemoList();
|
||||||
|
const [state, setState] = useState<State>({
|
||||||
|
isRequesting: false,
|
||||||
|
nextPageToken: "",
|
||||||
|
});
|
||||||
|
const sortedMemoList = props.listSort ? props.listSort(memoList.value) : memoList.value;
|
||||||
|
|
||||||
|
const setIsRequesting = (isRequesting: boolean) => {
|
||||||
|
setState((state) => ({ ...state, isRequesting }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchMoreMemos = async () => {
|
||||||
|
setIsRequesting(true);
|
||||||
|
const response = await memoStore.fetchMemos({
|
||||||
|
filter: props.filter || "",
|
||||||
|
pageSize: props.pageSize || DEFAULT_LIST_MEMOS_PAGE_SIZE,
|
||||||
|
pageToken: state.nextPageToken,
|
||||||
|
});
|
||||||
|
setState(() => ({
|
||||||
|
isRequesting: false,
|
||||||
|
nextPageToken: response.nextPageToken,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
memoList.reset();
|
||||||
|
setState((state) => ({ ...state, nextPageToken: "" }));
|
||||||
|
fetchMoreMemos();
|
||||||
|
}, [props.filter, props.pageSize]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{sortedMemoList.map((memo) => props.renderer(memo))}
|
||||||
|
{state.nextPageToken && (
|
||||||
|
<div className="w-full flex flex-row justify-center items-center my-4">
|
||||||
|
<Button
|
||||||
|
variant="plain"
|
||||||
|
color="neutral"
|
||||||
|
loading={state.isRequesting}
|
||||||
|
endDecorator={<ArrowDownIcon className="w-4 h-auto" />}
|
||||||
|
onClick={() => fetchMoreMemos()}
|
||||||
|
>
|
||||||
|
{t("memo.load-more")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!state.nextPageToken && sortedMemoList.length === 0 && (
|
||||||
|
<div className="w-full mt-12 mb-8 flex flex-col justify-center items-center italic">
|
||||||
|
<Empty />
|
||||||
|
<p className="mt-2 text-gray-600 dark:text-gray-400">{t("message.no-data")}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PagedMemoList;
|
@ -0,0 +1,3 @@
|
|||||||
|
import PagedMemoList from "./PagedMemoList";
|
||||||
|
|
||||||
|
export default PagedMemoList;
|
Loading…
Reference in New Issue