/** * Recent Activity Component * * Displays recent project activity feed with action items. */ 'use client'; import { formatDistanceToNow } from 'date-fns'; import { Activity, MessageSquare, GitPullRequest, PlayCircle, AlertCircle, Users, Cog, type LucideIcon, } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle, } from '@/components/ui/card'; import { Skeleton } from '@/components/ui/skeleton'; import type { ActivityItem } from './types'; // ============================================================================ // Types // ============================================================================ interface RecentActivityProps { /** Activity items to display */ activities: ActivityItem[]; /** Whether data is loading */ isLoading?: boolean; /** Maximum items to show */ maxItems?: number; /** Callback when "View All" is clicked */ onViewAll?: () => void; /** Callback when an action item is clicked */ onActionClick?: (activityId: string) => void; /** Additional CSS classes */ className?: string; } // ============================================================================ // Helper Functions // ============================================================================ function getActivityIcon(type: ActivityItem['type']): LucideIcon { switch (type) { case 'agent_message': return MessageSquare; case 'issue_update': return GitPullRequest; case 'agent_status': return PlayCircle; case 'approval_request': return AlertCircle; case 'sprint_event': return Users; case 'system': default: return Cog; } } function formatTimestamp(timestamp: string): string { try { return formatDistanceToNow(new Date(timestamp), { addSuffix: true }); } catch { return 'Unknown time'; } } // ============================================================================ // Subcomponents // ============================================================================ interface ActivityItemRowProps { activity: ActivityItem; onActionClick?: (activityId: string) => void; } function ActivityItemRow({ activity, onActionClick }: ActivityItemRowProps) { const Icon = getActivityIcon(activity.type); const timestamp = formatTimestamp(activity.timestamp); return (

{activity.agent && ( {activity.agent} )}{' '} {activity.message}

{timestamp}

{activity.requires_action && onActionClick && ( )}
); } function RecentActivitySkeleton({ count = 5 }: { count?: number }) { return (
{Array.from({ length: count }).map((_, i) => (
))}
); } // ============================================================================ // Main Component // ============================================================================ export function RecentActivity({ activities, isLoading = false, maxItems = 5, onViewAll, onActionClick, className, }: RecentActivityProps) { if (isLoading) { return ; } const displayedActivities = activities.slice(0, maxItems); return (
{onViewAll && activities.length > maxItems && ( )}
{displayedActivities.length === 0 ? (
) : (
{displayedActivities.map((activity) => ( ))}
)}
); }