diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index 477d4e6..3ddbb07 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -1,3 +1,4 @@ +import { useQuery } from '@tanstack/react-query'; import { TrendingUp, ShoppingCart, @@ -5,26 +6,35 @@ import { CreditCard, Package, AlertCircle, + Loader2, } from 'lucide-react'; +import { dashboardApi, ordersApi, inventoryApi } from '../lib/api'; -const stats = [ - { name: 'Ventas Hoy', value: '$1,240', change: '+12%', icon: TrendingUp, color: 'green' }, - { name: 'Pedidos', value: '23', change: '+5', icon: ShoppingCart, color: 'blue' }, - { name: 'Clientes', value: '156', change: '+3', icon: Users, color: 'purple' }, - { name: 'Fiados Pendientes', value: '$2,100', change: '-$450', icon: CreditCard, color: 'orange' }, -]; +interface DashboardStats { + salesToday: number; + ordersCount: number; + customersCount: number; + pendingFiado: number; + salesChange: string; + ordersChange: string; + customersChange: string; + fiadoChange: string; +} -const recentOrders = [ - { id: 'MCH-001', customer: 'Maria Lopez', total: 156.00, status: 'ready', time: '10:30 AM' }, - { id: 'MCH-002', customer: 'Juan Perez', total: 89.50, status: 'preparing', time: '10:45 AM' }, - { id: 'MCH-003', customer: 'Ana Garcia', total: 234.00, status: 'pending', time: '11:00 AM' }, -]; +interface Order { + id: string; + customer: { name: string } | null; + total: number; + status: string; + createdAt: string; +} -const lowStockProducts = [ - { name: 'Coca-Cola 600ml', stock: 5, minStock: 10 }, - { name: 'Pan Bimbo', stock: 2, minStock: 5 }, - { name: 'Leche Lala 1L', stock: 3, minStock: 8 }, -]; +interface LowStockProduct { + id: string; + name: string; + stock: number; + minStock: number; +} const statusColors: Record = { pending: 'bg-yellow-100 text-yellow-800', @@ -33,7 +43,111 @@ const statusColors: Record = { completed: 'bg-gray-100 text-gray-800', }; +const statusLabels: Record = { + pending: 'Pendiente', + preparing: 'Preparando', + ready: 'Listo', + completed: 'Completado', +}; + +function formatCurrency(amount: number): string { + return new Intl.NumberFormat('es-MX', { + style: 'currency', + currency: 'MXN', + }).format(amount); +} + +function LoadingSpinner() { + return ( +
+ +
+ ); +} + +function ErrorMessage({ message }: { message: string }) { + return ( +
+ + {message} +
+ ); +} + export function Dashboard() { + // Fetch dashboard stats + const { + data: statsData, + isLoading: statsLoading, + error: statsError, + } = useQuery({ + queryKey: ['dashboard-stats'], + queryFn: async () => { + const response = await dashboardApi.getStats(); + return response.data as DashboardStats; + }, + }); + + // Fetch recent orders + const { + data: ordersData, + isLoading: ordersLoading, + error: ordersError, + } = useQuery({ + queryKey: ['recent-orders'], + queryFn: async () => { + const response = await ordersApi.getAll({ status: undefined }); + return (response.data as Order[]).slice(0, 5); + }, + }); + + // Fetch low stock products + const { + data: lowStockData, + isLoading: lowStockLoading, + error: lowStockError, + } = useQuery({ + queryKey: ['low-stock'], + queryFn: async () => { + const response = await inventoryApi.getLowStock(); + return response.data as LowStockProduct[]; + }, + }); + + // Build stats array from API data + const stats = statsData + ? [ + { + name: 'Ventas Hoy', + value: formatCurrency(statsData.salesToday), + change: statsData.salesChange, + icon: TrendingUp, + color: 'green', + }, + { + name: 'Pedidos', + value: String(statsData.ordersCount), + change: statsData.ordersChange, + icon: ShoppingCart, + color: 'blue', + }, + { + name: 'Clientes', + value: String(statsData.customersCount), + change: statsData.customersChange, + icon: Users, + color: 'purple', + }, + { + name: 'Fiados Pendientes', + value: formatCurrency(statsData.pendingFiado), + change: statsData.fiadoChange, + icon: CreditCard, + color: 'orange', + }, + ] + : []; + return (
@@ -42,26 +156,32 @@ export function Dashboard() {
{/* Stats Grid */} -
- {stats.map((stat) => ( -
-
-
-

{stat.name}

-

{stat.value}

-

- {stat.change} -

-
-
- + {statsLoading ? ( + + ) : statsError ? ( + + ) : ( +
+ {stats.map((stat) => ( +
+
+
+

{stat.name}

+

{stat.value}

+

+ {stat.change} +

+
+
+ +
-
- ))} -
+ ))} +
+ )}
{/* Recent Orders */} @@ -75,25 +195,35 @@ export function Dashboard() { Ver todos
-
- {recentOrders.map((order) => ( -
-
-

{order.id}

-

{order.customer}

+ {ordersLoading ? ( + + ) : ordersError ? ( + + ) : ordersData && ordersData.length > 0 ? ( +
+ {ordersData.map((order) => ( +
+
+

{order.id.slice(0, 8).toUpperCase()}

+

+ {order.customer?.name || 'Cliente General'} +

+
+
+

{formatCurrency(order.total)}

+ + {statusLabels[order.status] || order.status} + +
-
-

${order.total.toFixed(2)}

- - {order.status} - -
-
- ))} -
+ ))} +
+ ) : ( +

No hay pedidos recientes

+ )}
{/* Low Stock Alert */} @@ -107,23 +237,31 @@ export function Dashboard() { Ver inventario
-
- {lowStockProducts.map((product) => ( -
-
- -

{product.name}

+ {lowStockLoading ? ( + + ) : lowStockError ? ( + + ) : lowStockData && lowStockData.length > 0 ? ( +
+ {lowStockData.map((product) => ( +
+
+ +

{product.name}

+
+
+

{product.stock} unidades

+

Min: {product.minStock}

+
-
-

{product.stock} unidades

-

Min: {product.minStock}

-
-
- ))} -
+ ))} +
+ ) : ( +

No hay productos con stock bajo

+ )}