product updates
This commit is contained in:
@@ -76,11 +76,11 @@ const productRateSchema = Joi.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const userProductSchema = Joi.object({
|
const userProductSchema = Joi.object({
|
||||||
productId: Joi.number().integer().positive(),
|
productId: Joi.number().integer().positive().allow(null).optional(),
|
||||||
customName: Joi.string().max(255),
|
customName: Joi.string().max(255).allow(null).optional(),
|
||||||
customRateAmount: Joi.number().positive(),
|
customRateAmount: Joi.number().positive().allow(null).optional(),
|
||||||
customRateUnit: Joi.string().max(50),
|
customRateUnit: Joi.string().max(50).allow(null).optional(),
|
||||||
notes: Joi.string()
|
notes: Joi.string().allow(null, '').optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Application validation schemas
|
// Application validation schemas
|
||||||
|
|||||||
@@ -350,6 +350,10 @@ const CreateProductModal = ({ onSubmit, onCancel, sharedProducts, categories })
|
|||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
productId: '',
|
productId: '',
|
||||||
customName: '',
|
customName: '',
|
||||||
|
categoryId: '',
|
||||||
|
productType: 'granular',
|
||||||
|
brand: '',
|
||||||
|
activeIngredients: '',
|
||||||
customRateAmount: '',
|
customRateAmount: '',
|
||||||
customRateUnit: 'lbs/1000 sq ft',
|
customRateUnit: 'lbs/1000 sq ft',
|
||||||
notes: ''
|
notes: ''
|
||||||
@@ -363,6 +367,12 @@ const CreateProductModal = ({ onSubmit, onCancel, sharedProducts, categories })
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If creating a completely custom product (no base product), require more fields
|
||||||
|
if (!formData.productId && (!formData.categoryId || !formData.productType)) {
|
||||||
|
toast.error('Please select a category and product type for custom products');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const submitData = {
|
const submitData = {
|
||||||
productId: formData.productId ? parseInt(formData.productId) : null,
|
productId: formData.productId ? parseInt(formData.productId) : null,
|
||||||
customName: formData.customName || null,
|
customName: formData.customName || null,
|
||||||
@@ -413,6 +423,63 @@ const CreateProductModal = ({ onSubmit, onCancel, sharedProducts, categories })
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Show additional fields when creating completely custom product */}
|
||||||
|
{!formData.productId && (
|
||||||
|
<>
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div>
|
||||||
|
<label className="label">Category *</label>
|
||||||
|
<select
|
||||||
|
className="input"
|
||||||
|
value={formData.categoryId}
|
||||||
|
onChange={(e) => setFormData({ ...formData, categoryId: e.target.value })}
|
||||||
|
required={!formData.productId}
|
||||||
|
>
|
||||||
|
<option value="">Select category...</option>
|
||||||
|
{categories.map((category) => (
|
||||||
|
<option key={category.id} value={category.id}>
|
||||||
|
{category.name}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="label">Product Type *</label>
|
||||||
|
<select
|
||||||
|
className="input"
|
||||||
|
value={formData.productType}
|
||||||
|
onChange={(e) => setFormData({ ...formData, productType: e.target.value })}
|
||||||
|
>
|
||||||
|
<option value="granular">Granular</option>
|
||||||
|
<option value="liquid">Liquid</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="label">Brand</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input"
|
||||||
|
value={formData.brand}
|
||||||
|
onChange={(e) => setFormData({ ...formData, brand: e.target.value })}
|
||||||
|
placeholder="e.g., Scotts, Syngenta, Custom Mix"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="label">Active Ingredients</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input"
|
||||||
|
value={formData.activeIngredients}
|
||||||
|
onChange={(e) => setFormData({ ...formData, activeIngredients: e.target.value })}
|
||||||
|
placeholder="e.g., 2,4-D 25%, Nitrogen 24%, Iron 2%"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<div className="grid grid-cols-2 gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label className="label">Application Rate</label>
|
<label className="label">Application Rate</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user