import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSupplierPriceLists, useCreateSupplierPriceList, useUpdateSupplierPriceList, useDeleteSupplierPriceList } from '../../../../api/hooks/suppliers'; import { useIngredients } from '../../../../api/hooks/inventory'; import type { SupplierPriceListCreate, SupplierPriceListResponse } from '../../../../api/types/suppliers'; import { QuickAddIngredientModal } from '../../inventory/QuickAddIngredientModal'; interface SupplierProductManagerProps { tenantId: string; supplierId: string; supplierName: string; } interface ProductFormData { inventory_product_id: string; product_name?: string; unit_price: string; unit_of_measure: string; minimum_order_quantity: string; } export const SupplierProductManager: React.FC = ({ tenantId, supplierId, supplierName }) => { const { t } = useTranslation(); // Fetch existing price lists for this supplier const { data: priceLists = [], isLoading: priceListsLoading } = useSupplierPriceLists( tenantId, supplierId, true // only active ); // Fetch all inventory items const { data: inventoryItems = [], isLoading: inventoryLoading } = useIngredients(tenantId); // Mutations const createPriceListMutation = useCreateSupplierPriceList(); const updatePriceListMutation = useUpdateSupplierPriceList(); const deletePriceListMutation = useDeleteSupplierPriceList(); // UI State const [isExpanded, setIsExpanded] = useState(false); const [isAdding, setIsAdding] = useState(false); const [editingId, setEditingId] = useState(null); const [selectedProducts, setSelectedProducts] = useState([]); const [productForms, setProductForms] = useState>({}); const [errors, setErrors] = useState>({}); // Quick add modal state const [showQuickAddModal, setShowQuickAddModal] = useState(false); // Filter available products (not already in price list) const availableProducts = inventoryItems.filter( item => !priceLists.some(pl => pl.inventory_product_id === item.id) ); const handleToggleProduct = (productId: string) => { setSelectedProducts(prev => { if (prev.includes(productId)) { // Remove const newSelected = prev.filter(id => id !== productId); const newForms = { ...productForms }; delete newForms[productId]; setProductForms(newForms); return newSelected; } else { // Add with default form const product = inventoryItems.find(p => p.id === productId); setProductForms(prev => ({ ...prev, [productId]: { inventory_product_id: productId, product_name: product?.name || '', unit_price: '', unit_of_measure: product?.unit_of_measure || 'kg', minimum_order_quantity: '1' } })); return [...prev, productId]; } }); }; // Quick add handlers const handleIngredientCreated = (ingredient: any) => { // Ingredient created - auto-select it handleToggleProduct(ingredient.id); setShowQuickAddModal(false); }; const handleUpdateForm = (productId: string, field: string, value: string) => { setProductForms(prev => ({ ...prev, [productId]: { ...prev[productId], [field]: value } })); }; const validateForms = (): boolean => { const newErrors: Record = {}; selectedProducts.forEach(productId => { const form = productForms[productId]; if (!form.unit_price || parseFloat(form.unit_price) <= 0) { newErrors[`${productId}_price`] = 'Price must be greater than 0'; } if (!form.unit_of_measure) { newErrors[`${productId}_unit`] = 'Unit of measure is required'; } }); setErrors(newErrors); return Object.keys(newErrors).length === 0; }; const handleSaveProducts = async () => { if (!validateForms()) return; try { const promises = selectedProducts.map(productId => { const form = productForms[productId]; const priceListData: SupplierPriceListCreate = { inventory_product_id: form.inventory_product_id, unit_price: parseFloat(form.unit_price), unit_of_measure: form.unit_of_measure, minimum_order_quantity: form.minimum_order_quantity ? parseInt(form.minimum_order_quantity) : 1, price_per_unit: parseFloat(form.unit_price), // Same as unit_price for now is_active: true }; return createPriceListMutation.mutateAsync({ tenantId, supplierId, priceListData }); }); await Promise.all(promises); // Reset form setSelectedProducts([]); setProductForms({}); setIsAdding(false); } catch (error) { console.error('Error saving products:', error); } }; const handleDeleteProduct = async (priceListId: string) => { if (!window.confirm(t('common:confirm_delete', 'Are you sure?'))) return; try { await deletePriceListMutation.mutateAsync({ tenantId, supplierId, priceListId }); } catch (error) { console.error('Error deleting product:', error); } }; const getProductName = (inventoryProductId: string) => { const product = inventoryItems.find(p => p.id === inventoryProductId); return product?.name || inventoryProductId; }; if (!isExpanded) { return (
); } return (
{/* Header */}
{t('setup_wizard:suppliers.products_for', 'Products for {{name}}', { name: supplierName })}
{/* Existing products */} {priceLists.length > 0 && (
{priceLists.map((priceList) => (
{getProductName(priceList.inventory_product_id)} €{priceList.unit_price.toFixed(2)}/{priceList.unit_of_measure} {priceList.minimum_order_quantity && priceList.minimum_order_quantity > 1 && ( (Min: {priceList.minimum_order_quantity}) )}
))}
)} {/* Add products section */} {!isAdding && ( )} {/* Product selection form */} {isAdding && (

{t('setup_wizard:suppliers.select_products', 'Select Products')}

{/* Product checkboxes */}
{availableProducts.map(product => (
{/* Price form for selected products */} {selectedProducts.includes(product.id) && productForms[product.id] && (
handleUpdateForm(product.id, 'unit_price', e.target.value)} className={`w-full px-2 py-1 text-sm bg-[var(--bg-primary)] border ${ errors[`${product.id}_price`] ? 'border-[var(--color-error)]' : 'border-[var(--border-secondary)]' } rounded focus:outline-none focus:ring-1 focus:ring-[var(--color-primary)] text-[var(--text-primary)]`} placeholder="0.00" />
handleUpdateForm(product.id, 'minimum_order_quantity', e.target.value)} className="w-full px-2 py-1 text-sm bg-[var(--bg-primary)] border border-[var(--border-secondary)] rounded focus:outline-none focus:ring-1 focus:ring-[var(--color-primary)] text-[var(--text-primary)]" />
)}
))} {/* Add New Product Button */}
{/* Actions */} {selectedProducts.length > 0 && (
)}
)} {/* Warning if no products */} {priceLists.length === 0 && !isAdding && (
⚠️ {t('setup_wizard:suppliers.no_products_warning', 'Add at least 1 product to enable automatic purchase orders')}
)} {/* Quick Add Ingredient Modal */} setShowQuickAddModal(false)} onCreated={handleIngredientCreated} tenantId={tenantId} context="supplier" />
); };