## Major Enhancements ### 🏗️ Architecture & Infrastructure - Implement comprehensive Docker testing infrastructure with hermetic environment - Add Forgejo Actions CI/CD pipeline for automated deployments - Create Page Object Model (POM) testing architecture reducing test duplication by 90% - Establish security-first development patterns with input validation and output escaping ### 🧪 Testing Framework Modernization - Migrate 146+ tests from 80 duplicate files to centralized architecture - Add comprehensive E2E test suites for all user roles and workflows - Implement WordPress error detection with automatic site health monitoring - Create robust browser lifecycle management with proper cleanup ### 📚 Documentation & Guides - Add comprehensive development best practices guide - Create detailed administrator setup documentation - Establish user guides for trainers and master trainers - Document security incident reports and migration guides ### 🔧 Core Plugin Features - Enhance trainer profile management with certification system - Improve find trainer functionality with advanced filtering - Strengthen master trainer area with content management - Add comprehensive venue and organizer management ### 🛡️ Security & Reliability - Implement security-first patterns throughout codebase - Add comprehensive input validation and output escaping - Create secure credential management system - Establish proper WordPress role-based access control ### 🎯 WordPress Integration - Strengthen singleton pattern implementation across all classes - Enhance template hierarchy with proper WordPress integration - Improve page manager with hierarchical URL structure - Add comprehensive shortcode and menu system ### 🔍 Developer Experience - Add extensive debugging and troubleshooting tools - Create comprehensive test data seeding scripts - Implement proper error handling and logging - Establish consistent code patterns and standards ### 📊 Performance & Optimization - Optimize database queries and caching strategies - Improve asset loading and script management - Enhance template rendering performance - Streamline user experience across all interfaces 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
748 lines
No EOL
26 KiB
PHP
748 lines
No EOL
26 KiB
PHP
<?php
|
|
/**
|
|
* Training Leads Management
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* HVAC_Training_Leads class
|
|
*/
|
|
class HVAC_Training_Leads {
|
|
|
|
/**
|
|
* Instance of this class
|
|
*
|
|
* @var HVAC_Training_Leads
|
|
*/
|
|
private static $instance = null;
|
|
|
|
/**
|
|
* Get instance of this class
|
|
*
|
|
* @return HVAC_Training_Leads
|
|
*/
|
|
public static function instance() {
|
|
if (null === self::$instance) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Legacy method for backwards compatibility
|
|
*
|
|
* @deprecated Use instance() instead
|
|
* @return HVAC_Training_Leads
|
|
*/
|
|
public static function get_instance() {
|
|
return self::instance();
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct() {
|
|
add_action('init', array($this, 'init_hooks'));
|
|
}
|
|
|
|
/**
|
|
* Initialize hooks
|
|
*/
|
|
public function init_hooks() {
|
|
// Register shortcode
|
|
add_shortcode('hvac_trainer_training_leads', array($this, 'render_training_leads_page'));
|
|
|
|
// AJAX handlers
|
|
add_action('wp_ajax_hvac_update_lead_status', array($this, 'ajax_update_lead_status'));
|
|
add_action('wp_ajax_hvac_mark_lead_replied', array($this, 'ajax_mark_lead_replied'));
|
|
}
|
|
|
|
/**
|
|
* Render the Training Leads page
|
|
*/
|
|
public function render_training_leads_page($atts = array()) {
|
|
if (!is_user_logged_in()) {
|
|
return '<p>Please log in to view your training leads.</p>';
|
|
}
|
|
|
|
// Check user capabilities
|
|
$user = wp_get_current_user();
|
|
if (!in_array('hvac_trainer', $user->roles) && !in_array('hvac_master_trainer', $user->roles) && !current_user_can('manage_options')) {
|
|
return '<p>You do not have permission to view this page.</p>';
|
|
}
|
|
|
|
// Get current user
|
|
$current_user = wp_get_current_user();
|
|
|
|
// Get submissions for this trainer
|
|
$submissions = $this->get_trainer_submissions($current_user->ID);
|
|
|
|
ob_start();
|
|
?>
|
|
<div class="hvac-training-leads-wrapper">
|
|
<div class="hvac-page-header">
|
|
<h1>Training Leads</h1>
|
|
<p class="hvac-page-description">Manage contact requests from potential training clients</p>
|
|
</div>
|
|
|
|
<?php if (!empty($submissions)) : ?>
|
|
<div class="hvac-leads-table-wrapper">
|
|
<table class="hvac-leads-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Name</th>
|
|
<th>Email</th>
|
|
<th>Phone</th>
|
|
<th>Location</th>
|
|
<th>Message</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($submissions as $submission) : ?>
|
|
<tr class="hvac-lead-row" data-lead-id="<?php echo esc_attr($submission->id); ?>">
|
|
<td class="hvac-lead-date">
|
|
<?php echo esc_html(date('M j, Y', strtotime($submission->submission_date))); ?>
|
|
</td>
|
|
<td class="hvac-lead-name">
|
|
<?php echo esc_html($submission->first_name . ' ' . $submission->last_name); ?>
|
|
</td>
|
|
<td class="hvac-lead-email">
|
|
<a href="mailto:<?php echo esc_attr($submission->email); ?>">
|
|
<?php echo esc_html($submission->email); ?>
|
|
</a>
|
|
</td>
|
|
<td class="hvac-lead-phone">
|
|
<?php if ($submission->phone) : ?>
|
|
<a href="tel:<?php echo esc_attr($submission->phone); ?>">
|
|
<?php echo esc_html($submission->phone); ?>
|
|
</a>
|
|
<?php else : ?>
|
|
<span class="hvac-no-data">—</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="hvac-lead-location">
|
|
<?php
|
|
$location_parts = array_filter([
|
|
$submission->city,
|
|
$submission->state_province
|
|
]);
|
|
if (!empty($location_parts)) {
|
|
echo esc_html(implode(', ', $location_parts));
|
|
} else {
|
|
echo '<span class="hvac-no-data">—</span>';
|
|
}
|
|
?>
|
|
</td>
|
|
<td class="hvac-lead-message">
|
|
<?php if ($submission->message) : ?>
|
|
<div class="hvac-message-preview" title="<?php echo esc_attr($submission->message); ?>">
|
|
<?php echo esc_html(wp_trim_words($submission->message, 8, '...')); ?>
|
|
</div>
|
|
<?php if (strlen($submission->message) > 50) : ?>
|
|
<button class="hvac-btn hvac-btn-small hvac-view-message"
|
|
data-message="<?php echo esc_attr($submission->message); ?>">
|
|
View Full
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php else : ?>
|
|
<span class="hvac-no-data">—</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="hvac-lead-status">
|
|
<span class="hvac-status-badge hvac-status-<?php echo esc_attr($submission->status); ?>">
|
|
<?php echo esc_html(ucfirst($submission->status)); ?>
|
|
</span>
|
|
</td>
|
|
<td class="hvac-lead-actions">
|
|
<div class="hvac-action-buttons">
|
|
<?php if ($submission->status === 'new') : ?>
|
|
<button class="hvac-btn hvac-btn-small hvac-mark-read"
|
|
data-lead-id="<?php echo esc_attr($submission->id); ?>">
|
|
Mark Read
|
|
</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($submission->status !== 'replied') : ?>
|
|
<button class="hvac-btn hvac-btn-small hvac-btn-success hvac-mark-replied"
|
|
data-lead-id="<?php echo esc_attr($submission->id); ?>">
|
|
Mark Replied
|
|
</button>
|
|
<?php endif; ?>
|
|
|
|
<button class="hvac-btn hvac-btn-small hvac-btn-secondary hvac-archive-lead"
|
|
data-lead-id="<?php echo esc_attr($submission->id); ?>">
|
|
Archive
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php else : ?>
|
|
<div class="hvac-no-leads">
|
|
<div class="hvac-empty-state">
|
|
<div class="hvac-empty-icon">
|
|
<span class="dashicons dashicons-email-alt"></span>
|
|
</div>
|
|
<h3>No inbound training requests</h3>
|
|
<p>When potential clients contact you through the "Find a Trainer" directory, their messages will appear here.</p>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="hvac-leads-cta">
|
|
<div class="hvac-cta-card">
|
|
<h3>Want more training leads?</h3>
|
|
<p>Share your profile with the world to attract more potential clients!</p>
|
|
<a href="<?php echo esc_url(home_url('/trainer/profile/')); ?>"
|
|
class="hvac-btn hvac-btn-primary hvac-btn-large">
|
|
Share your profile with the world!
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Message Modal -->
|
|
<div id="hvac-message-modal" class="hvac-modal" style="display: none;">
|
|
<div class="hvac-modal-content">
|
|
<div class="hvac-modal-header">
|
|
<h4>Full Message</h4>
|
|
<button class="hvac-modal-close">×</button>
|
|
</div>
|
|
<div class="hvac-modal-body">
|
|
<div id="hvac-full-message"></div>
|
|
</div>
|
|
<div class="hvac-modal-footer">
|
|
<button class="hvac-btn hvac-btn-secondary hvac-modal-close">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
jQuery(document).ready(function($) {
|
|
// Handle status updates
|
|
$('.hvac-mark-read, .hvac-mark-replied, .hvac-archive-lead').on('click', function(e) {
|
|
e.preventDefault();
|
|
|
|
var $button = $(this);
|
|
var leadId = $button.data('lead-id');
|
|
var action = '';
|
|
var newStatus = '';
|
|
|
|
if ($button.hasClass('hvac-mark-read')) {
|
|
action = 'hvac_update_lead_status';
|
|
newStatus = 'read';
|
|
} else if ($button.hasClass('hvac-mark-replied')) {
|
|
action = 'hvac_mark_lead_replied';
|
|
newStatus = 'replied';
|
|
} else if ($button.hasClass('hvac-archive-lead')) {
|
|
action = 'hvac_update_lead_status';
|
|
newStatus = 'archived';
|
|
}
|
|
|
|
$button.prop('disabled', true).text('Processing...');
|
|
|
|
$.ajax({
|
|
url: hvac_ajax.url,
|
|
type: 'POST',
|
|
data: {
|
|
action: action,
|
|
lead_id: leadId,
|
|
status: newStatus,
|
|
nonce: hvac_ajax.nonce
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
location.reload(); // Refresh to show updated status
|
|
} else {
|
|
alert('Error: ' + (response.data.message || 'Unknown error'));
|
|
$button.prop('disabled', false).text($button.hasClass('hvac-mark-read') ? 'Mark Read' :
|
|
$button.hasClass('hvac-mark-replied') ? 'Mark Replied' : 'Archive');
|
|
}
|
|
},
|
|
error: function() {
|
|
alert('Network error. Please try again.');
|
|
$button.prop('disabled', false).text($button.hasClass('hvac-mark-read') ? 'Mark Read' :
|
|
$button.hasClass('hvac-mark-replied') ? 'Mark Replied' : 'Archive');
|
|
}
|
|
});
|
|
});
|
|
|
|
// Handle message modal
|
|
$('.hvac-view-message').on('click', function(e) {
|
|
e.preventDefault();
|
|
var message = $(this).data('message');
|
|
$('#hvac-full-message').html(message.replace(/\n/g, '<br>'));
|
|
$('#hvac-message-modal').fadeIn();
|
|
});
|
|
|
|
$('.hvac-modal-close').on('click', function(e) {
|
|
e.preventDefault();
|
|
$('#hvac-message-modal').fadeOut();
|
|
});
|
|
|
|
// Close modal on outside click
|
|
$('#hvac-message-modal').on('click', function(e) {
|
|
if (e.target === this) {
|
|
$(this).fadeOut();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.hvac-training-leads-wrapper {
|
|
max-width: 1200px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
|
|
.hvac-page-header {
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.hvac-page-header h1 {
|
|
margin: 0 0 10px 0;
|
|
font-size: 28px;
|
|
color: #1d2327;
|
|
}
|
|
|
|
.hvac-page-description {
|
|
margin: 0;
|
|
color: #646970;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.hvac-leads-table-wrapper {
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
overflow: hidden;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.hvac-leads-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
.hvac-leads-table th,
|
|
.hvac-leads-table td {
|
|
padding: 12px 15px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #e5e5e5;
|
|
}
|
|
|
|
.hvac-leads-table th {
|
|
background: #f8f9fa;
|
|
font-weight: 600;
|
|
color: #1d2327;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.hvac-leads-table tbody tr:hover {
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.hvac-lead-date,
|
|
.hvac-lead-phone {
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.hvac-lead-email a,
|
|
.hvac-lead-phone a {
|
|
color: #0073aa;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.hvac-lead-email a:hover,
|
|
.hvac-lead-phone a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.hvac-message-preview {
|
|
max-width: 200px;
|
|
word-wrap: break-word;
|
|
}
|
|
|
|
.hvac-no-data {
|
|
color: #999;
|
|
font-style: italic;
|
|
}
|
|
|
|
.hvac-status-badge {
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.hvac-status-new {
|
|
background: #fff3cd;
|
|
color: #856404;
|
|
}
|
|
|
|
.hvac-status-read {
|
|
background: #d1ecf1;
|
|
color: #0c5460;
|
|
}
|
|
|
|
.hvac-status-replied {
|
|
background: #d4edda;
|
|
color: #155724;
|
|
}
|
|
|
|
.hvac-status-archived {
|
|
background: #f8d7da;
|
|
color: #721c24;
|
|
}
|
|
|
|
.hvac-action-buttons {
|
|
display: flex;
|
|
gap: 8px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.hvac-btn {
|
|
padding: 6px 12px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
text-decoration: none;
|
|
display: inline-block;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
text-align: center;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.hvac-btn-small {
|
|
padding: 4px 8px;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.hvac-btn-large {
|
|
padding: 12px 24px;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.hvac-btn-primary {
|
|
background: #0073aa;
|
|
color: #fff;
|
|
}
|
|
|
|
.hvac-btn-primary:hover {
|
|
background: #005a87;
|
|
color: #fff;
|
|
}
|
|
|
|
.hvac-btn-success {
|
|
background: #28a745;
|
|
color: #fff;
|
|
}
|
|
|
|
.hvac-btn-success:hover {
|
|
background: #218838;
|
|
color: #fff;
|
|
}
|
|
|
|
.hvac-btn-secondary {
|
|
background: #6c757d;
|
|
color: #fff;
|
|
}
|
|
|
|
.hvac-btn-secondary:hover {
|
|
background: #545b62;
|
|
color: #fff;
|
|
}
|
|
|
|
.hvac-no-leads {
|
|
text-align: center;
|
|
padding: 60px 20px;
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.hvac-empty-icon {
|
|
font-size: 48px;
|
|
color: #c3c4c7;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.hvac-empty-state h3 {
|
|
margin: 0 0 10px 0;
|
|
color: #1d2327;
|
|
font-size: 20px;
|
|
}
|
|
|
|
.hvac-empty-state p {
|
|
margin: 0;
|
|
color: #646970;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.hvac-leads-cta {
|
|
text-align: center;
|
|
}
|
|
|
|
.hvac-cta-card {
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
color: #fff;
|
|
padding: 40px 30px;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
|
}
|
|
|
|
.hvac-cta-card h3 {
|
|
margin: 0 0 10px 0;
|
|
font-size: 24px;
|
|
}
|
|
|
|
.hvac-cta-card p {
|
|
margin: 0 0 20px 0;
|
|
font-size: 16px;
|
|
opacity: 0.9;
|
|
}
|
|
|
|
.hvac-cta-card .hvac-btn-primary {
|
|
background: #fff;
|
|
color: #667eea;
|
|
border: none;
|
|
}
|
|
|
|
.hvac-cta-card .hvac-btn-primary:hover {
|
|
background: #f8f9fa;
|
|
color: #667eea;
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
/* Modal styles */
|
|
.hvac-modal {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0,0,0,0.5);
|
|
z-index: 9999;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.hvac-modal-content {
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
|
max-width: 500px;
|
|
width: 90%;
|
|
max-height: 80vh;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.hvac-modal-header {
|
|
padding: 20px 25px;
|
|
border-bottom: 1px solid #e5e5e5;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.hvac-modal-header h4 {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
color: #1d2327;
|
|
}
|
|
|
|
.hvac-modal-close {
|
|
background: none;
|
|
border: none;
|
|
font-size: 24px;
|
|
cursor: pointer;
|
|
color: #646970;
|
|
padding: 0;
|
|
width: 30px;
|
|
height: 30px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.hvac-modal-close:hover {
|
|
color: #1d2327;
|
|
}
|
|
|
|
.hvac-modal-body {
|
|
padding: 25px;
|
|
max-height: 400px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.hvac-modal-footer {
|
|
padding: 20px 25px;
|
|
border-top: 1px solid #e5e5e5;
|
|
text-align: right;
|
|
}
|
|
|
|
/* Responsive design */
|
|
@media (max-width: 1200px) {
|
|
.hvac-training-leads-wrapper {
|
|
padding: 15px;
|
|
}
|
|
|
|
.hvac-leads-table-wrapper {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.hvac-leads-table {
|
|
min-width: 800px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.hvac-page-header h1 {
|
|
font-size: 24px;
|
|
}
|
|
|
|
.hvac-leads-table th,
|
|
.hvac-leads-table td {
|
|
padding: 8px 12px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.hvac-action-buttons {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.hvac-cta-card {
|
|
padding: 30px 20px;
|
|
}
|
|
|
|
.hvac-cta-card h3 {
|
|
font-size: 20px;
|
|
}
|
|
}
|
|
</style>
|
|
<?php
|
|
|
|
return ob_get_clean();
|
|
}
|
|
|
|
/**
|
|
* Get contact submissions for a specific trainer
|
|
*/
|
|
private function get_trainer_submissions($trainer_id) {
|
|
if (!class_exists('HVAC_Contact_Submissions_Table')) {
|
|
require_once HVAC_PLUGIN_DIR . 'includes/database/class-hvac-contact-submissions-table.php';
|
|
}
|
|
|
|
return HVAC_Contact_Submissions_Table::get_submissions([
|
|
'trainer_id' => $trainer_id,
|
|
'limit' => 100,
|
|
'orderby' => 'submission_date',
|
|
'order' => 'DESC'
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* AJAX handler to update lead status
|
|
*/
|
|
public function ajax_update_lead_status() {
|
|
check_ajax_referer('hvac_ajax_nonce', 'nonce');
|
|
|
|
$user = wp_get_current_user();
|
|
if (!is_user_logged_in() || (!in_array('hvac_trainer', $user->roles) && !in_array('hvac_master_trainer', $user->roles) && !current_user_can('manage_options'))) {
|
|
wp_send_json_error(['message' => 'Unauthorized']);
|
|
}
|
|
|
|
$lead_id = isset($_POST['lead_id']) ? absint($_POST['lead_id']) : 0;
|
|
$status = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : '';
|
|
|
|
if (!$lead_id || !$status) {
|
|
wp_send_json_error(['message' => 'Invalid parameters']);
|
|
}
|
|
|
|
// Verify the lead belongs to the current user
|
|
if (!$this->verify_lead_ownership($lead_id, get_current_user_id())) {
|
|
wp_send_json_error(['message' => 'Access denied']);
|
|
}
|
|
|
|
if (!class_exists('HVAC_Contact_Submissions_Table')) {
|
|
require_once HVAC_PLUGIN_DIR . 'includes/database/class-hvac-contact-submissions-table.php';
|
|
}
|
|
|
|
$result = HVAC_Contact_Submissions_Table::update_status($lead_id, $status);
|
|
|
|
if ($result) {
|
|
wp_send_json_success(['message' => 'Status updated successfully']);
|
|
} else {
|
|
wp_send_json_error(['message' => 'Failed to update status']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* AJAX handler to mark lead as replied
|
|
*/
|
|
public function ajax_mark_lead_replied() {
|
|
check_ajax_referer('hvac_ajax_nonce', 'nonce');
|
|
|
|
$user = wp_get_current_user();
|
|
if (!is_user_logged_in() || (!in_array('hvac_trainer', $user->roles) && !in_array('hvac_master_trainer', $user->roles) && !current_user_can('manage_options'))) {
|
|
wp_send_json_error(['message' => 'Unauthorized']);
|
|
}
|
|
|
|
$lead_id = isset($_POST['lead_id']) ? absint($_POST['lead_id']) : 0;
|
|
|
|
if (!$lead_id) {
|
|
wp_send_json_error(['message' => 'Invalid lead ID']);
|
|
}
|
|
|
|
// Verify the lead belongs to the current user
|
|
if (!$this->verify_lead_ownership($lead_id, get_current_user_id())) {
|
|
wp_send_json_error(['message' => 'Access denied']);
|
|
}
|
|
|
|
if (!class_exists('HVAC_Contact_Submissions_Table')) {
|
|
require_once HVAC_PLUGIN_DIR . 'includes/database/class-hvac-contact-submissions-table.php';
|
|
}
|
|
|
|
$result = HVAC_Contact_Submissions_Table::update_status($lead_id, 'replied');
|
|
|
|
if ($result) {
|
|
wp_send_json_success(['message' => 'Lead marked as replied']);
|
|
} else {
|
|
wp_send_json_error(['message' => 'Failed to update status']);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Verify that a lead belongs to the current user
|
|
*/
|
|
private function verify_lead_ownership($lead_id, $user_id) {
|
|
if (!class_exists('HVAC_Contact_Submissions_Table')) {
|
|
require_once HVAC_PLUGIN_DIR . 'includes/database/class-hvac-contact-submissions-table.php';
|
|
}
|
|
|
|
$submission = HVAC_Contact_Submissions_Table::get_submission($lead_id);
|
|
|
|
return $submission && $submission->trainer_id == $user_id;
|
|
}
|
|
}
|
|
|
|
// Initialize the class
|
|
HVAC_Training_Leads::get_instance();
|