288 lines
16 KiB
PHP
288 lines
16 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/layout.php';
|
|
|
|
$errors = [];
|
|
$flash = null;
|
|
|
|
// Check permission
|
|
if (!has_permission('manage_truck_owners')) {
|
|
render_header(t('truck_owners'), 'truck_owners');
|
|
echo '<div class="container py-5"><div class="alert alert-danger">Access Denied. You do not have permission to manage truck owners.</div></div>';
|
|
render_footer();
|
|
exit;
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'], $_POST['user_id'])) {
|
|
$userId = (int)$_POST['user_id'];
|
|
$action = $_POST['action'];
|
|
|
|
if ($action === 'approve') {
|
|
db()->prepare("UPDATE users SET status = 'active' WHERE id = ? AND role = 'truck_owner'")->execute([$userId]);
|
|
$flash = 'Truck Owner approved successfully.';
|
|
} elseif ($action === 'reject') {
|
|
db()->prepare("UPDATE users SET status = 'rejected' WHERE id = ? AND role = 'truck_owner'")->execute([$userId]);
|
|
$flash = 'Truck Owner rejected.';
|
|
} elseif ($action === 'delete') {
|
|
db()->prepare("DELETE FROM truck_owner_profiles WHERE user_id = ?")->execute([$userId]);
|
|
db()->prepare("DELETE FROM users WHERE id = ? AND role = 'truck_owner'")->execute([$userId]);
|
|
$flash = 'Truck Owner deleted.';
|
|
}
|
|
}
|
|
|
|
// Search and Pagination parameters
|
|
$q = trim($_GET['q'] ?? '');
|
|
$status = trim($_GET['status'] ?? '');
|
|
$page = max(1, (int)($_GET['page'] ?? 1));
|
|
$limit = 10;
|
|
$offset = ($page - 1) * $limit;
|
|
|
|
$whereClause = "u.role = 'truck_owner'";
|
|
$params = [];
|
|
|
|
if ($q !== '') {
|
|
$whereClause .= " AND (u.full_name LIKE ? OR u.email LIKE ? OR p.plate_no LIKE ? OR p.truck_type LIKE ?)";
|
|
$likeQ = "%$q%";
|
|
$params = array_merge($params, [$likeQ, $likeQ, $likeQ, $likeQ]);
|
|
}
|
|
|
|
if ($status !== '' && in_array($status, ['active', 'pending', 'rejected'])) {
|
|
$whereClause .= " AND u.status = ?";
|
|
$params[] = $status;
|
|
}
|
|
|
|
// Total count
|
|
$countSql = "
|
|
SELECT COUNT(*)
|
|
FROM users u
|
|
LEFT JOIN truck_owner_profiles p ON u.id = p.user_id
|
|
WHERE $whereClause
|
|
";
|
|
$stmt = db()->prepare($countSql);
|
|
$stmt->execute($params);
|
|
$total = (int)$stmt->fetchColumn();
|
|
$totalPages = (int)ceil($total / $limit);
|
|
|
|
// Fetch truck owners
|
|
$sql = "
|
|
SELECT u.id, u.email, u.full_name, u.status, u.created_at,
|
|
p.phone, p.truck_type, p.load_capacity, p.plate_no,
|
|
p.id_card_path, p.truck_pic_path, p.registration_path,
|
|
c.name_en AS country_name,
|
|
ci.name_en AS city_name
|
|
FROM users u
|
|
LEFT JOIN truck_owner_profiles p ON u.id = p.user_id
|
|
LEFT JOIN countries c ON p.country_id = c.id
|
|
LEFT JOIN cities ci ON p.city_id = ci.id
|
|
WHERE $whereClause
|
|
ORDER BY u.created_at DESC
|
|
LIMIT $limit OFFSET $offset
|
|
";
|
|
$stmt = db()->prepare($sql);
|
|
$stmt->execute($params);
|
|
$owners = $stmt->fetchAll();
|
|
|
|
render_header('Manage Truck Owners', 'admin', true);
|
|
?>
|
|
|
|
<div class="row g-0">
|
|
<div class="col-md-2 bg-white border-end min-vh-100">
|
|
<?php render_admin_sidebar('truck_owners'); ?>
|
|
</div>
|
|
<div class="col-md-10 p-4">
|
|
<div class="page-intro d-flex flex-column flex-md-row justify-content-between align-items-md-center mb-4">
|
|
<div>
|
|
<h1 class="section-title mb-1">Truck Owners</h1>
|
|
<p class="muted mb-0">Review registrations and approve truck owners.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if ($flash): ?>
|
|
<div class="alert alert-success" data-auto-dismiss="true"><?= e($flash) ?></div>
|
|
<?php endif; ?>
|
|
|
|
<div class="panel p-4 mb-4">
|
|
<form method="get" class="row g-3">
|
|
<div class="col-md-8">
|
|
<label class="form-label small text-muted">Search</label>
|
|
<input type="text" name="q" class="form-control" placeholder="Search name, email, plate..." value="<?= e($q) ?>">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label small text-muted">Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="">All Statuses</option>
|
|
<option value="active" <?= $status === 'active' ? 'selected' : '' ?>>Active</option>
|
|
<option value="pending" <?= $status === 'pending' ? 'selected' : '' ?>>Pending</option>
|
|
<option value="rejected" <?= $status === 'rejected' ? 'selected' : '' ?>>Rejected</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-1 d-flex align-items-end">
|
|
<button type="submit" class="btn btn-primary w-100">Filter</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="panel p-0">
|
|
<?php if (!$owners && ($q || $status)): ?>
|
|
<div class="p-4"><p class="muted mb-0">No truck owners found matching your criteria.</p></div>
|
|
<?php elseif (!$owners): ?>
|
|
<div class="p-4"><p class="muted mb-0">No truck owners registered yet.</p></div>
|
|
<?php else: ?>
|
|
<div class="table-responsive">
|
|
<table class="table mb-0 align-middle table-hover">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th class="ps-4">ID</th>
|
|
<th>Name / Email</th>
|
|
<th>Truck Info</th>
|
|
<th>Documents</th>
|
|
<th>Status</th>
|
|
<th class="text-end pe-4">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($owners as $owner): ?>
|
|
<tr>
|
|
<td class="ps-4"><?= e((string)$owner['id']) ?></td>
|
|
<td>
|
|
<div class="fw-bold text-dark"><?= e($owner['full_name']) ?></div>
|
|
<div class="text-muted small"><a href="mailto:<?= e($owner['email']) ?>" class="text-decoration-none"><?= e($owner['email']) ?></a></div>
|
|
<div class="text-muted small"><?= e((string)$owner['phone']) ?></div>
|
|
</td>
|
|
<td>
|
|
<div><strong>Type:</strong> <?= e((string)$owner['truck_type']) ?></div>
|
|
<div><strong>Cap:</strong> <?= e((string)$owner['load_capacity']) ?>t</div>
|
|
<div><strong>Plate:</strong> <?= e((string)$owner['plate_no']) ?></div>
|
|
</td>
|
|
<td>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary d-flex align-items-center gap-1" data-bs-toggle="modal" data-bs-target="#docsModal<?= $owner['id'] ?>">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-file-earmark-text" viewBox="0 0 16 16">
|
|
<path d="M5.5 7a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1zM5 9.5a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5m0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5"/>
|
|
<path d="M9.5 0H4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V4.5zm0 1v2A1.5 1.5 0 0 0 11 4.5h2V14a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1z"/>
|
|
</svg>
|
|
View Docs
|
|
</button>
|
|
</td>
|
|
<td>
|
|
<?php if ($owner['status'] === 'active'): ?>
|
|
<span class="badge bg-success-subtle text-success">Active</span>
|
|
<?php elseif ($owner['status'] === 'pending'): ?>
|
|
<span class="badge bg-warning-subtle text-warning">Pending</span>
|
|
<?php else: ?>
|
|
<span class="badge bg-danger-subtle text-danger"><?= e(ucfirst($owner['status'] ?? 'unknown')) ?></span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="text-end pe-4">
|
|
<div class="d-inline-flex gap-1 align-items-center">
|
|
<a href="admin_truck_owner_edit.php?id=<?= e((string)$owner['id']) ?>" class="btn btn-sm btn-light border text-primary" title="Edit Owner">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-pencil" viewBox="0 0 16 16">
|
|
<path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325"/>
|
|
</svg>
|
|
</a>
|
|
<form method="post" class="d-inline m-0 p-0">
|
|
<input type="hidden" name="user_id" value="<?= e((string)$owner['id']) ?>">
|
|
<?php if ($owner['status'] !== 'active'): ?>
|
|
<button type="submit" name="action" value="approve" class="btn btn-sm btn-success" title="Approve">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-check-lg" viewBox="0 0 16 16">
|
|
<path d="M12.736 3.97a.733.733 0 0 1 1.047 0c.286.289.29.756.01 1.05L7.88 12.01a.733.733 0 0 1-1.065.02L3.217 8.384a.757.757 0 0 1 0-1.06.733.733 0 0 1 1.047 0l3.052 3.093 5.4-6.425z"/>
|
|
</svg>
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php if ($owner['status'] !== 'rejected'): ?>
|
|
<button type="submit" name="action" value="reject" class="btn btn-sm btn-warning" title="Reject">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-x-lg" viewBox="0 0 16 16">
|
|
<path d="M2.146 2.854a.5.5 0 1 1 .708-.708L8 7.293l5.146-5.147a.5.5 0 0 1 .708.708L8.707 8l5.147 5.146a.5.5 0 0 1-.708.708L8 8.707l-5.146 5.147a.5.5 0 0 1-.708-.708L7.293 8z"/>
|
|
</svg>
|
|
</button>
|
|
<?php endif; ?>
|
|
<button type="submit" name="action" value="delete" class="btn btn-sm btn-danger" onclick="return confirm('Delete this truck owner forever?');" title="Delete">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-trash" viewBox="0 0 16 16">
|
|
<path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5m3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0z"/>
|
|
<path d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4zM2.5 3h11V2h-11z"/>
|
|
</svg>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<?php if ($totalPages > 1): ?>
|
|
<div class="px-4 py-3 border-top d-flex justify-content-between align-items-center">
|
|
<span class="text-muted small">Showing <?= count($owners) ?> of <?= $total ?> truck owners</span>
|
|
<ul class="pagination pagination-sm mb-0">
|
|
<li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>">
|
|
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&page=<?= $page - 1 ?>">Previous</a>
|
|
</li>
|
|
<?php for ($i = 1; $i <= $totalPages; $i++): ?>
|
|
<li class="page-item <?= $i === $page ? 'active' : '' ?>">
|
|
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&page=<?= $i ?>"><?= $i ?></a>
|
|
</li>
|
|
<?php endfor; ?>
|
|
<li class="page-item <?= $page >= $totalPages ? 'disabled' : '' ?>">
|
|
<a class="page-link" href="?q=<?= urlencode($q) ?>&status=<?= urlencode($status) ?>&page=<?= $page + 1 ?>">Next</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php foreach ($owners as $owner): ?>
|
|
<?php
|
|
$idCards = json_decode($owner['id_card_path'] ?? '[]', true) ?: [];
|
|
$regs = json_decode($owner['registration_path'] ?? '[]', true) ?: [];
|
|
$pic = $owner['truck_pic_path'];
|
|
?>
|
|
<div class="modal fade" id="docsModal<?= $owner['id'] ?>" tabindex="-1" aria-hidden="true">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Documents for <?= e($owner['full_name']) ?></h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<h6>ID Card</h6>
|
|
<div class="d-flex gap-2 mb-3 overflow-auto">
|
|
<?php foreach ($idCards as $path): ?>
|
|
<a href="<?= e('/' . $path) ?>" target="_blank">
|
|
<img src="<?= e('/' . $path) ?>" alt="ID Card" class="img-thumbnail" style="max-height: 150px;">
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<h6>Truck Registration</h6>
|
|
<div class="d-flex gap-2 mb-3 overflow-auto">
|
|
<?php foreach ($regs as $path): ?>
|
|
<a href="<?= e('/' . $path) ?>" target="_blank">
|
|
<img src="<?= e('/' . $path) ?>" alt="Registration" class="img-thumbnail" style="max-height: 150px;">
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<h6>Truck Picture</h6>
|
|
<?php if ($pic): ?>
|
|
<div>
|
|
<a href="<?= e('/' . $pic) ?>" target="_blank">
|
|
<img src="<?= e('/' . $pic) ?>" alt="Truck Pic" class="img-thumbnail" style="max-height: 250px;">
|
|
</a>
|
|
</div>
|
|
<?php else: ?>
|
|
<span class="text-muted">No picture uploaded.</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
|
|
<?php render_footer(); ?>
|