'use client'; import { useState, useEffect, useMemo } from 'react'; import { JiraConfig } from '@/lib/types'; import { useJiraAnalytics } from '@/hooks/useJiraAnalytics'; import { useJiraExport } from '@/hooks/useJiraExport'; import { filterAnalyticsByPeriod, getPeriodInfo, type PeriodFilter } from '@/lib/jira-period-filter'; import { Header } from '@/components/ui/Header'; import { Card, CardHeader, CardContent } from '@/components/ui/Card'; import { Button } from '@/components/ui/Button'; import { VelocityChart } from '@/components/jira/VelocityChart'; import { TeamDistributionChart } from '@/components/jira/TeamDistributionChart'; import { CycleTimeChart } from '@/components/jira/CycleTimeChart'; import { TeamActivityHeatmap } from '@/components/jira/TeamActivityHeatmap'; import { BurndownChart } from '@/components/jira/BurndownChart'; import { ThroughputChart } from '@/components/jira/ThroughputChart'; import { QualityMetrics } from '@/components/jira/QualityMetrics'; import { PredictabilityMetrics } from '@/components/jira/PredictabilityMetrics'; import { CollaborationMatrix } from '@/components/jira/CollaborationMatrix'; import { SprintComparison } from '@/components/jira/SprintComparison'; import AnomalyDetectionPanel from '@/components/jira/AnomalyDetectionPanel'; import FilterBar from '@/components/jira/FilterBar'; import SprintDetailModal, { SprintDetails } from '@/components/jira/SprintDetailModal'; import { getSprintDetails } from '../../actions/jira-sprint-details'; import { useJiraFilters } from '@/hooks/useJiraFilters'; import { SprintVelocity } from '@/lib/types'; import Link from 'next/link'; interface JiraDashboardPageClientProps { initialJiraConfig: JiraConfig; } export function JiraDashboardPageClient({ initialJiraConfig }: JiraDashboardPageClientProps) { const { analytics: rawAnalytics, isLoading, error, loadAnalytics, refreshAnalytics } = useJiraAnalytics(); const { isExporting, error: exportError, exportCSV, exportJSON } = useJiraExport(); const { availableFilters, activeFilters, filteredAnalytics, applyFilters, hasActiveFilters } = useJiraFilters(); const [selectedPeriod, setSelectedPeriod] = useState('current'); const [selectedSprint, setSelectedSprint] = useState(null); const [showSprintModal, setShowSprintModal] = useState(false); const [activeTab, setActiveTab] = useState<'overview' | 'velocity' | 'analytics' | 'quality'>('overview'); // Filtrer les analytics selon la période sélectionnée et les filtres avancés const analytics = useMemo(() => { const baseAnalytics = hasActiveFilters && filteredAnalytics ? filteredAnalytics : rawAnalytics; if (!baseAnalytics) return null; return filterAnalyticsByPeriod(baseAnalytics, selectedPeriod); }, [rawAnalytics, filteredAnalytics, selectedPeriod, hasActiveFilters]); // Informations sur la période pour l'affichage const periodInfo = getPeriodInfo(selectedPeriod); useEffect(() => { // Charger les analytics au montage si Jira est configuré avec un projet if (initialJiraConfig.enabled && initialJiraConfig.projectKey) { loadAnalytics(); } }, [initialJiraConfig.enabled, initialJiraConfig.projectKey, loadAnalytics]); // Gestion du clic sur un sprint const handleSprintClick = (sprint: SprintVelocity) => { setSelectedSprint(sprint); setShowSprintModal(true); }; const handleCloseSprintModal = () => { setShowSprintModal(false); setSelectedSprint(null); }; const loadSprintDetails = async (sprintName: string): Promise => { const result = await getSprintDetails(sprintName); if (result.success && result.data) { return result.data; } else { throw new Error(result.error || 'Erreur lors du chargement des détails du sprint'); } }; // Vérifier si Jira est configuré const isJiraConfigured = initialJiraConfig.enabled && initialJiraConfig.baseUrl && initialJiraConfig.email && initialJiraConfig.apiToken; const hasProjectConfigured = isJiraConfigured && initialJiraConfig.projectKey; if (!isJiraConfigured) { return (

⚙️ Configuration requise

Jira n'est pas configuré. Vous devez d'abord configurer votre connexion Jira pour accéder aux analytics d'équipe.

); } if (!hasProjectConfigured) { return (

🎯 Projet requis

Aucun projet n'est configuré pour les analytics d'équipe. Configurez un projet spécifique à surveiller dans les paramètres Jira.

); } return (
{/* Breadcrumb */}
Paramètres / Intégrations / Dashboard Jira
{/* Header avec contrôles */}

📊 Analytics d'équipe

Surveillance en temps réel du projet {initialJiraConfig.projectKey}

{periodInfo.icon} {periodInfo.label} • {periodInfo.description}

{/* Sélecteur de période */}
{[ { value: '7d', label: '7j' }, { value: '30d', label: '30j' }, { value: '3m', label: '3m' }, { value: 'current', label: 'Sprint' } ].map((period: { value: string; label: string }) => ( ))}
{analytics && ( <>
💾 Données en cache
{/* Boutons d'export */}
)}
{/* Contenu principal */} {error && (
{error}
)} {exportError && (
⚠️ Erreur d'export: {exportError}
)} {isLoading && !analytics && (
{/* Skeleton loading */} {[1, 2, 3, 4, 5, 6].map(i => (
))}
)} {analytics && (
{/* En-tête compact du projet */}

🎯 {analytics.project.name} ({periodInfo.label})

{analytics.project.totalIssues}
Tickets
{analytics.teamMetrics.totalAssignees}
Équipe
{analytics.teamMetrics.activeAssignees}
Actifs
{analytics.velocityMetrics.currentSprintPoints}
Points
{/* Barre de filtres */} {/* Détection d'anomalies */} {/* Onglets de navigation */}
{/* Contenu des onglets */} {activeTab === 'overview' && (
{/* Graphiques principaux */}

👥 Répartition de l'équipe

🚀 Vélocité des sprints

{/* Métriques de temps et cycle time */}

⏱️ Cycle Time par type

{analytics.cycleTimeMetrics.averageCycleTime}
jours en moyenne globale

🚀 Vélocité

{analytics.velocityMetrics.averageVelocity}
points par sprint
{analytics.velocityMetrics.sprintHistory.map(sprint => (
{sprint.sprintName} {sprint.completedPoints}/{sprint.plannedPoints}
))}
{/* Métriques avancées */}

📉 Burndown Chart

📈 Throughput

{/* Métriques de qualité */}

🎯 Métriques de qualité

{/* Métriques de predictabilité */}

📊 Predictabilité

{/* Matrice de collaboration - ligne entière */}

🤝 Matrice de collaboration

{/* Comparaison inter-sprints */}

📊 Comparaison inter-sprints

{/* Heatmap d'activité de l'équipe */}

🔥 Heatmap d'activité de l'équipe

)} {activeTab === 'velocity' && (
{/* Graphique de vélocité */}

🚀 Vélocité des sprints

{/* Burndown et Throughput */}

📉 Burndown Chart

📊 Throughput

{/* Comparaison des sprints */}

📊 Comparaison des sprints

)} {activeTab === 'analytics' && (
{/* Métriques de temps et cycle time */}

⏱️ Cycle Time par type

{analytics.cycleTimeMetrics.averageCycleTime.toFixed(1)}
Cycle time moyen (jours)

🔥 Heatmap d'activité

{/* Métriques avancées */}

🎯 Métriques de qualité

📈 Predictabilité

)} {activeTab === 'quality' && (
{/* Collaboration et équipe */}

👥 Répartition de l'équipe

🤝 Matrice de collaboration

)}
)}
{/* Modal de détail de sprint */}
); }