import React from 'react'; import { useApp } from '../contexts/AppContext'; import { Card } from './ui/card'; import { Badge } from './ui/badge'; import { Progress } from './ui/progress'; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, LineChart, Line } from 'recharts'; import { CheckCircle2, Clock, AlertCircle, TrendingUp } from 'lucide-react'; import { differenceInDays, format } from 'date-fns'; export const Dashboard: React.FC = () => { const { tasks, userStories, activeSprint } = useApp(); if (!activeSprint) { return (

No Active Sprint

Please activate a sprint from the Sprint Management page to view the dashboard.

); } const sprintTasks = tasks.filter(task => { const story = userStories.find(s => s.id === task.userStoryId); return story?.sprintId === activeSprint.id; }); const todoTasks = sprintTasks.filter(t => t.status === 'todo').length; const inProgressTasks = sprintTasks.filter(t => t.status === 'in-progress').length; const blockedTasks = sprintTasks.filter(t => t.status === 'blocked').length; const doneTasks = sprintTasks.filter(t => t.status === 'done').length; const sprintStories = userStories.filter(s => s.sprintId === activeSprint.id); const totalPoints = sprintStories.reduce((sum, s) => sum + s.storyPoints, 0); const completedPoints = sprintStories .filter(story => { const storyTasks = tasks.filter(t => t.userStoryId === story.id); return storyTasks.length > 0 && storyTasks.every(t => t.status === 'done'); }) .reduce((sum, s) => sum + s.storyPoints, 0); const progressPercentage = totalPoints > 0 ? (completedPoints / totalPoints) * 100 : 0; const daysTotal = differenceInDays(new Date(activeSprint.endDate), new Date(activeSprint.startDate)); const daysElapsed = differenceInDays(new Date(), new Date(activeSprint.startDate)); const daysRemaining = Math.max(0, differenceInDays(new Date(activeSprint.endDate), new Date())); // Task distribution data const taskDistribution = [ { name: 'To Do', value: todoTasks, fill: '#94a3b8' }, { name: 'In Progress', value: inProgressTasks, fill: '#3b82f6' }, { name: 'Blocked', value: blockedTasks, fill: '#ef4444' }, { name: 'Done', value: doneTasks, fill: '#10b981' } ]; // Mock burndown data (in a real app, this would be calculated from historical data) const generateBurndownData = () => { const data = []; const idealBurnRate = totalPoints / daysTotal; for (let day = 0; day <= daysTotal; day++) { const ideal = Math.max(0, totalPoints - (idealBurnRate * day)); const actual = day <= daysElapsed ? Math.max(0, totalPoints - (completedPoints * (day / Math.max(daysElapsed, 1)))) : null; data.push({ day: day, ideal: Math.round(ideal), actual: actual !== null ? Math.round(actual) : null }); } return data; }; const burndownData = generateBurndownData(); // Find blocked tasks const blockedTasksList = sprintTasks.filter(t => t.status === 'blocked'); return (

Sprint Dashboard

{activeSprint.name} - {activeSprint.goal}

{/* Key Metrics */}

Total Tasks

{sprintTasks.length}

In Progress

{inProgressTasks}

Blocked

{blockedTasks}

Days Remaining

{daysRemaining}

{/* Sprint Progress */}

Sprint Progress

{completedPoints} / {totalPoints} points
{Math.round(progressPercentage)}% complete {format(new Date(activeSprint.startDate), 'MMM dd')} - {format(new Date(activeSprint.endDate), 'MMM dd')}
{/* Charts */}
{/* Task Distribution */}

Task Distribution

{/* Sprint Burndown */}

Sprint Burndown

{/* Blocked Items Alert */} {blockedTasks > 0 && (

Blocked Tasks Require Attention

{blockedTasks} task{blockedTasks !== 1 ? 's are' : ' is'} currently blocked and may impact sprint progress.

{blockedTasksList.map(task => (
• {task.title}
))}
)} {/* Team Velocity Insights */}

Team Insights

Sprint Capacity {activeSprint.capacity} points
Committed Points {totalPoints} points
Completed Points {completedPoints} points
Capacity Utilization {activeSprint.capacity > 0 ? Math.round((totalPoints / activeSprint.capacity) * 100) : 0}%
); };