fix map and stuff
This commit is contained in:
@@ -95,10 +95,10 @@ const applicationPlanSchema = Joi.object({
|
|||||||
lawnSectionId: Joi.number().integer().positive().required(),
|
lawnSectionId: Joi.number().integer().positive().required(),
|
||||||
equipmentId: Joi.number().integer().positive().required(),
|
equipmentId: Joi.number().integer().positive().required(),
|
||||||
plannedDate: Joi.date().required(),
|
plannedDate: Joi.date().required(),
|
||||||
notes: Joi.string(),
|
notes: Joi.string().allow('').optional(),
|
||||||
products: Joi.array().items(Joi.object({
|
products: Joi.array().items(Joi.object({
|
||||||
productId: Joi.number().integer().positive(),
|
productId: Joi.number().integer().positive().optional(),
|
||||||
userProductId: Joi.number().integer().positive(),
|
userProductId: Joi.number().integer().positive().optional(),
|
||||||
rateAmount: Joi.number().positive().required(),
|
rateAmount: Joi.number().positive().required(),
|
||||||
rateUnit: Joi.string().max(50).required()
|
rateUnit: Joi.string().max(50).required()
|
||||||
})).min(1).required()
|
})).min(1).required()
|
||||||
|
|||||||
@@ -355,9 +355,27 @@ const PropertyMap = ({
|
|||||||
|
|
||||||
{/* Existing sections */}
|
{/* Existing sections */}
|
||||||
{sections.map((section) => {
|
{sections.map((section) => {
|
||||||
if (!section.polygonData?.coordinates?.[0]) return null;
|
console.log('Section:', section);
|
||||||
|
|
||||||
|
// Handle both string and object polygon data
|
||||||
|
let polygonData = section.polygonData;
|
||||||
|
if (typeof polygonData === 'string') {
|
||||||
|
try {
|
||||||
|
polygonData = JSON.parse(polygonData);
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse polygon data:', e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!polygonData?.coordinates?.[0]) {
|
||||||
|
console.log('No coordinates found for section:', section.id);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const coordinates = polygonData.coordinates[0].map(([lng, lat]) => [lat, lng]);
|
||||||
|
console.log('Mapped coordinates:', coordinates);
|
||||||
|
|
||||||
const coordinates = section.polygonData.coordinates[0].map(([lng, lat]) => [lat, lng]);
|
|
||||||
const isInternallySelected = selectedSection?.id === section.id;
|
const isInternallySelected = selectedSection?.id === section.id;
|
||||||
const isExternallySelected = selectedSections.includes(section.id);
|
const isExternallySelected = selectedSections.includes(section.id);
|
||||||
const isSelected = isInternallySelected || isExternallySelected;
|
const isSelected = isInternallySelected || isExternallySelected;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
WrenchScrewdriverIcon,
|
WrenchScrewdriverIcon,
|
||||||
CalculatorIcon
|
CalculatorIcon
|
||||||
} from '@heroicons/react/24/outline';
|
} from '@heroicons/react/24/outline';
|
||||||
import { propertiesAPI, productsAPI, equipmentAPI, applicationsAPI } from '../../services/api';
|
import { propertiesAPI, productsAPI, equipmentAPI, applicationsAPI, nozzlesAPI } from '../../services/api';
|
||||||
import LoadingSpinner from '../../components/UI/LoadingSpinner';
|
import LoadingSpinner from '../../components/UI/LoadingSpinner';
|
||||||
import PropertyMap from '../../components/Maps/PropertyMap';
|
import PropertyMap from '../../components/Maps/PropertyMap';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
@@ -138,10 +138,12 @@ const Applications = () => {
|
|||||||
lawnSectionId: parseInt(areaId),
|
lawnSectionId: parseInt(areaId),
|
||||||
equipmentId: parseInt(planData.equipmentId),
|
equipmentId: parseInt(planData.equipmentId),
|
||||||
plannedDate: new Date().toISOString().split('T')[0], // Default to today
|
plannedDate: new Date().toISOString().split('T')[0], // Default to today
|
||||||
notes: planData.notes,
|
notes: planData.notes || '', // Ensure notes is never null/undefined
|
||||||
products: [{
|
products: [{
|
||||||
productId: planData.selectedProduct?.isShared ? parseInt(planData.selectedProduct.id) : null,
|
...(planData.selectedProduct?.isShared
|
||||||
userProductId: !planData.selectedProduct?.isShared ? parseInt(planData.selectedProduct.id) : null,
|
? { productId: parseInt(planData.selectedProduct.id) }
|
||||||
|
: { userProductId: parseInt(planData.selectedProduct.id) }
|
||||||
|
),
|
||||||
rateAmount: parseFloat(planData.selectedProduct?.customRateAmount || planData.selectedProduct?.rateAmount || 1),
|
rateAmount: parseFloat(planData.selectedProduct?.customRateAmount || planData.selectedProduct?.rateAmount || 1),
|
||||||
rateUnit: planData.selectedProduct?.customRateUnit || planData.selectedProduct?.rateUnit || 'per 1000sqft'
|
rateUnit: planData.selectedProduct?.customRateUnit || planData.selectedProduct?.rateUnit || 'per 1000sqft'
|
||||||
}]
|
}]
|
||||||
@@ -170,6 +172,7 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
const [properties, setProperties] = useState([]);
|
const [properties, setProperties] = useState([]);
|
||||||
const [products, setProducts] = useState([]);
|
const [products, setProducts] = useState([]);
|
||||||
const [equipment, setEquipment] = useState([]);
|
const [equipment, setEquipment] = useState([]);
|
||||||
|
const [nozzles, setNozzles] = useState([]);
|
||||||
const [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
const [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [loadingProperty, setLoadingProperty] = useState(false);
|
const [loadingProperty, setLoadingProperty] = useState(false);
|
||||||
@@ -181,6 +184,7 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
selectedProduct: null,
|
selectedProduct: null,
|
||||||
applicationType: '', // 'liquid' or 'granular'
|
applicationType: '', // 'liquid' or 'granular'
|
||||||
equipmentId: '',
|
equipmentId: '',
|
||||||
|
nozzleId: '',
|
||||||
notes: ''
|
notes: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -191,15 +195,17 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
const fetchPlanningData = async () => {
|
const fetchPlanningData = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const [propertiesResponse, productsResponse, equipmentResponse] = await Promise.all([
|
const [propertiesResponse, productsResponse, equipmentResponse, nozzlesResponse] = await Promise.all([
|
||||||
propertiesAPI.getAll(),
|
propertiesAPI.getAll(),
|
||||||
productsAPI.getAll(),
|
productsAPI.getAll(),
|
||||||
equipmentAPI.getAll()
|
equipmentAPI.getAll(),
|
||||||
|
nozzlesAPI.getAll()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
console.log('Properties response:', propertiesResponse.data);
|
console.log('Properties response:', propertiesResponse.data);
|
||||||
console.log('Products response:', productsResponse.data);
|
console.log('Products response:', productsResponse.data);
|
||||||
console.log('Equipment response:', equipmentResponse.data);
|
console.log('Equipment response:', equipmentResponse.data);
|
||||||
|
console.log('Nozzles response:', nozzlesResponse.data);
|
||||||
|
|
||||||
setProperties(propertiesResponse.data.data.properties || []);
|
setProperties(propertiesResponse.data.data.properties || []);
|
||||||
// Combine shared and user products with unique IDs
|
// Combine shared and user products with unique IDs
|
||||||
@@ -218,6 +224,7 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
const allProducts = [...sharedProducts, ...userProducts];
|
const allProducts = [...sharedProducts, ...userProducts];
|
||||||
setProducts(allProducts);
|
setProducts(allProducts);
|
||||||
setEquipment(equipmentResponse.data.data.equipment || []);
|
setEquipment(equipmentResponse.data.data.equipment || []);
|
||||||
|
setNozzles(nozzlesResponse.data.data?.nozzles || nozzlesResponse.data || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch planning data:', error);
|
console.error('Failed to fetch planning data:', error);
|
||||||
toast.error('Failed to load planning data');
|
toast.error('Failed to load planning data');
|
||||||
@@ -335,6 +342,7 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
{selectedPropertyDetails.latitude && selectedPropertyDetails.longitude && (
|
{selectedPropertyDetails.latitude && selectedPropertyDetails.longitude && (
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
|
{console.log('Map sections data:', selectedPropertyDetails.sections)}
|
||||||
<PropertyMap
|
<PropertyMap
|
||||||
center={[selectedPropertyDetails.latitude, selectedPropertyDetails.longitude]}
|
center={[selectedPropertyDetails.latitude, selectedPropertyDetails.longitude]}
|
||||||
zoom={18}
|
zoom={18}
|
||||||
@@ -474,6 +482,36 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Nozzle Selection for Liquid Applications */}
|
||||||
|
{planData.applicationType === 'liquid' && (
|
||||||
|
<div>
|
||||||
|
<label className="label flex items-center gap-2">
|
||||||
|
<BeakerIcon className="h-5 w-5" />
|
||||||
|
Nozzle Selection
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
className="input"
|
||||||
|
value={planData.nozzleId}
|
||||||
|
onChange={(e) => setPlanData({ ...planData, nozzleId: e.target.value })}
|
||||||
|
>
|
||||||
|
<option value="">Select nozzle (optional)...</option>
|
||||||
|
{nozzles.map((nozzle) => (
|
||||||
|
<option key={nozzle.id} value={nozzle.id}>
|
||||||
|
{nozzle.customName || nozzle.typeName}
|
||||||
|
{nozzle.orificeSize && ` - ${nozzle.orificeSize}`}
|
||||||
|
{nozzle.flowRateGpm && ` (${nozzle.flowRateGpm} GPM)`}
|
||||||
|
{nozzle.sprayAngle && ` ${nozzle.sprayAngle}°`}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
{nozzles.length === 0 && (
|
||||||
|
<p className="text-sm text-orange-600 mt-1">
|
||||||
|
No nozzles found. Add nozzles in Equipment management first.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Notes */}
|
{/* Notes */}
|
||||||
<div>
|
<div>
|
||||||
<label className="label">Notes</label>
|
<label className="label">Notes</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user