mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 12:17:24 +00:00
90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { PageResponse, Resource } from "../network/models.ts";
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
import showToast from "./toast.ts";
|
|
import ResourceCard from "./resource_card.tsx";
|
|
import { Masonry, useInfiniteLoader } from "masonic";
|
|
import Loading from "./loading.tsx";
|
|
import { useAppContext } from "./AppContext.tsx";
|
|
|
|
export default function ResourcesView({
|
|
loader,
|
|
storageKey,
|
|
actionBuilder,
|
|
}: {
|
|
loader: (page: number) => Promise<PageResponse<Resource>>;
|
|
storageKey?: string;
|
|
actionBuilder?: (resource: Resource) => React.ReactNode;
|
|
}) {
|
|
const [data, setData] = useState<Resource[]>([]);
|
|
const pageRef = useRef(1);
|
|
const totalPagesRef = useRef(1);
|
|
const isLoadingRef = useRef(false);
|
|
|
|
const appContext = useAppContext();
|
|
|
|
useEffect(() => {
|
|
if (storageKey) {
|
|
const data = appContext.get(storageKey + "/data");
|
|
const page = appContext.get(storageKey + "/page");
|
|
const totalPages = appContext.get(storageKey + "/totalPages");
|
|
console.log("loading data", data, page, totalPages);
|
|
if (data) {
|
|
setData(data);
|
|
pageRef.current = page;
|
|
totalPagesRef.current = totalPages;
|
|
}
|
|
}
|
|
}, [appContext, storageKey]);
|
|
|
|
useEffect(() => {
|
|
if (storageKey && data.length > 0) {
|
|
console.log("storing data", data);
|
|
appContext.set(storageKey + "/data", data);
|
|
appContext.set(storageKey + "/page", pageRef.current);
|
|
appContext.set(storageKey + "/totalPages", totalPagesRef.current);
|
|
}
|
|
}, [appContext, data, storageKey]);
|
|
|
|
const loadPage = useCallback(async () => {
|
|
if (pageRef.current > totalPagesRef.current) return;
|
|
if (isLoadingRef.current) return;
|
|
isLoadingRef.current = true;
|
|
const res = await loader(pageRef.current);
|
|
if (!res.success) {
|
|
showToast({ message: res.message, type: "error" });
|
|
} else {
|
|
isLoadingRef.current = false;
|
|
pageRef.current = pageRef.current + 1;
|
|
totalPagesRef.current = res.totalPages ?? 1;
|
|
let data = res.data ?? [];
|
|
setData((prev) => [...prev, ...data]);
|
|
}
|
|
}, [loader]);
|
|
|
|
useEffect(() => {
|
|
loadPage();
|
|
}, [loadPage]);
|
|
|
|
const maybeLoadMore = useInfiniteLoader(loadPage);
|
|
|
|
return (
|
|
<div className={"px-2 pt-2"}>
|
|
<Masonry
|
|
onRender={maybeLoadMore}
|
|
columnWidth={300}
|
|
items={data}
|
|
render={(e) => {
|
|
return (
|
|
<ResourceCard
|
|
resource={e.data}
|
|
key={e.data.id}
|
|
action={actionBuilder?.(e.data)}
|
|
/>
|
|
);
|
|
}}
|
|
></Masonry>
|
|
{pageRef.current <= totalPagesRef.current && <Loading />}
|
|
</div>
|
|
);
|
|
}
|