asdfdsa
This commit is contained in:
@@ -24,6 +24,8 @@ const Applications = () => {
|
|||||||
const [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
const [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
||||||
const [editingPlan, setEditingPlan] = useState(null);
|
const [editingPlan, setEditingPlan] = useState(null);
|
||||||
const [propertyCache, setPropertyCache] = useState({});
|
const [propertyCache, setPropertyCache] = useState({});
|
||||||
|
const [spreaderRecommendation, setSpreaderRecommendation] = useState(null);
|
||||||
|
const [loadingRecommendation, setLoadingRecommendation] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchApplications();
|
fetchApplications();
|
||||||
@@ -432,6 +434,11 @@ const ApplicationPlanModal = ({
|
|||||||
}
|
}
|
||||||
}, [editingPlan, products]);
|
}, [editingPlan, products]);
|
||||||
|
|
||||||
|
// Load spreader recommendation when relevant fields change
|
||||||
|
useEffect(() => {
|
||||||
|
loadSpreaderRecommendation(planData.selectedProduct, planData.equipmentId, planData.selectedAreas);
|
||||||
|
}, [planData.selectedProduct, planData.equipmentId, planData.selectedAreas, selectedPropertyDetails, equipment]);
|
||||||
|
|
||||||
const handlePropertyChange = async (propertyId) => {
|
const handlePropertyChange = async (propertyId) => {
|
||||||
setPlanData({ ...planData, propertyId, selectedAreas: [] });
|
setPlanData({ ...planData, propertyId, selectedAreas: [] });
|
||||||
if (propertyId && propertyId !== selectedPropertyDetails?.id?.toString()) {
|
if (propertyId && propertyId !== selectedPropertyDetails?.id?.toString()) {
|
||||||
@@ -440,6 +447,104 @@ const ApplicationPlanModal = ({
|
|||||||
setLoadingProperty(false);
|
setLoadingProperty(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Load spreader recommendations when granular product and spreader are selected
|
||||||
|
const loadSpreaderRecommendation = async (product, equipmentId, selectedAreas) => {
|
||||||
|
if (!product || !equipmentId || !selectedAreas.length || product.productType !== 'granular') {
|
||||||
|
setSpreaderRecommendation(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoadingRecommendation(true);
|
||||||
|
try {
|
||||||
|
// Find the selected equipment details
|
||||||
|
const selectedEquipment = equipment.find(eq => eq.id === parseInt(equipmentId));
|
||||||
|
if (!selectedEquipment) {
|
||||||
|
setSpreaderRecommendation(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load spreader settings for this product
|
||||||
|
const productApiId = product.isShared ? product.id : product.id; // Use the actual product ID
|
||||||
|
const endpoint = product.isShared
|
||||||
|
? `/api/product-spreader-settings/product/${productApiId}`
|
||||||
|
: `/api/product-spreader-settings/user-product/${productApiId}`;
|
||||||
|
|
||||||
|
const response = await fetch(endpoint, {
|
||||||
|
headers: {
|
||||||
|
'Authorization': `Bearer ${localStorage.getItem('authToken')}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
setSpreaderRecommendation(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
const settings = data.data?.settings || [];
|
||||||
|
|
||||||
|
// Find a matching setting for this equipment
|
||||||
|
let matchingSetting = null;
|
||||||
|
|
||||||
|
// First try to find exact equipment match
|
||||||
|
matchingSetting = settings.find(setting =>
|
||||||
|
setting.equipmentId === selectedEquipment.id
|
||||||
|
);
|
||||||
|
|
||||||
|
// If no exact match, try to find by equipment brand/manufacturer
|
||||||
|
if (!matchingSetting && selectedEquipment.manufacturer) {
|
||||||
|
matchingSetting = settings.find(setting =>
|
||||||
|
setting.spreaderBrand &&
|
||||||
|
setting.spreaderBrand.toLowerCase().includes(selectedEquipment.manufacturer.toLowerCase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If still no match, use any available setting as fallback
|
||||||
|
if (!matchingSetting && settings.length > 0) {
|
||||||
|
matchingSetting = settings[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchingSetting) {
|
||||||
|
// Calculate total area and product amount needed
|
||||||
|
const totalArea = selectedAreas.reduce((sum, areaId) => {
|
||||||
|
const area = selectedPropertyDetails?.sections?.find(s => s.id === areaId);
|
||||||
|
return sum + (area?.area || 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
// Calculate product amount based on rate
|
||||||
|
const rateAmount = product.customRateAmount || product.rateAmount || 1;
|
||||||
|
const rateUnit = product.customRateUnit || product.rateUnit || 'lbs/1000 sq ft';
|
||||||
|
|
||||||
|
let productAmountLbs = 0;
|
||||||
|
if (rateUnit.includes('1000')) {
|
||||||
|
// Rate per 1000 sq ft
|
||||||
|
productAmountLbs = (rateAmount * totalArea) / 1000;
|
||||||
|
} else if (rateUnit.includes('acre')) {
|
||||||
|
// Rate per acre (43,560 sq ft)
|
||||||
|
productAmountLbs = (rateAmount * totalArea) / 43560;
|
||||||
|
} else {
|
||||||
|
// Assume rate per sq ft
|
||||||
|
productAmountLbs = rateAmount * totalArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSpreaderRecommendation({
|
||||||
|
setting: matchingSetting,
|
||||||
|
equipment: selectedEquipment,
|
||||||
|
totalArea,
|
||||||
|
productAmountLbs: Math.round(productAmountLbs * 100) / 100, // Round to 2 decimal places
|
||||||
|
isExactMatch: settings.some(s => s.equipmentId === selectedEquipment.id)
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setSpreaderRecommendation(null);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load spreader recommendation:', error);
|
||||||
|
setSpreaderRecommendation(null);
|
||||||
|
} finally {
|
||||||
|
setLoadingRecommendation(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Filter equipment based on application type
|
// Filter equipment based on application type
|
||||||
const availableEquipment = equipment.filter(eq => {
|
const availableEquipment = equipment.filter(eq => {
|
||||||
@@ -665,6 +770,63 @@ const ApplicationPlanModal = ({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Spreader Recommendation for Granular Applications */}
|
||||||
|
{planData.applicationType === 'granular' && (spreaderRecommendation || loadingRecommendation) && (
|
||||||
|
<div className="bg-green-50 border border-green-200 rounded-lg p-4">
|
||||||
|
<div className="flex items-center gap-2 mb-3">
|
||||||
|
<CalculatorIcon className="h-5 w-5 text-green-600" />
|
||||||
|
<h3 className="font-semibold text-green-800">Spreader Recommendation</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{loadingRecommendation ? (
|
||||||
|
<div className="text-sm text-green-700">Loading recommendation...</div>
|
||||||
|
) : spreaderRecommendation ? (
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div className="flex items-start justify-between">
|
||||||
|
<div className="space-y-1">
|
||||||
|
<p className="text-sm font-medium text-green-800">
|
||||||
|
Spreader Setting: <span className="text-lg font-bold">{spreaderRecommendation.setting.settingValue}</span>
|
||||||
|
</p>
|
||||||
|
<p className="text-sm text-green-700">
|
||||||
|
Product Amount: <span className="font-semibold">{spreaderRecommendation.productAmountLbs} lbs</span>
|
||||||
|
</p>
|
||||||
|
<p className="text-xs text-green-600">
|
||||||
|
Total Area: {spreaderRecommendation.totalArea.toLocaleString()} sq ft
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="text-right">
|
||||||
|
<div className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium ${
|
||||||
|
spreaderRecommendation.isExactMatch
|
||||||
|
? 'bg-green-100 text-green-800'
|
||||||
|
: 'bg-yellow-100 text-yellow-800'
|
||||||
|
}`}>
|
||||||
|
{spreaderRecommendation.isExactMatch ? 'Exact Match' : 'Approximate'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{spreaderRecommendation.setting.rateDescription && (
|
||||||
|
<p className="text-xs text-green-600 italic">
|
||||||
|
{spreaderRecommendation.setting.rateDescription}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{spreaderRecommendation.setting.notes && (
|
||||||
|
<p className="text-xs text-green-600">
|
||||||
|
Note: {spreaderRecommendation.setting.notes}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!spreaderRecommendation.isExactMatch && (
|
||||||
|
<p className="text-xs text-yellow-700 bg-yellow-50 rounded p-2 mt-2">
|
||||||
|
⚠️ This setting is based on a similar spreader. Please verify the setting is appropriate for your specific equipment.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Nozzle Selection for Liquid Applications */}
|
{/* Nozzle Selection for Liquid Applications */}
|
||||||
{planData.applicationType === 'liquid' && (
|
{planData.applicationType === 'liquid' && (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
Reference in New Issue
Block a user