Initial commit

This commit is contained in:
Kwesi Banson Jnr
2026-09-09 09:50:06 +00:00
commit c7f93a7dc1
8369 changed files with 517137 additions and 0 deletions

View File

@@ -0,0 +1,86 @@
// public/js/dashboard.js
$(document).ready(function() {
console.log(base_url);
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);
});

22
public/assets/js/login.js Normal file
View File

@@ -0,0 +1,22 @@
// Where you want to render the map.
var element = document.getElementById('map');
// Height has to be set. You can do this in CSS too.
element.style = 'height:300px;';
// Create Leaflet map on map element.
var map = L.map(element);
// Add OSM tile layer to the Leaflet map.
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// Target's GPS coordinates.
var target = L.latLng('7.9527706', '-1.0307118');
// Set map's center to target with zoom 14.
map.setView(target, 7);
// Place a marker on the same location.
L.marker(target).addTo(map);

View File

@@ -0,0 +1,57 @@
// Where you want to render the map.
var element = document.getElementById('applicationmap');
// Height has to be set. You can do this in CSS too.
//element.style = 'height:450px;';
var defaultWKT = 'POLYGON((-1.22 7.14, -1.17 7.14, -1.17 7.26, -1.22 7.26, -1.22 7.14))';
searchLayer = new ol.layer.Vector({
title : 'Search Layer',
source : undefined,
style : new ol.style.Style({
stroke : new ol.style.Stroke({
color : 'red',
width : 3
})
})
});
// Create Openlayers map on map element.
var map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: element,
controls: ol.control.defaults().extend([
new ol.control.MousePosition({
projection: 'EPSG:4326',
coordinateFormat: function(coordinate) {
return ol.coordinate.format(coordinate, '{x}, {y}', 4);
},
}),
new ol.control.ScaleLine(),
]),
view: new ol.View({
center: [-135846.63, 891762.35],
zoom: 6
})
});
map.addLayer(searchLayer);
searchLayer.setSource(new ol.source.Vector({features : (new ol.format.WKT()).readFeatures(defaultWKT)}));
view.fit(searchLayer.getSource().getExtent());
pvlmd_map.getView().fit(searchLayer.getSource().getExtent(),{size : map.getSize(),maxZoom : 16})
function viewApplication(applicationId) {
console.log(applicationId);
window.location.href = "/permits/viewapplication?id=" + applicationId;
}
function viewPending() {
console.log('foo bar');
window.location.href = "/permits/pending";
}

217
public/assets/js/usermgt.js Normal file
View File

