import React, { useState, useMemo } from 'react'; import { Plus, Download, AlertTriangle, Package, Clock, CheckCircle, Eye, Edit, Calendar, DollarSign } from 'lucide-react'; import { Button, Input, Card, StatsGrid, StatusCard, getStatusColor, StatusModal } from '../../../../components/ui'; import { LoadingSpinner } from '../../../../components/shared'; import { formatters } from '../../../../components/ui/Stats/StatsPresets'; import { PageHeader } from '../../../../components/layout'; import { LowStockAlert } from '../../../../components/domain/inventory'; import { useIngredients, useStockAnalytics } from '../../../../api/hooks/inventory'; import { useCurrentTenant } from '../../../../stores/tenant.store'; import { IngredientResponse } from '../../../../api/types/inventory'; const InventoryPage: React.FC = () => { const [searchTerm, setSearchTerm] = useState(''); const [showForm, setShowForm] = useState(false); const [modalMode, setModalMode] = useState<'view' | 'edit'>('view'); const [selectedItem, setSelectedItem] = useState(null); const currentTenant = useCurrentTenant(); const tenantId = currentTenant?.id || ''; // API Data const { data: ingredientsData, isLoading: ingredientsLoading, error: ingredientsError } = useIngredients(tenantId, { search: searchTerm || undefined }); const { data: analyticsData, isLoading: analyticsLoading } = useStockAnalytics(tenantId); const ingredients = ingredientsData || []; const lowStockItems = ingredients.filter(ingredient => ingredient.stock_status === 'low_stock'); const getInventoryStatusConfig = (ingredient: IngredientResponse) => { const { stock_status } = ingredient; switch (stock_status) { case 'out_of_stock': return { color: getStatusColor('cancelled'), text: 'Sin Stock', icon: AlertTriangle, isCritical: true, isHighlight: false }; case 'low_stock': return { color: getStatusColor('pending'), text: 'Stock Bajo', icon: AlertTriangle, isCritical: false, isHighlight: true }; case 'overstock': return { color: getStatusColor('info'), text: 'Sobrestock', icon: Package, isCritical: false, isHighlight: false }; case 'in_stock': default: return { color: getStatusColor('completed'), text: 'Normal', icon: CheckCircle, isCritical: false, isHighlight: false }; } }; const filteredItems = useMemo(() => { if (!searchTerm) return ingredients; return ingredients.filter(ingredient => { const searchLower = searchTerm.toLowerCase(); return ingredient.name.toLowerCase().includes(searchLower) || ingredient.category.toLowerCase().includes(searchLower) || (ingredient.description && ingredient.description.toLowerCase().includes(searchLower)); }); }, [ingredients, searchTerm]); const inventoryStats = useMemo(() => { if (!analyticsData) { return { totalItems: ingredients.length, lowStockItems: lowStockItems.length, outOfStock: ingredients.filter(item => item.stock_status === 'out_of_stock').length, expiringSoon: 0, // This would come from expired stock API totalValue: ingredients.reduce((sum, item) => sum + (item.current_stock_level * (item.average_cost || 0)), 0), categories: [...new Set(ingredients.map(item => item.category))].length, }; } return { totalItems: analyticsData.total_ingredients || 0, lowStockItems: analyticsData.low_stock_count || 0, outOfStock: analyticsData.out_of_stock_count || 0, expiringSoon: analyticsData.expiring_soon_count || 0, totalValue: analyticsData.total_stock_value || 0, categories: [...new Set(ingredients.map(item => item.category))].length, }; }, [analyticsData, ingredients, lowStockItems]); const stats = [ { title: 'Total Artículos', value: inventoryStats.totalItems, variant: 'default' as const, icon: Package, }, { title: 'Stock Bajo', value: inventoryStats.lowStockItems, variant: 'warning' as const, icon: AlertTriangle, }, { title: 'Sin Stock', value: inventoryStats.outOfStock, variant: 'error' as const, icon: AlertTriangle, }, { title: 'Por Caducar', value: inventoryStats.expiringSoon, variant: 'error' as const, icon: Clock, }, { title: 'Valor Total', value: formatters.currency(inventoryStats.totalValue), variant: 'success' as const, icon: DollarSign, }, { title: 'Categorías', value: inventoryStats.categories, variant: 'info' as const, icon: Package, }, ]; // Loading and error states if (ingredientsLoading || analyticsLoading || !tenantId) { return (
); } if (ingredientsError) { return (

Error al cargar el inventario

{ingredientsError.message || 'Ha ocurrido un error inesperado'}

); } return (
console.log('Export inventory') }, { id: "new", label: "Nuevo Artículo", variant: "primary" as const, icon: Plus, onClick: () => setShowForm(true) } ]} /> {/* Stats Grid */} {/* Low Stock Alert */} {lowStockItems.length > 0 && ( )} {/* Simplified Controls */}
setSearchTerm(e.target.value)} className="w-full" />
{/* Inventory Items Grid */}
{filteredItems.map((ingredient) => { const statusConfig = getInventoryStatusConfig(ingredient); const stockPercentage = ingredient.max_stock_level ? Math.round((ingredient.current_stock_level / ingredient.max_stock_level) * 100) : 0; const averageCost = ingredient.average_cost || 0; const totalValue = ingredient.current_stock_level * averageCost; return ( 0 ? ` (${formatters.currency(averageCost)}/${ingredient.unit_of_measure})` : ''}` }} progress={ingredient.max_stock_level ? { label: 'Nivel de stock', percentage: stockPercentage, color: statusConfig.color } : undefined} metadata={[ `Rango: ${ingredient.low_stock_threshold} - ${ingredient.max_stock_level || 'Sin límite'} ${ingredient.unit_of_measure}`, `Stock disponible: ${ingredient.available_stock} ${ingredient.unit_of_measure}`, `Stock reservado: ${ingredient.reserved_stock} ${ingredient.unit_of_measure}`, ingredient.last_restocked ? `Último restock: ${new Date(ingredient.last_restocked).toLocaleDateString('es-ES')}` : 'Sin historial de restock', ...(ingredient.requires_refrigeration ? ['Requiere refrigeración'] : []), ...(ingredient.requires_freezing ? ['Requiere congelación'] : []), ...(ingredient.is_seasonal ? ['Producto estacional'] : []) ]} actions={[ { label: 'Ver', icon: Eye, variant: 'outline', onClick: () => { setSelectedItem(ingredient); setModalMode('view'); setShowForm(true); } }, { label: 'Editar', icon: Edit, variant: 'outline', onClick: () => { setSelectedItem(ingredient); setModalMode('edit'); setShowForm(true); } } ]} /> ); })}
{/* Empty State */} {filteredItems.length === 0 && (

No se encontraron artículos

Intenta ajustar la búsqueda o agregar un nuevo artículo al inventario

)} {/* Inventory Item Modal */} {showForm && selectedItem && ( { setShowForm(false); setSelectedItem(null); setModalMode('view'); }} mode={modalMode} onModeChange={setModalMode} title={selectedItem.name} subtitle={`${selectedItem.category}${selectedItem.description ? ` - ${selectedItem.description}` : ''}`} statusIndicator={getInventoryStatusConfig(selectedItem)} size="lg" sections={[ { title: 'Información Básica', icon: Package, fields: [ { label: 'Nombre', value: selectedItem.name, highlight: true }, { label: 'Categoría', value: selectedItem.category }, { label: 'Descripción', value: selectedItem.description || 'Sin descripción' }, { label: 'Unidad de medida', value: selectedItem.unit_of_measure } ] }, { title: 'Stock y Niveles', icon: Package, fields: [ { label: 'Stock actual', value: `${selectedItem.current_stock_level} ${selectedItem.unit_of_measure}`, highlight: true }, { label: 'Stock disponible', value: `${selectedItem.available_stock} ${selectedItem.unit_of_measure}` }, { label: 'Stock reservado', value: `${selectedItem.reserved_stock} ${selectedItem.unit_of_measure}` }, { label: 'Umbral mínimo', value: `${selectedItem.low_stock_threshold} ${selectedItem.unit_of_measure}` }, { label: 'Stock máximo', value: selectedItem.max_stock_level ? `${selectedItem.max_stock_level} ${selectedItem.unit_of_measure}` : 'Sin límite' }, { label: 'Punto de reorden', value: `${selectedItem.reorder_point} ${selectedItem.unit_of_measure}` } ] }, { title: 'Información Financiera', icon: DollarSign, fields: [ { label: 'Costo promedio por unidad', value: selectedItem.average_cost || 0, type: 'currency' }, { label: 'Valor total en stock', value: selectedItem.current_stock_level * (selectedItem.average_cost || 0), type: 'currency', highlight: true } ] }, { title: 'Información Adicional', icon: Calendar, fields: [ { label: 'Último restock', value: selectedItem.last_restocked || 'Sin historial', type: selectedItem.last_restocked ? 'datetime' : undefined }, { label: 'Vida útil', value: selectedItem.shelf_life_days ? `${selectedItem.shelf_life_days} días` : 'No especificada' }, { label: 'Requiere refrigeración', value: selectedItem.requires_refrigeration ? 'Sí' : 'No', highlight: selectedItem.requires_refrigeration }, { label: 'Requiere congelación', value: selectedItem.requires_freezing ? 'Sí' : 'No', highlight: selectedItem.requires_freezing }, { label: 'Producto estacional', value: selectedItem.is_seasonal ? 'Sí' : 'No' }, { label: 'Creado', value: selectedItem.created_at, type: 'datetime' } ] }, ...(selectedItem.notes ? [{ title: 'Notas', fields: [ { label: 'Observaciones', value: selectedItem.notes, span: 2 as const } ] }] : []) ]} onEdit={() => { console.log('Editing inventory item:', selectedItem.id); }} /> )}
); }; export default InventoryPage;