'use client' import React, { useState, useEffect } from 'react' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' import { Badge } from '@/components/ui/badge' import { ScrollArea } from '@/components/ui/scroll-area' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart' import { BarChart, Bar, LineChart, Line, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Legend, ResponsiveContainer } from 'recharts' import { TrendingUp, TrendingDown, DollarSign, Users, Package, AlertTriangle, Download, Calendar, ArrowRight } from 'lucide-react' import { toast } from 'sonner' import { format, startOfDay, endOfDay, startOfWeek, endOfWeek, startOfMonth, endOfMonth, startOfYear, endOfYear, subDays } from 'date-fns' import { fr } from 'date-fns/locale' // Types interface KPICardProps { title: string value: string | number change?: number icon: React.ReactNode trend?: 'up' | 'down' | 'neutral' } interface DashboardData { totalSales: { today: number week: number month: number year: number } revenue: { htToday: number ttcToday: number htMonth: number ttcMonth: number } totalClients: number topProducts: { designation: string quantity: number revenue: number }[] lowStockItems: { id: string reference: string designation: string stock: number stockMin: number }[] pendingWorkshopOrders: number } interface SalesReportData { salesByDate: { date: string sales: number revenue: number }[] salesByCategory: { category: string count: number revenue: number }[] salesByEmployee: { employee: string sales: number revenue: number }[] salesByPaymentMethod: { method: string count: number amount: number }[] } interface InventoryReportData { stockValuation: { totalValue: number byCategory: { category: string value: number count: number }[] } lowStockItems: { id: string reference: string designation: string category: string stock: number stockMin: number value: number }[] categoryBreakdown: { category: string totalProducts: number activeProducts: number totalStock: number stockValue: number }[] } // KPI Card Component function KPICard({ title, value, change, icon, trend = 'neutral' }: KPICardProps) { return ( {title}
{icon}
{typeof value === 'number' ? value.toLocaleString() : value}
{change !== undefined && (

{trend === 'up' && } {trend === 'down' && } {change > 0 ? '+' : ''}{change.toFixed(1)}% par rapport à hier

)}
) } // Chart colors const CHART_COLORS = { sales: '#10b981', revenue: '#3b82f6', monture: '#8b5cf6', verre: '#06b6d4', lentille: '#f59e0b', accessoire: '#ec4899', especes: '#10b981', carte: '#3b82f6', cheque: '#f59e0b', virement: '#8b5cf6', bonCaisse: '#ec4899', } export default function ReportsModule() { const [activeTab, setActiveTab] = useState('dashboard') const [dateRange, setDateRange] = useState<'today' | 'week' | 'month' | 'year' | 'custom'>('month') const [loading, setLoading] = useState(true) const [dashboardData, setDashboardData] = useState(null) const [salesData, setSalesData] = useState(null) const [inventoryData, setInventoryData] = useState(null) // Fetch dashboard data const fetchDashboardData = async () => { try { setLoading(true) const response = await fetch('/api/reports/dashboard') if (!response.ok) throw new Error('Failed to fetch dashboard data') const data = await response.json() setDashboardData(data) } catch (error) { console.error('Error fetching dashboard data:', error) toast.error('Erreur lors du chargement des données du tableau de bord') } finally { setLoading(false) } } // Fetch sales report data const fetchSalesData = async () => { try { const response = await fetch(`/api/reports/sales?range=${dateRange}`) if (!response.ok) throw new Error('Failed to fetch sales data') const data = await response.json() setSalesData(data) } catch (error) { console.error('Error fetching sales data:', error) toast.error('Erreur lors du chargement des données de ventes') } } // Fetch inventory report data const fetchInventoryData = async () => { try { const response = await fetch('/api/reports/inventory') if (!response.ok) throw new Error('Failed to fetch inventory data') const data = await response.json() setInventoryData(data) } catch (error) { console.error('Error fetching inventory data:', error) toast.error('Erreur lors du chargement des données de stock') } } // Export data to CSV const exportToCSV = async (type: 'sales' | 'inventory' | 'lowStock') => { try { const response = await fetch(`/api/reports/export/${type}?range=${dateRange}`) if (!response.ok) throw new Error('Failed to export data') const blob = await response.blob() const url = window.URL.createObjectURL(blob) const a = document.createElement('a') a.href = url a.download = `${type}_${format(new Date(), 'yyyy-MM-dd')}.csv` document.body.appendChild(a) a.click() window.URL.revokeObjectURL(url) document.body.removeChild(a) toast.success('Export CSV réussi') } catch (error) { console.error('Error exporting data:', error) toast.error('Erreur lors de l\'export des données') } } // Load data based on active tab useEffect(() => { if (activeTab === 'dashboard') { fetchDashboardData() } else if (activeTab === 'sales') { fetchSalesData() } else if (activeTab === 'inventory') { fetchInventoryData() } }, [activeTab, dateRange]) // Initial data load useEffect(() => { fetchDashboardData() }, []) const chartConfig = { sales: { label: 'Ventes', color: CHART_COLORS.sales }, revenue: { label: 'Chiffre d\'affaires', color: CHART_COLORS.revenue }, monture: { label: 'Montures', color: CHART_COLORS.monture }, verre: { label: 'Verres', color: CHART_COLORS.verre }, lentille: { label: 'Lentilles', color: CHART_COLORS.lentille }, accessoire: { label: 'Accessoires', color: CHART_COLORS.accessoire }, } return (
{/* Header */}

