feat: complete assessment tasks

This commit is contained in:
Ayobami
2025-08-07 16:34:00 +01:00
parent 463a238503
commit c32a12c13f
7 changed files with 381 additions and 93 deletions
+205 -50
View File
@@ -5,27 +5,67 @@
color: white;
/* White text color */
}
.bulk-actions {
margin-bottom: 15px;
padding: 10px;
background-color: #f8f9fa;
border-radius: 5px;
display: none;
}
.bulk-actions.show {
display: block;
}
</style>
<div class="container">
<h2 class="text-left">Licenses &nbsp; <a class="btn btn-primary" href="/admin/license/add">Add</a></h2>
<!-- Bulk Actions Form -->
<div class="bulk-actions" id="bulkActions">
<form action="/admin/license/list/multiselect" method="POST" onsubmit="return confirmBulkDelete()">
<div class="d-flex align-items-center">
<span class="mr-3"><strong>Selected items:</strong> <span id="selectedCount">0</span></span>
<button type="submit" name="delete" class="btn btn-danger btn-sm mr-2">
<i class="fa fa-trash"></i> Delete Selected
</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="clearSelection()">
Clear Selection
</button>
</div>
<input type="hidden" name="selected_items" id="selectedItems" value="">
</form>
</div>
<div class="row mt-2 mb-2">
<div class="col-md-6 col-md-offset-3">
<form action="?" method="GET">
<div class="input-group">
<input type="text" name="relationship_num" class="form-control mr-2" placeholder="Enter Relationship #" value="<?php echo $data['relationship_num']; ?>">
<span class="input-group-btn">
<button class="btn btn-primary" type="submit">Search</button>
</span>
</div><!-- /input-group -->
<div class="col-md-10 col-md-offset-1">
<form action="?" method="GET" class="form-inline">
<div class="input-group mr-2 mb-2">
<label class="mr-2" for="relationship_num">Relationship #</label>
<input id="relationship_num" type="text" name="relationship_num" class="form-control" placeholder="Enter Relationship #"
value="<?php echo htmlspecialchars($data['relationship_num'] ?? ''); ?>">
</div>
<div class="input-group mr-2 mb-2">
<label class="mr-2" for="email">Email</label>
<input id="email" type="text" name="email" class="form-control" placeholder="Fuzzy email search..."
value="<?php echo htmlspecialchars($data['email_search'] ?? ''); ?>">
</div>
<!-- Preserve cursor parameter when searching -->
<input type="hidden" name="cursor" value="0">
<span class="input-group-btn mb-2">
<button class="btn btn-primary mr-2" type="submit">Search</button>
<a class="btn btn-secondary" href="/admin/license">Clear</a>
</span>
</form>
</div><!-- /.col-md-6 -->
</div><!-- /.col-md-10 -->
</div><!-- /.row -->
<!-- Table Responsive Wrapper -->
<div class="table-responsive">
<table class="table table-hover dark-header">
<thead>
<tr>
<th>
<input type="checkbox" id="selectAll" onchange="toggleSelectAll()">
<label for="selectAll" class="ml-1">Select All</label>
</th>
<th>ID</th>
<th>Relationship #</th>
<th>Email</th>
@@ -38,6 +78,7 @@
<tbody>
<?php foreach ($data['data'] as $key => $value) {
echo ' <tr>';
echo ' <td><input type="checkbox" class="item-checkbox" value="' . $value->id . '" onchange="updateBulkActions()"></td>';
echo ' <td>' . $value->id . ' <br/><a class=" text-info" href="/admin/license/edit/' . $value->id . '">edit</a> <a class="text-danger" href="/admin/license/delete/' . $value->id . '">delete</a></td>';
echo ' <td>' . $value->relationship_num . ' </td>';
echo ' <td>' . $value->email . ' </td>';
@@ -53,49 +94,163 @@
</div>
<?php
// Retrieve parameters
// Retrieve cursor pagination parameters
$total = $data['total'];
$currentPage = $data['page'];
$perPage = 10;
// Calculate the number of pages
$totalPages = ceil($total / $perPage);
// Define a range of pages to show at any given time
$range = 2; // This can be adjusted as needed
$startPage = ($currentPage - $range) > 0 ? ($currentPage - $range) : 1;
$endPage = ($currentPage + $range) < $totalPages ? ($currentPage + $range) : $totalPages;
$lastId = isset($data['id']) ? $data['id'] : 0;
$currentCursor = isset($_GET['cursor']) ? intval($_GET['cursor']) : 0;
$relationshipNum = isset($_GET['relationship_num']) ? $_GET['relationship_num'] : '';
$emailSearch = isset($_GET['email']) ? $_GET['email'] : '';
// Build query parameters for pagination links
$queryParams = [];
if (!empty($relationshipNum)) {
$queryParams['relationship_num'] = $relationshipNum;
}
if (!empty($emailSearch)) {
$queryParams['email'] = $emailSearch;
}
// Helper function to build query string
function buildQueryString($params) {
return !empty($params) ? '&' . http_build_query($params) : '';
}
$queryString = buildQueryString($queryParams);
// Determine if we have previous/next pages
$hasPrevious = $currentCursor > 0;
$hasNext = count($data['data']) >= $perPage; // If we got a full page, assume there might be more
?>
<!-- Pagination -->
<nav aria-label="Page navigation">
<ul class="pagination">
<li class="ml-2">
<a href="?page=1" aria-label="Previous">
<span aria-hidden="true">&laquo;&laquo;</span>
</a>
</li>
<li class="ml-2">
<a href="?page=<?= ($currentPage - 1) > 0 ? $currentPage - 1 : 1 ?>" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
<?php
for ($i = $startPage; $i <= $endPage; $i++) {
echo '<li class="ml-2' . ($currentPage == $i ? ' active' : '') . '"><a href="?page=' . $i . '">' . $i . '</a></li>';
}
?>
<li class="ml-2">
<a href="?page=<?= ($currentPage + 1) < $totalPages ? $currentPage + 1 : $totalPages ?>" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
<li class="ml-2">
<a href="?page=<?= $totalPages ?>" aria-label="Next">
<span aria-hidden="true">&raquo;&raquo;</span>
</a>
</li>
</ul>
<!-- Cursor-based Pagination -->
<nav aria-label="Cursor-based page navigation">
<div class="d-flex justify-content-between align-items-center">
<div class="pagination-info">
<small class="text-muted">
Showing <?= count($data['data']) ?> items
<?php if ($total > 0): ?>
(Total: <?= $total ?> items)
<?php endif; ?>
</small>
</div>
<ul class="pagination mb-0">
<?php if ($hasPrevious): ?>
<li class="page-item">
<a class="page-link" href="?cursor=0<?= $queryString ?>" aria-label="First">
<span aria-hidden="true">&laquo;&laquo;</span>
<span class="sr-only">First</span>
</a>
</li>
<li class="page-item">
<a class="page-link" href="?cursor=<?= max(0, $currentCursor - $perPage) ?><?= $queryString ?>" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">Previous</span>
</a>
</li>
<?php else: ?>
<li class="page-item disabled">
<span class="page-link">
<span aria-hidden="true">&laquo;&laquo;</span>
</span>
</li>
<li class="page-item disabled">
<span class="page-link">
<span aria-hidden="true">&laquo;</span>
</span>
</li>
<?php endif; ?>
<li class="page-item active">
<span class="page-link">Current</span>
</li>
<?php if ($hasNext): ?>
<li class="page-item">
<a class="page-link" href="?cursor=<?= $lastId ?><?= $queryString ?>" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">Next</span>
</a>
</li>
<?php else: ?>
<li class="page-item disabled">
<span class="page-link">
<span aria-hidden="true">&raquo;</span>
</span>
</li>
<?php endif; ?>
</ul>
</div>
</nav>
</div>
</div>
<script>
function toggleSelectAll() {
const selectAll = document.getElementById('selectAll');
const checkboxes = document.querySelectorAll('.item-checkbox');
checkboxes.forEach(checkbox => {
checkbox.checked = selectAll.checked;
});
updateBulkActions();
}
function updateBulkActions() {
const checkboxes = document.querySelectorAll('.item-checkbox:checked');
const bulkActions = document.getElementById('bulkActions');
const selectedCount = document.getElementById('selectedCount');
const selectedItems = document.getElementById('selectedItems');
const selectAll = document.getElementById('selectAll');
const count = checkboxes.length;
selectedCount.textContent = count;
if (count > 0) {
bulkActions.classList.add('show');
const ids = Array.from(checkboxes).map(cb => cb.value);
selectedItems.value = ids.join(',');
} else {
bulkActions.classList.remove('show');
selectedItems.value = '';
}
// Update select all checkbox state
const allCheckboxes = document.querySelectorAll('.item-checkbox');
const checkedCheckboxes = document.querySelectorAll('.item-checkbox:checked');
if (checkedCheckboxes.length === 0) {
selectAll.indeterminate = false;
selectAll.checked = false;
} else if (checkedCheckboxes.length === allCheckboxes.length) {
selectAll.indeterminate = false;
selectAll.checked = true;
} else {
selectAll.indeterminate = true;
}
}
function clearSelection() {
const checkboxes = document.querySelectorAll('.item-checkbox');
const selectAll = document.getElementById('selectAll');
checkboxes.forEach(checkbox => {
checkbox.checked = false;
});
selectAll.checked = false;
selectAll.indeterminate = false;
updateBulkActions();
}
function confirmBulkDelete() {
const count = document.querySelectorAll('.item-checkbox:checked').length;
if (count === 0) {
alert('Please select at least one item to delete.');
return false;
}
return confirm(`Are you sure you want to delete ${count} selected license(s)? This action cannot be undone.`);
}
</script>