'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 { Dialog } from 'primereact/dialog'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { Tag } from 'primereact/tag'; import { ProgressBar } from 'primereact/progressbar'; import { Dropdown } from 'primereact/dropdown'; import { Calendar } from 'primereact/calendar'; import { InputTextarea } from 'primereact/inputtextarea'; import { InputNumber } from 'primereact/inputnumber'; import phaseService from '../../../services/phaseService'; import chantierService from '../../../services/chantierService'; import clientService from '../../../services/clientService'; import { PhaseChantier } from '../../../types/btp-extended'; import type { Chantier } from '../../../types/btp'; import { ActionButtonGroup, ViewButton, EditButton, DeleteButton, ActionButton } from '../../../components/ui/ActionButton'; import RoleProtectedPage from '@/components/RoleProtectedPage'; const ChantiersPageContent = () => { const [chantiers, setChantiers] = useState([]); const [clients, setClients] = useState([]); const [loading, setLoading] = useState(true); const [globalFilter, setGlobalFilter] = useState(''); const [selectedChantiers, setSelectedChantiers] = useState([]); const [chantierDialog, setChantierDialog] = useState(false); const [deleteChantierDialog, setDeleteChantierDialog] = useState(false); const [permanentDelete, setPermanentDelete] = useState(false); const [deleteChantierssDialog, setDeleteChantierssDialog] = useState(false); const [phasesDialog, setPhasesDialog] = useState(false); const [selectedChantierPhases, setSelectedChantierPhases] = useState([]); const [currentChantier, setCurrentChantier] = useState(null); const [chantier, setChantier] = useState({ id: '', nom: '', description: '', adresse: '', dateDebut: new Date(), dateFinPrevue: new Date(), dateFinReelle: null, statut: 'PLANIFIE', montantPrevu: 0, montantReel: 0, actif: true, client: null }); const [submitted, setSubmitted] = useState(false); const toast = useRef(null); const dt = useRef>(null); const statuts = [ { label: 'Planifié', value: 'PLANIFIE' }, { label: 'En cours', value: 'EN_COURS' }, { label: 'Terminé', value: 'TERMINE' }, { label: 'Annulé', value: 'ANNULE' }, { label: 'Suspendu', value: 'SUSPENDU' } ]; // États workflow BTP const workflowTransitions = { 'PLANIFIE': ['EN_COURS', 'ANNULE'], 'EN_COURS': ['TERMINE', 'SUSPENDU', 'ANNULE'], 'SUSPENDU': ['EN_COURS', 'ANNULE'], 'TERMINE': [], // Statut final 'ANNULE': [] // Statut final }; useEffect(() => { loadChantiers(); loadClients(); }, []); const loadChantiers = async () => { try { setLoading(true); const data = await chantierService.getAll(); setChantiers(data); } catch (error: any) { const errorMessage = error?.userMessage || error?.message || 'Impossible de charger les chantiers'; toast.current?.show({ severity: 'error', summary: 'Erreur de chargement', detail: errorMessage, life: 5000 }); } finally { setLoading(false); } }; const loadClients = async () => { try { const data = await clientService.getAll(); setClients(data.map(client => ({ label: `${client.prenom} ${client.nom}${client.entreprise ? ' - ' + client.entreprise : ''}`, value: client.id, client: client }))); } catch (error) { console.warn('Erreur lors du chargement des clients:', error); } }; const openNew = () => { setChantier({ id: '', nom: '', description: '', adresse: '', dateDebut: new Date(), dateFinPrevue: new Date(), dateFinReelle: null, statut: 'PLANIFIE', montantPrevu: 0, montantReel: 0, actif: true, client: null }); setSubmitted(false); setChantierDialog(true); }; const hideDialog = () => { setSubmitted(false); setChantierDialog(false); }; const hideDeleteChantierDialog = () => { setDeleteChantierDialog(false); }; const hideDeleteChantierssDialog = () => { setDeleteChantierssDialog(false); }; const saveChantier = async () => { setSubmitted(true); if (chantier.nom.trim() && chantier.client && chantier.adresse.trim()) { try { let updatedChantiers = [...chantiers]; // Préparer les données pour l'envoi const chantierToSave: any = { nom: chantier.nom.trim(), description: chantier.description || '', adresse: chantier.adresse.trim(), dateDebut: chantier.dateDebut instanceof Date ? chantier.dateDebut.toISOString().split('T')[0] : chantier.dateDebut, dateFinPrevue: chantier.dateFinPrevue instanceof Date ? chantier.dateFinPrevue.toISOString().split('T')[0] : chantier.dateFinPrevue, statut: chantier.statut, montantPrevu: Number(chantier.montantPrevu) || 0, montantReel: Number(chantier.montantReel) || 0, actif: chantier.actif !== undefined ? chantier.actif : true, clientId: chantier.client // Envoyer l'ID du client directement }; // Ajouter dateFinReelle seulement si elle existe if (chantier.dateFinReelle) { chantierToSave.dateFinReelle = chantier.dateFinReelle instanceof Date ? chantier.dateFinReelle.toISOString().split('T')[0] : chantier.dateFinReelle; } // Ne pas envoyer l'id lors de la création if (chantier.id) { chantierToSave.id = chantier.id; } console.log('Données à envoyer:', chantierToSave); if (chantier.id) { // Mise à jour const updatedChantier = await chantierService.update(chantier.id, chantierToSave); const index = chantiers.findIndex(c => c.id === chantier.id); updatedChantiers[index] = updatedChantier; toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Chantier mis à jour', life: 3000 }); } else { // Créer le nouveau chantier const newChantier = await chantierService.create(chantierToSave); updatedChantiers.push(newChantier); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Chantier créé', life: 3000 }); } setChantiers(updatedChantiers); setChantierDialog(false); setChantier({ id: '', nom: '', description: '', adresse: '', dateDebut: new Date(), dateFinPrevue: new Date(), dateFinReelle: null, statut: 'PLANIFIE', montantPrevu: 0, montantReel: 0, actif: true, client: null }); } catch (error: any) { // Utiliser le message enrichi par l'intercepteur const errorMessage = error?.userMessage || error?.message || 'Impossible de sauvegarder le chantier'; toast.current?.show({ severity: 'error', summary: 'Erreur de sauvegarde', detail: errorMessage, life: 5000 }); } } }; const editChantier = (chantier: Chantier) => { setChantier({ ...chantier, client: chantier.client?.id || null }); setChantierDialog(true); }; const confirmDeleteChantier = (chantier: Chantier, permanent: boolean = false) => { setChantier(chantier); setPermanentDelete(permanent); setDeleteChantierDialog(true); }; const deleteChantier = async () => { try { await chantierService.delete(chantier.id, permanentDelete); let updatedChantiers = chantiers.filter(c => c.id !== chantier.id); setChantiers(updatedChantiers); setDeleteChantierDialog(false); setPermanentDelete(false); toast.current?.show({ severity: 'success', summary: 'Succès', detail: 'Chantier supprimé', life: 3000 }); } catch (error: any) { const errorMessage = error?.userMessage || error?.message || 'Impossible de supprimer le chantier'; const statusCode = error?.statusCode; // Message d'erreur plus détaillé selon le code de statut let detail = errorMessage; if (statusCode === 409) { detail = 'Ce chantier ne peut pas être supprimé (peut-être en cours ou terminé)'; } else if (statusCode === 404) { detail = 'Ce chantier n\'existe plus'; } else if (statusCode === 403) { detail = 'Vous n\'avez pas les droits pour supprimer ce chantier'; } toast.current?.show({ severity: 'error', summary: 'Erreur de suppression', detail: detail, life: 5000 }); } }; const exportCSV = () => { dt.current?.exportCSV(); }; const onInputChange = (e: React.ChangeEvent, name: string) => { const val = (e.target && e.target.value) || ''; let _chantier = { ...chantier }; (_chantier as any)[name] = val; setChantier(_chantier); }; const onDateChange = (e: any, name: string) => { let _chantier = { ...chantier }; (_chantier as any)[name] = e.value; setChantier(_chantier); }; const onNumberChange = (e: any, name: string) => { let _chantier = { ...chantier }; (_chantier as any)[name] = e.value; setChantier(_chantier); }; const onDropdownChange = (e: any, name: string) => { let _chantier = { ...chantier }; (_chantier as any)[name] = e.value; setChantier(_chantier); }; const leftToolbarTemplate = () => { return (
); }; const rightToolbarTemplate = () => { return (