File size: 3,675 Bytes
aefe381 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /**
* VenueFlow — Queue Management UI
*/
// Filter queue stations by category
document.addEventListener('DOMContentLoaded', () => {
const filterBtns = document.querySelectorAll('.queue-filter');
filterBtns.forEach(btn => {
btn.addEventListener('click', () => {
const category = btn.dataset.category;
// Update active state
filterBtns.forEach(b => {
b.classList.remove('active');
b.classList.replace('btn-primary', 'btn-secondary');
b.setAttribute('aria-selected', 'false');
});
btn.classList.add('active');
btn.classList.replace('btn-secondary', 'btn-primary');
btn.setAttribute('aria-selected', 'true');
// Filter cards
const cards = document.querySelectorAll('#queue-stations-list .queue-card');
cards.forEach(card => {
if (category === 'all' || card.dataset.category === category) {
card.style.display = 'flex';
} else {
card.style.display = 'none';
}
});
});
});
// Auto-refresh queue data
setInterval(refreshQueues, 5000);
});
async function refreshQueues() {
try {
const data = await apiCall('/api/queue/summary');
if (!data || !data.stations) return;
data.stations.forEach(station => {
const card = document.querySelector(`[data-station-id="${station.id}"]`);
if (!card) return;
const waitEl = card.querySelector('.queue-wait');
if (waitEl) {
waitEl.textContent = Math.round(station.estimated_wait_minutes) + ' min';
waitEl.style.color = station.wait_color;
}
const metaEl = card.querySelector('.queue-meta');
if (metaEl) {
metaEl.textContent = `${station.category_label} • ${station.current_length} in line`;
}
const progressBar = card.querySelector('.progress-bar');
if (progressBar) {
const w = Math.min(station.estimated_wait_minutes * 3.3, 100);
progressBar.style.width = w + '%';
progressBar.className = `progress-bar ${station.wait_level}`;
}
});
} catch (e) {
// Silent fail for background refresh
}
}
async function joinQueue(stationId) {
try {
const ticket = await apiCall('/api/queue/join', {
method: 'POST',
body: JSON.stringify({ station_id: stationId }),
});
if (ticket && ticket.id) {
showToast(
'Queue Joined! 🎫',
`Ticket #${ticket.id} — Position ${ticket.position} at ${ticket.station_name}`,
'success',
8000
);
// Refresh the page to show updated tickets
setTimeout(() => location.reload(), 1500);
}
} catch (err) {
showToast('Could not join queue', err.message || 'Please try again', 'error');
}
}
async function cancelTicket(ticketId) {
if (!confirm('Cancel this virtual queue ticket?')) return;
try {
await apiCall('/api/queue/cancel', {
method: 'POST',
body: JSON.stringify({ ticket_id: ticketId }),
});
showToast('Ticket Cancelled', 'Your virtual queue spot has been released.', 'info');
setTimeout(() => location.reload(), 1000);
} catch (err) {
showToast('Could not cancel', err.message || 'Please try again', 'error');
}
}
console.log('⏱️ Queue UI loaded');
|