Initial dashboard widgets

This commit is contained in:
Ruben Ramirez 2025-04-04 09:17:41 -05:00
parent c0687c652b
commit 0124c0fa85
3 changed files with 349 additions and 2 deletions

View file

@ -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)

111
style.css
View file

@ -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;
}

View file

@ -29,8 +29,100 @@ get_header(); ?>
</header><!-- .entry-header -->
<div class="entry-content">
<p><?php esc_html_e( 'Welcome to the Quiztech Dashboard. Placeholder content.', 'quiztech' ); ?></p>
<!-- Add dashboard widgets, summaries, links here -->
<?php
// Fetch dashboard data using helper functions
$quick_links = function_exists('quiztech_get_dashboard_quick_links') ? quiztech_get_dashboard_quick_links() : [];
$recent_invitations = function_exists('quiztech_get_dashboard_recent_invitations') ? quiztech_get_dashboard_recent_invitations() : [];
$recent_completions = function_exists('quiztech_get_dashboard_recent_completions') ? quiztech_get_dashboard_recent_completions() : [];
$active_job_count = function_exists('quiztech_get_dashboard_active_job_count') ? quiztech_get_dashboard_active_job_count() : 0;
$credit_balance = ( function_exists('\Quiztech\AssessmentPlatform\Includes\quiztech_get_user_credit_balance') && is_user_logged_in() ) // Correct function name and namespace check
? \Quiztech\AssessmentPlatform\Includes\quiztech_get_user_credit_balance( get_current_user_id() ) // Correct function call
: __('N/A', 'quiztech');
?>
<div class="quiztech-dashboard-widgets">
<!-- Quick Links Widget -->
<div class="dashboard-widget quick-links">
<h2><?php esc_html_e('Quick Links', 'quiztech'); ?></h2>
<?php if (!empty($quick_links)) : ?>
<ul>
<?php foreach ($quick_links as $label => $url) : ?>
<?php if (!empty($url)) : ?>
<li><a href="<?php echo esc_url($url); ?>" class="button"><?php echo esc_html($label); ?></a></li>
<?php else : ?>
<li><span class="button disabled"><?php echo esc_html($label); ?> (<?php esc_html_e('Page not found', 'quiztech'); ?>)</span></li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
<?php else : ?>
<p><?php esc_html_e('Quick links could not be loaded.', 'quiztech'); ?></p>
<?php endif; ?>
</div>
<!-- Statistics Widget -->
<div class="dashboard-widget statistics">
<h2><?php esc_html_e('Statistics', 'quiztech'); ?></h2>
<p>
<strong><?php esc_html_e('Active Jobs:', 'quiztech'); ?></strong>
<?php echo esc_html($active_job_count); ?>
</p>
<p>
<strong><?php esc_html_e('Credits Remaining:', 'quiztech'); ?></strong>
<?php echo esc_html($credit_balance); ?>
</p>
</div>
<!-- Recent Activity Widget -->
<div class="dashboard-widget recent-activity">
<h2><?php esc_html_e('Recent Activity', 'quiztech'); ?></h2>
<div class="activity-section">
<h3><?php esc_html_e('Invitations Sent', 'quiztech'); ?></h3>
<?php if (!empty($recent_invitations)) : ?>
<ul>
<?php foreach ($recent_invitations as $invitation) : ?>
<li>
<?php echo esc_html(gmdate('Y-m-d', strtotime($invitation->created_at))); ?> -
<?php printf(
/* translators: 1: Applicant Email, 2: Job Title */
esc_html__('Invited %1$s for %2$s', 'quiztech'),
'<strong>' . esc_html($invitation->applicant_email) . '</strong>',
'<em>' . esc_html($invitation->job_title ?: __('N/A', 'quiztech')) . '</em>'
); ?>
</li>
<?php endforeach; ?>
</ul>
<?php else : ?>
<p><?php esc_html_e('No recent invitations found.', 'quiztech'); ?></p>
<?php endif; ?>
</div>
<div class="activity-section">
<h3><?php esc_html_e('Assessments Completed', 'quiztech'); ?></h3>
<?php if (!empty($recent_completions)) : ?>
<ul>
<?php foreach ($recent_completions as $completion) : ?>
<li>
<?php echo esc_html(gmdate('Y-m-d', strtotime($completion['completion_date']))); ?> -
<?php printf(
/* translators: 1: Applicant Email, 2: Job Title */
esc_html__('%1$s completed assessment for %2$s', 'quiztech'),
'<strong>' . esc_html($completion['applicant_email']) . '</strong>',
'<em>' . esc_html($completion['job_title'] ?: __('N/A', 'quiztech')) . '</em>'
); ?>
<?php /* <a href="<?php echo esc_url(get_edit_post_link($completion['evaluation_id'])); ?>">(View)</a> */ ?>
</li>
<?php endforeach; ?>
</ul>
<?php else : ?>
<p><?php esc_html_e('No recent completions found.', 'quiztech'); ?></p>
<?php endif; ?>
</div>
</div>
</div> <!-- .quiztech-dashboard-widgets -->
</div><!-- .entry-content -->
</article><!-- #post-<?php the_ID(); ?> -->