218 lines
13 KiB
PHP
218 lines
13 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
require_once __DIR__ . '/includes/layout.php';
|
|
|
|
$errors = [];
|
|
$flash = null;
|
|
|
|
// Handle action (Delete)
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'], $_POST['shipment_id'])) {
|
|
$shipmentId = (int)$_POST['shipment_id'];
|
|
$action = $_POST['action'];
|
|
|
|
if ($action === 'delete') {
|
|
db()->prepare("DELETE FROM shipments WHERE id = ?")->execute([$shipmentId]);
|
|
$flash = 'Shipment deleted successfully.';
|
|
}
|
|
}
|
|
|
|
// Search, Filter, Sort and Pagination parameters
|
|
$q = trim($_GET['q'] ?? '');
|
|
$status = trim($_GET['status'] ?? '');
|
|
$sort = trim($_GET['sort'] ?? 'newest');
|
|
$page = max(1, (int)($_GET['page'] ?? 1));
|
|
$limit = 10;
|
|
$offset = ($page - 1) * $limit;
|
|
|
|
$whereClause = "1=1";
|
|
$params = [];
|
|
|
|
if ($q !== '') {
|
|
$whereClause .= " AND (shipper_name LIKE ? OR shipper_company LIKE ? OR origin_city LIKE ? OR destination_city LIKE ? OR cargo_description LIKE ?)";
|
|
$likeQ = "%$q%";
|
|
$params = array_merge($params, array_fill(0, 5, $likeQ));
|
|
}
|
|
|
|
if ($status !== '' && in_array($status, ['posted', 'offered', 'confirmed', 'in_transit', 'delivered'])) {
|
|
$whereClause .= " AND status = ?";
|
|
$params[] = $status;
|
|
}
|
|
|
|
// Sorting logic
|
|
$orderBy = match ($sort) {
|
|
'oldest' => 'created_at ASC',
|
|
'pickup_asc' => 'pickup_date ASC',
|
|
'pickup_desc' => 'pickup_date DESC',
|
|
default => 'created_at DESC', // newest
|
|
};
|
|
|
|
// Total count
|
|
$countSql = "SELECT COUNT(*) FROM shipments WHERE $whereClause";
|
|
$stmt = db()->prepare($countSql);
|
|
$stmt->execute($params);
|
|
$total = (int)$stmt->fetchColumn();
|
|
$totalPages = (int)ceil($total / $limit);
|
|
|
|
// Fetch shipments
|
|
$sql = "
|
|
SELECT *
|
|
FROM shipments
|
|
WHERE $whereClause
|
|
ORDER BY $orderBy
|
|
LIMIT $limit OFFSET $offset
|
|
";
|
|
$stmt = db()->prepare($sql);
|
|
$stmt->execute($params);
|
|
$shipments = $stmt->fetchAll();
|
|
|
|
render_header('Manage Shipments', 'admin');
|
|
?>
|
|
|
|
<div class="row g-4">
|
|
<div class="col-lg-3">
|
|
<?php render_admin_sidebar('shipments'); ?>
|
|
</div>
|
|
<div class="col-lg-9">
|
|
<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">Shipments</h1>
|
|
<p class="muted mb-0">Manage all shipments across the platform.</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-5">
|
|
<label class="form-label small text-muted">Search</label>
|
|
<input type="text" name="q" class="form-control" placeholder="Search shipments..." 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="posted" <?= $status === 'posted' ? 'selected' : '' ?>>Posted</option>
|
|
<option value="offered" <?= $status === 'offered' ? 'selected' : '' ?>>Offered</option>
|
|
<option value="confirmed" <?= $status === 'confirmed' ? 'selected' : '' ?>>Confirmed</option>
|
|
<option value="in_transit" <?= $status === 'in_transit' ? 'selected' : '' ?>>In Transit</option>
|
|
<option value="delivered" <?= $status === 'delivered' ? 'selected' : '' ?>>Delivered</option>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label small text-muted">Sort By</label>
|
|
<select name="sort" class="form-select">
|
|
<option value="newest" <?= $sort === 'newest' ? 'selected' : '' ?>>Newest First</option>
|
|
<option value="oldest" <?= $sort === 'oldest' ? 'selected' : '' ?>>Oldest First</option>
|
|
<option value="pickup_asc" <?= $sort === 'pickup_asc' ? 'selected' : '' ?>>Pickup Date (Soonest)</option>
|
|
<option value="pickup_desc" <?= $sort === 'pickup_desc' ? 'selected' : '' ?>>Pickup Date (Latest)</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 (!$shipments && ($q || $status)): ?>
|
|
<div class="p-4"><p class="muted mb-0">No shipments found matching your criteria.</p></div>
|
|
<?php elseif (!$shipments): ?>
|
|
<div class="p-4"><p class="muted mb-0">No shipments found on the platform 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>Shipper</th>
|
|
<th>Route</th>
|
|
<th>Dates</th>
|
|
<th>Status</th>
|
|
<th class="text-end pe-4">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($shipments as $shipment): ?>
|
|
<tr>
|
|
<td class="ps-4"><?= e((string)$shipment['id']) ?></td>
|
|
<td>
|
|
<div class="fw-bold text-dark"><?= e($shipment['shipper_name']) ?></div>
|
|
<div class="text-muted small"><?= e((string)$shipment['shipper_company']) ?></div>
|
|
</td>
|
|
<td>
|
|
<div><span class="text-muted small">From:</span> <?= e($shipment['origin_city']) ?></div>
|
|
<div><span class="text-muted small">To:</span> <?= e($shipment['destination_city']) ?></div>
|
|
</td>
|
|
<td>
|
|
<div class="small"><span class="text-muted">Pick:</span> <?= e($shipment['pickup_date']) ?></div>
|
|
<div class="small"><span class="text-muted">Drop:</span> <?= e($shipment['delivery_date']) ?></div>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
$statusClass = 'bg-secondary-subtle text-secondary';
|
|
if ($shipment['status'] === 'posted') $statusClass = 'bg-primary-subtle text-primary';
|
|
elseif ($shipment['status'] === 'offered') $statusClass = 'bg-info-subtle text-info';
|
|
elseif ($shipment['status'] === 'confirmed') $statusClass = 'bg-success-subtle text-success';
|
|
elseif ($shipment['status'] === 'in_transit') $statusClass = 'bg-warning-subtle text-warning';
|
|
elseif ($shipment['status'] === 'delivered') $statusClass = 'bg-dark-subtle text-dark';
|
|
?>
|
|
<span class="badge <?= $statusClass ?>"><?= e(ucfirst(str_replace('_', ' ', $shipment['status']))) ?></span>
|
|
</td>
|
|
<td class="text-end pe-4">
|
|
<div class="d-inline-flex gap-1 align-items-center">
|
|
<a href="shipment_detail.php?id=<?= e((string)$shipment['id']) ?>" class="btn btn-sm btn-light border text-primary" title="View Shipment">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="bi bi-eye" viewBox="0 0 16 16">
|
|
<path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8zM1.173 8a13.133 13.133 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13.133 13.133 0 0 1 14.828 8c-.058.087-.122.183-.195.288-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5c-2.12 0-3.879-1.168-5.168-2.457A13.134 13.134 0 0 1 1.172 8z"/>
|
|
<path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5zM4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0z"/>
|
|
</svg>
|
|
</a>
|
|
<a href="admin_shipment_edit.php?id=<?= e((string)$shipment['id']) ?>" class="btn btn-sm btn-light border text-primary" title="Edit Shipment">
|
|
<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="shipment_id" value="<?= e((string)$shipment['id']) ?>">
|
|
<button type="submit" name="action" value="delete" class="btn btn-sm btn-danger" onclick="return confirm('Delete this shipment?');" 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($shipments) ?> of <?= $total ?> shipments</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) ?>&sort=<?= urlencode($sort) ?>&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) ?>&sort=<?= urlencode($sort) ?>&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) ?>&sort=<?= urlencode($sort) ?>&page=<?= $page + 1 ?>">Next</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php render_footer(); ?>
|