📋 All Bookings

Live view of every reservation made through AquaBook

📅
Total Bookings
🎱
8-Ball Pool
🎯
Snooker
👑
VIP Room

Reservation List

# Name Phone Date Time Slot Table Type Booked On Action

Loading bookings...

// ── Global bookings store ── let allBookings = []; let currentFilter = 'all'; // ── Toast ── function showToast(msg, type = 'success') { const toast = document.getElementById('toast'); toast.textContent = msg; toast.className = `toast show ${type === 'success' ? 'ok' : 'err'}`; setTimeout(() => toast.classList.remove('show'), 3000); } // ── Label helpers ── function tableLabel(type) { if (type === '8ball') return '🎱 8-Ball'; if (type === 'snooker') return '🎯 Snooker'; if (type === 'vip') return '👑 VIP Room'; return type; } function formatDate(dateStr) { if (!dateStr) return '—'; const d = new Date(dateStr); return d.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' }); } function formatCreatedAt(iso) { const d = new Date(iso); return d.toLocaleDateString('en-IN', { day: '2-digit', month: 'short', year: 'numeric' }); } // ── Update stats ── function updateStats(bookings) { document.getElementById('stat-total').textContent = bookings.length; document.getElementById('stat-8ball').textContent = bookings.filter(b => b.tableType === '8ball').length; document.getElementById('stat-snooker').textContent = bookings.filter(b => b.tableType === 'snooker').length; document.getElementById('stat-vip').textContent = bookings.filter(b => b.tableType === 'vip').length; } // ── Render table rows ── function renderTable(bookings) { const tbody = document.getElementById('bookings-body'); const stateDiv = document.getElementById('table-state'); if (bookings.length === 0) { tbody.innerHTML = ''; stateDiv.style.display = 'block'; stateDiv.innerHTML = '
📭

No bookings found for this filter.

'; return; } stateDiv.style.display = 'none'; tbody.innerHTML = bookings.map((b, i) => ` ${i + 1} ${b.name} ${b.phone || ''} ${b.date} ${b.timeSlot ? `${b.timeSlot}` : ''} ${tableLabel(b.tableType)} ${formatCreatedAt(b.createdAt)} `).join(''); } // ── Filter ── function filterBookings(btn, filter) { // Update active button document.querySelectorAll('.filter-bar button').forEach(b => b.classList.remove('active')); btn.classList.add('active'); currentFilter = filter; const filtered = filter === 'all' ? allBookings : allBookings.filter(b => b.tableType === filter); renderTable(filtered); } // ── Load bookings from API ── async function loadBookings() { const stateDiv = document.getElementById('table-state'); const tbody = document.getElementById('bookings-body'); tbody.innerHTML = ''; stateDiv.style.display = 'block'; stateDiv.innerHTML = '

Loading bookings...

'; try { const res = await fetch('https://aquabook-u419.onrender.com/api/bookings'); const data = await res.json(); allBookings = data; updateStats(data); const filtered = currentFilter === 'all' ? allBookings : allBookings.filter(b => b.tableType === currentFilter); renderTable(filtered); } catch (err) { stateDiv.style.display = 'block'; stateDiv.innerHTML = `
🚫

Could not connect to backend. Make sure the server is running on port 5000.

`; } } // ── Cancel / Delete booking ── async function cancelBooking(id) { if (!confirm('Are you sure you want to cancel this booking?')) return; const btn = document.getElementById(`cancel-${id}`); btn.disabled = true; btn.textContent = 'Cancelling...'; try { const res = await fetch(`https://aquabook-u419.onrender.com/api/bookings/${id}`, { method: 'DELETE' }); const data = await res.json(); if (res.ok) { // Remove row with fade const row = document.getElementById(`row-${id}`); row.style.opacity = '0'; row.style.transition = 'opacity 0.3s ease'; setTimeout(() => { allBookings = allBookings.filter(b => b._id !== id); updateStats(allBookings); const filtered = currentFilter === 'all' ? allBookings : allBookings.filter(b => b.tableType === currentFilter); renderTable(filtered); }, 300); showToast('✅ Booking cancelled successfully.', 'success'); } else { showToast(`❌ Error: ${data.error}`, 'error'); btn.disabled = false; btn.textContent = 'Cancel'; } } catch (err) { showToast('❌ Could not connect to server.', 'error'); btn.disabled = false; btn.textContent = 'Cancel'; } } // ── Load stats from /api/stats (Mongoose aggregation) ── async function loadStats() { try { const res = await fetch('https://aquabook-u419.onrender.com/api/stats'); const data = await res.json(); if (!res.ok) return; document.getElementById('stat-total').textContent = data.total; document.getElementById('stat-8ball').textContent = data.byType['8ball'] || 0; document.getElementById('stat-snooker').textContent = data.byType['snooker'] || 0; document.getElementById('stat-vip').textContent = data.byType['vip'] || 0; // Add Most Booked Date card if bookings exist const statsSection = document.getElementById('stats-section'); if (statsSection && !document.getElementById('stat-most-booked') && data.mostBookedDate.date !== 'N/A') { const card = document.createElement('div'); card.className = 'stat-card'; card.innerHTML = `
🔥
${data.mostBookedDate.date}
Most Booked Date (${data.mostBookedDate.count} bookings)
`; statsSection.appendChild(card); } } catch (err) { console.warn('Stats fetch failed:', err.message); } } // ── Init ── loadBookings(); loadStats();