feat: enhance JiraDashboard with initial analytics support
- Updated `JiraDashboardPageClient` to accept `initialAnalytics`, allowing for server-side analytics retrieval. - Modified `useJiraAnalytics` to initialize state with `initialAnalytics`, improving data handling. - Adjusted `CollaborationMatrix` to manage client-side rendering and analytics data processing, preventing hydration errors. - Enhanced `page.tsx` to fetch analytics based on Jira configuration, ensuring data is available for the dashboard.
This commit is contained in:
@@ -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) => {
|
||||
|
||||
@@ -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 (
|
||||
<JiraDashboardPageClient initialJiraConfig={jiraConfig} />
|
||||
<JiraDashboardPageClient
|
||||
initialJiraConfig={jiraConfig}
|
||||
initialAnalytics={initialAnalytics}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<CollaborationData[]>([]);
|
||||
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 (
|
||||
<div className={className}>
|
||||
<div className="animate-pulse bg-gray-200 dark:bg-gray-700 rounded-lg h-96" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 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') => {
|
||||
|
||||
@@ -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<JiraAnalytics | null>(null);
|
||||
export function useJiraAnalytics(initialAnalytics?: JiraAnalytics | null) {
|
||||
const [analytics, setAnalytics] = useState<JiraAnalytics | null>(initialAnalytics || null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isPending, startTransition] = useTransition();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user