'use client'; export const dynamic = 'force-dynamic'; import React, { useState, useEffect, useRef } from 'react'; import { Calendar } from 'primereact/calendar'; import { Card } from 'primereact/card'; import { Button } from 'primereact/button'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Toast } from 'primereact/toast'; import { Tag } from 'primereact/tag'; import { Toolbar } from 'primereact/toolbar'; import { InputText } from 'primereact/inputtext'; import { Dropdown } from 'primereact/dropdown'; import { Dialog } from 'primereact/dialog'; import { Timeline } from 'primereact/timeline'; import { chantierService } from '../../../services/api'; import { formatDate } from '../../../utils/formatters'; import type { Chantier } from '../../../types/btp'; interface PlanningEvent { id: string; title: string; date: Date; type: 'debut' | 'fin' | 'milestone'; chantier: Chantier; status: string; } const PlanningPage = () => { const [chantiers, setChantiers] = useState([]); const [selectedDate, setSelectedDate] = useState(new Date()); const [planningEvents, setPlanningEvents] = useState([]); const [loading, setLoading] = useState(true); const [globalFilter, setGlobalFilter] = useState(''); const [viewMode, setViewMode] = useState<'calendar' | 'table' | 'timeline'>('calendar'); const [filteredChantiers, setFilteredChantiers] = useState([]); const [eventDialog, setEventDialog] = useState(false); const [selectedEvent, setSelectedEvent] = useState(null); const toast = useRef(null); const viewModeOptions = [ { label: 'Calendrier', value: 'calendar' }, { label: 'Tableau', value: 'table' }, { label: 'Timeline', value: 'timeline' } ]; const statutOptions = [ { label: 'Tous', value: '' }, { label: 'Planifié', value: 'PLANIFIE' }, { label: 'En cours', value: 'EN_COURS' }, { label: 'Terminé', value: 'TERMINE' }, { label: 'Suspendu', value: 'SUSPENDU' } ]; useEffect(() => { loadChantiers(); }, []); useEffect(() => { generatePlanningEvents(); }, [chantiers, selectedDate]); const loadChantiers = async () => { try { setLoading(true); const data = await chantierService.getAll(); setChantiers(data); setFilteredChantiers(data); } catch (error) { console.error('Erreur lors du chargement des chantiers:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les chantiers', life: 3000 }); } finally { setLoading(false); } }; const generatePlanningEvents = () => { const events: PlanningEvent[] = []; chantiers.forEach(chantier => { // Événement de début events.push({ id: `${chantier.id}-debut`, title: `Début: ${chantier.nom}`, date: new Date(chantier.dateDebut), type: 'debut', chantier, status: chantier.statut }); // Événement de fin prévue if (chantier.dateFinPrevue) { events.push({ id: `${chantier.id}-fin-prevue`, title: `Fin prévue: ${chantier.nom}`, date: new Date(chantier.dateFinPrevue), type: 'fin', chantier, status: chantier.statut }); } // Événement de fin réelle if (chantier.dateFinReelle) { events.push({ id: `${chantier.id}-fin-reelle`, title: `Fin réelle: ${chantier.nom}`, date: new Date(chantier.dateFinReelle), type: 'fin', chantier, status: chantier.statut }); } }); setPlanningEvents(events.sort((a, b) => a.date.getTime() - b.date.getTime())); }; const filterChantiersForDate = (date: Date) => { return chantiers.filter(chantier => { const dateDebut = new Date(chantier.dateDebut); const dateFin = chantier.dateFinPrevue ? new Date(chantier.dateFinPrevue) : new Date(); return date >= dateDebut && date <= dateFin; }); }; const getEventsForDate = (date: Date) => { return planningEvents.filter(event => { const eventDate = new Date(event.date); return eventDate.toDateString() === date.toDateString(); }); }; const onDateSelect = (e: any) => { setSelectedDate(e.value); const chantiersForDate = filterChantiersForDate(e.value); setFilteredChantiers(chantiersForDate); }; const onViewModeChange = (e: any) => { setViewMode(e.value); }; const onEventClick = (event: PlanningEvent) => { setSelectedEvent(event); setEventDialog(true); }; const hideEventDialog = () => { setEventDialog(false); setSelectedEvent(null); }; const statusBodyTemplate = (rowData: Chantier) => { const getSeverity = (status: string) => { switch (status) { case 'PLANIFIE': return 'info'; case 'EN_COURS': return 'success'; case 'TERMINE': return 'secondary'; case 'ANNULE': return 'danger'; case 'SUSPENDU': return 'warning'; default: return 'info'; } }; const getLabel = (status: string) => { switch (status) { case 'PLANIFIE': return 'Planifié'; case 'EN_COURS': return 'En cours'; case 'TERMINE': return 'Terminé'; case 'ANNULE': return 'Annulé'; case 'SUSPENDU': return 'Suspendu'; default: return status; } }; return ( ); }; const dateBodyTemplate = (rowData: Chantier, field: string) => { const date = (rowData as any)[field]; return date ? formatDate(date) : ''; }; const clientBodyTemplate = (rowData: Chantier) => { if (!rowData.client) return ''; return `${rowData.client.prenom} ${rowData.client.nom}`; }; const dureeBodyTemplate = (rowData: Chantier) => { if (!rowData.dateFinPrevue) return ''; const debut = new Date(rowData.dateDebut); const fin = new Date(rowData.dateFinPrevue); const diffTime = fin.getTime() - debut.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); return `${diffDays} jours`; }; const timelineTemplate = (item: PlanningEvent) => { return (
{item.chantier.nom}
{item.chantier.client ? `${item.chantier.client.prenom} ${item.chantier.client.nom}` : 'Client non défini'}
{formatDate(item.date)}
); }; const leftToolbarTemplate = () => { return (
); }; const rightToolbarTemplate = () => { return (
setGlobalFilter(e.currentTarget.value)} />
); }; const header = (
Planning des Chantiers
); const eventDialogFooter = (