From caf6d92850f0468f62d581bb2915119bef05c5e4 Mon Sep 17 00:00:00 2001 From: Urtzi Alfaro Date: Fri, 19 Sep 2025 12:06:26 +0200 Subject: [PATCH] Imporve the routes and the menu --- .../domain/orders/OrderFormModal.tsx | 292 ++++++++---------- .../src/components/layout/Sidebar/Sidebar.tsx | 2 + .../src/pages/app/database/DatabasePage.tsx | 97 ++++++ frontend/src/router/AppRouter.tsx | 179 ++++++----- frontend/src/router/routes.config.ts | 201 ++++++------ 5 files changed, 437 insertions(+), 334 deletions(-) create mode 100644 frontend/src/pages/app/database/DatabasePage.tsx diff --git a/frontend/src/components/domain/orders/OrderFormModal.tsx b/frontend/src/components/domain/orders/OrderFormModal.tsx index 1cfceebe..a42e2a4d 100644 --- a/frontend/src/components/domain/orders/OrderFormModal.tsx +++ b/frontend/src/components/domain/orders/OrderFormModal.tsx @@ -76,10 +76,9 @@ export const OrderFormModal: React.FC = ({ priority_level: PriorityLevel.NORMAL }); - // Product selection - const [showProductModal, setShowProductModal] = useState(false); - const [productSearch, setProductSearch] = useState(''); - const [selectedCategory, setSelectedCategory] = useState(''); + // Simple product selection + const [selectedProductId, setSelectedProductId] = useState(''); + const [selectedQuantity, setSelectedQuantity] = useState(1); // API hooks const { data: customers = [] } = useCustomers({ @@ -110,8 +109,8 @@ export const OrderFormModal: React.FC = ({ // Reset form when modal closes setSelectedCustomer(null); setOrderItems([]); - setProductSearch(''); - setSelectedCategory(''); + setSelectedProductId(''); + setSelectedQuantity(1); setOrderData({ order_type: OrderType.STANDARD, priority: PriorityLevel.NORMAL, @@ -125,13 +124,18 @@ export const OrderFormModal: React.FC = ({ } }, [isOpen]); - const handleAddProduct = (product: any) => { - const existingItem = orderItems.find(item => item.product_id === product.id); + const handleAddSelectedProduct = () => { + if (!selectedProductId || selectedQuantity <= 0) return; + + const product = finishedProducts.find(p => p.id === selectedProductId); + if (!product) return; + + const existingItem = orderItems.find(item => item.product_id === selectedProductId); if (existingItem) { setOrderItems(items => items.map(item => - item.product_id === product.id - ? { ...item, quantity: item.quantity + 1 } + item.product_id === selectedProductId + ? { ...item, quantity: item.quantity + selectedQuantity } : item )); } else { @@ -140,14 +144,17 @@ export const OrderFormModal: React.FC = ({ product_name: product.name, product_sku: product.sku || undefined, product_category: product.category || undefined, - quantity: 1, + quantity: selectedQuantity, unit_of_measure: product.unit_of_measure || 'unidad', unit_price: product.average_cost || product.standard_cost || 0, line_discount: 0 }; setOrderItems(items => [...items, newItem]); } - setShowProductModal(false); + + // Reset selection + setSelectedProductId(''); + setSelectedQuantity(1); }; const handleUpdateItemQuantity = (productId: string, quantity: number) => { @@ -213,22 +220,6 @@ export const OrderFormModal: React.FC = ({ onClose(); }; - // Get unique categories for filtering - const uniqueCategories = Array.from(new Set( - finishedProducts - .map(product => product.category) - .filter(Boolean) - )).sort(); - - const filteredProducts = finishedProducts.filter(product => { - const matchesSearch = product.name.toLowerCase().includes(productSearch.toLowerCase()) || - (product.category && product.category.toLowerCase().includes(productSearch.toLowerCase())) || - (product.description && product.description.toLowerCase().includes(productSearch.toLowerCase())); - - const matchesCategory = !selectedCategory || product.category === selectedCategory; - - return matchesSearch && matchesCategory; - }); // Convert form data to StatusModal sections const modalSections: StatusModalSection[] = [ @@ -238,8 +229,30 @@ export const OrderFormModal: React.FC = ({ fields: [ { label: 'Cliente Seleccionado', - value: selectedCustomer ? `${selectedCustomer.name} (${selectedCustomer.customer_code})` : 'Ninguno', - span: 2 + value: selectedCustomer ? selectedCustomer.id : '', + type: 'select', + editable: true, + placeholder: 'Seleccionar cliente...', + options: customers.map(customer => ({ + value: customer.id, + label: `${customer.name} (${customer.customer_code})` + })), + span: 1 + }, + { + label: 'Nuevo Cliente', + value: ( + + ), + span: 1 } ] }, @@ -281,15 +294,88 @@ export const OrderFormModal: React.FC = ({ icon: Package, fields: [ { - label: 'Total de Productos', - value: orderItems.length, - highlight: true - }, - { - label: 'Lista de Productos', - value: orderItems.length > 0 ? orderItems.map(item => `${item.product_name} (x${item.quantity})`).join(', ') : 'Sin productos', + label: 'Agregar Producto', + value: ( +
+
+ +
+
+ setSelectedQuantity(Number(e.target.value))} + placeholder="Cant." + /> +
+ +
+ ), span: 2 - } + }, + ...(orderItems.length > 0 ? [{ + label: 'Productos en el Pedido', + value: ( +
+ {orderItems.map((item, index) => ( +
+
+

{item.product_name}

+

+ €{item.unit_price.toFixed(2)} × {item.quantity} = €{(item.unit_price * item.quantity).toFixed(2)} +

+
+
+ + {item.quantity} + + +
+
+ ))} +
+ ), + span: 2 + }] : []) ] }, { @@ -334,7 +420,12 @@ export const OrderFormModal: React.FC = ({ const field = section.fields[fieldIndex]; // Update order data based on field changes - if (section.title === 'Detalles del Pedido') { + if (section.title === 'Cliente') { + if (field.label === 'Cliente Seleccionado') { + const customer = customers.find(c => c.id === value); + setSelectedCustomer(customer || null); + } + } else if (section.title === 'Detalles del Pedido') { if (field.label === 'Tipo de Pedido') { setOrderData(prev => ({ ...prev, order_type: value as OrderType })); } else if (field.label === 'Prioridad') { @@ -361,17 +452,6 @@ export const OrderFormModal: React.FC = ({ size="2xl" showDefaultActions={false} actions={[ - { - label: selectedCustomer ? 'Cambiar Cliente' : 'Seleccionar Cliente', - variant: 'outline', - onClick: () => setShowCustomerSelector(true) - }, - { - label: 'Agregar Productos', - variant: 'outline', - onClick: () => setShowProductModal(true), - icon: Plus - }, { label: 'Cancelar', variant: 'outline', @@ -392,118 +472,6 @@ export const OrderFormModal: React.FC = ({ - {/* Product Selection Modal - Using StatusModal for consistency */} - setShowProductModal(false)} - mode="view" - title="Seleccionar Productos" - subtitle="Elija productos terminados para agregar al pedido" - size="2xl" - showDefaultActions={false} - sections={[ - { - title: 'Filtros', - icon: Package, - fields: [ - { - label: 'Buscar productos', - value: productSearch, - type: 'text', - editable: true, - placeholder: 'Buscar productos...', - span: 1 - }, - { - label: 'Categoría', - value: selectedCategory, - type: 'select', - editable: true, - placeholder: 'Todas las categorías', - options: [ - { value: '', label: 'Todas las categorías' }, - ...uniqueCategories.map(category => ({ - value: category, - label: category - })) - ], - span: 1 - } - ] - }, - { - title: 'Productos Disponibles', - icon: ShoppingCart, - fields: [ - { - label: 'Lista de productos', - value: ( -
- {productsLoading ? ( -
-

Cargando productos...

-
- ) : filteredProducts.length === 0 ? ( -
-

- {productSearch ? 'No se encontraron productos que coincidan con la búsqueda' : 'No hay productos finalizados disponibles'} -

-
- ) : ( - filteredProducts.map(product => ( -
-
-
-

{product.name}

- {product.description && ( -

{product.description}

- )} -
- {product.category && ( - - {product.category} - - )} - - €{(product.average_cost || product.standard_cost || 0).toFixed(2)} - -
-
- - -
- -
- Stock: {product.total_quantity || 0} {product.unit_of_measure} - {product.sku && SKU: {product.sku}} -
-
- )) - )} -
- ), - span: 2 - } - ] - } - ]} - onFieldChange={(sectionIndex, fieldIndex, value) => { - if (sectionIndex === 0) { - if (fieldIndex === 0) { - setProductSearch(String(value)); - } else if (fieldIndex === 1) { - setSelectedCategory(String(value)); - } - } - }} - /> {/* New Customer Modal - Using StatusModal for consistency */} > = { procurement: Truck, pos: Zap, data: Database, + database: Store, training: GraduationCap, notifications: Bell, settings: Settings, diff --git a/frontend/src/pages/app/database/DatabasePage.tsx b/frontend/src/pages/app/database/DatabasePage.tsx new file mode 100644 index 00000000..bdc5c58c --- /dev/null +++ b/frontend/src/pages/app/database/DatabasePage.tsx @@ -0,0 +1,97 @@ +import React from 'react'; +import { Outlet, useLocation } from 'react-router-dom'; +import { PageHeader } from '../../../components/layout/PageHeader/PageHeader'; +import { Database, Package, ShoppingCart, Truck, Settings, Users, MessageSquare } from 'lucide-react'; + +const DatabasePage: React.FC = () => { + const location = useLocation(); + const isParentRoute = location.pathname === '/app/database'; + + if (!isParentRoute) { + return ; + } + + return ( +
+ + +
+
+
+
+ +
+

Recetas

+
+

Gestiona las recetas de tus productos

+
+ +
+
+
+ +
+

Pedidos

+
+

Consulta el estado de todos los pedidos

+
+ + +
+
+
+ +
+

Proveedores

+
+

Gestiona tus proveedores

+
+ +
+
+
+ +
+

Inventario

+
+

Estado actual del inventario

+
+ +
+
+
+ +
+

Configuración de Panadería

+
+

Configuración general de tu panadería

+
+ +
+
+
+ +
+

Gestión de Equipo

+
+

Administra tu equipo de trabajo

+
+ +
+
+
+ +
+

Preferencias de Comunicación

+
+

Configura notificaciones y comunicaciones

+
+
+
+ ); +}; + +export default DatabasePage; \ No newline at end of file diff --git a/frontend/src/router/AppRouter.tsx b/frontend/src/router/AppRouter.tsx index 0cffde00..ad3703e3 100644 --- a/frontend/src/router/AppRouter.tsx +++ b/frontend/src/router/AppRouter.tsx @@ -33,6 +33,9 @@ const BakeryConfigPage = React.lazy(() => import('../pages/app/settings/bakery-c const TeamPage = React.lazy(() => import('../pages/app/settings/team/TeamPage')); const SubscriptionPage = React.lazy(() => import('../pages/app/settings/subscription/SubscriptionPage')); +// Database pages +const DatabasePage = React.lazy(() => import('../pages/app/database/DatabasePage')); + // Data pages const WeatherPage = React.lazy(() => import('../pages/app/data/weather/WeatherPage')); const TrafficPage = React.lazy(() => import('../pages/app/data/traffic/TrafficPage')); @@ -72,76 +75,118 @@ export const AppRouter: React.FC = () => { } /> - {/* Operations Routes */} - - - - - - } - /> - - - - - - } - /> - - - - - - } - /> - - } + } /> - - + - } + } /> - - - - - - } - /> - - } + } + /> + + {/* Database Routes - Current Bakery Status */} + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } + /> + + + + + + } /> {/* Analytics Routes */} @@ -187,18 +232,6 @@ export const AppRouter: React.FC = () => { /> - {/* Settings Routes */} - - - - - - } - /> - {/* Settings Routes */} { } /> - - - - - - } - /> - - - - - - } - />