Spaces:
Sleeping
Sleeping
{% extends "base.html" %} | |
{% block title %}Admin Dashboard - Farm Management Portal{% endblock %} | |
{% block content %} | |
<div class="container mt-4"> | |
<!-- Admin Header --> | |
<div class="row mb-4"> | |
<div class="col-12"> | |
<div class="card bg-dark text-white"> | |
<div class="card-body"> | |
<h2><i class="fas fa-shield-alt me-2"></i>Admin Dashboard</h2> | |
<p class="mb-0">System Management and Monitoring</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Statistics Cards --> | |
<div class="row mb-4"> | |
<div class="col-md-3 mb-3"> | |
<div class="card bg-primary text-white"> | |
<div class="card-body text-center"> | |
<i class="fas fa-users fa-3x mb-2"></i> | |
<h3>{{ total_farmers }}</h3> | |
<p class="mb-0">Total Farmers</p> | |
</div> | |
</div> | |
</div> | |
<div class="col-md-3 mb-3"> | |
<div class="card bg-success text-white"> | |
<div class="card-body text-center"> | |
<i class="fas fa-seedling fa-3x mb-2"></i> | |
<h3>{{ total_farms }}</h3> | |
<p class="mb-0">Total Farms</p> | |
</div> | |
</div> | |
</div> | |
<div class="col-md-3 mb-3"> | |
<div class="card bg-info text-white"> | |
<div class="card-body text-center"> | |
<i class="fas fa-brain fa-3x mb-2"></i> | |
<h3>{{ total_advisories }}</h3> | |
<p class="mb-0">AI Advisories</p> | |
</div> | |
</div> | |
</div> | |
<div class="col-md-3 mb-3"> | |
<div class="card bg-warning text-dark"> | |
<div class="card-body text-center"> | |
<i class="fas fa-sms fa-3x mb-2"></i> | |
<h3>{{ total_sms }}</h3> | |
<p class="mb-0">SMS Sent</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="row"> | |
<!-- Quick Actions --> | |
<div class="col-md-4 mb-4"> | |
<div class="card"> | |
<div class="card-header bg-secondary text-white"> | |
<h5><i class="fas fa-bolt me-2"></i>Quick Actions</h5> | |
</div> | |
<div class="card-body"> | |
<div class="d-grid gap-2"> | |
<a href="{{ url_for('admin_farmers') }}" class="btn btn-primary"> | |
<i class="fas fa-users me-2"></i>Manage Farmers | |
</a> | |
<a href="{{ url_for('admin_sms_logs') }}" class="btn btn-info"> | |
<i class="fas fa-sms me-2"></i>SMS Logs | |
</a> | |
<button class="btn btn-success" onclick="generateAllAdvisories()"> | |
<i class="fas fa-magic me-2"></i>Generate All Advisories | |
</button> | |
<button class="btn btn-warning" onclick="sendAllSMS()"> | |
<i class="fas fa-broadcast-tower me-2"></i>Send All SMS | |
</button> | |
<a href="{{ url_for('admin_logout') }}" class="btn btn-outline-danger"> | |
<i class="fas fa-sign-out-alt me-2"></i>Logout | |
</a> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Recent Farmers --> | |
<div class="col-md-8 mb-4"> | |
<div class="card"> | |
<div class="card-header"> | |
<h5><i class="fas fa-user-plus me-2"></i>Recent Farmers</h5> | |
</div> | |
<div class="card-body"> | |
{% if recent_farmers %} | |
<div class="table-responsive"> | |
<table class="table table-striped table-sm"> | |
<thead> | |
<tr> | |
<th>Name</th> | |
<th>Contact</th> | |
<th>Registered</th> | |
<th>Status</th> | |
<th>Actions</th> | |
</tr> | |
</thead> | |
<tbody> | |
{% for farmer in recent_farmers %} | |
<tr> | |
<td>{{ farmer.name }}</td> | |
<td>{{ farmer.contact_number }}</td> | |
<td>{{ farmer.created_at.strftime('%d %b %Y') }}</td> | |
<td> | |
<span class="badge bg-{{ 'success' if farmer.is_active else 'danger' }}"> | |
{{ 'Active' if farmer.is_active else 'Inactive' }} | |
</span> | |
</td> | |
<td> | |
<button class="btn btn-sm btn-outline-primary" onclick="viewFarmerDetails({{ farmer.id }})"> | |
<i class="fas fa-eye"></i> | |
</button> | |
</td> | |
</tr> | |
{% endfor %} | |
</tbody> | |
</table> | |
</div> | |
{% else %} | |
<div class="text-center text-muted py-3"> | |
<i class="fas fa-users fa-3x mb-3"></i> | |
<p>No farmers registered yet</p> | |
</div> | |
{% endif %} | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- SMS Logs --> | |
<div class="row"> | |
<div class="col-12"> | |
<div class="card"> | |
<div class="card-header"> | |
<h5><i class="fas fa-history me-2"></i>Recent SMS Activity</h5> | |
</div> | |
<div class="card-body"> | |
{% if recent_sms %} | |
<div class="table-responsive"> | |
<table class="table table-striped table-sm"> | |
<thead> | |
<tr> | |
<th>Farmer</th> | |
<th>Phone</th> | |
<th>Message</th> | |
<th>Status</th> | |
<th>Sent At</th> | |
</tr> | |
</thead> | |
<tbody> | |
{% for sms in recent_sms %} | |
<tr> | |
<td>{{ sms.farmer.name if sms.farmer else 'Unknown' }}</td> | |
<td>{{ sms.phone_number }}</td> | |
<td> | |
<span class="text-truncate d-inline-block" style="max-width: 200px;" title="{{ sms.message_content }}"> | |
{{ sms.message_content[:50] + '...' if sms.message_content|length > 50 else sms.message_content }} | |
</span> | |
</td> | |
<td> | |
<span class="badge bg-{{ 'success' if sms.status == 'sent' else 'danger' if sms.status == 'failed' else 'warning' }}"> | |
{{ sms.status|title }} | |
</span> | |
</td> | |
<td>{{ sms.sent_at.strftime('%d %b %Y %H:%M') }}</td> | |
</tr> | |
{% endfor %} | |
</tbody> | |
</table> | |
</div> | |
{% else %} | |
<div class="text-center text-muted py-3"> | |
<i class="fas fa-sms fa-3x mb-3"></i> | |
<p>No SMS activity yet</p> | |
</div> | |
{% endif %} | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Loading Modal --> | |
<div class="modal fade" id="loadingModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"> | |
<div class="modal-dialog modal-dialog-centered"> | |
<div class="modal-content"> | |
<div class="modal-body text-center"> | |
<div class="spinner-border text-primary" role="status"> | |
<span class="visually-hidden">Loading...</span> | |
</div> | |
<p class="mt-3 mb-0">Processing request...</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Farmer Details Modal --> | |
<div class="modal fade" id="farmerModal" tabindex="-1"> | |
<div class="modal-dialog modal-lg"> | |
<div class="modal-content"> | |
<div class="modal-header"> | |
<h5 class="modal-title">Farmer Details</h5> | |
<button type="button" class="btn-close" data-bs-dismiss="modal"></button> | |
</div> | |
<div class="modal-body" id="farmerModalBody"> | |
<!-- Farmer details will be loaded here --> | |
</div> | |
</div> | |
</div> | |
</div> | |
{% endblock %} | |
{% block extra_js %} | |
<script> | |
// Helper to show/hide the Bootstrap 5 modal using vanilla JS | |
function _getLoadingModalInstance(){ | |
const modalEl = document.getElementById('loadingModal'); | |
return bootstrap.Modal.getOrCreateInstance(modalEl); | |
} | |
function _getFarmerModalInstance(){ | |
const modalEl = document.getElementById('farmerModal'); | |
return bootstrap.Modal.getOrCreateInstance(modalEl); | |
} | |
function generateAllAdvisories() { | |
if (!confirm('Generate advisories for all farms? This may take a few minutes.')) { | |
return; | |
} | |
const modal = _getLoadingModalInstance(); | |
modal.show(); | |
fetch('/admin/generate_all_advisories', {method: 'POST'}) | |
.then(response => response.json()) | |
.then(data => { | |
modal.hide(); | |
if (data.success) { | |
alert(`Successfully generated ${data.count} advisories!`); | |
location.reload(); | |
} else { | |
alert('Failed to generate advisories: ' + (data.error || 'Unknown error')); | |
} | |
}) | |
.catch(error => { | |
modal.hide(); | |
alert('Error: ' + error.message); | |
}); | |
} | |
function sendAllSMS() { | |
if (!confirm('Send SMS advisories to all farmers? This will send messages immediately.')) { | |
return; | |
} | |
const modal = _getLoadingModalInstance(); | |
modal.show(); | |
fetch('/admin/send_all_sms', {method: 'POST'}) | |
.then(response => response.json()) | |
.then(data => { | |
modal.hide(); | |
if (data.success) { | |
alert(`Successfully sent ${data.sent} SMS messages!`); | |
location.reload(); | |
} else { | |
alert('Failed to send SMS: ' + (data.error || 'Unknown error')); | |
} | |
}) | |
.catch(error => { | |
modal.hide(); | |
alert('Error: ' + error.message); | |
}); | |
} | |
function viewFarmerDetails(farmerId) { | |
const modal = _getLoadingModalInstance(); | |
modal.show(); | |
fetch(`/admin/farmer/${farmerId}`) | |
.then(response => response.json()) | |
.then(data => { | |
modal.hide(); | |
if (data.success) { | |
const farmer = data.farmer; | |
const farms = data.farms; | |
let farmsHtml = ''; | |
if (farms.length > 0) { | |
farmsHtml = ` | |
<h6>Farms:</h6> | |
<div class="table-responsive"> | |
<table class="table table-sm"> | |
<thead> | |
<tr> | |
<th>Name</th> | |
<th>Size</th> | |
<th>Crops</th> | |
</tr> | |
</thead> | |
<tbody> | |
`; | |
farms.forEach(farm => { | |
farmsHtml += ` | |
<tr> | |
<td>${farm.farm_name}</td> | |
<td>${farm.farm_size} acres</td> | |
<td>${farm.crop_types.join(', ')}</td> | |
</tr> | |
`; | |
}); | |
farmsHtml += '</tbody></table></div>'; | |
} else { | |
farmsHtml = '<p class="text-muted">No farms registered</p>'; | |
} | |
document.getElementById('farmerModalBody').innerHTML = ` | |
<div class="row"> | |
<div class="col-md-6"> | |
<strong>Name:</strong> ${farmer.name}<br> | |
<strong>Age:</strong> ${farmer.age || 'N/A'}<br> | |
<strong>Gender:</strong> ${farmer.gender || 'N/A'}<br> | |
<strong>Aadhaar ID:</strong> ${farmer.aadhaar_id} | |
</div> | |
<div class="col-md-6"> | |
<strong>Contact:</strong> ${farmer.contact_number}<br> | |
<strong>Address:</strong> ${farmer.address}<br> | |
<strong>Status:</strong> | |
<span class="badge bg-${farmer.is_active ? 'success' : 'danger'}"> | |
${farmer.is_active ? 'Active' : 'Inactive'} | |
</span><br> | |
<strong>Registered:</strong> ${new Date(farmer.created_at).toLocaleDateString()} | |
</div> | |
</div> | |
<hr> | |
${farmsHtml} | |
`; | |
const farmerModal = _getFarmerModalInstance(); | |
farmerModal.show(); | |
} else { | |
alert('Failed to load farmer details'); | |
} | |
}) | |
.catch(error => { | |
modal.hide(); | |
alert('Error: ' + error.message); | |
}); | |
} | |
</script> | |
{% endblock %} | |