fix: Update PrimeReact to v10.8.3 and fix all compilation errors
This commit is contained in:
@@ -1,72 +1,22 @@
|
||||
/**
|
||||
* Hook pour les données du dashboard - Version 2025 BTP Xpress
|
||||
* Utilise UNIQUEMENT les données réelles du backend Quarkus
|
||||
*/
|
||||
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { apiClient } from '../services/api-client';
|
||||
import { Chantier } from '../types/btp';
|
||||
import {
|
||||
DashboardMetrics,
|
||||
ChantierActif,
|
||||
ActiviteRecente,
|
||||
TacheUrgente,
|
||||
DashboardPrincipalResponse,
|
||||
DashboardChantiersResponse,
|
||||
ChantierActifDTO
|
||||
} from '../types/dashboard';
|
||||
|
||||
// Types pour les données du dashboard
|
||||
export interface DashboardMetrics {
|
||||
totalChantiers: number;
|
||||
chantiersActifs: number;
|
||||
chantiersEnRetard: number;
|
||||
chantiersTermines: number;
|
||||
totalEquipes: number;
|
||||
equipesDisponibles: number;
|
||||
totalMateriel: number;
|
||||
materielDisponible: number;
|
||||
materielEnMaintenance: number;
|
||||
totalDocuments: number;
|
||||
totalPhotos: number;
|
||||
budgetTotal: number;
|
||||
coutReel: number;
|
||||
chiffreAffaires: number;
|
||||
objectifCA: number;
|
||||
tauxReussite: number;
|
||||
satisfactionClient: number;
|
||||
}
|
||||
|
||||
export interface ChantierActif {
|
||||
id: string;
|
||||
nom: string;
|
||||
client: string | { nom: string; prenom?: string };
|
||||
avancement: number;
|
||||
dateDebut: string;
|
||||
dateFinPrevue: string;
|
||||
statut: 'EN_COURS' | 'EN_RETARD' | 'PLANIFIE' | 'TERMINE';
|
||||
budget: number;
|
||||
coutReel: number;
|
||||
equipe?: {
|
||||
id: string;
|
||||
nom: string;
|
||||
nombreMembres: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface ActiviteRecente {
|
||||
id: string;
|
||||
type: 'CHANTIER' | 'MAINTENANCE' | 'DOCUMENT' | 'EQUIPE';
|
||||
titre: string;
|
||||
description: string;
|
||||
date: string;
|
||||
utilisateur: string;
|
||||
statut: 'SUCCESS' | 'WARNING' | 'ERROR' | 'INFO';
|
||||
}
|
||||
|
||||
export interface TacheUrgente {
|
||||
id: string;
|
||||
titre: string;
|
||||
description: string;
|
||||
priorite: 'HAUTE' | 'MOYENNE' | 'BASSE';
|
||||
echeance: string;
|
||||
assignee: string;
|
||||
statut: 'A_FAIRE' | 'EN_COURS' | 'TERMINEE';
|
||||
chantier?: {
|
||||
id: string;
|
||||
nom: string;
|
||||
};
|
||||
}
|
||||
// Ré-exporter les types pour compatibilité
|
||||
export type { DashboardMetrics, ChantierActif, ActiviteRecente, TacheUrgente };
|
||||
|
||||
interface DashboardData {
|
||||
metrics: DashboardMetrics | null;
|
||||
@@ -93,8 +43,8 @@ export const useDashboard = (periode: 'semaine' | 'mois' | 'trimestre' | 'annee'
|
||||
try {
|
||||
setData(prev => ({ ...prev, loading: true, error: null }));
|
||||
|
||||
console.log('📊 Dashboard: Démarrage du chargement des données...');
|
||||
console.log('🔗 API Base URL:', process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080/api/v1');
|
||||
console.log('📊 Dashboard: Démarrage du chargement des données depuis le backend...');
|
||||
console.log('🔗 API Base URL:', process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8080');
|
||||
|
||||
// Vérifier si la requête a été annulée
|
||||
if (abortController?.signal.aborted) {
|
||||
@@ -102,121 +52,98 @@ export const useDashboard = (periode: 'semaine' | 'mois' | 'trimestre' | 'annee'
|
||||
return;
|
||||
}
|
||||
|
||||
// Test de connectivité simple d'abord
|
||||
try {
|
||||
const healthCheck = await apiClient.get('/health');
|
||||
console.log('💚 Backend accessible:', healthCheck.status === 200 ? 'OK' : 'ERREUR');
|
||||
} catch (healthError) {
|
||||
console.warn('⚠️ Backend health check échoué, tentative des endpoints dashboard...', healthError.message);
|
||||
}
|
||||
|
||||
// Charger les données du dashboard depuis l'API - STRICTEMENT depuis le backend
|
||||
const [dashboardStatsResponse, chantiersActifsResponse] = await Promise.allSettled([
|
||||
apiClient.get('/api/v1/dashboard/stats').catch(async (error) => {
|
||||
console.warn('⚠️ /api/v1/dashboard/stats non disponible, fallback vers /api/v1/chantiers');
|
||||
// Si l'endpoint stats n'existe pas, essayer /api/v1/chantiers
|
||||
const chantiers = await apiClient.get('/api/v1/chantiers');
|
||||
const chantiersActifs = chantiers.data.filter(c => c.actif && (c.statut === 'EN_COURS' || c.statut === 'PLANIFIE'));
|
||||
return {
|
||||
data: {
|
||||
totalChantiers: chantiers.data.length,
|
||||
chantiersActifs: chantiersActifs.length,
|
||||
chantiersEnRetard: 0,
|
||||
chantiersTermines: chantiers.data.filter(c => c.statut === 'TERMINE').length,
|
||||
totalEquipes: 0,
|
||||
equipesDisponibles: 0,
|
||||
totalMateriel: 0,
|
||||
materielDisponible: 0,
|
||||
materielEnMaintenance: 0,
|
||||
totalDocuments: 0,
|
||||
totalPhotos: 0,
|
||||
budgetTotal: chantiersActifs.reduce((sum, c) => sum + (c.montantPrevu || 0), 0),
|
||||
coutReel: chantiersActifs.reduce((sum, c) => sum + (c.montantReel || 0), 0),
|
||||
chiffreAffaires: 0,
|
||||
objectifCA: 0,
|
||||
tauxReussite: 0,
|
||||
satisfactionClient: 0
|
||||
}
|
||||
};
|
||||
}),
|
||||
apiClient.get('/api/v1/chantiers').then(response => {
|
||||
const allChantiers = response.data;
|
||||
const chantiersActifs = allChantiers.filter(c => c.actif && (c.statut === 'EN_COURS' || c.statut === 'PLANIFIE'));
|
||||
return { data: chantiersActifs };
|
||||
})
|
||||
// Charger les données depuis les endpoints réels du backend
|
||||
const [dashboardPrincipalResponse, dashboardChantiersResponse] = await Promise.allSettled([
|
||||
apiClient.get<DashboardPrincipalResponse>('/api/v1/dashboard'),
|
||||
apiClient.get<DashboardChantiersResponse>('/api/v1/dashboard/chantiers')
|
||||
]);
|
||||
|
||||
// Extraire les données avec gestion d'erreur
|
||||
const dashboardStats = dashboardStatsResponse.status === 'fulfilled' ? dashboardStatsResponse.value.data : null;
|
||||
const chantiersActifs = chantiersActifsResponse.status === 'fulfilled' ? chantiersActifsResponse.value.data : [];
|
||||
|
||||
// Transformer les données pour correspondre à l'interface attendue - UNIQUEMENT données réelles
|
||||
const metrics = dashboardStats ? {
|
||||
totalChantiers: dashboardStats.totalChantiers || 0,
|
||||
chantiersActifs: chantiersActifs.length || 0,
|
||||
chantiersEnRetard: dashboardStats.chantiersEnRetard || 0,
|
||||
chantiersTermines: dashboardStats.chantiersTermines || 0,
|
||||
totalEquipes: dashboardStats.totalEquipes || 0,
|
||||
equipesDisponibles: dashboardStats.equipesDisponibles || 0,
|
||||
totalMateriel: dashboardStats.totalMateriel || 0,
|
||||
materielDisponible: dashboardStats.materielDisponible || 0,
|
||||
materielEnMaintenance: dashboardStats.materielEnMaintenance || 0,
|
||||
totalDocuments: dashboardStats.totalDocuments || 0,
|
||||
totalPhotos: dashboardStats.totalPhotos || 0,
|
||||
budgetTotal: dashboardStats.budgetTotal || 0,
|
||||
coutReel: dashboardStats.coutReel || 0,
|
||||
chiffreAffaires: dashboardStats.chiffreAffaires || 0,
|
||||
objectifCA: dashboardStats.objectifCA || 0,
|
||||
tauxReussite: dashboardStats.tauxReussite || 0,
|
||||
satisfactionClient: dashboardStats.satisfactionClient || 0
|
||||
} : null;
|
||||
|
||||
// Transformer les chantiers Chantier[] vers ChantierActif[] avec avancement asynchrone
|
||||
const transformedChantiersActifs: ChantierActif[] = await Promise.all(
|
||||
(chantiersActifs as Chantier[]).map(async (chantier) => ({
|
||||
id: chantier.id,
|
||||
nom: chantier.nom,
|
||||
client: typeof chantier.client === 'string' ? chantier.client : chantier.client?.nom || 'Client inconnu',
|
||||
avancement: await calculateAvancement(chantier),
|
||||
dateDebut: chantier.dateDebut,
|
||||
dateFinPrevue: chantier.dateFinPrevue || '',
|
||||
statut: mapStatutChantier(chantier.statut),
|
||||
budget: chantier.montantPrevu || 0,
|
||||
coutReel: chantier.montantReel || 0
|
||||
}))
|
||||
);
|
||||
|
||||
const activitesRecentes = []; // À implémenter avec un endpoint spécifique
|
||||
const tachesUrgentes = []; // À implémenter avec un endpoint spécifique
|
||||
|
||||
// Log des erreurs pour debugging
|
||||
if (dashboardStatsResponse.status === 'rejected') {
|
||||
console.error('❌ Erreur dashboard stats:', dashboardStatsResponse.reason?.message || dashboardStatsResponse.reason);
|
||||
console.error('📡 URL tentée:', 'GET /api/v1/dashboard/stats');
|
||||
// Vérifier les erreurs
|
||||
if (dashboardPrincipalResponse.status === 'rejected') {
|
||||
console.error('❌ Erreur dashboard principal:', dashboardPrincipalResponse.reason);
|
||||
throw new Error('Impossible de charger les métriques du dashboard');
|
||||
}
|
||||
if (chantiersActifsResponse.status === 'rejected') {
|
||||
console.error('❌ Erreur chantiers actifs:', chantiersActifsResponse.reason?.message || chantiersActifsResponse.reason);
|
||||
console.error('📡 URL tentée:', 'GET /api/v1/chantiers/actifs');
|
||||
|
||||
if (dashboardChantiersResponse.status === 'rejected') {
|
||||
console.error('❌ Erreur dashboard chantiers:', dashboardChantiersResponse.reason);
|
||||
throw new Error('Impossible de charger les chantiers actifs');
|
||||
}
|
||||
|
||||
console.log('✅ Dashboard stats:', dashboardStats ? 'Données reçues' : 'Pas de données');
|
||||
console.log('✅ Chantiers actifs:', chantiersActifs ? `${chantiersActifs.length} chantiers` : 'Pas de données');
|
||||
|
||||
const dashboardPrincipal = dashboardPrincipalResponse.value.data;
|
||||
const dashboardChantiers = dashboardChantiersResponse.value.data;
|
||||
|
||||
console.log('✅ Dashboard principal:', dashboardPrincipal);
|
||||
console.log('✅ Dashboard chantiers:', dashboardChantiers);
|
||||
|
||||
// Transformer les données backend vers le format attendu par le frontend
|
||||
const metrics: DashboardMetrics = {
|
||||
totalChantiers: dashboardPrincipal.chantiers.total,
|
||||
chantiersActifs: dashboardPrincipal.chantiers.actifs,
|
||||
chantiersEnRetard: dashboardChantiers.chantiersEnRetard.length,
|
||||
chantiersTermines: (dashboardChantiers.statistiques as any)?.termines || 0,
|
||||
totalEquipes: dashboardPrincipal.equipes.total,
|
||||
equipesDisponibles: dashboardPrincipal.equipes.disponibles,
|
||||
totalMateriel: dashboardPrincipal.materiel.total,
|
||||
materielDisponible: dashboardPrincipal.materiel.disponible,
|
||||
materielEnMaintenance: dashboardPrincipal.maintenance.enRetard + dashboardPrincipal.maintenance.planifiees,
|
||||
totalDocuments: dashboardPrincipal.documents.total,
|
||||
totalPhotos: 0, // TODO: Ajouter au backend si nécessaire
|
||||
budgetTotal: dashboardChantiers.chantiersActifs.reduce((sum, c) => sum + c.budget, 0),
|
||||
coutReel: dashboardChantiers.chantiersActifs.reduce((sum, c) => sum + c.coutReel, 0),
|
||||
chiffreAffaires: dashboardChantiers.chantiersActifs.reduce((sum, c) => sum + c.budget, 0),
|
||||
objectifCA: 0, // TODO: Ajouter au backend si nécessaire
|
||||
tauxReussite: (dashboardChantiers.statistiques as any)?.tauxReussite || 0,
|
||||
satisfactionClient: 0 // TODO: Ajouter au backend si nécessaire
|
||||
};
|
||||
|
||||
// Transformer les chantiers actifs du backend vers le format frontend
|
||||
const chantiersActifs: ChantierActif[] = dashboardChantiers.chantiersActifs.map((chantier: ChantierActifDTO) => ({
|
||||
id: chantier.id,
|
||||
nom: chantier.nom,
|
||||
client: chantier.client,
|
||||
avancement: chantier.avancement,
|
||||
dateDebut: chantier.dateDebut,
|
||||
dateFinPrevue: chantier.dateFinPrevue,
|
||||
statut: mapStatutFromBackend(chantier.statut),
|
||||
budget: chantier.budget,
|
||||
coutReel: chantier.coutReel
|
||||
}));
|
||||
|
||||
// Activités récentes et tâches urgentes - À implémenter avec des endpoints dédiés
|
||||
const activitesRecentes: ActiviteRecente[] = [];
|
||||
const tachesUrgentes: TacheUrgente[] = [];
|
||||
|
||||
console.log('✅ Données transformées:', {
|
||||
metrics,
|
||||
chantiersActifs: chantiersActifs.length,
|
||||
activitesRecentes: activitesRecentes.length,
|
||||
tachesUrgentes: tachesUrgentes.length
|
||||
});
|
||||
|
||||
setData({
|
||||
metrics,
|
||||
chantiersActifs: transformedChantiersActifs,
|
||||
chantiersActifs,
|
||||
activitesRecentes,
|
||||
tachesUrgentes,
|
||||
loading: false,
|
||||
error: null,
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
console.error('💥 Erreur lors du chargement du dashboard:', error);
|
||||
|
||||
const errorMessage = error.response?.status === 404
|
||||
? 'Endpoints du dashboard non trouvés. Vérifiez que le backend est à jour.'
|
||||
: error.response?.status === 401
|
||||
? 'Non authentifié. Veuillez vous reconnecter.'
|
||||
: error.response?.status === 500
|
||||
? 'Erreur serveur. Vérifiez les logs du backend.'
|
||||
: 'Erreur de communication avec le serveur. Vérifiez que le backend est démarré sur http://localhost:8080';
|
||||
|
||||
setData(prev => ({
|
||||
...prev,
|
||||
loading: false,
|
||||
error: 'Erreur de communication avec le serveur. Vérifiez que le backend est démarré sur http://localhost:8080',
|
||||
error: errorMessage,
|
||||
}));
|
||||
}
|
||||
}, [currentPeriode]);
|
||||
@@ -245,24 +172,23 @@ export const useDashboard = (periode: 'semaine' | 'mois' | 'trimestre' | 'annee'
|
||||
|
||||
if (hasAuthCode && !hasTokens) {
|
||||
console.log('📊 Dashboard Hook: Attente de la fin du traitement d\'authentification...');
|
||||
// Attendre un peu puis réessayer (délai réduit)
|
||||
const timer = setTimeout(() => {
|
||||
if (!abortController.signal.aborted) {
|
||||
console.log('📊 Dashboard Hook: Retry après authentification...');
|
||||
loadDashboardData(abortController);
|
||||
}
|
||||
}, 3000); // Attendre 3 secondes pour que l'auth se termine
|
||||
// NE PAS charger les données tant que l'authentification n'est pas terminée
|
||||
// La page dashboard appellera refresh() une fois l'authentification terminée
|
||||
console.log('📊 Dashboard Hook: Chargement différé en attente de l\'authentification');
|
||||
|
||||
return () => {
|
||||
clearTimeout(timer);
|
||||
abortController.abort();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Charger par défaut
|
||||
console.log('📊 Dashboard Hook: Chargement par défaut...');
|
||||
loadDashboardData(abortController);
|
||||
// Charger par défaut seulement si on n'est pas en train de s'authentifier
|
||||
if (typeof window === 'undefined' || !window.location.href.includes('code=')) {
|
||||
console.log('📊 Dashboard Hook: Chargement par défaut...');
|
||||
loadDashboardData(abortController);
|
||||
} else {
|
||||
console.log('📊 Dashboard Hook: Chargement différé (code d\'autorisation détecté)');
|
||||
}
|
||||
|
||||
return () => abortController.abort();
|
||||
}, [loadDashboardData]);
|
||||
@@ -286,49 +212,18 @@ export const useDashboard = (periode: 'semaine' | 'mois' | 'trimestre' | 'annee'
|
||||
};
|
||||
};
|
||||
|
||||
// Fonctions utilitaires pour transformer les données
|
||||
async function calculateAvancement(chantier: Chantier): Promise<number> {
|
||||
if (chantier.statut === 'TERMINE') return 100;
|
||||
if (chantier.statut === 'ANNULE') return 0;
|
||||
|
||||
try {
|
||||
// Essayer d'obtenir l'avancement granulaire basé sur les tâches
|
||||
const avancementGranulaire = await apiClient.get(`/chantiers/${chantier.id}/avancement-granulaire`);
|
||||
if (avancementGranulaire.data && typeof avancementGranulaire.data.pourcentage === 'number') {
|
||||
return Math.round(avancementGranulaire.data.pourcentage);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Avancement granulaire non disponible, utilisation du calcul temporel:', error);
|
||||
}
|
||||
|
||||
// Fallback : calcul basé sur les dates (ancien système)
|
||||
if (!chantier.dateDebut || !chantier.dateFinPrevue) {
|
||||
return chantier.statut === 'EN_COURS' ? 25 : 0;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
const start = new Date(chantier.dateDebut);
|
||||
const end = new Date(chantier.dateFinPrevue);
|
||||
|
||||
if (now < start) return 0;
|
||||
if (now > end) return 100;
|
||||
|
||||
const totalDays = (end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24);
|
||||
const elapsedDays = (now.getTime() - start.getTime()) / (1000 * 60 * 60 * 24);
|
||||
|
||||
const calculatedProgress = Math.min(Math.max((elapsedDays / totalDays) * 100, 0), 100);
|
||||
|
||||
return Math.round(calculatedProgress);
|
||||
}
|
||||
|
||||
function mapStatutChantier(statut: string): 'EN_COURS' | 'EN_RETARD' | 'PLANIFIE' | 'TERMINE' {
|
||||
// Fonctions utilitaires pour transformer les données backend
|
||||
function mapStatutFromBackend(statut: string): 'EN_COURS' | 'EN_RETARD' | 'PLANIFIE' | 'TERMINE' {
|
||||
switch (statut) {
|
||||
case 'EN_COURS': return 'EN_COURS';
|
||||
case 'PLANIFIE': return 'PLANIFIE';
|
||||
case 'TERMINE': return 'TERMINE';
|
||||
case 'EN_RETARD': return 'EN_RETARD';
|
||||
// Si le statut backend n'est pas reconnu, essayer de déterminer s'il est en retard
|
||||
default: return 'EN_COURS';
|
||||
case 'SUSPENDU': return 'EN_COURS'; // Mapper SUSPENDU vers EN_COURS pour l'affichage
|
||||
case 'ANNULE': return 'TERMINE'; // Mapper ANNULE vers TERMINE pour l'affichage
|
||||
default:
|
||||
console.warn(`Statut inconnu reçu du backend: ${statut}`);
|
||||
return 'EN_COURS';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user