/** * Activity Feed Page * * Full-page view of real-time project activity with: * - Real-time SSE connection * - Event filtering and search * - Time-based grouping * - Approval handling */ 'use client'; import { useState, useCallback } from 'react'; import { useProjectEvents } from '@/lib/hooks/useProjectEvents'; import { ActivityFeed } from '@/components/activity'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { RefreshCw, Bell, BellOff, AlertTriangle } from 'lucide-react'; import { EventType, type ProjectEvent } from '@/lib/types/events'; import { toast } from 'sonner'; // For demo purposes, use a placeholder project ID // In a real app, this would come from route params or user context const DEMO_PROJECT_ID = 'demo-project-001'; // Demo events for when SSE is not connected const DEMO_EVENTS: ProjectEvent[] = [ { id: 'demo-001', type: EventType.APPROVAL_REQUESTED, timestamp: new Date(Date.now() - 1000 * 60 * 5).toISOString(), project_id: DEMO_PROJECT_ID, actor_id: 'agent-001', actor_type: 'agent', payload: { approval_id: 'apr-001', approval_type: 'architecture_decision', description: 'Approval required for API design document for the checkout flow.', requested_by: 'Architect', timeout_minutes: 60, }, }, { id: 'demo-002', type: EventType.AGENT_MESSAGE, timestamp: new Date(Date.now() - 1000 * 60 * 10).toISOString(), project_id: DEMO_PROJECT_ID, actor_id: 'agent-002', actor_type: 'agent', payload: { agent_instance_id: 'agent-002', message: 'Completed JWT token generation and validation. Moving on to session management.', message_type: 'info', metadata: { progress: 65 }, }, }, { id: 'demo-003', type: EventType.AGENT_STATUS_CHANGED, timestamp: new Date(Date.now() - 1000 * 60 * 20).toISOString(), project_id: DEMO_PROJECT_ID, actor_id: 'agent-003', actor_type: 'agent', payload: { agent_instance_id: 'agent-003', previous_status: 'idle', new_status: 'active', reason: 'Started working on product catalog component', }, }, { id: 'demo-004', type: EventType.ISSUE_UPDATED, timestamp: new Date(Date.now() - 1000 * 60 * 30).toISOString(), project_id: DEMO_PROJECT_ID, actor_id: 'agent-002', actor_type: 'agent', payload: { issue_id: 'issue-038', changes: { status: { from: 'in_progress', to: 'in_review' } }, }, }, { id: 'demo-005', type: EventType.SPRINT_STARTED, timestamp: new Date(Date.now() - 1000 * 60 * 60 * 2).toISOString(), project_id: DEMO_PROJECT_ID, actor_id: null, actor_type: 'system', payload: { sprint_id: 'sprint-003', sprint_name: 'Sprint 3 - Authentication', goal: 'Complete user authentication module', issue_count: 8, }, }, { id: 'demo-006', type: EventType.WORKFLOW_COMPLETED, timestamp: new Date(Date.now() - 1000 * 60 * 60 * 24).toISOString(), project_id: DEMO_PROJECT_ID, actor_id: null, actor_type: 'system', payload: { workflow_id: 'wf-001', duration_seconds: 3600, result: { issues_completed: 5, code_coverage: 92 }, }, }, { id: 'demo-007', type: EventType.ISSUE_CREATED, timestamp: new Date(Date.now() - 1000 * 60 * 60 * 48).toISOString(), project_id: DEMO_PROJECT_ID, actor_id: 'agent-001', actor_type: 'agent', payload: { issue_id: 'issue-050', title: 'Add rate limiting to API endpoints', priority: 'medium', labels: ['security', 'api'], }, }, ]; export default function ActivityFeedPage() { const [notificationsEnabled, setNotificationsEnabled] = useState(true); // SSE hook for real-time events const { events: sseEvents, connectionState, reconnect, isConnected, } = useProjectEvents(DEMO_PROJECT_ID, { autoConnect: true, onEvent: (event) => { // Show notification for new events if enabled if (notificationsEnabled && event.type === EventType.APPROVAL_REQUESTED) { toast.info('New approval request', { description: 'An agent is requesting your approval.', }); } }, }); // Use demo events when not connected or no events received const events = isConnected && sseEvents.length > 0 ? sseEvents : DEMO_EVENTS; // Approval handlers const handleApprove = useCallback((event: ProjectEvent) => { // In a real app, this would call an API to approve the request toast.success('Approval granted', { description: `Approved request ${event.id}`, }); }, []); const handleReject = useCallback((event: ProjectEvent) => { // In a real app, this would call an API to reject the request toast.info('Approval rejected', { description: `Rejected request ${event.id}`, }); }, []); const handleEventClick = useCallback((event: ProjectEvent) => { // In a real app, this might navigate to a detail view if (process.env.NODE_ENV === 'development') { console.log('[ActivityFeedPage] Event clicked:', event); } }, []); const pendingCount = events.filter((e) => e.type === EventType.APPROVAL_REQUESTED).length; return (
Real-time updates from your projects
Demo Mode: Showing sample events. Connect to a real project to see live updates.