1jQuery(document).ready(function ($) { 2 // Define ajaxurl locally if it's not defined globally 3 const ajaxurl = window.ajaxurl || (typeof onboarding_ajax_object !== 'undefined' ? onboarding_ajax_object.ajax_url : ''); 4 const ajax_nonce = typeof onboarding_ajax_object !== 'undefined' ? onboarding_ajax_object.nonce : ''; 5 6 // Initialize Swiper (if swiper container is present on the page) 7 if ($('.mera-swiper').length > 0 && typeof Swiper !== 'undefined') { 8 var swiper = new Swiper(".mera-swiper", { 9 loop: true, 10 autoplay: { delay: 3500 }, 11 pagination: { el: ".swiper-pagination", clickable: true }, 12 effect: "slide", 13 speed: 900 14 }); 15 } 16 17 // Step state tracking 18 // 0 = Email Step (.sec0) 19 // 1 = OTP Step (.sec1) 20 // 2 = Company/Profile Wizard (.sec2) 21 // 3 = Set Password (.sec6) 22 let currentStep = 0; 23 24 // Sub-steps inside Step 2 (Wizard panes 1, 2, 3, 4, 5) 25 let activePane = 1; 26 const maxPane = 5; 27 28 // Cookie Utilities 29 function setCookie(name, value, days) { 30 if (!value) return; 31 const d = new Date(); 32 d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000)); 33 document.cookie = name + "=" + encodeURIComponent(value) + ";expires=" + d.toUTCString() + ";path=/"; 34 } 35 36 function getCookie(name) { 37 let nameEQ = name + "="; 38 let ca = document.cookie.split(';'); 39 for (let i = 0; i < ca.length; i++) { 40 let c = ca[i].trim(); 41 if (c.indexOf(nameEQ) == 0) return decodeURIComponent(c.substring(nameEQ.length)); 42 } 43 return null; 44 } 45 46 function deleteCookie(name) { 47 document.cookie = name + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; 48 } 49 50 // Safe Storage Utilities 51 function getOnboardingEmail() { 52 let email = ''; 53 try { 54 email = localStorage.getItem('onboarding_email') || ''; 55 } catch (e) {} 56 if (!email) { 57 email = getCookie('onboarding_email') || ''; 58 } 59 return email; 60 } 61 62 function setOnboardingEmail(email) { 63 try { 64 localStorage.setItem('onboarding_email', email); 65 } catch (e) {} 66 setCookie('onboarding_email', email, 30); 67 } 68 69 function removeOnboardingEmail() { 70 try { 71 localStorage.removeItem('onboarding_email'); 72 } catch (e) {} 73 deleteCookie('onboarding_email'); 74 } 75 76 // Parse URL parameter 77 function getURLParameter(name) { 78 let params = new URLSearchParams(window.location.search); 79 return params.get(name); 80 } 81 82 // Handle Campaign Cookies 83 const hostname = window.location.hostname; 84 if (hostname.includes('mera.work') || hostname.includes('meramonitor.com') || hostname.includes('localhost') || hostname.includes('127.0.0.1')) { 85 let utmSource = getURLParameter('utmSource') || getURLParameter('utm_source'); 86 let utmMedium = getURLParameter('utmMedium') || getURLParameter('utm_medium'); 87 let partnerCode = getURLParameter('partnerCode') || getURLParameter('partner_code'); 88 89 if (partnerCode) setCookie('campPartnerCode', partnerCode, 30); 90 if (utmSource) setCookie('campUtmSource', utmSource, 30); 91 if (utmMedium) setCookie('campUtmMedium', utmMedium, 30); 92 93 // Fallback default 94 if (!utmSource && !getCookie('campUtmSource')) { 95 setCookie('campUtmSource', 'SEO', 2); 96 } 97 } 98 99 // Populate hidden source fields for all forms 100 let storedSource = getCookie('campUtmSource') || getCookie('utm_source'); 101 if (storedSource) { 102 $('[id="utm_source"]').val(storedSource); 103 } 104 105 // Restore email from safe storage for all forms 106 var savedEmail = getOnboardingEmail(); 107 if (savedEmail) { 108 $('[id="emailaddress"]').text(savedEmail); 109 $('[id="emailsignup"]').val(savedEmail); 110 } 111 112 // Restore wizard state for all forms 113 try { 114 if (localStorage.getItem('wizard-company')) $('[id="company"]').val(localStorage.getItem('wizard-company')); 115 if (localStorage.getItem('wizard-name')) $('[id="fullname"]').val(localStorage.getItem('wizard-name')); 116 if (localStorage.getItem('wizard-phone')) $('[id="phone"]').val(localStorage.getItem('wizard-phone')); 117 if (localStorage.getItem('wizard-country')) $('[id="country"]').val(localStorage.getItem('wizard-country')); 118 } catch (e) {} 119 120 // STEP TRANSITION UTILITY 121 function showFormStep(stepIdx, context) { 122 currentStep = stepIdx; 123 const parent = context || $('.onboarding-container'); 124 125 // Hide all major wrappers inside this container 126 parent.find('.sec0, .sec1, .sec2, .sec6').removeClass('active-step').hide(); 127 128 // Dynamically hide/show any independent SSO widgets/divs on the page when moving past Step 0 129 if (stepIdx > 0) { 130 $('.sso-only-wrapper, .sso-divider, .google-micro').hide(); 131 } else { 132 $('.sso-only-wrapper, .sso-divider, .google-micro').show(); 133 } 134 135 // Dynamically handle column and widget layouts (Elementor, Gutenberg, etc.) to make Step 1+ full screen 136 const widget = parent.closest('.elementor-widget, .wp-block, [class*="widget"]'); 137 const column = parent.closest('.elementor-column, .wp-block-column, .vc_column_container, [class*="column"], [class*="col-"]'); 138 139 if (stepIdx > 0) { 140 if (widget.length) { 141 // Find the top-most column to clean up the entire layout 142 const topColumns = parent.parents('.elementor-column, .wp-block-column'); 143 const mainColumn = topColumns.length ? $(topColumns[topColumns.length - 1]) : column; 144 145 mainColumn.find('.elementor-widget, .elementor-inner-section, .wp-block-heading, .wp-block-paragraph').each(function() { 146 // Hide if it does not contain our form and is not the widget itself 147 if (!$.contains(this, parent[0]) && this !== widget[0]) { 148 $(this).addClass('onboarding-hidden-step').hide(); 149 } 150 }); 151 widget.css({ 152 'background': 'transparent', 153 'background-color': 'transparent', 154 'box-shadow': 'none', 155 'border': 'none', 156 'padding': '0' 157 }); 158 } 159 if (column.length) { 160 column.siblings().hide(); 161 column.css({ 162 'width': '100%', 163 'max-width': '100%', 164 'flex': '0 0 100%', 165 'background': 'transparent', 166 'background-color': 'transparent', 167 'box-shadow': 'none', 168 'border': 'none', 169 'padding': '0' 170 }); 171 } 172 parent.find('.onboarding-logo-wrapper').show(); 173 parent.addClass('onboarding-card-layout'); 174 } else { 175 if (widget.length) { 176 const topColumns = parent.parents('.elementor-column, .wp-block-column'); 177 const mainColumn = topColumns.length ? $(topColumns[topColumns.length - 1]) : column; 178 179 mainColumn.find('.onboarding-hidden-step').removeClass('onboarding-hidden-step').show(); 180 widget.css({ 181 'background': '', 182 'background-color': '', 183 'box-shadow': '', 184 'border': '', 185 'padding': '' 186 }); 187 } 188 if (column.length) { 189 column.siblings().show(); 190 column.css({ 191 'width': '', 192 'max-width': '', 193 'flex': '', 194 'background': '', 195 'background-color': '', 196 'box-shadow': '', 197 'border': '', 198 'padding': '' 199 }); 200 } 201 parent.find('.onboarding-logo-wrapper').hide(); 202 parent.removeClass('onboarding-card-layout'); 203 } 204 205 if (stepIdx === 0) { 206 parent.find('.sec0').addClass('active-step').show(); 207 } else if (stepIdx === 1) { 208 parent.find('.sec1').addClass('active-step').show(); 209 } else if (stepIdx === 2) { 210 parent.find('.sec2').addClass('active-step').show(); 211 showWizardPane(activePane, parent); 212 } else if (stepIdx === 3) { 213 parent.find('.sec6').addClass('active-step').show(); 214 } 215 } 216 217 // WIZARD PANES HANDLING (INSIDE STEP 2 / .sec2) 218 function showWizardPane(n, context) { 219 activePane = n; 220 const parent = context || $('.onboarding-container'); 221 222 // Hide all panes 223 parent.find('.onboarding-pane, .pane').addClass('hidden').removeClass('show').attr('aria-hidden', 'true'); 224 225 // Show pane 226 const targetPane = parent.find('#onboarding-step-' + n).length ? parent.find('#onboarding-step-' + n) : parent.find('#step-' + n); 227 targetPane.removeClass('hidden').addClass('show').attr('aria-hidden', 'false'); 228 229 // Update progress bar width and indicators 230 updateOnboardingProgress(n, parent); 231 232 // Actions visibility 233 if (n === 1) { 234 parent.find('#backBtn').hide(); 235 } else { 236 parent.find('#backBtn').show(); 237 } 238 239 const topProgress = parent.find('.top-progress, #progress-bar-container'); 240 if (n === 4 || n === 5) { 241 topProgress.hide(); 242 parent.find('.actions').hide(); 243 } else { 244 topProgress.show(); 245 parent.find('.actions').show(); 246 } 247 248 if (n === 4) {
249 parent.find('#nextBtn').text('Finish'); 250 } else { 251 parent.find('#nextBtn').text('Continue'); 252 } 253 254 validateCurrentPane(parent); 255 focusFirstField(parent); 256 } 257 258 function updateOnboardingProgress(paneIdx, parent) { 259 const parentContainer = parent || $('.onboarding-container'); 260 const progressBar = parentContainer.find('#progress-bar')[0]; 261 if (!progressBar) return; 262 263 // Pane 1 = 25%, Pane 2 = 50%, Pane 3 = 75%, Pane 4 = 100% 264 const widthPercent = Math.min((paneIdx / 4) * 100, 100); 265 progressBar.style.width = widthPercent + '%'; 266 267 for (let i = 1; i <= 4; i++) { 268 const indicator = parentContainer.find('#dot-' + i); 269 if (indicator.length) { 270 indicator.removeClass('active completed'); 271 if (i < paneIdx) { 272 indicator.addClass('completed'); 273 } else if (i === paneIdx) { 274 indicator.addClass('active'); 275 } 276 } 277 } 278 } 279 280 function focusFirstField(parent) { 281 const parentContainer = parent || $('.onboarding-container'); 282 setTimeout(() => { 283 if (activePane === 1) parentContainer.find('#company').focus(); 284 if (activePane === 2) parentContainer.find('#fullname').focus(); 285 if (activePane === 3) parentContainer.find('#phone').focus(); 286 }, 120); 287 } 288 289 function validateCurrentPane(parent) { 290 const parentContainer = parent || $('.onboarding-container'); 291 let isValid = false; 292 if (activePane === 1) { 293 isValid = parentContainer.find('#company').val().trim().length > 0; 294 } else if (activePane === 2) { 295 isValid = parentContainer.find('#fullname').val().trim().length > 0; 296 } else if (activePane === 3) { 297 const phoneVal = parentContainer.find('#phone').val().replace(/\D/g, ''); 298 const cc = parentContainer.find('#country').val(); 299 let minLen = 6; 300 if (cc === '+91' || cc === '+1' || cc === '+44') minLen = 10; 301 if (cc === '+61') minLen = 9; 302 isValid = phoneVal.length >= minLen; 303 } else if (activePane === 4 || activePane === 5) { 304 isValid = true; 305 } 306 307 toggleNextBtn(isValid, parentContainer); 308 } 309 310 function toggleNextBtn(enable, parent) { 311 const parentContainer = parent || $('.onboarding-container'); 312 const nextBtn = parentContainer.find('#nextBtn'); 313 if (enable) { 314 nextBtn.removeClass('disabled').removeAttr('aria-disabled').prop('disabled', false); 315 } else { 316 nextBtn.addClass('disabled').attr('aria-disabled', 'true').prop('disabled', true); 317 } 318 } 319 320 // Real-time wizard input tracking 321 $(document).on('input change', '#company, #fullname, #phone, #country', function () { 322 const onboardingContainer = $(this).closest('.onboarding-container'); 323 try { 324 localStorage.setItem('wizard-company', onboardingContainer.find('#company').val()); 325 localStorage.setItem('wizard-name', onboardingContainer.find('#fullname').val()); 326 localStorage.setItem('wizard-phone', onboardingContainer.find('#phone').val()); 327 localStorage.setItem('wizard-country', onboardingContainer.find('#country').val()); 328 } catch (e) {} 329 validateCurrentPane(onboardingContainer); 330 }); 331 332 // Format Phone input formatting (groups of digits) 333 $(document).on('input', '#phone', function (e) { 334 const onboardingContainer = $(this).closest('.onboarding-container'); 335 const raw = e.target.value.replace(/[^\d]/g, ''); 336 if (raw.length <= 3) { 337 e.target.value = raw; 338 } else if (raw.length <= 6) { 339 e.target.value = raw.slice(0, 3) + ' ' + raw.slice(3); 340 } else if (raw.length <= 10) { 341 e.target.value = raw.slice(0, 3) + ' ' + raw.slice(3, 6) + '-' + raw.slice(6); 342 } else { 343 e.target.value = raw; 344 } 345 validateCurrentPane(onboardingContainer); 346 }); 347 348 // STEP 0: EMAIL SIGNUP ACTION 349 function validateEmail(emailVal) { 350 const trimmed = emailVal.trim(); 351 if (trimmed === '') return 'Email is required.'; 352 const pattern = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/; 353 if (!pattern.test(trimmed)) return 'Please enter a valid email address.'; 354 return null; 355 } 356 357 $(document).on('click', '#email_submit', function (e) { 358 e.preventDefault(); 359 const onboardingContainer = $(this).closest('.onboarding-container'); 360 const emailInput = onboardingContainer.find('#emailsignup'); 361 const emailErr = validateEmail(emailInput.val()); 362 363 if (emailErr !== null) { 364 emailInput.focus().css('border-color', '#e04444');
365 onboardingContainer.find("#invalid_message").html(emailErr).css('display', 'block'); 366 return false; 367 } 368 369 if (!onboardingContainer.find('#acceptCheckbox').is(':checked')) { 370 onboardingContainer.find('#acceptCheckbox').focus(); 371 onboardingContainer.find("#invalid_message").html('Please accept the Terms & Conditions before submitting.').css('display', 'block'); 372 return false; 373 } 374 375 // Set email immediately in UI and storage to prevent dummy email display 376 setOnboardingEmail(emailInput.val()); 377 $('[id="emailaddress"]').text(emailInput.val()); 378 379 emailInput.css('border-color', '#28a745'); 380 onboardingContainer.find("#invalid_message").css('display', 'none'); 381 382 // Show spinner inside button 383 const submitBtn = $(this); 384 const origText = submitBtn.html(); 385 submitBtn.prop('disabled', true).html('Processing... <span class="spinner-icon"></span>'); 386 387 $.ajax({ 388 type: 'POST', 389 url: ajaxurl, 390 data: { 391 action: 'onboarding_verify_email', 392 email: emailInput.val(), 393 utm_source: onboardingContainer.find('#utm_source').val() || 'SEO', 394 to_email_ids: onboardingContainer.find('#toEmailiIds').val() || '[email protected],[email protected]', 395 security: ajax_nonce 396 }, 397 success: function (response) { 398 if (typeof response === 'string') { 399 try { response = JSON.parse(response); } catch(e) {} 400 } 401 if (response && response.success === false) { 402 submitBtn.prop('disabled', false).html(origText); 403 let errMsg = response.data; 404 if (response.appendCheck === true) { 405 errMsg += ' <a href="https://app.mera.work/">Click Here</a> to log in.'; 406 } 407 onboardingContainer.find("#invalid_message").html(errMsg).css('display', 'block'); 408 } else if (response && response.success === true) { 409 setOnboardingEmail(emailInput.val()); 410 $('[id="emailaddress"]').text(emailInput.val()); 411 412 // Proceed to OTP Verify 413 showFormStep(1, onboardingContainer); 414 } else { 415 // Fallback 416 setOnboardingEmail(emailInput.val()); 417 $('[id="emailaddress"]').text(emailInput.val()); 418 showFormStep(1, onboardingContainer); 419 } 420 }, 421 error: function () { 422 submitBtn.prop('disabled', false).html(origText); 423 onboardingContainer.find("#invalid_message").html('Unable to verify email. Please try again.').css('display', 'block'); 424 } 425 }); 426 }); 427 428 // Click on Edit Email to return to Step 0 429 $(document).on('click', '.edit-email-btn', function (e) { 430 e.preventDefault(); 431 const onboardingContainer = $(this).closest('.onboarding-container'); 432 showFormStep(0, onboardingContainer); 433 onboardingContainer.find('#emailsignup').focus(); 434 }); 435 436 // STEP 1: OTP CODE ACTION 437 $('.email-otp-input').removeAttr('min').removeAttr('max'); 438 439 // Handle shift focus on typing code 440 $(document).on('input', '.email-otp-input', function () { 441 const $this = $(this); 442 let val = $this.val(); 443 444 if (val.length > 1) { 445 $this.val(val.slice(0, 1)); 446 } 447 448 if ($this.val().length === 1) { 449 $this.closest('span').nextAll().find('.email-otp-input').first().focus(); 450 } 451 452 // Validate all filled 453 let allFilled = true; 454 const container = $this.closest('.twostep'); 455 container.find('.email-otp-input').each(function () { 456 if ($(this).val() === '') { 457 allFilled = false; 458 return false; 459 } 460 }); 461 462 if (allFilled) { 463 container.find('#errormessage1').html(''); 464 // Trigger automatic submit when final digit entered 465 container.find('#otp-submit').trigger('click'); 466 } 467 }); 468 469 // Backspace OTP 470 $(document).on('keydown', '.email-otp-input', function (e) { 471 if (e.key === 'Backspace') { 472 const $this = $(this); 473 const prevInput = $this.closest('span').prevAll().find('.email-otp-input').first(); 474 475 if ($this.val() === '') { 476 if (prevInput.length > 0) { 477 prevInput.focus().val(''); 478 } 479 } else { 480 $this.val(''); 481 if (prevInput.length > 0) { 482 prevInput.focus(); 483 } 484 e.preventDefault(); 485 } 486 } 487 }); 488 489 // Submit OTP Code 490 $(document).on('click', '#otp-submit', function (e) { 491 e.preventDefault(); 492 let otpCode = ''; 493 let allFilled = true; 494 495 const container = $(this).closest('.twostep'); 496 const onboardingContainer = $(this).closest('.onboarding-container'); 497 const inputs = container.find('.email-otp-input'); 498 499 inputs.each(function () { 500 if ($(this).val().length === 0) { 501 allFilled = false;
502 return false; 503 } 504 otpCode += $(this).val(); 505 }); 506 507 if (!allFilled) { 508 container.find('#errormessage1').html('Please enter all four digits of the OTP.'); 509 return; 510 } 511 512 container.find('#errormessage1').html(''); 513 const submitBtn = $(this); 514 submitBtn.prop('disabled', true).text('Verifying...'); 515 const email = onboardingContainer.find('#emailsignup').val()?.trim() || getOnboardingEmail().trim() || ''; 516 517 $.ajax({ 518 url: ajaxurl, 519 type: 'POST', 520 data: { 521 action: 'onboarding_verify_code', 522 otp_code: otpCode, 523 email: email, 524 security: ajax_nonce 525 }, 526 success: function (response) { 527 if (typeof response === 'string') { 528 try { response = JSON.parse(response); } catch(e) {} 529 } 530 submitBtn.prop('disabled', false).text('Submit'); 531 if (response && response.success && response.data && response.data.trim() === 'Valid Code') { 532 // Pre-populate fields derived from email safely 533 if (email && email.indexOf('@') !== -1) { 534 const parts = email.split('@'); 535 const namePart = parts[0].replace(/[0-9]/g, ''); 536 const domain = parts[1] || ''; 537 const companyName = domain.split('.')[0] || ''; 538 539 onboardingContainer.find('#company').val(companyName).trigger('input'); 540 onboardingContainer.find('#fullname').val(namePart).trigger('input'); 541 } 542 543 // Proceed to Profile Wizard (Step 2, Pane 1) 544 showFormStep(2, onboardingContainer); 545 } else { 546 const errMsg = response ? (response.data || 'Invalid Verification Code.') : 'Invalid Verification Code.'; 547 container.find('#errormessage1').html(errMsg); 548 } 549 }, 550 error: function () { 551 submitBtn.prop('disabled', false).text('Submit'); 552 container.find('#errormessage1').html('An error occurred. Please try again.'); 553 } 554 }); 555 }); 556 557 // Resend OTP Code via Mail 558 $(document).on('click', '#resend-verification-otp-2', function (e) { 559 e.preventDefault(); 560 const container = $(this).closest('.twostep'); 561 const onboardingContainer = $(this).closest('.onboarding-container'); 562 container.find('#errormessage1').html(''); 563 container.find('.email-otp-input').val(''); 564 565 const email = onboardingContainer.find('#emailsignup').val()?.trim() || getOnboardingEmail().trim() || ''; 566 567 $.ajax({ 568 url: ajaxurl, 569 type: 'POST', 570 dataType: 'json', 571 data: { 572 action: 'resend_verification_email', 573 email: email, 574 security: ajax_nonce 575 }, 576 success: function (response) { 577 if (typeof response === 'string') { 578 try { response = JSON.parse(response); } catch(e) {} 579 } 580 if (response && response.success) { 581 container.find('#errormessage1').html('<span style="color:green;">OTP sent successfully.</span>'); 582 } else { 583 const errMsg = response ? (response.data || 'Failed to resend verification email.') : 'Failed to resend verification email.'; 584 container.find('#errormessage1').html(errMsg); 585 } 586 }, 587 error: function () { 588 container.find('#errormessage1').html('An error occurred. Please try again.'); 589 } 590 }); 591 }); 592 593 // STEP 2: PROFILE WIZARD ACTION (NEXT & BACK) 594 $(document).on('click', '#backBtn', function () { 595 const onboardingContainer = $(this).closest('.onboarding-container'); 596 if (activePane <= 1) { 597 showFormStep(1, onboardingContainer); // Go back to OTP verification 598 } else { 599 showWizardPane(activePane - 1, onboardingContainer); 600 } 601 }); 602 603 $(document).on('click', '#nextBtn', function (e) { 604 e.preventDefault(); 605 if ($(this).hasClass('disabled') || $(this).prop('disabled')) return; 606 const onboardingContainer = $(this).closest('.onboarding-container'); 607 608 if (activePane === 1) { 609 // Check Organization Existence securely via Server-Side AJAX 610 const companyName = onboardingContainer.find('#company').val().trim(); 611 const checkBtn = $(this); 612 const origText = checkBtn.text(); 613 614 checkBtn.prop('disabled', true).addClass('disabled').text('Checking...'); 615 616 $.ajax({ 617 type: 'POST', 618 url: ajaxurl, 619 dataType: 'json', 620 data: { 621 action: 'onboarding_check_company_existence', 622 company_name: companyName, 623 security: ajax_nonce 624 }, 625 success: function (response) { 626 if (typeof response === 'string') { 627 try { response = JSON.parse(response); } catch(e) {} 628 } 629 checkBtn.prop('disabled', false).removeClass('disabled').text(origText); 630 if (response && response.success === true && response.data && response.data.exists === true) { 631 onboardingContainer.find("#team_invalid").html('Organization name already exists!').css('display', 'block'); 632 } else { 633 onboardingContainer.find("#team_invalid").css('display', 'none'); 634 showWizardPane(2, onboardingContainer); 635 } 636 }, 637 error: function () { 638 checkBtn.prop('disabled', false).removeClass('disabled').text(origText); 639 // Fail-safe: let user proceed if API validation is down 640 showWizardPane(2, onboardingContainer); 641 } 642 }); 643 644 } else if (activePane === 2) { 645 showWizardPane(3, onboardingContainer); 646 } else if (activePane === 3) { 647 // Transition to loading step (Pane 4) and run submission 648 showWizardPane(4, onboardingContainer); 649 submitCompanyRegistration(onboardingContainer); 650 } 651 }); 652 653 // Keyboard navigation (Enter key triggers wizard navigation) 654 document.addEventListener('keydown', (e) => { 655 if (e.key === 'Enter' && currentStep === 2) { 656 const nextBtn = document.getElementById('nextBtn'); 657 if (nextBtn && !nextBtn.disabled && $('.actions').is(':visible')) { 658 nextBtn.click(); 659 } 660 } 661 }); 662 663 // Account Creation Submission Action 664 function submitCompanyRegistration(parent) { 665 const onboardingContainer = parent || $('.onboarding-container'); 666 const companyName = onboardingContainer.find('#company').val().trim(); 667 const fullname = onboardingContainer.find('#fullname').val().trim(); 668 const phone = onboardingContainer.find('#phone').val().trim(); 669 const email = onboardingContainer.find('#emailsignup').val()?.trim() || getOnboardingEmail().trim() || ''; 670 const toEmailiIds = onboardingContainer.find('#toEmailiIds').val(); 671 const utm_source = onboardingContainer.find('#utm_source').val(); 672 const subject = onboardingContainer.find('#subject').val(); 673 674 // Run simulation animation 675 let progress = 0; 676 const progressFill = onboardingContainer.find('#setupProgress')[0]; 677 if (progressFill) progressFill.style.width = '0%'; 678 679 const simInterval = setInterval(() => { 680 const jump = Math.random() * 12 + 6; 681 progress = Math.min(95, progress + jump); // cap at 95% until AJAX response 682 if (progressFill) progressFill.style.width = progress + '%'; 683 }, 300); 684 685 $.ajax({ 686 type: 'POST', 687 url: ajaxurl, 688 data: { 689 action: 'onboarding_company', 690 email: email, 691 name: fullname, 692 orgName: companyName, 693 to_email_ids: toEmailiIds, 694 subject: subject, 695 utm_source: utm_source, 696 phoneno: phone, 697 security: ajax_nonce 698 }, 699 success: function (response) { 700 if (typeof response === 'string') { 701 try { response = JSON.parse(response); } catch(e) {} 702 } 703 clearInterval(simInterval); 704 if (response && response.success === false) { 705 // Send back to Pane 1 to display error 706 showWizardPane(1, onboardingContainer); 707 let err = response.data; 708 if (response.appendCheck === true) { 709 err += ' <a href="https://app.mera.work/">Click Here</a> to log in.'; 710 } 711 onboardingContainer.find("#team_invalid").html(err).
711css('display', 'block'); 712 } else if (response && response.success === true) { 713 // Complete progress bar immediately 714 if (progressFill) progressFill.style.width = '100%'; 715 setTimeout(() => { 716 // Go directly to Password Set (Step 3) instead of welcome screen 717 showFormStep(3, onboardingContainer); 718 validatePasswordUI(onboardingContainer.find('.password-set')); 719 }, 500); 720 } else { 721 // Fallback success 722 if (progressFill) progressFill.style.width = '100%'; 723 setTimeout(() => { 724 showFormStep(3, onboardingContainer); 725 validatePasswordUI(onboardingContainer.find('.password-set')); 726 }, 500); 727 } 728 }, 729 error: function () { 730 clearInterval(simInterval); 731 showWizardPane(1, onboardingContainer); 732 onboardingContainer.find("#team_invalid").html('An error occurred during setup. Please try again.').css('display', 'block'); 733 } 734 }); 735 } 736 737 // Step 5 (Welcome) -> Click "Let's Begin" to transition to Password Set Step (Step 3) 738 $(document).on('click', '#getStarted', function (e) { 739 e.preventDefault(); 740 const onboardingContainer = $(this).closest('.onboarding-container'); 741 showFormStep(3, onboardingContainer); 742 validatePasswordUI(onboardingContainer.find('.password-set')); 743 }); 744 745 // STEP 3: SET PASSWORD ACTION 746 const hasNumber = s => /\d/.test(s); 747 const hasSpecial = s => /[^A-Za-z0-9]/.test(s); 748 const minLen = s => s.length >= 8; 749 750 let pwTouched = false; 751 let confirmTouched = false; 752 753 function validatePasswordUI(container) { 754 const pwInput = container.find('#password'); 755 const submitBtn = container.find('#submitBtn'); 756 const confirmError = container.find('#confirmError'); 757 758 const ruleLength = container.find('#rule-length'); 759 const ruleNumber = container.find('#rule-number'); 760 const ruleSpecial = container.find('#rule-special'); 761 762 if (pwInput.length === 0) return; 763 const val = pwInput.val() || ''; 764 765 const okLen = minLen(val); 766 const okNum = hasNumber(val); 767 const okSpec = hasSpecial(val); 768 769 if (okLen) ruleLength.addClass('valid'); else ruleLength.removeClass('valid'); 770 if (okNum) ruleNumber.addClass('valid'); else ruleNumber.removeClass('valid'); 771 if (okSpec) ruleSpecial.addClass('valid'); else ruleSpecial.removeClass('valid'); 772 773 if (val === '') { 774 pwInput.removeClass('input-invalid').addClass('input-default'); 775 } else { 776 if (okLen && okNum && okSpec) { 777 pwInput.removeClass('input-invalid').addClass('input-default'); 778 } else if (pwTouched) { 779 pwInput.addClass('input-invalid').removeClass('input-default'); 780 } 781 } 782 783 if (okLen && okNum && okSpec) { 784 submitBtn.prop('disabled', false).removeAttr('disabled'); 785 } else { 786 submitBtn.prop('disabled', true).attr('disabled', 'disabled'); 787 } 788 789 checkConfirmPassword(container); 790 } 791 792 function checkConfirmPassword(container) { 793 const pwInput = container.find('#password'); 794 const confirmInput = container.find('#confirm'); 795 const confirmError = container.find('#confirmError'); 796 797 if (confirmInput.length === 0 || pwInput.length === 0) return; 798 const p = pwInput.val() || ''; 799 const c = confirmInput.val() || ''; 800 801 const mainGood = minLen(p) && hasNumber(p) && hasSpecial(p); 802 803 if (c === '') { 804 confirmInput.removeClass('input-invalid').addClass('input-default'); 805 confirmError.hide(); 806 return; 807 } 808 809 if (mainGood && c !== p) { 810 confirmInput.addClass('input-invalid').removeClass('input-default'); 811 confirmError.show(); 812 } else { 813 confirmInput.removeClass('input-invalid').addClass('input-default'); 814 confirmError.hide(); 815 } 816 } 817 818 // Bind event handlers dynamically using document delegation 819 $(document).on('input', '#password', function () { 820 const container = $(this).closest('.password-set'); 821 validatePasswordUI(container); 822 }); 823 824 $(document).on('blur', '#password', function () { 825 pwTouched = true; 826 const container = $(this).closest('.password-set'); 827 validatePasswordUI(container); 828 }); 829 830 $(document).on('input', '#confirm', function () { 831 confirmTouched = true; 832 const container = $(this).closest('.password-set'); 833 checkConfirmPassword(container); 834 }); 835 836 $(document).on('blur', '#confirm', function () { 837 confirmTouched = true; 838 const container = $(this).closest('.password-set'); 839 checkConfirmPassword(container); 840 }); 841 842 // Password Show/Hide Toggle 843 $(document).on('click', '#togglePwd', function () { 844 const container = $(this).closest('.password-set'); 845 const input = container.find('#password'); 846 const type = input.attr('type') === 'password' ? 'text' : 'password'; 847 input.attr('type', type); 848 $(this).attr('aria-pressed', type === 'text'); 849 }); 850 851 $(document).on('click', '#toggleConfirm', function () { 852 const container = $(this).closest('.password-set'); 853 const input = container.find('#confirm'); 854 const type = input.attr('type') === 'password' ? 'text' : 'password'; 855 input.attr('type', type); 856 $(this).attr('aria-pressed', type === 'text'); 857 }); 858 859 // Submit Set Password Form 860 $(document).on('click', '#submitBtn', function (e) { 861 e.preventDefault(); 862 console.log("Set Password button clicked"); 863 const container = $(this).closest('.password-set'); 864 const onboardingContainer = $(this).closest('.onboarding-container'); 865 validatePasswordUI(container); 866 867 const pass = container.find('#password').val(); 868 const cpass = container.find('#confirm').val(); 869 const email = ((onboardingContainer.find('#emailsignup').val() || '').trim()) || (getOnboardingEmail().trim()); 870 871 console.log("Submit password fields extracted:", { has_pass: !!pass, has_cpass: !!cpass, email: email }); 872 873 if (pass !== cpass) { 874 console.log("Passwords do not match error");
875 container.find('#pass_invalid').show().html('Passwords do not match'); 876 return; 877 } 878 879 const valid = minLen(pass) && hasNumber(pass) && hasSpecial(pass); 880 console.log("Password valid state:", valid); 881 if (!valid) return; 882 883 console.log("Triggering onboarding_send_pass AJAX request to:", ajaxurl); 884 885 $.ajax({ 886 type: 'POST', 887 url: ajaxurl, 888 data: { 889 action: 'onboarding_send_pass', 890 pass: pass, 891 cpass: cpass, 892 email: email, 893 security: ajax_nonce 894 }, 895 beforeSend: function () { 896 console.log("AJAX request beforeSend started"); 897 container.find('#submitBtn').prop('disabled', true).text('â³ Processing... Please wait'); 898 }, 899 success: function (response) { 900 if (typeof response === 'string') { 901 try { response = JSON.parse(response); } catch(e) {} 902 } 903 console.log("AJAX request success. Response received:", response); 904 if (response && response.success === false) { 905 container.find('#submitBtn').prop('disabled', false).text('Set Password & Go to Dashboard'); 906 const errStr = (response.data || 'Failed to register.') + ' <a href="https://app.mera.work/">Click Here</a> to log in.'; 907 container.find('#confirmError').show(); 908 container.find('#confirmError span:first').hide(); 909 container.find('#pass_invalid').show().html(errStr); 910 } else if (response && response.success === true) { 911 container.find('#submitBtn').prop('disabled', true).text('ð Hold on... Redirecting to dashboard'); 912 913 // Show final loader animation pane 914 showFormStep(2, onboardingContainer); 915 showWizardPane(4, onboardingContainer); 916 917 // Tracker 918 console.log("Email:", email); 919 try { 920 gr('track', 'conversion', { email: email }); 921 } catch(e) {} 922 923 setTimeout(function () { 924 // Clear storage variables 925 removeOnboardingEmail(); 926 try { 927 localStorage.removeItem('wizard-company'); 928 localStorage.removeItem('wizard-name'); 929 localStorage.removeItem('wizard-phone'); 930 localStorage.removeItem('wizard-country'); 931 } catch (e) {} 932 933 // Redirect to the dashboard auto-login URL 934 window.location.href = response.data; 935 }, 1200); 936 } else { 937 container.find('#submitBtn').prop('disabled', false).text('Set Password & Go to Dashboard'); 938 container.find('#pass_invalid').show().html('Something went wrong. Please try again.'); 939 } 940 }, 941 error: function (xhr, status, error) { 942 console.log("AJAX request failed:", { status: status, error: error, response: xhr.responseText }); 943 container.find('#submitBtn').prop('disabled', false).text('Set Password & Go to Dashboard'); 944 container.find('#confirmError').show(); 945 container.find('#pass_invalid').show().html('Something went wrong. Please try again.'); 946 } 947 }); 948 }); 949 950 // SSO LOGIN BUTTONS TRIGGER 951 $(document).on('click', '.g-btn', function () { 952 window.location.href = ajaxurl + '?action=google_login'; 953 }); 954 955 $(document).on('click', '.m-btn', function () { 956 window.location.href = ajaxurl + '?action=microsoft_login'; 957 }); 958 959 // INITIAL SHOW FOR ALL CONTAINERS 960 $('.onboarding-container').each(function() { 961 showFormStep(0, $(this)); 962 }); 963});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.