77 lines
2.0 KiB
TypeScript
77 lines
2.0 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
|
import type { AnimalStudiesCursor } from "@/actions/animalStudies/getAnimalStudiesPage";
|
|
import { getAnimalStudiesPage } from "@/actions/animalStudies/getAnimalStudiesPage";
|
|
import JustifiedGallery, { type JustifiedGalleryItem } from "@/components/gallery/JustifiedGallery";
|
|
|
|
export default function AnimalStudiesGallery({
|
|
tagSlugs,
|
|
}: {
|
|
tagSlugs: string[];
|
|
}) {
|
|
const [items, setItems] = useState<JustifiedGalleryItem[]>([]);
|
|
const [cursor, setCursor] = useState<AnimalStudiesCursor>(null);
|
|
const [done, setDone] = useState(false);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
const inFlight = useRef(false);
|
|
|
|
// Reset when tag filter changes (component key may already remount, but keep it safe)
|
|
useEffect(() => {
|
|
setItems([]);
|
|
setCursor(null);
|
|
setDone(false);
|
|
setLoading(false);
|
|
inFlight.current = false;
|
|
}, []);
|
|
|
|
const loadMore = useCallback(async () => {
|
|
if (inFlight.current || done) return;
|
|
inFlight.current = true;
|
|
setLoading(true);
|
|
|
|
try {
|
|
const res = await getAnimalStudiesPage({
|
|
take: 60,
|
|
cursor,
|
|
tagSlugs,
|
|
});
|
|
|
|
setItems((prev) => {
|
|
const seen = new Set(prev.map((x) => x.id));
|
|
const next = res.items.filter((x) => !seen.has(x.id));
|
|
return prev.concat(next);
|
|
});
|
|
|
|
setCursor(res.nextCursor);
|
|
if (!res.nextCursor) setDone(true);
|
|
} finally {
|
|
setLoading(false);
|
|
inFlight.current = false;
|
|
}
|
|
}, [cursor, done, tagSlugs]);
|
|
|
|
useEffect(() => {
|
|
void loadMore();
|
|
}, [loadMore]);
|
|
|
|
return (
|
|
<JustifiedGallery
|
|
items={items}
|
|
hrefFrom="animal-studies"
|
|
showCaption
|
|
targetRowHeight={160}
|
|
targetRowHeightMobile={160}
|
|
maxRowHeight={300}
|
|
maxRowItems={5}
|
|
maxRowItemsMobile={1}
|
|
gap={12}
|
|
onLoadMore={done ? undefined : () => void loadMore()}
|
|
hasMore={!done}
|
|
isLoadingMore={loading}
|
|
/>
|
|
);
|
|
}
|