// --- Guardrail 1: Punch Lockout --- document.addEventListener('DOMContentLoaded', function() { const btn = document.getElementById('ktc-punch-button'); const timerDiv = document.getElementById('ktc-timer'); const countdown = document.getElementById('ktc-countdown'); const form = document.getElementById('ktc-punch-form'); // Initial check on page load updateTimer(); function updateTimer() { const expiry = localStorage.getItem('ktc_lockout_expiry'); if (expiry) { const now = Date.now(); const timeLeft = Math.ceil((expiry - now) / 1000); if (timeLeft > 0) { btn.disabled = true; btn.style.opacity = '0.5'; btn.style.cursor = 'not-allowed'; timerDiv.style.display = 'block'; countdown.innerText = timeLeft; setTimeout(updateTimer, 1000); // Check again in 1s } else { btn.disabled = false; btn.style.opacity = '1'; btn.style.cursor = 'pointer'; timerDiv.style.display = 'none'; localStorage.removeItem('ktc_lockout_expiry'); } } } // --- New Listener for Admin Surgical Edits --- document.addEventListener('click', function(e) { // Check if the clicked element (or its parent) has our trigger class const trigger = e.target.closest('.ktc-edit-trigger'); if (trigger) { e.preventDefault(); // Stop the '#' jump // Pull the data attributes we set in PHP const logId = trigger.getAttribute('data-log-id'); const timestamp = trigger.getAttribute('data-current-time'); // Determine if it's "Today" for the future-time guardrail // Simple check: does the date string match today's YYYY-MM-DD? const todayStr = new Date().toISOString().split('T')[0]; const isToday = timestamp.includes(todayStr); // Fire your existing function ktc_open_edit_modal(logId, timestamp, isToday); } }); const body = document.querySelector('body'); if (body) { body.addEventListener('click', function(e) { // Check if the clicked element is our edit link if (e.target && e.target.classList.contains('ktc-edit-trigger')) { e.preventDefault(); const logId = e.target.getAttribute('data-log-id'); const currentTime = e.target.getAttribute('data-current-time'); // Extract HH:MM for the time input (expects 24hr format HH:MM) // Assuming timestamp format: "2026-05-04 14:30:00" const timeParts = currentTime.split(' '); const rawTime = timeParts.length > 1 ? timeParts[1].substring(0, 5) : ''; // Call the existing modal function ktc_open_edit_modal(logId, currentTime, true, rawTime); } }); } form?.addEventListener('submit', function(e) { // Set expiry for 60 seconds from now const expiryTime = Date.now() + 60000; localStorage.setItem('ktc_lockout_expiry', expiryTime); // The page will now refresh, and updateTimer() will catch it on reload }); }); // --- Guardrail 2: Modal Future-Time Validation --- document.getElementById('ktc_proposed_time')?.addEventListener('input', function() { const submitBtn = this.form.querySelector('button[type="submit"]'); // If the input has a 'max' attribute and value exceeds it if (this.max && this.value > this.max) { this.style.borderColor = 'red'; this.style.backgroundColor = '#fff0f0'; submitBtn.disabled = true; submitBtn.style.opacity = '0.5'; } else { this.style.borderColor = '#ccc'; this.style.backgroundColor = '#fff'; submitBtn.disabled = false; submitBtn.style.opacity = '1'; } }); function ktc_open_edit_modal(id, ts, isToday) { document.getElementById("ktc_edit_id").value = id; document.getElementById("ktc_modal_orig_time").innerText = "Original: " + ts; const timeInput = document.getElementById("ktc_proposed_time"); if (isToday) { // Set max to current Chicago time (HH:MM) const now = new Date().toLocaleTimeString('en-GB', { timeZone: ktcSovereignTZ, hour: '2-digit', minute: '2-digit' }); timeInput.setAttribute('max', now); } else { timeInput.removeAttribute('max'); } document.getElementById("ktc_edit_modal").style.display = "block"; } // --- Guardrail 3: The Live Heartbeat --- function ktc_start_heartbeat() { const elapsedElement = document.getElementById('ktc-live-elapsed'); if (!elapsedElement) return; // Pull the initial seconds we injected via PHP let totalSeconds = parseInt(elapsedElement.getAttribute('data-seconds')); setInterval(() => { totalSeconds++; // Math to format seconds into "Xh Ym Zs" or "Xh Ym" const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; // Update the display (Adding seconds for that "Live" feel) elapsedElement.innerText = `${hours}h ${minutes}m ${seconds}s`; }, 1000); } /** * Consolidated KTC Heartbeat: Handles Real-Time Clock & Title Teleportation */ function ktc_init_digital_clock() { const clock = document.getElementById('ktc-digital-clock'); if (!clock) return; // Use a single interval to handle both time updates and UI placement setInterval(() => { // 1. Generate the time string using our Sovereign Timezone const tz = typeof ktcSovereignTZ !== 'undefined' ? ktcSovereignTZ : 'America/Chicago'; const timeString = new Date().toLocaleTimeString('en-US', { timeZone: tz, hour12: true, hour: '2-digit', minute: '2-digit', second: '2-digit' }); // 2. Update the display clock.innerText = timeString; // 3. One-time Teleport Check // We only attempt to move it if it's not already inside the 'ktc-clock-target' const pageTitle = document.querySelector('.entry-title, h1.page-title, h1'); const isAlreadyTeleported = document.getElementById('ktc-clock-target'); if (pageTitle && !isAlreadyTeleported) { const target = document.createElement('span'); target.id = 'ktc-clock-target'; target.style.marginLeft = '20px'; target.style.fontSize = '0.6em'; target.style.verticalAlign = 'middle'; target.style.color = '#888'; // Subtle color for the clock in the title pageTitle.appendChild(target); target.appendChild(clock); // Physically moves the element in the DOM // Cleanup the source container if it exists const sourceContainer = document.getElementById('ktc-clock-teleport-source'); if (sourceContainer) sourceContainer.remove(); } }, 1000); } // Initialize on DOM load document.addEventListener('DOMContentLoaded', ktc_init_digital_clock); // Initialize on load document.addEventListener('DOMContentLoaded', ktc_start_heartbeat);