diff --git a/admin.php b/admin.php index b7f1f3a..25d8e16 100644 --- a/admin.php +++ b/admin.php @@ -17,147 +17,137 @@ qh_page_start( qh_t('Structured admin overview with separate pages for clinics and doctors.', 'نظرة عامة منظمة للإدارة مع صفحات مستقلة للعيادات والأطباء.') ); ?> -
+
-
+
- -
-

-

+

+

-
- -
-
-
- -

-

-
-
- -
-

-

-

-

-
-
- -
- - - - - -
- -
-
-
-
- -

-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
-
-
-
- -
-
-
- -
-
-
- -

-
- -
- -
- -
- -
-
-
-
:
-
- -
- -
- -
- -
-
-
- -

-
- -
- -
- -
- -
-
-
-
-
- -
- -
- -
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+ +

+ +
+ +
+
+
+
:
+
+ + + +
+ +
+ +
+
+
+ +
+
+
+
+ +
+
+ +

+ +
+ +
+
+
+
+
+ +
+ +
+ +
+
+
+
+
- + \ No newline at end of file diff --git a/admin_ads.php b/admin_ads.php new file mode 100644 index 0000000..74fe86e --- /dev/null +++ b/admin_ads.php @@ -0,0 +1,197 @@ +exec("CREATE TABLE IF NOT EXISTS hospital_ads ( + id INT AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NULL, + video_path VARCHAR(255) NOT NULL, + is_active TINYINT(1) DEFAULT 1, + sort_order INT DEFAULT 0, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +)"); + +// Handle Form Submissions +$message = ''; +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + if (isset($_POST['action']) && $_POST['action'] === 'add_video' && !empty($_FILES['video']['name'])) { + $uploadDir = __DIR__ . '/assets/videos/uploads/'; + if (!is_dir($uploadDir)) { + mkdir($uploadDir, 0777, true); + } + + $ext = strtolower(pathinfo($_FILES['video']['name'], PATHINFO_EXTENSION)); + $allowed = ['mp4', 'webm', 'ogg']; + + if (!in_array($ext, $allowed)) { + $message = qh_t("Invalid video format (.$ext). Allowed formats: MP4, WebM, OGG.", "تنسيق فيديو غير صالح (.$ext). الصيغ المسموحة: MP4, WebM, OGG."); + } elseif ($_FILES['video']['error'] !== UPLOAD_ERR_OK) { + $errorMap = [ + UPLOAD_ERR_INI_SIZE => 'File exceeds max size in php.ini.', + UPLOAD_ERR_FORM_SIZE => 'File exceeds max size in HTML form.', + UPLOAD_ERR_PARTIAL => 'File was partially uploaded.', + UPLOAD_ERR_NO_FILE => 'No file was uploaded.', + UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder.', + UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk.', + UPLOAD_ERR_EXTENSION => 'A PHP extension stopped the upload.' + ]; + $errMsg = $errorMap[$_FILES['video']['error']] ?? 'Unknown error'; + $message = qh_t('Upload error: ' . $errMsg, 'خطأ في الرفع: ' . $errMsg); + } else { + $filename = uniqid('vid_') . '.' . $ext; + $dest = $uploadDir . $filename; + + if (move_uploaded_file($_FILES['video']['tmp_name'], $dest)) { + $title = $_POST['title'] ?? ''; + $path = 'assets/videos/uploads/' . $filename; + + $stmt = $pdo->prepare("INSERT INTO hospital_ads (title, video_path, is_active) VALUES (?, ?, 1)"); + $stmt->execute([$title, $path]); + $message = qh_t('Video uploaded successfully.', 'تم رفع الفيديو بنجاح.'); + } else { + $message = qh_t('Failed to save uploaded file.', 'فشل في حفظ الملف المرفوع.'); + } + } + } elseif (isset($_POST['action']) && $_POST['action'] === 'delete_video' && !empty($_POST['video_id'])) { + $id = (int) $_POST['video_id']; + $stmt = $pdo->prepare("SELECT video_path FROM hospital_ads WHERE id = ?"); + $stmt->execute([$id]); + $video = $stmt->fetch(); + if ($video) { + $fullPath = __DIR__ . '/' . $video['video_path']; + if (file_exists($fullPath)) { + unlink($fullPath); + } + $pdo->prepare("DELETE FROM hospital_ads WHERE id = ?")->execute([$id]); + $message = qh_t('Video deleted successfully.', 'تم حذف الفيديو بنجاح.'); + } + } elseif (isset($_POST['action']) && $_POST['action'] === 'toggle_status' && !empty($_POST['video_id'])) { + $id = (int) $_POST['video_id']; + $stmt = $pdo->prepare("UPDATE hospital_ads SET is_active = NOT is_active WHERE id = ?"); + $stmt->execute([$id]); + $message = qh_t('Video status updated.', 'تم تحديث حالة الفيديو.'); + } +} + +// Fetch existing ads +$stmt = $pdo->query("SELECT * FROM hospital_ads ORDER BY sort_order ASC, id DESC"); +$ads = $stmt->fetchAll(); + +qh_page_start( + 'admin_ads', + qh_t('Manage Advertisements', 'إدارة الإعلانات'), + qh_t('Upload and manage videos to display on the queue screen.', 'رفع وإدارة الفيديوهات لعرضها على شاشة الطابور.') +); +?> +
+
+ + +
+
+
+

