'use client'; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, BarChart, Bar, Cell } from 'recharts'; import { SprintVelocity } from '@/lib/types'; import { Card, CardContent, CardHeader } from '@/components/ui/Card'; interface SprintComparisonProps { sprintHistory: SprintVelocity[]; className?: string; } interface ComparisonMetrics { velocityTrend: 'improving' | 'declining' | 'stable'; avgCompletion: number; consistency: 'high' | 'medium' | 'low'; bestSprint: SprintVelocity; worstSprint: SprintVelocity; predictions: { nextSprintEstimate: number; confidenceLevel: 'high' | 'medium' | 'low'; }; } export function SprintComparison({ sprintHistory, className }: SprintComparisonProps) { // Analyser les tendances const metrics = analyzeSprintTrends(sprintHistory); // Données pour les graphiques const comparisonData = sprintHistory.map(sprint => ({ name: sprint.sprintName.replace('Sprint ', ''), completion: sprint.completionRate, velocity: sprint.completedPoints, planned: sprint.plannedPoints, variance: sprint.plannedPoints > 0 ? ((sprint.completedPoints - sprint.plannedPoints) / sprint.plannedPoints) * 100 : 0 })); const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?: Array<{ value: number; name: string; color: string }>; label?: string }) => { if (active && payload && payload.length) { return (

Sprint {label}

{payload.map((item, index) => (
{item.name}: {typeof item.value === 'number' ? (item.name.includes('%') ? `${item.value}%` : item.value) : item.value }
))}
); } return null; }; return (
{/* Graphique de comparaison des taux de complétion */}

Évolution des taux de complétion

} />
{/* Graphique de comparaison des vélocités */}

Comparaison planifié vs réalisé

} />
{/* Métriques de comparaison */}
{metrics.velocityTrend === 'improving' ? '📈' : metrics.velocityTrend === 'declining' ? '📉' : '➡️'}
Tendance générale
80 ? 'text-green-500' : metrics.avgCompletion > 60 ? 'text-orange-500' : 'text-red-500' }`}> {Math.round(metrics.avgCompletion)}%
Complétion moyenne
{metrics.consistency === 'high' ? 'Haute' : metrics.consistency === 'medium' ? 'Moyenne' : 'Faible'}
Consistance
{metrics.predictions.nextSprintEstimate}
Prédiction suivante
{/* Insights et recommandations */}

🏆 Meilleur sprint

Sprint: {metrics.bestSprint.sprintName}
Points complétés: {metrics.bestSprint.completedPoints}
Taux de complétion: {metrics.bestSprint.completionRate}%

📉 Sprint à améliorer

Sprint: {metrics.worstSprint.sprintName}
Points complétés: {metrics.worstSprint.completedPoints}
Taux de complétion: {metrics.worstSprint.completionRate}%
{/* Recommandations */}

💡 Recommandations

{getRecommendations(metrics).map((recommendation, index) => (
{recommendation}
))}
); } /** * Analyse les tendances des sprints */ function analyzeSprintTrends(sprintHistory: SprintVelocity[]): ComparisonMetrics { if (sprintHistory.length === 0) { return { velocityTrend: 'stable', avgCompletion: 0, consistency: 'low', bestSprint: sprintHistory[0], worstSprint: sprintHistory[0], predictions: { nextSprintEstimate: 0, confidenceLevel: 'low' } }; } // Tendance de vélocité (comparer premiers vs derniers sprints) const firstHalf = sprintHistory.slice(0, Math.ceil(sprintHistory.length / 2)); const secondHalf = sprintHistory.slice(Math.floor(sprintHistory.length / 2)); const firstHalfAvg = firstHalf.reduce((sum, s) => sum + s.completedPoints, 0) / firstHalf.length; const secondHalfAvg = secondHalf.reduce((sum, s) => sum + s.completedPoints, 0) / secondHalf.length; const improvementRate = (secondHalfAvg - firstHalfAvg) / firstHalfAvg * 100; const velocityTrend: 'improving' | 'declining' | 'stable' = improvementRate > 10 ? 'improving' : improvementRate < -10 ? 'declining' : 'stable'; // Complétion moyenne const avgCompletion = sprintHistory.reduce((sum, s) => sum + s.completionRate, 0) / sprintHistory.length; // Consistance (variance des taux de complétion) const completionRates = sprintHistory.map(s => s.completionRate); const variance = completionRates.reduce((sum, rate) => sum + Math.pow(rate - avgCompletion, 2), 0) / completionRates.length; const standardDeviation = Math.sqrt(variance); const consistency: 'high' | 'medium' | 'low' = standardDeviation < 10 ? 'high' : standardDeviation < 20 ? 'medium' : 'low'; // Meilleur et pire sprint const bestSprint = sprintHistory.reduce((best, current) => current.completionRate > best.completionRate ? current : best); const worstSprint = sprintHistory.reduce((worst, current) => current.completionRate < worst.completionRate ? current : worst); // Prédiction pour le prochain sprint const recentSprints = sprintHistory.slice(-3); // 3 derniers sprints const recentAvg = recentSprints.reduce((sum, s) => sum + s.completedPoints, 0) / recentSprints.length; const nextSprintEstimate = Math.round(recentAvg); const confidenceLevel: 'high' | 'medium' | 'low' = consistency === 'high' && velocityTrend !== 'declining' ? 'high' : consistency === 'medium' ? 'medium' : 'low'; return { velocityTrend, avgCompletion, consistency, bestSprint, worstSprint, predictions: { nextSprintEstimate, confidenceLevel } }; } /** * Génère des recommandations basées sur l'analyse */ function getRecommendations(metrics: ComparisonMetrics): string[] { const recommendations: string[] = []; if (metrics.velocityTrend === 'declining') { recommendations.push("Tendance en baisse détectée - Identifier les blockers récurrents"); recommendations.push("Revoir les estimations ou la complexité des tâches récentes"); } else if (metrics.velocityTrend === 'improving') { recommendations.push("Excellente progression ! Maintenir les bonnes pratiques actuelles"); } if (metrics.avgCompletion < 60) { recommendations.push("Taux de complétion faible - Considérer des sprints plus courts ou moins ambitieux"); } else if (metrics.avgCompletion > 90) { recommendations.push("Taux de complétion très élevé - L'équipe pourrait prendre plus d'engagements"); } if (metrics.consistency === 'low') { recommendations.push("Consistance faible - Améliorer la prévisibilité des estimations"); recommendations.push("Organiser des rétrospectives pour identifier les causes de variabilité"); } if (recommendations.length === 0) { recommendations.push("Performance stable et prévisible - Continuer sur cette lancée !"); } return recommendations; }