feat(frontend): add Dashboard page and components for #53
Implement the main dashboard homepage with: - WelcomeHeader: Personalized greeting with user name - DashboardQuickStats: Stats cards for projects, agents, issues, approvals - RecentProjects: Dynamic grid showing 3-6 recent projects - PendingApprovals: Action-required approvals section - EmptyState: Onboarding experience for new users - useDashboard hook: Mock data fetching with React Query The dashboard serves as the authenticated homepage at /(authenticated)/ and provides quick access to all project management features. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
257
frontend/src/lib/api/hooks/useDashboard.ts
Normal file
257
frontend/src/lib/api/hooks/useDashboard.ts
Normal file
@@ -0,0 +1,257 @@
|
||||
/**
|
||||
* Dashboard Data Hook
|
||||
*
|
||||
* Provides data for the main dashboard including:
|
||||
* - Quick stats (projects, agents, issues, approvals)
|
||||
* - Recent projects
|
||||
* - Pending approvals
|
||||
*
|
||||
* Uses mock data until backend endpoints are available.
|
||||
*
|
||||
* @see Issue #53
|
||||
*/
|
||||
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import type { Project, ProjectStatus } from '@/components/projects/types';
|
||||
|
||||
// ============================================================================
|
||||
// Types
|
||||
// ============================================================================
|
||||
|
||||
export interface DashboardStats {
|
||||
activeProjects: number;
|
||||
runningAgents: number;
|
||||
openIssues: number;
|
||||
pendingApprovals: number;
|
||||
}
|
||||
|
||||
export interface DashboardProject extends Project {
|
||||
progress: number;
|
||||
openIssues: number;
|
||||
activeAgents: number;
|
||||
currentSprint?: string;
|
||||
lastActivity: string;
|
||||
}
|
||||
|
||||
export interface PendingApproval {
|
||||
id: string;
|
||||
type: 'sprint_boundary' | 'code_review' | 'architecture_decision' | 'deployment';
|
||||
title: string;
|
||||
description: string;
|
||||
projectId: string;
|
||||
projectName: string;
|
||||
requestedBy: string;
|
||||
requestedAt: string;
|
||||
priority: 'low' | 'medium' | 'high' | 'critical';
|
||||
}
|
||||
|
||||
export interface DashboardData {
|
||||
stats: DashboardStats;
|
||||
recentProjects: DashboardProject[];
|
||||
pendingApprovals: PendingApproval[];
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Mock Data
|
||||
// ============================================================================
|
||||
|
||||
const mockStats: DashboardStats = {
|
||||
activeProjects: 3,
|
||||
runningAgents: 8,
|
||||
openIssues: 24,
|
||||
pendingApprovals: 2,
|
||||
};
|
||||
|
||||
const mockProjects: DashboardProject[] = [
|
||||
{
|
||||
id: 'proj-001',
|
||||
name: 'E-Commerce Platform Redesign',
|
||||
description: 'Complete redesign of the e-commerce platform with modern UI/UX',
|
||||
status: 'active' as ProjectStatus,
|
||||
autonomy_level: 'milestone',
|
||||
created_at: '2025-11-15T10:00:00Z',
|
||||
updated_at: '2025-12-30T14:30:00Z',
|
||||
owner_id: 'user-001',
|
||||
progress: 67,
|
||||
openIssues: 12,
|
||||
activeAgents: 4,
|
||||
currentSprint: 'Sprint 3',
|
||||
lastActivity: '2 minutes ago',
|
||||
},
|
||||
{
|
||||
id: 'proj-002',
|
||||
name: 'Mobile Banking App',
|
||||
description: 'Native mobile app for banking services with biometric authentication',
|
||||
status: 'active' as ProjectStatus,
|
||||
autonomy_level: 'autonomous',
|
||||
created_at: '2025-11-20T09:00:00Z',
|
||||
updated_at: '2025-12-30T12:00:00Z',
|
||||
owner_id: 'user-001',
|
||||
progress: 45,
|
||||
openIssues: 8,
|
||||
activeAgents: 5,
|
||||
currentSprint: 'Sprint 2',
|
||||
lastActivity: '15 minutes ago',
|
||||
},
|
||||
{
|
||||
id: 'proj-003',
|
||||
name: 'Internal HR Portal',
|
||||
description: 'Employee self-service portal for HR operations',
|
||||
status: 'paused' as ProjectStatus,
|
||||
autonomy_level: 'full_control',
|
||||
created_at: '2025-10-01T08:00:00Z',
|
||||
updated_at: '2025-12-28T16:00:00Z',
|
||||
owner_id: 'user-001',
|
||||
progress: 23,
|
||||
openIssues: 5,
|
||||
activeAgents: 0,
|
||||
currentSprint: 'Sprint 1',
|
||||
lastActivity: '2 days ago',
|
||||
},
|
||||
{
|
||||
id: 'proj-004',
|
||||
name: 'API Gateway Modernization',
|
||||
description: 'Migrate legacy API gateway to cloud-native architecture',
|
||||
status: 'active' as ProjectStatus,
|
||||
autonomy_level: 'milestone',
|
||||
created_at: '2025-12-01T11:00:00Z',
|
||||
updated_at: '2025-12-30T10:00:00Z',
|
||||
owner_id: 'user-001',
|
||||
progress: 82,
|
||||
openIssues: 3,
|
||||
activeAgents: 2,
|
||||
currentSprint: 'Sprint 4',
|
||||
lastActivity: '1 hour ago',
|
||||
},
|
||||
{
|
||||
id: 'proj-005',
|
||||
name: 'Customer Analytics Dashboard',
|
||||
description: 'Real-time analytics dashboard for customer behavior insights',
|
||||
status: 'completed' as ProjectStatus,
|
||||
autonomy_level: 'autonomous',
|
||||
created_at: '2025-09-01T10:00:00Z',
|
||||
updated_at: '2025-12-15T17:00:00Z',
|
||||
owner_id: 'user-001',
|
||||
progress: 100,
|
||||
openIssues: 0,
|
||||
activeAgents: 0,
|
||||
lastActivity: '2 weeks ago',
|
||||
},
|
||||
{
|
||||
id: 'proj-006',
|
||||
name: 'DevOps Pipeline Automation',
|
||||
description: 'Automate CI/CD pipelines with AI-assisted deployments',
|
||||
status: 'active' as ProjectStatus,
|
||||
autonomy_level: 'milestone',
|
||||
created_at: '2025-12-10T14:00:00Z',
|
||||
updated_at: '2025-12-30T09:00:00Z',
|
||||
owner_id: 'user-001',
|
||||
progress: 35,
|
||||
openIssues: 6,
|
||||
activeAgents: 3,
|
||||
currentSprint: 'Sprint 1',
|
||||
lastActivity: '30 minutes ago',
|
||||
},
|
||||
];
|
||||
|
||||
const mockApprovals: PendingApproval[] = [
|
||||
{
|
||||
id: 'approval-001',
|
||||
type: 'sprint_boundary',
|
||||
title: 'Sprint 3 Completion Review',
|
||||
description: 'Review sprint deliverables and approve transition to Sprint 4',
|
||||
projectId: 'proj-001',
|
||||
projectName: 'E-Commerce Platform Redesign',
|
||||
requestedBy: 'Product Owner Agent',
|
||||
requestedAt: '2025-12-30T14:00:00Z',
|
||||
priority: 'high',
|
||||
},
|
||||
{
|
||||
id: 'approval-002',
|
||||
type: 'architecture_decision',
|
||||
title: 'Database Migration Strategy',
|
||||
description: 'Approve PostgreSQL to CockroachDB migration plan',
|
||||
projectId: 'proj-004',
|
||||
projectName: 'API Gateway Modernization',
|
||||
requestedBy: 'Architect Agent',
|
||||
requestedAt: '2025-12-30T10:30:00Z',
|
||||
priority: 'medium',
|
||||
},
|
||||
];
|
||||
|
||||
// ============================================================================
|
||||
// Hook
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Fetches dashboard data (stats, recent projects, pending approvals)
|
||||
*
|
||||
* @returns Query result with dashboard data
|
||||
*/
|
||||
export function useDashboard() {
|
||||
return useQuery<DashboardData>({
|
||||
queryKey: ['dashboard'],
|
||||
queryFn: async () => {
|
||||
// Simulate network delay
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
|
||||
// Return mock data
|
||||
// TODO: Replace with actual API call when backend is ready
|
||||
// const response = await apiClient.get('/api/v1/dashboard');
|
||||
// return response.data;
|
||||
|
||||
return {
|
||||
stats: mockStats,
|
||||
recentProjects: mockProjects,
|
||||
pendingApprovals: mockApprovals,
|
||||
};
|
||||
},
|
||||
staleTime: 30000, // 30 seconds
|
||||
refetchInterval: 60000, // Refetch every minute
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches only dashboard stats
|
||||
*/
|
||||
export function useDashboardStats() {
|
||||
return useQuery<DashboardStats>({
|
||||
queryKey: ['dashboard', 'stats'],
|
||||
queryFn: async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
return mockStats;
|
||||
},
|
||||
staleTime: 30000,
|
||||
refetchInterval: 60000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches recent projects for dashboard
|
||||
*
|
||||
* @param limit - Maximum number of projects to return
|
||||
*/
|
||||
export function useRecentProjects(limit: number = 6) {
|
||||
return useQuery<DashboardProject[]>({
|
||||
queryKey: ['dashboard', 'recentProjects', limit],
|
||||
queryFn: async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 400));
|
||||
return mockProjects.slice(0, limit);
|
||||
},
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches pending approvals
|
||||
*/
|
||||
export function usePendingApprovals() {
|
||||
return useQuery<PendingApproval[]>({
|
||||
queryKey: ['dashboard', 'pendingApprovals'],
|
||||
queryFn: async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 300));
|
||||
return mockApprovals;
|
||||
},
|
||||
staleTime: 30000,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user