1jQuery(document).ready(function ($) { 2 var resendDelay = 0; 3 var emailDomains = WAWP_Signup_Params.email_domains || ['gmail.com', 'yahoo.com', 'hotmail.com', 'outlook.com', 'aol.com']; 4 var otpMethod = WAWP_Signup_Params.otp_method || 'whatsapp'; 5 if (otpMethod === 'wa') { 6 otpMethod = 'whatsapp'; 7 } 8 var passwordStrong = WAWP_Signup_Params.password_strong || 0; 9 10 // Firebase SMS Integration 11 let confirmationResult = null; 12 let firebaseLoading = false; 13 14 async function ensureFirebase() { 15 if (typeof firebase !== 'undefined' && firebase.auth) { 16 if (!window.recaptchaVerifierSignup) await initFirebaseVerifierSignup(); 17 return true; 18 } 19 20 if (firebaseLoading) return new Promise(resolve => { 21 const i = setInterval(() => { if (typeof firebase !== 'undefined' && firebase.auth) { clearInterval(i); resolve(true); } }, 100); 22 }); 23 firebaseLoading = true; 24 25 const scripts = [ 26 'https://www.gstatic.com/firebasejs/9.1.1/firebase-app-compat.js', 27 'https://www.gstatic.com/firebasejs/9.1.1/firebase-auth-compat.js' 28 ]; 29 30 for (const src of scripts) { 31 await new Promise(resolve => { 32 const s = document.createElement('script'); 33 s.src = src; s.onload = resolve; document.head.appendChild(s); 34 }); 35 } 36 37 await initFirebaseVerifierSignup(); 38 return true; 39 } 40 41 async function initFirebaseVerifierSignup() { 42 if (!document.getElementById('wawp-firebase-recaptcha-signup')) return; 43 44 const config = WAWP_Signup_Params.firebase_config; 45 if (!config) { console.error('Firebase config missing'); return; } 46 47 if (!config.apiKey && config.api_key) config.apiKey = config.api_key; 48 if (!config.apiKey) { console.error('Firebase API Key missing'); return; } 49 50 // Clean the config object to only include valid Firebase parameters 51 const firebaseConfig = { 52 apiKey: config.apiKey || config.api_key, 53 authDomain: config.authDomain, 54 projectId: config.projectId, 55 storageBucket: config.storageBucket, 56 messagingSenderId: config.messagingSenderId, 57 appId: config.appId, 58 measurementId: config.measurementId 59 }; 60 61 let app = null; 62 try { 63 app = firebase.app('wawp_signup_app'); 64 } catch (e) { 65 app = firebase.initializeApp(firebaseConfig, 'wawp_signup_app'); 66 } 67 68 if (!window.recaptchaVerifierSignup) { 69 try { 70 window.recaptchaVerifierSignup = new firebase.auth.RecaptchaVerifier('wawp-firebase-recaptcha-signup', { 71 'size': 'invisible', 72 'callback': (response) => { } 73 }, app); 74 window.recaptchaVerifierSignup.render(); 75 } catch (e) { console.warn('Recaptcha init error', e); } 76 } 77 } 78 79 if (WAWP_Signup_Params.firebase_config && otpMethod === 'firebase') { 80 ensureFirebase(); 81 } 82 83 // Prefill phone from OTP login redirect (?pre_phone=) 84 (function prefillPhoneFromQuery() { 85 try { 86 var params = new URLSearchParams(window.location.search); 87 var p = params.get('pre_phone'); 88 if (p) { 89 p = decodeURIComponent(p); 90 $('#wawp_phone').val(p).trigger('input'); 91 } 92 } catch (e) { } 93 })(); 94 95 var recaptchaWidgetId = null; 96 97 function initRecaptcha(callback, attempt) { 98 if (!WAWP_Signup_Params.recaptcha_enabled || WAWP_Signup_Params.recaptcha_enabled === '0') { 99 if (typeof callback === 'function') callback(); 100 return; 101 } 102 103 attempt = typeof attempt === 'number' ? attempt : 1; 104 105 if (typeof grecaptcha === 'undefined' || typeof grecaptcha.render !== 'function') { 106 if (attempt <= 20) { 107 setTimeout(function () { initRecaptcha(callback, attempt + 1); }, 300); 108 } else if (typeof callback === 'function') { 109 callback(); 110 } 111 return; 112 } 113 114 grecaptcha.ready(function () { 115 var id = 'wawp-recaptcha-signup'; 116 var $container = $('#' + id); 117 if ($container.length && recaptchaWidgetId === null) { 118 try { 119 var isCheckbox = WAWP_Signup_Params.recaptcha_type === 'v2_checkbox'; 120 var params = { 121 'sitekey': WAWP_Signup_Params.recaptcha_site_key, 122 'size': isCheckbox ? 'normal' : 'invisible', 123 'badge': WAWP_Signup_Params.is_rtl ? 'bottomleft' : 'bottomright', 124 'callback': function (token) { 125 var cb = $container.data('wawp-recaptcha-cb'); 126 if (cb) { 127 cb(token); 128 $container.data('wawp-recaptcha-cb', null); 129 } 130 } 131 }; 132 recaptchaWidgetId = grecaptcha.render(id, params); 133 } catch (e) { 134 console.warn('WAWP Signup: ReCAPTCHA render error', e); 135 } 136 } 137 if (typeof callback === 'function') callback(); 138 }); 139 } 140 141 function triggerFirebaseFallback(originalError) { 142 if (!parseInt(WAWP_Signup_Params.fallback_enabled)) { 143 displayMessage(originalError, 'error'); 144 return; 145 } 146 147 const canWhatsApp = parseInt(WAWP_Signup_Params.whatsapp_configured) && $('#wawp_phone').val(); 148 const canEmail = parseInt(WAWP_Signup_Params.email_configured) && parseInt(WAWP_Signup_Params.email_enabled) && $('#wawp_email').val(); 149 150 if (canWhatsApp) { 151 displayMessage('ÙØ´Ù إرسا٠SMS. Ø¬Ø§Ø±Ù Ø§ÙØ¥Ø±Ø³Ø§Ù عبر ÙØ§ØªØ³Ø§Ø¨...'); 152 setTimeout(() => { triggerResend('whatsapp'); }, 1500); 153 } else if (canEmail) { 154 displayMessage('ÙØ´Ù إرسا٠SMS. Ø¬Ø§Ø±Ù Ø§ÙØ¥Ø±Ø³Ø§Ù عبر Ø§ÙØ¨Ø±Ùد Ø§ÙØ¥ÙÙØªØ±ÙÙÙ...'); 155 setTimeout(() => { triggerResend('email'); }, 1500); 156 } else { 157 displayMessage(originalError, 'error'); 158 } 159 } 160 161 $(window).on('load', function () { initRecaptcha(); }); 162 $(document).on('wawp_recaptcha_init', function () { setTimeout(initRecaptcha, 100); }); 163 164 function withRecaptcha(onSuccess, onError) { 165 if (!WAWP_Signup_Params.recaptcha_enabled || !WAWP_Signup_Params.recaptcha_site_key || otpMethod === 'firebase') { 166 onSuccess(null); 167 return; 168 } 169 170 initRecaptcha(function () { 171 if (recaptchaWidgetId !== null) { 172 var isCheckbox = WAWP_Signup_Params.recaptcha_type === 'v2_checkbox'; 173 var response = grecaptcha.getResponse(recaptchaWidgetId); 174 175 if (isCheckbox) { 176 if (response) { 177 onSuccess(response); 178 } else { 179 displayMessage(WAWP_Signup_L10n.pleaseSolveRecaptcha || 'Please solve the reCAPTCHA.', 'error'); 180 } 181 } else { 182 // Invisible mode 183 if (response) { 184 grecaptcha.reset(recaptchaWidgetId); 185 } 186 $('#wawp-recaptcha-signup').data('wawp-recaptcha-cb', onSuccess); 187 grecaptcha.execute(recaptchaWidgetId); 188 } 189 } else { 190 console.warn('WAWP Signup: ReCAPTCHA widget not found'); 191 onSuccess(null); 192 } 193 }); 194 } 195 196 async function wawpRest(op, data = {}) { 197 if (!WAWP_Signup_Params.rest_url) { 198 return $.post(WAWP_Signup_Params.ajax_url, { 199 action: 'wawp_signup_op', 200 nonce: WAWP_Signup_Params.nonce, 201 ...data, 202 op: op 203 }); 204 } 205 206 const response = await fetch(WAWP_Signup_Params.rest_url + '/' + op, { 207 method: 'POST', 208 headers: { 209 'Content-Type': 'application/json', 210 'X-WP-Nonce': WAWP_Signup_Params.nonce 211 }, 212 body: JSON.stringify(data) 213 }); 214 215 const result = await response.json(); 216 if (!response.ok) { 217 throw new Error(result.message || 'REST Request Failed'); 218 } 219 220 // Normalize response data structure for signup 221 let normalized = { 222 success: false, 223 data: {} 224 }; 225 226 if (result && typeof result === 'object') { 227 if ('success' in result && result.data && typeof result.data === 'object') { 228 const inner = result.data; 229 normalized.success = 'success' in inner ? !!inner.success : !!result.success; 230 231 for (const key in inner) { 232 if (key !== 'data' && key !== 'success') { 233 normalized.data[key] = inner[key]; 234 } 235 } 236 237 if (inner.data && typeof inner.data === 'object') { 238 for (const key in inner.data) { 239 normalized.data[key] = inner.data[key]; 240 } 241 } 242 } else { 243 normalized.success = !!result.success; 244 normalized.data = result.data || result; 245 } 246 } 247 248 return normalized; 249 } 250 251 function displayMessage(message, type = 'success') { 252 var color = (type === 'success') ? '#15803d' : '#b91c1c'; 253 var background = (type === 'success') ? '#e0faec' : '#fecaca'; 254 var border = (type === 'success') ? '1px solid rgba(21, 128, 61, 0.15)' : '1px solid rgba(185, 28, 28, 0.15)'; 255 $('.wawp-success-message').text(message).css({ 256 'color': color, 257 'padding': '12px 20px', 258 'border-radius': '10px', 259 'margin-top': '24px', 260 'text-align': 'center', 261 'font-size': '14px', 262 'font-weight': '600', 263 'background-color': background, 264 'border': border, 265 'box-sizing': 'border-box', 266 'width': '100%', 267 'display': 'inline-block' 268 }).removeClass('wawp-hide').show(); 269 } 270 271 function clearMessages() { 272 $('.wawp-success-message').hide().text(''); 273 $('.wawp-error-message').hide().text(''); 274 } 275 276 function showFieldError($input, errorText) { 277 $input.closest('.wawp-form-group') 278 .find('.wawp-error-message') 279 .text(errorText) 280 .show(); 281 } 282 283 284 if ($('#wawp_email').length > 0) { 285 $('#wawp_email').autocomplete({ 286 source: function (request, response) { 287 var term = request.term; 288 var atIndex = term.indexOf('@'); 289 if (atIndex === -1) { 290 if (term.trim() === '') { 291 response([]); 292 return; 293 } 294 var suggestions = []; 295 for (var i = 0; i < emailDomains.length && suggestions.length < 5; i++) { 296 suggestions.push(term + '@' + emailDomains[i]); 297 } 298 response(suggestions); 299 } else { 300 var prefix = term.substring(0, atIndex + 1); 301 var suffix = term.substring(atIndex + 1); 302 var suggestions = []; 303 for (var i = 0; i < emailDomains.length && suggestions.length < 5; i++) { 304 if (emailDomains[i].startsWith(suffix)) { 305 suggestions.push(prefix + emailDomains[i]); 306 } 307 } 308 response(suggestions); 309 } 310 }, 311 minLength: 1, 312 select: function (event, ui) { 313 $('#wawp_email').val(ui.item.value); 314 return false;
315 } 316 }).autocomplete("instance")._renderItem = function (ul, item) { 317 var atIndex = item.label.indexOf('@'); 318 var username = item.label.substring(0, atIndex); 319 var domain = item.label.substring(atIndex); 320 var formatted = '<span>' + username + '<span style="color: green;">' + domain + '</span></span>'; 321 return $('<li></li>') 322 .data("item.autocomplete", item) 323 .append(formatted) 324 .appendTo(ul); 325 }; 326 } 327 328 $(document).on('blur', '#wawp_email, #wawp_phone', function () { 329 const $input = $(this); 330 const value = $.trim($input.val()); 331 const field = $input.attr('id').replace('wawp_', ''); 332 333 if (!value || value.length < 3) return; 334 335 // Don't check if already showing a basic required error 336 const $group = $input.closest('.wawp-form-group'); 337 const $errorMsg = $group.find('.wawp-error-message'); 338 339 if ($input.hasClass('wawp-field-error') && $errorMsg.text() === WAWP_Signup_L10n.fieldRequired) { 340 return; 341 } 342 343 $input.addClass('wawp-checking'); 344 $errorMsg.hide().text(''); 345 346 wawpRest('check_availability', { [field]: value }).then(response => { 347 $input.removeClass('wawp-checking wawp-field-error wawp-field-success'); 348 349 if (!response.success) { 350 $input.addClass('wawp-field-error'); 351 showFieldError($input, response.data.message); 352 } else { 353 $input.addClass('wawp-field-success'); 354 } 355 }).catch(() => { $input.removeClass('wawp-checking'); }); 356 }); 357 358 $('#wawp-signup-form').on('submit', function (e) { 359 e.preventDefault(); 360 clearMessages(); 361 var form = $(this); 362 var data = form.serializeArray(); 363 var obj = {}; 364 data.forEach(item => obj[item.name] = item.value); 365 obj['otp_method'] = otpMethod; 366 367 form.find('.wawp-form-control').removeClass('wawp-field-error wawp-field-success'); 368 var hasError = false; 369 form.find('.wawp-form-control[required]').each(function () { 370 if ($.trim($(this).val()) === '') { 371 $(this).addClass('wawp-field-error'); 372 showFieldError($(this), WAWP_Signup_L10n.fieldRequired); 373 hasError = true; 374 } 375 }); 376 if (hasError) return; 377 var submitButton = form.find('.wawp-submit-button'); 378 var originalBtnHtml = submitButton.html(); 379 380 withRecaptcha(async function (token) { 381 submitButton.prop('disabled', true).html('<i class="ri-loader-5-line"></i>'); 382 const $msgBox = form.next('.wawp-success-message'); 383 384 if (token) obj['g-recaptcha-response'] = token; 385 386 try { 387 const response = await wawpRest('signup', obj); 388 submitButton.prop('disabled', false).html(originalBtnHtml); 389 if (response.success) { 390 if (response.data.redirect_url) { 391 displayMessage(response.data.message); 392 setTimeout(function () { window.location.href = response.data.redirect_url; }, 2000); 393 return; 394 } 395 if (response.data.otp_transient) { 396 form.hide(); 397 $('#wawp-signup-branding').hide(); 398 $('#wawp-otp-section').removeClass('wawp-hide').show(); 399 400 const otpMethod = response.data.method || response.data.otp_method; 401 const phone = response.data.phone || ''; 402 let fullPhone = phone.startsWith('+') ? phone : '+' + phone; 403 404 if (fullPhone.startsWith('+229') && fullPhone.length === 12) { 405 fullPhone = '+22901' + fullPhone.substring(4); 406 } 407 408 $('#wawp-otp-form').data('phone', phone); 409 $('#wawp-otp-form').data('method', otpMethod); 410 411 if (otpMethod === 'email' || response.data.is_magic_link || response.data.whatsapp_auth_type === 'list') { 412 $('#wawp-otp-section').addClass('wawp-hide').hide(); 413 $('#wawp-otp-branding, #wawp-otp-form').hide(); 414 415 const waitingHtml = ` 416 <div class="wawp-list-waiting-container" style="background: white; padding: 40px 20px; border-radius: 12px; text-align: center; box-shadow: 0 10px 25px -5px rgba(0,0,0,0.1);"> 417 <div class="wawp-list-waiting-icon" style="width: 80px; height: 80px; background: #e0faec; color: #15803d; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 24px; font-size: 40px;"> 418 <i class="ri-shield-check-line"></i> 419 </div> 420 <h4 class="wawp-list-waiting-title" style="font-size: 20px; font-weight: 800; color: #1a202c; margin-bottom: 12px;">${WAWP_Signup_L10n.verifyYourIdentity || 'Verify Your Identity'}</h4> 421 <p class="wawp-list-waiting-text" style="font-size: 14px; color: #4a5568; line-height: 1.6; margin-bottom: 24px;"> 422 ${otpMethod === 'email' ? (WAWP_Signup_L10n.weSentLink || 'We sent a secure verification link to your email') + ' <b>' + response.data.email + '</b>.<br>' + (WAWP_Signup_L10n.pleaseClickLink || 'Please check your inbox and click the link to verify.') : (WAWP_Signup_L10n.weSentSecureRequest || 'We sent a secure verification request to') + ' <b>' + fullPhone + '</b>.<br>' + (WAWP_Signup_L10n.pleaseCheckDevice || 'Please check your device and approve it to continue.')} 423 </p> 424 <div style="margin-top: 20px; border-top: 1px solid #edf2f7; padding-top: 20px;"> 425 <a href="#" class="js-wawp-back-to-signup" style="font-size: 13px; color: #718096; font-weight: 600; text-decoration: underline;">${WAWP_Signup_L10n.changeDetailsOrRetry || 'Change details or retry'}</a> 426 </div> 427 </div> 428 `; 429 $('#wawp-otp-section').after(waitingHtml); 430 startListPolling(otpMethod === 'email' ? response.data.email : phone, response.data.otp_transient); 431 } else { 432 $('#otp-icon').attr('class', otpMethod === 'firebase' ? 'ri-message-3-line' : 'ri-whatsapp-line'); 433 $('#wawp-otp-sent-heading').text(WAWP_Signup_L10n.checkYourPhone); 434 $('#wawp-otp-sent-message').html(WAWP_Signup_L10n.weSentCode.replace('%s', fullPhone)); 435 $('#wawp-resend-message').text(WAWP_Signup_L10n.wrongNumber); 436 $('#wawp-edit-contact-btn').text(WAWP_Signup_L10n.reEnterNumber); 437 } 438 439 $('#wawp_otp_transient').val(response.data.otp_transient); 440
441 function setupVerificationUI(method) { 442 $('#wawp-otp-form').data('method', method); 443 startResendCooldown(parseInt(WAWP_Signup_Params.initial_cooldown) || 30); 444 setupFallbacks(method); 445 } 446 447 function setupFallbacks(method) { 448 $('#wawp-firebase-fallback, #wawp-whatsapp-fallback').remove(); 449 if (!parseInt(WAWP_Signup_Params.fallback_enabled)) return; 450 if (method === 'firebase' && parseInt(WAWP_Signup_Params.whatsapp_configured)) { 451 createFallbackLink('whatsapp', 10); 452 } else if (method === 'whatsapp' && parseInt(WAWP_Signup_Params.firebase_configured)) { 453 createFallbackLink('firebase', 15); 454 } 455 } 456 457 function createFallbackLink(targetMethod, delay) { 458 const isWhatsApp = targetMethod === 'whatsapp'; 459 const linkId = isWhatsApp ? 'wawp-whatsapp-fallback-link' : 'wawp-firebase-fallback-link'; 460 const containerId = isWhatsApp ? 'wawp-firebase-fallback' : 'wawp-whatsapp-fallback'; 461 const color = isWhatsApp ? '#25d366' : '#f57c00'; 462 const icon = isWhatsApp ? 'ri-whatsapp-line' : 'ri-fire-line'; 463 const text = isWhatsApp ? WAWP_Signup_L10n.sendOTPWhatsApp : WAWP_Signup_L10n.sendOTPSMS;
464 const $fallbackContainer = $('<div id="' + containerId + '" style="margin-top: 10px; font-size: 14px; text-align: center;"></div>'); 465 const $fallbackLink = $('<a href="#" id="' + linkId + '" style="color: ' + color + '; text-decoration: none; cursor: not-allowed; opacity: 0.6; display: flex; align-items: center; justify-content: center; gap: 5px;"><i class="' + icon + '"></i> <span>' + text + ' (' + delay + 's)</span></a>'); 466 $fallbackContainer.append($fallbackLink); 467 $('.wawp-success-message').append($fallbackContainer); 468 469 let remaining = delay; 470 let interval = setInterval(() => { 471 remaining--; 472 if (remaining > 0) { $fallbackLink.find('span').text(text + ' (' + remaining + 's)'); } else { 473 clearInterval(interval); 474 $fallbackLink.css({ 'cursor': 'pointer', 'opacity': '1' }).find('span').text(text); 475 $fallbackLink.on('click', function (e) { e.preventDefault(); triggerResend(targetMethod); }); 476 } 477 }, 1000); 478 } 479 480 if (otpMethod === 'firebase') { 481 displayMessage(WAWP_Signup_L10n.sendingCode); 482 ensureFirebase().then(() => { 483 const app = firebase.app('wawp_signup_app'); 484 app.auth().signInWithPhoneNumber(fullPhone, window.recaptchaVerifierSignup) 485 .then((result) => { 486 confirmationResult = result; 487 clearMessages(); 488 displayMessage(WAWP_Signup_L10n.codeSentSuccess || 'Code sent successfully!'); 489 setupVerificationUI('firebase'); 490 submitButton.prop('disabled', false).html(originalBtnHtml); 491 }).catch((error) => { 492 clearMessages(); 493 submitButton.prop('disabled', false).html(originalBtnHtml); 494 triggerFirebaseFallback(error.message); 495 }); 496 }).catch((err) => { 497 clearMessages(); 498 submitButton.prop('disabled', false).html(originalBtnHtml); 499 triggerFirebaseFallback('Firebase initialization failed.'); 500 }); 501 } else { 502 clearMessages(); 503 displayMessage(WAWP_Signup_L10n.codeSentSuccess || 'Code sent successfully!'); 504 setupVerificationUI(otpMethod); 505 submitButton.prop('disabled', false).html(originalBtnHtml); 506 } 507 } else { 508 displayMessage(response.data.message); 509 form.find('.wawp-form-control').addClass('wawp-field-success'); 510 form[0].reset(); 511 if (recaptchaWidgetId !== null) grecaptcha.reset(recaptchaWidgetId); 512 } 513 } else { 514 submitButton.prop('disabled', false).html(originalBtnHtml); 515 if (response.data.errors) { 516 $.each(response.data.errors, function (field, message) { 517 var $input = $('#' + field); 518 if ($input.length) { $input.addClass('wawp-field-error'); showFieldError($input, message); } 519 }); 520 } 521 if (response.data.message) displayMessage(response.data.message, 'error'); 522 if (recaptchaWidgetId !== null) grecaptcha.reset(recaptchaWidgetId); 523 } 524 } catch (err) { 525 submitButton.prop('disabled', false).html(originalBtnHtml); 526 displayMessage(WAWP_Signup_L10n.unexpectedError, 'error'); 527 } 528 }, function (errMsg) { 529 displayMessage(errMsg, 'error'); 530 }); 531 }); 532 533 function startResendCooldown(seconds = 30) { 534 let remaining = seconds; 535 $('#wawp-resend-otp-btn').prop('disabled', true).text(WAWP_Signup_L10n.waitSeconds.replace('%s', remaining)); 536 if (window.wawpSignupResendInterval) clearInterval(window.wawpSignupResendInterval); 537 538 window.wawpSignupResendInterval = setInterval(() => { 539 remaining--; 540 if (remaining > 0) { 541 $('#wawp-resend-otp-btn').text(WAWP_Signup_L10n.waitSeconds.replace('%s', remaining)); 542 } else { 543 clearInterval(window.wawpSignupResendInterval); 544 $('#wawp-resend-otp-btn').prop('disabled', false).text(WAWP_Signup_L10n.resendCode); 545 } 546 }, 1000); 547 } 548 549 function triggerResend(forceMethod = null) { 550 const transientKey = $('#wawp_otp_transient').val(); 551 const currentMethod = forceMethod || $('#wawp-otp-form').data('method'); 552 const phone = $('#wawp-otp-form').data('phone'); 553 let fullPhone = phone.startsWith('+') ? phone : '+' + phone; 554 555 if (fullPhone.startsWith('+229') && fullPhone.length === 12) fullPhone = '+22901' + fullPhone.substring(4); 556 557 const $btn = $('#wawp-resend-otp-btn'); 558 const $msgBox = $('.wawp-success-message'); 559 560 $btn.prop('disabled', true).html('<i class="ri-loader-5-line"></i>'); 561 562 if (currentMethod === 'firebase') { 563 ensureFirebase().then(() => { 564 const app = firebase.app('wawp_signup_app'); 565 app.auth().signInWithPhoneNumber(fullPhone, window.recaptchaVerifierSignup) 566 .then((result) => { 567 confirmationResult = result; 568 displayMessage(WAWP_Signup_L10n.codeResentSMS || 'Code resent via SMS!'); 569 $btn.prop('disabled', false).text(WAWP_Signup_L10n.resendCode); 570 startResendCooldown(parseInt(WAWP_Signup_Params.initial_cooldown) || 30); 571 }).catch((error) => { 572 $btn.prop('disabled', false).text(WAWP_Signup_L10n.resendCode); 573 triggerFirebaseFallback(error.message); 574 }); 575 }); 576 } else { 577 wawpRest('resend', { 578 otp_transient: transientKey, 579 nonce_field: $('#wawp-otp-form input[name="wawp_signup_nonce_field"]').val(), 580 force_otp_method: currentMethod 581 }).then(response => { 582 $btn.prop('disabled', false).text(WAWP_Signup_L10n.resendCode); 583 if (response.success) { 584 displayMessage(response.data.message); 585 $('#wawp_otp_transient').val(response.data.otp_transient); 586 startResendCooldown(parseInt(WAWP_Signup_Params.initial_cooldown) || 30); 587 } else { 588 displayMessage(response.data.message, 'error'); 589 } 590 }).catch(() => { 591 $btn.prop('disabled', false).text(WAWP_Signup_L10n.resendCode); 592 }); 593 } 594 } 595 596 $('#wawp-otp-form').on('submit', function (e) { 597 e.preventDefault(); 598 clearMessages(); 599 var form = $(this); 600 var verifyButton = form.find('.wawp-submit-button'); 601 var originalBtnHtml = verifyButton.html(); 602 verifyButton.prop('disabled', true).html('<i class="ri-loader-5-line"></i>'); 603 604 if (confirmationResult) { 605 const otpCode = $('#wawp_otp_code').val().trim(); 606 confirmationResult.confirm(otpCode).then((result) => { 607 result.user.getIdToken().then(idToken => { 608 wawpRest('verify', { idToken: idToken, otp_transient: $('#wawp_otp_transient').val() }).then(response => { 609 verifyButton.prop('disabled', false).html(originalBtnHtml); 610 if (response.success) { 611 displayMessage(response.data.message); 612 if (response.data.redirect_url) setTimeout(function () { window.location.href = response.data.redirect_url; }, 2000); 613 } else { displayMessage(response.data.message, 'error'); } 614 }); 615 }); 616 }).catch(error => { 617 verifyButton.prop('disabled', false).html(originalBtnHtml); 618 displayMessage(error.message, 'error'); 619 }); 620 } else { 621 var data = form.serializeArray(); 622 var obj = {}; 623 data.forEach(item => obj[item.name] = item.value); 624 wawpRest('verify', obj).then(response => { 625 verifyButton.prop('disabled', false).html(originalBtnHtml); 626 if (response.success) { 627 displayMessage(response.data.message); 628 if (response.data.redirect_url) setTimeout(function () { window.location.href = response.data.redirect_url; }, 2000); 629 else $('#wawp-signup-container').hide(); 630 } else { 631 if (response.data.message) displayMessage(response.data.message, 'error'); 632 } 633 }).catch(() => { verifyButton.prop('disabled', false).html(originalBtnHtml); }); 634 } 635 }); 636 637 $(document).on('click', '#wawp-edit-contact-btn', function () { 638 $('#wawp-otp-section').hide(); 639 clearMessages(); 640 $('#wawp-otp-form')[0].reset(); 641 $('#wawp_otp_transient').val(''); 642 $('#wawp-signup-branding').show(); 643 $('#wawp-signup-form').show(); 644 if (window.wawpSignupResendInterval) clearInterval(window.wawpSignupResendInterval); 645 $('#wawp-resend-otp-btn').prop('disabled', false).html(WAWP_Signup_L10n.resendCode); 646 }); 647 648 $(document).on('click', '#wawp-resend-otp-btn', function () { triggerResend(); }); 649 650 function getPasswordStrength(password) { 651 var strength = { percent: 0, color: 'red', text: 'Weak' }; 652 var rules = [ 653 { regex: /[A-Z]/, increment: 20 }, 654 { regex: /[a-z]/, increment: 20 }, 655 { regex: /[0-9]/, increment: 20 }, 656 { regex: /.{8,}/, increment: 20 }, 657 { regex: /[^A-Za-z0-9]/, increment: 20 } 658 ];
659 rules.forEach(function (rule) { 660 if (rule.regex.test(password)) strength.percent += rule.increment; 661 }); 662 if (strength.percent >= 90) { strength.color = '#22c55e'; strength.text = 'excellent'; } 663 else if (strength.percent >= 70) { strength.color = '#22c55e'; strength.text = 'Strong'; } 664 else if (strength.percent >= 50) { strength.color = '#f59e0b'; strength.text = 'Average'; } 665 else { strength.color = '#ef4444'; strength.text = 'Weak'; } 666 return strength; 667 } 668 669 if ($('#wawp_password').length > 0 && passwordStrong) { 670 $('#wawp_password').on('input', function () { 671 var password = $(this).val(); 672 $('#password-requirements li').each(function (index) { 673 var regex; 674 switch (index) { 675 case 0: regex = /[A-Z]/; break; 676 case 1: regex = /[a-z]/; break; 677 case 2: regex = /[0-9]/; break; 678 case 3: regex = /.{8,}/; break; 679 case 4: regex = /[^A-Za-z0-9]/; break; 680 default: regex = /.*/; break; 681 } 682 if (regex.test(password)) $(this).find('.wawp-check').html('<i class="ri-check-line text-success"></i>'); 683 else $(this).find('.wawp-check').html('<i class="ri-close-line text-danger"></i>'); 684 }); 685 var strength = getPasswordStrength(password); 686 $('#password-strength-meter').css({ width: strength.percent + '%', backgroundColor: strength.color }); 687 $('#password-strength-text').text(strength.text).css('color', strength.color); 688 }); 689 } 690 691 $('.wawp-toggle-password').click(function () { 692 var passwordInput = $(this).siblings('input[type="password"], input[type="text"]'); 693 var type = (passwordInput.attr('type') === 'password') ? 'text' : 'password'; 694 passwordInput.attr('type', type); 695 $(this).find('i').toggleClass('ri-eye-off-line'); 696 }); 697 698 $(document).on('click', '.wawp-fast-login-signup-toggle', function (e) { 699 e.preventDefault(); 700 const $wrapper = $(this).closest('.wawp-fast-login-wrapper'); 701 const $loginView = $wrapper.find('.wawp-fast-login-view-login'); 702 const $signupView = $wrapper.find('.wawp-fast-login-view-signup'); 703 if ($loginView.length) { 704 $loginView.fadeOut(200, function () { 705 if ($signupView.length) { 706 $signupView.fadeIn(200, function () { $(window).trigger('resize'); $(document).trigger('wawp_recaptcha_init'); }); 707 } 708 }); 709 } else if ($signupView.length) { $signupView.fadeIn(200); } 710 }); 711 712 $(document).on('click', '.wawp-fast-login-login-toggle', function (e) { 713 e.preventDefault(); 714 const $wrapper = $(this).closest('.wawp-fast-login-wrapper'); 715 const $loginView = $wrapper.find('.wawp-fast-login-view-login'); 716 const $signupView = $wrapper.find('.wawp-fast-login-view-signup'); 717 if ($signupView.length) { 718 $signupView.fadeOut(200, function () { 719 if ($loginView.length) { 720 $loginView.fadeIn(200, function () { $(window).trigger('resize'); $(document).trigger('wawp_recaptcha_init'); }); 721 } 722 }); 723 } else if ($loginView.length) { $loginView.fadeIn(200); } 724 }); 725 726 $(document).on('click', '.js-wawp-back-to-signup', function (e) { 727 e.preventDefault(); 728 if (pollInterval) clearInterval(pollInterval); 729 $('.wawp-list-waiting-container').remove(); 730 $('#wawp-signup-branding').show(); 731 $('#wawp-signup-form').show(); 732 $('#wawp-otp-section').addClass('wawp-hide').hide(); 733 }); 734 735 let pollInterval = null; 736 function startListPolling(phone, authId) { 737 if (pollInterval) clearInterval(pollInterval); 738 let attempts = 0; 739 const maxAttempts = 60; 740 pollInterval = setInterval(async () => { 741 attempts++; 742 if (attempts > maxAttempts) { 743 clearInterval(pollInterval); 744 $('.wawp-list-waiting-container').remove(); 745 displayMessage(WAWP_Signup_L10n.authTimeout || 'Authentication timeout. Please try again.', 'error'); 746 $('#wawp-signup-branding, #wawp-signup-form').show(); 747 return; 748 } 749 try { 750 const resp = await wawpRest('status', { otp_transient: authId, whatsapp: phone }); 751 if (resp.success && resp.data.verified) { 752 clearInterval(pollInterval); 753 $('.wawp-list-waiting-container').html('<div class="wawp-list-waiting-icon" style="background:#15803d; color:white;"><i class="ri-check-line"></i></div><h4 class="wawp-list-waiting-title">' + (WAWP_Signup_L10n.verified || 'Verified!') + '</h4><p class="wawp-list-waiting-text">' + (WAWP_Signup_L10n.accountCreated || 'Your account has been created successfully.') + '</p>'); 754 setTimeout(() => { if (resp.data.redirect_url) window.location.href = resp.data.redirect_url; else window.location.reload(); }, 1500); 755 } else if (resp.success && resp.data.status === 'rejected') { 756 clearInterval(pollInterval); 757 $('.wawp-list-waiting-container').remove(); 758 displayMessage(WAWP_Signup_L10n.registrationRejected || 'Registration rejected from your phone.', 'error'); 759 $('#wawp-signup-branding, #wawp-signup-form').show(); 760 } 761 } catch (e) { } 762 }, parseInt(WAWP_Signup_Params.polling_interval) || 1500); 763 } 764});
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.