diff --git a/frontend/src/components/domain/unified-wizard/wizards/CustomerOrderWizard.tsx b/frontend/src/components/domain/unified-wizard/wizards/CustomerOrderWizard.tsx index 9119c1d4..6d4a4300 100644 --- a/frontend/src/components/domain/unified-wizard/wizards/CustomerOrderWizard.tsx +++ b/frontend/src/components/domain/unified-wizard/wizards/CustomerOrderWizard.tsx @@ -1,5 +1,626 @@ -import React from 'react'; -import { WizardStep } from '../../../ui/WizardModal/WizardModal'; +import React, { useState } from 'react'; +import { WizardStep, WizardStepProps } from '../../../ui/WizardModal/WizardModal'; +import { + Users, + Plus, + Package, + Truck, + CreditCard, + Search, + CheckCircle2, + Calendar, + MapPin, +} from 'lucide-react'; + +interface WizardDataProps extends WizardStepProps { + data: Record; + onDataChange: (data: Record) => void; +} + +// Step 1: Customer Selection +const CustomerSelectionStep: React.FC = ({ data, onDataChange, onNext }) => { + const [searchQuery, setSearchQuery] = useState(''); + const [showNewCustomerForm, setShowNewCustomerForm] = useState(false); + const [selectedCustomer, setSelectedCustomer] = useState(data.customer || null); + + // Mock customer data - replace with actual API call + const mockCustomers = [ + { id: 1, name: 'Restaurante El Molino', type: 'Mayorista', phone: '+34 123 456 789' }, + { id: 2, name: 'Cafetería Central', type: 'Minorista', phone: '+34 987 654 321' }, + { id: 3, name: 'Hotel Vista Mar', type: 'Eventos', phone: '+34 555 123 456' }, + ]; + + const [newCustomer, setNewCustomer] = useState({ + name: '', + type: 'retail', + phone: '', + email: '', + }); + + const filteredCustomers = mockCustomers.filter((customer) => + customer.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + + const handleSelectCustomer = (customer: any) => { + setSelectedCustomer(customer); + setShowNewCustomerForm(false); + }; + + const handleContinue = () => { + if (showNewCustomerForm) { + onDataChange({ ...data, customer: newCustomer, isNewCustomer: true }); + } else { + onDataChange({ ...data, customer: selectedCustomer, isNewCustomer: false }); + } + onNext(); + }; + + return ( +
+
+ +

+ ¿Para quién es este pedido? +

+

+ Busca un cliente existente o crea uno nuevo +

+
+ + {!showNewCustomerForm ? ( + <> + {/* Search Bar */} +
+ + setSearchQuery(e.target.value)} + placeholder="Buscar cliente por nombre..." + className="w-full pl-10 pr-4 py-3 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)] bg-[var(--bg-primary)] text-[var(--text-primary)]" + /> +
+ + {/* Customer List */} +
+ {filteredCustomers.map((customer) => ( + + ))} +
+ + {/* Create New Customer Button */} + + + ) : ( + <> + {/* New Customer Form */} +
+

+ + Nuevo Cliente +

+ +
+
+ + setNewCustomer({ ...newCustomer, name: e.target.value })} + placeholder="Ej: Restaurante El Molino" + className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + /> +
+ +
+ + +
+ +
+ + setNewCustomer({ ...newCustomer, phone: e.target.value })} + placeholder="+34 123 456 789" + className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + /> +
+ +
+ + setNewCustomer({ ...newCustomer, email: e.target.value })} + placeholder="contacto@restaurante.com" + className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + /> +
+
+ + +
+ + )} + + {/* Continue Button */} +
+ +
+
+ ); +}; + +// Step 2: Order Items +const OrderItemsStep: React.FC = ({ data, onDataChange, onNext }) => { + const [orderItems, setOrderItems] = useState(data.orderItems || []); + + // Mock product data - replace with actual API call + const mockProducts = [ + { id: 1, name: 'Baguette Tradicional', price: 1.5, unit: 'unidad' }, + { id: 2, name: 'Croissant de Mantequilla', price: 2.0, unit: 'unidad' }, + { id: 3, name: 'Pan Integral', price: 2.5, unit: 'kg' }, + { id: 4, name: 'Tarta de Manzana', price: 18.0, unit: 'unidad' }, + ]; + + const handleAddItem = () => { + setOrderItems([ + ...orderItems, + { id: Date.now(), productId: '', productName: '', quantity: 1, unitPrice: 0, customRequirements: '', subtotal: 0 }, + ]); + }; + + const handleUpdateItem = (index: number, field: string, value: any) => { + const updated = orderItems.map((item: any, i: number) => { + if (i === index) { + const newItem = { ...item, [field]: value }; + + // If product selected, update price and name + if (field === 'productId') { + const product = mockProducts.find((p) => p.id === parseInt(value)); + if (product) { + newItem.productName = product.name; + newItem.unitPrice = product.price; + } + } + + // Auto-calculate subtotal + if (field === 'quantity' || field === 'unitPrice' || field === 'productId') { + newItem.subtotal = (newItem.quantity || 0) * (newItem.unitPrice || 0); + } + return newItem; + } + return item; + }); + setOrderItems(updated); + }; + + const handleRemoveItem = (index: number) => { + setOrderItems(orderItems.filter((_: any, i: number) => i !== index)); + }; + + const calculateTotal = () => { + return orderItems.reduce((sum: number, item: any) => sum + (item.subtotal || 0), 0); + }; + + const handleContinue = () => { + onDataChange({ ...data, orderItems, totalAmount: calculateTotal() }); + onNext(); + }; + + return ( +
+
+ +

