39414-vm/display.php
2026-03-31 16:34:19 +00:00

157 lines
9.3 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/queue_bootstrap.php';
qh_boot();
$activeCalls = qh_fetch_tickets(['called', 'in_progress'], null, 8);
$queueOverview = qh_queue_overview();
$activeVideos = [];
try {
$stmt = db()->query("SELECT video_path FROM hospital_ads WHERE is_active = 1 ORDER BY sort_order ASC, id DESC LIMIT 10");
if ($stmt) {
$activeVideos = $stmt->fetchAll(PDO::FETCH_COLUMN);
}
} catch (Throwable $e) {
// Table might not exist yet, safe to ignore
}
qh_page_start(
'display',
qh_t('General display board', 'لوحة العرض العامة'),
qh_t('Public queue display.', 'شاشة طوابير عامة.')
);
?>
<div class="container-fluid px-3 px-lg-4 py-3" data-auto-refresh="20">
<div class="row g-4 h-100">
<div class="col-xl-8 col-lg-7 d-flex flex-column gap-4">
<div class="card shadow-sm border-0 flex-grow-1">
<div class="card-header bg-white border-bottom py-3 d-flex justify-content-between align-items-center">
<div>
<h1 class="h3 mb-0 text-gray-800 fw-bold"><?= qh_h(qh_t('Now Serving', 'يتم الآن النداء')) ?></h1>
</div>
<div class="d-flex align-items-center gap-3">
<div class="fs-4 fw-bold text-dark js-live-clock"><?= qh_h(date('H:i')) ?></div>
<button type="button" class="btn btn-outline-secondary btn-sm shadow-sm js-fullscreen-toggle" aria-pressed="false" data-label-enter="<?= qh_h(qh_t('Fullscreen', 'ملء الشاشة')) ?>" data-label-exit="<?= qh_h(qh_t('Exit fullscreen', 'إنهاء ملء الشاشة')) ?>"><i class="bi bi-arrows-fullscreen"></i></button>
</div>
</div>
<div class="card-body p-4 bg-light">
<?php if ($activeCalls): ?>
<div class="row g-3">
<?php foreach ($activeCalls as $ticket): $speech = qh_call_message($ticket); ?>
<div class="col-6 col-lg-3">
<div class="card border-0 shadow-sm h-100" data-announcement-key="<?= qh_h((string) $ticket['id']) ?>-<?= qh_h((string) strtotime((string) $ticket['called_at'])) ?>" data-announcement-en="<?= qh_h($speech['en']) ?>" data-announcement-ar="<?= qh_h($speech['ar']) ?>">
<div class="card-body text-center p-3">
<div class="display-5 fw-bold text-primary mb-1"><?= qh_h($ticket['ticket_number']) ?></div>
<div class="fs-6 text-muted mb-1 text-truncate" style="max-width: 100%;" title="<?= qh_h(qh_name($ticket, 'doctor_name', qh_t('Doctor', 'الطبيب'))) ?>"><?= qh_h(qh_name($ticket, 'doctor_name', qh_t('Doctor', 'الطبيب'))) ?></div>
<div class="d-inline-block bg-primary text-white rounded px-2 py-1 fs-6 fw-bold mt-1">
<?= qh_h(qh_t('Room', 'غرفة')) ?> <?= qh_h($ticket['doctor_room'] ?? '--') ?>
</div>
</div>
<div class="card-footer bg-white text-center text-muted small py-1" style="font-size: 0.75rem;">
<?= qh_format_datetime($ticket['called_at'] ?? $ticket['updated_at']) ?>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="d-flex align-items-center justify-content-center h-100 min-vh-50 text-muted">
<div class="text-center">
<i class="bi bi-display display-1 mb-3 opacity-50"></i>
<h2><?= qh_h(qh_t('No active calls right now.', 'لا توجد نداءات نشطة حالياً.')) ?></h2>
<p class="lead opacity-75"><?= qh_h(qh_t('Please wait for your ticket number.', 'يرجى الانتظار حتى يتم نداء رقم تذكرتك.')) ?></p>
</div>
</div>
<?php endif; ?>
</div>
</div>
<div class="card shadow-sm border-0">
<div class="card-header bg-white border-bottom py-3">
<h5 class="mb-0 font-weight-bold text-dark"><?= qh_h(qh_t('Queue by Clinic', 'الطابور حسب العيادة')) ?></h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="table-light">
<tr>
<th class="border-0 px-4 py-3"><?= qh_h(qh_t('Clinic', 'العيادة')) ?></th>
<th class="border-0 py-3 text-center"><?= qh_h(qh_t('Vitals Wait', 'انتظار العلامات')) ?></th>
<th class="border-0 px-4 py-3 text-center"><?= qh_h(qh_t('Doctor Wait', 'انتظار الطبيب')) ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($queueOverview as $row): ?>
<tr>
<td class="fw-semibold px-4 py-3 text-dark"><?= qh_h(qh_name($row)) ?></td>
<td class="py-3 text-center"><span class="badge bg-warning text-dark rounded-pill px-3"><?= qh_h((string) $row['vitals_waiting']) ?></span></td>
<td class="py-3 text-center px-4"><span class="badge bg-info text-dark rounded-pill px-3"><?= qh_h((string) $row['doctor_waiting']) ?></span></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="col-xl-4 col-lg-5">
<div class="sticky-top" style="top: 1rem; height: 60vh;">
<?php if (!empty($activeVideos)): ?>
<div class="card shadow-sm border-0 h-100 bg-black overflow-hidden d-flex justify-content-center align-items-center">
<video id="adsVideoPlayer" class="w-100 h-100 object-fit-contain" autoplay muted playsinline>
<source src="<?= qh_h($activeVideos[0]) ?>" type="video/mp4">
</video>
<script>
document.addEventListener('DOMContentLoaded', function() {
const videos = <?= json_encode($activeVideos, JSON_UNESCAPED_SLASHES) ?>;
let currentIdx = 0;
const player = document.getElementById('adsVideoPlayer');
if (videos.length > 1) {
player.addEventListener('ended', function() {
currentIdx = (currentIdx + 1) % videos.length;
player.src = videos[currentIdx];
player.play().catch(function(e) { console.error("Error playing video:", e); });
});
} else {
// If only one video, loop it
player.loop = true;
}
});
</script>
</div>
<?php else: ?>
<div class="card shadow-sm border-0 h-100 bg-primary text-white">
<div class="card-header border-bottom border-light border-opacity-25 py-3 bg-transparent d-flex justify-content-between align-items-center">
<h5 class="mb-0 font-weight-bold text-white"><i class="bi bi-info-circle me-2"></i><?= qh_h(qh_t('Information', 'معلومات')) ?></h5>
<span class="badge bg-white text-primary rounded-pill small"><?= qh_h(qh_t('Notices', 'تنبيهات')) ?></span>
</div>
<div class="card-body p-4 d-flex flex-column gap-4">
<div class="border border-light border-opacity-25 rounded p-4 bg-white bg-opacity-10">
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Service', 'خدمة')) ?></div>
<h4 class="text-white fw-bold"><?= qh_h(qh_t('Lab packages & checks', 'باقات المختبر والفحوصات')) ?></h4>
<p class="mb-0 text-white text-opacity-75"><?= qh_h(qh_t('Ask reception about bundled blood tests, diabetes follow-up, and annual screenings.', 'اسأل الاستقبال عن باقات تحاليل الدم، ومتابعة السكري، والفحوصات السنوية.')) ?></p>
</div>
<div class="border border-light border-opacity-25 rounded p-4 bg-white bg-opacity-10">
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Reminder', 'تذكير')) ?></div>
<h4 class="text-white fw-bold"><?= qh_h(qh_t('Keep your ticket visible', 'احتفظ بتذكرتك ظاهرة')) ?></h4>
<p class="mb-0 text-white text-opacity-75"><?= qh_h(qh_t('We announce ticket numbers on this screen and by voice. Stay near your department area.', 'نعلن أرقام التذاكر على هذه الشاشة وبالصوت. يرجى البقاء قرب منطقة القسم الخاص بك.')) ?></p>
</div>
<div class="border border-light border-opacity-25 rounded p-4 bg-white bg-opacity-10">
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Wayfinding', 'الإرشاد')) ?></div>
<h4 class="text-white fw-bold"><?= qh_h(qh_t('Pharmacy & billing', 'الصيدلية والمحاسبة')) ?></h4>
<p class="mb-0 text-white text-opacity-75"><?= qh_h(qh_t('Completed visits can proceed to the pharmacy and billing desk near the main exit.', 'بعد انتهاء الزيارة يمكن التوجه إلى الصيدلية ومكتب المحاسبة قرب المخرج الرئيسي.')) ?></p>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<?php qh_page_end(); ?>