import { useEffect, useState, useCallback } from 'react' import { fetchAPI } from '../api/client' import Pagination from '../components/Pagination' import ErrorBanner from '../components/ErrorBanner' import Loading from '../components/Loading' interface ActivityEvent { id: number event_type: string media_id: number | null media_type: string | null title: string description: string | null data: Record created_at: string } interface PaginatedResponse { data: ActivityEvent[] total: number page: number page_size: number total_pages: number } const PAGE_SIZE = 50 function eventTypeBadge(type: string): { label: string; className: string } { switch (type) { case 'grab': return { label: 'Grab', className: 'bg-blue-600' } case 'import': return { label: 'Import', className: 'bg-green-600' } case 'download_complete': return { label: 'Download', className: 'bg-green-600' } case 'download_failed': return { label: 'Failed', className: 'bg-red-600' } case 'quality_upgrade': return { label: 'Upgrade', className: 'bg-purple-600' } case 'safety_block': return { label: 'Blocked', className: 'bg-orange-600' } case 'error': return { label: 'Error', className: 'bg-red-600' } default: return { label: 'Info', className: 'bg-gray-600' } } } function formatTimeAgo(dateStr: string): string { const diff = Date.now() - new Date(dateStr).getTime() const minutes = Math.floor(diff / 60000) if (minutes < 60) return `${minutes}m ago` const hours = Math.floor(minutes / 60) if (hours < 24) return `${hours}h ago` const days = Math.floor(hours / 24) return `${days}d ago` } export default function Activity() { const [events, setEvents] = useState([]) const [total, setTotal] = useState(0) const [page, setPage] = useState(1) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [typeFilter, setTypeFilter] = useState('') const fetchActivity = useCallback(() => { setLoading(true) setError(null) let url = `/api/activity?page=${page}&page_size=${PAGE_SIZE}` if (typeFilter) url += `&event_type=${typeFilter}` fetchAPI(url) .then(res => { setEvents(res.data ?? []) setTotal(res.total) }) .catch(err => setError(err.message || 'Something went wrong. Please try again.')) .finally(() => setLoading(false)) }, [page, typeFilter]) useEffect(() => { fetchActivity() }, [fetchActivity]) return (

Activity

{error && } {loading ? ( ) : events.length === 0 ? (
No activity events
) : ( <>
{events.map(event => { const badge = eventTypeBadge(event.event_type) return ( ) })}
Type Title Media Time
{badge.label}

{event.title}

{event.description && (

{event.description}

)}
{event.media_id != null ? `${event.media_type} #${event.media_id}` : '—'} {formatTimeAgo(event.created_at)}
)}
) }