fix edit on products
This commit is contained in:
@@ -21,6 +21,8 @@ const Products = () => {
|
||||
const [selectedCategory, setSelectedCategory] = useState('');
|
||||
const [selectedType, setSelectedType] = useState('');
|
||||
const [activeTab, setActiveTab] = useState('shared'); // 'shared' or 'custom'
|
||||
const [editingProduct, setEditingProduct] = useState(null);
|
||||
const [showEditForm, setShowEditForm] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
@@ -88,6 +90,24 @@ const Products = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditProduct = (product) => {
|
||||
setEditingProduct(product);
|
||||
setShowEditForm(true);
|
||||
};
|
||||
|
||||
const handleUpdateProduct = async (productData) => {
|
||||
try {
|
||||
await productsAPI.updateUserProduct(editingProduct.id, productData);
|
||||
toast.success('Product updated successfully!');
|
||||
setShowEditForm(false);
|
||||
setEditingProduct(null);
|
||||
fetchData();
|
||||
} catch (error) {
|
||||
console.error('Failed to update product:', error);
|
||||
toast.error('Failed to update product');
|
||||
}
|
||||
};
|
||||
|
||||
const ProductCard = ({ product, isUserProduct = false }) => (
|
||||
<div className="card">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
@@ -105,9 +125,13 @@ const Products = () => {
|
||||
<span className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium mt-1 ${
|
||||
product.productType === 'liquid'
|
||||
? 'bg-blue-100 text-blue-800'
|
||||
: 'bg-green-100 text-green-800'
|
||||
: product.productType === 'granular'
|
||||
? 'bg-green-100 text-green-800'
|
||||
: 'bg-gray-100 text-gray-800'
|
||||
}`}>
|
||||
{product.productType || 'Unknown'}
|
||||
{product.productType ?
|
||||
product.productType.charAt(0).toUpperCase() + product.productType.slice(1)
|
||||
: 'Type not set'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -115,7 +139,7 @@ const Products = () => {
|
||||
{isUserProduct && (
|
||||
<div className="flex gap-1">
|
||||
<button
|
||||
onClick={() => {/* Handle edit */}}
|
||||
onClick={() => handleEditProduct(product)}
|
||||
className="p-1 text-gray-400 hover:text-blue-600"
|
||||
>
|
||||
<PencilIcon className="h-4 w-4" />
|
||||
@@ -341,6 +365,20 @@ const Products = () => {
|
||||
categories={categories}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Edit Product Form Modal */}
|
||||
{showEditForm && editingProduct && (
|
||||
<EditProductModal
|
||||
product={editingProduct}
|
||||
onSubmit={handleUpdateProduct}
|
||||
onCancel={() => {
|
||||
setShowEditForm(false);
|
||||
setEditingProduct(null);
|
||||
}}
|
||||
sharedProducts={sharedProducts}
|
||||
categories={categories}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -538,4 +576,124 @@ const CreateProductModal = ({ onSubmit, onCancel, sharedProducts, categories })
|
||||
);
|
||||
};
|
||||
|
||||
// Edit Product Modal Component
|
||||
const EditProductModal = ({ product, onSubmit, onCancel, sharedProducts, categories }) => {
|
||||
const [formData, setFormData] = useState({
|
||||
productId: product.baseProductId || '',
|
||||
customName: product.customName || '',
|
||||
customRateAmount: product.customRateAmount || '',
|
||||
customRateUnit: product.customRateUnit || 'lbs/1000 sq ft',
|
||||
notes: product.notes || ''
|
||||
});
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!formData.productId && !formData.customName) {
|
||||
toast.error('Please select a base product or enter a custom name');
|
||||
return;
|
||||
}
|
||||
|
||||
const submitData = {
|
||||
productId: formData.productId ? parseInt(formData.productId) : null,
|
||||
customName: formData.customName || null,
|
||||
customRateAmount: formData.customRateAmount ? parseFloat(formData.customRateAmount) : null,
|
||||
customRateUnit: formData.customRateUnit || null,
|
||||
notes: formData.notes || null
|
||||
};
|
||||
|
||||
onSubmit(submitData);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div className="bg-white rounded-lg p-6 w-full max-w-lg max-h-[90vh] overflow-y-auto">
|
||||
<h3 className="text-lg font-semibold mb-4">Edit Product</h3>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label className="label">Base Product (Optional)</label>
|
||||
<select
|
||||
className="input"
|
||||
value={formData.productId}
|
||||
onChange={(e) => setFormData({ ...formData, productId: e.target.value })}
|
||||
>
|
||||
<option value="">Select a base product...</option>
|
||||
{sharedProducts.map((sharedProduct) => (
|
||||
<option key={sharedProduct.id} value={sharedProduct.id}>
|
||||
{sharedProduct.name} {sharedProduct.brand && `- ${sharedProduct.brand}`}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="label">Custom Name</label>
|
||||
<input
|
||||
type="text"
|
||||
className="input"
|
||||
value={formData.customName}
|
||||
onChange={(e) => setFormData({ ...formData, customName: e.target.value })}
|
||||
placeholder="e.g., My 24-0-11 Blend, Custom Herbicide Mix"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="label">Application Rate</label>
|
||||
<input
|
||||
type="number"
|
||||
step="0.01"
|
||||
className="input"
|
||||
value={formData.customRateAmount}
|
||||
onChange={(e) => setFormData({ ...formData, customRateAmount: e.target.value })}
|
||||
placeholder="2.5"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="label">Rate Unit</label>
|
||||
<select
|
||||
className="input"
|
||||
value={formData.customRateUnit}
|
||||
onChange={(e) => setFormData({ ...formData, customRateUnit: e.target.value })}
|
||||
>
|
||||
<option value="lbs/1000 sq ft">lbs/1000 sq ft</option>
|
||||
<option value="oz/1000 sq ft">oz/1000 sq ft</option>
|
||||
<option value="gal/acre">gal/acre</option>
|
||||
<option value="fl oz/1000 sq ft">fl oz/1000 sq ft</option>
|
||||
<option value="ml/1000 sq ft">ml/1000 sq ft</option>
|
||||
<option value="tbsp/1000 sq ft">tbsp/1000 sq ft</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="label">Notes</label>
|
||||
<textarea
|
||||
className="input"
|
||||
rows="3"
|
||||
value={formData.notes}
|
||||
onChange={(e) => setFormData({ ...formData, notes: e.target.value })}
|
||||
placeholder="Special mixing instructions, storage notes, etc."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 pt-4">
|
||||
<button type="submit" className="btn-primary flex-1">
|
||||
Update Product
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onCancel}
|
||||
className="btn-secondary flex-1"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Products;
|
||||
Reference in New Issue
Block a user