{"id":34,"date":"2026-01-05T19:02:19","date_gmt":"2026-01-05T11:02:19","guid":{"rendered":"https:\/\/www.ukm.my\/imenhub\/?page_id=34"},"modified":"2026-03-13T09:52:26","modified_gmt":"2026-03-13T01:52:26","slug":"gunasama-kompleks","status":"publish","type":"page","link":"https:\/\/www.ukm.my\/imenhub\/gunasama-kompleks\/","title":{"rendered":"Gunasama Kompleks"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"34\" class=\"elementor elementor-34\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-65f3f9d e-con-full e-flex e-con e-parent\" data-id=\"65f3f9d\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-44a0018 elementor-widget elementor-widget-html\" data-id=\"44a0018\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!DOCTYPE html>\n<html lang=\"ms\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>Tempahan Gunasama Kompleks<\/title>\n    \n    <!-- Tailwind CSS -->\n    <script src=\"https:\/\/cdn.tailwindcss.com\"><\/script>\n    \n    <!-- FontAwesome -->\n    <link rel=\"stylesheet\" href=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/font-awesome\/6.4.0\/css\/all.min.css\">\n    \n    <!-- FullCalendar CSS & JS -->\n    <script src='https:\/\/cdn.jsdelivr.net\/npm\/fullcalendar@6.1.8\/index.global.min.js'><\/script>\n    \n    <!-- Google Fonts -->\n    <link href=\"https:\/\/fonts.googleapis.com\/css2?family=SF+Pro+Display:wght@300;400;500;600&family=Inter:wght@300;400;500;600;700&display=swap&__ncforminfo=-5mfqbvFMdNOvExINE7kIpSwma0A5sH6OSCAUSf-L6BUS-QP0LD2zShHf6spCE48I37olRfW_I-xqUpp_KI9I79wBBpxTU8gMYrOZt3SZqE=&__ncforminfo=HTPFpAh0YnhSJpxsgng3GoNegDtLUtSg4Po4BJtGzlAAbmPy2EbfmYO_tlMtGrUJGVIiVCGj9xjVlsOM4H88KOwS6ZPOxZUtEs0OJ621ATl6gnuv3l0iXQ==\" rel=\"stylesheet\">\n\n    <!-- SweetAlert2 for Popups -->\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/sweetalert2@11\"><\/script>\n\n    <style>\n        body { font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif; background-color: #f2f2f7; }\n        \n        \/* Custom Scrollbar *\/\n        ::-webkit-scrollbar { width: 6px; }\n        ::-webkit-scrollbar-track { background: transparent; }\n        ::-webkit-scrollbar-thumb { background: #d1d5db; border-radius: 10px; }\n\n        \/* iOS Style Calendar Tweaks *\/\n        .fc { --fc-border-color: transparent; --fc-today-bg-color: transparent; }\n        .fc-theme-standard td, .fc-theme-standard th { border: none; }\n        .fc-col-header-cell-cushion { color: #8e8e93; font-weight: 600; font-size: 0.8rem; text-transform: uppercase; }\n        .fc-daygrid-day-number { color: #1c1c1e; font-weight: 500; padding: 8px; text-decoration: none !important; }\n        \n        \/* Past Dates Styling *\/\n        .fc-day-past .fc-daygrid-day-frame { opacity: 0.6; background-color: #f9fafb; }\n        \n        \/* Circular Selection for Date *\/\n        .fc-daygrid-day.fc-day-today .fc-daygrid-day-number {\n            background-color: #007aff; color: white; border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; margin: 4px;\n        }\n        .selected-date-cell .fc-daygrid-day-number {\n            background-color: #1c1c1e !important; color: white !important; border-radius: 50%; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; margin: 4px;\n        }\n\n        \/* HIDE EVENTS TEXT IN CALENDAR - SHOW DOTS ONLY *\/\n        .fc-daygrid-event { display: flex; justify-content: center; background: transparent !important; border: none !important; margin-top: 2px; }\n        .fc-event-title { display: none; } \/* Hide text *\/\n        \n        \/* Custom Dot *\/\n        .event-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; margin: 0 2px; }\n\n        \/* Modal Transitions *\/\n        .modal { transition: opacity 0.25s ease; }\n        body.modal-active { overflow-x: hidden; overflow-y: visible !important; }\n\n        \/* Timeline Styles *\/\n        .timeline-container { position: relative; height: 12px; background-color: #e5e5ea; border-radius: 6px; overflow: hidden; margin-top: 20px;}\n        .timeline-block { position: absolute; height: 100%; top: 0; background-color: #4169E1; opacity: 0.8; z-index: 10; border-radius: 2px;}\n        .current-time-marker { position: absolute; top: -4px; bottom: -4px; width: 2px; background-color: #ef4444; z-index: 20; border-radius: 2px; }\n\n        \/* iOS List Item Style *\/\n        .ios-list-item { transition: background-color 0.2s; }\n        .ios-list-item:active { background-color: #e5e5ea; }\n\n        \/* Disabled option style for select *\/\n        option:disabled { background-color: #f3f4f6; color: #9ca3af; text-decoration: line-through; }\n\n        \/* PROGRESS BAR CUSTOM STYLE *\/\n        .custom-progress-bar {\n            background-image: \n                linear-gradient(45deg, rgba(255,255,255,0.3) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.3) 50%, rgba(255,255,255,0.3) 75%, transparent 75%, transparent),\n                linear-gradient(to right, #FF3B30, #FF9500, #FFCC00, #34C759); \n            background-size: 20px 20px, 100% 100%; \n            animation: progress-bar-stripes 1s linear infinite;\n        }\n        @keyframes progress-bar-stripes {\n            0% { background-position: 20px 0, 0 0; }\n            100% { background-position: 0 0, 0 0; }\n        }\n        \n        \/* Loading Overlay *\/\n        #loadingOverlay {\n            backdrop-filter: blur(5px);\n            background: rgba(255,255,255,0.7);\n        }\n    <\/style>\n<\/head>\n<body class=\"text-gray-900 selection:bg-blue-100 relative\">\n\n    <!-- Loading Overlay (Initial Load Only) -->\n    <div id=\"loadingOverlay\" class=\"fixed inset-0 z-[60] flex items-center justify-center hidden\">\n        <div class=\"bg-white p-4 rounded-xl shadow-lg flex items-center gap-3 border border-gray-100\">\n            <div class=\"animate-spin rounded-full h-5 w-5 border-b-2 border-blue-600\"><\/div>\n            <span class=\"text-sm font-semibold text-gray-700\">fethching booking...<\/span>\n        <\/div>\n    <\/div>\n\n    <!-- Navbar -->\n    <nav class=\"bg-white\/80 backdrop-blur-md sticky top-0 z-40 border-b border-gray-200\">\n        <div class=\"max-w-5xl mx-auto px-4 sm:px-6\">\n            <div class=\"flex justify-between h-14 items-center\">\n                <div class=\"flex items-center gap-3 cursor-pointer\" onclick=\"showBookingView()\">\n                    <div class=\"w-8 h-8 bg-blue-600 rounded-lg flex items-center justify-center text-white font-bold shadow-sm\">G<\/div>\n                    <div>\n                        <div class=\"flex items-center gap-2\">\n                            <h1 class=\"text-sm font-bold text-gray-900 leading-tight\">Gunasama Kompleks<\/h1>\n                            <!-- Sync Indicator -->\n                            <span id=\"miniSync\" class=\"hidden text-[10px] text-blue-500 font-medium animate-pulse bg-blue-50 px-2 py-0.5 rounded-full border border-blue-100\">\n                                <i class=\"fas fa-sync fa-spin mr-1\"><\/i> Mengemaskini...\n                            <\/span>\n                        <\/div>\n                        <p class=\"text-[10px] text-gray-500\">Sistem Tempahan<\/p>\n                    <\/div>\n                <\/div>\n                <div class=\"flex items-center gap-3\">\n                    <button onclick=\"toggleAdminView()\" class=\"text-xs font-semibold text-gray-500 hover:text-blue-600 transition\">\n                        <i class=\"fas fa-user-shield\"><\/i> Admin\n                    <\/button>\n                    <button onclick=\"openBookingModal()\" class=\"bg-blue-600 hover:bg-blue-700 text-white px-4 py-1.5 rounded-full text-sm font-medium shadow-sm active:scale-95 transition\">\n                        <i class=\"fas fa-plus\"><\/i> Tempah\n                    <\/button>\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/nav>\n\n    <!-- VIEWS CONTAINER -->\n    <main class=\"max-w-5xl mx-auto px-4 sm:px-6 py-6\">\n\n        <!-- VIEW 1: BOOKING & CALENDAR -->\n        <div id=\"bookingView\">\n            \n            <!-- iOS Segmented Control (Tabs) -->\n            <div class=\"bg-gray-200\/80 p-1 rounded-lg flex gap-0.5 mb-6 max-w-lg mx-auto backdrop-blur-sm\">\n                <button onclick=\"switchTab('Bilik Mesyuarat')\" id=\"tab-Bilik Mesyuarat\" class=\"facility-tab flex-1 py-1.5 px-3 rounded-[6px] text-xs font-semibold transition-all duration-200 text-center shadow-sm bg-white text-black\">\n                    Bilik Mesyuarat\n                <\/button>\n                <button onclick=\"switchTab('Bilik Seminar 1')\" id=\"tab-Bilik Seminar 1\" class=\"facility-tab flex-1 py-1.5 px-3 rounded-[6px] text-xs font-semibold transition-all duration-200 text-center text-gray-500 hover:text-gray-900\">\n                    Bilik Seminar 1\n                <\/button>\n                <button onclick=\"switchTab('Bilik Seminar 2')\" id=\"tab-Bilik Seminar 2\" class=\"facility-tab flex-1 py-1.5 px-3 rounded-[6px] text-xs font-semibold transition-all duration-200 text-center text-gray-500 hover:text-gray-900\">\n                    Bilik Seminar 2\n                <\/button>\n            <\/div>\n\n            <div class=\"grid grid-cols-1 md:grid-cols-12 gap-6 mt-6\">\n                \n                <!-- CALENDAR (Left\/Top) -->\n                <div class=\"md:col-span-7 bg-white p-4 rounded-2xl shadow-sm border border-gray-100 h-fit\">\n                    <div class=\"flex justify-between items-center mb-2 px-2\">\n                        <h2 class=\"text-lg font-bold\">Kalendar<\/h2>\n                        <!-- Dynamic Legend based on PTJ Colors -->\n                        <div class=\"flex flex-wrap gap-3 text-[10px] font-bold uppercase tracking-wide justify-end\" id=\"ptjLegend\">\n                            <!-- Injected by JS -->\n                        <\/div>\n                    <\/div>\n                    \n                    <div id='calendar' class=\"text-sm\"><\/div>\n                    \n                    <!-- Daily Timeline Visualization (Mini) -->\n                    <div class=\"px-2 mt-4\">\n                        <div class=\"flex justify-between text-[10px] text-gray-400 font-medium uppercase tracking-wider mb-1\">\n                            <span>08:00<\/span>\n                            <span id=\"timelineLabel\">slot hari ini<\/span>\n                            <span>18:00<\/span>\n                        <\/div>\n                        <div class=\"timeline-container\" id=\"dailyTimeline\">\n                            <!-- JS Injected Blocks -->\n                        <\/div>\n                    <\/div>\n                <\/div>\n\n                <!-- SELECTED DAY AGENDA (Right\/Bottom) -->\n                <div class=\"md:col-span-5 flex flex-col h-full\">\n\n                    <!-- BOOKING PHASE INFO CARD -->\n                    <div class=\"bg-white\/80 backdrop-blur-md rounded-2xl shadow-sm border border-gray-100 p-5 mb-6\">\n                        <div class=\"flex items-center gap-3\">\n                            <div class=\"w-10 h-10 bg-blue-100 text-blue-600 rounded-xl flex items-center justify-center\">\n                                <i class=\"fas fa-info-circle\"><\/i>\n                            <\/div>\n                            <div>\n                                <h3 class=\"font-bold text-gray-900 text-sm leading-tight\">Fasa Tempahan Suku Tahunan<\/h3>\n                                <p class=\"text-xs text-gray-500\">Jadual pembukaan tempahan adalah seperti berikut:<\/p>\n                            <\/div>\n                        <\/div>\n                        <ul class=\"mt-4 space-y-2 text-xs text-gray-700\">\n                             <li class=\"flex items-start gap-3\">\n                                <i class=\"fas fa-calendar-check text-green-500 w-4 text-center pt-1\"><\/i>\n                                <div>\n                                    <strong class=\"font-semibold\">Fasa 1 (Jan-Mac):<\/strong> Dibuka pada <span class=\"font-bold text-blue-600\">20 Dis<\/span>\n                                <\/div>\n                            <\/li>\n                            <li class=\"flex items-start gap-3\">\n                                <i class=\"fas fa-calendar-check text-green-500 w-4 text-center pt-1\"><\/i>\n                                <div>\n                                    <strong class=\"font-semibold\">Fasa 2 (Apr-Jun):<\/strong> Dibuka pada <span class=\"font-bold text-blue-600\">20 Mac<\/span>\n                                <\/div>\n                            <\/li>\n                            <li class=\"flex items-start gap-3\">\n                                <i class=\"fas fa-calendar-check text-green-500 w-4 text-center pt-1\"><\/i>\n                                <div>\n                                    <strong class=\"font-semibold\">Fasa 3 (Jul-Sep):<\/strong> Dibuka pada <span class=\"font-bold text-blue-600\">20 Jun<\/span>\n                                <\/div>\n                            <\/li>\n                            <li class=\"flex items-start gap-3\">\n                                <i class=\"fas fa-calendar-check text-green-500 w-4 text-center pt-1\"><\/i>\n                                <div>\n                                    <strong class=\"font-semibold\">Fasa 4 (Okt-Dis):<\/strong> Dibuka pada <span class=\"font-bold text-blue-600\">20 Sep<\/span>\n                                <\/div>\n                            <\/li>\n                        <\/ul>\n                    <\/div>\n\n                    <div class=\"bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden flex-1 min-h-[400px]\">\n                        <div class=\"p-4 border-b border-gray-100 bg-gray-50\/50 backdrop-blur\">\n                            <div class=\"flex justify-between items-start\">\n                                <div>\n                                    <h2 class=\"text-lg font-bold text-gray-900\" id=\"agendaDate\">Pilih Tarikh<\/h2>\n                                    <p class=\"text-xs text-gray-500\" id=\"agendaSubtitle\">Tekan tarikh di kalendar untuk lihat butiran<\/p>\n                                <\/div>\n                                <span id=\"pastDateBadge\" class=\"hidden bg-gray-200 text-gray-600 text-[10px] font-bold px-2 py-1 rounded uppercase tracking-wide\">\n                                    Sejarah\n                                <\/span>\n                            <\/div>\n                        <\/div>\n                        \n                        <div id=\"agendaList\" class=\"overflow-y-auto max-h-[500px] p-2\">\n                            <!-- Empty State -->\n                            <div class=\"flex flex-col items-center justify-center h-48 text-gray-400\">\n                                <i class=\"fas fa-calendar-day text-3xl mb-2\"><\/i>\n                                <span class=\"text-sm\">Tiada tempahan dipilih<\/span>\n                            <\/div>\n                        <\/div>\n                    <\/div>\n                <\/div>\n            <\/div>\n        <\/div>\n\n        <!-- VIEW 2: ADMIN PORTAL (Hidden by default) -->\n        <div id=\"adminView\" class=\"hidden space-y-6\">\n            \n            <!-- HEADER -->\n            <div class=\"bg-white rounded-2xl shadow-sm border border-gray-100 overflow-hidden p-6 border-b border-gray-100 flex justify-between items-center bg-gray-900 text-white\">\n                <div>\n                    <h2 class=\"text-xl font-bold\">Konsol Admin<\/h2>\n                    <p class=\"text-xs text-gray-400\">Urus PIC & Tetapan<\/p>\n                <\/div>\n                <div class=\"flex gap-2\">\n                    <button onclick=\"showBookingView()\" class=\"text-xs bg-gray-700 hover:bg-gray-600 px-3 py-1 rounded border border-gray-600\">Keluar<\/button>\n                <\/div>\n            <\/div>\n\n            <!-- SECTION 1: USER MANAGEMENT -->\n            <div class=\"grid grid-cols-1 md:grid-cols-3 gap-6\">\n                <!-- Add User Form -->\n                <div class=\"md:col-span-1 bg-white p-5 rounded-2xl border border-gray-200 shadow-sm\">\n                    <h3 class=\"font-bold text-gray-800 mb-4 text-sm\">Daftar PIC Baru<\/h3>\n                    <form onsubmit=\"handleAdminAddUser(event)\">\n                        <div class=\"space-y-3\">\n                            <div>\n                                <label class=\"block text-[10px] font-bold text-gray-500 uppercase\">No. Pekerja (ID)<\/label>\n                                <input type=\"text\" id=\"adminNewId\" class=\"w-full p-2 border rounded text-sm bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500\" placeholder=\"Contoh: K12345\" required>\n                            <\/div>\n                            <div>\n                                <label class=\"block text-[10px] font-bold text-gray-500 uppercase\">PTJ (Fakulti\/Jabatan)<\/label>\n                                <select id=\"adminNewPtj\" class=\"w-full p-2 border rounded text-sm bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500\" required>\n                                    <option value=\"\">Pilih PTJ<\/option>\n                                    <!-- Populated from Hardcoded List -->\n                                <\/select>\n                            <\/div>\n                            <div>\n                                <label class=\"block text-[10px] font-bold text-gray-500 uppercase\">Nama Penuh<\/label>\n                                <input type=\"text\" id=\"adminNewName\" class=\"w-full p-2 border rounded text-sm bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500\" placeholder=\"Nama Penuh\" required>\n                            <\/div>\n                            <div>\n                                <label class=\"block text-[10px] font-bold text-gray-500 uppercase\">Emel<\/label>\n                                <input type=\"email\" id=\"adminNewEmail\" class=\"w-full p-2 border rounded text-sm bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500\" placeholder=\"Emel Rasmi\" required>\n                            <\/div>\n                            <button type=\"submit\" class=\"w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 rounded text-xs transition\">TAMBAH PENGGUNA<\/button>\n                        <\/div>\n                    <\/form>\n                    \n                    <!-- NOTE: Manage Colors Section Removed as requested -->\n                <\/div>\n\n                <!-- User Table -->\n                <div class=\"md:col-span-2 bg-white rounded-2xl border border-gray-200 shadow-sm overflow-hidden\">\n                    <div class=\"p-4 bg-gray-50 border-b border-gray-200\">\n                        <h3 class=\"font-bold text-gray-800 text-sm\">Pangkalan Data PIC Berdaftar<\/h3>\n                    <\/div>\n                    <div class=\"overflow-x-auto\">\n                        <table class=\"min-w-full divide-y divide-gray-200\">\n                            <thead class=\"bg-white\">\n                                <tr>\n                                    <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500 uppercase\">ID<\/th>\n                                    <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500 uppercase\">PTJ<\/th>\n                                    <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500 uppercase\">Nama<\/th>\n                                    <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500 uppercase\">Emel<\/th>\n                                    <th class=\"px-4 py-2 text-right text-xs font-bold text-gray-500 uppercase\">Tindakan<\/th>\n                                <\/tr>\n                            <\/thead>\n                            <tbody id=\"adminUserTable\" class=\"divide-y divide-gray-200 bg-white\"><\/tbody>\n                        <\/table>\n                    <\/div>\n                <\/div>\n            <\/div>\n\n            <!-- SECTION 2: BOOKING LOGS & ARCHIVE -->\n            <div class=\"bg-white rounded-2xl border border-gray-200 shadow-sm overflow-hidden\">\n                <div class=\"p-4 bg-gray-50 border-b border-gray-200 flex justify-between items-center\">\n                    <div class=\"flex gap-4\">\n                        <button onclick=\"renderBookingLog('active')\" class=\"text-sm font-bold text-blue-600 border-b-2 border-blue-600 pb-1\" id=\"btnActiveLog\">Log Aktif<\/button>\n                        <button onclick=\"renderBookingLog('archive')\" class=\"text-sm font-bold text-gray-400 hover:text-gray-600 pb-1\" id=\"btnArchiveLog\">Log Arkib<\/button>\n                    <\/div>\n                    <div class=\"flex gap-2\">\n                        <button onclick=\"runArchive()\" class=\"text-xs bg-orange-100 text-orange-700 hover:bg-orange-200 px-3 py-1 rounded border border-orange-200 font-semibold transition\"><i class=\"fas fa-box-archive\"><\/i> Jalankan Arkib<\/button>\n                        <button onclick=\"downloadLog()\" class=\"text-xs bg-green-100 text-green-700 hover:bg-green-200 px-3 py-1 rounded border border-green-200 font-semibold transition\"><i class=\"fas fa-download\"><\/i> Muat Turun<\/button>\n                    <\/div>\n                <\/div>\n                <div class=\"max-h-96 overflow-y-auto p-4\">\n                    <table class=\"min-w-full divide-y divide-gray-100\">\n                        <thead class=\"bg-gray-50\">\n                            <tr>\n                                <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500\">Tarikh<\/th>\n                                <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500\">Fasiliti<\/th>\n                                <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500\">Pengguna<\/th>\n                                <th class=\"px-4 py-2 text-left text-xs font-bold text-gray-500\">Tujuan<\/th>\n                            <\/tr>\n                        <\/thead>\n                        <tbody id=\"bookingLogTable\" class=\"divide-y divide-gray-100\">\n                            <!-- Populated by JS -->\n                        <\/tbody>\n                    <\/table>\n                <\/div>\n            <\/div>\n\n        <\/div>\n    <\/main>\n\n    <!-- Booking Modal (Existing) -->\n    <div id=\"bookingModal\" class=\"modal opacity-0 pointer-events-none fixed inset-0 flex items-center justify-center z-50 p-4\">\n        <div class=\"modal-overlay absolute inset-0 bg-black\/40 backdrop-blur-sm\" onclick=\"closeBookingModal()\"><\/div>\n        <div class=\"modal-container bg-white w-full max-w-md mx-auto rounded-2xl shadow-2xl z-50 overflow-hidden transform transition-all scale-95\" id=\"modalContent\">\n            <div class=\"px-6 py-4 border-b border-gray-100 flex justify-between items-center bg-gray-50\">\n                <h3 class=\"font-bold text-lg text-gray-900\">Tempahan Baru<\/h3>\n                <button onclick=\"closeBookingModal()\" class=\"text-gray-400 hover:text-gray-600 transition\"><i class=\"fas fa-times\"><\/i><\/button>\n            <\/div>\n            <div class=\"p-6\">\n                <form id=\"bookingForm\" onsubmit=\"handleBookingSubmit(event)\">\n                    <div id=\"step1\" class=\"mb-6\">\n                        <label class=\"block text-xs font-bold text-gray-500 uppercase mb-2\">Identiti Anda<\/label>\n                        <div class=\"flex gap-2\">\n                            <input type=\"text\" id=\"picId\" placeholder=\"No. Pekerja (Contoh: P12345)\" class=\"flex-1 bg-gray-50 border border-gray-200 rounded-lg py-2.5 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 transition\">\n                            <button type=\"button\" onclick=\"verifyPIC()\" class=\"bg-gray-900 text-white px-4 rounded-lg text-sm font-medium hover:bg-gray-800 transition\">Sahkan<\/button>\n                        <\/div>\n                        <p id=\"picStatus\" class=\"text-xs mt-2 h-4\"><\/p>\n                    <\/div>\n                    <div id=\"step2\" class=\"hidden opacity-50 pointer-events-none transition-all duration-300 space-y-4\">\n                        <div class=\"p-3 bg-blue-50 rounded-lg border border-blue-100 flex justify-between items-center\">\n                            <span class=\"text-xs font-bold text-blue-800 uppercase\">Fasiliti<\/span>\n                            <span id=\"bookingFacilityDisplay\" class=\"text-sm font-bold text-blue-900\">Bilik Mesyuarat<\/span>\n                            <input type=\"hidden\" id=\"bookFacility\" value=\"Bilik Mesyuarat\">\n                        <\/div>\n                        <div>\n                            <label class=\"block text-xs font-bold text-gray-500 uppercase mb-1\">Tujuan<\/label>\n                            <input type=\"text\" id=\"bookPurpose\" class=\"w-full border border-gray-200 rounded-lg py-2 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500\" placeholder=\"Contoh: Mesyuarat Bulanan\" required>\n                        <\/div>\n                        <div>\n                            <label class=\"block text-xs font-bold text-gray-500 uppercase mb-1\">Tarikh<\/label>\n                            <input type=\"date\" id=\"bookDate\" class=\"w-full border border-gray-200 rounded-lg py-2 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500\" required>\n                            <p class=\"text-[10px] text-gray-400 mt-1\" id=\"dateLimitText\"><\/p>\n                        <\/div>\n                        <div class=\"grid grid-cols-2 gap-4\">\n                            <div>\n                                <label class=\"block text-xs font-bold text-gray-500 uppercase mb-1\">Masa Mula<\/label>\n                                <select id=\"startTime\" class=\"w-full border border-gray-200 rounded-lg py-2 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white\"><\/select>\n                            <\/div>\n                            <div>\n                                <label class=\"block text-xs font-bold text-gray-500 uppercase mb-1\">Masa Tamat<\/label>\n                                <select id=\"endTime\" class=\"w-full border border-gray-200 rounded-lg py-2 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 bg-white\"><\/select>\n                            <\/div>\n                        <\/div>\n                        <input type=\"hidden\" id=\"picEmail\">\n                        <button type=\"submit\" class=\"w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 rounded-xl shadow-lg shadow-blue-200 transform active:scale-[0.98] transition mt-2\">Sahkan Tempahan<\/button>\n                    <\/div>\n                <\/form>\n            <\/div>\n        <\/div>\n    <\/div>\n\n    <script>\n        \/\/ --- CONFIGURATION ---\n        const WEB_APP_URL = \"https:\/\/script.google.com\/macros\/s\/AKfycby88m62BEk9tPCK9gWKCNngiBPVG3PMmQHVMUnzIVVzjkF_YdPIBpT_mPvhotTT0xNXkQ\/exec\"; \n\n        \/\/ --- NEW FEATURE: HARDCODED PTJ COLORS ---\n        const PREDEFINED_PTJ = {\n            'IMEN': 'darkblue',\n            'SELFUEL': 'orangered',\n            'SERI': 'darkcyan',\n            'IDEA': 'brown',\n            'ALAF': 'purple',\n            'IPI': 'steelblue' \/\/ Soft green\n        };\n\n        \/\/ --- DATA STORE ---\n        \/\/ We use the predefined list as the source of truth for colors now\n        let PTJ_COLORS = PREDEFINED_PTJ;\n\n        \/\/ Default Data\n        let USERS = { 'P12345': { name: 'Dr. Sarah', email: 'sarah@ukm.edu.my', ptj: 'IMEN' } };\n        let BOOKINGS = [];\n        let ARCHIVED_BOOKINGS = []; \n        let currentLogView = 'active'; \n\n        let currentFacility = 'Bilik Mesyuarat';\n        let calendar;\n\n        \/\/ --- INIT ---\n        document.addEventListener('DOMContentLoaded', function() {\n            initCalendar();\n            \n            \/\/ --- FEATURE: CACHE-FIRST STRATEGY ---\n            \/\/ 1. Load and render existing local data immediately for instant UI\n            const hasData = loadLocalData();\n            \n            if (hasData) {\n                console.log(\"Loading from cache...\");\n                renderUI();\n                \/\/ 2. BACKGROUND SYNC (Two-Stage)\n                if (WEB_APP_URL) fetchDataFromBackend(true); \n            } else {\n                \/\/ 3. COLD START\n                if (WEB_APP_URL) fetchDataFromBackend(false);\n                else {\n                    console.warn('No Backend URL. Using Demo Data.');\n                    loadLocalData();\n                    renderUI();\n                }\n            }\n\n            \/\/ Event Listeners\n            document.getElementById('bookDate').addEventListener('change', updateTimeSlotAvailability);\n            document.getElementById('startTime').addEventListener('change', updateEndTimeOptions);\n            \n            updateTabUI();\n            updatePtjDropdown(); \n        });\n\n        \/\/ --- BACKEND INTEGRATION (TWO-STAGE SYNC) ---\n        \n        async function fetchDataFromBackend(isBackground = false) {\n            \/\/ Stage 1: Active Data\n            if (!isBackground) setLoading(true);\n            else {\n                document.getElementById('miniSync').classList.remove('hidden'); \/\/ Show non-blocking indicator\n            }\n\n            try {\n                const response = await fetch(WEB_APP_URL);\n                const data = await response.json();\n                USERS = data.users || {};\n                BOOKINGS = data.bookings || [];\n                \n                \/\/ SAVE TO CACHE\n                saveLocalData();\n                renderUI();\n\n                \/\/ Update Logs if visible\n                if (!document.getElementById('adminView').classList.contains('hidden')) {\n                    renderBookingLog('active');\n                }\n                \n                \/\/ --- FEATURE: AUTO ARCHIVE CHECK ---\n                \/\/ If we have very old active bookings, trigger archive cleanly\n                checkForAutoArchiveNeeded();\n\n                \/\/ --- FEATURE: CHAINED SYNC ---\n                \/\/ Stage 2: Background Archive Fetch\n                if (isBackground) {\n                    console.log(\"Active data synced. Fetching archive in background...\");\n                    fetchArchiveData(true);\n                }\n\n            } catch (error) {\n                if (!isBackground) Swal.fire('Ralat Sinkronisasi', 'Gagal mendapatkan data.', 'error');\n                console.error(error);\n            } finally {\n                setLoading(false);\n                \/\/ Keep mini sync visible if we are going to stage 2, otherwise hide it\n                \/\/ Logic handled inside fetchArchiveData\n                if (!isBackground) document.getElementById('miniSync').classList.add('hidden');\n            }\n        }\n\n        async function fetchArchiveData(isBackground = false) {\n            if (!isBackground) setLoading(true);\n            \n            try {\n                const response = await fetch(WEB_APP_URL + \"?op=get_archive\");\n                const data = await response.json();\n                ARCHIVED_BOOKINGS = data;\n                \n                if (!isBackground) renderBookingLog('archive');\n                console.log(\"Archive synced.\");\n\n            } catch (error) {\n                if (!isBackground) Swal.fire('Ralat', 'Gagal mendapatkan arkib.', 'error');\n                console.error(error);\n            } finally {\n                if (!isBackground) setLoading(false);\n                document.getElementById('miniSync').classList.add('hidden'); \/\/ Fully done\n            }\n        }\n\n        \/\/ --- FEATURE: AUTO ARCHIVE LOGIC ---\n        function checkForAutoArchiveNeeded() {\n            \/\/ Logic: If there are active bookings older than 30 days, trigger a cleanup\n            const thirtyDaysAgo = new Date();\n            thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);\n            \n            const hasOldData = BOOKINGS.some(b => new Date(b.end) < thirtyDaysAgo);\n            \n            if (hasOldData) {\n                console.log(\"Old active data detected. Triggering auto-archive to speed up future loads...\");\n                \/\/ Silent Post\n                postToBackend({ op: 'archive_past_bookings' }, true);\n            }\n        }\n\n        async function postToBackend(payload, isSilent = false) {\n            if (!WEB_APP_URL) {\n                \/\/ Local fallback simulation\n                if(payload.op === 'create_booking') { BOOKINGS.push(payload); }\n                if(payload.op === 'delete_booking') { BOOKINGS = BOOKINGS.filter(b => b.id != payload.id); }\n                if(payload.op === 'add_user') { USERS[payload.id] = { name: payload.name, email: payload.email, ptj: payload.ptj }; }\n                if(payload.op === 'delete_user') { delete USERS[payload.id]; }\n                saveLocalData();\n                renderUI();\n                return { status: 'success' };\n            }\n\n            if (!isSilent) setLoading(true);\n            try {\n                const response = await fetch(WEB_APP_URL, {\n                    method: 'POST',\n                    mode: 'no-cors', \n                    headers: { 'Content-Type': 'application\/json' },\n                    body: JSON.stringify(payload)\n                });\n                await new Promise(r => setTimeout(r, 1000)); \n                await fetchDataFromBackend(false); \n                return { status: 'success' };\n            } catch (error) {\n                if (!isSilent) Swal.fire('Ralat Rangkaian', 'Tindakan gagal.', 'error');\n                return { status: 'error' };\n            } finally {\n                if (!isSilent) setLoading(false);\n            }\n        }\n\n        function setLoading(isLoading) {\n            const overlay = document.getElementById('loadingOverlay');\n            if (isLoading) overlay.classList.remove('hidden');\n            else overlay.classList.add('hidden');\n        }\n\n        function loadLocalData() {\n            const u = localStorage.getItem('imen_users');\n            const b = localStorage.getItem('imen_bookings');\n            if(u && b) {\n                USERS = JSON.parse(u);\n                BOOKINGS = JSON.parse(b);\n                return true; \n            }\n            return false; \n        }\n\n        function saveLocalData() {\n            localStorage.setItem('imen_users', JSON.stringify(USERS));\n            localStorage.setItem('imen_bookings', JSON.stringify(BOOKINGS));\n        }\n\n        function getLocalISODate(date) {\n            const offset = date.getTimezoneOffset();\n            const local = new Date(date.getTime() - (offset * 60 * 1000));\n            return local.toISOString().split('T')[0];\n        }\n\n        \/\/ --- CORE UI LOGIC ---\n\n        function renderUI() {\n            calendar.refetchEvents();\n            renderDailyTimeline();\n            updateAgendaList(new Date()); \n            renderAdminTable();\n            renderLegend();\n        }\n\n        function handleBookingSubmit(e) {\n            e.preventDefault();\n            const picId = document.getElementById('picId').value.trim();\n            const facility = document.getElementById('bookFacility').value;\n            const date = document.getElementById('bookDate').value;\n            const start = document.getElementById('startTime').value;\n            const end = document.getElementById('endTime').value;\n            const purpose = document.getElementById('bookPurpose').value;\n            const picName = USERS[picId].name;\n            \n            \/\/ --- FEATURE: PAST DATE PREVENTION ---\n            const selectedDate = new Date(date);\n            const today = new Date();\n            today.setHours(0,0,0,0);\n            \n            if (selectedDate < today) {\n                return Swal.fire('Ralat', 'Tidak boleh menempah tarikh lepas.', 'warning');\n            }\n            \/\/ -------------------------------------\n\n            if (parseInt(start.replace(':','')) >= parseInt(end.replace(':',''))) return Swal.fire('Ralat', 'Masa tidak sah', 'error');\n            \n            const startDt = new Date(date + 'T' + start);\n            const endDt = new Date(date + 'T' + end);\n            \n            const overlap = BOOKINGS.some(b => {\n                if (b.facility !== facility) return false;\n                const bStart = new Date(b.start);\n                const bEnd = new Date(b.end);\n                return (startDt < bEnd && endDt > bStart);\n            });\n            \n            if (overlap) return Swal.fire('Bertindih', 'Masa ini sudah ditempah', 'warning');\n\n            const payload = {\n                op: 'create_booking',\n                id: Date.now().toString(),\n                title: purpose,\n                facility,\n                start: date + 'T' + start,\n                end: date + 'T' + end,\n                user: picName,\n                userId: picId,\n                purpose,\n                email: document.getElementById('picEmail').value \n            };\n\n            postToBackend(payload).then(() => {\n                closeBookingModal();\n                Swal.fire('Berjaya', 'Tempahan disahkan.', 'success');\n            });\n        }\n\n        function showRevokeOptions(bookingId) {\n            const booking = BOOKINGS.find(b => b.id == bookingId); \n            if(!booking) return;\n\n            const now = new Date();\n            const bookingStart = new Date(booking.start); \n            \n            if (now >= bookingStart) {\n                 Swal.fire('Gagal Batal', 'Tempahan telah bermula atau berlalu.', 'warning');\n                 return;\n            }\n\n            Swal.fire({\n                title: 'Urus Tempahan',\n                html: `<p class=\"text-xs text-red-500 mb-2\">Untuk batal, masukkan ID Pekerja anda:<\/p><input type=\"text\" id=\"revokeId\" class=\"swal2-input text-center uppercase\" placeholder=\"P12345\">`,\n                showCancelButton: true,\n                confirmButtonText: 'Batal Tempahan',\n                cancelButtonText: 'Tutup',\n                confirmButtonColor: '#ef4444',\n                preConfirm: () => {\n                    const inputId = Swal.getPopup().querySelector('#revokeId').value.trim();\n                    if (String(inputId).toUpperCase() !== String(booking.userId).toUpperCase()) {\n                        Swal.showValidationMessage('ID tidak sepadan');\n                    }\n                    return inputId;\n                }\n            }).then((result) => {\n                if (result.isConfirmed) {\n                    postToBackend({ op: 'delete_booking', id: booking.id }).then(() => {\n                        Swal.fire('Dibatalkan', 'Tempahan telah dibatalkan.', 'success');\n                    });\n                }\n            });\n        }\n\n        function toggleAdminView() {\n            const view = document.getElementById('adminView');\n            if (view.classList.contains('hidden')) {\n                Swal.fire({ title: 'Akses Admin', input: 'password', inputPlaceholder: 'masukkan id admin', showCancelButton: true, confirmButtonText: 'Masuk', cancelButtonText: 'Batal' })\n                .then((result) => {\n                    if (result.value === '013254') {\n                        document.getElementById('bookingView').classList.add('hidden');\n                        view.classList.remove('hidden');\n                        renderUI();\n                        renderBookingLog('active');\n                    }\n                });\n            } else { showBookingView(); }\n        }\n\n        function showBookingView() {\n            document.getElementById('adminView').classList.add('hidden');\n            document.getElementById('bookingView').classList.remove('hidden');\n            renderUI();\n        }\n\n        function editUser(id) {\n            const u = USERS[id];\n            if(!u) return;\n            const ptjOptions = Object.keys(PREDEFINED_PTJ).map(ptj => `<option value=\"${ptj}\" ${u.ptj === ptj ? 'selected' : ''}>${ptj}<\/option>`).join('');\n\n            Swal.fire({\n                title: 'Kemaskini Pengguna',\n                html: `\n                    <input id=\"editName\" class=\"swal2-input\" placeholder=\"Nama\" value=\"${u.name}\">\n                    <input id=\"editEmail\" class=\"swal2-input\" placeholder=\"Emel\" value=\"${u.email}\">\n                    <select id=\"editPtj\" class=\"swal2-input\">${ptjOptions}<\/select>\n                `,\n                showCancelButton: true,\n                confirmButtonText: 'Kemaskini',\n                cancelButtonText: 'Batal',\n                preConfirm: () => {\n                    return {\n                        op: 'edit_user',\n                        id: id,\n                        name: document.getElementById('editName').value,\n                        email: document.getElementById('editEmail').value,\n                        ptj: document.getElementById('editPtj').value\n                    }\n                }\n            }).then((result) => {\n                if(result.isConfirmed) {\n                    postToBackend(result.value).then(() => Swal.fire('Dikemaskini', 'Maklumat pengguna dikemaskini', 'success'));\n                }\n            });\n        }\n\n        function deleteUser(id) {\n            Swal.fire({ title: 'Padam Pengguna?', showCancelButton: true, confirmButtonColor: '#d33', confirmButtonText: 'Ya, Padam', cancelButtonText: 'Batal' }).then((r) => {\n                if(r.isConfirmed) postToBackend({ op: 'delete_user', id }).then(() => Swal.fire('Dipadami', '', 'success'));\n            });\n        }\n\n        function handleAdminAddUser(e) {\n            e.preventDefault();\n            const id = document.getElementById('adminNewId').value.trim();\n            const ptj = document.getElementById('adminNewPtj').value;\n            const name = document.getElementById('adminNewName').value.trim();\n            const email = document.getElementById('adminNewEmail').value.trim();\n            \n            if (USERS[id]) return Swal.fire('Ralat', 'ID sudah wujud', 'error');\n\n            postToBackend({ op: 'add_user', id, name, email, ptj }).then(() => {\n                e.target.reset();\n                Swal.fire('Ditambah', `Pengguna ${name} ditambah`, 'success');\n            });\n        }\n\n        function renderBookingLog(type) {\n            currentLogView = type;\n            const tbody = document.getElementById('bookingLogTable');\n            const btnActive = document.getElementById('btnActiveLog');\n            const btnArchive = document.getElementById('btnArchiveLog');\n            \n            if (type === 'active') {\n                btnActive.className = \"text-sm font-bold text-blue-600 border-b-2 border-blue-600 pb-1\";\n                btnArchive.className = \"text-sm font-bold text-gray-400 hover:text-gray-600 pb-1\";\n            } else {\n                btnActive.className = \"text-sm font-bold text-gray-400 hover:text-gray-600 pb-1\";\n                btnArchive.className = \"text-sm font-bold text-blue-600 border-b-2 border-blue-600 pb-1\";\n            }\n\n            const data = (type === 'active') ? BOOKINGS : ARCHIVED_BOOKINGS;\n            \n            if (type === 'archive' && ARCHIVED_BOOKINGS.length === 0) {\n                fetchArchiveData(); \/\/ Fetch if not yet fetched\n                tbody.innerHTML = '<tr><td colspan=\"4\" class=\"p-4 text-center text-gray-400\">Memuatkan arkib...<\/td><\/tr>';\n                return;\n            }\n\n            if (data.length === 0) {\n                tbody.innerHTML = '<tr><td colspan=\"4\" class=\"p-4 text-center text-gray-400\">Tiada rekod dijumpai.<\/td><\/tr>';\n                return;\n            }\n\n            const sorted = [...data].sort((a,b) => new Date(b.start) - new Date(a.start));\n\n            tbody.innerHTML = sorted.map(b => `\n                <tr class=\"hover:bg-gray-50 text-xs\">\n                    <td class=\"px-4 py-2 text-gray-900 font-medium\">${b.start.replace('T', ' ')}<\/td>\n                    <td class=\"px-4 py-2 text-gray-600\">${b.facility}<\/td>\n                    <td class=\"px-4 py-2 text-gray-600\">${b.user}<\/td>\n                    <td class=\"px-4 py-2 text-gray-500 truncate max-w-[150px]\">${b.purpose}<\/td>\n                <\/tr>\n            `).join('');\n        }\n\n        function runArchive() {\n            Swal.fire({\n                title: 'Arkibkan Tempahan Lepas?',\n                text: \"Memindahkan tempahan yang selesai ke 'Archive'.\",\n                icon: 'warning',\n                showCancelButton: true,\n                confirmButtonText: 'Ya, Arkibkan',\n                cancelButtonText: 'Batal'\n            }).then((r) => {\n                if(r.isConfirmed) {\n                    postToBackend({ op: 'archive_past_bookings' }).then(() => Swal.fire('Diarkibkan', 'Rekod lama dipindahkan.', 'success'));\n                }\n            });\n        }\n\n        function downloadLog() {\n            const data = (currentLogView === 'active') ? BOOKINGS : ARCHIVED_BOOKINGS;\n            if (data.length === 0) return Swal.fire('Kosong', 'Tiada data untuk dimuat turun.', 'info');\n            \n            let csv = \"ID,User,Facility,Start,End,Purpose\\n\";\n            data.forEach(b => {\n                csv += `${b.id},\"${b.user}\",\"${b.facility}\",${b.start},${b.end},\"${b.purpose}\"\\n`;\n            });\n            const link = document.createElement(\"a\");\n            link.href = \"data:text\/csv;charset=utf-8,\" + encodeURI(csv);\n            link.download = `gunasama_${currentLogView}_log.csv`;\n            document.body.appendChild(link);\n            link.click();\n            document.body.removeChild(link);\n        }\n\n        function verifyPIC() {\n            const id = document.getElementById('picId').value.trim();\n            const statusEl = document.getElementById('picStatus');\n            const step2El = document.getElementById('step2');\n            if (USERS[id]) {\n                statusEl.innerHTML = `<span class=\"text-green-600 font-bold\"><i class=\"fas fa-check-circle\"><\/i> ${USERS[id].name} (${USERS[id].ptj})<\/span>`;\n                document.getElementById('picEmail').value = USERS[id].email;\n                step2El.classList.remove('hidden', 'opacity-50', 'pointer-events-none');\n            } else {\n                statusEl.innerHTML = `<span class=\"text-red-500 font-medium\"><i class=\"fas fa-exclamation-circle\"><\/i> Akses Ditolak\/Tiada Data.<\/span>`;\n                step2El.classList.add('hidden', 'opacity-50', 'pointer-events-none');\n            }\n        }\n\n        function calculateMaxBookingDate() {\n            const now = new Date();\n            const currentMonth = now.getMonth(); \n            const currentYear = now.getFullYear();\n            const currentDate = now.getDate();\n            const currentQuarterEndMonth = Math.floor(currentMonth \/ 3) * 3 + 2;\n            let limitMonth = currentQuarterEndMonth;\n            let limitYear = currentYear;\n            if (currentMonth === currentQuarterEndMonth && currentDate >= 20) {\n                limitMonth += 3;\n            }\n            return new Date(limitYear, limitMonth + 1, 0); \n        }\n\n        function updateTimeSlotAvailability() {\n            const dateVal = document.getElementById('bookDate').value;\n            const startSelect = document.getElementById('startTime');\n            const endSelect = document.getElementById('endTime');\n            startSelect.innerHTML = '';\n            endSelect.innerHTML = '<option value=\"\">Pilih Mula Dahulu<\/option>';\n            \n            if (!dateVal) return;\n\n            const todaysBookings = BOOKINGS.filter(b => {\n                if (b.facility !== currentFacility) return false;\n                const bookingDate = new Date(b.start);\n                return getLocalISODate(bookingDate) === dateVal;\n            });\n\n            const startHours = [8,9,10,11,12,13,14,15,16,17];\n            \n            startHours.forEach(h => {\n                let isOccupied = false;\n                todaysBookings.forEach(b => {\n                    const s = new Date(b.start);\n                    const e = new Date(b.end);\n                    const sH = s.getHours();\n                    const eH = e.getHours();\n                    if (h >= sH && h < eH) isOccupied = true;\n                });\n\n                const timeStr = h < 10 ? `0${h}:00` : `${h}:00`;\n                const displayStr = h < 12 ? `${timeStr} AM` : (h === 12 ? `12:00 PM` : `${h-12}:00 PM`);\n                \n                const option = document.createElement('option');\n                option.value = timeStr;\n                option.text = isOccupied ? `${displayStr} (Penuh)` : displayStr;\n                option.disabled = isOccupied;\n                startSelect.appendChild(option);\n            });\n\n            if (startSelect.options.length > 0 && !startSelect.value) {\n                for(let opt of startSelect.options) { if(!opt.disabled) { startSelect.value = opt.value; break; } }\n            }\n            updateEndTimeOptions();\n        }\n\n        function updateEndTimeOptions() {\n            const dateVal = document.getElementById('bookDate').value;\n            const startVal = document.getElementById('startTime').value;\n            const endSelect = document.getElementById('endTime');\n            endSelect.innerHTML = '';\n            \n            if (!dateVal || !startVal) return;\n            \n            const startHour = parseInt(startVal.split(':')[0]);\n            \n            const todaysBookings = BOOKINGS.filter(b => {\n                if (b.facility !== currentFacility) return false;\n                const bookingDate = new Date(b.start);\n                return getLocalISODate(bookingDate) === dateVal;\n            });\n            \n            todaysBookings.sort((a,b) => new Date(a.start) - new Date(b.start));\n            \n            let cutoffHour = 18; \n            \n            for (let b of todaysBookings) {\n                const s = new Date(b.start);\n                const sH = s.getHours();\n                \n                if (sH > startHour) {\n                    cutoffHour = sH;\n                    break;\n                }\n            }\n\n            for (let h = startHour + 1; h <= 18; h++) {\n                const timeStr = h < 10 ? `0${h}:00` : `${h}:00`;\n                const displayStr = h < 12 ? `${timeStr} AM` : (h === 12 ? `12:00 PM` : `${h-12}:00 PM`);\n                \n                let isDisabled = false;\n                let label = displayStr;\n\n                if (h > cutoffHour) {\n                    isDisabled = true;\n                    label += \" (Penuh)\";\n                }\n\n                const option = document.createElement('option');\n                option.value = timeStr;\n                option.text = label;\n                option.disabled = isDisabled;\n                endSelect.appendChild(option);\n            }\n        }\n\n        function renderLegend() {\n            const legendEl = document.getElementById('ptjLegend');\n            legendEl.innerHTML = Object.entries(PTJ_COLORS).map(([ptj, color]) => `\n                <div class=\"flex items-center gap-1\"><span class=\"w-2 h-2 rounded-full\" style=\"background-color: ${color}\"><\/span> ${ptj}<\/div>\n            `).join('');\n        }\n\n        function initCalendar() {\n\t\t\tvar calendarEl = document.getElementById('calendar');\n            var maxDate = calculateMaxBookingDate();\n\n            \/\/ --- FIX: Add 1 Day for FullCalendar Display ---\n            \/\/ FullCalendar's 'end' date is exclusive (it stops BEFORE this date).\n            \/\/ If maxDate is March 31, we need to set this to April 1 so March 31 is shown.\n            var calendarDisplayLimit = new Date(maxDate);\n            calendarDisplayLimit.setDate(calendarDisplayLimit.getDate() + 1);\n\n            calendar = new FullCalendar.Calendar(calendarEl, {\n                initialView: 'dayGridMonth',\n                headerToolbar: { left: 'prev', center: 'title', right: 'next' },\n                titleFormat: { month: 'short', year: 'numeric' },\n                \n                \/\/ --- FEATURE: PAST DATE VIEWING ---\n                \/\/ Use the modified +1 date here\n                validRange: { end: calendarDisplayLimit }, \n                \n                height: 'auto',\n                firstDay: 1, \n                fixedWeekCount: false,\n                \n                \/\/ --- VISUAL: Gray out past dates ---\n                dayCellClassNames: (arg) => {\n                    const cellDate = arg.date;\n                    const today = new Date();\n                    today.setHours(0,0,0,0);\n                    if (cellDate < today) return ['fc-day-past'];\n                    return [];\n                },\n                \n                eventContent: function(arg) {\n                    const userId = arg.event.extendedProps.userId;\n                    const user = USERS[userId] || { ptj: 'Unknown' };\n                    \/\/ Fallback to grey if PTJ color not found\n                    const dotColor = PTJ_COLORS[user.ptj] || '#9ca3af';\n                    let dotEl = document.createElement('div');\n                    dotEl.className = 'event-dot';\n                    dotEl.style.backgroundColor = dotColor;\n                    return { domNodes: [dotEl] };\n                },\n                \n                events: function(info, successCallback) {\n                    let filtered = BOOKINGS.filter(b => b.facility === currentFacility);\n                    let events = filtered.map(b => ({\n                        id: b.id,\n                        start: b.start,\n                        end: b.end,\n                        userId: b.userId \n                    }));\n                    successCallback(events);\n                },\n                \n                dateClick: function(info) {\n                    document.querySelectorAll('.selected-date-cell').forEach(el => el.classList.remove('selected-date-cell'));\n                    info.dayEl.classList.add('selected-date-cell');\n                    updateAgendaList(info.dateStr);\n                }\n            });\n            calendar.render();\n\t\t\t}\n\n        function updateAgendaList(dateInput) {\n            let dateStr;\n            let dateObj;\n\n            if (typeof dateInput === 'string') {\n                dateStr = dateInput;\n                const parts = dateStr.split('-');\n                dateObj = new Date(parts[0], parts[1] - 1, parts[2]);\n            } else {\n                dateStr = getLocalISODate(dateInput);\n                dateObj = dateInput;\n            }\n\n            \/\/ Using 'ms-MY' for Bahasa Malaysia date formatting\n            const displayDate = dateObj.toLocaleDateString('ms-MY', { weekday: 'long', month: 'long', day: 'numeric' });\n            \n            document.getElementById('agendaDate').textContent = displayDate;\n            document.getElementById('agendaSubtitle').textContent = currentFacility;\n            \n            \/\/ --- FEATURE: VISUAL BADGE FOR PAST DATE ---\n            const today = new Date();\n            today.setHours(0,0,0,0);\n            if (dateObj < today) {\n                document.getElementById('pastDateBadge').classList.remove('hidden');\n            } else {\n                document.getElementById('pastDateBadge').classList.add('hidden');\n            }\n\n            const listEl = document.getElementById('agendaList');\n            \n            const dayBookings = BOOKINGS.filter(b => b.facility === currentFacility && b.start.startsWith(dateStr))\n                .sort((a,b) => new Date(a.start) - new Date(b.start));\n\n            if (dayBookings.length === 0) {\n                listEl.innerHTML = `<div class=\"flex flex-col items-center justify-center h-48 text-gray-400\"><i class=\"fas fa-mug-hot text-2xl mb-2 opacity-50\"><\/i><span class=\"text-sm font-medium\">Kosong sepanjang hari<\/span><\/div>`;\n                return;\n            }\n\n            const now = new Date();\n\n            listEl.innerHTML = dayBookings.map(b => {\n                const start = new Date(b.start);\n                const end = new Date(b.end);\n                \n                const user = USERS[b.userId] || { ptj: 'Unknown' };\n                const color = PTJ_COLORS[user.ptj] || '#9ca3af';\n                \n                let progress = 0;\n                let isActive = false;\n                if (now > end) {\n                    progress = 100;\n                } else if (now > start && now < end) {\n                    isActive = true;\n                    const totalDuration = end - start;\n                    const elapsed = now - start;\n                    progress = (elapsed \/ totalDuration) * 100;\n                }\n\n                const startTimeStr = start.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});\n                const endTimeStr = end.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});\n                \n                return `\n                <div onclick=\"showRevokeOptions('${b.id}')\" class=\"ios-list-item cursor-pointer p-4 pb-8 border-b border-gray-100 flex items-start gap-3 group relative overflow-hidden\">\n                    \n                    <div class=\"text-xs font-bold text-gray-500 w-14 pt-1 text-right leading-tight flex-shrink-0\">\n                        ${startTimeStr}<br>\n                        <span class=\"text-gray-300 font-normal\">${endTimeStr}<\/span>\n                    <\/div>\n                    \n                    <div class=\"flex-1 z-10 min-w-0\">\n                        <h4 class=\"text-sm font-bold text-gray-900 break-words leading-snug\">${b.purpose}<\/h4>\n                        <div class=\"flex gap-2 items-center mt-1\">\n                            <span class=\"text-[10px] font-bold px-1.5 py-0.5 rounded bg-gray-100 text-gray-600\" style=\"color:${color}\">${user.ptj}<\/span>\n                            <span class=\"text-xs text-gray-500\">${b.user}<\/span>\n                        <\/div>\n                    <\/div>\n\n                    <div class=\"text-gray-300 group-hover:text-blue-500 transition z-10 flex-shrink-0 self-center\">\n                        <i class=\"fas fa-chevron-right text-xs\"><\/i>\n                    <\/div>\n\n                    ${isActive || progress > 0 ? `\n                        <div class=\"absolute bottom-2 left-4 right-4 h-2 bg-gray-100 rounded-full overflow-hidden\">\n                            <div class=\"h-full rounded-full custom-progress-bar transition-all duration-1000\" style=\"width: ${progress}%\"><\/div>\n                        <\/div>\n                    ` : ''}\n                <\/div>\n                `;\n            }).join('');\n        }\n\n        function renderAdminTable() {\n            const tbody = document.getElementById('adminUserTable');\n            tbody.innerHTML = Object.entries(USERS).map(([id, data]) => `\n                <tr class=\"hover:bg-gray-50\">\n                    <td class=\"px-4 py-2 text-xs font-medium text-gray-900\">${id}<\/td>\n                    <td class=\"px-4 py-2 text-xs text-gray-500\">\n                        <span class=\"px-2 py-1 rounded bg-gray-100 font-bold\" style=\"color: ${PTJ_COLORS[data.ptj] || '#666'}\">${data.ptj || '-'}<\/span>\n                    <\/td>\n                    <td class=\"px-4 py-2 text-xs text-gray-500\">${data.name}<\/td>\n                    <td class=\"px-4 py-2 text-xs text-gray-500\">${data.email}<\/td>\n                    <td class=\"px-4 py-2 text-right text-xs font-medium flex gap-2 justify-end\">\n                        <button onclick=\"editUser('${id}')\" class=\"text-blue-500 hover:text-blue-700\"><i class=\"fas fa-pencil\"><\/i><\/button>\n                        <button onclick=\"deleteUser('${id}')\" class=\"text-red-600 hover:text-red-900\">Padam<\/button>\n                    <\/td>\n                <\/tr>\n            `).join('');\n        }\n        \n        function updatePtjDropdown() {\n            const select = document.getElementById('adminNewPtj');\n            \/\/ Populate from the hardcoded constant PREDEFINED_PTJ\n            select.innerHTML = '<option value=\"\">Pilih PTJ<\/option>' + \n                Object.keys(PREDEFINED_PTJ).map(ptj => `<option value=\"${ptj}\">${ptj}<\/option>`).join('');\n        }\n\n        function switchTab(facility) {\n            currentFacility = facility;\n            updateTabUI();\n            calendar.refetchEvents();\n            renderDailyTimeline();\n            \n            document.getElementById('bookFacility').value = facility;\n            document.getElementById('bookingFacilityDisplay').textContent = facility;\n            document.getElementById('agendaSubtitle').textContent = facility;\n            document.getElementById('agendaList').innerHTML = `<div class=\"flex flex-col items-center justify-center h-48 text-gray-400\"><span class=\"text-sm\">Fasiliti ditukar. Sila pilih tarikh.<\/span><\/div>`;\n        }\n\n        function updateTabUI() {\n            document.querySelectorAll('.facility-tab').forEach(el => {\n                if (el.id === `tab-${currentFacility}`) {\n                    el.classList.remove('text-gray-500', 'hover:text-gray-900', 'bg-transparent');\n                    el.classList.add('bg-white', 'text-black', 'shadow-sm');\n                } else {\n                    el.classList.add('text-gray-500', 'hover:text-gray-900', 'bg-transparent');\n                    el.classList.remove('bg-white', 'text-black', 'shadow-sm');\n                }\n            });\n        }\n\n        function renderDailyTimeline() {\n            const container = document.getElementById('dailyTimeline');\n            container.innerHTML = ''; \n            const now = new Date();\n            const startHour = 8;\n            const endHour = 18;\n            const totalHours = endHour - startHour;\n            const currentH = now.getHours() + now.getMinutes()\/60;\n            if (currentH >= startHour && currentH <= endHour) {\n                const pct = ((currentH - startHour) \/ totalHours) * 100;\n                const marker = document.createElement('div');\n                marker.className = 'current-time-marker';\n                marker.style.left = `${pct}%`;\n                container.appendChild(marker);\n            }\n            const todayStr = now.toISOString().split('T')[0];\n            const todays = BOOKINGS.filter(b => b.facility === currentFacility && b.start.startsWith(todayStr));\n            todays.forEach(b => {\n                const s = new Date(b.start);\n                const e = new Date(b.end);\n                const sH = Math.max(startHour, s.getHours() + s.getMinutes()\/60);\n                const eH = Math.min(endHour, e.getHours() + e.getMinutes()\/60);\n                if (eH > sH) {\n                    const left = ((sH - startHour) \/ totalHours) * 100;\n                    const width = ((eH - sH) \/ totalHours) * 100;\n                    const block = document.createElement('div');\n                    block.className = 'timeline-block';\n                    block.style.left = `${left}%`;\n                    block.style.width = `${width}%`;\n                    const user = USERS[b.userId] || { ptj: 'Unknown' };\n                    \/\/ Fallback color if undefined\n                    block.style.backgroundColor = PTJ_COLORS[user.ptj] || '#9ca3af';\n                    container.appendChild(block);\n                }\n            });\n        }\n\n        function openBookingModal() {\n            document.getElementById('bookingModal').classList.remove('opacity-0', 'pointer-events-none');\n            document.getElementById('modalContent').classList.remove('scale-95');\n            document.getElementById('modalContent').classList.add('scale-100');\n            document.getElementById('bookingForm').reset();\n            document.getElementById('step2').classList.add('hidden', 'opacity-50', 'pointer-events-none');\n            document.getElementById('picStatus').innerHTML = '';\n            \n            \/\/ --- FIX FOR GREYED OUT DATE ---\n            var maxDate = calculateMaxBookingDate();\n\n            \/\/ Manually format to YYYY-MM-DD using local time to prevent timezone shifts\n            \/\/ (Standard .toISOString() converts to UTC, which might act strangely near midnight)\n            var year = maxDate.getFullYear();\n            var month = (\"0\" + (maxDate.getMonth() + 1)).slice(-2);\n            var day = (\"0\" + maxDate.getDate()).slice(-2);\n            var maxDateString = `${year}-${month}-${day}`;\n\n            \/\/ --- FEATURE: PREVENT BOOKING PAST DATES ---\n            \/\/ We do the same manual formatting for 'today' to be safe\n            var now = new Date();\n            var minYear = now.getFullYear();\n            var minMonth = (\"0\" + (now.getMonth() + 1)).slice(-2);\n            var minDay = (\"0\" + now.getDate()).slice(-2);\n            var minDateString = `${minYear}-${minMonth}-${minDay}`;\n            \n            document.getElementById('bookDate').min = minDateString;\n            document.getElementById('bookDate').max = maxDateString;\n            \n            \/\/ Update the helper text\n            document.getElementById('dateLimitText').innerHTML = `Dibuka sehingga: ${maxDate.toLocaleDateString('ms-MY')}<br><br>Setiap fasa akan mula dibuka pada setiap 20hb (Mac, Jun, Sept, Dec)<br>Fasa 1: Jan-Mac<br>Fasa 2: Apr-Jun<br>Fasa 3: Jul-Sept<br>Fasa 4: Okt-Dec`;\n        }\n\n        function closeBookingModal() {\n            document.getElementById('bookingModal').classList.add('opacity-0', 'pointer-events-none');\n            document.getElementById('modalContent').classList.remove('scale-100');\n            document.getElementById('modalContent').classList.add('scale-95');\n        }\n    <\/script>\n<\/body>\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Tempahan Gunasama Kompleks fethching booking&#8230; G Gunasama Kompleks Mengemaskini&#8230; Sistem Tempahan Admin Tempah Bilik Mesyuarat Bilik Seminar 1 Bilik Seminar 2 Kalendar 08:00 slot hari<a class=\"ut-readmore\" href=\"https:\/\/www.ukm.my\/imenhub\/gunasama-kompleks\/\"> &#8230;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-34","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/pages\/34","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/comments?post=34"}],"version-history":[{"count":81,"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/pages\/34\/revisions"}],"predecessor-version":[{"id":384,"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/pages\/34\/revisions\/384"}],"wp:attachment":[{"href":"https:\/\/www.ukm.my\/imenhub\/wp-json\/wp\/v2\/media?parent=34"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}