Defer artwork comments from initial render

This commit is contained in:
2026-08-29 12:07:08 +02:00
parent 8a80aae21e
commit 4ab315e9d7
8 changed files with 267 additions and 138 deletions
+7 -33
View File
@@ -18,6 +18,7 @@ import ArtworkViewer from '../components/viewer/ArtworkViewer'
import ReactionBar from '../components/comments/ReactionBar'
import GroupSummaryPanel from '../components/groups/GroupSummaryPanel'
import SeoHead from '../components/seo/SeoHead'
import { useDeferredSimilarAi } from '../lib/useDeferredSimilarAi'
function publisherToGroupSummary(publisher) {
if (!publisher || publisher.type !== 'group') return null
@@ -42,7 +43,7 @@ function publisherToGroupSummary(publisher) {
}
}
function ArtworkPage({ artwork: initialArtwork, related: initialRelated, presentMd: initialMd, presentLg: initialLg, presentXl: initialXl, presentSq: initialSq, canonicalUrl: initialCanonical, isAuthenticated = false, comments: initialComments = [], groupSummary: initialGroupSummary = null, reactionTotals: initialReactionTotals = {}, seo = null }) {
function ArtworkPage({ artwork: initialArtwork, navigation: initialNavigation = null, related: initialRelated, presentMd: initialMd, presentLg: initialLg, presentXl: initialXl, presentSq: initialSq, canonicalUrl: initialCanonical, isAuthenticated = false, groupSummary: initialGroupSummary = null, reactionTotals: initialReactionTotals = {}, seo = null }) {
const [viewerOpen, setViewerOpen] = useState(false)
const [showMatureArtwork, setShowMatureArtwork] = useState(false)
const openViewer = useCallback(() => setViewerOpen(true), [])
@@ -66,12 +67,12 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
const [presentXl, setPresentXl] = useState(initialXl)
const [presentSq, setPresentSq] = useState(initialSq)
const [related, setRelated] = useState(initialRelated)
const [comments, setComments] = useState(initialComments)
const [canonicalUrl, setCanonicalUrl] = useState(initialCanonical)
const [groupSummary, setGroupSummary] = useState(initialGroupSummary || publisherToGroupSummary(initialArtwork?.publisher))
const [selectedMediaId, setSelectedMediaId] = useState('cover')
const [similarRecommendations, setSimilarRecommendations] = useState([])
const [trendingRecommendations, setTrendingRecommendations] = useState([])
const similarAiAnchorRef = useRef(null)
const { items: deferredSimilarRecommendations } = useDeferredSimilarAi(artwork?.id, similarAiAnchorRef)
// Nav arrow state — populated by ArtworkNavigator once neighbors resolve
const [navState, setNavState] = useState({ hasPrev: false, hasNext: false, navigatePrev: null, navigateNext: null })
@@ -89,32 +90,6 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
.catch(() => setReactionTotals({}))
}, [artwork?.id])
useEffect(() => {
let isCancelled = false
const loadSimilarRecommendations = async () => {
if (!artwork?.id) {
setSimilarRecommendations([])
return
}
try {
const response = await fetch(`/api/art/${artwork.id}/similar-ai`, { credentials: 'same-origin' })
if (!response.ok) throw new Error('similar fetch failed')
const payload = await response.json()
if (!isCancelled) setSimilarRecommendations(payload?.data || [])
} catch {
if (!isCancelled) setSimilarRecommendations([])
}
}
loadSimilarRecommendations()
return () => {
isCancelled = true
}
}, [artwork?.id])
useEffect(() => {
let isCancelled = false
@@ -165,7 +140,6 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
setCanonicalUrl(data.canonical_url ?? window.location.href)
setGroupSummary(data.group_summary ?? publisherToGroupSummary(data.publisher))
setSelectedMediaId('cover')
setSimilarRecommendations([])
setTrendingRecommendations([])
setViewerOpen(false) // close viewer when navigating away
setShowMatureArtwork(false)
@@ -348,7 +322,6 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
{/* Comments */}
<ArtworkComments
artworkId={artwork.id}
comments={comments}
isLoggedIn={isAuthenticated}
loginUrl="/login"
/>
@@ -371,11 +344,11 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
</div>
{/* ── Full-width recommendation rails ─────────────────────────── */}
<div className="mt-14 w-full max-w-screen-2xl mx-auto min-h-[640px]">
<div ref={similarAiAnchorRef} className="mt-14 w-full max-w-screen-2xl mx-auto min-h-[640px]">
<ArtworkRecommendationsRails
artwork={artwork}
related={related}
similarApiData={similarRecommendations}
similarApiData={deferredSimilarRecommendations}
trendingData={trendingRecommendations}
/>
</div>
@@ -384,6 +357,7 @@ function ArtworkPage({ artwork: initialArtwork, related: initialRelated, present
{/* Artwork navigator — prev/next arrows, keyboard, swipe, no page reload */}
<ArtworkNavigator
artworkId={artwork.id}
navigation={artwork.navigation || initialNavigation}
onNavigate={handleNavigate}
onOpenViewer={openViewer}
onReady={setNavState}