'use client'; export const dynamic = 'force-dynamic'; import React, { useState, useEffect, useRef } from 'react'; import { useRouter } from 'next/navigation'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Button } from 'primereact/button'; import { Card } from 'primereact/card'; import { ProgressBar } from 'primereact/progressbar'; import { Badge } from 'primereact/badge'; import { Toast } from 'primereact/toast'; import { InputText } from 'primereact/inputtext'; import { FilterMatchMode } from 'primereact/api'; import { apiClient } from '../../../../services/api-client'; import { executionGranulaireService } from '../../../../services/executionGranulaireService'; /** * Interface pour les chantiers avec avancement granulaire */ interface ChantierExecutionGranulaire { id: string; nom: string; client: string | { nom: string; prenom?: string }; statut: 'EN_COURS' | 'PLANIFIE' | 'TERMINE' | 'EN_RETARD'; dateDebut: Date; dateFinPrevue: Date; avancementGranulaire?: number; totalTaches: number; tachesTerminees: number; avancementCalcule: boolean; // Si l'avancement est basé sur les tâches ou les dates derniereMAJ?: Date; } /** * Page listant tous les chantiers avec possibilité d'accès à l'exécution granulaire */ const ChantiersExecutionGranulaire = () => { const router = useRouter(); const toast = useRef(null); // États principaux const [chantiers, setChantiers] = useState([]); const [loading, setLoading] = useState(true); const [globalFilterValue, setGlobalFilterValue] = useState(''); const [filters, setFilters] = useState({ global: { value: null, matchMode: FilterMatchMode.CONTAINS } }); useEffect(() => { loadChantiersWithAvancement(); }, []); /** * Charge tous les chantiers avec leur avancement granulaire */ const loadChantiersWithAvancement = async () => { try { setLoading(true); // Charger tous les chantiers actifs const chantiersResponse = await apiClient.get('/chantiers'); const allChantiers = chantiersResponse.data.filter((c: any) => c.actif && (c.statut === 'EN_COURS' || c.statut === 'PLANIFIE') ); // Pour chaque chantier, essayer d'obtenir l'avancement granulaire const chantiersWithAvancement = await Promise.all( allChantiers.map(async (chantier: any) => { let avancementData = null; let avancementCalcule = false; try { // Essayer d'obtenir l'avancement granulaire avancementData = await executionGranulaireService.getAvancementGranulaire(chantier.id); avancementCalcule = true; } catch (error) { // Pas encore d'avancement granulaire, on utilisera un calcul basé sur les dates console.log(`Avancement granulaire non disponible pour ${chantier.nom}`); } return { id: chantier.id, nom: chantier.nom, client: chantier.client?.nom || chantier.client || 'Client non défini', statut: chantier.statut, dateDebut: new Date(chantier.dateDebut), dateFinPrevue: new Date(chantier.dateFinPrevue || Date.now()), avancementGranulaire: avancementData?.pourcentage || calculateDateBasedProgress(chantier), totalTaches: avancementData?.totalTaches || 0, tachesTerminees: avancementData?.tachesTerminees || 0, avancementCalcule, derniereMAJ: avancementData?.derniereMAJ }; }) ); setChantiers(chantiersWithAvancement); } catch (error) { console.error('Erreur lors du chargement des chantiers:', error); showToast('error', 'Erreur', 'Impossible de charger la liste des chantiers'); } finally { setLoading(false); } }; /** * Calcule l'avancement basé sur les dates si pas d'avancement granulaire */ const calculateDateBasedProgress = (chantier: any): number => { if (chantier.statut === 'TERMINE') return 100; if (chantier.statut === 'PLANIFIE') return 0; if (!chantier.dateDebut || !chantier.dateFinPrevue) return 10; 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); return Math.min(Math.max((elapsedDays / totalDays) * 100, 0), 100); }; /** * Affiche un toast message */ const showToast = (severity: 'success' | 'info' | 'warn' | 'error', summary: string, detail: string) => { toast.current?.show({ severity, summary, detail, life: 3000 }); }; /** * Navigue vers la page d'exécution granulaire d'un chantier */ const navigateToExecution = (chantier: ChantierExecutionGranulaire) => { router.push(`/chantiers/${chantier.id}/execution-granulaire`); }; /** * Initialise l'exécution granulaire pour un chantier */ const initialiserExecution = async (chantier: ChantierExecutionGranulaire) => { try { await executionGranulaireService.initialiserExecutionGranulaire(chantier.id); showToast('success', 'Succès', `Exécution granulaire initialisée pour ${chantier.nom}`); await loadChantiersWithAvancement(); // Recharger pour mettre à jour l'état } catch (error) { console.error('Erreur lors de l\'initialisation:', error); showToast('error', 'Erreur', 'Impossible d\'initialiser l\'exécution granulaire'); } }; /** * Gestion du filtre global */ const onGlobalFilterChange = (e: React.ChangeEvent) => { const value = e.target.value; let _filters = { ...filters }; _filters['global'].value = value; setFilters(_filters); setGlobalFilterValue(value); }; /** * Template pour l'affichage du nom du client */ const clientBodyTemplate = (rowData: ChantierExecutionGranulaire) => { if (typeof rowData.client === 'string') { return rowData.client; } return rowData.client?.nom || 'Client inconnu'; }; /** * Template pour l'affichage du statut */ const statutBodyTemplate = (rowData: ChantierExecutionGranulaire) => { const severityMap: Record = { 'EN_COURS': 'info', 'PLANIFIE': 'warning', 'TERMINE': 'success', 'EN_RETARD': 'danger' }; return ; }; /** * Template pour l'affichage de l'avancement */ const avancementBodyTemplate = (rowData: ChantierExecutionGranulaire) => { const progress = Math.round(rowData.avancementGranulaire || 0); return (
{progress}% {!rowData.avancementCalcule && ( )} {rowData.avancementCalcule && ( )}
); }; /** * Template pour l'affichage des tâches */ const tachesBodyTemplate = (rowData: ChantierExecutionGranulaire) => { if (!rowData.avancementCalcule) { return -; } return (
{rowData.tachesTerminees} / {rowData.totalTaches}
tâches terminées
); }; /** * Template pour les actions */ const actionsBodyTemplate = (rowData: ChantierExecutionGranulaire) => { return (
{rowData.avancementCalcule ? (
); }; /** * En-tête du tableau avec filtre de recherche */ const renderHeader = () => { return (
Chantiers - Exécution Granulaire
); }; return (
{/* En-tête de la page */}

Exécution Granulaire des Chantiers

Gérez l'avancement détaillé de vos chantiers avec un suivi granulaire par tâche

{/* Tableau des chantiers */}
rowData.dateDebut.toLocaleDateString('fr-FR')} style={{ width: '120px' }} /> rowData.dateFinPrevue.toLocaleDateString('fr-FR')} style={{ width: '120px' }} />
); }; export default ChantiersExecutionGranulaire;