Implement the projects CRUD page with: - ProjectCard: Card component with status badge, progress, metrics, actions - ProjectFilters: Search, status filter, complexity, sort controls - ProjectsGrid: Grid/list view toggle with loading and empty states - useProjects hook: Mock data with filtering, sorting, pagination Features include: - Debounced search (300ms) - Quick filters (status) and extended filters (complexity, sort) - Grid and list view toggle - Click navigation to project detail
272 lines
7.6 KiB
TypeScript
272 lines
7.6 KiB
TypeScript
/**
|
|
* 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<ProjectsListResponse>({
|
|
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,
|
|
});
|
|
}
|