Files
Subscription-Content-Manage…/public/assets/js/dashboard.js
2026-09-25 16:44:37 +00:00

134 lines
6.1 KiB
JavaScript

// public/js/dashboard.js
$(document).ready(function() {
function fetchDashboardStats() {
$.ajax({
url: base_url + '/api/dashboard/stats',
method: 'GET',
dataType: 'json',
success: function(response) {
// 1. Update the Grand Totals
// toLocaleString() adds thousands separators for large numbers
$('#grand-total').text(response.summary.total.toLocaleString());
$('#grand-active').text(response.summary.active.toLocaleString());
$('#grand-inactive').text(response.summary.inactive.toLocaleString());
// 2. Clear the loading spinner
let container = $('#service-cards-container');
container.empty();
// 3. Generate Individual Service Cards
if (response.services.length === 0) {
container.html('<div class="col-12"><div class="alert alert-info">No subscription services configured yet.</div></div>');
return;
}
response.services.forEach(function(service) {
// Handle edge cases where total is 0 to avoid division by zero
let activeRate = service.total_subscribers > 0
? Math.round((service.active_subscribers / service.total_subscribers) * 100)
: 0;
let cardHtml = `
<div class="col-md-6 col-lg-4 mb-4">
<div class="card shadow-sm h-100 border-top border-primary border-3">
<div class="card-body">
<h5 class="card-title text-truncate" title="${service.name}">${service.name}</h5>
<div class="mt-3">
<div class="d-flex justify-content-between mb-1">
<span class="text-muted">Total</span>
<span class="fw-bold">${service.total_subscribers.toLocaleString()}</span>
</div>
<div class="d-flex justify-content-between mb-1">
<span class="text-muted">Active</span>
<span class="text-success fw-bold">${service.active_subscribers.toLocaleString()}</span>
</div>
<div class="mt-3">
<div class="d-flex justify-content-between mb-1">
<small class="text-muted">Active Rate</small>
<small class="fw-bold">${activeRate}%</small>
</div>
<div class="progress" style="height: 6px;">
<div class="progress-bar bg-success" role="progressbar" style="width: ${activeRate}%" aria-valuenow="${activeRate}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</div>
</div>
</div>
<div class="card-footer bg-white border-top-0 text-end">
<a href="${base_url}/services/${service.id}/details" class="btn btn-sm btn-outline-secondary">View Details</a>
</div>
</div>
</div>
`;
container.append(cardHtml);
});
},
error: function(xhr) {
$('#loading-services').html(`
<div class="alert alert-danger">
Failed to load dashboard statistics. Please try refreshing the page.
</div>
`);
// Set fallback text for the totals
$('#grand-total, #grand-active, #grand-inactive').text('Error');
}
});
}
// Initialize the fetch
fetchDashboardStats();
// Todo: Refresh data every 5 minutes (300000 ms) automatically without page reload
// setInterval(fetchDashboardStats, 300000);
$('#syncTriggerBtn').on('click', function() {
let btn = $(this);
let icon = $('#syncIcon');
let text = $('#syncText');
// Disable button and add spinning effect
btn.prop('disabled', true);
icon.addClass('spinner-border spinner-border-sm');
text.text('Syncing...');
$.ajax({
url: base_url + '/api/subscriptions/sync',
method: 'POST',
data: {
_token: $('meta[name="csrf-token"]').attr('content')
},
success: function(response) {
// Use SweetAlert2 for a clean success alert
Swal.fire({
icon: 'success',
title: 'Synchronized!',
text: response.message,
timer: 2000,
showConfirmButton: false
});
// Refresh dashboard data instantly to reflect updated counts
fetchDashboardStats();
},
error: function(xhr) {
let errorMsg = xhr.responseJSON && xhr.responseJSON.message
? xhr.responseJSON.message
: 'An unexpected error occurred during synchronization.';
Swal.fire({
icon: 'error',
title: 'Sync Failed',
text: errorMsg
});
},
complete: function() {
// Restore button state
btn.prop('disabled', false);
icon.removeClass('spinner-border spinner-border-sm');
text.text('Sync Now');
}
});
});
});