add paginations
This commit is contained in:
parent
4ee179ebfe
commit
1b3577b917
75
expenses.php
75
expenses.php
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
require_once __DIR__ . '/includes/accounting_functions.php'; // Include accounting helpers
|
require_once __DIR__ . '/includes/accounting_functions.php'; // Include accounting helpers
|
||||||
|
require_once __DIR__ . '/includes/pagination.php';
|
||||||
|
|
||||||
if (!canView('expenses')) {
|
if (!canView('expenses')) {
|
||||||
redirect('index.php');
|
redirect('index.php');
|
||||||
@ -152,28 +153,56 @@ $date_to = $_GET['date_to'] ?? date('Y-m-t');
|
|||||||
$category_filter = $_GET['category_id'] ?? '';
|
$category_filter = $_GET['category_id'] ?? '';
|
||||||
$search = $_GET['search'] ?? '';
|
$search = $_GET['search'] ?? '';
|
||||||
|
|
||||||
|
// Build WHERE clause
|
||||||
|
$whereConditions = ["e.date BETWEEN ? AND ?"];
|
||||||
|
$params = [$date_from, $date_to];
|
||||||
|
|
||||||
|
if ($category_filter) {
|
||||||
|
$whereConditions[] = "e.category_id = ?";
|
||||||
|
$params[] = $category_filter;
|
||||||
|
}
|
||||||
|
if ($search) {
|
||||||
|
$whereConditions[] = "(e.description LIKE ? OR e.vendor LIKE ? OR e.reference LIKE ?)";
|
||||||
|
$params[] = "%$search%";
|
||||||
|
$params[] = "%$search%";
|
||||||
|
$params[] = "%$search%";
|
||||||
|
}
|
||||||
|
|
||||||
|
$whereClause = implode(' AND ', $whereConditions);
|
||||||
|
|
||||||
|
// Pagination
|
||||||
|
$page = $_GET['page'] ?? 1;
|
||||||
|
$perPage = 10;
|
||||||
|
|
||||||
|
// Count Total Items & Sum Total Amount
|
||||||
|
$countSql = "SELECT COUNT(*) as count, SUM(amount) as total_amount FROM expenses e WHERE $whereClause";
|
||||||
|
$countStmt = db()->prepare($countSql);
|
||||||
|
$countStmt->execute($params);
|
||||||
|
$countResult = $countStmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$totalExpenses = $countResult['count'];
|
||||||
|
$grandTotalAmount = $countResult['total_amount'] ?? 0;
|
||||||
|
|
||||||
|
$pagination = getPagination($page, $totalExpenses, $perPage);
|
||||||
|
|
||||||
|
// Fetch Items
|
||||||
$sql = "SELECT e.*, c.name as category_name, u.username as created_by_name
|
$sql = "SELECT e.*, c.name as category_name, u.username as created_by_name
|
||||||
FROM expenses e
|
FROM expenses e
|
||||||
LEFT JOIN expense_categories c ON e.category_id = c.id
|
LEFT JOIN expense_categories c ON e.category_id = c.id
|
||||||
LEFT JOIN users u ON e.user_id = u.id
|
LEFT JOIN users u ON e.user_id = u.id
|
||||||
WHERE e.date BETWEEN ? AND ?";
|
WHERE $whereClause
|
||||||
$params = [$date_from, $date_to];
|
ORDER BY e.date DESC, e.id DESC
|
||||||
|
LIMIT ? OFFSET ?";
|
||||||
|
|
||||||
if ($category_filter) {
|
// Add LIMIT/OFFSET to params
|
||||||
$sql .= " AND e.category_id = ?";
|
$params[] = $pagination['limit'];
|
||||||
$params[] = $category_filter;
|
$params[] = $pagination['offset'];
|
||||||
}
|
|
||||||
if ($search) {
|
|
||||||
$sql .= " AND (e.description LIKE ? OR e.vendor LIKE ? OR e.reference LIKE ?)";
|
|
||||||
$params[] = "%$search%";
|
|
||||||
$params[] = "%$search%";
|
|
||||||
$params[] = "%$search%";
|
|
||||||
}
|
|
||||||
|
|
||||||
$sql .= " ORDER BY e.date DESC, e.id DESC";
|
|
||||||
|
|
||||||
$stmt = db()->prepare($sql);
|
$stmt = db()->prepare($sql);
|
||||||
$stmt->execute($params);
|
foreach ($params as $k => $v) {
|
||||||
|
$type = is_int($v) ? PDO::PARAM_INT : PDO::PARAM_STR;
|
||||||
|
$stmt->bindValue($k + 1, $v, $type);
|
||||||
|
}
|
||||||
|
$stmt->execute();
|
||||||
$expenses = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$expenses = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
// Fetch Categories for Dropdown
|
// Fetch Categories for Dropdown
|
||||||
@ -299,9 +328,16 @@ if (isset($_SESSION['success'])) {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<tr class="bg-light fw-bold">
|
<!-- Page Total -->
|
||||||
<td colspan="4" class="text-end">الإجمالي:</td>
|
<tr class="bg-light">
|
||||||
<td class="text-danger"><?= number_format(array_sum(array_column($expenses, 'amount')), 2) ?></td>
|
<td colspan="4" class="text-end fw-bold">إجمالي الصفحة:</td>
|
||||||
|
<td class="text-danger fw-bold"><?= number_format(array_sum(array_column($expenses, 'amount')), 2) ?></td>
|
||||||
|
<td colspan="3"></td>
|
||||||
|
</tr>
|
||||||
|
<!-- Grand Total -->
|
||||||
|
<tr class="bg-light border-top-0">
|
||||||
|
<td colspan="4" class="text-end fw-bold">الإجمالي الكلي (للبحث الحالي):</td>
|
||||||
|
<td class="text-danger fw-bold"><?= number_format($grandTotalAmount, 2) ?></td>
|
||||||
<td colspan="3"></td>
|
<td colspan="3"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@ -309,6 +345,9 @@ if (isset($_SESSION['success'])) {
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-footer bg-white">
|
||||||
|
<?= renderPagination($pagination['current_page'], $pagination['total_pages']) ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once 'includes/header.php';
|
require_once 'includes/header.php';
|
||||||
|
require_once __DIR__ . '/includes/pagination.php';
|
||||||
|
|
||||||
// Check Permission
|
// Check Permission
|
||||||
if (!canView('hr_employees')) {
|
if (!canView('hr_employees')) {
|
||||||
@ -85,6 +86,12 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
// Fetch Departments for Dropdown
|
// Fetch Departments for Dropdown
|
||||||
$departments = db()->query("SELECT * FROM hr_departments ORDER BY name")->fetchAll();
|
$departments = db()->query("SELECT * FROM hr_departments ORDER BY name")->fetchAll();
|
||||||
|
|
||||||
|
// Pagination
|
||||||
|
$page = $_GET['page'] ?? 1;
|
||||||
|
$perPage = 10;
|
||||||
|
$totalEmployees = db()->query("SELECT COUNT(*) FROM hr_employees")->fetchColumn();
|
||||||
|
$pagination = getPagination($page, $totalEmployees, $perPage);
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||||
@ -224,7 +231,7 @@ $departments = db()->query("SELECT * FROM hr_departments ORDER BY name")->fetchA
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- List View -->
|
<!-- List View -->
|
||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm mb-4">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-hover align-middle">
|
<table class="table table-hover align-middle">
|
||||||
@ -240,8 +247,16 @@ $departments = db()->query("SELECT * FROM hr_departments ORDER BY name")->fetchA
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php
|
<?php
|
||||||
$sql = "SELECT e.*, d.name as dept_name FROM hr_employees e LEFT JOIN hr_departments d ON e.department_id = d.id ORDER BY e.first_name";
|
$sql = "SELECT e.*, d.name as dept_name
|
||||||
$stmt = db()->query($sql);
|
FROM hr_employees e
|
||||||
|
LEFT JOIN hr_departments d ON e.department_id = d.id
|
||||||
|
ORDER BY e.first_name
|
||||||
|
LIMIT ? OFFSET ?";
|
||||||
|
$stmt = db()->prepare($sql);
|
||||||
|
$stmt->bindValue(1, $pagination['limit'], PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(2, $pagination['offset'], PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
while ($row = $stmt->fetch()):
|
while ($row = $stmt->fetch()):
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
@ -307,6 +322,9 @@ $departments = db()->query("SELECT * FROM hr_departments ORDER BY name")->fetchA
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-footer bg-white">
|
||||||
|
<?= renderPagination($pagination['current_page'], $pagination['total_pages']) ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
100
includes/pagination.php
Normal file
100
includes/pagination.php
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate pagination parameters.
|
||||||
|
*
|
||||||
|
* @param int $page Current page number (1-based)
|
||||||
|
* @param int $total Total number of items
|
||||||
|
* @param int $perPage Items per page (default 10)
|
||||||
|
* @return array ['offset' => int, 'limit' => int, 'total_pages' => int, 'current_page' => int]
|
||||||
|
*/
|
||||||
|
function getPagination($page, $total, $perPage = 10) {
|
||||||
|
$page = max(1, (int)$page);
|
||||||
|
$perPage = max(1, (int)$perPage);
|
||||||
|
$totalPages = ceil($total / $perPage);
|
||||||
|
|
||||||
|
// Ensure page doesn't exceed total pages (unless total is 0)
|
||||||
|
if ($totalPages > 0 && $page > $totalPages) {
|
||||||
|
$page = $totalPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
$offset = ($page - 1) * $perPage;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'offset' => $offset,
|
||||||
|
'limit' => $perPage,
|
||||||
|
'total_pages' => $totalPages,
|
||||||
|
'current_page' => $page
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to build pagination link with existing query params
|
||||||
|
*/
|
||||||
|
function getPaginationLink($page, $queryParams = []) {
|
||||||
|
$params = array_merge($_GET, $queryParams);
|
||||||
|
$params['page'] = $page;
|
||||||
|
return '?' . http_build_query($params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render pagination links using Bootstrap 5.
|
||||||
|
*
|
||||||
|
* @param int $currentPage
|
||||||
|
* @param int $totalPages
|
||||||
|
* @return string HTML for pagination
|
||||||
|
*/
|
||||||
|
function renderPagination($currentPage, $totalPages) {
|
||||||
|
if ($totalPages <= 1) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = '<nav aria-label="Page navigation" class="mt-4"><ul class="pagination justify-content-center">';
|
||||||
|
|
||||||
|
// Previous Button
|
||||||
|
if ($currentPage > 1) {
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . getPaginationLink($currentPage - 1) . '">السابق</a></li>';
|
||||||
|
} else {
|
||||||
|
$html .= '<li class="page-item disabled"><span class="page-link">السابق</span></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Page Numbers
|
||||||
|
// Simple logic: Show all if <= 7, else show start, end, and around current
|
||||||
|
// For simplicity in this iteration, let's show a sliding window or just simple list
|
||||||
|
// Let's do a simple sliding window of 5
|
||||||
|
$start = max(1, $currentPage - 2);
|
||||||
|
$end = min($totalPages, $currentPage + 2);
|
||||||
|
|
||||||
|
if ($start > 1) {
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . getPaginationLink(1) . '">1</a></li>';
|
||||||
|
if ($start > 2) {
|
||||||
|
$html .= '<li class="page-item disabled"><span class="page-link">...</span></li>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = $start; $i <= $end; $i++) {
|
||||||
|
$active = ($i == $currentPage) ? 'active' : '';
|
||||||
|
if ($i == $currentPage) {
|
||||||
|
$html .= '<li class="page-item active"><span class="page-link">' . $i . '</span></li>';
|
||||||
|
} else {
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . getPaginationLink($i) . '">' . $i . '</a></li>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($end < $totalPages) {
|
||||||
|
if ($end < $totalPages - 1) {
|
||||||
|
$html .= '<li class="page-item disabled"><span class="page-link">...</span></li>';
|
||||||
|
}
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . getPaginationLink($totalPages) . '">' . $totalPages . '</a></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next Button
|
||||||
|
if ($currentPage < $totalPages) {
|
||||||
|
$html .= '<li class="page-item"><a class="page-link" href="' . getPaginationLink($currentPage + 1) . '">التالي</a></li>';
|
||||||
|
} else {
|
||||||
|
$html .= '<li class="page-item disabled"><span class="page-link">التالي</span></li>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= '</ul></nav>';
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
53
meetings.php
53
meetings.php
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
ob_start();
|
ob_start();
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
require_once __DIR__ . '/includes/pagination.php';
|
||||||
|
|
||||||
if (!canView('meetings')) {
|
if (!canView('meetings')) {
|
||||||
redirect('index.php');
|
redirect('index.php');
|
||||||
@ -67,27 +68,60 @@ $date_to = $_GET['date_to'] ?? date('Y-m-t');
|
|||||||
$status_filter = $_GET['status'] ?? '';
|
$status_filter = $_GET['status'] ?? '';
|
||||||
$search = $_GET['search'] ?? '';
|
$search = $_GET['search'] ?? '';
|
||||||
|
|
||||||
$sql = "SELECT m.*, u.username as created_by_name
|
// Base WHERE conditions
|
||||||
FROM meetings m
|
$whereConditions = ["DATE(m.start_time) BETWEEN ? AND ?"];
|
||||||
LEFT JOIN users u ON m.created_by = u.id
|
|
||||||
WHERE DATE(m.start_time) BETWEEN ? AND ?";
|
|
||||||
$params = [$date_from, $date_to];
|
$params = [$date_from, $date_to];
|
||||||
|
|
||||||
if ($status_filter) {
|
if ($status_filter) {
|
||||||
$sql .= " AND m.status = ?";
|
$whereConditions[] = "m.status = ?";
|
||||||
$params[] = $status_filter;
|
$params[] = $status_filter;
|
||||||
}
|
}
|
||||||
if ($search) {
|
if ($search) {
|
||||||
$sql .= " AND (m.title LIKE ? OR m.description LIKE ? OR m.location LIKE ?)";
|
$whereConditions[] = "(m.title LIKE ? OR m.description LIKE ? OR m.location LIKE ?)";
|
||||||
$params[] = "%$search%";
|
$params[] = "%$search%";
|
||||||
$params[] = "%$search%";
|
$params[] = "%$search%";
|
||||||
$params[] = "%$search%";
|
$params[] = "%$search%";
|
||||||
}
|
}
|
||||||
|
|
||||||
$sql .= " ORDER BY m.start_time ASC";
|
$whereClause = implode(' AND ', $whereConditions);
|
||||||
|
|
||||||
|
// Pagination
|
||||||
|
$page = $_GET['page'] ?? 1;
|
||||||
|
$perPage = 10;
|
||||||
|
|
||||||
|
// Count Total Items
|
||||||
|
$countSql = "SELECT COUNT(*) FROM meetings m WHERE $whereClause";
|
||||||
|
$countStmt = db()->prepare($countSql);
|
||||||
|
$countStmt->execute($params);
|
||||||
|
$totalMeetings = $countStmt->fetchColumn();
|
||||||
|
|
||||||
|
$pagination = getPagination($page, $totalMeetings, $perPage);
|
||||||
|
|
||||||
|
// Fetch Items with Limit
|
||||||
|
$sql = "SELECT m.*, u.username as created_by_name
|
||||||
|
FROM meetings m
|
||||||
|
LEFT JOIN users u ON m.created_by = u.id
|
||||||
|
WHERE $whereClause
|
||||||
|
ORDER BY m.start_time ASC
|
||||||
|
LIMIT ? OFFSET ?";
|
||||||
|
|
||||||
|
// Add LIMIT and OFFSET to params
|
||||||
|
$params[] = $pagination['limit'];
|
||||||
|
$params[] = $pagination['offset'];
|
||||||
|
|
||||||
$stmt = db()->prepare($sql);
|
$stmt = db()->prepare($sql);
|
||||||
$stmt->execute($params);
|
|
||||||
|
// Bind params manually because limit/offset must be integers
|
||||||
|
// But wait, $params is mixed string/int.
|
||||||
|
// PDO::execute($params) treats all as strings which is fine for limit/offset in MySQL usually,
|
||||||
|
// but strictly speaking, LIMIT/OFFSET should be ints.
|
||||||
|
// Let's bind all params.
|
||||||
|
foreach ($params as $k => $v) {
|
||||||
|
// 1-based index
|
||||||
|
$type = is_int($v) ? PDO::PARAM_INT : PDO::PARAM_STR;
|
||||||
|
$stmt->bindValue($k + 1, $v, $type);
|
||||||
|
}
|
||||||
|
$stmt->execute();
|
||||||
$meetings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
$meetings = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
if (isset($_SESSION['success'])) {
|
if (isset($_SESSION['success'])) {
|
||||||
@ -244,6 +278,9 @@ if (isset($_SESSION['success'])) {
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-footer bg-white">
|
||||||
|
<?= renderPagination($pagination['current_page'], $pagination['total_pages']) ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
|
|||||||
15
users.php
15
users.php
@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/includes/header.php';
|
require_once __DIR__ . '/includes/header.php';
|
||||||
|
require_once __DIR__ . '/includes/pagination.php';
|
||||||
|
|
||||||
if (!canView('users')) {
|
if (!canView('users')) {
|
||||||
redirect('index.php');
|
redirect('index.php');
|
||||||
@ -174,7 +175,16 @@ if (isset($_SESSION['error'])) {
|
|||||||
unset($_SESSION['error']);
|
unset($_SESSION['error']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = db()->query("SELECT * FROM users ORDER BY created_at DESC");
|
// Pagination
|
||||||
|
$page = $_GET['page'] ?? 1;
|
||||||
|
$perPage = 10;
|
||||||
|
$totalUsers = db()->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||||
|
$pagination = getPagination($page, $totalUsers, $perPage);
|
||||||
|
|
||||||
|
$stmt = db()->prepare("SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?");
|
||||||
|
$stmt->bindValue(1, $pagination['limit'], PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(2, $pagination['offset'], PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
$users = $stmt->fetchAll();
|
$users = $stmt->fetchAll();
|
||||||
|
|
||||||
// Fetch permissions for all users
|
// Fetch permissions for all users
|
||||||
@ -278,6 +288,9 @@ if (isset($_GET['action']) && $_GET['action'] === 'edit' && isset($_GET['id']))
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="card-footer bg-white">
|
||||||
|
<?= renderPagination($pagination['current_page'], $pagination['total_pages']) ?>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- User Modal -->
|
<!-- User Modal -->
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user