/** * Projects List Hook * * Provides data for the projects list page with filtering, * sorting, and pagination. * * Uses mock data until backend endpoints are available. * * @see Issue #54 */ import { useQuery } from '@tanstack/react-query'; import type { ProjectStatus } from '@/components/projects/types'; // ============================================================================ // Types // ============================================================================ export interface ProjectListItem { id: string; name: string; description?: string; status: ProjectStatus; complexity: 'low' | 'medium' | 'high'; progress: number; openIssues: number; activeAgents: number; currentSprint?: string; lastActivity: string; createdAt: string; owner: { id: string; name: string; }; tags?: string[]; } export interface ProjectsListParams { search?: string; status?: ProjectStatus | 'all'; complexity?: 'low' | 'medium' | 'high' | 'all'; sortBy?: 'recent' | 'name' | 'progress' | 'issues'; sortOrder?: 'asc' | 'desc'; page?: number; limit?: number; } export interface ProjectsListResponse { data: ProjectListItem[]; pagination: { page: number; limit: number; total: number; totalPages: number; }; } // ============================================================================ // Mock Data // ============================================================================ const mockProjects: ProjectListItem[] = [ { id: 'proj-001', name: 'E-Commerce Platform Redesign', description: 'Complete redesign of the e-commerce platform with modern UI/UX and improved checkout flow', status: 'active', complexity: 'high', progress: 67, openIssues: 12, activeAgents: 4, currentSprint: 'Sprint 3', lastActivity: '2 minutes ago', createdAt: '2025-11-15T10:00:00Z', owner: { id: 'user-001', name: 'Felipe Cardoso' }, tags: ['e-commerce', 'frontend', 'ux'], }, { id: 'proj-002', name: 'Mobile Banking App', description: 'Native mobile app for banking services with biometric authentication and real-time notifications', status: 'active', complexity: 'high', progress: 45, openIssues: 8, activeAgents: 5, currentSprint: 'Sprint 2', lastActivity: '15 minutes ago', createdAt: '2025-11-20T09:00:00Z', owner: { id: 'user-001', name: 'Felipe Cardoso' }, tags: ['mobile', 'fintech', 'security'], }, { id: 'proj-003', name: 'Internal HR Portal', description: 'Employee self-service portal for HR operations including leave requests and performance reviews', status: 'paused', complexity: 'medium', progress: 23, openIssues: 5, activeAgents: 0, currentSprint: 'Sprint 1', lastActivity: '2 days ago', createdAt: '2025-10-01T08:00:00Z', owner: { id: 'user-002', name: 'Maria Santos' }, tags: ['internal', 'hr', 'portal'], }, { id: 'proj-004', name: 'API Gateway Modernization', description: 'Migrate legacy API gateway to cloud-native architecture with improved rate limiting and caching', status: 'active', complexity: 'high', progress: 82, openIssues: 3, activeAgents: 2, currentSprint: 'Sprint 4', lastActivity: '1 hour ago', createdAt: '2025-12-01T11:00:00Z', owner: { id: 'user-001', name: 'Felipe Cardoso' }, tags: ['api', 'cloud', 'infrastructure'], }, { id: 'proj-005', name: 'Customer Analytics Dashboard', description: 'Real-time analytics dashboard for customer behavior insights with ML-powered predictions', status: 'completed', complexity: 'medium', progress: 100, openIssues: 0, activeAgents: 0, lastActivity: '2 weeks ago', createdAt: '2025-09-01T10:00:00Z', owner: { id: 'user-003', name: 'Alex Johnson' }, tags: ['analytics', 'ml', 'dashboard'], }, { id: 'proj-006', name: 'DevOps Pipeline Automation', description: 'Automate CI/CD pipelines with AI-assisted deployments and rollback capabilities', status: 'active', complexity: 'medium', progress: 35, openIssues: 6, activeAgents: 3, currentSprint: 'Sprint 1', lastActivity: '30 minutes ago', createdAt: '2025-12-10T14:00:00Z', owner: { id: 'user-001', name: 'Felipe Cardoso' }, tags: ['devops', 'automation', 'ci-cd'], }, { id: 'proj-007', name: 'Inventory Management System', description: 'Warehouse inventory tracking with barcode scanning and automated reordering', status: 'archived', complexity: 'low', progress: 100, openIssues: 0, activeAgents: 0, lastActivity: '1 month ago', createdAt: '2025-06-15T08:00:00Z', owner: { id: 'user-002', name: 'Maria Santos' }, tags: ['inventory', 'warehouse', 'logistics'], }, { id: 'proj-008', name: 'Customer Support Chatbot', description: 'AI-powered chatbot for 24/7 customer support with sentiment analysis', status: 'active', complexity: 'medium', progress: 58, openIssues: 4, activeAgents: 2, currentSprint: 'Sprint 2', lastActivity: '45 minutes ago', createdAt: '2025-12-05T09:00:00Z', owner: { id: 'user-003', name: 'Alex Johnson' }, tags: ['ai', 'chatbot', 'support'], }, ]; // ============================================================================ // Hook // ============================================================================ /** * Fetches projects list with filtering, sorting, and pagination */ export function useProjects(params: ProjectsListParams = {}) { const { search = '', status = 'all', complexity = 'all', sortBy = 'recent', sortOrder = 'desc', page = 1, limit = 50, } = params; return useQuery({ queryKey: ['projects', { search, status, complexity, sortBy, sortOrder, page, limit }], queryFn: async () => { // Simulate network delay await new Promise((resolve) => setTimeout(resolve, 400)); // Filter projects let filtered = [...mockProjects]; // Search filter if (search) { const searchLower = search.toLowerCase(); filtered = filtered.filter( (p) => p.name.toLowerCase().includes(searchLower) || p.description?.toLowerCase().includes(searchLower) || p.tags?.some((t) => t.toLowerCase().includes(searchLower)) ); } // Status filter if (status !== 'all') { filtered = filtered.filter((p) => p.status === status); } // Complexity filter if (complexity !== 'all') { filtered = filtered.filter((p) => p.complexity === complexity); } // Sort filtered.sort((a, b) => { let comparison = 0; switch (sortBy) { case 'name': comparison = a.name.localeCompare(b.name); break; case 'progress': comparison = a.progress - b.progress; break; case 'issues': comparison = a.openIssues - b.openIssues; break; case 'recent': default: comparison = new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(); break; } return sortOrder === 'asc' ? comparison : -comparison; }); // Pagination const total = filtered.length; const totalPages = Math.ceil(total / limit); const start = (page - 1) * limit; const end = start + limit; const paginatedData = filtered.slice(start, end); return { data: paginatedData, pagination: { page, limit, total, totalPages, }, }; }, staleTime: 30000, }); }