Files
2026-05-16 23:00:37 -05:00

280 lines
11 KiB
PHP

<?php
ob_start();
/**
* Tom's Java Jive - Admin Orders Page
*/
$pageTitle = 'Orders';
require_once __DIR__ . '/includes/header.php';
// Handle status update
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
$orderId = $_POST['order_id'] ?? '';
if ($action === 'update_status' && $orderId) {
$status = $_POST['status'] ?? '';
$trackingNumber = $_POST['tracking_number'] ?? null;
$updateData = ['order_status' => $status];
if ($trackingNumber) {
$updateData['tracking_number'] = $trackingNumber;
}
db()->update('orders', $updateData, 'order_id = :id', ['id' => $orderId]);
setFlash('success', 'Order status updated');
header('Location: /admin/orders.php');
exit;
}
}
// Filters
$status = $_GET['status'] ?? '';
$search = $_GET['search'] ?? '';
$dateFrom = $_GET['date_from'] ?? '';
$dateTo = $_GET['date_to'] ?? '';
$page = max(1, intval($_GET['page'] ?? 1));
// Build query
$where = ['1=1'];
$params = [];
if ($status) {
$where[] = 'order_status = :status';
$params['status'] = $status;
}
if ($search) {
$where[] = '(order_number LIKE :search OR customer_name LIKE :search OR customer_email LIKE :search)';
$params['search'] = '%' . $search . '%';
}
if ($dateFrom) {
$where[] = 'DATE(created_at) >= :date_from';
$params['date_from'] = $dateFrom;
}
if ($dateTo) {
$where[] = 'DATE(created_at) <= :date_to';
$params['date_to'] = $dateTo;
}
$whereClause = implode(' AND ', $where);
// Get total and paginate
$totalOrders = db()->count('orders', $whereClause, $params);
$pagination = paginate($totalOrders, $page, ADMIN_ITEMS_PER_PAGE);
// Get orders
$orders = db()->fetchAll(
"SELECT * FROM orders WHERE {$whereClause} ORDER BY created_at DESC LIMIT :limit OFFSET :offset",
array_merge($params, ['limit' => $pagination['per_page'], 'offset' => $pagination['offset']])
);
$statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'];
?>
<div class="page-header">
<h1 class="page-title">Orders</h1>
<a href="/admin/pos.php" class="btn btn-primary">
<i class="fas fa-plus"></i> New Order (POS)
</a>
</div>
<?php if (hasFlash('success')): ?>
<div class="alert alert-success">
<i class="fas fa-check-circle"></i>
<?= getFlash('success') ?>
</div>
<?php endif; ?>
<!-- Filters -->
<div class="admin-card">
<div class="admin-card-body">
<form method="GET" style="display: flex; gap: 1rem; flex-wrap: wrap; align-items: end;">
<div class="form-group mb-0" style="flex: 1; min-width: 200px;">
<label class="form-label">Search</label>
<input type="text" name="search" class="form-input" placeholder="Order #, name, email..."
value="<?= htmlspecialchars($search) ?>">
</div>
<div class="form-group mb-0">
<label class="form-label">Status</label>
<select name="status" class="form-select">
<option value="">All Statuses</option>
<?php foreach ($statuses as $s): ?>
<option value="<?= $s ?>" <?= $status === $s ? 'selected' : '' ?>>
<?= ucfirst($s) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group mb-0">
<label class="form-label">From Date</label>
<input type="date" name="date_from" class="form-input" value="<?= $dateFrom ?>">
</div>
<div class="form-group mb-0">
<label class="form-label">To Date</label>
<input type="date" name="date_to" class="form-input" value="<?= $dateTo ?>">
</div>
<button type="submit" class="btn btn-secondary">
<i class="fas fa-filter"></i> Filter
</button>
<?php if ($status || $search || $dateFrom || $dateTo): ?>
<a href="/admin/orders.php" class="btn btn-secondary">Clear</a>
<?php endif; ?>
</form>
</div>
</div>
<!-- Orders Table -->
<div class="admin-card">
<div class="admin-card-header">
<span><?= $totalOrders ?> orders found</span>
</div>
<div class="admin-card-body" style="padding: 0;">
<table class="admin-table">
<thead>
<tr>
<th>Order</th>
<th>Customer</th>
<th>Items</th>
<th>Total</th>
<th>Payment</th>
<th>Status</th>
<th>Date</th>
<th style="width: 150px;">Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($orders)): ?>
<tr>
<td colspan="8" class="text-muted" style="text-align: center; padding: 2rem;">
No orders found
</td>
</tr>
<?php else: ?>
<?php foreach ($orders as $order):
$items = json_decode($order['items'], true) ?? [];
$itemCount = array_sum(array_column($items, 'quantity'));
?>
<tr>
<td>
<strong><?= htmlspecialchars($order['order_number']) ?></strong>
<?php if ($order['is_pos_order']): ?>
<span class="badge badge-primary">POS</span>
<?php endif; ?>
</td>
<td>
<div><?= htmlspecialchars($order['customer_name'] ?? 'Guest') ?></div>
<small class="text-muted"><?= htmlspecialchars($order['customer_email']) ?></small>
</td>
<td><?= $itemCount ?> item<?= $itemCount !== 1 ? 's' : '' ?></td>
<td><strong><?= formatCurrency($order['total']) ?></strong></td>
<td>
<?php
$paymentClass = match($order['payment_status']) {
'paid' => 'success',
'failed' => 'error',
'refunded' => 'warning',
default => 'primary'
};
?>
<span class="badge badge-<?= $paymentClass ?>">
<?= ucfirst($order['payment_status']) ?>
</span>
</td>
<td>
<?php
$statusClass = match($order['order_status']) {
'pending' => 'warning',
'confirmed', 'processing' => 'primary',
'shipped', 'delivered' => 'success',
'cancelled', 'refunded' => 'error',
default => 'primary'
};
?>
<span class="badge badge-<?= $statusClass ?>">
<?= ucfirst($order['order_status']) ?>
</span>
</td>
<td class="text-muted"><?= formatDate($order['created_at']) ?></td>
<td>
<a href="/admin/order.php?id=<?= $order['order_id'] ?>"
class="btn btn-sm btn-secondary" title="View">
<i class="fas fa-eye"></i>
</a>
<button type="button" class="btn btn-sm btn-secondary"
onclick="openStatusModal('<?= $order['order_id'] ?>', '<?= $order['order_status'] ?>')"
title="Update Status">
<i class="fas fa-edit"></i>
</button>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<!-- Pagination -->
<?php if ($pagination['total_pages'] > 1): ?>
<div style="display: flex; justify-content: center; margin-top: 1rem;">
<?= renderPagination($pagination, '/admin/orders.php?status=' . urlencode($status) . '&search=' . urlencode($search)) ?>
</div>
<?php endif; ?>
<!-- Status Update Modal -->
<div class="modal-overlay" id="statusModal">
<div class="modal">
<div class="modal-header">
<h3 class="modal-title">Update Order Status</h3>
<button type="button" class="modal-close" onclick="Modal.close('statusModal')">&times;</button>
</div>
<form method="POST" action="">
<div class="modal-body">
<input type="hidden" name="action" value="update_status">
<input type="hidden" name="order_id" id="modalOrderId">
<div class="form-group">
<label class="form-label">Status</label>
<select name="status" id="modalStatus" class="form-select" required>
<?php foreach ($statuses as $s): ?>
<option value="<?= $s ?>"><?= ucfirst($s) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group mb-0" id="trackingGroup" style="display: none;">
<label class="form-label">Tracking Number</label>
<input type="text" name="tracking_number" class="form-input" placeholder="Enter tracking number">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" onclick="Modal.close('statusModal')">Cancel</button>
<button type="submit" class="btn btn-primary">Update Status</button>
</div>
</form>
</div>
</div>
<script>
function openStatusModal(orderId, currentStatus) {
document.getElementById('modalOrderId').value = orderId;
document.getElementById('modalStatus').value = currentStatus;
Modal.open('statusModal');
}
document.getElementById('modalStatus').addEventListener('change', function() {
document.getElementById('trackingGroup').style.display =
this.value === 'shipped' ? 'block' : 'none';
});
</script>
<?php require_once __DIR__ . '/includes/footer.php'; ?>