diff --git a/assets/ktc-app.js.bak1 b/assets/ktc-app.js.bak1 deleted file mode 100755 index dc727ba..0000000 --- a/assets/ktc-app.js.bak1 +++ /dev/null @@ -1,196 +0,0 @@ - - -// --- 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); - - diff --git a/includes/class-admin.php~ b/includes/class-admin.php~ deleted file mode 100755 index 21f6cf9..0000000 --- a/includes/class-admin.php~ +++ /dev/null @@ -1,370 +0,0 @@ - admin_url( 'admin-ajax.php' ), - 'lockoutTime' => 60 // Seconds for the button cooldown - )); - - $tz_string = get_option( 'ktc_timezone', 'America/Chicago' ); - wp_add_inline_script( 'ktc-app-js', "const ktcSovereignTZ = '{$tz_string}';", 'before' ); - - } - - public static function init() { - add_shortcode( 'krista_timeclock', array( __CLASS__, 'render_timeclock' ) ); - add_shortcode( 'ktc_portal_welcome', array( __CLASS__, 'render_welcome' ) ); - add_action( 'wp_footer', array( __CLASS__, 'inject_ui_scripts' ) ); - add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) ); - add_action( 'admin_menu', array( __CLASS__, 'register_settings_page' ) ); - - add_action( 'admin_init', function() { - if ( ! current_user_can('manage_options') && ! defined('DOING_AJAX') && $GLOBALS['pagenow'] !== 'profile.php' && current_user_can('ktc_user') ) { - wp_safe_redirect( home_url('/') ); exit; - } - }); - - add_action( 'admin_init', function() { - add_settings_section( 'ktc_main_section', 'General Configuration', null, 'ktc-settings' ); - add_settings_field( 'ktc_week_start_field', 'Week Starts On', function() { - $val = get_option('ktc_week_start', 'Monday'); - echo ""; - }, 'ktc-settings', 'ktc_main_section' ); - add_settings_field( 'ktc_timezone_field', 'Sovereign Timezone', array( __CLASS__, 'render_timezone_field' ), 'ktc-settings', 'ktc_main_section' ); - }); - - } - -/** - * Renders a unified dashboard header. - * Consolidates Admin 'Pulse' and User 'Stats' based on capability. - */ - public static function render_welcome() { - if ( ! is_user_logged_in() ) return 'Please log in to continue'; - - $user = wp_get_current_user(); - $is_admin = current_user_can('manage_options'); - - // Everyone gets Personal Stats - $stats = KTC_Logic::get_user_stats( $user->ID ); - $user_stat_data = [ - ['label' => 'This Week', 'val' => $stats['week'] . ' hrs', 'color' => '#2196F3'], - ['label' => 'This Month', 'val' => $stats['month'] . ' hrs', 'color' => '#4CAF50'], - ['label' => 'My Pending TORs', 'val' => $stats['pending_tor'], 'color' => '#FF9800'] - ]; - - ob_start(); ?> - - -
Personal Time Tracking Overview
-Please log in.
'; - global $wpdb; - $user_id = get_current_user_id(); - $table_name = $wpdb->prefix . 'ktc_logs'; - - $status = $wpdb->get_var( $wpdb->prepare( "SELECT action_type FROM $table_name WHERE user_id = %d ORDER BY timestamp DESC LIMIT 1", $user_id ) ) ?: 'clock_out'; - $btn_color = ($status === 'clock_in') ? '#d9534f' : '#5cb85c'; - $next_action = ($status === 'clock_in') ? 'clock_out' : 'clock_in'; - - ob_start(); ?> -| - | action_type)); ?> | -- |
Hours before a shift is flagged as a "Zombie Shift".
'; -} - -/** - * Renders the Teams Toggle and Webhook URL - */ -public static function render_teams_fields() { - $enabled = get_option( 'ktc_enable_teams', 0 ); - $webhook = get_option( 'ktc_teams_webhook', '' ); - ?> - -Enter your Microsoft Teams Incoming Webhook URL.
- - -This defines the legal "Source of Truth" for all timestamps, bypassing server or WP site drift.
-