'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 { Button } from 'primereact/button'; import { Calendar } from 'primereact/calendar'; import { Dropdown } from 'primereact/dropdown'; import { Tag } from 'primereact/tag'; import { ProgressBar } from 'primereact/progressbar'; import { Toast } from 'primereact/toast'; import { Toolbar } from 'primereact/toolbar'; import { Badge } from 'primereact/badge'; import { devisService } from '../../../../services/api'; import { formatCurrency, formatDate } from '../../../../utils/formatters'; interface DevisStats { totalDevis: number; montantTotal: number; tauxAcceptation: number; tauxConversion: number; delaiMoyenReponse: number; repartitionStatuts: { [key: string]: number }; evolutionMensuelle: Array<{ mois: string; nombre: number; montant: number }>; topClients: Array<{ client: string; nombre: number; montant: number }>; performanceCommerciale: Array<{ commercial: string; devis: number; acceptes: number; montant: number }>; } const DevisStatsPage = () => { const toast = useRef(null); const [stats, setStats] = useState({ totalDevis: 0, montantTotal: 0, tauxAcceptation: 0, tauxConversion: 0, delaiMoyenReponse: 0, repartitionStatuts: {}, evolutionMensuelle: [], topClients: [], performanceCommerciale: [] }); const [loading, setLoading] = useState(true); const [dateDebut, setDateDebut] = useState(new Date(new Date().getFullYear(), 0, 1)); const [dateFin, setDateFin] = useState(new Date()); const [periodeSelectionnee, setPeriodeSelectionnee] = useState('annee'); const periodeOptions = [ { label: 'Cette année', value: 'annee' }, { label: 'Ce trimestre', value: 'trimestre' }, { label: 'Ce mois', value: 'mois' }, { label: 'Personnalisée', value: 'custom' } ]; useEffect(() => { loadStats(); }, [dateDebut, dateFin]); const loadStats = async () => { try { setLoading(true); // TODO: Remplacer par un vrai appel API // const response = await devisService.getStatistiques(dateDebut, dateFin); // Données simulées pour la démonstration const mockStats: DevisStats = { totalDevis: 156, montantTotal: 2450000, tauxAcceptation: 68.5, tauxConversion: 72.3, delaiMoyenReponse: 5.2, repartitionStatuts: { 'ACCEPTE': 107, 'EN_ATTENTE': 23, 'REFUSE': 18, 'EXPIRE': 8 }, evolutionMensuelle: [ { mois: 'Jan', nombre: 12, montant: 180000 }, { mois: 'Fév', nombre: 15, montant: 220000 }, { mois: 'Mar', nombre: 18, montant: 280000 }, { mois: 'Avr', nombre: 14, montant: 195000 }, { mois: 'Mai', nombre: 20, montant: 310000 }, { mois: 'Jun', nombre: 16, montant: 240000 }, { mois: 'Jul', nombre: 22, montant: 350000 }, { mois: 'Aoû', nombre: 19, montant: 290000 }, { mois: 'Sep', nombre: 20, montant: 395000 } ], topClients: [ { client: 'Bouygues Construction', nombre: 8, montant: 450000 }, { client: 'Vinci Construction', nombre: 6, montant: 380000 }, { client: 'Eiffage', nombre: 5, montant: 320000 }, { client: 'Spie Batignolles', nombre: 4, montant: 280000 }, { client: 'GTM Bâtiment', nombre: 3, montant: 210000 } ], performanceCommerciale: [ { commercial: 'Jean Dupont', devis: 45, acceptes: 32, montant: 680000 }, { commercial: 'Marie Martin', devis: 38, acceptes: 26, montant: 520000 }, { commercial: 'Pierre Durand', devis: 42, acceptes: 28, montant: 590000 }, { commercial: 'Sophie Bernard', devis: 31, acceptes: 21, montant: 410000 } ] }; setStats(mockStats); } catch (error) { console.error('Erreur lors du chargement des statistiques:', error); toast.current?.show({ severity: 'error', summary: 'Erreur', detail: 'Impossible de charger les statistiques' }); } finally { setLoading(false); } }; const handlePeriodeChange = (periode: string) => { setPeriodeSelectionnee(periode); const now = new Date(); switch (periode) { case 'annee': setDateDebut(new Date(now.getFullYear(), 0, 1)); setDateFin(new Date()); break; case 'trimestre': const trimestre = Math.floor(now.getMonth() / 3); setDateDebut(new Date(now.getFullYear(), trimestre * 3, 1)); setDateFin(new Date()); break; case 'mois': setDateDebut(new Date(now.getFullYear(), now.getMonth(), 1)); setDateFin(new Date()); break; } }; // Configuration des graphiques const chartOptions = { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'bottom' as const } }, scales: { y: { beginAtZero: true } } }; const evolutionData = { labels: stats.evolutionMensuelle.map(item => item.mois), datasets: [ { label: 'Nombre de devis', data: stats.evolutionMensuelle.map(item => item.nombre), borderColor: '#3B82F6', backgroundColor: 'rgba(59, 130, 246, 0.1)', yAxisID: 'y' }, { label: 'Montant (k€)', data: stats.evolutionMensuelle.map(item => item.montant / 1000), borderColor: '#10B981', backgroundColor: 'rgba(16, 185, 129, 0.1)', yAxisID: 'y1' } ] }; const repartitionData = { labels: Object.keys(stats.repartitionStatuts), datasets: [{ data: Object.values(stats.repartitionStatuts), backgroundColor: [ '#10B981', // ACCEPTE - vert '#F59E0B', // EN_ATTENTE - orange '#EF4444', // REFUSE - rouge '#6B7280' // EXPIRE - gris ] }] }; const getStatutSeverity = (statut: string) => { switch (statut) { case 'ACCEPTE': return 'success'; case 'REFUSE': return 'danger'; case 'EXPIRE': return 'warning'; case 'EN_ATTENTE': return 'info'; default: return 'info'; } }; const toolbarStartTemplate = () => (

Statistiques des Devis

); const toolbarEndTemplate = () => (
handlePeriodeChange(e.value)} className="w-10rem" /> {periodeSelectionnee === 'custom' && ( <> setDateDebut(e.value || new Date())} placeholder="Date début" dateFormat="dd/mm/yy" /> setDateFin(e.value || new Date())} placeholder="Date fin" dateFormat="dd/mm/yy" /> )}
); return (
{/* KPIs principaux */}
Total Devis
{stats.totalDevis}
+12% vs période précédente
Montant Total
{formatCurrency(stats.montantTotal)}
+8% vs période précédente
Taux d'Acceptation
{stats.tauxAcceptation}%
Délai Moyen
{stats.delaiMoyenReponse} jours
+0.3j vs période précédente
{/* Graphiques */}
{/* Top clients */}
(
{rowData.client}
)} /> formatCurrency(rowData.montant)} />
{/* Performance commerciale */}
( 0.7 ? 'success' : 'warning'} /> )} /> formatCurrency(rowData.montant)} />
{/* Analyse détaillée */}
Tendances
  • • Croissance de 12% du nombre de devis
  • • Augmentation de 8% du CA
  • • Taux d'acceptation stable à 68.5%
Points d'attention
  • • Délai de réponse en hausse (+0.3j)
  • • 23 devis en attente de réponse
  • • 8 devis expirés ce mois
Recommandations
  • • Relancer les devis en attente
  • • Optimiser les délais de réponse
  • • Cibler les gros clients
); }; export default DevisStatsPage;