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(); ?>

Welcome, display_name ); ?>

Personal Time Tracking Overview


'Active Now', 'val' => $pulse['active_now'], 'color' => '#4CAF50'], ['label' => 'Pending Edits', 'val' => $pulse['pending_edits'], 'color' => '#2196F3'], ['label' => 'System TORs', 'val' => $pulse['total_pending_tor'], 'color' => '#FF9800'] ]; ?>

System Pulse

ADMIN CONSOLE

🛠️ System Settings ⚙️ Global Profile
🚪 Logout
$label
$val"; } public static function render_timeclock() { if ( ! is_user_logged_in() ) return '

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(); ?>
Current Shift:
Status: Off the Clock
Weekly Total: hrs
get_results( $wpdb->prepare( "SELECT * FROM $table_name WHERE user_id = %d ORDER BY timestamp DESC LIMIT 10", $user_id ) ); if ( $history ): ?>

Recent Activity

timestamp); $orig_time = wp_date( 'D, M j, g:i a', $ts_local ); $is_today = (wp_date('Y-m-d', $ts_local) === (new DateTime('now', new DateTimeZone(KTC_TIMEZONE)))->format('Y-m-d')) ? 'true' : 'false'; ?>
action_type)); ?>
get_results("SELECT * FROM {$wpdb->prefix}ktc_logs WHERE status = 'pending_correction' ORDER BY timestamp DESC"); if ( ! $pending ) return ''; ob_start(); ?>

Admin: Correction Queue

user_id); ?>
display_name; ?>: proposed_timestamp)); ?>
Approve Reject
'integer', 'default' => 12] ); register_setting( 'ktc_settings_group', 'ktc_enable_teams', ['type' => 'boolean', 'default' => 0] ); register_setting( 'ktc_settings_group', 'ktc_teams_webhook', ['type' => 'string'] ); // 3. Section add_settings_section( 'ktc_main_section', 'Core Configuration', '__return_false', 'ktc-settings' ); // 4. Fields - Triple check that these method names exist in this class add_settings_field( 'ktc_timezone_field', 'Timezone', array( __CLASS__, 'render_timezone_field' ), 'ktc-settings', 'ktc_main_section' ); add_settings_field( 'ktc_alert_threshold_field', 'Zombie Alert Threshold (Hours)', array( __CLASS__, 'render_threshold_field' ), 'ktc-settings', 'ktc_main_section' ); add_settings_field( 'ktc_teams_config_field', 'MS Teams Integration', array( 'KTC_Admin', 'render_teams_fields' ), 'ktc-settings', 'ktc_main_section' ); } public static function render_settings_content() { ?>

Krista Time Clock Settings

'; echo '

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.