From 11ebe5cd00beede74dc681a0a4281d9df8fb1109 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Tue, 23 Sep 2025 22:07:52 +0200 Subject: [PATCH] refactor: remove unused analytics actions and integrate metrics directly - Deleted `analytics.ts` and `deadline-analytics.ts` as they were no longer needed. - Integrated `AnalyticsService` and `DeadlineAnalyticsService` directly into `HomePage` and `DailyPage`, streamlining data fetching. - Updated components to utilize the new metrics structure, ensuring proper data flow and rendering. --- src/actions/analytics.ts | 25 ---- src/actions/deadline-analytics.ts | 29 ---- src/app/daily/DailyPageClient.tsx | 7 +- src/app/daily/page.tsx | 7 +- src/app/page.tsx | 10 +- src/components/HomePageClient.tsx | 27 +++- src/components/daily/DeadlineReminder.tsx | 125 ++++++++---------- .../dashboard/ProductivityAnalytics.tsx | 66 +-------- src/components/deadline/DeadlineOverview.tsx | 63 +-------- 9 files changed, 107 insertions(+), 252 deletions(-) delete mode 100644 src/actions/analytics.ts delete mode 100644 src/actions/deadline-analytics.ts diff --git a/src/actions/analytics.ts b/src/actions/analytics.ts deleted file mode 100644 index fd19127..0000000 --- a/src/actions/analytics.ts +++ /dev/null @@ -1,25 +0,0 @@ -'use server'; - -import { AnalyticsService, ProductivityMetrics, TimeRange } from '@/services/analytics/analytics'; - -export async function getProductivityMetrics(timeRange?: TimeRange): Promise<{ - success: boolean; - data?: ProductivityMetrics; - error?: string; -}> { - try { - const metrics = await AnalyticsService.getProductivityMetrics(timeRange); - - return { - success: true, - data: metrics - }; - } catch (error) { - console.error('Erreur lors de la récupération des métriques:', error); - - return { - success: false, - error: error instanceof Error ? error.message : 'Erreur inconnue' - }; - } -} diff --git a/src/actions/deadline-analytics.ts b/src/actions/deadline-analytics.ts deleted file mode 100644 index 8856c95..0000000 --- a/src/actions/deadline-analytics.ts +++ /dev/null @@ -1,29 +0,0 @@ -'use server'; - -import { DeadlineAnalyticsService } from '@/services/analytics/deadline-analytics'; - -export async function getDeadlineMetrics() { - try { - const metrics = await DeadlineAnalyticsService.getDeadlineMetrics(); - return { success: true, data: metrics }; - } catch (error) { - console.error('Erreur lors de la récupération des métriques d\'échéance:', error); - return { - success: false, - error: error instanceof Error ? error.message : 'Erreur lors de la récupération des métriques d\'échéance' - }; - } -} - -export async function getCriticalDeadlines() { - try { - const tasks = await DeadlineAnalyticsService.getCriticalDeadlines(); - return { success: true, data: tasks }; - } catch (error) { - console.error('Erreur lors de la récupération des échéances critiques:', error); - return { - success: false, - error: error instanceof Error ? error.message : 'Erreur lors de la récupération des échéances critiques' - }; - } -} diff --git a/src/app/daily/DailyPageClient.tsx b/src/app/daily/DailyPageClient.tsx index d8d359a..8d520eb 100644 --- a/src/app/daily/DailyPageClient.tsx +++ b/src/app/daily/DailyPageClient.tsx @@ -4,6 +4,7 @@ import { useState, useEffect } from 'react'; import React from 'react'; import { useDaily } from '@/hooks/useDaily'; import { DailyView, DailyCheckboxType } from '@/lib/types'; +import { DeadlineMetrics } from '@/services/analytics/deadline-analytics'; import { Button } from '@/components/ui/Button'; import { Card } from '@/components/ui/Card'; import { DailyCalendar } from '@/components/daily/DailyCalendar'; @@ -18,12 +19,14 @@ interface DailyPageClientProps { initialDailyView?: DailyView; initialDailyDates?: string[]; initialDate?: Date; + initialDeadlineMetrics?: DeadlineMetrics | null; } export function DailyPageClient({ initialDailyView, initialDailyDates = [], - initialDate + initialDate, + initialDeadlineMetrics }: DailyPageClientProps = {}) { const { dailyView, @@ -214,7 +217,7 @@ export function DailyPageClient({ {/* Rappel des échéances urgentes - Desktop uniquement */}
- +
{/* Contenu principal */} diff --git a/src/app/daily/page.tsx b/src/app/daily/page.tsx index 1d2df8c..4e397ef 100644 --- a/src/app/daily/page.tsx +++ b/src/app/daily/page.tsx @@ -1,6 +1,7 @@ import { Metadata } from 'next'; import { DailyPageClient } from './DailyPageClient'; import { dailyService } from '@/services/task-management/daily'; +import { DeadlineAnalyticsService } from '@/services/analytics/deadline-analytics'; import { getToday } from '@/lib/date-utils'; // Force dynamic rendering (no static generation) @@ -16,9 +17,10 @@ export default async function DailyPage() { const today = getToday(); try { - const [dailyView, dailyDates] = await Promise.all([ + const [dailyView, dailyDates, deadlineMetrics] = await Promise.all([ dailyService.getDailyView(today), - dailyService.getDailyDates() + dailyService.getDailyDates(), + DeadlineAnalyticsService.getDeadlineMetrics().catch(() => null) // Graceful fallback ]); return ( @@ -26,6 +28,7 @@ export default async function DailyPage() { initialDailyView={dailyView} initialDailyDates={dailyDates} initialDate={today} + initialDeadlineMetrics={deadlineMetrics} /> ); } catch (error) { diff --git a/src/app/page.tsx b/src/app/page.tsx index 9df933f..66801d0 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,5 +1,7 @@ import { tasksService } from '@/services/task-management/tasks'; import { tagsService } from '@/services/task-management/tags'; +import { AnalyticsService } from '@/services/analytics/analytics'; +import { DeadlineAnalyticsService } from '@/services/analytics/deadline-analytics'; import { HomePageClient } from '@/components/HomePageClient'; // Force dynamic rendering (no static generation) @@ -7,10 +9,12 @@ export const dynamic = 'force-dynamic'; export default async function HomePage() { // SSR - Récupération des données côté serveur - const [initialTasks, initialTags, initialStats] = await Promise.all([ + const [initialTasks, initialTags, initialStats, productivityMetrics, deadlineMetrics] = await Promise.all([ tasksService.getTasks(), tagsService.getTags(), - tasksService.getTaskStats() + tasksService.getTaskStats(), + AnalyticsService.getProductivityMetrics(), + DeadlineAnalyticsService.getDeadlineMetrics() ]); return ( @@ -18,6 +22,8 @@ export default async function HomePage() { initialTasks={initialTasks} initialTags={initialTags} initialStats={initialStats} + productivityMetrics={productivityMetrics} + deadlineMetrics={deadlineMetrics} /> ); } diff --git a/src/components/HomePageClient.tsx b/src/components/HomePageClient.tsx index 5ee849d..1eef6d9 100644 --- a/src/components/HomePageClient.tsx +++ b/src/components/HomePageClient.tsx @@ -8,15 +8,22 @@ import { DashboardStats } from '@/components/dashboard/DashboardStats'; import { QuickActions } from '@/components/dashboard/QuickActions'; import { RecentTasks } from '@/components/dashboard/RecentTasks'; import { ProductivityAnalytics } from '@/components/dashboard/ProductivityAnalytics'; +import { ProductivityMetrics } from '@/services/analytics/analytics'; +import { DeadlineMetrics } from '@/services/analytics/deadline-analytics'; interface HomePageClientProps { initialTasks: Task[]; initialTags: (Tag & { usage: number })[]; initialStats: TaskStats; + productivityMetrics: ProductivityMetrics; + deadlineMetrics: DeadlineMetrics; } -function HomePageContent() { +function HomePageContent({ productivityMetrics, deadlineMetrics }: { + productivityMetrics: ProductivityMetrics; + deadlineMetrics: DeadlineMetrics; +}) { const { stats, syncing, createTask, tasks } = useTasksContext(); // Handler pour la création de tâche @@ -40,7 +47,10 @@ function HomePageContent() { {/* Analytics et métriques */} - + {/* Tâches récentes */} @@ -49,14 +59,23 @@ function HomePageContent() { ); } -export function HomePageClient({ initialTasks, initialTags, initialStats }: HomePageClientProps) { +export function HomePageClient({ + initialTasks, + initialTags, + initialStats, + productivityMetrics, + deadlineMetrics +}: HomePageClientProps) { return ( - + ); } diff --git a/src/components/daily/DeadlineReminder.tsx b/src/components/daily/DeadlineReminder.tsx index d85e1f5..1aae135 100644 --- a/src/components/daily/DeadlineReminder.tsx +++ b/src/components/daily/DeadlineReminder.tsx @@ -1,80 +1,38 @@ 'use client'; -import { useState, useEffect, useTransition } from 'react'; -import { DeadlineTask } from '@/services/analytics/deadline-analytics'; -import { getDeadlineMetrics } from '@/actions/deadline-analytics'; +import { DeadlineTask, DeadlineMetrics } from '@/services/analytics/deadline-analytics'; import { Card } from '@/components/ui/Card'; -export function DeadlineReminder() { - const [urgentTasks, setUrgentTasks] = useState([]); - const [error, setError] = useState(null); - const [isPending, startTransition] = useTransition(); - - useEffect(() => { - const loadUrgentTasks = () => { - startTransition(async () => { - try { - setError(null); - const response = await getDeadlineMetrics(); - - if (response.success && response.data) { - // Combiner toutes les tâches urgentes et trier par urgence - const combinedTasks = [ - ...response.data.overdue, - ...response.data.critical, - ...response.data.warning - ].sort((a, b) => { - // En retard d'abord, puis critique, puis attention - const urgencyOrder: Record = { 'overdue': 0, 'critical': 1, 'warning': 2 }; - if (urgencyOrder[a.urgencyLevel] !== urgencyOrder[b.urgencyLevel]) { - return urgencyOrder[a.urgencyLevel] - urgencyOrder[b.urgencyLevel]; - } - // Si même urgence, trier par jours restants - return a.daysRemaining - b.daysRemaining; - }); - - setUrgentTasks(combinedTasks); - } else { - setError(response.error || 'Erreur lors du chargement des échéances'); - } - } catch (err) { - setError(err instanceof Error ? err.message : 'Erreur lors du chargement des échéances'); - console.error('Erreur échéances:', err); - } - }); - }; - - loadUrgentTasks(); - }, []); - - const getUrgencyIcon = (task: DeadlineTask) => { - if (task.urgencyLevel === 'overdue') return '🔴'; - if (task.urgencyLevel === 'critical') return '🟠'; - return '🟡'; - }; - - const getUrgencyText = (task: DeadlineTask) => { - if (task.urgencyLevel === 'overdue') { - return task.daysRemaining === -1 ? 'En retard de 1 jour' : `En retard de ${Math.abs(task.daysRemaining)} jours`; - } else if (task.urgencyLevel === 'critical') { - return task.daysRemaining === 0 ? 'Échéance aujourd\'hui' : - task.daysRemaining === 1 ? 'Échéance demain' : - `Dans ${task.daysRemaining} jours`; - } else { - return `Dans ${task.daysRemaining} jours`; +// Fonction utilitaire pour combiner et trier les tâches urgentes +function combineAndSortUrgentTasks(metrics: DeadlineMetrics): DeadlineTask[] { + return [ + ...metrics.overdue, + ...metrics.critical, + ...metrics.warning + ].sort((a, b) => { + // En retard d'abord, puis critique, puis attention + const urgencyOrder: Record = { 'overdue': 0, 'critical': 1, 'warning': 2 }; + if (urgencyOrder[a.urgencyLevel] !== urgencyOrder[b.urgencyLevel]) { + return urgencyOrder[a.urgencyLevel] - urgencyOrder[b.urgencyLevel]; } - }; + // Si même urgence, trier par jours restants + return a.daysRemaining - b.daysRemaining; + }); +} - const getSourceIcon = (source: string) => { - switch (source) { - case 'jira': return '🔗'; - case 'reminder': return '📱'; - default: return '📋'; - } - }; +interface DeadlineReminderProps { + deadlineMetrics?: DeadlineMetrics | null; +} - // Ne rien afficher si pas de tâches urgentes ou si en cours de chargement - if (isPending || error || urgentTasks.length === 0) { +export function DeadlineReminder({ deadlineMetrics }: DeadlineReminderProps) { + // Ne rien afficher si pas de données ou pas de tâches urgentes + if (!deadlineMetrics) { + return null; + } + + const urgentTasks = combineAndSortUrgentTasks(deadlineMetrics); + + if (urgentTasks.length === 0) { return null; } @@ -118,3 +76,30 @@ export function DeadlineReminder() { ); } + +// Fonctions utilitaires déplacées en dehors du composant +function getUrgencyIcon(task: DeadlineTask): string { + if (task.urgencyLevel === 'overdue') return '🔴'; + if (task.urgencyLevel === 'critical') return '🟠'; + return '🟡'; +} + +function getUrgencyText(task: DeadlineTask): string { + if (task.urgencyLevel === 'overdue') { + return task.daysRemaining === -1 ? 'En retard de 1 jour' : `En retard de ${Math.abs(task.daysRemaining)} jours`; + } else if (task.urgencyLevel === 'critical') { + return task.daysRemaining === 0 ? 'Échéance aujourd\'hui' : + task.daysRemaining === 1 ? 'Échéance demain' : + `Dans ${task.daysRemaining} jours`; + } else { + return `Dans ${task.daysRemaining} jours`; + } +} + +function getSourceIcon(source: string): string { + switch (source) { + case 'jira': return '🔗'; + case 'reminder': return '📱'; + default: return '📋'; + } +} diff --git a/src/components/dashboard/ProductivityAnalytics.tsx b/src/components/dashboard/ProductivityAnalytics.tsx index 8560826..2fb5822 100644 --- a/src/components/dashboard/ProductivityAnalytics.tsx +++ b/src/components/dashboard/ProductivityAnalytics.tsx @@ -1,8 +1,5 @@ -'use client'; - -import { useState, useEffect, useTransition } from 'react'; import { ProductivityMetrics } from '@/services/analytics/analytics'; -import { getProductivityMetrics } from '@/actions/analytics'; +import { DeadlineMetrics } from '@/services/analytics/deadline-analytics'; import { CompletionTrendChart } from '@/components/charts/CompletionTrendChart'; import { VelocityChart } from '@/components/charts/VelocityChart'; import { PriorityDistributionChart } from '@/components/charts/PriorityDistributionChart'; @@ -10,66 +7,17 @@ import { WeeklyStatsCard } from '@/components/charts/WeeklyStatsCard'; import { Card } from '@/components/ui/Card'; import { DeadlineOverview } from '@/components/deadline/DeadlineOverview'; -export function ProductivityAnalytics() { - const [metrics, setMetrics] = useState(null); - const [error, setError] = useState(null); - const [isPending, startTransition] = useTransition(); +interface ProductivityAnalyticsProps { + metrics: ProductivityMetrics; + deadlineMetrics: DeadlineMetrics; +} - useEffect(() => { - const loadMetrics = () => { - startTransition(async () => { - try { - setError(null); - const response = await getProductivityMetrics(); - - if (response.success && response.data) { - setMetrics(response.data); - } else { - setError(response.error || 'Erreur lors du chargement des métriques'); - } - } catch (err) { - setError(err instanceof Error ? err.message : 'Erreur lors du chargement des métriques'); - console.error('Erreur analytics:', err); - } - }); - }; - - loadMetrics(); - }, []); - - if (isPending) { - return ( -
- {Array.from({ length: 4 }).map((_, i) => ( - -
-
-
- ))} -
- ); - } - - if (error) { - return ( - -
-
⚠️
-

Erreur de chargement

-

{error}

-
-
- ); - } - - if (!metrics) { - return null; - } +export function ProductivityAnalytics({ metrics, deadlineMetrics }: ProductivityAnalyticsProps) { return (
{/* Section Échéances Critiques */} - + {/* Titre de section Analytics */}
diff --git a/src/components/deadline/DeadlineOverview.tsx b/src/components/deadline/DeadlineOverview.tsx index bb406cd..963f414 100644 --- a/src/components/deadline/DeadlineOverview.tsx +++ b/src/components/deadline/DeadlineOverview.tsx @@ -1,68 +1,13 @@ -'use client'; - -import { useState, useEffect, useTransition } from 'react'; import { DeadlineMetrics } from '@/services/analytics/deadline-analytics'; -import { getDeadlineMetrics } from '@/actions/deadline-analytics'; -import { Card } from '@/components/ui/Card'; import { DeadlineRiskCard } from './DeadlineRiskCard'; import { CriticalDeadlinesCard } from './CriticalDeadlinesCard'; import { DeadlineSummaryCard } from './DeadlineSummaryCard'; -export function DeadlineOverview() { - const [metrics, setMetrics] = useState(null); - const [error, setError] = useState(null); - const [isPending, startTransition] = useTransition(); +interface DeadlineOverviewProps { + metrics: DeadlineMetrics; +} - useEffect(() => { - const loadMetrics = () => { - startTransition(async () => { - try { - setError(null); - const response = await getDeadlineMetrics(); - - if (response.success && response.data) { - setMetrics(response.data); - } else { - setError(response.error || 'Erreur lors du chargement des échéances'); - } - } catch (err) { - setError(err instanceof Error ? err.message : 'Erreur lors du chargement des échéances'); - console.error('Erreur échéances:', err); - } - }); - }; - - loadMetrics(); - }, []); - - if (isPending) { - return ( -
- {Array.from({ length: 3 }).map((_, i) => ( - -
-
-
- ))} -
- ); - } - - if (error) { - return ( - -
-
⚠️
-

Erreur de chargement des échéances

-

{error}

-
-
- ); - } - - if (!metrics) { - return null; - } +export function DeadlineOverview({ metrics }: DeadlineOverviewProps) { return (