210 lines
8.3 KiB
PHP
210 lines
8.3 KiB
PHP
<?php
|
|
include 'header.php';
|
|
require_once '../db/config.php';
|
|
|
|
// Ensure the user is a logged-in restaurant owner
|
|
if (!isset($_SESSION['restaurant_user_id'])) {
|
|
header('Location: ../restaurant_login.php');
|
|
exit;
|
|
}
|
|
|
|
$restaurant_id = $_SESSION['restaurant_id'];
|
|
|
|
// Fetch orders belonging to this restaurant
|
|
$stmt = $pdo->prepare("
|
|
SELECT o.id, o.total_price, o.status, o.created_at, u.name as user_name
|
|
FROM orders o
|
|
JOIN users u ON o.user_id = u.id
|
|
WHERE o.restaurant_id = ?
|
|
ORDER BY o.created_at DESC
|
|
");
|
|
$stmt->execute([$restaurant_id]);
|
|
$orders = $stmt->fetchAll();
|
|
|
|
$possible_statuses = ['Pending', 'Confirmed', 'Preparing', 'Out for Delivery', 'Delivered', 'Cancelled'];
|
|
?>
|
|
|
|
<div class="container mt-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h2>Your Restaurant's Orders</h2>
|
|
<span class="badge badge-success" id="update-indicator" style="display: none;">Updated just now</span>
|
|
</div>
|
|
|
|
<div id="orders-table-container">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Order ID</th>
|
|
<th>Customer</th>
|
|
<th>Total Price</th>
|
|
<th>Order Date</th>
|
|
<th>Status</th>
|
|
<th>Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="orders-tbody">
|
|
<?php if (empty($orders)): ?>
|
|
<tr>
|
|
<td colspan="6" class="text-center">No orders found.</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($orders as $order): ?>
|
|
<tr data-order-id="<?php echo $order['id']; ?>">
|
|
<td><?php echo $order['id']; ?></td>
|
|
<td><?php echo htmlspecialchars($order['user_name']); ?></td>
|
|
<td>$<?php echo number_format($order['total_price'], 2); ?></td>
|
|
<td><?php echo $order['created_at']; ?></td>
|
|
<td>
|
|
<select class="form-control form-control-sm status-select">
|
|
<?php foreach ($possible_statuses as $status): ?>
|
|
<option value="<?php echo $status; ?>" <?php echo ($order['status'] === $status) ? 'selected' : ''; ?>>
|
|
<?php echo htmlspecialchars($status); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<a href="order_details.php?order_id=<?php echo $order['id']; ?>" class="btn btn-info btn-sm">View Details</a>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- New Order Notification Modal -->
|
|
<div class="modal fade" id="newOrderModal" tabindex="-1" role="dialog" aria-labelledby="newOrderModalLabel" aria-hidden="true">
|
|
<div class="modal-dialog modal-dialog-centered" role="document">
|
|
<div class="modal-content border-success">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="newOrderModalLabel">You have a new order!</h5>
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
<div class="modal-body">
|
|
A new order has just arrived. Please check your order list.
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-success" data-dismiss="modal">Got it</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const ordersTbody = document.getElementById('orders-tbody');
|
|
const updateIndicator = document.getElementById('update-indicator');
|
|
const noOrdersRow = document.querySelector('#orders-tbody td[colspan="6"]');
|
|
let lastCheckTimestamp = new Date().toISOString().slice(0, 19).replace('T', ' ');
|
|
|
|
const notificationSound = new Audio('https://cdn.jsdelivr.net/npm/ion-sound@3.0.7/sounds/bell_ring.mp3');
|
|
notificationSound.preload = 'auto';
|
|
|
|
const possibleStatuses = <?php echo json_encode($possible_statuses); ?>;
|
|
|
|
// --- Function to update status via API ---
|
|
async function updateOrderStatus(orderId, newStatus) {
|
|
try {
|
|
const response = await fetch('update_order_status.php', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ order_id: orderId, status: newStatus }),
|
|
});
|
|
const result = await response.json();
|
|
if (!response.ok) throw new Error(result.error || 'Failed to update status');
|
|
console.log('Status updated:', result.message);
|
|
showUpdateIndicator();
|
|
} catch (error) {
|
|
console.error('Error updating status:', error);
|
|
alert('Error: ' + error.message);
|
|
}
|
|
}
|
|
|
|
// --- Attach event listener to dropdowns ---
|
|
ordersTbody.addEventListener('change', function (e) {
|
|
if (e.target.classList.contains('status-select')) {
|
|
const selectedStatus = e.target.value;
|
|
const orderId = e.target.closest('tr').dataset.orderId;
|
|
updateOrderStatus(orderId, selectedStatus);
|
|
}
|
|
});
|
|
|
|
// --- Function to show a brief update indicator ---
|
|
function showUpdateIndicator() {
|
|
updateIndicator.style.display = 'inline';
|
|
setTimeout(() => { updateIndicator.style.display = 'none'; }, 2000);
|
|
}
|
|
|
|
// --- Create a new table row for a new order ---
|
|
function createOrderRow(order) {
|
|
const row = document.createElement('tr');
|
|
row.dataset.orderId = order.id;
|
|
|
|
const statusOptions = possibleStatuses.map(status =>
|
|
`<option value="${status}" ${order.status === status ? 'selected' : ''}>${status}</option>`
|
|
).join('');
|
|
|
|
row.innerHTML = `
|
|
<td>${order.id}</td>
|
|
<td>${order.user_name}</td>
|
|
<td>${parseFloat(order.total_price).toFixed(2)}</td>
|
|
<td>${order.created_at}</td>
|
|
<td>
|
|
<select class="form-control form-control-sm status-select">
|
|
${statusOptions}
|
|
</select>
|
|
</td>
|
|
<td>
|
|
<a href="order_details.php?order_id=${order.id}" class="btn btn-info btn-sm">View Details</a>
|
|
</td>
|
|
`;
|
|
return row;
|
|
}
|
|
|
|
// --- Function to check for new orders ---
|
|
async function checkForNewOrders() {
|
|
try {
|
|
const response = await fetch(`../api/get_new_orders.php?since=${encodeURIComponent(lastCheckTimestamp)}`);
|
|
if (!response.ok) {
|
|
console.error('Failed to check for new orders. Status:', response.status);
|
|
return;
|
|
}
|
|
const newOrders = await response.json();
|
|
|
|
if (newOrders.length > 0) {
|
|
console.log(`Found ${newOrders.length} new order(s).`);
|
|
|
|
// Play sound and show modal
|
|
notificationSound.play().catch(e => console.error("Audio play failed:", e));
|
|
$('#newOrderModal').modal('show');
|
|
|
|
// Remove "No orders found" message if it exists
|
|
if (noOrdersRow && noOrdersRow.parentElement.parentElement === ordersTbody) {
|
|
ordersTbody.innerHTML = '';
|
|
}
|
|
|
|
// Add new orders to the top of the table
|
|
newOrders.forEach(order => {
|
|
const newRow = createOrderRow(order);
|
|
ordersTbody.prepend(newRow);
|
|
});
|
|
|
|
// Update the timestamp to the latest order's creation time
|
|
lastCheckTimestamp = newOrders[0].created_at;
|
|
}
|
|
} catch (error) {
|
|
console.error('Error checking for new orders:', error);
|
|
}
|
|
}
|
|
|
|
// --- Initial timestamp and polling ---
|
|
console.log('Starting order polling. Last check:', lastCheckTimestamp);
|
|
setInterval(checkForNewOrders, 15000); // Check every 15 seconds
|
|
});
|
|
</script>
|
|
|
|
<?php include 'footer.php'; ?>
|