/** * Sprint Progress Component * * Displays sprint overview with progress bar, issue stats, and burndown chart. */ 'use client'; import { TrendingUp, Calendar } from 'lucide-react'; import { format } from 'date-fns'; import { cn } from '@/lib/utils'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Skeleton } from '@/components/ui/skeleton'; import { ProgressBar } from './ProgressBar'; import { BurndownChart } from './BurndownChart'; import type { Sprint, BurndownDataPoint } from './types'; // ============================================================================ // Types // ============================================================================ interface SprintProgressProps { /** Current sprint data */ sprint: Sprint | null; /** Burndown chart data */ burndownData?: BurndownDataPoint[]; /** List of available sprints for selector */ availableSprints?: { id: string; name: string }[]; /** Currently selected sprint ID */ selectedSprintId?: string; /** Callback when sprint selection changes */ onSprintChange?: (sprintId: string) => void; /** Whether data is loading */ isLoading?: boolean; /** Additional CSS classes */ className?: string; } // ============================================================================ // Helper Functions // ============================================================================ function formatSprintDates(startDate?: string, endDate?: string): string { if (!startDate || !endDate) return 'Dates not set'; try { const start = format(new Date(startDate), 'MMM d'); const end = format(new Date(endDate), 'MMM d, yyyy'); return `${start} - ${end}`; } catch { return 'Invalid dates'; } } function calculateProgress(sprint: Sprint): number { if (sprint.total_issues === 0) return 0; return Math.round((sprint.completed_issues / sprint.total_issues) * 100); } // ============================================================================ // Subcomponents // ============================================================================ interface StatCardProps { value: number; label: string; colorClass: string; } function StatCard({ value, label, colorClass }: StatCardProps) { return (
No sprint is currently active
Create a sprint to track progress