Spaces:
Sleeping
Sleeping
{% extends "base.html" %} | |
{% block title %}Add Farm - Farm Management Portal{% endblock %} | |
{% block extra_css %} | |
<style> | |
#map { | |
height: 400px; | |
width: 100%; | |
border-radius: 8px; | |
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
margin-bottom: 20px; | |
} | |
.form-section { | |
background-color: #f8f9fa; | |
padding: 20px; | |
border-radius: 8px; | |
margin-bottom: 20px; | |
} | |
</style> | |
{% endblock %} | |
{% block content %} | |
<div class="container mt-4"> | |
<div class="row"> | |
<div class="col-12"> | |
<div class="card"> | |
<div class="card-header bg-success text-white"> | |
<h4><i class="fas fa-plus me-2"></i>Add New Farm</h4> | |
</div> | |
<div class="card-body"> | |
<form method="POST" id="farmForm"> | |
<div class="row"> | |
<!-- Farm Details --> | |
<div class="col-md-6"> | |
<div class="form-section"> | |
<h5><i class="fas fa-seedling me-2"></i>Farm Details</h5> | |
<div class="mb-3"> | |
<label for="farm_name" class="form-label">Farm Name *</label> | |
<input type="text" class="form-control" id="farm_name" name="farm_name" required> | |
</div> | |
<div class="row"> | |
<div class="col-md-6 mb-3"> | |
<label for="farm_size" class="form-label">Farm Size (Acres) *</label> | |
<input type="number" class="form-control" id="farm_size" name="farm_size" step="0.01" min="0.1" required> | |
</div> | |
<div class="col-md-6 mb-3"> | |
<label for="irrigation_type" class="form-label">Irrigation Type *</label> | |
<select class="form-select" id="irrigation_type" name="irrigation_type" required> | |
<option value="">Select Irrigation</option> | |
<option value="Drip">Drip Irrigation</option> | |
<option value="Sprinkler">Sprinkler</option> | |
<option value="Flood">Flood Irrigation</option> | |
<option value="Rain-fed">Rain-fed</option> | |
<option value="Bore-well">Bore-well</option> | |
</select> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<label for="farm_type" class="form-label">Farm Type *</label> | |
<select class="form-select" id="farm_type" name="farm_type" required onchange="toggleFarmSections()"> | |
<option value="">Select Farm Type</option> | |
<option value="crop">Crop Farming</option> | |
<option value="dairy">Dairy Farm</option> | |
<option value="poultry">Poultry Farm</option> | |
<option value="goat">Goat Farming</option> | |
<option value="pig">Pig Farming</option> | |
<option value="fishery">Fish Farming</option> | |
<option value="mixed">Mixed Farming</option> | |
</select> | |
</div> | |
<!-- Crop Farming Section --> | |
<div class="mb-3" id="crop-section" style="display: none;"> | |
<label class="form-label">Crop Types *</label> | |
<div class="row"> | |
<div class="col-md-6"> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Rice" id="crop_rice" name="crop_types"> | |
<label class="form-check-label" for="crop_rice">Rice</label> | |
</div> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Wheat" id="crop_wheat" name="crop_types"> | |
<label class="form-check-label" for="crop_wheat">Wheat</label> | |
</div> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Cotton" id="crop_cotton" name="crop_types"> | |
<label class="form-check-label" for="crop_cotton">Cotton</label> | |
</div> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Sugarcane" id="crop_sugarcane" name="crop_types"> | |
<label class="form-check-label" for="crop_sugarcane">Sugarcane</label> | |
</div> | |
</div> | |
<div class="col-md-6"> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Maize" id="crop_maize" name="crop_types"> | |
<label class="form-check-label" for="crop_maize">Maize</label> | |
</div> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Vegetables" id="crop_vegetables" name="crop_types"> | |
<label class="form-check-label" for="crop_vegetables">Vegetables</label> | |
</div> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Fruits" id="crop_fruits" name="crop_types"> | |
<label class="form-check-label" for="crop_fruits">Fruits</label> | |
</div> | |
<div class="form-check"> | |
<input class="form-check-input" type="checkbox" value="Pulses" id="crop_pulses" name="crop_types"> | |
<label class="form-check-label" for="crop_pulses">Pulses</label> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Livestock Section --> | |
<div class="mb-3" id="livestock-section" style="display: none;"> | |
<label class="form-label">Livestock Details</label> | |
<div class="row"> | |
<div class="col-md-6 mb-3"> | |
<label for="livestock_types" class="form-label">Livestock Types</label> | |
<select class="form-select" id="livestock_types" name="livestock_types" multiple> | |
<option value="Cows">Cows</option> | |
<option value="Buffalo">Buffalo</option> | |
<option value="Chickens">Chickens</option> | |
<option value="Ducks">Ducks</option> | |
<option value="Goats">Goats</option> | |
<option value="Sheep">Sheep</option> | |
<option value="Pigs">Pigs</option> | |
<option value="Fish">Fish</option> | |
</select> | |
<div class="form-text">Hold Ctrl to select multiple types</div> | |
</div> | |
<div class="col-md-6 mb-3"> | |
<label for="livestock_count" class="form-label">Total Livestock Count</label> | |
<input type="number" class="form-control" id="livestock_count" name="livestock_count" min="1"> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-6 mb-3"> | |
<label for="housing_type" class="form-label">Housing Type</label> | |
<select class="form-select" id="housing_type" name="housing_type"> | |
<option value="">Select Housing Type</option> | |
<option value="Open">Open Housing</option> | |
<option value="Semi-Open">Semi-Open Housing</option> | |
<option value="Closed">Closed Housing</option> | |
<option value="Cage">Cage System</option> | |
<option value="Free-Range">Free Range</option> | |
<option value="Pond">Pond System</option> | |
</select> | |
</div> | |
<div class="col-md-6 mb-3"> | |
<label for="feeding_system" class="form-label">Feeding System</label> | |
<select class="form-select" id="feeding_system" name="feeding_system"> | |
<option value="">Select Feeding System</option> | |
<option value="Grazing">Grazing</option> | |
<option value="Stall-fed">Stall Feeding</option> | |
<option value="Mixed">Mixed System</option> | |
<option value="Automatic">Automatic Feeding</option> | |
<option value="Manual">Manual Feeding</option> | |
</select> | |
</div> | |
</div> | |
<div class="mb-3"> | |
<label for="breed_info" class="form-label">Breed Information</label> | |
<textarea class="form-control" id="breed_info" name="breed_info" rows="2" placeholder="Describe the breeds of livestock you have..."></textarea> | |
</div> | |
</div> | |
<!-- Detailed crops table: name, area, sowing month --> | |
<div class="mb-3" id="crop-details-section" style="display: none;"> | |
<label class="form-label">Crops (name, area in acres, sowing month) *</label> | |
<div class="table-responsive"> | |
<table class="table table-bordered" id="crops-table-add"> | |
<thead> | |
<tr> | |
<th>Crop Name</th> | |
<th>Area (acres)</th> | |
<th>Sowing Month</th> | |
<th>Actions</th> | |
</tr> | |
</thead> | |
<tbody id="crops-tbody-add"> | |
<tr> | |
<td><input type="text" class="form-control" name="crop_name[]" required></td> | |
<td><input type="number" class="form-control" name="crop_area[]" step="0.01" min="0" required></td> | |
<td> | |
<select class="form-select" name="crop_month[]" required> | |
<option value="">Select Month</option> | |
<option>January</option> | |
<option>February</option> | |
<option>March</option> | |
<option>April</option> | |
<option>May</option> | |
<option>June</option> | |
<option>July</option> | |
<option>August</option> | |
<option>September</option> | |
<option>October</option> | |
<option>November</option> | |
<option>December</option> | |
</select> | |
</td> | |
<td><button type="button" class="btn btn-danger btn-sm remove-crop">Remove</button></td> | |
</tr> | |
</tbody> | |
</table> | |
<button type="button" id="add-crop-row" class="btn btn-success">Add Crop</button> | |
</div> | |
</div> | |
<!-- Soil Data Section --> | |
<h5><i class="fas fa-mountain me-2"></i>Soil Information</h5> | |
<div class="mb-3"> | |
<label for="soil_type" class="form-label">Soil Type</label> | |
<select class="form-select" id="soil_type" name="soil_type"> | |
<option value="">Select Soil Type</option> | |
<option value="Black">Black Soil</option> | |
<option value="Red">Red Soil</option> | |
<option value="Clay">Clay Soil</option> | |
<option value="Sandy">Sandy Soil</option> | |
<option value="Loamy">Loamy Soil</option> | |
</select> | |
</div> | |
<div class="row"> | |
<div class="col-md-6 mb-3"> | |
<label for="ph_level" class="form-label">pH Level</label> | |
<input type="number" class="form-control" id="ph_level" name="ph_level" step="0.1" min="0" max="14"> | |
</div> | |
<div class="col-md-6 mb-3"> | |
<label for="moisture_percentage" class="form-label">Moisture %</label> | |
<input type="number" class="form-control" id="moisture_percentage" name="moisture_percentage" step="0.1" min="0" max="100"> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-4 mb-3"> | |
<label for="nitrogen_level" class="form-label">Nitrogen (ppm)</label> | |
<input type="number" class="form-control" id="nitrogen_level" name="nitrogen_level" step="0.1" min="0"> | |
</div> | |
<div class="col-md-4 mb-3"> | |
<label for="phosphorus_level" class="form-label">Phosphorus (ppm)</label> | |
<input type="number" class="form-control" id="phosphorus_level" name="phosphorus_level" step="0.1" min="0"> | |
</div> | |
<div class="col-md-4 mb-3"> | |
<label for="potassium_level" class="form-label">Potassium (ppm)</label> | |
<input type="number" class="form-control" id="potassium_level" name="potassium_level" step="0.1" min="0"> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Map Section --> | |
<div class="col-md-6"> | |
<div class="form-section"> | |
<h5><i class="fas fa-map-marker-alt me-2"></i>Farm Location</h5> | |
<div class="mb-3"> | |
<div id="map"></div> | |
</div> | |
<div class="row mb-3"> | |
<div class="col-6"> | |
<button type="button" id="startDrawingBtn" class="btn btn-success w-100"> | |
<i class="fas fa-draw-polygon me-2"></i>Draw Boundary | |
</button> | |
</div> | |
<div class="col-6"> | |
<button type="button" id="clearDrawingBtn" class="btn btn-danger w-100"> | |
<i class="fas fa-trash me-2"></i>Clear | |
</button> | |
</div> | |
</div> | |
<div class="alert alert-info" id="drawingStatus"> | |
<i class="fas fa-info-circle me-2"></i> | |
Click "Draw Boundary" and mark your farm area on the map. | |
</div> | |
<div class="row"> | |
<div class="col-6"> | |
<label for="latitude" class="form-label">Latitude *</label> | |
<input type="number" class="form-control" id="latitude" name="latitude" step="0.000001" readonly required> | |
</div> | |
<div class="col-6"> | |
<label for="longitude" class="form-label">Longitude *</label> | |
<input type="number" class="form-control" id="longitude" name="longitude" step="0.000001" readonly required> | |
</div> | |
</div> | |
<!-- Hidden fields for coordinates data --> | |
<input type="hidden" id="field_coordinates" name="field_coordinates"> | |
</div> | |
</div> | |
</div> | |
<div class="row mt-4"> | |
<div class="col-12 text-center"> | |
<button type="submit" class="btn btn-success btn-lg me-3" id="submitBtn" disabled> | |
<i class="fas fa-save me-2"></i>Save Farm | |
</button> | |
<a href="{{ url_for('farmer_dashboard') }}" class="btn btn-secondary btn-lg"> | |
<i class="fas fa-arrow-left me-2"></i>Back to Dashboard | |
</a> | |
</div> | |
</div> | |
</form> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
{% endblock %} | |
{% block extra_js %} | |
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBvVLjWmCja331H8SuIZ4UlJdZytuYkC6Y&libraries=drawing,places&callback=initMap" async defer></script> | |
<script> | |
// Toggle farm sections based on farm type | |
function toggleFarmSections() { | |
const farmType = document.getElementById('farm_type').value; | |
const cropSection = document.getElementById('crop-section'); | |
const livestockSection = document.getElementById('livestock-section'); | |
const cropDetailsSection = document.getElementById('crop-details-section'); | |
// Hide all sections first | |
cropSection.style.display = 'none'; | |
livestockSection.style.display = 'none'; | |
cropDetailsSection.style.display = 'none'; | |
// Show relevant sections based on farm type | |
if (farmType === 'crop' || farmType === 'mixed') { | |
cropSection.style.display = 'block'; | |
cropDetailsSection.style.display = 'block'; | |
} | |
if (farmType === 'dairy' || farmType === 'poultry' || farmType === 'goat' || | |
farmType === 'pig' || farmType === 'fishery' || farmType === 'mixed') { | |
livestockSection.style.display = 'block'; | |
// Auto-select appropriate livestock types based on farm type | |
const livestockSelect = document.getElementById('livestock_types'); | |
for (let option of livestockSelect.options) { | |
option.selected = false; // Clear previous selections | |
} | |
switch(farmType) { | |
case 'dairy': | |
for (let option of livestockSelect.options) { | |
if (option.value === 'Cows' || option.value === 'Buffalo') { | |
option.selected = true; | |
} | |
} | |
break; | |
case 'poultry': | |
for (let option of livestockSelect.options) { | |
if (option.value === 'Chickens' || option.value === 'Ducks') { | |
option.selected = true; | |
} | |
} | |
break; | |
case 'goat': | |
for (let option of livestockSelect.options) { | |
if (option.value === 'Goats') { | |
option.selected = true; | |
} | |
} | |
break; | |
case 'pig': | |
for (let option of livestockSelect.options) { | |
if (option.value === 'Pigs') { | |
option.selected = true; | |
} | |
} | |
break; | |
case 'fishery': | |
for (let option of livestockSelect.options) { | |
if (option.value === 'Fish') { | |
option.selected = true; | |
} | |
} | |
break; | |
} | |
} | |
} | |
let map, drawingManager, polygon; | |
let isDrawing = false; | |
function initMap() { | |
// Initialize map (centered on India) | |
map = new google.maps.Map(document.getElementById('map'), { | |
center: { lat: 20.5937, lng: 78.9629 }, | |
zoom: 5, | |
mapTypeControl: true, | |
fullscreenControl: true, | |
streetViewControl: true | |
}); | |
// Initialize drawing manager | |
drawingManager = new google.maps.drawing.DrawingManager({ | |
drawingMode: null, | |
drawingControl: false, | |
polygonOptions: { | |
fillColor: '#4CAF50', | |
fillOpacity: 0.3, | |
strokeWeight: 2, | |
strokeColor: '#4CAF50', | |
clickable: true, | |
editable: true | |
} | |
}); | |
drawingManager.setMap(map); | |
// Helper: compute approximate area in acres from polygon vertices | |
function computeAreaAcresFromLatLngArray(latlngArray) { | |
// latlngArray: [{lat, lng}, ...] | |
if (!latlngArray || latlngArray.length < 3) return 0; | |
// Compute average latitude | |
let latSum = 0; | |
latlngArray.forEach(p => latSum += p.lat); | |
const latAvg = latSum / latlngArray.length; | |
const latAvgRad = latAvg * Math.PI / 180.0; | |
const metersPerDegLat = 111132.92; | |
const metersPerDegLon = 111320.0 * Math.cos(latAvgRad); | |
// Convert to planar meters | |
const pts = latlngArray.map(p => ({ | |
x: p.lng * metersPerDegLon, | |
y: p.lat * metersPerDegLat | |
})); | |
// Shoelace | |
let area = 0; | |
for (let i = 0; i < pts.length; i++) { | |
const j = (i + 1) % pts.length; | |
area += pts[i].x * pts[j].y - pts[j].x * pts[i].y; | |
} | |
area = Math.abs(area) / 2.0; // in m^2 | |
// convert to acres | |
const acres = area / 4046.8564224; | |
return Math.round(acres * 10000) / 10000; // 4 decimal places | |
} | |
// Event listener for polygon completion | |
drawingManager.addListener('polygoncomplete', function(poly) { | |
if (polygon) { | |
polygon.setMap(null); | |
} | |
polygon = poly; | |
// Get polygon coordinates | |
const coordinates = []; | |
const vertices = polygon.getPath(); | |
for (let i = 0; i < vertices.getLength(); i++) { | |
const xy = vertices.getAt(i); | |
coordinates.push([xy.lng(), xy.lat()]); | |
} | |
// Convert coordinates to objects with lat,lng for easier processing | |
const latlngObjects = coordinates.map(c => ({ lat: c[1], lng: c[0] })); | |
// Store coordinates | |
document.getElementById('field_coordinates').value = JSON.stringify(latlngObjects); | |
// Calculate center point | |
const bounds = new google.maps.LatLngBounds(); | |
vertices.forEach(vertex => bounds.extend(vertex)); | |
const center = bounds.getCenter(); | |
// Update latitude and longitude fields | |
document.getElementById('latitude').value = center.lat(); | |
document.getElementById('longitude').value = center.lng(); | |
// Compute area and update farm_size input automatically | |
const acres = computeAreaAcresFromLatLngArray(latlngObjects); | |
if (acres > 0) { | |
document.getElementById('farm_size').value = acres; | |
} | |
// Update status | |
document.getElementById('drawingStatus').innerHTML = | |
'<i class="fas fa-check-circle me-2"></i>Farm boundary marked successfully!'; | |
document.getElementById('drawingStatus').className = 'alert alert-success'; | |
// Enable submit button | |
document.getElementById('submitBtn').disabled = false; | |
// Stop drawing mode | |
drawingManager.setDrawingMode(null); | |
isDrawing = false; | |
// Update button text | |
document.getElementById('startDrawingBtn').innerHTML = | |
'<i class="fas fa-edit me-2"></i>Edit Boundary'; | |
}); | |
} | |
// Start drawing | |
document.getElementById('startDrawingBtn').addEventListener('click', function() { | |
if (!isDrawing) { | |
drawingManager.setDrawingMode(google.maps.drawing.OverlayType.POLYGON); | |
isDrawing = true; | |
this.innerHTML = '<i class="fas fa-stop me-2"></i>Stop Drawing'; | |
this.className = 'btn btn-warning w-100'; | |
} else { | |
drawingManager.setDrawingMode(null); | |
isDrawing = false; | |
this.innerHTML = '<i class="fas fa-draw-polygon me-2"></i>Draw Boundary'; | |
this.className = 'btn btn-success w-100'; | |
} | |
}); | |
// Clear drawing | |
document.getElementById('clearDrawingBtn').addEventListener('click', function() { | |
if (polygon) { | |
polygon.setMap(null); | |
polygon = null; | |
} | |
// Clear form fields | |
document.getElementById('field_coordinates').value = ''; | |
document.getElementById('latitude').value = ''; | |
document.getElementById('longitude').value = ''; | |
// Reset status | |
document.getElementById('drawingStatus').innerHTML = | |
'<i class="fas fa-info-circle me-2"></i>Click "Draw Boundary" and mark your farm area on the map.'; | |
document.getElementById('drawingStatus').className = 'alert alert-info'; | |
// Disable submit button | |
document.getElementById('submitBtn').disabled = true; | |
// Reset drawing mode | |
drawingManager.setDrawingMode(null); | |
isDrawing = false; | |
// Reset button | |
const drawBtn = document.getElementById('startDrawingBtn'); | |
drawBtn.innerHTML = '<i class="fas fa-draw-polygon me-2"></i>Draw Boundary'; | |
drawBtn.className = 'btn btn-success w-100'; | |
}); | |
// Form validation | |
document.getElementById('farmForm').addEventListener('submit', function(e) { | |
const cropTypes = document.querySelectorAll('input[name="crop_types"]:checked'); | |
if (cropTypes.length === 0) { | |
e.preventDefault(); | |
alert('Please select at least one crop type.'); | |
return false; | |
} | |
if (!document.getElementById('latitude').value || !document.getElementById('longitude').value) { | |
e.preventDefault(); | |
alert('Please mark your farm location on the map.'); | |
return false; | |
} | |
}); | |
// Crop rows management (add/remove) | |
document.getElementById('add-crop-row').addEventListener('click', function() { | |
const tbody = document.getElementById('crops-tbody-add'); | |
const row = document.createElement('tr'); | |
row.innerHTML = ` | |
<td><input type="text" class="form-control" name="crop_name[]" required></td> | |
<td><input type="number" class="form-control" name="crop_area[]" step="0.01" min="0" required></td> | |
<td> | |
<select class="form-select" name="crop_month[]" required> | |
<option value="">Select Month</option> | |
<option>January</option> | |
<option>February</option> | |
<option>March</option> | |
<option>April</option> | |
<option>May</option> | |
<option>June</option> | |
<option>July</option> | |
<option>August</option> | |
<option>September</option> | |
<option>October</option> | |
<option>November</option> | |
<option>December</option> | |
</select> | |
</td> | |
<td><button type="button" class="btn btn-danger btn-sm remove-crop">Remove</button></td> | |
`; | |
tbody.appendChild(row); | |
// Attach remove handler | |
row.querySelector('.remove-crop').addEventListener('click', function() { | |
if (tbody.children.length > 1) row.remove(); | |
else alert('At least one crop is required'); | |
}); | |
}); | |
// Attach remove handler to initial row(s) | |
document.querySelectorAll('#crops-tbody-add .remove-crop').forEach(btn => { | |
btn.addEventListener('click', function() { | |
const tbody = document.getElementById('crops-tbody-add'); | |
if (tbody.children.length > 1) this.closest('tr').remove(); | |
else alert('At least one crop is required'); | |
}); | |
}); | |
// Get user location | |
if (navigator.geolocation) { | |
navigator.geolocation.getCurrentPosition(function(position) { | |
const userLocation = { | |
lat: position.coords.latitude, | |
lng: position.coords.longitude | |
}; | |
map.setCenter(userLocation); | |
map.setZoom(15); | |
}); | |
} | |
</script> | |
{% endblock %} | |