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