rl-warmup-plugin/js/dashboard-modal.js
ruben e251e7fe24 Fix JavaScript error in dashboard modal
- Changed $steps variable from const to let to allow reassignment
- Added new modal styling and AJAX form handlers
- Fixed campaign form JavaScript

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
2025-03-07 07:34:04 -06:00

484 lines
No EOL
20 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Dashboard Modal & Multi-step Form Handlers
*/
jQuery(document).ready(function($) {
// Modal elements
const $fabButton = $('.mf-floating-action-button');
const $modalOverlay = $('.mf-modal-overlay');
const $modalContainer = $('.mf-modal-container');
const $modalClose = $('.mf-modal-close');
const $backBtn = $('.mf-back-btn');
const $nextBtn = $('.mf-next-btn');
// Step indicators
const $stepDots = $('.mf-step-dot');
let $steps = $('.mf-step');
// Selection buttons
const $selectionButtons = $('.mf-selection-button');
// Current step and selected type
let currentStep = 0;
let selectedType = '';
let domainData = {
domain: '',
isValid: false,
usesCloudFlare: false,
cloudflareZoneId: '',
cloudflareEmail: '',
cloudflareKey: '',
hasMX: false,
configureMailferno: false,
emailAccounts: []
};
// Open Modal
$fabButton.on('click', function() {
resetForm();
$modalOverlay.addClass('active');
});
// Close Modal
$modalClose.on('click', closeModal);
$modalOverlay.on('click', function(e) {
if (e.target === this) {
closeModal();
}
});
function closeModal() {
$modalOverlay.removeClass('active');
resetForm();
}
// Reset Form
function resetForm() {
currentStep = 0;
selectedType = '';
domainData = {
domain: '',
isValid: false,
usesCloudFlare: false,
cloudflareZoneId: '',
cloudflareEmail: '',
cloudflareKey: '',
hasMX: false,
configureMailferno: false,
emailAccounts: []
};
$selectionButtons.removeClass('selected');
updateStepIndicators();
showCurrentStep();
$('.mf-validation-error').hide();
$('.mf-success-message, .mf-error-message').remove();
$('.mf-loading').hide();
$('#mf-domain-input').val('');
$('#mf-cloudflare-email').val('');
$('#mf-cloudflare-key').val('');
$('.mf-mx-option').removeClass('selected');
$('.mf-email-row:not(:first)').remove();
$('.mf-email-row input').val('');
}
// Selection buttons
$selectionButtons.on('click', function() {
$selectionButtons.removeClass('selected');
$(this).addClass('selected');
selectedType = $(this).data('type');
$nextBtn.removeClass('disabled');
});
// Navigation buttons
$backBtn.on('click', function() {
if (currentStep > 0) {
currentStep--;
updateStepIndicators();
showCurrentStep();
}
});
$nextBtn.on('click', function() {
if ($(this).hasClass('disabled')) return;
// Handle first step (selection)
if (currentStep === 0) {
if (!selectedType) {
alert('Please select an option to continue');
return;
}
// Set up next steps based on selection
setupStepsByType(selectedType);
currentStep++;
updateStepIndicators();
showCurrentStep();
return;
}
// Domain specific step handling
if (selectedType === 'domain') {
const result = handleDomainStep(currentStep);
if (!result) return; // If step validation fails, don't proceed
}
// If we reach here, move to next step
currentStep++;
updateStepIndicators();
showCurrentStep();
});
// Update step indicators
function updateStepIndicators() {
$stepDots.removeClass('active completed');
// Update for current setup
$stepDots.each(function(index) {
if (index < currentStep) {
$(this).addClass('completed');
} else if (index === currentStep) {
$(this).addClass('active');
}
});
// Update back button visibility
if (currentStep === 0) {
$backBtn.hide();
} else {
$backBtn.show();
}
// Update next button text
const isLastStep = (currentStep === $steps.length - 1);
$nextBtn.text(isLastStep ? 'Next' : 'Next');
// When on selection step, disable next until selection made
if (currentStep === 0) {
$nextBtn.toggleClass('disabled', !selectedType);
} else {
$nextBtn.removeClass('disabled');
}
}
// Show current step
function showCurrentStep() {
$steps.removeClass('active');
$steps.eq(currentStep).addClass('active');
}
// Setup steps by selected type
function setupStepsByType(type) {
// Hide all steps except the first one
$steps.not(':first').remove();
// Clear step indicators
$('.mf-steps-indicator').empty();
let stepCount = 1; // Selection step
if (type === 'domain') {
// Step 1: Input domain
$('<div class="mf-step">')
.append('<h3>Enter Domain Name</h3>')
.append('<div class="mf-form-field"><label for="mf-domain-input">Domain Name</label><input type="text" id="mf-domain-input" placeholder="example.com"><div class="mf-validation-error" id="domain-validation-error">Please enter a valid domain name</div></div>')
.append('<div class="mf-loading" style="display:none;"><div class="mf-loading-spinner"></div><p>Validating domain...</p></div>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
// Step 2: CloudFlare verification
$('<div class="mf-step">')
.append('<h3>Verify CloudFlare Connection</h3>')
.append('<div class="mf-form-field"><label for="mf-cloudflare-email">CloudFlare Email</label><input type="email" id="mf-cloudflare-email" placeholder="your@email.com"></div>')
.append('<div class="mf-form-field"><label for="mf-cloudflare-key">CloudFlare API Key</label><input type="password" id="mf-cloudflare-key" placeholder="Your API key"></div>')
.append('<div class="mf-validation-error" id="cloudflare-validation-error">Please enter valid CloudFlare credentials</div>')
.append('<div class="mf-loading" style="display:none;"><div class="mf-loading-spinner"></div><p>Verifying CloudFlare credentials...</p></div>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
// Step 3: MX Configuration
$('<div class="mf-step">')
.append('<h3>Email Server Configuration</h3>')
.append('<p>How would you like to configure email for this domain?</p>')
.append('<div class="mf-mx-options"><div class="mf-mx-option" data-option="mailferno"><h4>Use Mailferno MX Server</h4><p>Configure this domain to use Mailferno\'s email server. Best if this is a new domain not currently used for email.</p></div><div class="mf-mx-option" data-option="existing"><h4>Keep Existing Configuration</h4><p>Keep your current email server configuration. Best if this domain is already being used for email.</p></div></div>')
.append('<div class="mf-validation-error" id="mx-validation-error">Please select an MX configuration option</div>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
// Step 4: Email accounts
$('<div class="mf-step">')
.append('<h3>Add Email Accounts</h3>')
.append('<p>Would you like to create email accounts for this domain now?</p>')
.append('<div class="mf-email-list"><div class="mf-email-row"><input type="text" class="mf-email-local" placeholder="username"><span>@'+domainData.domain+'</span><button type="button" class="mf-remove-email-btn">×</button></div></div>')
.append('<button type="button" class="mf-add-email-btn">+ Add Another Email</button>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
// Final step
$('<div class="mf-step">')
.append('<h3>Domain Setup Complete</h3>')
.append('<div class="mf-success-message">Your domain has been successfully added to Mailferno!</div>')
.append('<p>You can now continue to manage your domain, email accounts, and campaigns from the dashboard.</p>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
} else if (type === 'campaign') {
// Add campaign specific steps
$('<div class="mf-step">')
.append('<h3>Create Campaign</h3>')
.append('<p>Campaign creation functionality will be implemented here.</p>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
// Final step
$('<div class="mf-step">')
.append('<h3>Campaign Created</h3>')
.append('<div class="mf-success-message">Your campaign has been successfully created!</div>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
} else if (type === 'email') {
// Add email account specific steps
$('<div class="mf-step">')
.append('<h3>Create Email Account</h3>')
.append('<p>Email account creation functionality will be implemented here.</p>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
// Final step
$('<div class="mf-step">')
.append('<h3>Email Account Created</h3>')
.append('<div class="mf-success-message">Your email account has been successfully created!</div>')
.appendTo($modalContainer.find('.mf-modal-body'));
stepCount++;
}
// Create step indicators
for (let i = 0; i < stepCount; i++) {
$('<div class="mf-step-dot">')
.addClass(i === 0 ? 'completed' : (i === 1 ? 'active' : ''))
.appendTo($('.mf-steps-indicator'));
}
// Make steps accessible
$steps = $('.mf-step');
// Setup event handlers for the domain steps
if (type === 'domain') {
setupDomainStepHandlers();
}
}
// Domain step specific handlers
function setupDomainStepHandlers() {
// Step 1: Domain validation
$('#mf-domain-input').on('input', function() {
// Basic validation
const domain = $(this).val().trim();
const isValid = /^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(domain);
if (isValid) {
$('#domain-validation-error').hide();
domainData.domain = domain;
} else {
$('#domain-validation-error').show();
}
});
// Step 3: MX Configuration
$('.mf-mx-option').on('click', function() {
$('.mf-mx-option').removeClass('selected');
$(this).addClass('selected');
domainData.configureMailferno = ($(this).data('option') === 'mailferno');
});
// Step 4: Email accounts
$('.mf-add-email-btn').on('click', function() {
const $newRow = $('.mf-email-row').first().clone();
$newRow.find('input').val('');
$newRow.insertBefore($(this));
});
// Remove email button
$(document).on('click', '.mf-remove-email-btn', function() {
if ($('.mf-email-row').length > 1) {
$(this).closest('.mf-email-row').remove();
} else {
$('.mf-email-row').find('input').val('');
}
});
}
// Domain step validation and AJAX handling
function handleDomainStep(step) {
// Adjust step to match domain-specific numbering (after selection)
const domainStep = step - 1;
switch(domainStep) {
case 0: // Domain input validation
const domain = $('#mf-domain-input').val().trim();
if (!domain || !/^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/.test(domain)) {
$('#domain-validation-error').show();
return false;
}
domainData.domain = domain;
// Show loading indicator
$steps.eq(currentStep).find('.mf-loading').show();
$nextBtn.addClass('disabled');
// AJAX validation call to check if domain is valid and uses CloudFlare
$.ajax({
url: dashboard_modal_vars.ajax_url,
type: 'POST',
data: {
action: 'validate_domain',
security: dashboard_modal_vars.nonce,
domain: domain
},
success: function(response) {
$steps.eq(currentStep).find('.mf-loading').hide();
if (response.success) {
domainData.isValid = true;
domainData.usesCloudFlare = response.data.usesCloudFlare;
if (!domainData.usesCloudFlare) {
$steps.eq(currentStep).append('<div class="mf-error-message">This domain is not using CloudFlare nameservers. Please configure CloudFlare for this domain before continuing.</div>');
return;
}
// Update domain text in email step
$('.mf-email-row span').text('@' + domain);
// Continue to next step
$nextBtn.removeClass('disabled');
$nextBtn.trigger('click');
} else {
$steps.eq(currentStep).append('<div class="mf-error-message">' + response.data.message + '</div>');
$nextBtn.removeClass('disabled');
}
},
error: function() {
$steps.eq(currentStep).find('.mf-loading').hide();
$steps.eq(currentStep).append('<div class="mf-error-message">Error validating domain. Please try again.</div>');
$nextBtn.removeClass('disabled');
}
});
return false; // Prevent automatic next step - we'll handle it in AJAX callback
case 1: // CloudFlare verification
const email = $('#mf-cloudflare-email').val().trim();
const key = $('#mf-cloudflare-key').val().trim();
if (!email || !key) {
$('#cloudflare-validation-error').show();
return false;
}
domainData.cloudflareEmail = email;
domainData.cloudflareKey = key;
// Show loading indicator
$steps.eq(currentStep).find('.mf-loading').show();
$nextBtn.addClass('disabled');
// AJAX call to verify CloudFlare credentials
$.ajax({
url: dashboard_modal_vars.ajax_url,
type: 'POST',
data: {
action: 'verify_cloudflare',
security: dashboard_modal_vars.nonce,
domain: domainData.domain,
email: email,
key: key
},
success: function(response) {
$steps.eq(currentStep).find('.mf-loading').hide();
if (response.success) {
domainData.cloudflareZoneId = response.data.zoneId;
domainData.hasMX = response.data.hasMX;
// Continue to next step
$nextBtn.removeClass('disabled');
$nextBtn.trigger('click');
} else {
$steps.eq(currentStep).append('<div class="mf-error-message">' + response.data.message + '</div>');
$nextBtn.removeClass('disabled');
}
},
error: function() {
$steps.eq(currentStep).find('.mf-loading').hide();
$steps.eq(currentStep).append('<div class="mf-error-message">Error verifying CloudFlare credentials. Please try again.</div>');
$nextBtn.removeClass('disabled');
}
});
return false; // Prevent automatic next step - we'll handle it in AJAX callback
case 2: // MX Configuration
if (!$('.mf-mx-option.selected').length) {
$('#mx-validation-error').show();
return false;
}
domainData.configureMailferno = ($('.mf-mx-option.selected').data('option') === 'mailferno');
return true;
case 3: // Email accounts
domainData.emailAccounts = [];
let allValid = true;
$('.mf-email-row').each(function() {
const username = $(this).find('.mf-email-local').val().trim();
if (username) {
domainData.emailAccounts.push(username + '@' + domainData.domain);
}
});
if (allValid) {
// Create domain via AJAX
$nextBtn.addClass('disabled');
$.ajax({
url: dashboard_modal_vars.ajax_url,
type: 'POST',
data: {
action: 'create_domain',
security: dashboard_modal_vars.nonce,
domainData: JSON.stringify(domainData)
},
success: function(response) {
if (response.success) {
// Update final step
$steps.eq(currentStep + 1).find('.mf-success-message').text(response.data.message);
// Continue to next step
$nextBtn.removeClass('disabled');
$nextBtn.trigger('click');
// Reload page after a short delay to show updated dashboard
setTimeout(function() {
window.location.reload();
}, 5000);
} else {
$steps.eq(currentStep).append('<div class="mf-error-message">' + response.data.message + '</div>');
$nextBtn.removeClass('disabled');
}
},
error: function() {
$steps.eq(currentStep).append('<div class="mf-error-message">Error creating domain. Please try again.</div>');
$nextBtn.removeClass('disabled');
}
});
return false;
}
return allValid;
case 4: // Final step - just close modal
closeModal();
return true;
}
return true;
}
});