+

+
+
+ + +
+ + +
+
+
+
+
+
+ +
+ + +
+
+ + +
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
+ + + +
+
+ + + +
+
+
+
+
+
+ +
+
+
+ \ No newline at end of file diff --git a/admin_clinics.php b/admin_clinics.php index 8409903..ea4a18d 100644 --- a/admin_clinics.php +++ b/admin_clinics.php @@ -38,151 +38,148 @@ qh_page_start( qh_t('Professional clinic directory with search, edit, and delete actions.', 'دليل احترافي للعيادات مع البحث وخيارات التعديل والحذف.') ); ?> -
+
-
+
- -
-

-

+

+

-
+ + + +
-
-
-
+
-
-
-
-
- -

-

-
-
-
- - -
- -
- - - - - - - - - - - - - (int) $clinic['id'], 'q' => $search]); ?> - - - - - - - - - -
-
-
-
-
- -
- - - - -
-
-
-
- -
- -
-
-
- -

-

-
-
- -
- - - - - - -
-
- - -
-
- - -
+
+
+
+
+
+
-
- - -
- -
- - -
- -
-
- > - -
-
-
- -
- - - +
+ +
+

+
+ +
+ + + + + + + + + + + + (int) $clinic['id'], 'q' => $search]); ?> + + + + + + + + +
+
+
+
+
+ + + + + + + +
+
+
- -
+
+
+ +
+
+
+
+
+ +
+
+ + + + + + +
+
+ + +
+
+ + +
+
+ +
+ + +
+ +
+ + +
+ +
+
+ > + +
+
+ +
+ + + + +
+
+
+
+
- + \ No newline at end of file diff --git a/admin_hospital.php b/admin_hospital.php index 773f062..fddf64d 100644 --- a/admin_hospital.php +++ b/admin_hospital.php @@ -57,106 +57,141 @@ qh_page_start(
-
-
- -

-

-
-
- -
+ -
-
- - + +
+
+
+

+

+
-
- - +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
-
-
- - +
+ + +
+
+
+

+

+
-
- - -
-
- - +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
-
-
- - -
-
- - -
-
+
-
-
- - + +
+
+
+

+

+
-
- - -
-
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- -
-
- - -
-
- - -
-
- - +
+
+ + + +
+ + +
+ +
+
+ + + +
+ + +
+ +
+
+ + +
+
+ + +
- - + +
@@ -222,7 +257,7 @@ qh_page_start( <?= qh_h(qh_t('Hospital logo preview', 'معاينة شعار المستشفى')) ?> -
+
@@ -230,7 +265,7 @@ qh_page_start( <?= qh_h(qh_t('Favicon preview', 'معاينة الأيقونة')) ?> -
+
@@ -240,4 +275,4 @@ qh_page_start( - + \ No newline at end of file diff --git a/assets/css/custom.css b/assets/css/custom.css index ecf9684..ed04ee7 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -1159,3 +1159,103 @@ html[dir="rtl"] .hospital-detail-list dt, html[dir="rtl"] .hospital-detail-list dd { text-align: right; } + +/* Print Ticket Styling (80mm Thermal Printer) */ +@media print { + body * { + visibility: hidden; + } + + header.app-header, + main.app-shell > .container-fluid, + main.app-shell > .container, + main.app-shell > .container-xxl, + div[style*="position: fixed; bottom: 0"] { + display: none !important; + } + + #print-ticket, #print-ticket * { + visibility: visible; + } + + #print-ticket { + position: absolute; + left: 0; + top: 0; + width: 80mm; + margin: 0; + padding: 5mm; + display: block !important; + background: white; + color: black; + font-family: system-ui, -apple-system, sans-serif; + } + + .print-ticket-inner { + text-align: center; + width: 100%; + } + + .pt-header { + font-size: 1.2rem; + font-weight: bold; + margin-bottom: 5px; + border-bottom: 1px solid black; + padding-bottom: 5px; + } + + .pt-token-title { + font-size: 0.9rem; + margin-top: 10px; + } + + .pt-token-number { + font-size: 3.5rem; + font-weight: bold; + line-height: 1; + margin: 5px 0 10px 0; + } + + .pt-patient-name { + font-size: 1.1rem; + font-weight: bold; + margin-bottom: 10px; + } + + .pt-divider { + border-top: 1px dashed black; + margin: 10px 0; + } + + .pt-detail { + font-size: 1rem; + text-align: left; + margin-bottom: 5px; + display: flex; + justify-content: space-between; + } + + html[dir="rtl"] .pt-detail { + text-align: right; + flex-direction: row-reverse; + } + + .pt-label { + font-weight: bold; + } + + .pt-datetime { + margin-top: 8px; + font-size: 0.85rem; + } + + .pt-footer { + font-size: 0.85rem; + margin-top: 10px; + } + + @page { + margin: 0; + size: 80mm auto; + } +} diff --git a/assets/images/uploads/img_69cbc7b59b0785.42983933.png b/assets/images/uploads/img_69cbc7b59b0785.42983933.png new file mode 100644 index 0000000..7818441 Binary files /dev/null and b/assets/images/uploads/img_69cbc7b59b0785.42983933.png differ diff --git a/assets/images/uploads/img_69cbc7b59c3a98.53445034.png b/assets/images/uploads/img_69cbc7b59c3a98.53445034.png new file mode 100644 index 0000000..7818441 Binary files /dev/null and b/assets/images/uploads/img_69cbc7b59c3a98.53445034.png differ diff --git a/assets/videos/uploads/test_video_1.mp4 b/assets/videos/uploads/test_video_1.mp4 new file mode 100644 index 0000000..0a4dd5b Binary files /dev/null and b/assets/videos/uploads/test_video_1.mp4 differ diff --git a/assets/videos/uploads/test_video_2.mp4 b/assets/videos/uploads/test_video_2.mp4 new file mode 100644 index 0000000..99c2076 Binary files /dev/null and b/assets/videos/uploads/test_video_2.mp4 differ diff --git a/assets/videos/uploads/vid_69cbe51070e11.mp4 b/assets/videos/uploads/vid_69cbe51070e11.mp4 new file mode 100644 index 0000000..fe4000d Binary files /dev/null and b/assets/videos/uploads/vid_69cbe51070e11.mp4 differ diff --git a/display.php b/display.php index 6de797b..741e9df 100644 --- a/display.php +++ b/display.php @@ -3,95 +3,155 @@ declare(strict_types=1); require_once __DIR__ . '/queue_bootstrap.php'; qh_boot(); -$activeCalls = qh_fetch_tickets(['called', 'in_progress'], null, 6); +$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 with separated English and Arabic modes.', 'شاشة طوابير عامة مع وضعي عرض منفصلين بالعربية والإنجليزية.') + qh_t('Public queue display.', 'شاشة طوابير عامة.') ); ?> -
-
-
-
-
-
-

-

+
+
+
+
+
+
+

+
+
+
+ +
-
- -
+ +
+ +
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+ +
+
+ +

+

+
+
+
- -
- -
-
-
-
·
-
-
- -
-
-
- +
+
+
- -
- - -
- - -
-

-
- -
-
-
-
- - -
-
-
- +
+
+ + + + + + + + + + + + + + + + + +
+
- -
+
+ - + \ No newline at end of file diff --git a/doctor.php b/doctor.php index 18a3d7d..3de9e3b 100644 --- a/doctor.php +++ b/doctor.php @@ -11,86 +11,101 @@ $doctorQueue = $selectedDoctorId > 0 ? qh_fetch_tickets(['ready_for_doctor', 'ca qh_page_start( 'doctor', - qh_t('Doctor room queue', 'طابور غرفة الطبيب'), - qh_t('Doctor workspace with separate English and Arabic page views.', 'مساحة عمل الطبيب مع صفحات عربية وإنجليزية منفصلة.') + qh_t('Doctor queue', 'طابور الطبيب'), + qh_t('Doctor workspace.', 'مساحة عمل الطبيب.') ); ?> -
-
+
+
- -
-

-

+

+

-
+
-
- -
- - - -
-
-
+
+
+
+
+
+ + +
+ +
- - - + +
+
+
+
+
+ + + +
-
-
-
-

-

-
- - +
+
+
+
+
+ +
+

+
+ +
+

+
+ +
+ + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + +
+
+
- - -
- -
-
-
-
-
-
·
-
-
- - -
-
-
-
-
-
-
-
-
- -
- -
- - -
-
- + \ No newline at end of file diff --git a/index.php b/index.php index bf84f41..626a49d 100644 --- a/index.php +++ b/index.php @@ -14,156 +14,153 @@ qh_page_start( qh_t('English operations dashboard for the hospital queue workflow.', 'لوحة عمليات عربية لمسار طابور المستشفى.') ); ?> -
-
-
-
- -
-

-

-
- - -
-
-
-
-
-
-
-
-
-
-
+
+
+
+

+

+
+
+ + +
+
+ +
+
+
+
+
+
-
- -
-
-
-
-
-

-

-
- +
+
+
+
+
-
- - - - - - - - - - - - - - - - - - - - - -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+
-
-

-

- -
- -
-
-
-
·
+
+
+
+
+
+ +
+ +
+
+
+
+
+
- -
- -
- -
- - -
- + +
+ +
+

+
+ +
-
+
-
- '01', 'title' => qh_t('Reception issues one ticket', 'الاستقبال يصدر تذكرة واحدة'), 'copy' => qh_t('Choose the clinic and doctor once at the front desk.', 'يتم اختيار العيادة والطبيب مرة واحدة من مكتب الاستقبال.')], - ['step' => '02', 'title' => qh_t('Optional vitals step', 'خطوة العلامات الحيوية عند الحاجة'), 'copy' => qh_t('Only clinics that require vitals route through nursing first.', 'فقط العيادات التي تتطلب العلامات الحيوية تمر أولاً على التمريض.')], - ['step' => '03', 'title' => qh_t('Doctor calls the patient', 'الطبيب ينادي المريض'), 'copy' => qh_t('The doctor room page pushes the next call to the display.', 'صفحة غرفة الطبيب ترسل النداء التالي إلى الشاشة.')], - ['step' => '04', 'title' => qh_t('Display announces the call', 'الشاشة تعلن النداء'), 'copy' => qh_t('Patients see the latest ticket and room assignment immediately.', 'يرى المرضى آخر تذكرة ورقم الغرفة مباشرة.')], - ]; - ?> - -
-
- -

-

-
-
- -
- -
-
-
-

-

-
- +
+
+
- -
- - - - - - - - - - - - - +
+ +
+
+ - - - - - - + + + + + + - - -
-
- -
- - -
- -
+ + + + + + + + + + + + + + +
+ +
+

+
+ +
+
- + \ No newline at end of file diff --git a/nursing.php b/nursing.php index 56c889f..6ab11da 100644 --- a/nursing.php +++ b/nursing.php @@ -8,63 +8,59 @@ $waitingTickets = qh_fetch_tickets(['waiting_vitals'], null, 20); qh_page_start( 'nursing', - qh_t('Nursing vitals queue', 'طابور التمريض للعلامات الحيوية'), - qh_t('Nursing workspace with separate English and Arabic views.', 'مساحة عمل التمريض مع فصل بين الواجهة العربية والإنجليزية.') + qh_t('Nursing vitals', 'علامات التمريض'), + qh_t('Nursing workspace.', 'مساحة عمل التمريض.') ); ?> -
-
+
+
- -
-

-

+

+

-
+
-
-
-
-

-

-
- +
+
+
+
- -
- -
-
-
-
-
-
· ·
-
-
- - +
+ +
+ +
+
+
+
+
+
+
+
+ + +
+
+ +
+ + +
+
+ +
+
-
- -
- - -
-
- -
-
-
- -
- -
- - -
- + +
+ +
+

+
+ +
- + \ No newline at end of file diff --git a/output.html b/output.html new file mode 100644 index 0000000..e69de29 diff --git a/queue_bootstrap.php b/queue_bootstrap.php index 3e78a3a..7a7a0d0 100644 --- a/queue_bootstrap.php +++ b/queue_bootstrap.php @@ -72,11 +72,15 @@ CREATE TABLE IF NOT EXISTS hospital_profile_settings ( favicon_url VARCHAR(255) DEFAULT NULL, primary_color VARCHAR(7) DEFAULT NULL, secondary_color VARCHAR(7) DEFAULT NULL, + news_ticker_en VARCHAR(1000) DEFAULT NULL, + news_ticker_ar VARCHAR(1000) DEFAULT NULL, updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci SQL; db()->exec($profileSql); + try { db()->exec("ALTER TABLE hospital_profile_settings ADD COLUMN news_ticker_en VARCHAR(1000) DEFAULT NULL"); } catch (\Throwable $e) {} + try { db()->exec("ALTER TABLE hospital_profile_settings ADD COLUMN news_ticker_ar VARCHAR(1000) DEFAULT NULL"); } catch (\Throwable $e) {} } function qh_seed_demo_data(): void @@ -163,9 +167,9 @@ function qh_seed_hospital_profile(): void $stmt = db()->prepare( 'INSERT INTO hospital_profile_settings - (id, name_en, name_ar, short_name, tagline_en, tagline_ar, phone, email, website, address_en, address_ar, working_hours_en, working_hours_ar, logo_url, favicon_url, primary_color, secondary_color) + (id, name_en, name_ar, short_name, tagline_en, tagline_ar, phone, email, website, address_en, address_ar, working_hours_en, working_hours_ar, logo_url, favicon_url, primary_color, secondary_color, news_ticker_en, news_ticker_ar) VALUES - (1, :name_en, :name_ar, :short_name, :tagline_en, :tagline_ar, :phone, :email, :website, :address_en, :address_ar, :working_hours_en, :working_hours_ar, :logo_url, :favicon_url, :primary_color, :secondary_color)' + (1, :name_en, :name_ar, :short_name, :tagline_en, :tagline_ar, :phone, :email, :website, :address_en, :address_ar, :working_hours_en, :working_hours_ar, :logo_url, :favicon_url, :primary_color, :secondary_color, :news_ticker_en, :news_ticker_ar)' ); $stmt->execute([ @@ -185,6 +189,8 @@ function qh_seed_hospital_profile(): void 'favicon_url' => '', 'primary_color' => '#0f8b8d', 'secondary_color' => '#16697a', + 'news_ticker_en' => 'Welcome to our hospital.', + 'news_ticker_ar' => 'مرحباً بكم في مستشفانا.', ]); } @@ -389,6 +395,11 @@ function qh_admin_sections(): array 'description' => qh_t('Admin home and setup summary.', 'الصفحة الرئيسية وملخص الإعدادات.'), 'icon' => 'overview', ], +'admin_ads.php' => [ + 'label' => qh_t('Advertisements', 'الإعلانات'), + 'description' => qh_t('Manage videos shown on the queue display.', 'إدارة الفيديوهات المعروضة على شاشة الطابور.'), + 'icon' => 'display', + ], 'admin_hospital.php' => [ 'label' => qh_t('Hospital profile', 'ملف المستشفى'), 'description' => qh_t('Manage logo, favicon, contact details, and brand colors.', 'إدارة الشعار والأيقونة وبيانات التواصل وألوان الهوية.'), @@ -552,6 +563,15 @@ function qh_page_start(string $activePage, string $pageTitle, string $metaDescri function qh_page_end(): void { + $profile = qh_fetch_hospital_profile(); + $newsTicker = trim((string)($profile['news_ticker'] ?? '')); + + if ($newsTicker !== '') { + echo '
'; + echo '' . qh_h($newsTicker) . ''; + echo '
'; + } + $assetVersionJs = qh_asset_version('assets/js/main.js'); echo ''; echo ''; @@ -894,6 +914,53 @@ function qh_require_post(): void +function qh_handle_image_upload(string $inputName): string +{ + if (!isset($_FILES[$inputName]) || $_FILES[$inputName]['error'] !== UPLOAD_ERR_OK) { + return ''; + } + + $tmpName = $_FILES[$inputName]['tmp_name']; + $finfo = finfo_open(FILEINFO_MIME_TYPE); + if ($finfo === false) return ''; + $mime = finfo_file($finfo, $tmpName); + finfo_close($finfo); + + if (!is_string($mime) || !str_starts_with($mime, 'image/')) { + throw new InvalidArgumentException(qh_t('Invalid image format.', 'تنسيق صورة غير صالح.')); + } + + $ext = match ($mime) { + 'image/jpeg' => '.jpg', + 'image/png' => '.png', + 'image/gif' => '.gif', + 'image/webp' => '.webp', + 'image/svg+xml' => '.svg', + 'image/x-icon' => '.ico', + 'image/vnd.microsoft.icon' => '.ico', + default => '.bin' + }; + + if ($ext === '.bin') { + throw new InvalidArgumentException(qh_t('Unsupported image type.', 'نوع الصورة غير مدعوم.')); + } + + $uploadDir = __DIR__ . '/assets/images/uploads'; + if (!is_dir($uploadDir)) { + if (!mkdir($uploadDir, 0775, true)) { + throw new RuntimeException(qh_t('Failed to create upload directory.', 'فشل إنشاء مجلد الرفع.')); + } + } + + $filename = uniqid('img_', true) . $ext; + $dest = $uploadDir . '/' . $filename; + + if (!move_uploaded_file($tmpName, $dest)) { + throw new RuntimeException(qh_t('Failed to save uploaded file.', 'فشل حفظ الملف المرفوع.')); + } + + return 'assets/images/uploads/' . $filename; +} function qh_admin_handle_request(): void { if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST') { @@ -901,7 +968,7 @@ function qh_admin_handle_request(): void } $action = trim((string) ($_POST['action'] ?? '')); - if ($action === '') { + if ($action === '' || in_array($action, ['add_video', 'delete_video', 'toggle_status'])) { return; } @@ -1046,8 +1113,25 @@ function qh_admin_handle_request(): void $addressAr = trim((string) ($_POST['address_ar'] ?? '')); $workingHoursEn = trim((string) ($_POST['working_hours_en'] ?? '')); $workingHoursAr = trim((string) ($_POST['working_hours_ar'] ?? '')); - $logoUrl = trim((string) ($_POST['logo_url'] ?? '')); - $faviconUrl = trim((string) ($_POST['favicon_url'] ?? '')); + $newsTickerEn = trim((string) ($_POST['news_ticker_en'] ?? '')); + $newsTickerAr = trim((string) ($_POST['news_ticker_ar'] ?? '')); + $profile = qh_fetch_hospital_profile(); + $logoUrl = $profile['logo_url'] ?? ''; + $faviconUrl = $profile['favicon_url'] ?? ''; + + if (!empty($_POST['remove_logo'])) { + $logoUrl = ''; + } else { + $newLogo = qh_handle_image_upload('logo_upload'); + if ($newLogo !== '') $logoUrl = $newLogo; + } + + if (!empty($_POST['remove_favicon'])) { + $faviconUrl = ''; + } else { + $newFavicon = qh_handle_image_upload('favicon_upload'); + if ($newFavicon !== '') $faviconUrl = $newFavicon; + } $primaryColor = qh_sanitize_hex_color($_POST['primary_color'] ?? '', '#0F8B8D'); $secondaryColor = qh_sanitize_hex_color($_POST['secondary_color'] ?? '', '#16697A'); @@ -1060,12 +1144,7 @@ function qh_admin_handle_request(): void if ($website !== '' && filter_var($website, FILTER_VALIDATE_URL) === false) { throw new InvalidArgumentException(qh_t('Please enter a valid website URL.', 'يرجى إدخال رابط موقع صالح.')); } - if ($logoUrl !== '' && filter_var($logoUrl, FILTER_VALIDATE_URL) === false) { - throw new InvalidArgumentException(qh_t('Please enter a valid logo URL.', 'يرجى إدخال رابط صالح للشعار.')); - } - if ($faviconUrl !== '' && filter_var($faviconUrl, FILTER_VALIDATE_URL) === false) { - throw new InvalidArgumentException(qh_t('Please enter a valid favicon URL.', 'يرجى إدخال رابط صالح للأيقونة.')); - } + $stmt = $pdo->prepare( "UPDATE hospital_profile_settings @@ -1084,7 +1163,9 @@ function qh_admin_handle_request(): void logo_url = :logo_url, favicon_url = :favicon_url, primary_color = :primary_color, - secondary_color = :secondary_color + secondary_color = :secondary_color, + news_ticker_en = :news_ticker_en, + news_ticker_ar = :news_ticker_ar WHERE id = 1" ); $stmt->execute([ @@ -1104,6 +1185,8 @@ function qh_admin_handle_request(): void 'favicon_url' => $faviconUrl, 'primary_color' => $primaryColor, 'secondary_color' => $secondaryColor, + 'news_ticker_en' => $newsTickerEn, + 'news_ticker_ar' => $newsTickerAr, ]); qh_set_flash('success', qh_t('Hospital profile updated successfully.', 'تم تحديث ملف المستشفى بنجاح.')); } diff --git a/reception.php b/reception.php index ceb4ea3..022e2b4 100644 --- a/reception.php +++ b/reception.php @@ -11,112 +11,157 @@ $todayTickets = qh_fetch_tickets(['waiting_vitals', 'ready_for_doctor', 'called' qh_page_start( 'reception', - qh_t('Reception ticket issuance', 'إصدار التذاكر في الاستقبال'), - qh_t('Reception page with separated language views.', 'صفحة الاستقبال مع فصل واضح بين اللغتين.') + qh_t('Reception', 'الاستقبال'), + qh_t('Issue new tickets and manage patient flow.', 'إصدار التذاكر الجديدة وإدارة حركة المرضى.') ); ?> -
-
+
+
- -
-

-

+

+

-
+
-
-
-

-
-
- - -
-
- - -
-
- - -
-
- - -
- -
+
+
+
+
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
-
+
-
-
-
-
-
-
-
· ·
+
+
+
+
+
+
+
+
+
+
+ + +
-
- - +
+
+
:
+
:
+
:
-
-
-
:
-
:
-
:
-
-
-

-

-
- - - - - - - - - - - - - - - - - - - - - -
+
+
+
+
+
+

+
+
+ + + + + + + + + + + + + + + + + + + +
+
+
- + + + + \ No newline at end of file diff --git a/ticket.php b/ticket.php index 2695ecb..73f3059 100644 --- a/ticket.php +++ b/ticket.php @@ -39,6 +39,7 @@ qh_page_start(
+ :
@@ -79,4 +80,36 @@ qh_page_start(
+ + +