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.
This commit is contained in:
@@ -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'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useDaily } from '@/hooks/useDaily';
|
import { useDaily } from '@/hooks/useDaily';
|
||||||
import { DailyView, DailyCheckboxType } from '@/lib/types';
|
import { DailyView, DailyCheckboxType } from '@/lib/types';
|
||||||
|
import { DeadlineMetrics } from '@/services/analytics/deadline-analytics';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { Card } from '@/components/ui/Card';
|
import { Card } from '@/components/ui/Card';
|
||||||
import { DailyCalendar } from '@/components/daily/DailyCalendar';
|
import { DailyCalendar } from '@/components/daily/DailyCalendar';
|
||||||
@@ -18,12 +19,14 @@ interface DailyPageClientProps {
|
|||||||
initialDailyView?: DailyView;
|
initialDailyView?: DailyView;
|
||||||
initialDailyDates?: string[];
|
initialDailyDates?: string[];
|
||||||
initialDate?: Date;
|
initialDate?: Date;
|
||||||
|
initialDeadlineMetrics?: DeadlineMetrics | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DailyPageClient({
|
export function DailyPageClient({
|
||||||
initialDailyView,
|
initialDailyView,
|
||||||
initialDailyDates = [],
|
initialDailyDates = [],
|
||||||
initialDate
|
initialDate,
|
||||||
|
initialDeadlineMetrics
|
||||||
}: DailyPageClientProps = {}) {
|
}: DailyPageClientProps = {}) {
|
||||||
const {
|
const {
|
||||||
dailyView,
|
dailyView,
|
||||||
@@ -214,7 +217,7 @@ export function DailyPageClient({
|
|||||||
|
|
||||||
{/* Rappel des échéances urgentes - Desktop uniquement */}
|
{/* Rappel des échéances urgentes - Desktop uniquement */}
|
||||||
<div className="hidden sm:block container mx-auto px-4 pt-4 pb-2">
|
<div className="hidden sm:block container mx-auto px-4 pt-4 pb-2">
|
||||||
<DeadlineReminder />
|
<DeadlineReminder deadlineMetrics={initialDeadlineMetrics} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Contenu principal */}
|
{/* Contenu principal */}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Metadata } from 'next';
|
import { Metadata } from 'next';
|
||||||
import { DailyPageClient } from './DailyPageClient';
|
import { DailyPageClient } from './DailyPageClient';
|
||||||
import { dailyService } from '@/services/task-management/daily';
|
import { dailyService } from '@/services/task-management/daily';
|
||||||
|
import { DeadlineAnalyticsService } from '@/services/analytics/deadline-analytics';
|
||||||
import { getToday } from '@/lib/date-utils';
|
import { getToday } from '@/lib/date-utils';
|
||||||
|
|
||||||
// Force dynamic rendering (no static generation)
|
// Force dynamic rendering (no static generation)
|
||||||
@@ -16,9 +17,10 @@ export default async function DailyPage() {
|
|||||||
const today = getToday();
|
const today = getToday();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [dailyView, dailyDates] = await Promise.all([
|
const [dailyView, dailyDates, deadlineMetrics] = await Promise.all([
|
||||||
dailyService.getDailyView(today),
|
dailyService.getDailyView(today),
|
||||||
dailyService.getDailyDates()
|
dailyService.getDailyDates(),
|
||||||
|
DeadlineAnalyticsService.getDeadlineMetrics().catch(() => null) // Graceful fallback
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -26,6 +28,7 @@ export default async function DailyPage() {
|
|||||||
initialDailyView={dailyView}
|
initialDailyView={dailyView}
|
||||||
initialDailyDates={dailyDates}
|
initialDailyDates={dailyDates}
|
||||||
initialDate={today}
|
initialDate={today}
|
||||||
|
initialDeadlineMetrics={deadlineMetrics}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { tasksService } from '@/services/task-management/tasks';
|
import { tasksService } from '@/services/task-management/tasks';
|
||||||
import { tagsService } from '@/services/task-management/tags';
|
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';
|
import { HomePageClient } from '@/components/HomePageClient';
|
||||||
|
|
||||||
// Force dynamic rendering (no static generation)
|
// Force dynamic rendering (no static generation)
|
||||||
@@ -7,10 +9,12 @@ export const dynamic = 'force-dynamic';
|
|||||||
|
|
||||||
export default async function HomePage() {
|
export default async function HomePage() {
|
||||||
// SSR - Récupération des données côté serveur
|
// 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(),
|
tasksService.getTasks(),
|
||||||
tagsService.getTags(),
|
tagsService.getTags(),
|
||||||
tasksService.getTaskStats()
|
tasksService.getTaskStats(),
|
||||||
|
AnalyticsService.getProductivityMetrics(),
|
||||||
|
DeadlineAnalyticsService.getDeadlineMetrics()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -18,6 +22,8 @@ export default async function HomePage() {
|
|||||||
initialTasks={initialTasks}
|
initialTasks={initialTasks}
|
||||||
initialTags={initialTags}
|
initialTags={initialTags}
|
||||||
initialStats={initialStats}
|
initialStats={initialStats}
|
||||||
|
productivityMetrics={productivityMetrics}
|
||||||
|
deadlineMetrics={deadlineMetrics}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,22 @@ import { DashboardStats } from '@/components/dashboard/DashboardStats';
|
|||||||
import { QuickActions } from '@/components/dashboard/QuickActions';
|
import { QuickActions } from '@/components/dashboard/QuickActions';
|
||||||
import { RecentTasks } from '@/components/dashboard/RecentTasks';
|
import { RecentTasks } from '@/components/dashboard/RecentTasks';
|
||||||
import { ProductivityAnalytics } from '@/components/dashboard/ProductivityAnalytics';
|
import { ProductivityAnalytics } from '@/components/dashboard/ProductivityAnalytics';
|
||||||
|
import { ProductivityMetrics } from '@/services/analytics/analytics';
|
||||||
|
import { DeadlineMetrics } from '@/services/analytics/deadline-analytics';
|
||||||
|
|
||||||
interface HomePageClientProps {
|
interface HomePageClientProps {
|
||||||
initialTasks: Task[];
|
initialTasks: Task[];
|
||||||
initialTags: (Tag & { usage: number })[];
|
initialTags: (Tag & { usage: number })[];
|
||||||
initialStats: TaskStats;
|
initialStats: TaskStats;
|
||||||
|
productivityMetrics: ProductivityMetrics;
|
||||||
|
deadlineMetrics: DeadlineMetrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function HomePageContent() {
|
function HomePageContent({ productivityMetrics, deadlineMetrics }: {
|
||||||
|
productivityMetrics: ProductivityMetrics;
|
||||||
|
deadlineMetrics: DeadlineMetrics;
|
||||||
|
}) {
|
||||||
const { stats, syncing, createTask, tasks } = useTasksContext();
|
const { stats, syncing, createTask, tasks } = useTasksContext();
|
||||||
|
|
||||||
// Handler pour la création de tâche
|
// Handler pour la création de tâche
|
||||||
@@ -40,7 +47,10 @@ function HomePageContent() {
|
|||||||
<QuickActions onCreateTask={handleCreateTask} />
|
<QuickActions onCreateTask={handleCreateTask} />
|
||||||
|
|
||||||
{/* Analytics et métriques */}
|
{/* Analytics et métriques */}
|
||||||
<ProductivityAnalytics />
|
<ProductivityAnalytics
|
||||||
|
metrics={productivityMetrics}
|
||||||
|
deadlineMetrics={deadlineMetrics}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Tâches récentes */}
|
{/* Tâches récentes */}
|
||||||
<RecentTasks tasks={tasks} />
|
<RecentTasks tasks={tasks} />
|
||||||
@@ -49,14 +59,23 @@ function HomePageContent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HomePageClient({ initialTasks, initialTags, initialStats }: HomePageClientProps) {
|
export function HomePageClient({
|
||||||
|
initialTasks,
|
||||||
|
initialTags,
|
||||||
|
initialStats,
|
||||||
|
productivityMetrics,
|
||||||
|
deadlineMetrics
|
||||||
|
}: HomePageClientProps) {
|
||||||
return (
|
return (
|
||||||
<TasksProvider
|
<TasksProvider
|
||||||
initialTasks={initialTasks}
|
initialTasks={initialTasks}
|
||||||
initialTags={initialTags}
|
initialTags={initialTags}
|
||||||
initialStats={initialStats}
|
initialStats={initialStats}
|
||||||
>
|
>
|
||||||
<HomePageContent />
|
<HomePageContent
|
||||||
|
productivityMetrics={productivityMetrics}
|
||||||
|
deadlineMetrics={deadlineMetrics}
|
||||||
|
/>
|
||||||
</TasksProvider>
|
</TasksProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,14 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState, useEffect, useTransition } from 'react';
|
import { DeadlineTask, DeadlineMetrics } from '@/services/analytics/deadline-analytics';
|
||||||
import { DeadlineTask } from '@/services/analytics/deadline-analytics';
|
|
||||||
import { getDeadlineMetrics } from '@/actions/deadline-analytics';
|
|
||||||
import { Card } from '@/components/ui/Card';
|
import { Card } from '@/components/ui/Card';
|
||||||
|
|
||||||
export function DeadlineReminder() {
|
// Fonction utilitaire pour combiner et trier les tâches urgentes
|
||||||
const [urgentTasks, setUrgentTasks] = useState<DeadlineTask[]>([]);
|
function combineAndSortUrgentTasks(metrics: DeadlineMetrics): DeadlineTask[] {
|
||||||
const [error, setError] = useState<string | null>(null);
|
return [
|
||||||
const [isPending, startTransition] = useTransition();
|
...metrics.overdue,
|
||||||
|
...metrics.critical,
|
||||||
useEffect(() => {
|
...metrics.warning
|
||||||
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) => {
|
].sort((a, b) => {
|
||||||
// En retard d'abord, puis critique, puis attention
|
// En retard d'abord, puis critique, puis attention
|
||||||
const urgencyOrder: Record<string, number> = { 'overdue': 0, 'critical': 1, 'warning': 2 };
|
const urgencyOrder: Record<string, number> = { 'overdue': 0, 'critical': 1, 'warning': 2 };
|
||||||
@@ -32,49 +18,21 @@ export function DeadlineReminder() {
|
|||||||
// Si même urgence, trier par jours restants
|
// Si même urgence, trier par jours restants
|
||||||
return a.daysRemaining - b.daysRemaining;
|
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');
|
interface DeadlineReminderProps {
|
||||||
console.error('Erreur échéances:', err);
|
deadlineMetrics?: DeadlineMetrics | null;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
loadUrgentTasks();
|
export function DeadlineReminder({ deadlineMetrics }: DeadlineReminderProps) {
|
||||||
}, []);
|
// Ne rien afficher si pas de données ou pas de tâches urgentes
|
||||||
|
if (!deadlineMetrics) {
|
||||||
const getUrgencyIcon = (task: DeadlineTask) => {
|
return null;
|
||||||
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`;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const getSourceIcon = (source: string) => {
|
const urgentTasks = combineAndSortUrgentTasks(deadlineMetrics);
|
||||||
switch (source) {
|
|
||||||
case 'jira': return '🔗';
|
|
||||||
case 'reminder': return '📱';
|
|
||||||
default: return '📋';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Ne rien afficher si pas de tâches urgentes ou si en cours de chargement
|
if (urgentTasks.length === 0) {
|
||||||
if (isPending || error || urgentTasks.length === 0) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,3 +76,30 @@ export function DeadlineReminder() {
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 '📋';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useState, useEffect, useTransition } from 'react';
|
|
||||||
import { ProductivityMetrics } from '@/services/analytics/analytics';
|
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 { CompletionTrendChart } from '@/components/charts/CompletionTrendChart';
|
||||||
import { VelocityChart } from '@/components/charts/VelocityChart';
|
import { VelocityChart } from '@/components/charts/VelocityChart';
|
||||||
import { PriorityDistributionChart } from '@/components/charts/PriorityDistributionChart';
|
import { PriorityDistributionChart } from '@/components/charts/PriorityDistributionChart';
|
||||||
@@ -10,66 +7,17 @@ import { WeeklyStatsCard } from '@/components/charts/WeeklyStatsCard';
|
|||||||
import { Card } from '@/components/ui/Card';
|
import { Card } from '@/components/ui/Card';
|
||||||
import { DeadlineOverview } from '@/components/deadline/DeadlineOverview';
|
import { DeadlineOverview } from '@/components/deadline/DeadlineOverview';
|
||||||
|
|
||||||
export function ProductivityAnalytics() {
|
interface ProductivityAnalyticsProps {
|
||||||
const [metrics, setMetrics] = useState<ProductivityMetrics | null>(null);
|
metrics: ProductivityMetrics;
|
||||||
const [error, setError] = useState<string | null>(null);
|
deadlineMetrics: DeadlineMetrics;
|
||||||
const [isPending, startTransition] = useTransition();
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
|
||||||
{Array.from({ length: 4 }).map((_, i) => (
|
|
||||||
<Card key={i} className="p-6 animate-pulse">
|
|
||||||
<div className="h-4 bg-[var(--border)] rounded mb-4 w-1/3"></div>
|
|
||||||
<div className="h-64 bg-[var(--border)] rounded"></div>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
export function ProductivityAnalytics({ metrics, deadlineMetrics }: ProductivityAnalyticsProps) {
|
||||||
return (
|
|
||||||
<Card className="p-6 mb-8 mt-8">
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="text-red-500 text-4xl mb-2">⚠️</div>
|
|
||||||
<h3 className="text-lg font-semibold mb-2">Erreur de chargement</h3>
|
|
||||||
<p className="text-[var(--muted-foreground)] text-sm">{error}</p>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!metrics) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-8">
|
<div className="space-y-8">
|
||||||
{/* Section Échéances Critiques */}
|
{/* Section Échéances Critiques */}
|
||||||
<DeadlineOverview />
|
<DeadlineOverview metrics={deadlineMetrics} />
|
||||||
|
|
||||||
{/* Titre de section Analytics */}
|
{/* Titre de section Analytics */}
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
|
|||||||
@@ -1,68 +1,13 @@
|
|||||||
'use client';
|
|
||||||
|
|
||||||
import { useState, useEffect, useTransition } from 'react';
|
|
||||||
import { DeadlineMetrics } from '@/services/analytics/deadline-analytics';
|
import { DeadlineMetrics } from '@/services/analytics/deadline-analytics';
|
||||||
import { getDeadlineMetrics } from '@/actions/deadline-analytics';
|
|
||||||
import { Card } from '@/components/ui/Card';
|
|
||||||
import { DeadlineRiskCard } from './DeadlineRiskCard';
|
import { DeadlineRiskCard } from './DeadlineRiskCard';
|
||||||
import { CriticalDeadlinesCard } from './CriticalDeadlinesCard';
|
import { CriticalDeadlinesCard } from './CriticalDeadlinesCard';
|
||||||
import { DeadlineSummaryCard } from './DeadlineSummaryCard';
|
import { DeadlineSummaryCard } from './DeadlineSummaryCard';
|
||||||
|
|
||||||
export function DeadlineOverview() {
|
interface DeadlineOverviewProps {
|
||||||
const [metrics, setMetrics] = useState<DeadlineMetrics | null>(null);
|
metrics: DeadlineMetrics;
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
const [isPending, startTransition] = useTransition();
|
|
||||||
|
|
||||||
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 (
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
|
|
||||||
{Array.from({ length: 3 }).map((_, i) => (
|
|
||||||
<Card key={i} className="p-6 animate-pulse">
|
|
||||||
<div className="h-4 bg-[var(--border)] rounded mb-4 w-1/2"></div>
|
|
||||||
<div className="h-20 bg-[var(--border)] rounded"></div>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error) {
|
export function DeadlineOverview({ metrics }: DeadlineOverviewProps) {
|
||||||
return (
|
|
||||||
<Card className="p-6 mb-8">
|
|
||||||
<div className="text-center">
|
|
||||||
<div className="text-red-500 text-4xl mb-2">⚠️</div>
|
|
||||||
<h3 className="text-lg font-semibold mb-2">Erreur de chargement des échéances</h3>
|
|
||||||
<p className="text-[var(--muted-foreground)] text-sm">{error}</p>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!metrics) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
|||||||
Reference in New Issue
Block a user