'use client'; export const dynamic = 'force-dynamic'; import React, { useState, useEffect, useRef } from 'react'; import { Card } from 'primereact/card'; import { Button } from 'primereact/button'; import { Calendar } from 'primereact/calendar'; import { Chart } from 'primereact/chart'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { Dropdown } from 'primereact/dropdown'; import { TabView, TabPanel } from 'primereact/tabview'; import { Knob } from 'primereact/knob'; import { ProgressBar } from 'primereact/progressbar'; import { Badge } from 'primereact/badge'; import { chantierService, clientService, factureService, devisService } from '../../../services/api'; import { formatCurrency, formatDate } from '../../../utils/formatters'; import type { Chantier, Client, Facture, Devis } from '../../../types/btp'; import { StatutChantier } from '../../../types/btp'; interface ReportData { chantiers: Chantier[]; clients: Client[]; factures: Facture[]; devis: Devis[]; } interface ChantierStats { total: number; planifies: number; enCours: number; termines: number; annules: number; enRetard: number; } interface FinancialStats { chiffreAffaires: number; benefices: number; facturesEnAttente: number; devisEnAttente: number; tauxReussite: number; } const RapportsPage = () => { const [reportData, setReportData] = useState({ chantiers: [], clients: [], factures: [], devis: [] }); const [loading, setLoading] = useState(true); const [dateDebut, setDateDebut] = useState(new Date(new Date().getFullYear(), 0, 1)); const [dateFin, setDateFin] = useState(new Date()); const [selectedPeriod, setSelectedPeriod] = useState('annee'); const [activeIndex, setActiveIndex] = useState(0); const [chantierStats, setChantierStats] = useState({ total: 0, planifies: 0, enCours: 0, termines: 0, annules: 0, enRetard: 0 }); const [financialStats, setFinancialStats] = useState({ chiffreAffaires: 0, benefices: 0, facturesEnAttente: 0, devisEnAttente: 0, tauxReussite: 0 }); const [chartData, setChartData] = useState({}); const [chartOptions, setChartOptions] = useState({}); const toast = useRef(null); const periodOptions = [ { label: 'Cette semaine', value: 'semaine' }, { label: 'Ce mois', value: 'mois' }, { label: 'Ce trimestre', value: 'trimestre' }, { label: 'Cette année', value: 'annee' }, { label: 'Personnalisé', value: 'custom' } ]; useEffect(() => { loadReportData(); }, [dateDebut, dateFin]); useEffect(() => { calculateStats(); generateChartData(); }, [reportData]); const loadReportData = async () => { try { setLoading(true); // Simuler des données de rapport const mockChantiers: Chantier[] = [ { id: '1', nom: 'Résidence Les Palmiers', description: 'Construction de 20 appartements', adresse: '123 Rue des Palmiers, Abidjan', dateDebut: '2024-01-15', dateFinPrevue: '2024-06-15', dateFinReelle: '2024-06-20', statut: StatutChantier.TERMINE, montantPrevu: 850000, montantReel: 820000, dateCreation: '2024-01-01', dateModification: '2024-06-20', actif: true, client: { id: '1', nom: 'Kouassi', prenom: 'Jean', email: 'jean.kouassi@email.com', telephone: '07 12 34 56 78', adresse: '456 Rue de la Paix', codePostal: '00225', ville: 'Abidjan', entreprise: 'Entreprise Kouassi', dateCreation: '2024-01-01', dateModification: '2024-01-01', actif: true } }, { id: '2', nom: 'Immeuble Commercial', description: 'Bureaux commerciaux', adresse: '789 Boulevard Principal, Abidjan', dateDebut: '2024-03-01', dateFinPrevue: '2024-12-31', dateFinReelle: null, statut: StatutChantier.EN_COURS, montantPrevu: 1200000, montantReel: 600000, dateCreation: '2024-02-01', dateModification: '2024-10-15', actif: true, client: { id: '2', nom: 'Traoré', prenom: 'Fatou', email: 'fatou.traore@email.com', telephone: '07 98 76 54 32', adresse: '321 Avenue du Commerce', codePostal: '00225', ville: 'Abidjan', entreprise: 'Traoré SARL', dateCreation: '2024-02-01', dateModification: '2024-02-01', actif: true } } ]; setReportData({ chantiers: mockChantiers, clients: [], factures: [], devis: [] }); } catch (error) { console.error('Erreur lors du chargement des données:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les données', life: 3000 }); } finally { setLoading(false); } }; const calculateStats = () => { const { chantiers } = reportData; const stats: ChantierStats = { total: chantiers.length, planifies: chantiers.filter(c => c.statut === 'PLANIFIE').length, enCours: chantiers.filter(c => c.statut === 'EN_COURS').length, termines: chantiers.filter(c => c.statut === 'TERMINE').length, annules: chantiers.filter(c => c.statut === 'ANNULE').length, enRetard: chantiers.filter(c => { if (!c.dateFinPrevue) return false; const now = new Date(); return new Date(c.dateFinPrevue) < now && c.statut !== 'TERMINE'; }).length }; setChantierStats(stats); const financialStats: FinancialStats = { chiffreAffaires: chantiers.reduce((sum, c) => sum + (c.montantReel || 0), 0), benefices: chantiers.reduce((sum, c) => sum + ((c.montantReel || 0) - (c.montantPrevu || 0)), 0), facturesEnAttente: 0, devisEnAttente: 0, tauxReussite: Math.round((stats.termines / Math.max(stats.total, 1)) * 100) }; setFinancialStats(financialStats); }; const generateChartData = () => { const { chantiers } = reportData; // Graphique en secteurs - Statuts des chantiers const pieData = { labels: ['Planifiés', 'En cours', 'Terminés', 'Annulés'], datasets: [ { data: [ chantierStats.planifies, chantierStats.enCours, chantierStats.termines, chantierStats.annules ], backgroundColor: [ '#3B82F6', '#10B981', '#6B7280', '#EF4444' ], borderColor: [ '#1D4ED8', '#047857', '#374151', '#DC2626' ], borderWidth: 1 } ] }; // Graphique en barres - Évolution mensuelle const barData = { labels: ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun', 'Jul', 'Aoû', 'Sep', 'Oct', 'Nov', 'Déc'], datasets: [ { label: 'Chiffre d\'affaires', data: [120000, 150000, 180000, 200000, 250000, 300000, 280000, 320000, 350000, 380000, 400000, 450000], backgroundColor: '#3B82F6', borderColor: '#1D4ED8', borderWidth: 1 }, { label: 'Bénéfices', data: [20000, 25000, 30000, 35000, 40000, 45000, 42000, 48000, 52000, 55000, 58000, 62000], backgroundColor: '#10B981', borderColor: '#047857', borderWidth: 1 } ] }; setChartData({ pie: pieData, bar: barData }); const options = { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' } } }; setChartOptions(options); }; const onPeriodChange = (e: any) => { setSelectedPeriod(e.value); const now = new Date(); let debut = new Date(); switch (e.value) { case 'semaine': debut = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 7); break; case 'mois': debut = new Date(now.getFullYear(), now.getMonth(), 1); break; case 'trimestre': debut = new Date(now.getFullYear(), Math.floor(now.getMonth() / 3) * 3, 1); break; case 'annee': debut = new Date(now.getFullYear(), 0, 1); break; default: return; } setDateDebut(debut); setDateFin(now); }; const exportPDF = () => { toast.current?.show({ severity: 'info', summary: 'Export PDF', detail: 'Génération du rapport PDF...', life: 3000 }); }; const exportExcel = () => { toast.current?.show({ severity: 'info', summary: 'Export Excel', detail: 'Génération du rapport Excel...', life: 3000 }); }; const leftToolbarTemplate = () => { return (
{selectedPeriod === 'custom' && ( <> setDateDebut(e.value || new Date())} dateFormat="dd/mm/yy" placeholder="Date début" /> setDateFin(e.value || new Date())} dateFormat="dd/mm/yy" placeholder="Date fin" /> )}
); }; const rightToolbarTemplate = () => { return (
); }; const renderVueEnsemble = () => { return (
{/* Indicateurs principaux */}
{chantierStats.total}
Chantiers Total
{chantierStats.termines}
Chantiers Terminés
{chantierStats.enCours}
En Cours
{chantierStats.enRetard}
En Retard
{/* Indicateurs financiers */}
{formatCurrency(financialStats.chiffreAffaires)}
Chiffre d'Affaires
{formatCurrency(financialStats.benefices)}
Bénéfices
Projets Terminés avec Succès
{/* Graphiques */}
); }; const renderRapportChantiers = () => { return (
rowData.client ? `${rowData.client.prenom} ${rowData.client.nom}` : 'Non défini' } /> formatDate(rowData.dateDebut)} sortable /> formatDate(rowData.dateFinPrevue)} sortable /> ( )} /> formatCurrency(rowData.montantPrevu)} sortable /> formatCurrency(rowData.montantReel || 0)} sortable /> { const progress = rowData.statut === 'TERMINE' ? 100 : rowData.statut === 'EN_COURS' ? 50 : rowData.statut === 'PLANIFIE' ? 0 : 0; return ; }} />
); }; const renderRapportFinancier = () => { return (
{formatCurrency(financialStats.chiffreAffaires)}
Total des revenus
{formatCurrency(financialStats.benefices)}
Total des bénéfices
{financialStats.chiffreAffaires > 0 ? `${Math.round((financialStats.benefices / financialStats.chiffreAffaires) * 100)}%` : '0%' }
Marge bénéficiaire
formatCurrency(rowData.montantPrevu)} sortable /> formatCurrency(rowData.montantReel || 0)} sortable /> { const ecart = (rowData.montantReel || 0) - rowData.montantPrevu; return ( = 0 ? 'text-green-500' : 'text-red-500'}> {formatCurrency(ecart)} ); }} /> { const rentabilite = rowData.montantPrevu > 0 ? (((rowData.montantReel || 0) - rowData.montantPrevu) / rowData.montantPrevu * 100) : 0; return ( = 0 ? 'text-green-500' : 'text-red-500'}> {rentabilite.toFixed(1)}% ); }} />
); }; return (
setActiveIndex(e.index)}> {renderVueEnsemble()} {renderRapportChantiers()} {renderRapportFinancier()}
); }; export default RapportsPage;