This commit is contained in:
2026-03-20 21:17:26 +01:00
parent 1a62fcb81d
commit 29c3ff8572
229 changed files with 13147 additions and 2577 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import ArtworkGallery from '../../artwork/ArtworkGallery'
function FavSkeleton() {
@@ -14,12 +14,22 @@ function FavSkeleton() {
* Shows artworks the user has favourited.
*/
export default function TabFavourites({ favourites, isOwner, username }) {
const [items, setItems] = useState(favourites ?? [])
const [nextCursor, setNextCursor] = useState(null)
const initialItems = Array.isArray(favourites)
? favourites
: (favourites?.data ?? [])
const [items, setItems] = useState(initialItems)
const [nextCursor, setNextCursor] = useState(favourites?.next_cursor ?? null)
const [loadingMore, setLoadingMore] = useState(false)
const loadMoreRef = useRef(null)
const loadMore = async () => {
useEffect(() => {
setItems(initialItems)
setNextCursor(favourites?.next_cursor ?? null)
}, [favourites, initialItems])
const loadMore = useCallback(async () => {
if (!nextCursor || loadingMore) return
setLoadingMore(true)
try {
const res = await fetch(
@@ -33,7 +43,30 @@ export default function TabFavourites({ favourites, isOwner, username }) {
}
} catch (_) {}
setLoadingMore(false)
}
}, [loadingMore, nextCursor, username])
useEffect(() => {
const node = loadMoreRef.current
if (!node || !nextCursor) {
return undefined
}
const observer = new IntersectionObserver(
(entries) => {
if (entries.some((entry) => entry.isIntersecting)) {
loadMore()
}
},
{
rootMargin: '320px 0px',
}
)
observer.observe(node)
return () => observer.disconnect()
}, [loadMore, nextCursor])
return (
<div
@@ -68,6 +101,10 @@ export default function TabFavourites({ favourites, isOwner, username }) {
{loadingMore && Array.from({ length: 4 }).map((_, i) => <FavSkeleton key={`sk-${i}`} />)}
</ArtworkGallery>
{nextCursor && (
<div ref={loadMoreRef} className="h-6 w-full" aria-hidden="true" />
)}
{nextCursor && (
<div className="mt-8 text-center">
<button