update
This commit is contained in:
@@ -192,15 +192,25 @@ function ReportModal({ open, onClose, onSubmit, submitting }) {
|
||||
|
||||
export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStatsChange }) {
|
||||
const [favorited, setFavorited] = useState(Boolean(artwork?.viewer?.is_favorited))
|
||||
const [bookmarked, setBookmarked] = useState(Boolean(artwork?.viewer?.is_bookmarked))
|
||||
const [bookmarkCount, setBookmarkCount] = useState(Number(stats?.bookmarks ?? artwork?.stats?.bookmarks ?? 0))
|
||||
const [downloading, setDownloading] = useState(false)
|
||||
const [reporting, setReporting] = useState(false)
|
||||
const [reported, setReported] = useState(false)
|
||||
const [reportOpen, setReportOpen] = useState(false)
|
||||
const isLoggedIn = artwork?.viewer != null
|
||||
const isLoggedIn = Boolean(artwork?.viewer?.is_authenticated)
|
||||
useEffect(() => {
|
||||
setFavorited(Boolean(artwork?.viewer?.is_favorited))
|
||||
}, [artwork?.id, artwork?.viewer?.is_favorited])
|
||||
|
||||
useEffect(() => {
|
||||
setBookmarked(Boolean(artwork?.viewer?.is_bookmarked))
|
||||
}, [artwork?.id, artwork?.viewer?.is_bookmarked])
|
||||
|
||||
useEffect(() => {
|
||||
setBookmarkCount(Number(stats?.bookmarks ?? artwork?.stats?.bookmarks ?? 0))
|
||||
}, [artwork?.id, artwork?.stats?.bookmarks, stats?.bookmarks])
|
||||
|
||||
const shareUrl = canonicalUrl || artwork?.canonical_url || (typeof window !== 'undefined' ? window.location.href : '#')
|
||||
const csrfToken = typeof document !== 'undefined'
|
||||
? document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
|
||||
@@ -249,6 +259,11 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
}
|
||||
|
||||
const onToggleFavorite = async () => {
|
||||
if (!isLoggedIn) {
|
||||
window.location.href = '/login'
|
||||
return
|
||||
}
|
||||
|
||||
const nextState = !favorited
|
||||
setFavorited(nextState)
|
||||
try {
|
||||
@@ -257,6 +272,26 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
} catch { setFavorited(!nextState) }
|
||||
}
|
||||
|
||||
const onToggleBookmark = async () => {
|
||||
if (!isLoggedIn) {
|
||||
window.location.href = '/login'
|
||||
return
|
||||
}
|
||||
|
||||
const nextState = !bookmarked
|
||||
setBookmarked(nextState)
|
||||
setBookmarkCount((current) => Math.max(0, current + (nextState ? 1 : -1)))
|
||||
|
||||
try {
|
||||
const payload = await postInteraction(`/api/artworks/${artwork.id}/bookmark`, { state: nextState })
|
||||
setBookmarked(Boolean(payload?.is_bookmarked))
|
||||
setBookmarkCount(Number(payload?.stats?.bookmarks ?? 0))
|
||||
} catch {
|
||||
setBookmarked(!nextState)
|
||||
setBookmarkCount((current) => Math.max(0, current + (nextState ? -1 : 1)))
|
||||
}
|
||||
}
|
||||
|
||||
const openReport = () => {
|
||||
if (reported) return
|
||||
setReportOpen(true)
|
||||
@@ -274,6 +309,7 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
}
|
||||
|
||||
const favCount = formatCount(stats?.favorites ?? artwork?.stats?.favorites ?? 0)
|
||||
const savedCount = formatCount(bookmarkCount)
|
||||
const viewCount = formatCount(stats?.views ?? artwork?.stats?.views ?? 0)
|
||||
|
||||
return (
|
||||
@@ -296,6 +332,21 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
<span className="tabular-nums">{favCount}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-label={bookmarked ? 'Remove bookmark' : 'Save artwork'}
|
||||
onClick={onToggleBookmark}
|
||||
className={[
|
||||
'inline-flex items-center gap-2 rounded-full border px-5 py-2.5 text-sm font-medium transition-all duration-200',
|
||||
bookmarked
|
||||
? 'border-amber-400/35 bg-amber-400/14 text-amber-200 shadow-lg shadow-amber-500/10 hover:bg-amber-400/18'
|
||||
: 'border-white/[0.08] bg-white/[0.04] text-white/70 hover:border-white/[0.15] hover:bg-white/[0.07] hover:text-white',
|
||||
].join(' ')}
|
||||
>
|
||||
<BookmarkIcon filled={bookmarked} />
|
||||
<span className="tabular-nums">{savedCount}</span>
|
||||
</button>
|
||||
|
||||
{/* Views stat pill */}
|
||||
<div className="inline-flex items-center gap-2 rounded-full border border-white/[0.08] bg-white/[0.04] px-5 py-2.5 text-sm font-medium text-white/70">
|
||||
<CloudDownIcon />
|
||||
@@ -353,6 +404,21 @@ export default function ArtworkActionBar({ artwork, stats, canonicalUrl, onStats
|
||||
<span className="tabular-nums">{favCount}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-label={bookmarked ? 'Remove bookmark' : 'Save artwork'}
|
||||
onClick={onToggleBookmark}
|
||||
className={[
|
||||
'inline-flex items-center gap-1.5 rounded-full border px-3.5 py-2 text-xs font-medium transition-all',
|
||||
bookmarked
|
||||
? 'border-amber-400/35 bg-amber-400/14 text-amber-200'
|
||||
: 'border-white/[0.08] bg-white/[0.04] text-white/70',
|
||||
].join(' ')}
|
||||
>
|
||||
<BookmarkIcon filled={bookmarked} />
|
||||
<span className="tabular-nums">{savedCount}</span>
|
||||
</button>
|
||||
|
||||
{/* Share */}
|
||||
<ArtworkShareButton artwork={artwork} shareUrl={shareUrl} size="small" isLoggedIn={isLoggedIn} />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user