Files
towercontrol/components/dashboard/charts/ProductivityInsights.tsx
2025-09-19 17:05:13 +02:00

191 lines
8.2 KiB
TypeScript

'use client';
import { DailyMetrics } from '@/services/metrics';
interface ProductivityInsightsProps {
data: DailyMetrics[];
className?: string;
}
export function ProductivityInsights({ data, className }: ProductivityInsightsProps) {
// Calculer les insights
const totalCompleted = data.reduce((sum, day) => sum + day.completed, 0);
const totalCreated = data.reduce((sum, day) => sum + day.newTasks, 0);
// const averageCompletion = data.reduce((sum, day) => sum + day.completionRate, 0) / data.length;
// Trouver le jour le plus productif
const mostProductiveDay = data.reduce((best, day) =>
day.completed > best.completed ? day : best
);
// Trouver le jour avec le plus de nouvelles tâches
const mostCreativeDay = data.reduce((best, day) =>
day.newTasks > best.newTasks ? day : best
);
// Analyser la tendance
const firstHalf = data.slice(0, Math.ceil(data.length / 2));
const secondHalf = data.slice(Math.ceil(data.length / 2));
const firstHalfAvg = firstHalf.reduce((sum, day) => sum + day.completed, 0) / firstHalf.length;
const secondHalfAvg = secondHalf.reduce((sum, day) => sum + day.completed, 0) / secondHalf.length;
const trend = secondHalfAvg > firstHalfAvg ? 'up' : secondHalfAvg < firstHalfAvg ? 'down' : 'stable';
// Calculer la consistance (écart-type faible = plus consistant)
const avgCompleted = totalCompleted / data.length;
const variance = data.reduce((sum, day) => {
const diff = day.completed - avgCompleted;
return sum + diff * diff;
}, 0) / data.length;
const standardDeviation = Math.sqrt(variance);
const consistencyScore = Math.max(0, 100 - (standardDeviation * 10)); // Score sur 100
// Ratio création/completion
const creationRatio = totalCreated > 0 ? (totalCompleted / totalCreated) * 100 : 0;
const getTrendIcon = () => {
switch (trend) {
case 'up': return { icon: '📈', color: 'text-green-600', label: 'En amélioration' };
case 'down': return { icon: '📉', color: 'text-red-600', label: 'En baisse' };
default: return { icon: '➡️', color: 'text-blue-600', label: 'Stable' };
}
};
const getConsistencyLevel = () => {
if (consistencyScore >= 80) return { label: 'Très régulier', color: 'text-green-600', icon: '🎯' };
if (consistencyScore >= 60) return { label: 'Assez régulier', color: 'text-blue-600', icon: '📊' };
if (consistencyScore >= 40) return { label: 'Variable', color: 'text-yellow-600', icon: '📊' };
return { label: 'Très variable', color: 'text-red-600', icon: '📊' };
};
const getRatioStatus = () => {
if (creationRatio >= 100) return { label: 'Équilibré+', color: 'text-green-600', icon: '⚖️' };
if (creationRatio >= 80) return { label: 'Bien équilibré', color: 'text-blue-600', icon: '⚖️' };
if (creationRatio >= 60) return { label: 'Légèrement en retard', color: 'text-yellow-600', icon: '⚖️' };
return { label: 'Accumulation', color: 'text-red-600', icon: '⚖️' };
};
const trendInfo = getTrendIcon();
const consistencyInfo = getConsistencyLevel();
const ratioInfo = getRatioStatus();
return (
<div className={className}>
<div className="space-y-4">
{/* Insights principaux */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Jour le plus productif */}
<div className="p-4 bg-green-50 dark:bg-green-950/20 rounded-lg">
<div className="flex items-center justify-between mb-2">
<h4 className="font-medium text-green-900 dark:text-green-100">
🏆 Jour champion
</h4>
<span className="text-2xl font-bold text-green-600">
{mostProductiveDay.completed}
</span>
</div>
<p className="text-sm text-green-800 dark:text-green-200">
{mostProductiveDay.dayName} - {mostProductiveDay.completed} tâches terminées
</p>
<p className="text-xs text-green-600 mt-1">
Taux: {mostProductiveDay.completionRate.toFixed(1)}%
</p>
</div>
{/* Jour le plus créatif */}
<div className="p-4 bg-blue-50 dark:bg-blue-950/20 rounded-lg">
<div className="flex items-center justify-between mb-2">
<h4 className="font-medium text-blue-900 dark:text-blue-100">
💡 Jour créatif
</h4>
<span className="text-2xl font-bold text-blue-600">
{mostCreativeDay.newTasks}
</span>
</div>
<p className="text-sm text-blue-800 dark:text-blue-200">
{mostCreativeDay.dayName} - {mostCreativeDay.newTasks} nouvelles tâches
</p>
<p className="text-xs text-blue-600 mt-1">
{mostCreativeDay.dayName === mostProductiveDay.dayName ?
'Également jour le plus productif!' :
'Journée de planification'}
</p>
</div>
</div>
{/* Analyses comportementales */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{/* Tendance */}
<div className="p-4 bg-[var(--card)] border border-[var(--border)] rounded-lg">
<div className="flex items-center gap-2 mb-2">
<span className="text-2xl">{trendInfo.icon}</span>
<h4 className="font-medium text-[var(--foreground)]">Tendance</h4>
</div>
<p className={`text-sm font-medium ${trendInfo.color}`}>
{trendInfo.label}
</p>
<p className="text-xs text-[var(--muted-foreground)] mt-1">
{secondHalfAvg > firstHalfAvg ?
`+${(((secondHalfAvg - firstHalfAvg) / firstHalfAvg) * 100).toFixed(1)}%` :
`${(((secondHalfAvg - firstHalfAvg) / firstHalfAvg) * 100).toFixed(1)}%`}
</p>
</div>
{/* Consistance */}
<div className="p-4 bg-[var(--card)] border border-[var(--border)] rounded-lg">
<div className="flex items-center gap-2 mb-2">
<span className="text-2xl">{consistencyInfo.icon}</span>
<h4 className="font-medium text-[var(--foreground)]">Régularité</h4>
</div>
<p className={`text-sm font-medium ${consistencyInfo.color}`}>
{consistencyInfo.label}
</p>
<p className="text-xs text-[var(--muted-foreground)] mt-1">
Score: {consistencyScore.toFixed(0)}/100
</p>
</div>
{/* Ratio Création/Completion */}
<div className="p-4 bg-[var(--card)] border border-[var(--border)] rounded-lg">
<div className="flex items-center gap-2 mb-2">
<span className="text-2xl">{ratioInfo.icon}</span>
<h4 className="font-medium text-[var(--foreground)]">Équilibre</h4>
</div>
<p className={`text-sm font-medium ${ratioInfo.color}`}>
{ratioInfo.label}
</p>
<p className="text-xs text-[var(--muted-foreground)] mt-1">
{creationRatio.toFixed(0)}% de completion
</p>
</div>
</div>
{/* Recommandations */}
<div className="p-4 bg-yellow-50 dark:bg-yellow-950/20 rounded-lg">
<h4 className="font-medium text-yellow-900 dark:text-yellow-100 mb-2 flex items-center gap-2">
💡 Recommandations
</h4>
<div className="space-y-1 text-sm text-yellow-800 dark:text-yellow-200">
{trend === 'down' && (
<p> Essayez de retrouver votre rythme du début de semaine</p>
)}
{consistencyScore < 60 && (
<p> Essayez de maintenir un rythme plus régulier</p>
)}
{creationRatio < 80 && (
<p> Concentrez-vous plus sur terminer les tâches existantes</p>
)}
{creationRatio > 120 && (
<p> Excellent rythme! Peut-être ralentir la création de nouvelles tâches</p>
)}
{mostProductiveDay.dayName === mostCreativeDay.dayName && (
<p> Excellente synergie création/exécution le {mostProductiveDay.dayName}</p>
)}
</div>
</div>
</div>
</div>
);
}