asdfdsa
This commit is contained in:
@@ -24,6 +24,8 @@ const Applications = () => {
|
||||
const [selectedPropertyDetails, setSelectedPropertyDetails] = useState(null);
|
||||
const [editingPlan, setEditingPlan] = useState(null);
|
||||
const [propertyCache, setPropertyCache] = useState({});
|
||||
const [spreaderRecommendation, setSpreaderRecommendation] = useState(null);
|
||||
const [loadingRecommendation, setLoadingRecommendation] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetchApplications();
|
||||
@@ -432,6 +434,11 @@ const ApplicationPlanModal = ({
|
||||
}
|
||||
}, [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) => {
|
||||
setPlanData({ ...planData, propertyId, selectedAreas: [] });
|
||||
if (propertyId && propertyId !== selectedPropertyDetails?.id?.toString()) {
|
||||
@@ -440,6 +447,104 @@ const ApplicationPlanModal = ({
|
||||
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
|
||||
const availableEquipment = equipment.filter(eq => {
|
||||
@@ -665,6 +770,63 @@ const ApplicationPlanModal = ({
|
||||
</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 */}
|
||||
{planData.applicationType === 'liquid' && (
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user