fix: Update PrimeReact to v10.8.3 and fix all compilation errors

This commit is contained in:
dahoud
2025-10-13 03:01:36 +00:00
parent 2a2e54c0e3
commit 30cad6220b
85 changed files with 928 additions and 2020 deletions

View File

@@ -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';
}
}