@@ -0,0 +1,217 @@
$(document).ready(function(){
// $('.editUserBtn').click(function(evnt){
// });
//
console.log('foo bar');
$('#editAllowedApps').select2({
// width: "resolve",
dropdownParent: $('#editUserModal'),
placeholder : "Select options, multiple allowed"
});
$('#allowedApps').select2({
// width: "resolve",
dropdownParent: $('#addUserModal'),
placeholder : "Select options, multiple allowed"
});
$('#inputPermissions').select2({
// width: "resolve",
dropdownParent: $('#editUserModal'),
placeholder : "Select options, multiple allowed"
});
$('.editUserBtn').click(function(evnt){
evnt.preventDefault();
var selectedUserId = $(this).siblings('.userIdinput').val();
const formData = new FormData();
formData.append('user_id', selectedUserId);
$.ajax({
url: base_url + '/users/edit/' + selectedUserId,
type: 'GET',
processData: false,
contentType: false,
beforeSend: function() {
$('#editSuccessArea').text("");
$('#editErrorArea').text("Please wait ... loading user details!");
},
success: function(data) {
var jason = data.data;
if(data.success == true){
var allowedAppsArray = [];
if (jason['allowed_apps']) {
allowedAppsArray = jason['allowed_apps'].split(",");
}
console.log(jason['full_name']);
$('#editFullName').val(jason['full_name']);
$('#editEmail').val(jason['email']);
$('#editUsername').val(jason['username']);
$('#editGender').val(jason['gender']);
$('#editTitle').val(jason['title']);
$('#editUaPostion').val(jason['ua_position']);
$('#editPhone').val(jason['phone']);
$('#editAllowedApps').val(allowedAppsArray).trigger('change');
$('#editRegionID').val(jason['region_id']);
$('#editDistrictId').val(jason['district_id']);
$('#editUaPostion').val(jason['ua_position']);
$('#editGender').val(jason['gender']);
$("input[name='user_id']").val(jason.ua_id);
}
//$('#editUserModal').modal('show');
},
error: function(xhr, status, error) {
console.error('Error:', error);
$('#errorArea').text(error);
$('#errorArea').text(error);
}
});
});
$('.viewUserBtn').click(function(evnt){
evnt.preventDefault();
var selectedUserId = $(this).siblings('.userIdinput').val();
const formData = new FormData();
formData.append('user_id', selectedUserId);
$.ajax({
url: base_url + '/users/' + selectedUserId,
type: 'GET',
processData: false,
contentType: false,
beforeSend: function() {
$('#viewSuccessArea').text("");
$('#viewErrorArea').text("Please wait ... loading user details!");
},
success: function(data) {
var jason = data.data;
if(data.success == true){
var allowedAppsArray = [];
if (jason['allowed_apps']) {
allowedAppsArray = jason['allowed_apps'].split(",");
}
console.log(jason['full_name']);
$('#viewFullName').val(jason['full_name']);
$('#viewEmail').val(jason['email']);
$('#viewUsername').val(jason['username']);
$('#viewGender').val(jason['gender']);
$('#viewTitle').val(jason['title']);
$('#viewUaPostion').val(jason['ua_position']);
$('#viewPhone').val(jason['phone']);
$('#viewAllowedApps').val(allowedAppsArray).trigger('change');
$('#viewRegionID').val(jason['region_id']);
$('#viewDistrictId').val(jason['district_id']);
$('#viewUaPostion').val(jason['ua_position']);
$('#viewGender').val(jason['gender']);
$("input[name='user_id']").val(jason.ua_id);
}
//$('#editUserModal').modal('show');
},
error: function(xhr, status, error) {
console.error('Error:', error);
$('#errorArea').text(error);
$('#errorArea').text(error);
}
});
});
$("#newUserForm").submit(function(evt){
evt.preventDefault();
$('#successArea').addClass('d-none');
$('#errorsArea').removeClass('d-none');
var formData = new FormData($(this)[0]);
$.ajax({
url: base_url + '/users',
type: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: function() {
$('#successArea').text("");
$('#successArea').text("Please wait ... user creation in progress!");
},
success: function(data) {
if (data['success'] == true) {
$('#successArea').removeClass('d-none');
$('#errorsArea').addClass('d-none');
$('#successArea').text("");
$('#successArea').text("User successfully created!");
// location.reload();
setTimeout(function() {
location.reload(); // Reloads the current page
}, 15000);
}
else{
$('#successArea').addClass('d-none');
$('#errorArea').removeClass('d-none');
$('#errorArea').text("");
$('#errorArea').text("User could not be created!");
}
},
error: function(xhr, status, error) {
console.error('Error:', error);
$('#successArea').text(error);
$('#successArea').text(error);
}
});
});
$("#editUserForm").submit(function(evt){
evt.preventDefault();
$('#successArea').addClass('d-none');
$('#errorsArea').removeClass('d-none');
var formData = new FormData($(this)[0]);
$.ajax({
url: base_url + '/users/update/',
type: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: function() {
// $('#updateBtn').addClass('d-none');
// $('#uodateProgressBtn').removeClass('d-none');
// $('#updateResultsDiv').removeClass('d-none');
// $('#updateResultsParagraph').text("Processing Please wait ...");
},
success: function(data) {
console.log(data);
$('#editSuccessArea').removeClass('d-none');
$('#editErrorArea').addClass('d-none');
$('#editSuccessArea').text("");
$('#editSuccessArea').text("User successfully details updated!");
},
error: function(xhr, status, error) {
console.error('Error:', error);
$('#editSuccessArea').text(error);
$('#editErrorArea').text(error);
location.reload();
}
});
});
$('#regionID').change(function(){
var options = $('#districtID');
var region_id = $('#regionID').val();
$.get( base_url + '/admin/districts/' + region_id, function (data) {
$('#districtID').empty();
$.each(data['districts'], function(id, row) {
$('#districtID').append($("<option />").val(row.districtid).text(row.district_name));
});
});
});
});