Initial commit
This commit is contained in:
299
hooks/useChantierActions.ts
Normal file
299
hooks/useChantierActions.ts
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* 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<Toast>;
|
||||
onRefresh?: () => void;
|
||||
}
|
||||
|
||||
interface UseChantierActionsReturn {
|
||||
handleQuickView: (chantier: ChantierActif) => void;
|
||||
handleViewStats: (chantier: ChantierActif) => Promise<void>;
|
||||
handleGenerateReport: (chantier: ChantierActif) => Promise<void>;
|
||||
handleExport: (chantier: ChantierActif, format: 'pdf' | 'excel') => Promise<void>;
|
||||
handleToggleSuspend: (chantier: ChantierActif) => void;
|
||||
handleClose: (chantier: ChantierActif) => void;
|
||||
handleArchive: (chantier: ChantierActif) => void;
|
||||
handleMenuAction: (action: string, chantier: ChantierActif) => Promise<void>;
|
||||
// Nouvelles actions prioritaires BTP
|
||||
handleSuspendChantier: (chantier: ChantierActif) => void;
|
||||
handleCloseChantier: (chantier: ChantierActif) => void;
|
||||
handleNotifyClient: (chantier: ChantierActif) => Promise<void>;
|
||||
handleGenerateInvoice: (chantier: ChantierActif) => Promise<void>;
|
||||
handleCreateAmendment: (chantier: ChantierActif) => Promise<void>;
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user