/** * RecentActivityWidget - Shows last 5 significant operations * Displays AI task completions, publishing events, etc. */ import { Link } from 'react-router-dom'; import { GroupIcon, BoltIcon, FileTextIcon, FileIcon, PaperPlaneIcon, ListIcon, AlertIcon, CheckCircleIcon, } from '../../icons'; export interface ActivityItem { id: string; type: 'clustering' | 'ideas' | 'content' | 'images' | 'published' | 'keywords' | 'error' | 'sync'; title: string; description: string; timestamp: Date; href?: string; success?: boolean; } interface RecentActivityWidgetProps { activities: ActivityItem[]; loading?: boolean; } /** * Activity config with solid colored backgrounds for visual distinction: * - clustering: purple/pink (matches Clusters module) * - ideas: warning/amber (matches Ideas module) * - content: brand/primary (blue) - matches Writer content module * - images: purple/pink (matches Images module) * - published: success/green (matches Published module) * - keywords: brand/primary (blue) - matches Keywords module * - error: error/red * - sync: success/green */ const activityConfig: Record = { clustering: { icon: GroupIcon, gradient: 'from-purple-500 to-purple-600' }, ideas: { icon: BoltIcon, gradient: 'from-warning-500 to-warning-600' }, content: { icon: FileTextIcon, gradient: 'from-brand-500 to-brand-600' }, images: { icon: FileIcon, gradient: 'from-purple-500 to-purple-600' }, published: { icon: PaperPlaneIcon, gradient: 'from-success-500 to-success-600' }, keywords: { icon: ListIcon, gradient: 'from-brand-500 to-brand-600' }, error: { icon: AlertIcon, gradient: 'from-error-500 to-error-600' }, sync: { icon: CheckCircleIcon, gradient: 'from-success-500 to-success-600' }, }; // Default config for unknown activity types const defaultActivityConfig = { icon: BoltIcon, gradient: 'from-gray-500 to-gray-600' }; function formatRelativeTime(date: Date): string { const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffMins = Math.floor(diffMs / 60000); const diffHours = Math.floor(diffMs / 3600000); const diffDays = Math.floor(diffMs / 86400000); if (diffMins < 1) return 'Just now'; if (diffMins < 60) return `${diffMins}m ago`; if (diffHours < 24) return `${diffHours}h ago`; if (diffDays === 1) return 'Yesterday'; if (diffDays < 7) return `${diffDays}d ago`; return date.toLocaleDateString(); } export default function RecentActivityWidget({ activities, loading }: RecentActivityWidgetProps) { return (
{/* Header */}

Recent Activity

{/* Activity List */}
{loading ? ( // Loading skeleton Array.from({ length: 5 }).map((_, i) => (
)) ) : activities.length === 0 ? (

No recent activity

AI operations will appear here

) : ( activities.slice(0, 5).map((activity) => { const config = activityConfig[activity.type] || defaultActivityConfig; const Icon = config.icon; const content = (

{activity.title}

{formatRelativeTime(activity.timestamp)}

); return activity.href ? ( {content} ) : (
{content}
); }) )}
{/* View All Link */} {activities.length > 0 && ( View All Activity → )}
); }