/** * Hook personnalisé pour gérer les actions sur les chantiers * Centralise la logique métier et facilite la réutilisation */ import { useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { Toast } from 'primereact/toast'; import { confirmDialog } from 'primereact/confirmdialog'; import { chantierActionsService } from '../services/chantierActionsService'; import { ChantierActif } from './useDashboard'; interface UseChantierActionsProps { toast?: React.RefObject; onRefresh?: () => void; } interface UseChantierActionsReturn { handleQuickView: (chantier: ChantierActif) => void; handleViewStats: (chantier: ChantierActif) => Promise; handleGenerateReport: (chantier: ChantierActif) => Promise; handleExport: (chantier: ChantierActif, format: 'pdf' | 'excel') => Promise; handleToggleSuspend: (chantier: ChantierActif) => void; handleClose: (chantier: ChantierActif) => void; handleArchive: (chantier: ChantierActif) => void; handleMenuAction: (action: string, chantier: ChantierActif) => Promise; // Nouvelles actions prioritaires BTP handleSuspendChantier: (chantier: ChantierActif) => void; handleCloseChantier: (chantier: ChantierActif) => void; handleNotifyClient: (chantier: ChantierActif) => Promise; handleGenerateInvoice: (chantier: ChantierActif) => Promise; handleCreateAmendment: (chantier: ChantierActif) => Promise; } export const useChantierActions = ({ toast, onRefresh }: UseChantierActionsProps = {}): UseChantierActionsReturn => { const router = useRouter(); const showToast = useCallback((severity: 'success' | 'info' | 'warn' | 'error', summary: string, detail: string, life = 3000) => { toast?.current?.show({ severity, summary, detail, life }); }, [toast]); const handleQuickView = useCallback(async (chantier: ChantierActif) => { try { // Pour la vue rapide, on utilise les données déjà disponibles // Si nécessaire, on peut récupérer des détails depuis l'endpoint /chantiers/{id} // Mais pour l'instant, on utilise ce qu'on a déjà console.log('Vue rapide du chantier:', chantier); // Calculer des stats basiques depuis les données existantes const joursEcoules = chantier.dateDebut ? Math.floor((new Date().getTime() - new Date(chantier.dateDebut).getTime()) / (1000 * 60 * 60 * 24)) : 0; const joursRestants = chantier.dateFinPrevue ? Math.floor((new Date(chantier.dateFinPrevue).getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24)) : 0; const tauxDepense = chantier.budget > 0 ? Math.round((chantier.coutReel / chantier.budget) * 100) : 0; // Les données sont déjà passées au composant Dialog, pas besoin d'appel API showToast('info', 'Vue rapide', `Affichage des détails de ${chantier.nom}`); } catch (error) { console.error('Erreur lors de l\'affichage de la vue rapide:', error); showToast('warn', 'Avertissement', 'Détails limités disponibles'); } }, [showToast]); const handleViewStats = useCallback(async (chantier: ChantierActif) => { showToast('info', 'Chargement', 'Chargement des statistiques...', 2000); try { const stats = await chantierActionsService.getChantierStats(chantier.id); router.push(`/chantiers/${chantier.id}#stats`); } catch (error) { showToast('error', 'Erreur', 'Impossible de charger les statistiques'); } }, [router, showToast]); const handleGenerateReport = useCallback(async (chantier: ChantierActif) => { showToast('info', 'Génération en cours', `Génération du rapport pour ${chantier.nom}...`); const result = await chantierActionsService.generateReport(chantier.id); if (result.success) { showToast('success', 'Rapport généré', 'Le rapport a été téléchargé avec succès'); } else { showToast('error', 'Erreur', result.message, 5000); } }, [showToast]); const handleExport = useCallback(async (chantier: ChantierActif, format: 'pdf' | 'excel') => { showToast('info', 'Export en cours', `Export ${format.toUpperCase()} pour ${chantier.nom}...`); const result = await chantierActionsService.exportChantier(chantier.id, format); if (result.success) { showToast('success', 'Export réussi', `Le fichier ${format.toUpperCase()} a été téléchargé`); } else { showToast('error', 'Erreur d\'export', result.message, 5000); } }, [showToast]); const handleToggleSuspend = useCallback((chantier: ChantierActif) => { const isSuspended = chantier.statut === 'SUSPENDU'; const action = isSuspended ? 'reprendre' : 'suspendre'; confirmDialog({ message: `Êtes-vous sûr de vouloir ${action} le chantier "${chantier.nom}" ?`, header: 'Confirmation', icon: 'pi pi-exclamation-triangle', acceptLabel: 'Oui', rejectLabel: 'Non', accept: async () => { const result = await chantierActionsService.toggleSuspend(chantier.id, !isSuspended); if (result.success) { showToast('success', 'Succès', result.message); onRefresh?.(); } else { showToast('error', 'Erreur', result.message, 5000); } } }); }, [showToast, onRefresh]); const handleClose = useCallback((chantier: ChantierActif) => { confirmDialog({ message: `Êtes-vous sûr de vouloir clôturer le chantier "${chantier.nom}" ?\nCette action est irréversible.`, header: 'Clôturer le chantier', icon: 'pi pi-info-circle', acceptClassName: 'p-button-success', acceptLabel: 'Clôturer', rejectLabel: 'Annuler', accept: async () => { const result = await chantierActionsService.closeChantier(chantier.id); if (result.success) { showToast('success', 'Chantier clôturé', result.message); onRefresh?.(); } else { showToast('error', 'Erreur', result.message, 5000); } } }); }, [showToast, onRefresh]); const handleArchive = useCallback((chantier: ChantierActif) => { confirmDialog({ message: `Voulez-vous archiver le chantier "${chantier.nom}" ?\nIl sera déplacé dans les archives.`, header: 'Archiver le chantier', icon: 'pi pi-inbox', acceptLabel: 'Archiver', rejectLabel: 'Annuler', accept: async () => { const result = await chantierActionsService.archiveChantier(chantier.id); if (result.success) { showToast('info', 'Chantier archivé', result.message); onRefresh?.(); } else { showToast('error', 'Erreur', result.message, 5000); } } }); }, [showToast, onRefresh]); const handleMenuAction = useCallback(async (action: string, chantier: ChantierActif) => { switch (action) { case 'details': router.push(`/chantiers/${chantier.id}`); break; case 'documents': router.push(`/documents?chantier=${chantier.id}`); break; case 'photos': router.push(`/photos/par-chantier?id=${chantier.id}`); break; case 'team': router.push(`/equipes?chantier=${chantier.id}`); break; case 'equipment': router.push(`/materiels?chantier=${chantier.id}`); break; case 'report': await handleGenerateReport(chantier); break; case 'export-pdf': await handleExport(chantier, 'pdf'); break; case 'export-excel': await handleExport(chantier, 'excel'); break; case 'toggle-suspend': handleToggleSuspend(chantier); break; case 'close': handleClose(chantier); break; case 'archive': handleArchive(chantier); break; default: console.warn('Action inconnue:', action); } }, [router, handleGenerateReport, handleExport, handleToggleSuspend, handleClose, handleArchive]); // Actions prioritaires BTP const handleSuspendChantier = useCallback((chantier: ChantierActif) => { confirmDialog({ message: `Suspendre temporairement le chantier "${chantier.nom}" ?\nLes équipes seront notifiées.`, header: 'Suspendre le chantier', icon: 'pi pi-pause-circle', acceptClassName: 'p-button-warning p-button-text p-button-rounded', acceptLabel: 'Suspendre', rejectLabel: 'Annuler', accept: async () => { try { const result = await chantierActionsService.suspendChantier(chantier.id); showToast('warn', 'Chantier suspendu', `${chantier.nom} a été suspendu temporairement`); onRefresh?.(); } catch (error) { showToast('error', 'Erreur', 'Impossible de suspendre le chantier'); } } }); }, [showToast, onRefresh]); const handleCloseChantier = useCallback((chantier: ChantierActif) => { confirmDialog({ message: `Clôturer définitivement le chantier "${chantier.nom}" ?\nUn rapport final sera généré.`, header: 'Clôturer le chantier', icon: 'pi pi-check-circle', acceptClassName: 'p-button-success p-button-text p-button-rounded', acceptLabel: 'Clôturer', rejectLabel: 'Annuler', accept: async () => { try { const result = await chantierActionsService.closeChantierDefinitively(chantier.id); showToast('success', 'Chantier clôturé', `${chantier.nom} a été clôturé avec succès`); onRefresh?.(); } catch (error) { showToast('error', 'Erreur', 'Impossible de clôturer le chantier'); } } }); }, [showToast, onRefresh]); const handleNotifyClient = useCallback(async (chantier: ChantierActif) => { try { showToast('info', 'Envoi en cours...', 'Préparation de la notification client'); const result = await chantierActionsService.notifyClient(chantier.id); showToast('success', 'Notification envoyée', `Le client a été informé de l'avancement du chantier ${chantier.nom}`); } catch (error) { showToast('error', 'Erreur', 'Impossible d\'envoyer la notification au client'); } }, [showToast]); const handleGenerateInvoice = useCallback(async (chantier: ChantierActif) => { try { showToast('info', 'Génération...', 'Préparation de la facture intermédiaire'); const result = await chantierActionsService.generateIntermediateInvoice(chantier.id); showToast('success', 'Facture générée', `Facture intermédiaire créée pour ${chantier.nom}`); // Ouvrir la facture dans un nouvel onglet si URL fournie if (result.pdfUrl) { window.open(result.pdfUrl, '_blank'); } } catch (error) { showToast('error', 'Erreur', 'Impossible de générer la facture intermédiaire'); } }, [showToast]); const handleCreateAmendment = useCallback(async (chantier: ChantierActif) => { try { showToast('info', 'Création avenant...', 'Préparation du document d\'avenant'); const result = await chantierActionsService.createAmendment(chantier.id); showToast('success', 'Avenant créé', `Avenant budgétaire créé pour ${chantier.nom}`); // Rediriger vers la page d'édition de l'avenant router.push(`/chantiers/${chantier.id}/avenant/${result.amendmentId}`); } catch (error) { showToast('error', 'Erreur', 'Impossible de créer l\'avenant'); } }, [showToast, router]); return { handleQuickView, handleViewStats, handleGenerateReport, handleExport, handleToggleSuspend, handleClose, handleArchive, handleMenuAction, // Nouvelles actions prioritaires handleSuspendChantier, handleCloseChantier, handleNotifyClient, handleGenerateInvoice, handleCreateAmendment }; };