'use client'; import React, { useState, useEffect } from 'react'; import { Card } from 'primereact/card'; import { Button } from 'primereact/button'; import { Calendar } from 'primereact/calendar'; import { Dropdown } from 'primereact/dropdown'; import { Toolbar } from 'primereact/toolbar'; import { Badge } from 'primereact/badge'; import { Tag } from 'primereact/tag'; import { Dialog } from 'primereact/dialog'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { useRouter } from 'next/navigation'; import { apiClient } from '../../../../services/api-client'; interface EvenementMaintenance { id: number; title: string; start: Date; end?: Date; type: 'PREVENTIVE' | 'CORRECTIVE' | 'PLANIFIEE' | 'URGENTE'; statut: 'PLANIFIEE' | 'EN_COURS' | 'TERMINEE' | 'ANNULEE'; priorite: 'BASSE' | 'NORMALE' | 'HAUTE' | 'CRITIQUE'; materielNom: string; technicienNom?: string; description: string; dureeEstimee: number; color: string; } interface VueCalendrier { date: Date; evenements: EvenementMaintenance[]; conflits: Array<{ technicienId: number; technicienNom: string; maintenances: EvenementMaintenance[]; }>; } const CalendrierMaintenancePage = () => { const [vueCalendrier, setVueCalendrier] = useState({ date: new Date(), evenements: [], conflits: [] }); const [loading, setLoading] = useState(true); const [selectedDate, setSelectedDate] = useState(new Date()); const [filterType, setFilterType] = useState(null); const [filterTechnicien, setFilterTechnicien] = useState(null); const [detailDialog, setDetailDialog] = useState(false); const [selectedEvenement, setSelectedEvenement] = useState(null); const [techniciens, setTechniciens] = useState([]); const [vueMode, setVueMode] = useState<'mois' | 'semaine' | 'jour'>('mois'); const router = useRouter(); const typeOptions = [ { label: 'Tous', value: null }, { label: 'Préventive', value: 'PREVENTIVE' }, { label: 'Corrective', value: 'CORRECTIVE' }, { label: 'Planifiée', value: 'PLANIFIEE' }, { label: 'Urgente', value: 'URGENTE' } ]; const vueModeOptions = [ { label: 'Mois', value: 'mois' }, { label: 'Semaine', value: 'semaine' }, { label: 'Jour', value: 'jour' } ]; useEffect(() => { loadCalendrierMaintenance(); loadTechniciens(); }, [selectedDate, filterType, filterTechnicien, vueMode]); const loadCalendrierMaintenance = async () => { try { setLoading(true); console.log('🔄 Chargement du calendrier de maintenance...'); const params = new URLSearchParams(); params.append('date', selectedDate.toISOString().split('T')[0]); params.append('vue', vueMode); if (filterType) params.append('type', filterType); if (filterTechnicien) params.append('technicienId', filterTechnicien); const response = await apiClient.get(`/api/maintenances/calendrier?${params.toString()}`); console.log('✅ Calendrier chargé:', response.data); // Transformer les données pour le calendrier const evenements = response.data.maintenances?.map((m: any) => ({ ...m, start: new Date(m.datePlanifiee), end: m.dateFin ? new Date(m.dateFin) : new Date(new Date(m.datePlanifiee).getTime() + m.dureeEstimee * 60 * 60 * 1000), title: `${m.materielNom} - ${m.typeMaintenance}`, color: getTypeColor(m.typeMaintenance, m.statut) })) || []; setVueCalendrier({ date: selectedDate, evenements, conflits: response.data.conflits || [] }); } catch (error) { console.error('❌ Erreur lors du chargement du calendrier:', error); setVueCalendrier({ date: selectedDate, evenements: [], conflits: [] }); } finally { setLoading(false); } }; const loadTechniciens = async () => { try { const response = await apiClient.get('/api/employes/techniciens'); setTechniciens(response.data || []); } catch (error) { console.error('❌ Erreur lors du chargement des techniciens:', error); } }; const getTypeColor = (type: string, statut: string) => { if (statut === 'TERMINEE') return '#10b981'; // vert if (statut === 'ANNULEE') return '#6b7280'; // gris switch (type) { case 'PREVENTIVE': return '#3b82f6'; // bleu case 'CORRECTIVE': return '#f59e0b'; // orange case 'PLANIFIEE': return '#8b5cf6'; // violet case 'URGENTE': return '#ef4444'; // rouge default: return '#6b7280'; } }; const getStatutSeverity = (statut: string) => { switch (statut) { case 'PLANIFIEE': return 'info'; case 'EN_COURS': return 'warning'; case 'TERMINEE': return 'success'; case 'ANNULEE': return 'danger'; default: return 'secondary'; } }; const getTypeSeverity = (type: string) => { switch (type) { case 'PREVENTIVE': return 'info'; case 'CORRECTIVE': return 'warning'; case 'PLANIFIEE': return 'success'; case 'URGENTE': return 'danger'; default: return 'secondary'; } }; const ouvrirDetail = (evenement: EvenementMaintenance) => { setSelectedEvenement(evenement); setDetailDialog(true); }; const planifierMaintenance = () => { router.push(`/maintenance/nouveau?date=${selectedDate.toISOString().split('T')[0]}`); }; const resoudreConflit = async (conflitId: number) => { try { await apiClient.post(`/api/maintenances/conflits/${conflitId}/resoudre`); console.log('✅ Conflit résolu'); loadCalendrierMaintenance(); } catch (error) { console.error('❌ Erreur lors de la résolution du conflit:', error); } }; const genererJoursCalendrier = () => { const debut = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), 1); const fin = new Date(selectedDate.getFullYear(), selectedDate.getMonth() + 1, 0); const jours = []; // Ajouter les jours du mois précédent pour compléter la première semaine const premierJourSemaine = debut.getDay(); for (let i = premierJourSemaine - 1; i >= 0; i--) { const jour = new Date(debut); jour.setDate(jour.getDate() - i - 1); jours.push(jour); } // Ajouter tous les jours du mois for (let jour = 1; jour <= fin.getDate(); jour++) { jours.push(new Date(selectedDate.getFullYear(), selectedDate.getMonth(), jour)); } // Ajouter les jours du mois suivant pour compléter la dernière semaine const dernierJourSemaine = fin.getDay(); for (let i = 1; i <= 6 - dernierJourSemaine; i++) { const jour = new Date(fin); jour.setDate(jour.getDate() + i); jours.push(jour); } return jours; }; const getEvenementsJour = (jour: Date) => { return vueCalendrier.evenements.filter(evt => { const dateEvt = new Date(evt.start); return dateEvt.toDateString() === jour.toDateString(); }); }; const leftToolbarTemplate = () => { return (
); }; const rightToolbarTemplate = () => { return (
setVueMode(e.value)} placeholder="Vue" />
); }; const conflitBodyTemplate = (rowData: any) => { return (
); }; return (
{/* Filtres */}
setFilterType(e.value)} placeholder="Tous les types" />
setFilterTechnicien(e.value)} optionLabel="nom" optionValue="id" placeholder="Tous les techniciens" filter />
setSelectedDate(e.value as Date)} showIcon dateFormat="dd/mm/yy" placeholder="Sélectionner une date" />
{/* Calendrier */}
{vueMode === 'mois' && (
{/* En-têtes des jours */} {['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'].map(jour => (
{jour}
))} {/* Jours du calendrier */} {genererJoursCalendrier().map((jour, index) => { const evenementsJour = getEvenementsJour(jour); const estAujourdhui = jour.toDateString() === new Date().toDateString(); const estMoisCourant = jour.getMonth() === selectedDate.getMonth(); return (
setSelectedDate(jour)} >
{jour.getDate()}
{evenementsJour.slice(0, 3).map(evt => (
{ e.stopPropagation(); ouvrirDetail(evt); }} > {evt.title.length > 20 ? `${evt.title.substring(0, 20)}...` : evt.title}
))} {evenementsJour.length > 3 && (
+{evenementsJour.length - 3} autres
)}
); })}
)} {vueMode === 'jour' && (

{selectedDate.toLocaleDateString('fr-FR', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })}

{getEvenementsJour(selectedDate).map(evt => (
ouvrirDetail(evt)} >
{evt.title}
{evt.description}
{evt.start.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })} {evt.end && ` - ${evt.end.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit' })}`}
))} {getEvenementsJour(selectedDate).length === 0 && (
Aucune maintenance planifiée pour cette date
)}
)}
{/* Panneau latéral */}
{/* Conflits */} {vueCalendrier.conflits.length > 0 && ( } /> )} {/* Statistiques */}
Total maintenances:
Urgentes: e.type === 'URGENTE').length} severity="danger" />
Préventives: e.type === 'PREVENTIVE').length} severity="info" />
En cours: e.statut === 'EN_COURS').length} severity="warning" />
Terminées: e.statut === 'TERMINEE').length} severity="success" />
{/* Dialog Détail Événement */} setDetailDialog(false)} footer={
} > {selectedEvenement && (

{selectedEvenement.title}

Matériel: {selectedEvenement.materielNom}

Technicien: {selectedEvenement.technicienNom || 'Non assigné'}

Date: {selectedEvenement.start.toLocaleDateString('fr-FR')}

Durée estimée: {selectedEvenement.dureeEstimee}h

Description: {selectedEvenement.description}

)}
); }; export default CalendrierMaintenancePage;