import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { productSheetService } from '../../services/api'; import useFormatters from '../../hooks/useFormatters'; const ProductSheetModal = ({ sheet, settings, onSave, onClose }) => { const { t } = useTranslation(); const { currency } = useFormatters(); const isEditing = !!sheet; const [formData, setFormData] = useState({ name: '', sku: '', description: '', category: '', currency: 'EUR', business_setting_id: '', is_active: true, // Strategic pricing fields competitor_price: '', min_price: '', max_price: '', premium_multiplier: '1.00', price_strategy: 'neutral', psychological_rounding: false, target_margin_percent: '', }); const [items, setItems] = useState([]); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const [showStrategicPricing, setShowStrategicPricing] = useState(false); const itemTypes = [ { value: 'product_cost', label: t('business.products.itemTypes.productCost') }, { value: 'packaging', label: t('business.products.itemTypes.packaging') }, { value: 'label', label: t('business.products.itemTypes.label') }, { value: 'shipping', label: t('business.products.itemTypes.shipping') }, { value: 'handling', label: t('business.products.itemTypes.handling') }, { value: 'other', label: t('business.products.itemTypes.other') }, ]; useEffect(() => { if (sheet) { setFormData({ name: sheet.name || '', sku: sheet.sku || '', description: sheet.description || '', category: sheet.category || '', currency: sheet.currency || 'EUR', business_setting_id: sheet.business_setting_id || '', is_active: sheet.is_active ?? true, // Strategic pricing fields competitor_price: sheet.competitor_price || '', min_price: sheet.min_price || '', max_price: sheet.max_price || '', premium_multiplier: sheet.premium_multiplier || '1.00', price_strategy: sheet.price_strategy || 'neutral', psychological_rounding: sheet.psychological_rounding ?? false, target_margin_percent: sheet.target_margin_percent || '', }); setItems(sheet.items?.map(item => ({ id: item.id, name: item.name, type: item.type, amount: item.amount, quantity: item.quantity || 1, unit: item.unit || '', })) || []); // Show strategic pricing if any field is set if (sheet.competitor_price || sheet.min_price || sheet.max_price || sheet.target_margin_percent || sheet.price_strategy !== 'neutral') { setShowStrategicPricing(true); } } }, [sheet]); const handleChange = (e) => { const { name, value, type, checked } = e.target; setFormData(prev => ({ ...prev, [name]: type === 'checkbox' ? checked : value, })); }; const handleItemChange = (index, field, value) => { setItems(prev => prev.map((item, i) => i === index ? { ...item, [field]: value } : item )); }; const addItem = () => { setItems(prev => [...prev, { name: '', type: 'product_cost', amount: '', quantity: 1, unit: '', }]); }; const removeItem = (index) => { setItems(prev => prev.filter((_, i) => i !== index)); }; // Calcular CMV total const calculateCmv = () => { return items.reduce((sum, item) => { const amount = parseFloat(item.amount) || 0; const quantity = parseFloat(item.quantity) || 1; return sum + (amount / quantity); }, 0); }; // Calcular preço de venda preview const calculateSalePrice = () => { if (!formData.business_setting_id) return null; const setting = settings.find(s => s.id === parseInt(formData.business_setting_id)); if (!setting || !setting.markup_factor) return null; return calculateCmv() * setting.markup_factor; }; const handleSubmit = async (e) => { e.preventDefault(); setSaving(true); setError(null); // Validar itens const validItems = items.filter(item => item.name && item.amount); try { const dataToSend = { ...formData, business_setting_id: formData.business_setting_id || null, items: validItems.map(item => ({ name: item.name, type: item.type, amount: parseFloat(item.amount) || 0, quantity: parseFloat(item.quantity) || 1, unit: item.unit || null, })), }; let result; if (isEditing) { // Para edição, primeiro atualiza a ficha, depois gerencia itens result = await productSheetService.update(sheet.id, { name: formData.name, sku: formData.sku, description: formData.description, category: formData.category, currency: formData.currency, business_setting_id: formData.business_setting_id || null, is_active: formData.is_active, // Strategic pricing fields competitor_price: formData.competitor_price ? parseFloat(formData.competitor_price) : null, min_price: formData.min_price ? parseFloat(formData.min_price) : null, max_price: formData.max_price ? parseFloat(formData.max_price) : null, premium_multiplier: parseFloat(formData.premium_multiplier) || 1.0, price_strategy: formData.price_strategy, psychological_rounding: formData.psychological_rounding, target_margin_percent: formData.target_margin_percent ? parseFloat(formData.target_margin_percent) : null, }); // Remover itens que não existem mais const existingIds = items.filter(i => i.id).map(i => i.id); for (const oldItem of sheet.items || []) { if (!existingIds.includes(oldItem.id)) { await productSheetService.removeItem(sheet.id, oldItem.id); } } // Atualizar ou criar itens for (const item of validItems) { if (item.id) { await productSheetService.updateItem(sheet.id, item.id, { name: item.name, type: item.type, amount: parseFloat(item.amount) || 0, quantity: parseFloat(item.quantity) || 1, unit: item.unit || null, }); } else { await productSheetService.addItem(sheet.id, { name: item.name, type: item.type, amount: parseFloat(item.amount) || 0, quantity: parseFloat(item.quantity) || 1, unit: item.unit || null, }); } } // Recalcular preço if (formData.business_setting_id) { result = await productSheetService.recalculatePrice(sheet.id, formData.business_setting_id); } else { result = await productSheetService.getById(sheet.id); } } else { result = await productSheetService.create(dataToSend); } onSave(result); } catch (err) { setError(err.response?.data?.message || err.response?.data?.errors || t('common.error')); } finally { setSaving(false); } }; const currencies = ['EUR', 'USD', 'BRL', 'GBP']; const cmvTotal = calculateCmv(); const salePrice = calculateSalePrice(); return (
{isEditing ? t('business.products.edit') : t('business.products.add')}
{error && (
{typeof error === 'string' ? error : JSON.stringify(error)}
)}
{/* Info básica */}