Agricultural Dashboard
Total Acreage
0
Total Costs to Date
$0
Estimated Revenue
$0
Est. Profitability
$0/acre
Field Status
Alerts & Notifications
Select a field from the "Farm Overview" map to see details.
Global Parameters
Manage Crop Types
Manage Resource Types
Select a field from the "Farm Overview" map to see details.
`; }; const renderOverview = () => { const fieldMap = document.getElementById('field-map'); const alertsList = document.getElementById('alerts-list'); fieldMap.innerHTML = ''; alertsList.innerHTML = ''; let totalAcreage = 0, totalCosts = 0, totalEstRevenue = 0; const marketPrices = getMarketPrices(); sourceData.fields.forEach(field => { const planting = sourceData.plantings.find(p => p.FieldID === field.FieldID); totalAcreage += field.Acreage; const fieldActivities = sourceData.activities.filter(a => a.FieldID === field.FieldID); totalCosts += fieldActivities.reduce((sum, a) => sum + (a.Cost || 0), 0); const plot = document.createElement('div'); plot.className = 'field-plot'; plot.onclick = () => showFieldDetails(field.FieldID); if (!planting) { plot.innerHTML = `${field.FieldName}Fallow`; plot.classList.add('status-good'); } else { const harvestDate = new Date(planting.ExpectedHarvestDate + 'T00:00:00'); const diffDays = Math.ceil((harvestDate - today) / (1000 * 60 * 60 * 24)); plot.innerHTML = `${field.FieldName}${planting.CropType}`; totalEstRevenue += (planting.ExpectedYield * field.Acreage) * (marketPrices[planting.CropType] || 0); if (diffDays <= 7 && diffDays >= 0) { plot.classList.add('status-attention'); const li = document.createElement('li'); li.innerHTML = `⚠️ ${field.FieldName} harvest is due in ${diffDays} days.`; alertsList.appendChild(li); } else if (diffDays < 0) { plot.classList.add('status-alert'); const li = document.createElement('li'); li.innerHTML = `🔴 ${field.FieldName} is ready for harvest.`; li.className = 'alert-harvest'; alertsList.appendChild(li); } else { plot.classList.add('status-good'); } } fieldMap.appendChild(plot); }); if (alertsList.innerHTML === '') alertsList.innerHTML = `Details for ${field.FieldName}
`; if (planting) { const plantingDate = new Date(planting.PlantingDate + 'T00:00:00'); const daysSincePlanted = Math.floor((today - plantingDate) / (1000 * 60 * 60 * 24)); const fieldCosts = activities.reduce((sum, a) => sum + (a.Cost || 0), 0); content += `Crop
${planting.CropType}
Acreage
${field.Acreage}
Days Since Planting
${daysSincePlanted}
Costs for Field
${formatCurrency(fieldCosts)}
This field is currently fallow (no crop planted).
`; } view.innerHTML = content; tabs.details.click(); }; const renderCustomization = () => { const renderList = (key, listEl, deleteFn, addFn) => { listEl.innerHTML = ''; customizable[key].forEach((item, index) => { const li = document.createElement('li'); li.textContent = item; const btn = document.createElement('button'); btn.innerHTML = '×'; btn.className = 'ag-manager-delete-btn'; btn.onclick = () => { customizable[key].splice(index, 1); renderAll(); }; li.appendChild(btn); listEl.appendChild(li); }); }; renderList('crops', document.getElementById('crop-type-list')); renderList('resources', document.getElementById('resource-type-list')); // Render market price inputs const pricesContainer = document.getElementById('market-prices-container'); pricesContainer.innerHTML = ''; customizable.crops.forEach(crop => { const div = document.createElement('div'); div.className = 'setting-group'; div.style.display = 'inline-block'; div.style.margin = '10px'; div.innerHTML = ` `; pricesContainer.appendChild(div); }); document.querySelectorAll('.market-price-input').forEach(input => input.addEventListener('input', renderOverview)); }; const getMarketPrices = () => { const prices = {}; document.querySelectorAll('.market-price-input').forEach(input => { prices[input.dataset.crop] = parseFloat(input.value) || 0; }); return prices; }; // --- EVENT LISTENERS --- generateBtn.addEventListener('click', buildDashboard); document.getElementById('add-crop-btn').addEventListener('click', () => { const input = document.getElementById('new-crop-type'); const val = input.value.trim(); if(val && !customizable.crops.includes(val)) { customizable.crops.push(val); input.value=''; renderAll(); } }); document.getElementById('add-resource-btn').addEventListener('click', () => { const input = document.getElementById('new-resource-type'); const val = input.value.trim(); if(val && !customizable.resources.includes(val)) { customizable.resources.push(val); input.value=''; renderAll(); } }); window.agSwitchTab = (evt, tabName) => { if (evt.currentTarget.classList.contains('disabled')) return; document.querySelectorAll('#ag-dashboard-container .ag-tab-content').forEach(tc => tc.style.display = 'none'); document.querySelectorAll('#ag-dashboard-container .ag-tab-button').forEach(tl => tl.classList.remove('active')); document.getElementById(tabName).style.display = 'block'; evt.currentTarget.classList.add('active'); }; // --- INITIALIZATION --- loadSampleData(); });