Rapports

Tableau de bord et statistiques de votre magasin

{activeTab !== 'dashboard' && ( )}
{/* Main Tabs */} Tableau de bord Rapports de ventes Rapports de stock {/* Dashboard Tab */} {loading && !dashboardData ? (

Chargement...

) : ( <> {/* KPI Cards */}
} /> } /> } /> } trend={dashboardData?.pendingWorkshopOrders && dashboardData.pendingWorkshopOrders > 0 ? 'down' : 'neutral'} />
{/* Additional KPIs */}
} /> } /> } /> } />
{/* Top Products and Low Stock */}
{/* Top Selling Products */} Top 5 des produits vendus Les produits les plus populaires ce mois
{dashboardData?.topProducts.length === 0 ? (

Aucune vente ce mois

) : ( dashboardData?.topProducts.map((product, index) => (

{product.designation}

{product.quantity} vendus

{product.revenue.toFixed(2)} €

)) )}
{/* Low Stock Alerts */} Alertes de stock {dashboardData?.lowStockItems.length || 0} Produits en dessous du stock minimum
{dashboardData?.lowStockItems.length === 0 ? (

Aucune alerte de stock

) : ( dashboardData?.lowStockItems.map((item) => (

{item.designation}

{item.reference}

{item.stock} / {item.stockMin}
)) )}
)}
{/* Sales Reports Tab */} {loading && !salesData ? (

Chargement...

) : ( <> {/* Sales by Date Chart */} Évolution des ventes Ventes et chiffre d'affaires par période } />
{/* Sales by Category Pie Chart */} Ventes par catégorie Répartition des ventes par type de produit `${category} ${(percent * 100).toFixed(0)}%`} > {salesData?.salesByCategory.map((entry, index) => ( ))} } /> {/* Sales by Payment Method */} Mode de paiement Répartition des paiements } />
{/* Sales by Employee Table */} Ventes par employé Performance de l'équipe Employé Nombre de ventes Chiffre d'affaires {salesData?.salesByEmployee.length === 0 ? ( Aucune donnée disponible ) : ( salesData?.salesByEmployee.map((employee, index) => ( {employee.employee} {employee.sales} {employee.revenue.toFixed(2)} € )) )}
)}
{/* Inventory Reports Tab */} {loading && !inventoryData ? (

Chargement...

) : ( <> {/* Stock Valuation */} Valorisation du stock Valeur totale du stock par catégorie

Valeur totale du stock

{inventoryData?.stockValuation.totalValue.toFixed(2)} € HT

} />
{/* Category Breakdown Table */} Répartition par catégorie Détails du stock par type de produit Catégorie Produits Stock Valeur {inventoryData?.categoryBreakdown.length === 0 ? ( Aucune donnée disponible ) : ( inventoryData?.categoryBreakdown.map((cat) => ( {cat.category} {cat.activeProducts} / {cat.totalProducts} {cat.totalStock} {cat.stockValue.toFixed(2)} € )) )}
{/* Low Stock Details */} Produits en stock faible {inventoryData?.lowStockItems.length || 0} Produits nécessitant un réapprovisionnement
{inventoryData?.lowStockItems.length === 0 ? (

Tous les stocks sont OK

) : ( inventoryData?.lowStockItems.map((item) => (

{item.designation}

{item.reference} • {item.category}

{item.stock} unités

Min: {item.stockMin}

)) )}
)}
) }