document.addEventListener('DOMContentLoaded', () => { const clinicSelects = document.querySelectorAll('.js-clinic-select'); clinicSelects.forEach((clinicSelect) => { const form = clinicSelect.closest('form'); if (!form) return; const doctorSelect = form.querySelector('.js-doctor-select'); if (!doctorSelect) return; const syncDoctors = () => { const clinicId = clinicSelect.value; Array.from(doctorSelect.options).forEach((option) => { if (!option.value) { option.hidden = false; return; } const visible = option.dataset.clinicId === clinicId; option.hidden = !visible; if (!visible && option.selected) { doctorSelect.value = ''; } }); }; clinicSelect.addEventListener('change', syncDoctors); syncDoctors(); }); const ticketPrintButton = document.querySelector('.js-print-ticket'); if (ticketPrintButton) { ticketPrintButton.addEventListener('click', () => window.print()); } document.querySelectorAll('.js-app-toast').forEach((toastNode) => { if (window.bootstrap && bootstrap.Toast) { bootstrap.Toast.getOrCreateInstance(toastNode, { delay: 3200 }).show(); } }); const locale = document.body.dataset.locale || 'en'; const timeZone = document.body.dataset.timezone || 'UTC'; const liveClock = document.querySelector('.js-live-clock'); if (liveClock) { const renderClock = () => { const now = new Date(); const opts = { hour: '2-digit', minute: '2-digit' }; if (timeZone) opts.timeZone = timeZone; try { liveClock.textContent = now.toLocaleTimeString(locale === 'ar' ? 'ar-SA' : 'en-US', opts); } catch (e) { opts.timeZone = undefined; liveClock.textContent = now.toLocaleTimeString(locale === 'ar' ? 'ar-SA' : 'en-US', opts); } }; renderClock(); window.setInterval(renderClock, 1000 * 30); } if (document.body.dataset.page === 'display') { const fullscreenButton = document.querySelector('.js-fullscreen-toggle'); const syncFullscreenButton = () => { if (!fullscreenButton) return; const isFullscreen = !!document.fullscreenElement; fullscreenButton.textContent = isFullscreen ? (fullscreenButton.dataset.labelExit || 'Exit full display') : (fullscreenButton.dataset.labelEnter || 'Full display'); fullscreenButton.setAttribute('aria-pressed', isFullscreen ? 'true' : 'false'); }; if (fullscreenButton && document.fullscreenEnabled) { fullscreenButton.addEventListener('click', async () => { try { if (document.fullscreenElement) { await document.exitFullscreen(); } else { await document.documentElement.requestFullscreen(); } } catch (error) { console.warn('Fullscreen toggle failed', error); } }); document.addEventListener('fullscreenchange', syncFullscreenButton); syncFullscreenButton(); } else if (fullscreenButton) { fullscreenButton.hidden = true; } let audioCtx = null; const initAudio = () => { try { const AudioContext = window.AudioContext || window.webkitAudioContext; if (!audioCtx && AudioContext) { audioCtx = new AudioContext(); } if (audioCtx && audioCtx.state === 'suspended') { audioCtx.resume(); } } catch (e) { console.warn('AudioContext init failed', e); } }; const audioBtn = document.querySelector('.js-audio-toggle'); if (audioBtn) { const updateAudioBtnState = () => { const isEnabled = window.localStorage.getItem('hospitalQueue:audioEnabled') === 'true'; if (isEnabled) { audioBtn.innerHTML = ''; } else { audioBtn.innerHTML = ''; } audioBtn.setAttribute('aria-pressed', isEnabled.toString()); const videoPlayer = document.getElementById('adsVideoPlayer'); if (videoPlayer) { videoPlayer.muted = !isEnabled; } }; updateAudioBtnState(); audioBtn.addEventListener('click', () => { const isEnabled = window.localStorage.getItem('hospitalQueue:audioEnabled') === 'true'; const nextState = !isEnabled; window.localStorage.setItem('hospitalQueue:audioEnabled', nextState.toString()); updateAudioBtnState(); if (nextState) { initAudio(); if ('speechSynthesis' in window) { const primeUtterance = new SpeechSynthesisUtterance(''); window.speechSynthesis.speak(primeUtterance); } } }); } const playChime = () => { try { if (!audioCtx) initAudio(); if (!audioCtx) return; if (audioCtx.state === 'suspended') audioCtx.resume(); const playTone = (freq, startTime, duration) => { const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.connect(gain); gain.connect(audioCtx.destination); osc.type = 'sine'; osc.frequency.setValueAtTime(freq, audioCtx.currentTime + startTime); gain.gain.setValueAtTime(0, audioCtx.currentTime + startTime); gain.gain.linearRampToValueAtTime(0.5, audioCtx.currentTime + startTime + 0.05); gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + startTime + duration); osc.start(audioCtx.currentTime + startTime); osc.stop(audioCtx.currentTime + startTime + duration); }; playTone(523.25, 0, 0.4); // C5 playTone(659.25, 0.3, 0.6); // E5 } catch (e) { console.warn('AudioContext failed', e); } }; const checkAnnouncements = () => { const cards = Array.from(document.querySelectorAll('.announcement-card')); const latest = cards[0]; const audioEnabled = window.localStorage.getItem('hospitalQueue:audioEnabled') === 'true'; if (latest) { const announcementKey = latest.dataset.announcementKey || ''; const storageKey = `hospitalQueue:lastAnnouncement:${locale}`; const storedKey = window.localStorage.getItem(storageKey) || ''; if (announcementKey && announcementKey !== storedKey) { window.localStorage.setItem(storageKey, announcementKey); if (audioEnabled) { const videoPlayer = document.getElementById('adsVideoPlayer'); if (videoPlayer) videoPlayer.volume = 0.1; playChime(); if ('speechSynthesis' in window) { setTimeout(() => { const text = locale === 'ar' ? (latest.dataset.announcementAr || '') : (latest.dataset.announcementEn || ''); if (text) { window.speechSynthesis.cancel(); const utterance = new SpeechSynthesisUtterance(text); utterance.lang = locale === 'ar' ? 'ar-SA' : 'en-US'; const voices = window.speechSynthesis.getVoices(); const preferredVoice = voices.find((voice) => voice.lang.toLowerCase().startsWith(locale === 'ar' ? 'ar' : 'en')); if (preferredVoice) utterance.voice = preferredVoice; utterance.onend = () => { if (videoPlayer) videoPlayer.volume = 1.0; }; utterance.onerror = () => { if (videoPlayer) videoPlayer.volume = 1.0; }; window.speechSynthesis.speak(utterance); } else { if (videoPlayer) videoPlayer.volume = 1.0; } }, 1200); // play voice after chime finishes } else { setTimeout(() => { if (videoPlayer) videoPlayer.volume = 1.0; }, 2000); } } } } }; checkAnnouncements(); const autoRefreshSeconds = parseInt(document.querySelector('[data-auto-refresh]')?.dataset.autoRefresh || '0', 10); if (autoRefreshSeconds > 0) { window.setInterval(async () => { try { const response = await fetch(window.location.href, { headers: { 'X-Requested-With': 'XMLHttpRequest' } }); if (response.ok) { const html = await response.text(); const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const newSections = doc.querySelector('#queueSections'); const currentSections = document.querySelector('#queueSections'); if (newSections && currentSections) { currentSections.innerHTML = newSections.innerHTML; } const oldTicker = document.querySelector('.news-ticker-container'); const newTicker = doc.querySelector('.news-ticker-container'); if (oldTicker && newTicker) { oldTicker.innerHTML = newTicker.innerHTML; } checkAnnouncements(); } } catch (e) { console.error('Auto-refresh failed', e); } }, autoRefreshSeconds * 1000); } } });