diff --git a/src/app/jira-dashboard/JiraDashboardPageClient.tsx b/src/app/jira-dashboard/JiraDashboardPageClient.tsx
index 6627893..61ef078 100644
--- a/src/app/jira-dashboard/JiraDashboardPageClient.tsx
+++ b/src/app/jira-dashboard/JiraDashboardPageClient.tsx
@@ -1,7 +1,7 @@
'use client';
import { useState, useEffect, useMemo } from 'react';
-import { JiraConfig } from '@/lib/types';
+import { JiraConfig, JiraAnalytics } from '@/lib/types';
import { useJiraAnalytics } from '@/hooks/useJiraAnalytics';
import { useJiraExport } from '@/hooks/useJiraExport';
import { filterAnalyticsByPeriod, getPeriodInfo, type PeriodFilter } from '@/lib/jira-period-filter';
@@ -28,10 +28,11 @@ import Link from 'next/link';
interface JiraDashboardPageClientProps {
initialJiraConfig: JiraConfig;
+ initialAnalytics?: JiraAnalytics | null;
}
-export function JiraDashboardPageClient({ initialJiraConfig }: JiraDashboardPageClientProps) {
- const { analytics: rawAnalytics, isLoading, error, loadAnalytics, refreshAnalytics } = useJiraAnalytics();
+export function JiraDashboardPageClient({ initialJiraConfig, initialAnalytics }: JiraDashboardPageClientProps) {
+ const { analytics: rawAnalytics, isLoading, error, loadAnalytics, refreshAnalytics } = useJiraAnalytics(initialAnalytics);
const { isExporting, error: exportError, exportCSV, exportJSON } = useJiraExport();
const {
availableFilters,
@@ -56,11 +57,11 @@ export function JiraDashboardPageClient({ initialJiraConfig }: JiraDashboardPage
const periodInfo = getPeriodInfo(selectedPeriod);
useEffect(() => {
- // Charger les analytics au montage si Jira est configuré avec un projet
- if (initialJiraConfig.enabled && initialJiraConfig.projectKey) {
+ // Charger les analytics au montage seulement si Jira est configuré ET qu'on n'a pas déjà des données
+ if (initialJiraConfig.enabled && initialJiraConfig.projectKey && !initialAnalytics) {
loadAnalytics();
}
- }, [initialJiraConfig.enabled, initialJiraConfig.projectKey, loadAnalytics]);
+ }, [initialJiraConfig.enabled, initialJiraConfig.projectKey, loadAnalytics, initialAnalytics]);
// Gestion du clic sur un sprint
const handleSprintClick = (sprint: SprintVelocity) => {
diff --git a/src/app/jira-dashboard/page.tsx b/src/app/jira-dashboard/page.tsx
index d4e661e..64d73ce 100644
--- a/src/app/jira-dashboard/page.tsx
+++ b/src/app/jira-dashboard/page.tsx
@@ -1,4 +1,5 @@
import { userPreferencesService } from '@/services/core/user-preferences';
+import { getJiraAnalytics } from '@/actions/jira-analytics';
import { JiraDashboardPageClient } from './JiraDashboardPageClient';
// Force dynamic rendering
@@ -7,8 +8,20 @@ export const dynamic = 'force-dynamic';
export default async function JiraDashboardPage() {
// Récupérer la config Jira côté serveur
const jiraConfig = await userPreferencesService.getJiraConfig();
+
+ // Récupérer les analytics côté serveur (utilise le cache du service)
+ let initialAnalytics = null;
+ if (jiraConfig.enabled && jiraConfig.projectKey) {
+ const analyticsResult = await getJiraAnalytics(false); // Utilise le cache
+ if (analyticsResult.success) {
+ initialAnalytics = analyticsResult.data;
+ }
+ }
return (
-
+
);
}
diff --git a/src/components/jira/CollaborationMatrix.tsx b/src/components/jira/CollaborationMatrix.tsx
index 26c961d..1b27e1a 100644
--- a/src/components/jira/CollaborationMatrix.tsx
+++ b/src/components/jira/CollaborationMatrix.tsx
@@ -1,6 +1,6 @@
'use client';
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { JiraAnalytics } from '@/lib/types';
import { Card } from '@/components/ui/Card';
@@ -23,10 +23,16 @@ interface CollaborationData {
}
export function CollaborationMatrix({ analytics, className }: CollaborationMatrixProps) {
- // Analyser les patterns de collaboration basés sur les données existantes
- const collaborationData: CollaborationData[] = analytics.teamMetrics.issuesDistribution.map(assignee => {
- // Simuler des collaborations basées sur les données réelles
- const totalTickets = assignee.totalIssues;
+ const [collaborationData, setCollaborationData] = useState([]);
+ const [isClient, setIsClient] = useState(false);
+
+ useEffect(() => {
+ setIsClient(true);
+
+ // Analyser les patterns de collaboration basés sur les données existantes
+ const data: CollaborationData[] = analytics.teamMetrics.issuesDistribution.map(assignee => {
+ // Simuler des collaborations basées sur les données réelles
+ const totalTickets = assignee.totalIssues;
// Générer des partenaires de collaboration réalistes
const otherAssignees = analytics.teamMetrics.issuesDistribution.filter(a => a.assignee !== assignee.assignee);
@@ -67,13 +73,25 @@ export function CollaborationMatrix({ analytics, className }: CollaborationMatri
};
});
- // Statistiques globales
- const avgCollaboration = collaborationData.reduce((sum, d) => sum + d.collaborationScore, 0) / collaborationData.length;
- const avgIsolation = collaborationData.reduce((sum, d) => sum + d.isolation, 0) / collaborationData.length;
- const mostCollaborative = collaborationData.reduce((max, current) =>
- current.collaborationScore > max.collaborationScore ? current : max, collaborationData[0]);
- const mostIsolated = collaborationData.reduce((max, current) =>
- current.isolation > max.isolation ? current : max, collaborationData[0]);
+ setCollaborationData(data);
+}, [analytics]);
+
+// Ne pas rendre côté serveur pour éviter l'erreur d'hydratation
+if (!isClient) {
+ return (
+
+ );
+}
+
+// Statistiques globales
+const avgCollaboration = collaborationData.reduce((sum, d) => sum + d.collaborationScore, 0) / collaborationData.length;
+const avgIsolation = collaborationData.reduce((sum, d) => sum + d.isolation, 0) / collaborationData.length;
+const mostCollaborative = collaborationData.reduce((max, current) =>
+ current.collaborationScore > max.collaborationScore ? current : max, collaborationData[0]);
+const mostIsolated = collaborationData.reduce((max, current) =>
+ current.isolation > max.isolation ? current : max, collaborationData[0]);
// Couleur d'intensité
const getIntensityColor = (intensity: 'low' | 'medium' | 'high') => {
diff --git a/src/hooks/useJiraAnalytics.ts b/src/hooks/useJiraAnalytics.ts
index 1f0376b..4c8aecb 100644
--- a/src/hooks/useJiraAnalytics.ts
+++ b/src/hooks/useJiraAnalytics.ts
@@ -4,8 +4,8 @@ import { useState, useTransition, useCallback } from 'react';
import { getJiraAnalytics } from '@/actions/jira-analytics';
import { JiraAnalytics } from '@/lib/types';
-export function useJiraAnalytics() {
- const [analytics, setAnalytics] = useState(null);
+export function useJiraAnalytics(initialAnalytics?: JiraAnalytics | null) {
+ const [analytics, setAnalytics] = useState(initialAnalytics || null);
const [error, setError] = useState(null);
const [isPending, startTransition] = useTransition();