'use client'; import React, { useState, useEffect, useRef } from 'react'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Button } from 'primereact/button'; import { InputText } from 'primereact/inputtext'; import { Card } from 'primereact/card'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { Tag } from 'primereact/tag'; import { Dialog } from 'primereact/dialog'; import { Calendar } from 'primereact/calendar'; import { InputTextarea } from 'primereact/inputtextarea'; import { ProgressBar } from 'primereact/progressbar'; import { Chip } from 'primereact/chip'; import { chantierService } from '../../../../services/api'; import { formatDate, formatCurrency } from '../../../../utils/formatters'; import type { Chantier } from '../../../../types/btp'; import { ActionButtonGroup, ViewButton, ActionButton } from '../../../../components/ui/ActionButton'; const ChantiersRetardPage = () => { const [chantiers, setChantiers] = useState([]); const [loading, setLoading] = useState(true); const [globalFilter, setGlobalFilter] = useState(''); const [selectedChantiers, setSelectedChantiers] = useState([]); const [actionDialog, setActionDialog] = useState(false); const [selectedChantier, setSelectedChantier] = useState(null); const [actionType, setActionType] = useState<'extend' | 'status'>('extend'); const [newEndDate, setNewEndDate] = useState(null); const [actionNotes, setActionNotes] = useState(''); const toast = useRef(null); const dt = useRef>(null); useEffect(() => { loadChantiers(); }, []); const loadChantiers = async () => { try { setLoading(true); const data = await chantierService.getAll(); // Filtrer les chantiers en retard (planifiés avec date dépassée OU en cours avec date fin prévue dépassée) const chantiersEnRetard = data.filter(chantier => { const today = new Date(); // Chantiers planifiés dont la date de début est dépassée if (chantier.statut === 'PLANIFIE') { const startDate = new Date(chantier.dateDebut); return startDate < today; } // Chantiers en cours dont la date de fin prévue est dépassée if (chantier.statut === 'EN_COURS') { const endDate = new Date(chantier.dateFinPrevue); return endDate < today; } return false; }); setChantiers(chantiersEnRetard); } catch (error) { console.error('Erreur lors du chargement des chantiers:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les chantiers en retard', life: 3000 }); } finally { setLoading(false); } }; const getDelayDays = (chantier: Chantier) => { const today = new Date(); let referenceDate: Date; if (chantier.statut === 'PLANIFIE') { referenceDate = new Date(chantier.dateDebut); } else { referenceDate = new Date(chantier.dateFinPrevue); } const diffTime = today.getTime() - referenceDate.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); return diffDays; }; const getDelaySeverity = (days: number) => { if (days <= 7) return 'warning'; if (days <= 30) return 'danger'; return 'danger'; }; const getPriorityLevel = (days: number) => { if (days <= 3) return { level: 'FAIBLE', color: 'orange' }; if (days <= 15) return { level: 'MOYEN', color: 'red' }; return { level: 'URGENT', color: 'red' }; }; const calculateProgress = (chantier: Chantier) => { if (chantier.statut !== 'EN_COURS' || !chantier.dateDebut || !chantier.dateFinPrevue) return 0; const now = new Date(); const start = new Date(chantier.dateDebut); const end = new Date(chantier.dateFinPrevue); 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), 120); // Peut dépasser 100% si en retard }; const extendDeadline = (chantier: Chantier) => { setSelectedChantier(chantier); setActionType('extend'); setNewEndDate(new Date(chantier.dateFinPrevue)); setActionNotes(''); setActionDialog(true); }; const changeStatus = (chantier: Chantier) => { setSelectedChantier(chantier); setActionType('status'); setActionNotes(''); setActionDialog(true); }; const handleAction = async () => { if (!selectedChantier) return; try { let updatedChantier = { ...selectedChantier }; if (actionType === 'extend' && newEndDate) { updatedChantier.dateFinPrevue = newEndDate.toISOString().split('T')[0]; } else if (actionType === 'status') { updatedChantier.statut = 'SUSPENDU' as any; } await chantierService.update(selectedChantier.id, updatedChantier); // Recharger la liste si le statut a changé if (actionType === 'status') { setChantiers(prev => prev.filter(c => c.id !== selectedChantier.id)); } else { // Mettre à jour le chantier dans la liste setChantiers(prev => prev.map(c => c.id === selectedChantier.id ? updatedChantier : c )); } setActionDialog(false); toast.current?.show({ severity: 'success', summary: 'Succès', detail: actionType === 'extend' ? 'Échéance reportée' : 'Chantier suspendu', life: 3000 }); } catch (error) { console.error('Erreur lors de l\'action:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible d\'effectuer l\'action', life: 3000 }); } }; const exportCSV = () => { dt.current?.exportCSV(); }; const generateAlertReport = () => { const urgentChantiers = chantiers.filter(c => getPriorityLevel(getDelayDays(c)).level === 'URGENT'); const report = ` === ALERTE CHANTIERS EN RETARD === Date du rapport: ${new Date().toLocaleDateString('fr-FR')} CHANTIERS URGENTS (${urgentChantiers.length}): ${urgentChantiers.map(c => ` - ${c.nom} Client: ${c.client ? `${c.client.prenom} ${c.client.nom}` : 'N/A'} Retard: ${getDelayDays(c)} jours Statut: ${c.statut} Budget: ${formatCurrency(c.montantPrevu || 0)} `).join('')} STATISTIQUES: - Total chantiers en retard: ${chantiers.length} - Retard moyen: ${Math.round(chantiers.reduce((sum, c) => sum + getDelayDays(c), 0) / chantiers.length)} jours - Impact budgétaire: ${formatCurrency(chantiers.reduce((sum, c) => sum + (c.montantPrevu || 0), 0))} `; const blob = new Blob([report], { type: 'text/plain;charset=utf-8;' }); const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = `alerte_retards_${new Date().toISOString().split('T')[0]}.txt`; link.click(); toast.current?.show({ severity: 'success', summary: 'Rapport généré', detail: 'Le rapport d\'alerte a été téléchargé', life: 3000 }); }; const leftToolbarTemplate = () => { return (
Chantiers en retard ({chantiers.length})
); }; const rightToolbarTemplate = () => { return (