'use client'; export const dynamic = 'force-dynamic'; import React, { useState, useEffect, useRef } from 'react'; import { Card } from 'primereact/card'; import { Chart } from 'primereact/chart'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Tag } from 'primereact/tag'; import { Button } from 'primereact/button'; import { Toast } from 'primereact/toast'; import { Calendar } from 'primereact/calendar'; import { Badge } from 'primereact/badge'; import { Timeline } from 'primereact/timeline'; import { ProgressBar } from 'primereact/progressbar'; import { Divider } from 'primereact/divider'; import { Panel } from 'primereact/panel'; import { useRouter } from 'next/navigation'; interface ResumeQuotidien { date: Date; chantiers: { actifs: number; nouveaux: number; termines: number; retards: number; }; employes: { presents: number; absents: number; enMission: number; disponibles: number; }; materiels: { utilises: number; disponibles: number; enMaintenance: number; horsService: number; }; finances: { chiffreAffaires: number; depenses: number; benefice: number; facturesEmises: number; }; alertes: { critiques: number; elevees: number; moyennes: number; total: number; }; evenements: EvenementQuotidien[]; objectifs: ObjectifQuotidien[]; } interface EvenementQuotidien { id: string; heure: string; type: string; titre: string; description: string; statut: string; importance: string; } interface ObjectifQuotidien { id: string; titre: string; description: string; progression: number; echeance: Date; responsable: string; statut: string; } const DashboardResumeQuotidien = () => { const toast = useRef(null); const router = useRouter(); const [resume, setResume] = useState(null); const [loading, setLoading] = useState(true); const [selectedDate, setSelectedDate] = useState(new Date()); const [chartData, setChartData] = useState({}); const [chartOptions, setChartOptions] = useState({}); useEffect(() => { loadResumeQuotidien(); initCharts(); }, [selectedDate]); const loadResumeQuotidien = async () => { try { setLoading(true); // TODO: Remplacer par un vrai appel API // const response = await dashboardService.getResumeQuotidien(selectedDate); // Données simulées pour la démonstration const mockResume: ResumeQuotidien = { date: selectedDate, chantiers: { actifs: 8, nouveaux: 2, termines: 1, retards: 3 }, employes: { presents: 45, absents: 5, enMission: 38, disponibles: 7 }, materiels: { utilises: 28, disponibles: 12, enMaintenance: 4, horsService: 2 }, finances: { chiffreAffaires: 125000, depenses: 89000, benefice: 36000, facturesEmises: 8 }, alertes: { critiques: 2, elevees: 5, moyennes: 12, total: 19 }, evenements: [ { id: '1', heure: '08:00', type: 'REUNION', titre: 'Briefing équipe Résidence Les Jardins', description: 'Point sécurité et planning de la journée', statut: 'TERMINE', importance: 'HAUTE' }, { id: '2', heure: '09:30', type: 'LIVRAISON', titre: 'Réception matériaux Centre Commercial', description: 'Livraison acier pour structure', statut: 'EN_COURS', importance: 'HAUTE' }, { id: '3', heure: '11:00', type: 'MAINTENANCE', titre: 'Révision pelleteuse CAT 320D', description: 'Maintenance préventive système hydraulique', statut: 'PLANIFIE', importance: 'MOYENNE' }, { id: '4', heure: '14:00', titre: 'Coulage dalle béton', type: 'CHANTIER', description: 'Coulage niveau R+1 Résidence Les Jardins', statut: 'PLANIFIE', importance: 'HAUTE' }, { id: '5', heure: '16:30', type: 'REUNION', titre: 'Point client Hôtel Luxe', description: 'Validation avancement travaux', statut: 'PLANIFIE', importance: 'MOYENNE' } ], objectifs: [ { id: '1', titre: 'Finaliser gros œuvre Résidence', description: 'Terminer le gros œuvre du bâtiment A', progression: 85, echeance: new Date('2025-01-15'), responsable: 'Jean Dupont', statut: 'EN_COURS' }, { id: '2', titre: 'Livraison Centre Commercial', description: 'Respecter la date de livraison prévue', progression: 60, echeance: new Date('2025-02-28'), responsable: 'Marie Martin', statut: 'EN_COURS' }, { id: '3', titre: 'Formation équipe sécurité', description: 'Former 100% de l\'équipe aux nouvelles normes', progression: 40, echeance: new Date('2025-01-31'), responsable: 'Pierre Leroy', statut: 'EN_COURS' } ] }; setResume(mockResume); } catch (error) { console.error('Erreur lors du chargement du résumé quotidien:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger le résumé quotidien' }); } finally { setLoading(false); } }; const initCharts = () => { if (!resume) return; const documentStyle = getComputedStyle(document.documentElement); // Graphique de répartition des chantiers const chantiersData = { labels: ['Actifs', 'Nouveaux', 'Terminés', 'En retard'], datasets: [ { data: [ resume.chantiers.actifs, resume.chantiers.nouveaux, resume.chantiers.termines, resume.chantiers.retards ], backgroundColor: [ documentStyle.getPropertyValue('--green-500'), documentStyle.getPropertyValue('--blue-500'), documentStyle.getPropertyValue('--purple-500'), documentStyle.getPropertyValue('--red-500') ] } ] }; const options = { plugins: { legend: { labels: { usePointStyle: true, color: documentStyle.getPropertyValue('--text-color') } } } }; setChartData(chantiersData); setChartOptions(options); }; const getEvenementIcon = (type: string) => { switch (type) { case 'REUNION': return 'pi pi-users'; case 'LIVRAISON': return 'pi pi-truck'; case 'MAINTENANCE': return 'pi pi-wrench'; case 'CHANTIER': return 'pi pi-building'; default: return 'pi pi-calendar'; } }; const getEvenementColor = (importance: string) => { switch (importance) { case 'HAUTE': return '#dc2626'; case 'MOYENNE': return '#d97706'; case 'BASSE': return '#059669'; default: return '#6b7280'; } }; const getStatutSeverity = (statut: string) => { switch (statut) { case 'TERMINE': return 'success'; case 'EN_COURS': return 'warning'; case 'PLANIFIE': return 'info'; case 'ANNULE': return 'danger'; default: return 'secondary'; } }; const evenementStatutTemplate = (rowData: EvenementQuotidien) => ( ); const evenementTypeTemplate = (rowData: EvenementQuotidien) => (
{rowData.type}
); const objectifProgressionTemplate = (rowData: ObjectifQuotidien) => (
{rowData.progression}%
); const objectifEcheanceTemplate = (rowData: ObjectifQuotidien) => { const now = new Date(); const echeance = rowData.echeance; const diffDays = Math.ceil((echeance.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)); let severity = 'info'; if (diffDays < 0) severity = 'danger'; else if (diffDays < 7) severity = 'warning'; else if (diffDays < 30) severity = 'info'; return (
{echeance.toLocaleDateString('fr-FR')}
); }; if (!resume) { return
Chargement...
; } return (
{/* En-tête avec sélection de date */}

Résumé Quotidien

setSelectedDate(e.value as Date)} dateFormat="dd/mm/yy" showIcon placeholder="Sélectionner une date" />

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

{/* Métriques principales */}
Chantiers Actifs
{resume.chantiers.actifs}
{resume.chantiers.nouveaux} nouveaux, {resume.chantiers.retards} en retard
Employés Présents
{resume.employes.presents}
{resume.employes.enMission} en mission, {resume.employes.disponibles} disponibles
Matériels Utilisés
{resume.materiels.utilises}
{resume.materiels.disponibles} disponibles, {resume.materiels.enMaintenance} en maintenance
CA du Jour
{new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', notation: 'compact' }).format(resume.finances.chiffreAffaires)}
Bénéfice: {new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', notation: 'compact' }).format(resume.finances.benefice)}
{/* Alertes du jour */} {resume.alertes.total > 0 && (
Alertes du Jour
{resume.alertes.critiques}
Critiques
{resume.alertes.elevees}
Élevées
{resume.alertes.moyennes}
Moyennes
)} {/* Graphique et indicateurs */}
Répartition des Chantiers
Indicateurs Financiers
{new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', notation: 'compact' }).format(resume.finances.chiffreAffaires)}
Chiffre d'affaires
{new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', notation: 'compact' }).format(resume.finances.depenses)}
Dépenses
{new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', notation: 'compact' }).format(resume.finances.benefice)}
Bénéfice
{resume.finances.facturesEmises}
Factures émises
{/* Planning de la journée */}
Planning de la Journée
{/* Objectifs en cours */}
Objectifs en Cours
{resume.objectifs.map((objectif, index) => (

{objectif.description}

Progression {objectif.progression}%
Responsable: {objectif.responsable} Échéance: {objectif.echeance.toLocaleDateString('fr-FR')}
))}
{/* Actions rapides */}
Actions Rapides
); }; export default DashboardResumeQuotidien;