'use client'; import React, { useState, useEffect } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { Card } from 'primereact/card'; import { Button } from 'primereact/button'; import { DataTable } from 'primereact/datatable'; import { Column } from 'primereact/column'; import { ProgressBar } from 'primereact/progressbar'; import { Chart } from 'primereact/chart'; import { Tag } from 'primereact/tag'; interface BudgetChantier { id: number; chantierNom: string; budgetTotal: number; depenseTotal: number; resteAEngager: number; lignesBudget: LigneBudget[]; } interface LigneBudget { id: number; categorie: string; budgetPrevu: number; depenseReel: number; ecart: number; pourcentageUtilisation: number; } export default function ChantierBudgetPage() { const params = useParams(); const router = useRouter(); const id = params.id as string; const [budget, setBudget] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { if (id) { loadBudget(); } }, [id]); const loadBudget = async () => { try { setLoading(true); const API_URL = process.env.NEXT_PUBLIC_API_URL || 'https://api.lions.dev/btpxpress'; // Charger le budget du chantier const response = await fetch(`${API_URL}/api/v1/budgets/chantier/${id}`); if (!response.ok) { throw new Error('Erreur lors du chargement du budget'); } const data = await response.json(); setBudget(data); } catch (error) { console.error('Erreur:', error); } finally { setLoading(false); } }; const formatMontant = (montant: number) => { return new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR' }).format(montant); }; const montantBodyTemplate = (rowData: LigneBudget, field: string) => { const value = (rowData as any)[field]; return formatMontant(value); }; const ecartBodyTemplate = (rowData: LigneBudget) => { const severity = rowData.ecart >= 0 ? 'success' : 'danger'; const icon = rowData.ecart >= 0 ? 'pi-check' : 'pi-exclamation-triangle'; return ( ); }; const progressionBodyTemplate = (rowData: LigneBudget) => { const severity = rowData.pourcentageUtilisation > 100 ? 'danger' : rowData.pourcentageUtilisation > 80 ? 'warning' : 'success'; return (
{rowData.pourcentageUtilisation.toFixed(1)}%
); }; const getChartData = () => { if (!budget) return null; return { labels: budget.lignesBudget?.map(l => l.categorie) || [], datasets: [ { label: 'Budget prévu', backgroundColor: '#42A5F5', data: budget.lignesBudget?.map(l => l.budgetPrevu) || [] }, { label: 'Dépenses réelles', backgroundColor: '#FFA726', data: budget.lignesBudget?.map(l => l.depenseReel) || [] } ] }; }; const getChartOptions = () => { return { maintainAspectRatio: false, aspectRatio: 0.8, plugins: { legend: { position: 'top', } }, scales: { y: { beginAtZero: true, ticks: { callback: function(value: any) { return formatMontant(value); } } } } }; }; const getPourcentageUtilisation = () => { if (!budget || budget.budgetTotal === 0) return 0; return (budget.depenseTotal / budget.budgetTotal) * 100; }; return (
{/* Vue d'ensemble */}
{budget ? formatMontant(budget.budgetTotal) : formatMontant(0)}
Montant budgété
{budget ? formatMontant(budget.depenseTotal) : formatMontant(0)}
Montant dépensé
{budget ? formatMontant(budget.resteAEngager) : formatMontant(0)}
Montant disponible
{/* Progression */}
100 ? '#ef4444' : getPourcentageUtilisation() > 80 ? '#f59e0b' : '#10b981'} style={{ height: '30px' }} />
{getPourcentageUtilisation().toFixed(1)}% du budget utilisé
{/* Graphique */}
{/* Répartition */}
l.categorie) || [], datasets: [{ data: budget?.lignesBudget?.map(l => l.budgetPrevu) || [], backgroundColor: [ '#42A5F5', '#66BB6A', '#FFA726', '#EF5350', '#AB47BC', '#26C6DA' ] }] }} style={{ height: '400px' }} />
{/* Tableau détaillé */}
montantBodyTemplate(rowData, 'budgetPrevu')} sortable /> montantBodyTemplate(rowData, 'depenseReel')} sortable /> (
)} />
); }