chore: refactor project structure and clean up unused components
- Updated `TODO.md` to reflect new testing tasks and final structure expectations. - Simplified TypeScript path mappings in `tsconfig.json` for better clarity. - Revised business logic separation rules in `.cursor/rules` to align with new directory structure. - Deleted unused client components and services to streamline the codebase. - Adjusted import paths in scripts to match the new structure.
This commit is contained in:
190
src/components/dashboard/charts/ProductivityInsights.tsx
Normal file
190
src/components/dashboard/charts/ProductivityInsights.tsx
Normal file
@@ -0,0 +1,190 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user