diff --git a/frontend/src/components/Applications/ApplicationPlanModal.js b/frontend/src/components/Applications/ApplicationPlanModal.js index a8e1149..d940963 100644 --- a/frontend/src/components/Applications/ApplicationPlanModal.js +++ b/frontend/src/components/Applications/ApplicationPlanModal.js @@ -1,9 +1,402 @@ -// This is a placeholder - the ApplicationPlanModal component was in the main file -// We need to extract it to this separate file for better organization -// For now, the modal functionality is temporarily unavailable until we recreate it +import React, { useState, useEffect } from 'react'; +import { XMarkIcon, MapPinIcon, WrenchScrewdriverIcon, BeakerIcon } from '@heroicons/react/24/outline'; +import PropertyMap from '../Maps/PropertyMap'; +import toast from 'react-hot-toast'; -const ApplicationPlanModal = () => { - return
ApplicationPlanModal - To be implemented
; +const ApplicationPlanModal = ({ + onClose, + properties, + products, + equipment, + nozzles, + selectedPropertyDetails, + onPropertySelect, + editingPlan, + onSubmit +}) => { + const [selectedPropertyId, setSelectedPropertyId] = useState(''); + const [selectedAreas, setSelectedAreas] = useState([]); + const [selectedEquipmentId, setSelectedEquipmentId] = useState(''); + const [selectedNozzleId, setSelectedNozzleId] = useState(''); + const [selectedProducts, setSelectedProducts] = useState([]); + const [plannedDate, setPlannedDate] = useState(''); + const [notes, setNotes] = useState(''); + const [loading, setLoading] = useState(false); + + // Initialize form with editing data if provided + useEffect(() => { + if (editingPlan) { + setSelectedPropertyId(editingPlan.propertyId || ''); + setSelectedAreas(editingPlan.selectedAreas || []); + setSelectedEquipmentId(editingPlan.equipmentId || ''); + setSelectedNozzleId(editingPlan.nozzleId || ''); + setSelectedProducts(editingPlan.products || []); + setPlannedDate(editingPlan.plannedDate || ''); + setNotes(editingPlan.notes || ''); + } + }, [editingPlan]); + + // Handle property selection + const handlePropertyChange = async (propertyId) => { + setSelectedPropertyId(propertyId); + setSelectedAreas([]); // Clear selected areas when property changes + + if (propertyId && onPropertySelect) { + await onPropertySelect(propertyId); + } + }; + + // Handle area selection on map + const handleAreaClick = (area) => { + setSelectedAreas(prev => { + if (prev.includes(area.id)) { + return prev.filter(id => id !== area.id); + } else { + return [...prev, area.id]; + } + }); + }; + + // Add product to plan + const addProduct = () => { + setSelectedProducts(prev => [...prev, { + productId: null, + userProductId: null, + rateAmount: '', + rateUnit: 'oz/1000sqft', + isUserProduct: false + }]); + }; + + // Remove product from plan + const removeProduct = (index) => { + setSelectedProducts(prev => prev.filter((_, i) => i !== index)); + }; + + // Update product in plan + const updateProduct = (index, field, value) => { + setSelectedProducts(prev => prev.map((product, i) => + i === index ? { ...product, [field]: value } : product + )); + }; + + // Handle form submission + const handleSubmit = async (e) => { + e.preventDefault(); + + // Validation + if (!selectedPropertyId) { + toast.error('Please select a property'); + return; + } + if (selectedAreas.length === 0) { + toast.error('Please select at least one area'); + return; + } + if (!selectedEquipmentId) { + toast.error('Please select equipment'); + return; + } + if (selectedProducts.length === 0) { + toast.error('Please add at least one product'); + return; + } + if (!plannedDate) { + toast.error('Please select a planned date'); + return; + } + + // Validate products have required fields + for (const product of selectedProducts) { + if (!product.productId && !product.userProductId) { + toast.error('Please select a product for all entries'); + return; + } + if (!product.rateAmount) { + toast.error('Please enter rate amount for all products'); + return; + } + } + + setLoading(true); + + try { + const planData = { + propertyId: parseInt(selectedPropertyId), + selectedAreas, + equipmentId: selectedEquipmentId, + nozzleId: selectedNozzleId || null, + products: selectedProducts, + plannedDate, + notes + }; + + await onSubmit(planData); + onClose(); + } catch (error) { + console.error('Failed to submit plan:', error); + toast.error('Failed to save application plan'); + } finally { + setLoading(false); + } + }; + + return ( +
+
+ {/* Header */} +
+

+ {editingPlan ? 'Edit Application Plan' : 'Plan New Application'} +

+ +
+ +
+
+ {/* Left Column - Form */} +
+ {/* Property Selection */} +
+ + +
+ + {/* Equipment Selection */} +
+ + +
+ + {/* Nozzle Selection (for sprayers) */} + {selectedEquipmentId && equipment.find(eq => eq.id == selectedEquipmentId)?.type === 'sprayer' && ( +
+ + +
+ )} + + {/* Planned Date */} +
+ + setPlannedDate(e.target.value)} + className="w-full border border-gray-300 rounded px-3 py-2" + required + /> +
+ + {/* Products */} +
+
+ + +
+ + {selectedProducts.map((product, index) => ( +
+
+ + +
+ updateProduct(index, 'rateAmount', e.target.value)} + className="border border-gray-300 rounded px-2 py-1 flex-1" + required + /> + +
+ + +
+
+ ))} + + {selectedProducts.length === 0 && ( +

No products added yet

+ )} +
+ + {/* Notes */} +
+ +