application update again
This commit is contained in:
@@ -104,7 +104,9 @@ 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 [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [loadingProperty, setLoadingProperty] = useState(false);
|
||||||
|
|
||||||
const [planData, setPlanData] = useState({
|
const [planData, setPlanData] = useState({
|
||||||
propertyId: '',
|
propertyId: '',
|
||||||
@@ -124,12 +126,21 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const [propertiesResponse, productsResponse, equipmentResponse] = await Promise.all([
|
const [propertiesResponse, productsResponse, equipmentResponse] = await Promise.all([
|
||||||
propertiesAPI.getAll(),
|
propertiesAPI.getAll(),
|
||||||
productsAPI.getUserProducts(),
|
productsAPI.getAll(),
|
||||||
equipmentAPI.getAll()
|
equipmentAPI.getAll()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
console.log('Properties response:', propertiesResponse.data);
|
||||||
|
console.log('Products response:', productsResponse.data);
|
||||||
|
console.log('Equipment response:', equipmentResponse.data);
|
||||||
|
|
||||||
setProperties(propertiesResponse.data.data.properties || []);
|
setProperties(propertiesResponse.data.data.properties || []);
|
||||||
setProducts(productsResponse.data.data.products || []);
|
// Combine shared and user products
|
||||||
|
const allProducts = [
|
||||||
|
...(productsResponse.data.data.sharedProducts || []),
|
||||||
|
...(productsResponse.data.data.userProducts || [])
|
||||||
|
];
|
||||||
|
setProducts(allProducts);
|
||||||
setEquipment(equipmentResponse.data.data.equipment || []);
|
setEquipment(equipmentResponse.data.data.equipment || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch planning data:', error);
|
console.error('Failed to fetch planning data:', error);
|
||||||
@@ -139,7 +150,28 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedProperty = properties.find(p => p.id === parseInt(planData.propertyId));
|
const fetchPropertyDetails = async (propertyId) => {
|
||||||
|
try {
|
||||||
|
setLoadingProperty(true);
|
||||||
|
const response = await propertiesAPI.getById(parseInt(propertyId));
|
||||||
|
console.log('Property details response:', response.data);
|
||||||
|
setSelectedPropertyDetails(response.data.data.property);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch property details:', error);
|
||||||
|
toast.error('Failed to load property details');
|
||||||
|
setSelectedPropertyDetails(null);
|
||||||
|
} finally {
|
||||||
|
setLoadingProperty(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePropertyChange = (propertyId) => {
|
||||||
|
setPlanData({ ...planData, propertyId, selectedAreas: [] });
|
||||||
|
setSelectedPropertyDetails(null);
|
||||||
|
if (propertyId) {
|
||||||
|
fetchPropertyDetails(propertyId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Filter equipment based on application type
|
// Filter equipment based on application type
|
||||||
const availableEquipment = equipment.filter(eq => {
|
const availableEquipment = equipment.filter(eq => {
|
||||||
@@ -199,7 +231,7 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
<select
|
<select
|
||||||
className="input"
|
className="input"
|
||||||
value={planData.propertyId}
|
value={planData.propertyId}
|
||||||
onChange={(e) => setPlanData({ ...planData, propertyId: e.target.value, selectedAreas: [] })}
|
onChange={(e) => handlePropertyChange(e.target.value)}
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="">Select a property...</option>
|
<option value="">Select a property...</option>
|
||||||
@@ -212,11 +244,18 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Area Selection */}
|
{/* Area Selection */}
|
||||||
{selectedProperty && selectedProperty.sections && selectedProperty.sections.length > 0 && (
|
{loadingProperty && (
|
||||||
|
<div className="flex items-center gap-2 text-gray-600">
|
||||||
|
<LoadingSpinner size="sm" />
|
||||||
|
<span>Loading property details...</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedPropertyDetails && selectedPropertyDetails.sections && selectedPropertyDetails.sections.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<label className="label">Application Areas *</label>
|
<label className="label">Application Areas *</label>
|
||||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
|
||||||
{selectedProperty.sections.map((section) => (
|
{selectedPropertyDetails.sections.map((section) => (
|
||||||
<label key={section.id} className="flex items-center">
|
<label key={section.id} className="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
@@ -225,21 +264,29 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
||||||
/>
|
/>
|
||||||
<span className="ml-2 text-sm">
|
<span className="ml-2 text-sm">
|
||||||
{section.name} ({section.sqFt ? `${section.sqFt} sq ft` : 'No size'})
|
{section.name} ({section.area ? `${Math.round(section.area)} sq ft` : 'No size'})
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{planData.selectedAreas.length > 0 && (
|
{planData.selectedAreas.length > 0 && (
|
||||||
<p className="text-sm text-gray-600 mt-2">
|
<p className="text-sm text-gray-600 mt-2">
|
||||||
Total area: {selectedProperty.sections
|
Total area: {selectedPropertyDetails.sections
|
||||||
.filter(s => planData.selectedAreas.includes(s.id))
|
.filter(s => planData.selectedAreas.includes(s.id))
|
||||||
.reduce((total, s) => total + (s.sqFt || 0), 0)} sq ft
|
.reduce((total, s) => total + (s.area || 0), 0).toFixed(0)} sq ft
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{selectedPropertyDetails && (!selectedPropertyDetails.sections || selectedPropertyDetails.sections.length === 0) && (
|
||||||
|
<div className="p-4 bg-yellow-50 border border-yellow-200 rounded-lg">
|
||||||
|
<p className="text-yellow-800 text-sm">
|
||||||
|
This property has no lawn sections defined. Please add lawn sections to the property first.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Product Selection */}
|
{/* Product Selection */}
|
||||||
<div>
|
<div>
|
||||||
<label className="label flex items-center gap-2">
|
<label className="label flex items-center gap-2">
|
||||||
@@ -251,21 +298,43 @@ const ApplicationPlanModal = ({ onClose, onSubmit }) => {
|
|||||||
value={planData.productId}
|
value={planData.productId}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const selectedProduct = products.find(p => p.id === parseInt(e.target.value));
|
const selectedProduct = products.find(p => p.id === parseInt(e.target.value));
|
||||||
|
console.log('Selected product:', selectedProduct);
|
||||||
|
|
||||||
|
// Determine application type from product type
|
||||||
|
let applicationType = '';
|
||||||
|
if (selectedProduct) {
|
||||||
|
const productType = selectedProduct.productType || selectedProduct.customProductType;
|
||||||
|
// Map product types to application types
|
||||||
|
if (productType && (productType.toLowerCase().includes('liquid') || productType.toLowerCase().includes('concentrate'))) {
|
||||||
|
applicationType = 'liquid';
|
||||||
|
} else if (productType && (productType.toLowerCase().includes('granular') || productType.toLowerCase().includes('granule'))) {
|
||||||
|
applicationType = 'granular';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setPlanData({
|
setPlanData({
|
||||||
...planData,
|
...planData,
|
||||||
productId: e.target.value,
|
productId: e.target.value,
|
||||||
applicationType: selectedProduct?.applicationType || ''
|
applicationType: applicationType
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
required
|
required
|
||||||
>
|
>
|
||||||
<option value="">Select a product...</option>
|
<option value="">Select a product...</option>
|
||||||
{products.map((product) => (
|
{products.map((product) => {
|
||||||
|
const displayName = product.customName || product.name;
|
||||||
|
const productType = product.productType || product.customProductType;
|
||||||
|
const brand = product.brand || product.customBrand;
|
||||||
|
const rateInfo = product.customRateAmount && product.customRateUnit
|
||||||
|
? ` (${product.customRateAmount} ${product.customRateUnit})`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
return (
|
||||||
<option key={product.id} value={product.id}>
|
<option key={product.id} value={product.id}>
|
||||||
{product.name} - {product.applicationType}
|
{displayName}{brand ? ` - ${brand}` : ''}{productType ? ` (${productType})` : ''}{rateInfo}
|
||||||
{product.applicationRate && ` (${product.applicationRate} ${product.applicationRateUnit})`}
|
|
||||||
</option>
|
</option>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user