feat: add reusable gallery carousel and ranking feed infrastructure
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
|
||||
export default function ArtworkActions({ artwork, canonicalUrl, mobilePriority = false }) {
|
||||
export default function ArtworkActions({ artwork, canonicalUrl, mobilePriority = false, onStatsChange }) {
|
||||
const [liked, setLiked] = useState(Boolean(artwork?.viewer?.is_liked))
|
||||
const [favorited, setFavorited] = useState(Boolean(artwork?.viewer?.is_favorited))
|
||||
const [reporting, setReporting] = useState(false)
|
||||
@@ -17,11 +17,16 @@ export default function ArtworkActions({ artwork, canonicalUrl, mobilePriority =
|
||||
if (!artwork?.id) return
|
||||
const key = `sb_viewed_${artwork.id}`
|
||||
if (typeof sessionStorage !== 'undefined' && sessionStorage.getItem(key)) return
|
||||
if (typeof sessionStorage !== 'undefined') sessionStorage.setItem(key, '1')
|
||||
fetch(`/api/art/${artwork.id}/view`, {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-TOKEN': csrfToken || '', 'Content-Type': 'application/json' },
|
||||
credentials: 'same-origin',
|
||||
}).then(res => {
|
||||
// Only mark as seen after a confirmed success — if the POST fails the
|
||||
// next page load will retry rather than silently skipping forever.
|
||||
if (res.ok && typeof sessionStorage !== 'undefined') {
|
||||
sessionStorage.setItem(key, '1')
|
||||
}
|
||||
}).catch(() => {})
|
||||
}, [artwork?.id]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
@@ -81,6 +86,7 @@ export default function ArtworkActions({ artwork, canonicalUrl, mobilePriority =
|
||||
setLiked(nextState)
|
||||
try {
|
||||
await postInteraction(`/api/artworks/${artwork.id}/like`, { state: nextState })
|
||||
onStatsChange?.({ likes: nextState ? 1 : -1 })
|
||||
} catch {
|
||||
setLiked(!nextState)
|
||||
}
|
||||
@@ -91,6 +97,7 @@ export default function ArtworkActions({ artwork, canonicalUrl, mobilePriority =
|
||||
setFavorited(nextState)
|
||||
try {
|
||||
await postInteraction(`/api/artworks/${artwork.id}/favorite`, { state: nextState })
|
||||
onStatsChange?.({ favorites: nextState ? 1 : -1 })
|
||||
} catch {
|
||||
setFavorited(!nextState)
|
||||
}
|
||||
|
||||
@@ -7,8 +7,8 @@ function formatCount(value) {
|
||||
return `${number}`
|
||||
}
|
||||
|
||||
export default function ArtworkStats({ artwork }) {
|
||||
const stats = artwork?.stats || {}
|
||||
export default function ArtworkStats({ artwork, stats: statsProp }) {
|
||||
const stats = statsProp || artwork?.stats || {}
|
||||
const width = artwork?.dimensions?.width || 0
|
||||
const height = artwork?.dimensions?.height || 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user