PageSourceSearch

https://lass-pay.com/wp-content/plugins/automation-web-platform/assets/js/wawp-signup.js?ver=1791353167

js lass-pay.com collected 2026-10-07 06:07:20 UTC 37,417 bytes, 764 lines download raw bytes

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.