import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { WizardStep, WizardStepProps } from '../../../ui/WizardModal/WizardModal'; import { Edit3, Upload, CheckCircle2, Download, FileSpreadsheet, Calendar, DollarSign, Package, CreditCard, Loader2, X, AlertCircle, } from 'lucide-react'; import { useTenant } from '../../../../stores/tenant.store'; import { salesService } from '../../../../api/services/sales'; import { inventoryService } from '../../../../api/services/inventory'; import { showToast } from '../../../../utils/toast'; // ======================================== // STEP 1: Entry Method Selection // ======================================== const EntryMethodStep: React.FC = ({ dataRef, onDataChange, onNext }) => { const data = dataRef?.current || {}; const { t } = useTranslation('wizards'); const [selectedMethod, setSelectedMethod] = useState<'manual' | 'upload'>( data.entryMethod || 'manual' ); const handleSelect = (method: 'manual' | 'upload') => { setSelectedMethod(method); const newData = { ...data, entryMethod: method }; onDataChange?.(newData); // Automatically advance to next step after selection setTimeout(() => onNext?.(), 100); }; return (

{t('salesEntry.entryMethod.title')}

{t('salesEntry.entryMethod.subtitle')}

{/* Manual Entry Option */} {/* File Upload Option */}
); }; // ======================================== // STEP 2a: Manual Entry Form // ======================================== const ManualEntryStep: React.FC = ({ dataRef, onDataChange, onNext }) => { const data = dataRef?.current || {}; const { t } = useTranslation('wizards'); const { currentTenant } = useTenant(); const [products, setProducts] = useState([]); const [loadingProducts, setLoadingProducts] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetchProducts(); }, []); const fetchProducts = async () => { if (!currentTenant?.id) return; setLoadingProducts(true); try { const result = await inventoryService.getIngredients(currentTenant.id); // Filter for finished products only const finishedProducts = result.filter((p: any) => p.category === 'finished_product'); setProducts(finishedProducts); } catch (err: any) { console.error('Error fetching products:', err); setError(t('salesEntry.messages.errorLoadingProducts')); } finally { setLoadingProducts(false); } }; const handleAddItem = () => { const newItems = [ ...(data.salesItems || []), { id: Date.now(), productId: '', product: '', quantity: 1, unitPrice: 0, subtotal: 0 }, ]; onDataChange?.({ ...data, salesItems: newItems }); }; const handleUpdateItem = (index: number, field: string, value: any) => { const updated = (data.salesItems || []).map((item: any, i: number) => { if (i === index) { const newItem = { ...item, [field]: value }; // If product is selected, auto-fill price if (field === 'productId') { const selectedProduct = products.find((p: any) => p.id === value); if (selectedProduct) { newItem.product = selectedProduct.name; newItem.unitPrice = selectedProduct.average_cost || selectedProduct.last_purchase_price || 0; } } // Auto-calculate subtotal if (field === 'quantity' || field === 'unitPrice' || field === 'productId') { newItem.subtotal = (newItem.quantity || 0) * (newItem.unitPrice || 0); } return newItem; } return item; }); onDataChange?.({ ...data, salesItems: updated }); }; const handleRemoveItem = (index: number) => { const newItems = (data.salesItems || []).filter((_: any, i: number) => i !== index); onDataChange?.({ ...data, salesItems: newItems }); }; const calculateTotal = () => { return (data.salesItems || []).reduce((sum: number, item: any) => sum + (item.subtotal || 0), 0); }; // Auto-save totalAmount when items change useEffect(() => { onDataChange?.({ ...data, totalAmount: calculateTotal(), }); }, [data.salesItems]); return (

{t('salesEntry.manualEntry.title')}

{t('salesEntry.manualEntry.subtitle')}

{/* Date and Payment Method */}
onDataChange?.({ ...data, saleDate: 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)] bg-[var(--bg-primary)] text-[var(--text-primary)]" />
{error && (
{error}
)} {/* Sales Items */}
{loadingProducts ? (
{t('salesEntry.manualEntry.products.loading')}
) : products.length === 0 ? (

{t('salesEntry.manualEntry.products.noFinishedProducts')}

{t('salesEntry.manualEntry.products.addToInventory')}

) : (data.salesItems || []).length === 0 ? (

{t('salesEntry.manualEntry.products.noProductsAdded')}

{t('salesEntry.manualEntry.products.clickToBegin')}

) : (
{(data.salesItems || []).map((item: any, index: number) => (
handleUpdateItem(index, 'quantity', parseFloat(e.target.value) || 0) } className="w-full px-2 py-1.5 text-sm border border-[var(--border-secondary)] rounded focus:outline-none focus:ring-1 focus:ring-[var(--color-primary)]" min="0" step="1" />
handleUpdateItem(index, 'unitPrice', parseFloat(e.target.value) || 0) } className="w-full px-2 py-1.5 text-sm border border-[var(--border-secondary)] rounded focus:outline-none focus:ring-1 focus:ring-[var(--color-primary)]" min="0" step="0.01" />
€{item.subtotal.toFixed(2)}
))}
)} {/* Total */} {(data.salesItems || []).length > 0 && (
{t('salesEntry.manualEntry.products.total')} €{calculateTotal().toFixed(2)}
)}
{/* Notes */}