| |
| |
| |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| const filterBtns = document.querySelectorAll('.queue-filter'); |
|
|
| filterBtns.forEach(btn => { |
| btn.addEventListener('click', () => { |
| const category = btn.dataset.category; |
|
|
| |
| 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'); |
|
|
| |
| 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'; |
| } |
| }); |
| }); |
| }); |
|
|
| |
| 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) { |
| |
| } |
| } |
|
|
| 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 |
| ); |
|
|
| |
| 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'); |
|
|