import { useMemo } from 'react'; import { ProductivityMetrics } from '@/services/analytics/analytics'; import { DeadlineMetrics } from '@/services/analytics/deadline-analytics'; import { TagDistributionMetrics } from '@/services/analytics/tag-analytics'; import { CompletionTrendChart } from '@/components/charts/CompletionTrendChart'; import { VelocityChart } from '@/components/charts/VelocityChart'; import { PriorityDistributionChart } from '@/components/charts/PriorityDistributionChart'; import { WeeklyStatsCard } from '@/components/charts/WeeklyStatsCard'; import { TagDistributionChart } from '@/components/dashboard/TagDistributionChart'; import { Card, MetricCard } from '@/components/ui'; import { DeadlineOverview } from '@/components/deadline/DeadlineOverview'; import { Emoji } from '@/components/ui/Emoji'; interface ProductivityAnalyticsProps { metrics: ProductivityMetrics; deadlineMetrics: DeadlineMetrics; tagMetrics: TagDistributionMetrics; selectedSources: string[]; hiddenSources?: string[]; } export function ProductivityAnalytics({ metrics, deadlineMetrics, tagMetrics, selectedSources, hiddenSources = [], }: ProductivityAnalyticsProps) { // Filtrer les métriques selon les sources sélectionnées const filteredMetrics = useMemo(() => { if (selectedSources.length === 0) { return metrics; } // Pour les métriques complexes, on garde les données originales // car elles nécessitent un recalcul complet côté serveur // TODO: Implémenter le recalcul côté client ou créer une API return metrics; }, [metrics, selectedSources]); const filteredDeadlineMetrics = useMemo(() => { let filteredOverdue = deadlineMetrics.overdue; let filteredCritical = deadlineMetrics.critical; let filteredWarning = deadlineMetrics.warning; let filteredUpcoming = deadlineMetrics.upcoming; // Si on a des sources sélectionnées, ne garder que celles-ci if (selectedSources.length > 0) { filteredOverdue = filteredOverdue.filter((task) => selectedSources.includes(task.source) ); filteredCritical = filteredCritical.filter((task) => selectedSources.includes(task.source) ); filteredWarning = filteredWarning.filter((task) => selectedSources.includes(task.source) ); filteredUpcoming = filteredUpcoming.filter((task) => selectedSources.includes(task.source) ); } else if (hiddenSources.length > 0) { // Sinon, retirer les sources masquées filteredOverdue = filteredOverdue.filter( (task) => !hiddenSources.includes(task.source) ); filteredCritical = filteredCritical.filter( (task) => !hiddenSources.includes(task.source) ); filteredWarning = filteredWarning.filter( (task) => !hiddenSources.includes(task.source) ); filteredUpcoming = filteredUpcoming.filter( (task) => !hiddenSources.includes(task.source) ); } return { overdue: filteredOverdue, critical: filteredCritical, warning: filteredWarning, upcoming: filteredUpcoming, summary: { overdueCount: filteredOverdue.length, criticalCount: filteredCritical.length, warningCount: filteredWarning.length, upcomingCount: filteredUpcoming.length, totalWithDeadlines: filteredOverdue.length + filteredCritical.length + filteredWarning.length + filteredUpcoming.length, }, }; }, [deadlineMetrics, selectedSources, hiddenSources]); return (
{/* Section Échéances Critiques */} {/* Titre de section Analytics */}

Analytics & Métriques

Derniers 30 jours
{/* Performance hebdomadaire */} {/* Graphiques principaux */}
{/* Distributions */}
{/* Status Flow - Graphique simple en barres horizontales */}

Répartition par Statut

{filteredMetrics.statusFlow.map((item, index) => (
{item.status}
{item.count}
{item.percentage}%
))}
{/* Distribution par Tags */} {/* Insights automatiques */}

Insights

0 ? Math.round( filteredMetrics.velocityData.reduce( (acc, item) => acc + item.completed, 0 ) / filteredMetrics.velocityData.length ) : 0 } tâches/sem`} color="primary" /> (item.count > max.count ? item : max), filteredMetrics.priorityDistribution[0] )?.priority || 'N/A' } color="success" /> { const completed = filteredMetrics.statusFlow.find((s) => s.status === 'Terminé') ?.count || 0; const total = filteredMetrics.statusFlow.reduce( (acc, s) => acc + s.count, 0 ); return total > 0 ? Math.round((completed / total) * 100) : 0; })()}%`} color="warning" />
); }