import React, { useEffect, useState } from 'react' function actorLabel(item) { if (!item?.user) { return 'Someone' } return item.user.username ? `@${item.user.username}` : item.user.name || 'User' } function describeActivity(item) { const artworkTitle = item?.artwork?.title || 'an artwork' const mentionTarget = item?.mentioned_user?.username || item?.mentioned_user?.name || 'someone' const reactionLabel = item?.reaction?.label || 'reacted' switch (item?.type) { case 'comment': return `commented on ${artworkTitle}` case 'reply': return `replied on ${artworkTitle}` case 'reaction': return `${reactionLabel.toLowerCase()} on ${artworkTitle}` case 'mention': return `mentioned @${mentionTarget} on ${artworkTitle}` default: return 'shared new activity' } } function timeLabel(dateString) { const date = new Date(dateString) if (Number.isNaN(date.getTime())) { return 'just now' } return date.toLocaleString() } export default function ActivityFeed() { const [items, setItems] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState('') useEffect(() => { let cancelled = false async function load() { try { setLoading(true) const response = await window.axios.get('/api/activity', { params: { filter: 'my', per_page: 8, }, }) if (!cancelled) { setItems(Array.isArray(response.data?.data) ? response.data.data : []) setError('') } } catch (err) { if (!cancelled) { setError('Could not load activity right now.') } } finally { if (!cancelled) { setLoading(false) } } } load() return () => { cancelled = true } }, []) return (

Activity Feed

Recent actions
{loading ?

Loading activity...

: null} {error ?

{error}

: null} {!loading && !error && items.length === 0 ? (

No recent activity yet.

) : null} {!loading && !error && items.length > 0 ? (
{items.map((item) => (

{actorLabel(item)} {describeActivity(item)}

{item.comment?.body ? (

{item.comment.body}

) : null}

{timeLabel(item.created_at)}

))}
) : null}
) }