From 0124c0fa8587d90f995f809dc666f4aaf1f1a33e Mon Sep 17 00:00:00 2001 From: Ruben Ramirez Date: Fri, 4 Apr 2025 09:17:41 -0500 Subject: [PATCH] Initial dashboard widgets --- functions.php | 144 ++++++++++++++++++++++++++++++++ style.css | 111 ++++++++++++++++++++++++ template-quiztech-dashboard.php | 96 ++++++++++++++++++++- 3 files changed, 349 insertions(+), 2 deletions(-) diff --git a/functions.php b/functions.php index bc33afa..d82c76e 100644 --- a/functions.php +++ b/functions.php @@ -585,4 +585,148 @@ function quiztech_ajax_save_question() { } add_action( 'wp_ajax_quiztech_save_question', 'quiztech_ajax_save_question' ); + + +// --- Dashboard Helper Functions --- + +/** + * Get URLs for dashboard quick links. + * + * @return array Associative array of 'Label' => 'URL'. + */ +function quiztech_get_dashboard_quick_links() { + $links = []; + $page_slugs = [ + 'manage-jobs' => __('Manage Jobs', 'quiztech'), + 'assessment-builder' => __('Manage Assessments', 'quiztech'), // Link to builder/manager + 'manage-questions' => __('Manage Questions', 'quiztech'), + 'manage-credits' => __('Manage Credits', 'quiztech'), + // Add 'Create New' links if separate pages exist, otherwise link to managers + // 'create-job' => __('Create New Job', 'quiztech'), + ]; + + foreach ($page_slugs as $slug => $label) { + $page = get_page_by_path($slug); + $links[$label] = $page ? get_permalink($page->ID) : ''; // Return empty string if page not found + } + + // Add direct links for creating new content if possible (often handled by query args on manager pages) + // Example: $links[__('Create New Job', 'quiztech')] = add_query_arg('action', 'new', $links[__('Manage Jobs', 'quiztech')]); + + return $links; +} + +/** + * Get recent invitations sent. + * + * @param int $count Number of invitations to retrieve. + * @return array Array of invitation objects/arrays. + */ +function quiztech_get_dashboard_recent_invitations($count = 5) { + global $wpdb; + $invitations_table = $wpdb->prefix . 'quiztech_invitations'; + $posts_table = $wpdb->posts; + + // Ensure table exists before querying + if ($wpdb->get_var("SHOW TABLES LIKE '{$invitations_table}'") != $invitations_table) { + return []; // Table doesn't exist + } + + $query = $wpdb->prepare( + "SELECT inv.applicant_email, inv.created_at, p.post_title AS job_title + FROM {$invitations_table} inv + LEFT JOIN {$posts_table} p ON inv.job_id = p.ID + ORDER BY inv.created_at DESC + LIMIT %d", + absint($count) + ); + + $results = $wpdb->get_results($query); + + return $results ? $results : []; +} + +/** + * Get recent completed assessments. + * + * @param int $count Number of completions to retrieve. + * @return array Array of completion data. + */ +function quiztech_get_dashboard_recent_completions($count = 5) { + global $wpdb; + $invitations_table = $wpdb->prefix . 'quiztech_invitations'; + $completions = []; + + $args = [ + 'post_type' => 'user_evaluation', + 'post_status' => 'completed', // Assuming 'completed' status is used + 'posts_per_page' => absint($count), + 'orderby' => 'date', + 'order' => 'DESC', + 'meta_query' => [ + [ + 'key' => 'quiztech_invitation_id', + 'compare' => 'EXISTS' // Ensure it's linked + ] + ] + ]; + + $query = new WP_Query($args); + + if ($query->have_posts()) { + // Check if invitations table exists + $invitations_table_exists = ($wpdb->get_var("SHOW TABLES LIKE '{$invitations_table}'") == $invitations_table); + + while ($query->have_posts()) { + $query->the_post(); + $evaluation_id = get_the_ID(); + $completion_date = get_the_date(); // Or post_modified if that's more relevant + $invitation_id = get_post_meta($evaluation_id, 'quiztech_invitation_id', true); + $applicant_email = 'N/A'; + $job_title = 'N/A'; + + if ($invitation_id && $invitations_table_exists) { + $invitation_data = $wpdb->get_row($wpdb->prepare( + "SELECT inv.applicant_email, p.post_title AS job_title + FROM {$invitations_table} inv + LEFT JOIN {$wpdb->posts} p ON inv.job_id = p.ID + WHERE inv.id = %d", + absint($invitation_id) + )); + if ($invitation_data) { + $applicant_email = $invitation_data->applicant_email; + $job_title = $invitation_data->job_title; + } + } + + $completions[] = [ + 'applicant_email' => $applicant_email, + 'job_title' => $job_title, + 'completion_date' => $completion_date, + 'evaluation_id' => $evaluation_id // For potential linking + ]; + } + wp_reset_postdata(); + } + + return $completions; +} + +/** + * Get the count of active job posts. + * + * @return int Count of published jobs. + */ +function quiztech_get_dashboard_active_job_count() { + $args = [ + 'post_type' => 'job', + 'post_status' => 'publish', + 'posts_per_page' => -1, // Count all + 'fields' => 'ids' // Only need IDs for counting + ]; + $query = new WP_Query($args); + return $query->post_count; +} + +// --- End Dashboard Helper Functions --- add_action( 'template_redirect', 'quiztech_handle_credit_purchase_submission', 1 ); // Hook earlier (priority 1) diff --git a/style.css b/style.css index 3b2ef87..85437e2 100644 --- a/style.css +++ b/style.css @@ -116,3 +116,114 @@ #assessment-builder-library .library-question-item:active { cursor: grabbing; } + + +/* Quiztech Dashboard Styles */ +.quiztech-dashboard-widgets { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); /* Responsive grid */ + gap: 20px; + margin-top: 20px; +} + +.dashboard-widget { + border: 1px solid #e0e0e0; + padding: 15px 20px; + background-color: #fff; + box-shadow: 0 1px 1px rgba(0,0,0,.04); +} + +.dashboard-widget h2 { + margin-top: 0; + margin-bottom: 15px; + font-size: 1.2em; + border-bottom: 1px solid #eee; + padding-bottom: 10px; +} + +.dashboard-widget h3 { + margin-top: 15px; + margin-bottom: 10px; + font-size: 1em; + color: #555; +} + +/* Quick Links Widget */ +.quick-links ul { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-wrap: wrap; + gap: 10px; +} + +.quick-links li { + margin: 0; +} + +.quick-links a.button, +.quick-links span.button.disabled { + display: inline-block; + padding: 8px 15px; + text-decoration: none; + border: 1px solid #ccc; + border-radius: 3px; + background-color: #f7f7f7; + color: #555; + text-align: center; +} + +.quick-links a.button:hover { + background-color: #f0f0f0; + border-color: #999; + color: #333; +} + +.quick-links span.button.disabled { + background-color: #eee; + color: #aaa; + cursor: not-allowed; +} + +/* Statistics Widget */ +.statistics p { + margin: 0 0 10px 0; + font-size: 0.95em; +} + +.statistics strong { + margin-right: 5px; +} + +/* Recent Activity Widget */ +.recent-activity .activity-section { + margin-bottom: 15px; +} + +.recent-activity ul { + list-style: none; + margin: 0 0 10px 0; + padding: 0; + font-size: 0.9em; + color: #333; +} + +.recent-activity li { + padding: 5px 0; + border-bottom: 1px dotted #eee; + margin: 0; +} + +.recent-activity li:last-child { + border-bottom: none; +} + +.recent-activity strong { + color: #0073aa; +} + +.recent-activity em { + color: #555; +} + diff --git a/template-quiztech-dashboard.php b/template-quiztech-dashboard.php index 6d0e832..628763a 100644 --- a/template-quiztech-dashboard.php +++ b/template-quiztech-dashboard.php @@ -29,8 +29,100 @@ get_header(); ?>
-

- + + +
+ + + + + +
+

+

+ + +

+

+ + +

+
+ + +
+

+ +
+

+ +
    + +
  • + created_at))); ?> - + ' . esc_html($invitation->applicant_email) . '', + '' . esc_html($invitation->job_title ?: __('N/A', 'quiztech')) . '' + ); ?> +
  • + +
+ +

+ +
+ +
+

+ +
    + +
  • + - + ' . esc_html($completion['applicant_email']) . '', + '' . esc_html($completion['job_title'] ?: __('N/A', 'quiztech')) . '' + ); ?> + ">(View) */ ?> +
  • + +
+ +

+ +
+
+ +
+