482 lines
24 KiB
PHP
482 lines
24 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
require_once __DIR__ . '/queue_bootstrap.php';
|
|
qh_boot();
|
|
|
|
$activeCalls = qh_fetch_tickets(['called', 'in_progress', 'nursing_called'], null, 8);
|
|
$queueOverview = qh_queue_overview();
|
|
|
|
function qh_display_ads_column_exists(PDO $pdo, string $column): bool
|
|
{
|
|
static $cache = [];
|
|
|
|
if (array_key_exists($column, $cache)) {
|
|
return $cache[$column];
|
|
}
|
|
|
|
$stmt = $pdo->prepare(
|
|
"SELECT COUNT(*) FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = 'hospital_ads' AND COLUMN_NAME = ?"
|
|
);
|
|
$stmt->execute([DB_NAME, $column]);
|
|
|
|
return $cache[$column] = ((int) $stmt->fetchColumn() > 0);
|
|
}
|
|
|
|
$activeAds = [];
|
|
try {
|
|
$pdo = db();
|
|
$hasMediaType = qh_display_ads_column_exists($pdo, 'media_type');
|
|
$hasMediaPath = qh_display_ads_column_exists($pdo, 'media_path');
|
|
|
|
if ($hasMediaType && $hasMediaPath) {
|
|
$stmt = $pdo->query(
|
|
"SELECT id, title,
|
|
COALESCE(NULLIF(media_type, ''), 'video') AS media_type,
|
|
COALESCE(NULLIF(media_path, ''), NULLIF(video_path, '')) AS media_path
|
|
FROM hospital_ads
|
|
WHERE is_active = 1
|
|
ORDER BY sort_order ASC, id DESC"
|
|
);
|
|
} elseif ($hasMediaPath) {
|
|
$stmt = $pdo->query(
|
|
"SELECT id, title, 'video' AS media_type,
|
|
COALESCE(NULLIF(media_path, ''), NULLIF(video_path, '')) AS media_path
|
|
FROM hospital_ads
|
|
WHERE is_active = 1
|
|
ORDER BY sort_order ASC, id DESC"
|
|
);
|
|
} else {
|
|
$stmt = $pdo->query(
|
|
"SELECT id, title, 'video' AS media_type, video_path AS media_path
|
|
FROM hospital_ads
|
|
WHERE is_active = 1
|
|
ORDER BY sort_order ASC, id DESC"
|
|
);
|
|
}
|
|
|
|
if ($stmt) {
|
|
foreach ($stmt->fetchAll() as $ad) {
|
|
$mediaPath = (string) ($ad['media_path'] ?? '');
|
|
if ($mediaPath === '') {
|
|
continue;
|
|
}
|
|
$activeAds[] = [
|
|
'id' => (int) ($ad['id'] ?? 0),
|
|
'title' => (string) ($ad['title'] ?? ''),
|
|
'type' => (($ad['media_type'] ?? 'video') === 'image') ? 'image' : 'video',
|
|
'path' => $mediaPath,
|
|
'duration' => 10,
|
|
];
|
|
}
|
|
}
|
|
} catch (Throwable $e) {
|
|
// Table might not exist yet, safe to ignore
|
|
}
|
|
|
|
$activeNews = [];
|
|
try {
|
|
$stmt = db()->query("SELECT phrase FROM hospital_news WHERE is_active = 1 ORDER BY sort_order ASC, id DESC");
|
|
if ($stmt) {
|
|
$activeNews = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
}
|
|
} catch (Throwable $e) {
|
|
// Table might not exist yet
|
|
}
|
|
|
|
qh_page_start(
|
|
'display',
|
|
qh_t('General display board', 'لوحة العرض العامة'),
|
|
qh_t('Public queue display.', 'شاشة طوابير عامة.')
|
|
);
|
|
?>
|
|
<style>
|
|
/* Remove top spacing from the shell wrapper */
|
|
main.app-shell {
|
|
padding-top: 0 !important;
|
|
padding-bottom: 0 !important;
|
|
}
|
|
@keyframes highlightPulse {
|
|
0% { transform: scale(1); box-shadow: var(--shadow); border-color: transparent; background-color: var(--surface); }
|
|
50% { transform: scale(1.08); box-shadow: 0 0 40px rgba(255, 235, 59, 0.9); border-color: #ffb300; background-color: #ffeb3b; }
|
|
100% { transform: scale(1); box-shadow: var(--shadow); border-color: transparent; background-color: var(--surface); }
|
|
}
|
|
.blinking-ticket,
|
|
.announcement-current-turn {
|
|
animation: highlightPulse 1.5s ease-in-out infinite;
|
|
z-index: 10;
|
|
position: relative;
|
|
background-image: none !important; /* Ensure background-color animation works against shorthand */
|
|
}
|
|
.announcement-queued-turn {
|
|
position: relative;
|
|
border-color: rgba(13, 110, 253, 0.28) !important;
|
|
background: linear-gradient(135deg, rgba(13, 110, 253, 0.08), rgba(13, 202, 240, 0.12));
|
|
box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.08), 0 14px 30px rgba(13, 110, 253, 0.10);
|
|
transform: translateY(-2px);
|
|
transition: box-shadow 0.25s ease, transform 0.25s ease, background 0.25s ease, border-color 0.25s ease;
|
|
}
|
|
.announcement-queued-turn::after {
|
|
content: 'Next';
|
|
position: absolute;
|
|
top: 0.5rem;
|
|
right: 0.5rem;
|
|
padding: 0.18rem 0.5rem;
|
|
border-radius: 999px;
|
|
font-size: 0.72rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.04em;
|
|
color: #0b5ed7;
|
|
background: rgba(255, 255, 255, 0.92);
|
|
box-shadow: 0 6px 16px rgba(13, 110, 253, 0.12);
|
|
}
|
|
html[lang='ar'] .announcement-queued-turn::after {
|
|
content: 'التالي';
|
|
left: 0.5rem;
|
|
right: auto;
|
|
}
|
|
</style>
|
|
<div class="container-fluid px-0 px-lg-0 py-0 m-0" data-auto-refresh="3" style="min-height: 100vh; display: flex; flex-direction: column; ">
|
|
<!-- Top Header for Display Board -->
|
|
<header class="d-flex justify-content-between align-items-center bg-white py-2 px-3 shadow-sm border-0">
|
|
<div class="d-flex align-items-center gap-3">
|
|
<?php if ($logoUrl = qh_hospital_logo_url()): ?>
|
|
<img src="<?= qh_h($logoUrl) ?>" alt="<?= qh_h(qh_hospital_name()) ?>" style="height: 50px;">
|
|
<?php else: ?>
|
|
<div class="bg-primary text-white rounded d-flex align-items-center justify-content-center fs-6 fw-bold" style="width: 50px; height: 50px;">
|
|
<?= qh_h(qh_hospital_brand_initials()) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div>
|
|
<h1 class="h3 mb-0 fw-bold text-primary"><?= qh_h(qh_hospital_name()) ?></h1>
|
|
<?php if ($tagline = qh_hospital_tagline()): ?>
|
|
<div class="text-muted fw-semibold"><?= qh_h($tagline) ?></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="d-flex align-items-center gap-3">
|
|
<div class="fs-6 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 me-2 d-flex align-items-center gap-1 js-audio-toggle" id="globalAudioToggle" title="<?= qh_h(qh_t('Toggle Audio', 'تبديل الصوت')) ?>">
|
|
<i class="bi bi-megaphone"></i> <span class="d-none d-sm-inline"><?= qh_h(qh_t('Sound', 'الصوت')) ?></span>
|
|
</button>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm shadow-sm d-flex align-items-center gap-1 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> <span class="d-none d-sm-inline"><?= qh_h(qh_t('Fullscreen', 'ملء الشاشة')) ?></span></button>
|
|
</div>
|
|
</header>
|
|
|
|
<?php $pb = !empty($activeNews) ? "padding-bottom: 4rem !important;" : "padding-bottom: 1.5rem !important;"; ?>
|
|
<div class="row g-4 m-0 mt-2 px-3 px-lg-4 pt-0 flex-grow-1" style="<?= $pb ?>">
|
|
<div class="col-xl-8 col-lg-7 d-flex flex-column gap-1" id="queueSections">
|
|
<div class="card shadow-sm border-0 flex-grow-1">
|
|
<div class="card-header bg-white border-bottom py-2 d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h3 class="h5 mb-0 text-gray-800 fw-bold"><?= qh_h(qh_t('Now Serving', 'يتم الآن النداء')) ?></h3>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body p-1 bg-light">
|
|
<?php if ($activeCalls): ?>
|
|
<div class="row g-3 row-cols-2 row-cols-lg-5">
|
|
<?php foreach ($activeCalls as $ticket): $speech = qh_call_message($ticket);
|
|
$isNew = abs(time() - strtotime((string) $ticket["called_at"])) <= 15;
|
|
$blinkClass = $isNew ? 'blinking-ticket' : '';
|
|
?>
|
|
<div class="col">
|
|
<div class="card shadow-sm h-100 announcement-card <?= $blinkClass ?>" data-announcement-key="<?= qh_h((string) $ticket['id']) ?>-<?= qh_h((string) strtotime((string) $ticket['called_at'])) ?>" data-announcement-en="<?= qh_h($speech['speech_en'] ?? $speech['en']) ?>" data-announcement-ar="<?= qh_h($speech['speech_ar'] ?? $speech['ar']) ?>">
|
|
<div class="card-body w-100 text-center p-1 d-flex flex-column align-items-center justify-content-center">
|
|
<div class="fs-3 fw-bold text-primary mb-1"><?= qh_h($ticket['ticket_number']) ?></div>
|
|
<?php if ($ticket['status'] === 'nursing_called'): ?>
|
|
<div class="small text-muted mb-1 text-truncate w-100" title="<?= qh_h(qh_t('Nursing Station', 'محطة التمريض')) ?>"><?= qh_h(qh_t('Nursing Station', 'محطة التمريض')) ?></div>
|
|
<div class="bg-warning text-dark rounded px-2 py-1 small fw-bold mt-1 mb-2">
|
|
<?= qh_h(qh_t('Vitals', 'العلامات الحيوية')) ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="small text-muted mb-1 text-truncate w-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="bg-primary text-white rounded px-2 py-1 small fw-bold mt-1 mb-2">
|
|
<?= qh_h(qh_t('Room', 'غرفة')) ?> <?= qh_h($ticket['doctor_room'] ?? '--') ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="text-muted mt-auto" style="font-size: 0.65rem;">
|
|
<?= qh_format_datetime($ticket['called_at'] ?? $ticket['updated_at']) ?>
|
|
</div>
|
|
</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>
|
|
<h3><?= qh_h(qh_t('No active calls right now.', 'لا توجد نداءات نشطة حالياً.')) ?></h3>
|
|
<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-2">
|
|
<h6 class="mb-0 font-weight-bold text-dark"><?= qh_h(qh_t('Queue by Clinic', 'الإنتظار حسب العيادة')) ?></h5>
|
|
</div>
|
|
<div class="card-body p-1 bg-light">
|
|
<div class="row g-3 row-cols-2 row-cols-lg-5">
|
|
<?php foreach ($queueOverview as $row): ?>
|
|
<div class="col">
|
|
<div class="card border-0 shadow-sm h-100">
|
|
<div class="card-body p-1 d-flex flex-column justify-content-center">
|
|
<h6 class="fw-bold text-primary text-center mb-2 text-truncate" title="<?= qh_h(qh_name($row)) ?>"><?= qh_h(qh_name($row)) ?></h6>
|
|
<?php if ((int) ($row['requires_vitals'] ?? 0) === 1): ?>
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<span class="text-muted fw-semibold lh-sm" style="font-size: 0.7rem;"><?= qh_h(qh_t('Vitals Wait', 'غرفة المعاينة الأولية')) ?></span>
|
|
<span class="badge bg-warning text-dark rounded-pill px-2"><?= qh_h((string) $row['vitals_waiting']) ?></span>
|
|
</div>
|
|
<?php endif; ?>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<span class="text-muted fw-semibold lh-sm" style="font-size: 0.7rem;"><?= qh_h(qh_t('Doctor Wait', 'انتظار الطبيب')) ?></span>
|
|
<span class="badge bg-info text-dark rounded-pill px-2"><?= qh_h((string) $row['doctor_waiting']) ?></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-4 col-lg-5">
|
|
<div class="sticky-top" style="top: 1rem; height: 60vh;">
|
|
<?php if (!empty($activeAds)): ?>
|
|
<div class="card shadow-sm border-0 h-100 bg-black overflow-hidden d-flex justify-content-center align-items-center">
|
|
<div class="w-100 h-100 position-relative bg-black">
|
|
<video id="adsVideoPlayer" class="w-100 h-100 object-fit-contain d-none" muted playsinline></video>
|
|
<img id="adsImagePlayer" class="w-100 h-100 object-fit-contain d-none" src="" alt="<?= qh_h(qh_t('Hospital advertisement', 'إعلان المستشفى')) ?>">
|
|
</div>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const playlist = <?= json_encode($activeAds, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) ?>;
|
|
const player = document.getElementById('adsVideoPlayer');
|
|
const image = document.getElementById('adsImagePlayer');
|
|
const defaultImageAlt = "<?= qh_h(qh_t('Hospital advertisement', 'إعلان المستشفى')) ?>";
|
|
let imageTimer = null;
|
|
let savedType = sessionStorage.getItem('adsMediaType') || 'video';
|
|
let currentIdx = parseInt(sessionStorage.getItem('adsMediaIndex') || sessionStorage.getItem('adsVideoIndex') || '0', 10);
|
|
let currentTime = parseFloat(sessionStorage.getItem('adsVideoTime') || '0');
|
|
let imageStartedAt = parseInt(sessionStorage.getItem('adsImageStartedAt') || '0', 10);
|
|
|
|
if (!player || !image || playlist.length === 0) {
|
|
return;
|
|
}
|
|
|
|
if (isNaN(currentIdx) || currentIdx < 0 || currentIdx >= playlist.length) {
|
|
currentIdx = 0;
|
|
}
|
|
if (isNaN(currentTime) || currentTime < 0) {
|
|
currentTime = 0;
|
|
}
|
|
if (isNaN(imageStartedAt) || imageStartedAt < 0) {
|
|
imageStartedAt = 0;
|
|
}
|
|
|
|
const persistIndex = function() {
|
|
sessionStorage.setItem('adsMediaIndex', String(currentIdx));
|
|
sessionStorage.setItem('adsVideoIndex', String(currentIdx));
|
|
};
|
|
|
|
const clearImageTimer = function() {
|
|
if (imageTimer) {
|
|
clearTimeout(imageTimer);
|
|
imageTimer = null;
|
|
}
|
|
};
|
|
|
|
const showAudioPrompt = function() {
|
|
if (window.audioPromptShown || window.localStorage.getItem('hospitalQueue:audioEnabled') === 'false') {
|
|
return;
|
|
}
|
|
|
|
window.audioPromptShown = true;
|
|
const prompt = document.createElement('div');
|
|
prompt.style.position = 'fixed';
|
|
prompt.style.bottom = '20px';
|
|
prompt.style.left = '50%';
|
|
prompt.style.transform = 'translateX(-50%)';
|
|
prompt.style.zIndex = '9999';
|
|
prompt.style.backgroundColor = '#dc3545';
|
|
prompt.style.color = 'white';
|
|
prompt.style.padding = '15px 30px';
|
|
prompt.style.borderRadius = '50px';
|
|
prompt.style.cursor = 'pointer';
|
|
prompt.style.display = 'flex';
|
|
prompt.style.alignItems = 'center';
|
|
prompt.style.gap = '15px';
|
|
prompt.style.boxShadow = '0 10px 25px rgba(0,0,0,0.5)';
|
|
|
|
const msg = "<?= qh_h(qh_t('Sound blocked by TV/Browser. Click here or press OK on remote to enable.', 'تم حظر الصوت بواسطة المتصفح/التلفاز. انقر هنا أو اضغط OK في الريموت للتفعيل.')) ?>";
|
|
prompt.innerHTML = '<i class="bi bi-volume-mute-fill fs-3"></i> <span class="fs-6 fw-bold">' + msg + '</span>';
|
|
|
|
const enableSound = function(ev) {
|
|
if (ev && ev.type === 'keydown' && ev.key !== 'Enter' && ev.key !== ' ') return;
|
|
player.muted = false;
|
|
player.play().catch(e => console.warn('Still cannot play:', e));
|
|
if (document.body.contains(prompt)) {
|
|
document.body.removeChild(prompt);
|
|
}
|
|
if (ev && ev.type === 'keydown') {
|
|
document.body.click();
|
|
}
|
|
};
|
|
|
|
prompt.addEventListener('click', enableSound);
|
|
document.body.appendChild(prompt);
|
|
document.addEventListener('keydown', enableSound);
|
|
document.addEventListener('click', function(ev2) {
|
|
if (document.body.contains(prompt) && ev2.target !== prompt && !prompt.contains(ev2.target)) {
|
|
enableSound(ev2);
|
|
}
|
|
}, { once: true });
|
|
};
|
|
|
|
const playVideo = function() {
|
|
player.play().catch(function(e) {
|
|
console.error('Error playing video:', e);
|
|
if (!player.muted) {
|
|
player.muted = true;
|
|
player.play().catch(err => console.error('Fallback play failed:', err));
|
|
}
|
|
showAudioPrompt();
|
|
});
|
|
};
|
|
|
|
const showNextItem = function() {
|
|
clearImageTimer();
|
|
currentIdx = (currentIdx + 1) % playlist.length;
|
|
currentTime = 0;
|
|
imageStartedAt = 0;
|
|
savedType = 'video';
|
|
renderCurrent(true);
|
|
};
|
|
|
|
const renderCurrent = function(resetPosition) {
|
|
const item = playlist[currentIdx] || playlist[0];
|
|
persistIndex();
|
|
clearImageTimer();
|
|
sessionStorage.setItem('adsMediaType', item.type);
|
|
savedType = item.type;
|
|
|
|
if (item.type === 'image') {
|
|
player.pause();
|
|
player.removeAttribute('src');
|
|
player.load();
|
|
player.classList.add('d-none');
|
|
image.classList.remove('d-none');
|
|
image.src = item.path;
|
|
image.alt = item.title || defaultImageAlt;
|
|
|
|
const durationMs = Math.max(parseInt(item.duration || 10, 10), 3) * 1000;
|
|
let remainingMs = durationMs;
|
|
const canResumeImage = !resetPosition && imageStartedAt > 0;
|
|
|
|
if (!canResumeImage) {
|
|
imageStartedAt = Date.now();
|
|
} else {
|
|
const elapsedMs = Date.now() - imageStartedAt;
|
|
if (elapsedMs >= durationMs) {
|
|
showNextItem();
|
|
return;
|
|
}
|
|
remainingMs = durationMs - elapsedMs;
|
|
}
|
|
|
|
sessionStorage.setItem('adsImageStartedAt', String(imageStartedAt));
|
|
sessionStorage.setItem('adsVideoTime', '0');
|
|
imageTimer = window.setTimeout(showNextItem, remainingMs);
|
|
return;
|
|
}
|
|
|
|
image.classList.add('d-none');
|
|
player.classList.remove('d-none');
|
|
imageStartedAt = 0;
|
|
sessionStorage.removeItem('adsImageStartedAt');
|
|
|
|
const resumeTime = (!resetPosition && currentTime > 0) ? currentTime : 0;
|
|
player.loop = playlist.length === 1;
|
|
player.src = item.path;
|
|
player.load();
|
|
player.addEventListener('loadedmetadata', function onLoadedMetadata() {
|
|
if (resumeTime > 0 && resumeTime < player.duration) {
|
|
player.currentTime = resumeTime;
|
|
}
|
|
playVideo();
|
|
}, { once: true });
|
|
|
|
if (window.localStorage.getItem('hospitalQueue:audioEnabled') !== 'false') {
|
|
player.muted = false;
|
|
}
|
|
};
|
|
|
|
player.addEventListener('ended', function() {
|
|
if (playlist.length > 1) {
|
|
showNextItem();
|
|
}
|
|
});
|
|
|
|
window.addEventListener('beforeunload', function() {
|
|
persistIndex();
|
|
sessionStorage.setItem('adsMediaType', savedType);
|
|
if (savedType === 'video') {
|
|
sessionStorage.setItem('adsVideoTime', String(player.currentTime || 0));
|
|
} else {
|
|
sessionStorage.setItem('adsVideoTime', '0');
|
|
sessionStorage.setItem('adsImageStartedAt', String(imageStartedAt || Date.now()));
|
|
}
|
|
});
|
|
|
|
renderCurrent(false);
|
|
});
|
|
</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-2 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-1 d-flex flex-column gap-1">
|
|
<div class="border border-light border-opacity-25 rounded p-1 bg-white bg-opacity-10">
|
|
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Service', 'خدمة')) ?></div>
|
|
<h5 class="text-white fw-bold"><?= qh_h(qh_t('Lab packages & checks', 'باقات المختبر والفحوصات')) ?></h5>
|
|
<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-1 bg-white bg-opacity-10">
|
|
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Reminder', 'تذكير')) ?></div>
|
|
<h5 class="text-white fw-bold"><?= qh_h(qh_t('Keep your ticket visible', 'احتفظ بتذكرتك ظاهرة')) ?></h5>
|
|
<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-1 bg-white bg-opacity-10">
|
|
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Wayfinding', 'الإرشاد')) ?></div>
|
|
<h5 class="text-white fw-bold"><?= qh_h(qh_t('Pharmacy & billing', 'الصيدلية والمحاسبة')) ?></h5>
|
|
<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 if (!empty($activeNews)): ?>
|
|
<div class="news-ticker-container">
|
|
<div class="news-ticker-content">
|
|
<?php foreach ($activeNews as $news): ?>
|
|
<span class="news-ticker-item"><?= qh_h($news) ?></span>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php qh_page_end(); ?>
|