+ ¿Qué productos incluye el pedido? +

+

+ Cliente: {data.customer?.name} +

+
+ + {/* Order Items */} +
+
+ + +
+ + {orderItems.length === 0 ? ( +
+ +

No hay productos en el pedido

+

Haz clic en "Agregar Producto" para comenzar

+
+ ) : ( +
+ {orderItems.map((item: any, index: number) => ( +
+
+ + Producto #{index + 1} + + +
+ +
+
+ + +
+ +
+ + handleUpdateItem(index, 'quantity', parseFloat(e.target.value) || 0)} + className="w-full px-3 py-2 text-sm border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + min="0" + step="1" + /> +
+ +
+ + handleUpdateItem(index, 'unitPrice', parseFloat(e.target.value) || 0)} + className="w-full px-3 py-2 text-sm border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + min="0" + step="0.01" + /> +
+ +
+ + handleUpdateItem(index, 'customRequirements', e.target.value)} + placeholder="Ej: Sin nueces, extra chocolate..." + className="w-full px-3 py-2 text-sm border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + /> +
+
+ +
+ + Subtotal: €{item.subtotal.toFixed(2)} + +
+
+ ))} +
+ )} + + {/* Total */} + {orderItems.length > 0 && ( +
+
+ Total del Pedido: + + €{calculateTotal().toFixed(2)} + +
+
+ )} +
+ + {/* Continue Button */} +
+ +
+
+ ); +}; + +// Step 3: Delivery & Payment +const DeliveryPaymentStep: React.FC = ({ data, onDataChange, onComplete }) => { + const [deliveryData, setDeliveryData] = useState({ + deliveryDate: data.deliveryDate || '', + deliveryTime: data.deliveryTime || '', + deliveryMethod: data.deliveryMethod || 'pickup', + deliveryAddress: data.deliveryAddress || '', + paymentMethod: data.paymentMethod || 'invoice', + specialInstructions: data.specialInstructions || '', + orderStatus: data.orderStatus || 'pending', + }); + + const handleConfirm = () => { + onDataChange({ ...data, ...deliveryData }); + // Here you would typically make an API call to save the order + console.log('Saving order:', { ...data, ...deliveryData }); + onComplete(); + }; + + return ( +
+
+ +

+ Entrega y Pago +

+

+ Configura los detalles de entrega y forma de pago +

+
+ +
+ {/* Delivery Date & Time */} +
+
+ + setDeliveryData({ ...deliveryData, deliveryDate: e.target.value })} + min={new Date().toISOString().split('T')[0]} + className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + /> +
+ +
+ + setDeliveryData({ ...deliveryData, deliveryTime: e.target.value })} + className="w-full px-3 py-2 border border-[var(--border-secondary)] rounded-lg focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]" + /> +
+
+ + {/* Delivery Method */} +
+ +
+ + + +
+
+ + {/* Delivery Address (conditional) */} + {(deliveryData.deliveryMethod === 'delivery' || deliveryData.deliveryMethod === 'shipping') && ( +
+ +