PageSourceSearch

https://sozd.ai/wp-content/themes/sozd/js/main.js?ver=1.0

js sozd.ai collected 2026-10-05 13:05:36 UTC 120,985 bytes, 1,906 lines download raw bytes

1jQuery(document).ready(function ($) {
2
3	let currentPackage = null; 
4
5// Открытие модального окна при клике на кнопку удалить акк
6$('.del_acc').on('click', function() {
7    // Сброс состояния модального окна перед открытием
8    $('#delModal .modal-title').show();
9    $('#delModal .action_bt').show();
10    $('#delModal .modal-success-message').remove(); // Удаляем сообщение успеха, если осталось с прошлого раза
11    $('#delModal .modal-error-message').remove(); // Удаляем сообщение ошибки, если осталось
12    $('#delModal').fadeIn();
13});
14
15
16$('#sendYesBtn').on('click', function(e) {
17    e.preventDefault(); // Предотвратить стандартное поведение кнопки (если она submit)
18
19    var $btn = $(this);
20    var $modal = $('#delModal');
21    var $header = $modal.find('.modal-title');
22    var $actions = $modal.find('.action_bt');
23
24    // Отключить кнопку и показать индикатор загрузки
25    $btn.prop('disabled', true).text('Удаление...');
26
27    // --- AJAX-запрос на удаление ---
28    $.ajax({
29        url: mains_ajax_object.ajax_url, 
30        type: 'POST',
31        dataType: 'json',
32        data: {
33            action: 'delete_user_account',
34            // nonce: your_nonce_value // Если используете nonce
35        },
36        success: function(response) {
37            console.log('AJAX Success Response:', response); // Для отладки
38            if (response.success) {
39                // Успех: скрыть заголовок и кнопки, показать сообщение
40                $header.hide();
41                $actions.hide();
42                // Создать и вставить сообщение об успехе
43                var $successMessage = $('<p class="modal-success-message" style="text-align:center; color: green; font-weight: bold;">' + response.data.message + '</p>');
44                $modal.find('.modal-content').append($successMessage);
45
46                // Опционально: перенаправить пользователя через некоторое время
47                 setTimeout(function() {
48                     window.location.href = '/'; // Или на страницу выхода wp_logout_url()
49                 }, 2000); // Через 2 секунды
50
51            } else {
52                // Ошибка от сервера
53                showError(response.data.message || 'Произошла неизвестная ошибка при удалении аккаунта.');
54            }
55        },
56        error: function(xhr, status, error) {
57            console.error('AJAX Error Details:', xhr, status, error); // Для отладки
58            showError('Произошла ошибка при отправке запроса на удаление аккаунта.');
59        },
60        complete: function() {
61            // Включить кнопку обратно (хотя модальное окно может быть уже скрыто)
62            // $btn.prop('disabled', false).text('Да');
63        }
64    });
65});
66
67// --- Функция для отображения ошибок внутри модального окна ---
68function showError(message) {
69    // Удалить предыдущие сообщения об ошибках
70    $('#delModal .modal-error-message').remove();
71    // Создать и вставить новое сообщение об ошибке
72    var $errorMessage = $('<p class="modal-error-message" style="text-align:center; color: red; font-weight: bold;">' + message + '</p>');
73    // Вставляем перед кнопками действий или в конец контента
74    $('#delModal .modal-content').append($errorMessage);
75    // Включить кнопку "Да" обратно, если была отключена
76    $('#sendYesBtn').prop('disabled', false).text('Да');
77}
78
79
80    let $phoneModal;
81    let $userPhone;
82    let $sendPhoneBtn; 
83    let $phoneError;
84	//let $phoneClose;
85	
86    //const $phoneModal = $('#paymentModal');
87	//const $phoneModal_auth = $('#loginModal');
88    //const $userPhone = $('#userPhone');
89	//const $userPhoneAuth = $('#userPhoneAuth');
90    //const $sendPhoneBtn = $('#sendPhoneBtn');
91   // const $phoneError = $('#phoneError');
92	//const $phoneErrorAuth = $('#phoneErrorAuth');
93    const $phoneClose = $('.close');
94	
95	
96// --- Объединенный обработчик клика для .pricing-btn и .login-btn ---
97$(document).on('click', '.pricing-btn, .login-btn', function (e) {
98    e.preventDefault();
99
100    const $btn = $(this);
101    // Определяем тип кнопки
102    const isPricingBtn = $btn.hasClass('pricing-btn');
103    const isLoginBtn = $btn.hasClass('login-btn');
104
105    // Извлекаем данные пакета в зависимости от типа кнопки
106    let packageId, price, amount;
107
108    if (isPricingBtn) {
109        // Для .pricing-btn данные берутся из родительского .pricing-card
110        const $card = $btn.closest('.pricing-card');
111        packageId = $card.data('package-id');
112        price = $card.data('price') || 0;
113        amount = $card.data('amount');
114		
115		/*$phoneModal = $('#paymentModal'); // Модал для тарифов
116        $userPhone = $('#userPhone');     // Поле ввода в модале тарифов
117        $sendPhoneBtn = $('#sendPhoneBtn'); // Кнопка в модале тарифов
118        $phoneError = $('#phoneError');  
119        */
120		$phoneModal = $('#loginModal'); 
121        $userPhone = $('#userPhoneAuth'); // Поле ввода в модале входа
122        $sendPhoneBtn = $('#sendPhoneBtnAuth'); // Кнопка в модале входа
123        $phoneError = $('#phoneErrorAuth');		
124		
125		
126    } else if (isLoginBtn) {
127        // Для .login-btn данные берутся непосредственно с кнопки
128        packageId = $btn.data('package-id');
129        price = $btn.data('price') || 0;
130        amount = $btn.data('amount');
131		
132		$phoneModal = $('#loginModal');   // Модал для входа (предполагаем, что это #loginModal, а не $phoneModal_auth)
133        $userPhone = $('#userPhoneAuth'); // Поле ввода в модале входа
134        $sendPhoneBtn = $('#sendPhoneBtnAuth'); // Кнопка в модале входа
135        $phoneError = $('#phoneErrorAuth');
136		
137    } else {
138        // На всякий случай, если кнопка не соответствует ожидаемым классам
139        console.error('Обработчик: Неизвестная кнопка вызвала событие:', $btn.attr('class'));
140        return;
141    }
142  
143  // --- Инициализация маски для существующего поля #userPhone ---
144      initializePhoneMask($userPhone);
145
146    // Сохраняем выбранный пакет в глобальной переменной
147    window.currentPackageSelected = {
148        id: packageId,
149        price: price,
150        amount: amount
151    };
152
153    console.log('Выбран пакет:', window.currentPackageSelected);
154
155    // --- ЛОГИКА ДЛЯ БЛОКА С ПРОБНЫМИ КРИСТАЛЛАМИ (только для НЕавторизованных) ---
156    if (window.currentPackageSelected.price === 0 && window.currentPackageSelected.amount === 25) {
157        // Убедимся, что пользователь не авторизован (на всякий случай, хотя блок виден только неавторизованным)
158        if (typeof mains_ajax_object === 'undefined' || mains_ajax_object.is_user_logged_in != 1) {
159            console.log("Обнаружен блок пробных кристаллов для НЕавторизованного пользователя. Открываем модальное окно.");
160
161            // Определяем, какой модал использовать в зависимости от кнопки
162            let modalToUse = $phoneModal;
163            /*if (isPricingBtn) {
164                modalToUse = $phoneModal; // Используем модал, связанный с тарифами
165            } else if (isLoginBtn) {
166                modalToUse = $phoneModal_auth; // Используем модал, связанный с авторизацией
167            }
168            */
169            // Открываем модальное окно для ввода телефона
170            if (modalToUse && typeof modalToUse !== 'undefined') {
171                // resetPhoneModalState(); // Сброс состояния модалки (если применимо)
172                modalToUse.show();
173                modalToUse.data('isTrialAward', true); // Устанавливаем флаг пробных кристаллов
174                // Сохраняем данные пакета
175                modalToUse.data('selectedPackage', window.currentPackageSelected);
176            } else {
177                console.error(`Модальное окно для ${isPricingBtn ? 'тарифа' : 'входа'} не найдено.`);
178                alert('Ошибка: модальное окно Ð
178½Ðµ найдено.');
179            }
180        } else {
181             console.warn("Кнопка пробных кристаллов нажата авторизованным пользователем. Это не должно происходить.");
182             // Можно ничего не делать или показать сообщение
183        }
184        return; // Прекращаем обработку
185    }
186
187    // --- ЛОГИКА ДЛЯ БЛОКОВ С ЦЕНОЙ ---
188    // Проверяем авторизацию пользователя
189    if (typeof mains_ajax_object !== 'undefined' && mains_ajax_object.is_user_logged_in == 1) {
190        console.log("Пользователь авторизован. Переход к оплате.");
191        // Если пользователь авторизован, сразу переходим к оплате
192        if (typeof showPaymentForm !== 'undefined') {
193            showPaymentForm(
194                mains_ajax_object.current_user_id, // 1-й аргумент: ID пользователя
195                price,                             // 2-й аргумент: Цена
196                amount,                            // 3-й аргумент: Количество
197                packageId                          // 4-й аргумент: ID пакета
198            );
199        } else {
200            console.error('Функция showPaymentForm не определена.');
201            alert('Ошибка: форма оплаты недоступна.');
202        }
203    } else {
204        console.log("Пользователь не авторизован. Открываем модальное окно для ввода телефона.");
205
206        // Определяем, какой модал использовать в зависимости от кнопки
207        /*let modalToUse;
208        if (isPricingBtn) {
209            modalToUse = $phoneModal; // Используем модал, связанный с тарифами
210        } else if (isLoginBtn) {
211            modalToUse = $phoneModal_auth; // Используем модал, связанный с авторизацией
212        }*/
213		let modalToUse = $phoneModal;
214
215        // Если пользователь не авторизован, открываем модалку
216        if (modalToUse && typeof modalToUse !== 'undefined') {
217            // resetPhoneModalState(); // Сброс состояния модалки (если применимо)
218            modalToUse.show();
219            modalToUse.data('isTrialAward', false); // Сбрасываем флаг (или не устанавливаем)
220            // Сохраняем данные пакета для последующей оплаты
221            modalToUse.data('selectedPackage', window.currentPackageSelected);
222        } else {
223            console.error(`Модальное окно для ${isPricingBtn ? 'тарифа' : 'входа'} не найдено.`);
224            alert('Ошибка: модальное окно не найдено.');
225        }
226    }
227});
228// --- Конец объединенного обработчика ---
229
230
231
232    // --- НОВАЯ ЛОГИКА: Модальное окно с телефоном ---
233    // --- Маска ввода телефона (Vanilla JS) ---
234// --- Универсальная функция инициализации маски телефона ---
235function initializePhoneMask($phoneInput) {
236    if ($phoneInput.length) {
237        // Устанавливаем placeholder с маской
238        $phoneInput.attr('placeholder', '+7 (___) ___-__-__');
239        // Устанавливаем maxlength
240        $phoneInput.attr('maxlength', '18'); // +7 (999) 999-99-99
241
242        // Обработчик ввода
243        $phoneInput[0].addEventListener('input', function (e) {
244            // Сохраняем позицию курсора
245            let start = this.selectionStart;
246            let end = this.selectionEnd;
247            // Получаем введённое значение и оставляем только цифры
248            let value = this.value.replace(/\D/g, '');
249            // Если первая цифра 8, заменяем на 7
250            if (value.startsWith('8')) {
251                value = '7' + value.substring(1);
252            }
253            // Если первая цифра не 7, добавляем 7
254            else if (value.length > 0 && !value.startsWith('7')) {
255                value = '7' + value;
256            }
257            // Ограничиваем длину до 11 цифр (7XXXXXXXXXX)
258            if (value.length > 11) {
259                value = value.substring(0, 11);
260            }
261            // Форматируем номер
262            let formattedValue = '';
263            if (value.length > 0) {
264                formattedValue = '+7 (' + value.substring(1, 4);
265            }
266            if (value.length >= 5) {
267                formattedValue += ') ' + value.substring(4, 7);
268            }
269            if (value.length >= 8) {
270                formattedValue += '-' + value.substring(7, 9);
271            }
272            if (value.length >= 10) {
273                formattedValue += '-' + value.substring(9, 11);
274            }
275            // Устанавливаем отформатированное значение
276            this.value = formattedValue;
277            // Восстанавливаем позицию курсора (простая логика)
278            this.setSelectionRange(this.value.length, this.value.length);
279        });
280
281        // Предотвращаем ввод нецифровых символов (дополнительная мера)
282        $phoneInput[0].addEventListener('keypress', function (e) {
283            // Разрешаем только цифры, Backspace, Delete, Tab, Escape, Enter
284            if ([46, 8, 9, 27, 13].indexOf(e.keyCode) !== -1 ||
285                // Разрешаем Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+X
286                (e.keyCode === 65 && e.ctrlKey === true) ||
287                (e.keyCode === 67 && e.ctrlKey === true) ||
288                (e.keyCode === 86 && e.ctrlKey === true) ||
289                (e.keyCode === 88 && e.ctrlKey === true)) {
290                return; // Позволить
291            }
292            // Убедиться, что это цифра, и остановить ввод, если уже 18 символов
293            if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) {
294                e.preventDefault();
295            }
296            // Ограничиваем длину ввода
297            if (this.value.replace(/\D/g, '').length >= 11 && e.keyCode !== 8 && e.keyCode !== 46) {
298                 e.preventDefault();
299            }
300        });
301
302        // Обработка вставки (Paste)
303        $phoneInput[0].addEventListener('paste', function (e) {
304             e.preventDefault();
305             // Получаем вставленный текст
306             let paste = (e.clipboardData || window.clipboardData).getData('text');
307             // Оставляем только цифры
308             let pastedDigits = paste.replace(/\D/g, '');
309             // Если начинается с 8, меняем на 7
310             if (pastedDigits.startsWith('8')) {
311                 pastedDigits = '7' + pastedDigits.substring(1);
312             } else if (!pastedDigits.startsWith('7') && pastedDigits.length > 0) {
313                 pastedDigits = '7' + pastedDigits;
314             }
315             // Ограничиваем 11 цифрами
316             pastedDigits = pastedDigits.substring(0, 11);
317             // Форматируем и устанавливаем
318             let formattedValue = '';
319             if (pastedDigits.length > 0) {
320                 formattedValue = '+7 (' + pastedDigits.substring(1, 4);
321             }
322             if (pastedDigits.length >= 5) {
323                 formattedValue += ') ' + pastedDigits.substring(4, 7);
324             }
325             if (pastedDigits.length >= 8) {
326                 formattedValue += '-' + pastedDigits.substring(7, 9);
327             }
328             if (pastedDigits.length >= 10) {
329                 formattedValue += '-' + pastedDigits.substring(9, 11);
330             }
331             this.value = formattedValue;
332        });
333    }
334}
335
336
337
338// --- Инициализация маски для нового поля #userPhoneAuth ---
339//initializePhoneMask($userPhoneAuth);
340
341// --- Инициализация маски для нового поля #cont_phone ---
342// --- Ждём появления элемента ---
343    const phoneInputId = 'cont_phone';
344    const intervalId = setInterval(function() {
345        const $phoneInput = $('#' + phoneInputId);
346        if ($phoneInput.length && !$phoneInput.data('mask-initialized')) {
347            console.log("Элемент найден, инициализация маски для:", phoneInputId);
348            initializePhoneMask($phoneInput);
349            clearInterval(intervalId); // Останавливаем проверку, если элемент найден
350        }
351    }, 500); // Проверяем каждые 500 мс
352
353    // Можно добавить ограничение по времени, чтобы не проверять бесконечно
354    setTimeout(function() {
355        clearInterval(intervalId);
356        console.log("Таймаут ожидания элемента " + phoneInputId + " превышен.");
357    }, 3000); // Прекратить проверку через 3 секунды
358	
359
360    // Открытие модального окна (пример: при клике на кнопку или по условию)
361    // Вы можете вызывать showPhoneModal() в нужный момент
362    function showPhoneModal() {
363        $phoneModal.show();
364        // Сброс формы при открытии
365        $userPhone.val('');
366        // Устанавливаем placeholder заново, если поле пустое
367        if ($userPhone.val() === '') {
368             $userPhone.attr('placeholder', '+7 (___) ___-__-__');
369        }
370        hidePhoneError();
371    }
372
373    // Закрытие модального окна
374    $phoneClose.add($phoneModal).on('click', function (e) {
375        if (e.target === $phoneModal[0] || $(e.target).hasClass('close') || $(e.target).closest('.close').length) {
376            $phoneModal.hide();
377        }
378    });
379
380    // Показать ошибку
381    function showPhoneError(message) {
382        $phoneError.text(message).show();
383    }
384
385    // Скрыть ошибку
386    function hidePhoneError() {
387        $phoneError.hide();
388		//$phoneErrorAuth.hide();
389    }
390
391    // Валидация телефона
392 function validatePhone(phone) {
393        // Проверка на полноту: +7 (999) 999-99-99 - это 18 символов
394        // и должно содержать ровно 11 цифр, начинающихся с 7
395        const cleanPhone = phone.replace(/\D/g, '');
396        return phone.length === 18 && cleanPhone.length === 11 && cleanPhone.startsWith('7');
397    }
398
399// --- Функция для проверки чекбокса согласия ---
400function validateAgreementCheckbox(checkboxSelector, errorContainerSelector) {
401
402    const $checkbox = $(checkboxSelector);
403    const $errorContainer = $(errorContainerSelector);
404    const errorMessage = 'Пожалуйста, согласитесь с условиями использования и политикой конфиденциальности.';
405
406    if (!$checkbox.is(':checked')) {
407        // Если чекбокс не отмечен
408        if ($errorContainer.length) {
409            $errorContainer.text(errorMessage).show();
410        } else {
411            alert(errorMessage); // Запасной вариант
412        }
413        return false; // Валидация не пройдена
414    } else {
415        // Если чекбокс отмечен, скрываем ошибку
416        if ($errorContainer.length) {
417            $errorContainer.hide();
418        }
419        return true; // Валидация пройдена
420    }
421}
422// --- Конец функции ---	
423	
424	
425	// --- НОВАЯ Вспомогательная функция: Удаление флага авторизации/регистрации на сервере ---
426// Это предотвращает преждевременный успех check_phone_registration_status
427function deleteRedirectFlag(phone, successCallback, errorCallback) {
428    console.log("deleteRedirectFlag: Запрос на удаление флага для телефона:", phone);
429    // Получаем nonce для этой операции
430    $.ajax({
431        url: mains_ajax_object.ajax_url,
432        type: 'POST',
433        data: { 
434            action: 'get_phone_registration_nonce' // Используем существующий экшн
435        },
436        success: function(nonceResponse) {
437            console.log('deleteRedirectFlag: Nonce получен:', nonceResponse);
438            if (nonceResponse.success && nonceResponse.data.nonce) {
439                // Отправляем запрос на удаление флага
440                $.ajax({
441                    url: mains_ajax_object.ajax_url,
442                    type: 'POST',
443                    data: {
444                        action: 'delete_user_redirect_flag', // Новый экшн, который нужно добавить в functions.php
445                        phone: phone,
446                        nonce: nonceResponse.data.nonce
447                    },
448                    success: function(deleteResponse) {
449                        console.log('deleteRedirectFlag: Ответ от сервера:', deleteResponse);
450                        if (deleteResponse.success) {
451                            console.log("deleteRedirectFlag: Флаг успешно удален (или не существовал).");
452                            if (typeof successCallback === 'function') {
453                                successCallback();
454                            }
455                        } else {
456                            console.warn("deleteRedirectFlag: Ошибка при удалении флага:", deleteResponse.data?.message || 'Неизвестная ошибка');
457                            // Не критично, продолжаем процесс
458                            if (typeof successCallback === 'function') {
459                                successCallback();
460                            }
461                        }
462                    },
463                    error: function(xhr, status, error) {
464                        console.error('deleteRedirectFlag: Ошибка AJAX при удалении флага:', status, error);
465                        // Не критично, продолжаем процесс
466                        if (typeof successCallback === 'function') {
467                            successCallback();
468                        }
469                    }
470                });
471            } else {
472                console.error('deleteRedirectFlag: Не удалось получить nonce:', nonceResponse.data?.message || 'Неизвестная ошибка');
473                // Не критично, продолжаем процесс
474                if (typeof successCallback === 'function') {
475                    successCallback();
476                }
477            }
478        },
479        error: function(xhr, status, error) {
480            console.error('deleteRedirectFlag: Ошибка получения nonce:', status, error);
481            // Не критично, продолжаем процесс
482            if (typeof successCallback === 'function') {
483                successCallback();
484            }
485        }
486    });
487}
488// --- КОНЕЦ НОВОЙ Вспомогательной функции ---
489
490// --- Обработчик клика по кнопке отправки телефона (для оплаты и пробных кристаллов) ---
491// --- Использует sendZvonokCall и pollPhoneAuthStatus ---
492// --- Общий обработчик для #sendPhoneBtn и #sendPhoneBtnAuth ---
493$(document).on('click', '#sendPhoneBtn, #sendPhoneBtnAuth', function (e) {
494    e.preventDefault();
495
496    const $btn = $(this);
497    const originalBtnText = $btn.text();
498
499    // Определяем контекст на основе ID кнопки
500    let phoneInputSelector, modalSelector, checkboxSelector, errorContainerSelector;
501
502    if ($btn.is('#sendPhoneBtn')) {
503        phoneInputSelector = '#userPhone';
504        modalSelector = '#paymentModal';
505        checkboxSelector = '#custom-checkbox-reg';
506        errorContainerSelector = '#phoneError';
507    } else if ($btn.is('#sendPhoneBtnAuth')) {
508        phoneInputSelector = '#userPhoneAuth';
509        modalSelector = '#f_phone'; // Убедитесь, что #f_phone действительно является контейнером для #sendPhoneBtnAuth
510        checkboxSelector = '#custom-checkbox'; // Используем чекбокс для авторизации
511        errorContainerSelector = '#phoneErrorAuth'; // Используем контейнер ошибки для авторизации
512    } else {
513        console.error('Обработчик: Неизвестная кнопка вызвала событие:', $btn.attr('id'));
514        return; // Прекращаем выполнение, если кнопка неизвестна
515    }
516
517    const phone = $(phoneInputSelector).val().trim();
518    const $modal = $(modalSelector); // Контейнер модального окна, зависит от кнопки
519    const $errorContainer = $(errorContainerSelector); // Контейнер ошибки, зависит от кнопки
520    
521	const isAgreed = validateAgreementCheckbox(checkboxSelector, errorContainerSelector);
522    if (!isAgreed) {
523        // Если проверка не пройдена, останавливаем выполнение
524        return;
525    }
526	console.log(phoneInputSelector);
527    // --- Валидация и форматирование ---
528    hidePhoneError(); // Скрыть предыдущие ошибки
529
530	  if (typeof validatePhone !== 'function' || !validatePhone(phone)) {
531        const errorMsg = 'Пожалуйста, введите полный номер телефона.';
532        if ($errorContainer.length) {
533            $errorContainer.text(errorMsg).show();
534        } else {
535            alert(errorMsg);
536        }
537        // Кнопка будет разблокирована в onErrorCallback, если она там вызывается, или здесь:
538        $btn.prop('disabled', false).text(originalBtnText);
539        return; // Останавливаем выполнение при ошибке валидации
540    }
541	
542    const formattedPhone = '+7' + phone.replace(/\D/g, '').substring(1);
543    // --- Конец валидации ---
544
545    $btn.prop('disabled', true).text('Проверка...');
546
547    console.log("Начинаем проверку существования пользователя для телефона:", formattedPhone);
548
549    // --- Шаг 1: Получаем nonce для проверки пользователя ---
550    $.ajax({
551        url: mains_ajax_object.ajax_url,
552        type: 'POST',
553        data: {
554            action: 'get_phone_registration_nonce' // Используем существующий nonce action
555        },
556        success: function (nonceResponse) {
557            console.log('Nonce для проверки пользователя получен:', nonceResponse);
558            if (nonceResponse.success && nonceResponse.data.nonce) {
559
560                // --- Шаг 2: Проверяем, существует ли пользователь ---
561                $.ajax({
562                    url: mains_ajax_object.ajax_url,
563                    type: 'POST',
564                    data: {
565                        action: 'check_user_exists_by_phone',
566                        phone: formattedPhone,
567                        nonce: nonceResponse.data.nonce,
568                        // Передаем данные пакета
569                        package_id: window.currentPackageSelected ? window.currentPackageSelected.id : null,
570                        price: window.currentPackageSelected ? window.currentPackageSelected.price : null,
571                        amount: window.currentPackageSelected ? window.currentPackageSelected.amount : null
572                    },
573                    success: function (checkResponse) {
574                        console.log('Ответ проверки пользователя:', checkResponse);
575                        // Разблокируем кнопку, так как основная логика проверки завершена
576                        $btn.prop('disabled', false).text(originalBtnText);
577
578                        if (checkResponse.success) {
579                            if (checkResponse.data.user_exists) {
580                                // - ПОЛЬЗОВАТЕЛЬ НАЙДЕН -
581                                console.log('Пользователь найден.');
582
583                                // Определяем, является ли это пробными кристаллами
584                                const isTrial = window.currentPackageSelected &&
585                                    window.currentPackageSelected.price === 0 &&
586                                    window.currentPackageSelected.amount === 25;
587
588                                if (isTrial) {
589                                    // --- ЛОГИКА ДЛЯ ПРОБНЫХ КРИСТАЛЛОВ ---
590                                    console.log('Это пробные кристаллы. Начинаем авторизацию (отправку звонка для подтверждения).');
591                                    $btn.prop('disabled', true).text('Отправка звонка...');
592                                      
593									  
594									  // --- НОВОЕ: Шаг 1a: Удаляем старый флаг авторизации перед отправкой нового звонка ---
595                                   deleteRedirectFlag(formattedPhone, function() {
596                                   console.log("Старый флаг авторизации удален (или отсутствовал). Продолжаем отправку звонка.");
597						
598						
599                                    // --- Используем внешнюю универсальную функцию отправки звонка ---
600                                    const selectedPackage = window.currentPackageSelected || null;
601                                    sendZvonokCall(
602                                        formattedPhone,
603                                        selectedPackage, // Передаем данные пакета
604                                        // --- onSuccessCallback для sendZvonokCall ---
605                                        function(callResponse, nonceFromSendZvonok) { // nonceFromSendZvonok передается sendZvonokCall
606                                            console.log("Звонок для авторизации (пробные кристаллы) отправлен успешно.");
607
608                                            // Обновляем UI модального окна для состояния опроса
609                                            $modal.find('.modal-title').html(`<h2 class="modal-title">Звонок отправлен</h2>`);
610                                            $modal.find('.modal-description').text('Робот попросит нажать цифру, чтобы подтвердить ваш телефон');
611                                            // $modal.find('#userPhone').closest('.input-group').hide(); // ЗАМЕНЕНО
612                                            $(phoneInputSelector).closest('.input-group').hide();
613											// $modal.find('.checkbox-container').hide(); // ЗАМЕНЕНО
614											$(checkboxSelector).closest('.checkbox-container').hide();
615											
616                                            $btn.hide(); // Скрываем кнопку
617                                            // $('#phonePollingStatus').show().text('Ожидание подтверждения звонка...').css('color', '#007cba'); // ЗАМЕНЕНО
618                                            $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first().show().text('Ожидание подтверждения звонка...').css('color', '#007cba');
619
620                                            // --- Используем внешнюю универсальную функцию опроса авторизации ---
621                                            console.log("Звонок для авторизации (пробные кристаллы) отправлен успешно. Запуск универсального опроса.");
622
623                                            // Подготавливаем специфичные для #sendPhoneBtn параметры для pollPhoneAuthStatus
624                                            // const authPollingOptions = { // ЗАМЕНЕНО
625                                            const authPollingOptions = {
626                                                // statusElementSelector: '#phonePollingStatus', // Убедитесь, что ID правильный в #paymentModal // ЗАМЕНЕНО
627                                                statusElementSelector: '#phonePollingStatusAuth', // Используем правильный селектор для статуса в модалке авторизации
628                                                // modalContentSelector: '#paymentModal', // ЗАМЕНЕНО
629                                                modalContentSelector: modalSelector,
630                                                // phoneInputSelector: '#userPhone', // ЗАМЕНЕНО
631                                                phoneInputSelector: phoneInputSelector,
632                                                // buttonSelector: '#sendPhoneBtn', // ЗАМЕНЕНО
633                                                buttonSelector: '#' + $btn.attr('id'),
634                                                // Можно использовать параметры из старого #sendPhoneBtnAuth, если нужно больше времени:
635                                                // maxPolls: 60,
636                                                // pollIntervalTime: 5000,
637                                                onMaxAttempts: function () {
638                                                    // --- Специфичная логика возврата UI для #sendPhoneBtn ---
639                                                    console.log('Превышено максимальное количество попыток опроса авторизации (пробные кристаллы).');
640                                                    // const $modal = $('#paymentModal'); // ЗАМЕНЕНО - $modal уже определен выше
641                                                    // Возвращаем форму в исходное состояние
642                                                    setTimeout(() => {
643                                                        if ($modal.length) {
644                                                            $modal.find('.modal
644-title').html(`<h2 class="modal-title">Укажите номер телефона</h2>
645                                                                <p class="modal-description">На указанный номер моментально поступит звонок. Робот попросит нажать цифру, чтобы подтвердить ваш телефон</p>`);
646                                                            // $modal.find('#userPhone').closest('.input-group').show(); // ЗАМЕНЕНО
647                                                            $(phoneInputSelector).closest('.input-group').show();
648															// $modal.find('.checkbox-container').show(); // ЗАМЕНЕНО
649															$(checkboxSelector).closest('.checkbox-container').show();
650                                                            $btn.show().prop('disabled', false).text('Получить код подтверждения');
651                                                            // $('#userPhone').val(''); // ЗАМЕНЕНО
652                                                            $(phoneInputSelector).val('');
653                                                            // $('#phonePollingStatus').hide().text('').removeAttr('style'); // ЗАМЕНЕНО
654                                                            $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first().hide().text('').removeAttr('style');
655                                                        }
656                                                    }, 2000);
657                                                },
658                                                onError: function (xhr, status, error) {
659                                                    // Логика при ошибке AJAX
660                                                    console.warn('Ошибка AJAX в опросе авторизации #sendPhoneBtn (пробные кристаллы):', status, error);
661                                                }
662                                            };
663
664                                            // Запускаем универсальный опрос, передавая nonce, полученный в sendZvonokCall
665                                            // Предполагается, что nonceFromSendZvonok - это правильный nonce для check_phone_registration_status
666                                            pollPhoneAuthStatus(formattedPhone, nonceFromSendZvonok, authPollingOptions);
667                                            // --- Конец использования универсальной функции опроса ---
668
669                                        },
670                                        // --- onErrorCallback для sendZvonokCall ---
671                                        function (errorMsg) {
672                                            console.error("Ошибка отправки звонка для авторизации (пробные кристаллы):", errorMsg);
673                                            // showPhoneError(errorMsg); // ЗАМЕНЕНО
674                                            if ($errorContainer.length) {
675                                                $errorContainer.text(errorMsg).show();
676                                            } else {
677                                                alert(errorMsg);
678                                            }
679                                            $btn.prop('disabled', false).text(originalBtnText);
680                                            // Возвращаем форму в исходное состояние
681                                            $modal.find('.modal-title').html(`<h2 class="modal-title">Укажите номер телефона</h2>
682                                                <p class="modal-description">На указанный номер моментально поступит звонок. Робот попросит нажать цифру, чтобы подтвердить ваш телефон. После подтверждения не закрывайте это окно! Произойдет автоматическая авторизация!</p>`);
683                                            // $modal.find('#userPhone').closest('.input-group').show(); // ЗАМЕНЕНО
684                                            $(phoneInputSelector).closest('.input-group').show();
685											// $modal.find('.checkbox-container').show(); // ЗАМЕНЕНО
686											$(checkboxSelector).closest('.checkbox-container').show();
687                                            $btn.show().prop('disabled', false).text(originalBtnText);
688                                        }
689                                    );
690                                    // --- Конец использования sendZvonokCall ---
691                                 }, function(deleteError) {
692                        // Ошибка при удалении флага (редко бывает критичной)
693                        console.warn("Предупреждение: Ошибка при удалении старого флага авторизации:", deleteError);
694                        // Все равно продолжаем процесс, надеясь, что старый флаг не помешает
695                        // --- Шаг 2: Отправляем звонок для подтверждения ---
696                        sendZvonokCall(
697                            formattedPhone,
698                            null,
699                            function(callResponse, nonceForPolling) { /* ... логика onSuccess ... */ },
700                            function(errorMsg) { /* ... логика onError ... */ }
701                        );
702                        // --- Конец sendZvonokCall ---
703                    });
704                    // --- КОНЕЦ НОВОГО ---
705					
706                                } else {
707                                    // --- ЛОГИКА ДЛЯ ОБЫЧНЫХ ПАКЕТОВ (ПОЛЬЗОВАТЕЛЬ НАЙДЕН) ---
708                                    console.log('Это обычный пакет. Пользователь найден. Переход к оплате.');
709                                    // Скрываем модальное окно
710                                    $modal.hide();
711                                    // Переход к оплате
712                                    if (typeof showPaymentForm !== 'undefined') {
713                                        // Используем данные из checkResponse.data, так как они были получены на сервере
714                                        
715		const finalUserId = checkResponse.data.user_id;
716        const finalPrice = checkResponse.data.price !== undefined ? checkResponse.data.price : (window.currentPackageSelected ? window.currentPackageSelected.price : 0);
717        const finalAmount = checkResponse.data.amount !== undefined ? checkResponse.data.amount : (window.currentPackageSelected ? window.currentPackageSelected.amount : 0);
718        const finalPackageId = checkResponse.data.package_id !== undefined ? checkResponse.data.package_id : (window.currentPackageSelected ? window.currentPackageSelected.id : '');
719
720        showPaymentForm(finalUserId, finalPrice, finalAmount, finalPackageId);
721		
722		
723                                    } else {
724                                        console.error('Функция showPaymentForm не найдена.');
725                                        alert('Ошибка инициализации формы оплаты.');
726                                        // Восстанавливаем кнопку в исходное состояние
727                                        $btn.prop('disabled', false).text(originalBtnText);
728                                        showPhoneModal(); // Показываем модалку снова, если нужно
729                                    }
730                                }
731                            } else {
732                                // - ПОЛЬЗОВАТЕЛЬ НЕ НАЙДЕН, НУЖНА РЕГИСТРАЦИЯ -
733                                console.log('Пользователь не найден. Переход к регистрации (отправке звонка).');
734                                $btn.text('Отправка звонка...');
735
736                                // --- Используем внешнюю универсальную функцию отправки звонка ---
737                                const selectedPackage = window.currentPackageSelected || null;
738                                sendZvonokCall(
739                                    formattedPhone,
740                                    selectedPackage, // Передаем данные пакета
741                                    // --- onSuccessCallback для sendZvonokCall ---
742                                    function (callResponse, nonceFromSendZvonokReg) { // nonceFromSendZvonokReg передается sendZvonokCall
743                                        console.log("Звонок для регистрации отправлен успешно.");
744
745                                        // Обновляем UI модального окна для состояния опроса
746                                        $modal.find('.modal-title').html(`<h2 class="modal-title">Звонок отправлен</h2>`);
747                                        $modal.find('.modal-description').text('Робот попросит нажать цифру, чтобы подтвердить ваш телефон.После подтверждения не закрывайте это окно! Произойдет автоматическая авторизация!');
748                                        // $modal.find('#userPhone').closest('.input-group').hide(); // ЗАМЕНЕНО
749                                        $(phoneInputSelector).closest('.input-group').hide();
750										// $modal.find('.checkbox-container').hide(); // ЗАМЕНЕНО
751										$(checkboxSelector).closest('.checkbox-container').hide();
752                                        $btn.hide(); // Скрываем кнопку
753                                        // $('#phonePollingStatus').show().text('Ожидание подтверждения звонка...').css('color', '#007cba'); // ЗАМЕНЕНО
754                                        $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first().show().text('Ожидание подтверждения звонка...').css('color', '#007cba');
755
756                                        // --- Используем существующую функцию опроса регистрации ---
757                                        // Предполагается, что startRegistrationPolling существует и реализует логику
758                                        // с вызовом check_phone_registration_status и последующим начислением кристаллов/переходом к оплате
759										
760										const isTrial = (window.currentPackageSelected && window.currentPackageSelected.price === 0 && window.currentPackageSelected.amount === 25);
761                                        console.log("startRegistrationPolling: isTrial определен как:", isTrial, "для пакета:", window.currentPackageSelected, "в модальном окне:", $modal.selector);
762
763                                        startRegistrationPolling(formattedPhone, nonceFromSendZvonokReg, $modal, isTrial);
764										
765
766                                    },
767                                    // --- onErrorCallback для sendZvonokCall ---
768                                    function (errorMsg) {
769                                        console.error("Ошибка отправки звонка для регистрации:", errorMsg);
770                                        // showPhoneError(errorMsg); // ЗАМЕНЕНО
771                                        if ($errorContainer.length) {
772                                                $errorContainer.text(errorMsg).show();
773                                            } else {
774                                                alert(errorMsg);
775                                            }
776                                        $btn.prop('disabled', false).text(originalBtnText);
777                                        // Возвращаем форму в исходное состояние
778                                        $modal.find('.modal-title').html(`<h2 class="modal-title">Укажите номер телефона</h2>
779                                            <p class="modal-description">На указанный номер моментально поступит звонок. Робот попросит нажать цифру, чтобы подтвердить ваш телефон</p>`);
780                                        // $modal.find('#userPhone').closest('.input-group').show(); // ЗАМЕНЕНО
781                                        $(phoneInputSelector).closest('.input-group').show();
782										// $modal.find('.checkbox-container').show(); // ЗАМЕНЕНО
783										$(checkboxSelector).closest('.checkbox-container').show();
784                                        $btn.show().prop('disabled', false).text(originalBtnText);
785                                    }
786                                );
787                                // --- Конец использования sendZvonokCall ---
788                            }
789                        } else {
790                            // --- Ошибка от сервера при проверке пользователя ---
791                            console.error('Ошибка проверки пользователя:', checkResponse.data.message);
792                            // showPhoneError(checkResponse.data.message || 'Ошибка проверки пользователя.'); // ЗАМЕНЕНО
793                            if ($errorContainer.length) {
794                                $errorContainer.text(checkResponse.data.message || 'Ошибка проверки пользователя.').show();
795                            } else {
796                                alert(checkResponse.data.message || 'Ошибка проверки пользователя.');
797                            }
798                            $btn.prop('disabled', false).text(originalBtnText);
799                        }
800                    },
801                    error: function (xhr, status, error) {
802                        console.error('AJAX ошибка (check_user_exists_by_phone):', status, error);
803                        // showPhoneError('Ошибка соединения при проверке пользователя.'); // ЗАМЕНЕНО
804                        if ($errorContainer.length) {
805                                $errorContainer.text('Ошибка соединения при проверке пользователя.').show();
806                            } else {
807                                alert('Ошибка соединения при проверке пользователя.');
808                            }
809                        $btn.prop('disabled', false).text(originalBtnText);
810                    }
811                });
812                // --- Конец шага 2 ---
813
814            } else {
815                console.error('Не удалось получить nonce для проверки пользователя:', nonceResponse);
816                // showPhoneError('Ошибка безопасности при проверке пользователя.'); // ЗАМЕНЕНО
817                if ($errorContainer.length) {
818                                $errorContainer.text('Ошибка безопасности при проверке пользователя.').show();
819                            } else {
820                                alert('Ошибка безопасности при проверке пользователя.');
821                            }
822                $btn.prop('disabled', false).text(originalBtnText);
823            }
824        },
825        error: function (xhr, status, error) {
826            console.error('Ошибка получения nonce для проверки пользователя:', xhr, status, error);
827            // showPhoneError('Ошибка соединения (получение nonce для проверки).'); // ЗАМЕНЕНО
828            if ($errorContainer.length) {
829                                $errorContainer.text('Ошибка соединения (получение nonce для проверки).').show();
830                            } else {
831                                alert('Ошибка соединения (получение nonce для проверки).');
832                            }
833            $btn.prop('disabled', false).text(originalBtnText);
834        }
835    });
836    // --- Конец шага 1 ---
837});
838// --- Конец обработчика #sendPhoneBtn ---
839
840
841// --- Глобальная функция для перехода к оплате (вызывается из PHP/постбэка) ---
842
843window.redirectToPayment = function(userId, packageId, price, amount) {
844    // Эта функция вызывается из обработчика постбэка после успешной регистрации
845    console.log('Переход к оплате для пользователя (без email):', userId, {packageId, price, amount});
846
847    // --- НОВОЕ: Используем данные пакета из window.currentPackageSelected, игнорируя аргументы ---
848    let finalPrice, finalAmount;
849    if (typeof window.currentPackageSelected !== 'undefined' && window.currentPackageSelected) {
850        finalPrice = window.currentPackageSelected.price;
851        finalAmount = window.currentPackageSelected.amount;
852        console.log('Используем данные пакета из window.currentPackageSelected (игнорируем аргументы):', {finalPrice, finalAmount});
853    } else {
854        // Если по какой-то причине переменная не найдена, пытаемся использовать переданные значения
855        // (на случай, если логика изменится в будущем)
856        console.warn('window.currentPackageSelected не найден. Пытаемся использовать переданные значения:', {price, amount});
857        finalPrice = (price !== undefined && price > 0) ? price : 0;
858        finalAmount = (amount !== undefined && amount > 0) ? amount : 0;
859        if (finalPrice === 0 || finalAmount === 0) {
860            console.error('Не удалось определить корректные price или amount ни из window.currentPackageSelected, ни из аргументов!');
861        }
862    }
863    // --- КОНЕЦ НОВОГО ---
864
865    // Проверяем, существует ли функция showPaymentForm
866    if (typeof showPaymentForm !== 'undefined') {
867        console.log('Вызываем showPaymentForm напрямую (без email).');
868        // Скрываем модальное окно с телефоном, если оно еще открыто
869        if (typeof $phoneModal !== 'undefined') {
870            $phoneModal.hide();
871        }
872
873        // --- ИЗМЕНЕНО: Передаем userId и данные пакета, полученные выше ---
874        showPaymentForm(userId, finalPrice, finalAmount);
875        // --- КОНЕЦ ИЗМЕНЕНИЙ ---
876    } else {
877        console.error('Функция showPaymentForm не найдена.');
878        alert('Ошибка: форма оплаты недоступна. Пожалуйста, перезагрузите страницу.');
879    }
880};
881// --- КОНЕЦ Глобальной функции ---
882
883
884// --- Универсальная функция для проверки существования пользователя по телефону ---
885// Параметры:
886// - phone: Нормализованный номер телефона (+7XXXXXXXXXX)
887// - successCallback: Функция, вызываемая при успешном ответе от сервера.
888//                    Принимает объект ответа, например: {success: true, data: {user_exists: true, user_id: 123}}
889// - errorCallback: Функция, вызываемая при ошибке AJAX или другой критической ошибке.
890//                  Принимает объект ошибки или строку сообщения.
891function checkUserExists(phone, successCallback, errorCallback) {
892    if (!phone || typeof phone !== 'string') {
893        console.error('checkUserExists: Неверный формат номера телефона.');
894        if (typeof errorCallback === 'function') {
895            errorCallback('Неверный формат номера телефона.');
896        }
897        return;
898    }
899
900    console.log("Начинаем проверку существования пользователя для телефона:", phone);
901
902    // --- Шаг 1: Получить nonce ---
903    $.ajax({
904        url: mains_ajax_object.ajax_url,
905        type: 'POST',
906        data: {
907            action: 'get_phone_registration_nonce'
908        },
909        success: function(nonceResponse) {
910            console.log('Nonce для проверки пользователя получен:', nonceResponse);
911            if (nonceResponse.success && nonceResponse.data.nonce) {
912                
913                // --- Шаг 2: Проверить существование пользователя ---
914                $.ajax({
915                    url: mains_ajax_object.ajax_url,
916                    type: 'POST',
917                    data: {
918                        action: 'check_user_exists_by_phone',
919                        phone: phone,
920                        nonce: nonceResponse.data.nonce
921                        // Примечание: package_id, price, amount Ð
921½Ðµ передаются, так как не нужны для этой проверки
922                    },
923                    success: function(checkResponse) {
924                        console.log('Ответ проверки пользователя:', checkResponse);
925                        // Передаем ответ в successCallback, независимо от checkResponse.success
926                        // Логика обработки checkResponse.success будет внутри successCallback
927                        if (typeof successCallback === 'function') {
928                            successCallback(checkResponse);
929                        }
930                    },
931                    error: function(xhr, status, error) {
932                        console.error('AJAX ошибка (check_user_exists_by_phone):', status, error);
933                        if (typeof errorCallback === 'function') {
934                            errorCallback('Ошибка соединения при проверке пользователя.');
935                        }
936                    }
937                });
938                // --- КОНЕЦ ШАГА 2 ---
939                
940            } else {
941                const errorMsg = nonceResponse.data?.message || 'Ошибка безопасности при проверке пользователя (не удалось получить nonce).';
942                console.error('Не удалось получить nonce для проверки пользователя:', errorMsg);
943                if (typeof errorCallback === 'function') {
944                    errorCallback(errorMsg);
945                }
946            }
947        },
948        error: function(xhr, status, error) {
949            console.error('Ошибка получения nonce для проверки пользователя:', xhr, status, error);
950            if (typeof errorCallback === 'function') {
951                errorCallback('Ошибка соединения (получение nonce для проверки).');
952            }
953        }
954    });
955    // --- КОНЕЦ Шага 1 ---
956}
957
958// --- Универсальная функция для отправки звонка через Zvonok ---
959// Параметры:
960// - phone: Нормализованный номер телефона (+7XXXXXXXXXX)
961// - packageData: (Опционально) Объект с данными пакета {id, price, amount} для сохранения в transient
962// - successCallback: Функция, вызываемая при успешной отправке звонка.
963//                    Принимает объект ответа, например: {success: true, data: {call_id: "..."}}
964// - errorCallback: Функция, вызываемая при ошибке AJAX или другой критической ошибке.
965//                  Принимает объект ошибки или строку сообщения.
966function sendZvonokCall(phone, packageData, successCallback, errorCallback) {
967     if (!phone || typeof phone !== 'string') {
968        console.error('sendZvonokCall: Неверный формат номера телефона.');
969        if (typeof errorCallback === 'function') {
970            errorCallback('Неверный формат номера телефона.');
971        }
972        return;
973    }
974    
975    // Получаем nonce для отправки звонка
976    $.ajax({
977        url: mains_ajax_object.ajax_url,
978        type: 'POST',
979        data: {
980            action: 'get_phone_registration_nonce' // Используем тот же экшн для получения nonce
981        },
982        success: function(nonceResponse) {
983            console.log('Nonce для отправки звонка получен:', nonceResponse);
984            if (nonceResponse.success && nonceResponse.data.nonce) {
985                
986                // Подготавливаем данные для отправки звонка
987                var requestData = {
988                    action: 'send_zvonok_call',
989                    phone: phone,
990                    nonce: nonceResponse.data.nonce
991                };
992                
993                // Добавляем данные пакета, если они переданы
994                if (packageData && typeof packageData === 'object') {
995                    requestData.package_id = packageData.id || null;
996                    requestData.price = packageData.price || null;
997                    requestData.amount = packageData.amount || null;
998                }
999
1000                // Отправляем звонок
1001                $.ajax({
1002                    url: mains_ajax_object.ajax_url,
1003                    type: 'POST',
1004                    data: requestData,
1005                    success: function(callResponse) {
1006                        console.log('Ответ от send_zvonok_call:', callResponse);
1007                        if (callResponse.success && callResponse.data.call_id) {
1008                            // Успешно отправлено
1009                            if (typeof successCallback === 'function') {
1010                                successCallback(callResponse, nonceResponse.data.nonce);
1011                            }
1012                        } else {
1013                            // Ошибка от сервера при отправке звонка
1014                            const errorMsg = callResponse.data?.message || 'Произошла ошибка при отправке звонка.';
1015                            console.error('Ошибка от send_zvonok_call:', errorMsg);
1016                            if (typeof errorCallback === 'function') {
1017                                errorCallback(errorMsg);
1018                            }
1019                        }
1020                    },
1021                    error: function(xhr, status, error) {
1022                        console.error('AJAX ошибка (send_zvonok_call):', status, error);
1023                        if (typeof errorCallback === 'function') {
1024                            errorCallback('Произошла ошибка соединения. Пожалуйста, попробуйте позже.');
1025                        }
1026                    }
1027                });
1028                
1029            } else {
1030                const errorMsg = nonceResponse.data?.message || 'Ошибка безопасности при отправке звонка (не удалось получить nonce).';
1031                console.error('Не удалось получить nonce для отправки звонка:', errorMsg);
1032                if (typeof errorCallback === 'function') {
1033                    errorCallback(errorMsg);
1034                }
1035            }
1036        },
1037        error: function(xhr, status, error) {
1038            console.error('Ошибка получения nonce для отправки звонка:', xhr, status, error);
1039            if (typeof errorCallback === 'function') {
1040                errorCallback('Ошибка соединения (получение nonce для отправки звонка).');
1041            }
1042        }
1043    });
1044}
1045
1046
1047// --- Функция для запуска опроса статуса регистрации и выполнения последующих действий ---
1048// Эта функция используется, когда новый пользователь подтверждает звонок для регистрации.
1049// После подтверждения нужно либо начислить пробные кристаллы, либо перейти Ð
1049º форме оплаты.
1050// --- ИЗМЕНЕНАЯ ФУНКЦИЯ: startRegistrationPolling принимает $modal и isTrial ---
1051// phone: Нормализованный номер телефона
1052// nonce: Nonce для проверки статуса
1053// $modalOverride: jQuery объект модального окна (опционально, если не передан, использует $('#paymentModal'))
1054// isTrialOverride: Булевое значение, указывающее, является ли пакет пробными кристаллами (опционально, если не передан, пытается определить из $modal.data('isTrialAward'))
1055function startRegistrationPolling(phone, nonce, $modalOverride, isTrialOverride) {
1056    console.log(`startRegistrationPolling: Начало опроса статуса регистрации для ${phone}.`);
1057    console.log("startRegistrationPolling: DEBUG POINT 1: После начального лога");
1058
1059    // Используем переданный модал или дефолтный
1060    const $modal = $modalOverride || $('#paymentModal');
1061    console.log("startRegistrationPolling: DEBUG POINT 2: $modal найден?", $modal.length > 0);
1062    console.log("startRegistrationPolling: Используем модальное окно:", $modal.selector);
1063
1064    // Используем переданный isTrial или пытаемся получить из данных модального окна (для совместимости)
1065    // ВАЖНО: isTrialOverride должен быть вычислен до вызова startRegistrationPolling, чтобы избежать гонки с showPaymentForm
1066    const isTrial = (isTrialOverride !== undefined) ? isTrialOverride : ($modal.data('isTrialAward') || false);
1067    console.log("startRegistrationPolling: DEBUG POINT 3: isTrial =", isTrial);
1068    console.log("startRegistrationPolling: Используем isTrial (аргумент или из модала):", isTrial);
1069
1070    // Получаем данные пакета из данных модального окна (если были установлены) или из глобальной переменной
1071    // Пытаемся получить из модального окна, если оно было передано и содержит данные
1072    const selectedPackageFromModal = $modalOverride ? $modalOverride.data('selectedPackage') : null;
1073    // Используем глобальную переменную как резервный вариант
1074    const selectedPackage = selectedPackageFromModal || window.currentPackageSelected || null;
1075    console.log("startRegistrationPolling: DEBUG POINT 4: selectedPackage =", selectedPackage);
1076
1077    // Обновляем UI модального окна для состояния опроса (на всякий случай)
1078    console.log("startRegistrationPolling: DEBUG POINT 5: Начало обновления UI");
1079    try {
1080        $modal.find('.modal-title').html(`<h2 class="modal-title">Звонок отправлен</h2>`);
1081        $modal.find('.modal-description').text('Робот попросит нажать цифру, чтобы подтвердить ваш телефон.');
1082        // $modal.find('#userPhone').closest('.input-group').hide(); // УДАЛЕНО
1083        // $modal.find('.checkbox-container').hide(); // УДАЛЕНО
1084        // $('#sendPhoneBtn').hide(); // УДАЛЕНО - используем переменную $btn из вызывающего кода
1085        // const $statusElement = $('#phonePollingStatus'); // УДАЛЕНО
1086        const $statusElement = $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first(); // ИСПОЛЬЗУЕМ ПЕРЕДАННЫЙ $MODAL
1087        if ($statusElement.length) {
1088           // $statusElement.show().text('Ожидание подтверждения звонка...').css('color', '#007cba');
1089        }
1090        console.log("startRegistrationPolling: DEBUG POINT 6: UI обновлен успешно");
1091    } catch (uiError) {
1092        console.error("startRegistrationPolling: Ошибка при обновлении UI:", uiError);
1093    }
1094
1095    // --- Логика опроса ---
1096    console.log("startRegistrationPolling: DEBUG POINT 7: Инициализация переменных опроса");
1097    let pollInterval;
1098    let pollCount = 0;
1099    const maxPolls = 120; // Или возьмите из настроек
1100    const pollIntervalTime = 2000; // Или возьмите из настроек (5 секунд)
1101
1102    console.log("startRegistrationPolling: DEBUG POINT 8: Определение функции internalCheckReg
1102istrationStatus");
1103    function internalCheckRegistrationStatus() {
1104        console.log(`startRegistrationPolling: internalCheckRegistrationStatus: Вызов функции опроса №${pollCount + 1}/${maxPolls}...`);
1105        
1106        if (pollCount >= maxPolls) {
1107            console.log("startRegistrationPolling: internalCheckRegistrationStatus: Достигнут лимит попыток");
1108            clearInterval(pollInterval);
1109            // const $statusElement = $('#phonePollingStatus'); // УДАЛЕНО
1110            const $statusElement = $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first(); // ИСПОЛЬЗУЕМ ПЕРЕДАННЫЙ $MODAL
1111            if ($statusElement.length) {
1112                $statusElement.text('Превышено время ожидания подтверждения регистрации. Пожалуйста, попробуйте еще раз.').css('color', 'red');
1113            }
1114            // Возвращаем форму в исходное состояние
1115            // setTimeout(() => { // УДАЛЕНО - восстановление UI лучше в вызывающем коде
1116            //     $modal.find('.modal-title').html(`<h2 class="modal-title">Укажите номер телефона</h2>
1117            //         <p class="modal-description">На указанный номер моментально поступит звонок. Робот попросит нажать цифру, чтобы подтвердить ваш телефон</p>`);
1118            //     $modal.find('#userPhone').closest('.input-group').show();
1119			// 	$modal.find('.checkbox-container').show();
1120			// 	$('#sendPhoneBtn').show().prop('disabled', false).text('Получить код подтверждения');
1121            //     $('#userPhone').val('');
1122            //     if($('#phonePollingStatus').length) $('#phonePollingStatus').hide().text('').removeAttr('style');
1123            // }, 2000);
1124            return;
1125        }
1126
1127        pollCount++;
1128        console.log("startRegistrationPolling: internalCheckRegistrationStatus: pollCount увеличен до", pollCount);
1129
1130        $.ajax({
1131            url: mains_ajax_object.ajax_url,
1132            type: 'POST',
1133            data: {
1134                action: 'check_phone_registration_status', // Используем тот же экшн
1135                phone: phone,
1136                nonce: nonce
1137            },
1138            success: function(statusResponse) {
1139                console.log('startRegistrationPolling: internalCheckRegistrationStatus: Ответ от check_phone_registration_status:', statusResponse);
1140                try {
1141                    // const $statusElement = $('#phonePollingStatus'); // УДАЛЕНО
1142                    const $statusElement = $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first(); // ИСПОЛЬЗУЕМ ПЕРЕДАННЫЙ $MODAL
1143                    
1144                    if (statusResponse.success && statusResponse.data && statusResponse.data.user_id) {
1145                        // --- РЕГИСТРАЦИЯ ПОДТВЕРЖДЕНА ---
1146                        console.log('startRegistrationPolling: internalCheckRegistrationStatus: Регистрация подтверждена! Выполняем последующие действия...');
1147                        clearInterval(pollInterval);
1148                        ym(104015232,'reachGoal','rega');
1149						
1150                        if (isTrial) {
1151                            // --- Для пробных кристаллов: Начисляем кристаллы ---
1152                            console.log("startRegistrationPolling: internalCheckRegistrationStatus: Это пробные кристаллы. Начисляем 25 кристаллов.");
1153                            if ($statusElement.length) {
1154                                $statusElement.text('Регистрация подтверждена! Начисление кристаллов...').css('color', 'green');
1155                            }
1156
1157                             //console.log("startRegistrationPolling: internalCheckReg
1157istrationStatus: Подготовка AJAX-запроса к award_trial_crystals.");
1158                              //console.log("startRegistrationPolling: internalCheckRegistrationStatus: mains_ajax_object.award_trial_crystals_nonce перед отправкой:", mains_ajax_object.award_trial_crystals_nonce);
1159                          
1160// --- ИСПРАВЛЕНО: Используем секрет из mains_ajax_object ---
1161let secretPart = 'fallback_secret'; // Значение по умолчанию на случай ошибки
1162if (mains_ajax_object && mains_ajax_object.simple_secret) {
1163    secretPart = mains_ajax_object.simple_secret;
1164    console.log("startRegistrationPolling: internalCheckRegistrationStatus: Используем 'секрет' из mains_ajax_object:", secretPart);
1165} else {
1166    console.warn("startRegistrationPolling: internalCheckRegistrationStatus: 'simple_secret' не найден в mains_ajax_object. Используется значение по умолчанию.");
1167}
1168// --- КОНЕЦ ИСПРАВЛЕНИЯ ---
1169
1170// 2. Получаем timestamp
1171const currentTimestamp = Math.floor(Date.now() / 1000); // В секундах
1172console.log("startRegistrationPolling: internalCheckRegistrationStatus: Текущий timestamp:", currentTimestamp);
1173
1174// 3. Получаем user_id (предполагается, что он есть в statusResponse)
1175const userIdForToken = statusResponse.data.user_id || 0;
1176console.log("startRegistrationPolling: internalCheckRegistrationStatus: user_id для токена:", userIdForToken);
1177
1178// 4. Генерируем "токен" по той же логике, что и в PHP
1179// data_to_hash = secret_part . 'award_trial_crystals' . user_id . timestamp
1180const dataToHash = secretPart + 'award_trial_crystals' + userIdForToken + currentTimestamp;
1181console.log("startRegistrationPolling: internalCheckRegistrationStatus: Данные для генерации токена:", dataToHash);
1182
1183
1184// 5. Простая "хэш-функция" (имитация md5)
1185// Используем встроенную функцию Web Crypto API для SHA
1185-256
1186// Это современный и безопасный способ, не требующий внешних библиотек.
1187
1188async function generateSimpleToken(data) {
1189  const msgUint8 = new TextEncoder().encode(data);
1190  const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8);
1191  const hashArray = Array.from(new Uint8Array(hashBuffer));
1192  // Преобразуем в шестнадцатеричную строку и берем первые 12 символов (как в PHP)
1193  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
1194  return hashHex.substring(0, 12);
1195}
1196
1197// --- КОНЕЦ ГЕНЕРАЦИИ ПОЛЬЗОВАТЕЛЬСКОГО ТОКЕНА ---
1198
1199// --- ОТПРАВКА AJAX С ТОКЕНОМ ---
1200generateSimpleToken(dataToHash).then(tokenToUse => {
1201    console.log("startRegistrationPolling: internalCheckRegistrationStatus: Сгенерированный токен:", tokenToUse);
1202
1203                            // Вызываем AJAX для начисления кристаллов
1204                            $.ajax({
1205                                url: mains_ajax_object.ajax_url,
1206                                type: 'POST',
1207                                dataType: 'json',
1208                                data: {
1209                                    action: 'award_trial_crystals',
1210									//nonce: mains_ajax_object.award_trial_crystals_nonce, 
1211									 token: tokenToUse,
1212                                     timestamp: currentTimestamp,
1213                                     // user_id: statusResponse.data.user_id
1214									 user_id: userIdForToken
1215                                },
1216                                success: function(crystalResponse) {
1217                                    console.log('startRegistrationPolling: internalCheckRegistrationStatus: Кристаллы начислены:', crystalResponse);
1218                                    if(crystalResponse.success) {
1219                                        if ($statusElement.length) {
1220                                            $statusElement.text('Кристаллы начислены! Перезагрузка...').css('color', 'green');
1221                                        }
1222                                        // Обновляем баланс на странице перед перезагрузкой
1223                                        if($('.balance .kol_kristall').length > 0 && crystalResponse.data.new_balance !== undefined) {
1224                                             $('.balance .kol_kristall').text(crystalResponse.data.new_balance);
1225                                        }
1226                                        // Перенаправляем на главную
1227                                       /* setTimeout(function() {
1228                                            window.location.href = '/';
1229                                        }, 1500);*/
1230										
1231										$modal.find('.modal-title').html(`<h2 class="modal-title">Авторизуемся</h2>`);
1232                                        $modal.find('.modal-description').text('Ожидаем авторизацию...');
1233										$modal.find('.close').hide();
1234										$modal.find('#phonePollingStatus, #phonePollingStatusAuth').first().hide().text('').removeAttr('style');
1235										 
1236                                        // Обновляем страницу
1237                                        setTimeout(function() {
1238                                            window.location.reload();
1239                                        }, 3000);
1240										
1241                                    } else {
1242                                        console.error('startRegistrationPolling: internalCheckRegistrationStatus: Ошибка при начислении кристаллов после регистрации:', crystalResponse.data.message);
1243                                        if ($statusElement.length) {
1244                                            $statusElement.text(crystalResponse.data.message || 'Ошибка при начислении кристаллов после регистрации.').css('color', 'red');
1245                                        }
1246                                        $modal.hide();
1247                                    }
1248                                },
1249                                error: function(xhr, status, error) {
1250                                    console.error('startRegistrationPolling: internalCheckReg
1250istrationStatus: AJAX ошибка при начислении кристаллов после регистрации:', status, error);
1251                                    if ($statusElement.length) {
1252                                         $statusElement.text('Ошибка соединения при начислении кристаллов.').css('color', 'red');
1253                                    }
1254                                    $modal.hide();
1255                                }
1256                            });
1257                        }).catch(err => {
1258    console.error('startRegistrationPolling: internalCheckRegistrationStatus: Ошибка генерации токена:', err);
1259    const $statusElement = $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first(); // ИСПОЛЬЗУЕМ ПЕРЕДАННЫЙ $MODAL
1260    if ($statusElement.length) {
1261        $statusElement.text('Ошибка безопасности (Не удалось сгенерировать токен).').css('color', 'red');
1262    }
1263                        });
1264
1265						}  else {
1266                            // --- Для обычных пакетов: Переход к оплате ---
1267                            console.log("startRegistrationPolling: internalCheckRegistrationStatus: Это обычная оплата. Переход к форме оплаты.");
1268                            if ($statusElement.length) {
1269                                $statusElement.text('Регистрация подтверждена! Переход к оплате...').css('color', 'green');
1270                            }
1271
1272                            // Закрываем модалку
1273                            $modal.hide();
1274
1275                            // Переход к оплате
1276                            const finalUserId = statusResponse.data.user_id;
1277                            const finalPackageId = statusResponse.data.package_id || selectedPackage?.id || '';
1278                            const finalPrice = statusResponse.data.price || selectedPackage?.price || 0;
1279                            const finalAmount = statusResponse.data.amount || selectedPackage?.amount || 0;
1280
1281                            if (typeof showPaymentForm !== 'undefined') {
1282                               showPaymentForm(
1283        finalUserId,    // 1-й аргумент: ID пользователя (число)
1284        finalPrice,     // 2-й аргумент: Цена (число)
1285        finalAmount,    // 3-й аргумент: Количество (число)
1286        finalPackageId  // 4-й аргумент: ID пакета (строка или число)
1287    );
1288                            } else {
1289                                console.error('startRegistrationPolling: internalCheckRegistrationStatus: Функция showPaymentForm не определена.');
1290                                alert('Ошибка: форма оплаты недоступна.');
1291                            }
1292                        }
1293                    } else if (statusResponse.success) {
1294                         // success: true, но user_id нет
1295                         console.log('startRegistrationPolling: internalCheckRegistrationStatus: Промежуточный статус (success=true, no user_id):', statusResponse.data?.message || 'Ожидание...');
1296                         if ($statusElement.length) {
1297                             $statusElement.text(statusResponse.data?.message || 'Ожидание подтверждения звонка...').css('color', 'orange');
1298                         }
1299                    } else if (statusResponse.data && statusResponse.data.message) {
1300                        // success: false, но есть сообщение об ошибке
1301                        console.warn('startRegistrationPolling: internalCheckRegistrationStatus: Ошибка от сервера (success=false):', statusResponse.data.message);
1302                        if ($statusElement.length) {
1303                            $statusElement.text(statusResponse.data.message).css('color', 'red');
1304                        }
1305                    } else {
1306                        // Неожиданный формат ответа
1307                        console.warn('startRegistrationPolling: internalCheckReg
1307istrationStatus: Неожиданный формат ответа:', statusResponse);
1308                        if ($statusElement.length) {
1309                            //$statusElement.text('Неожиданный ответ от сервера. Повтор...').css('color', 'orange');
1310                        }
1311                    }
1312                } catch (processingError) {
1313                    console.error('startRegistrationPolling: internalCheckRegistrationStatus: Ошибка обработки ответа опроса регистрации:', processingError);
1314                }
1315            },
1316            error: function(xhr, status, error) {
1317                console.error('startRegistrationPolling: internalCheckRegistrationStatus: AJAX ошибка при опросе статуса регистрации:', status, error);
1318                // Не останавливаем опрос при ошибке соединения, продолжаем
1319                // const $statusElement = $('#phonePollingStatus'); // УДАЛЕНО
1320                const $statusElement = $modal.find('#phonePollingStatus, #phonePollingStatusAuth').first(); // ИСПОЛЬЗУЕМ ПЕРЕДАННЫЙ $MODAL
1321                if ($statusElement.length) {
1322                    var originalText = $statusElement.text();
1323                    var originalColor = $statusElement.css('color');
1324                    $statusElement.text('Ошибка соединения при опросе статуса. Повтор...').css('color', 'red');
1325                    setTimeout(() => {
1326                        if($statusElement.length && $statusElement.text().includes('Ошибка соединения')) {
1327                            $statusElement.text(originalText).css('color', originalColor);
1328                        }
1329                    }, 1500);
1330                }
1331            }
1332        });
1333    }
1334    console.log("startRegistrationPolling: DEBUG POINT 9: Функция internalCheckRegistrationStatus определена");
1335
1336    // Запуск опроса
1337    console.log('startRegistrationPolling: DEBUG POINT 10: Запуск опроса...');
1338    pollInterval = setInterval(internalCheckRegistrationStatus, pollIntervalTime);
1339    // Первая проверка чуть позже
1340    setTimeout(() => {
1341        console.log('startRegistrationPolling: DEBUG POINT 11: Запуск первой проверки через setTimeout');
1342        internalCheckRegistrationStatus();
1343    }, 1000); 
1344    console.log('startRegistrationPolling: DEBUG POINT 12: setInterval и setTimeout установлены');
1345}
1346
1347// --- Конец функции startRegistrationPolling ---
1348
1349
1350// --- Универсальная функция для опроса статуса авторизации после звонка ---
1351// Параметры:
1352// - phone: Нормализованный номер телефона (+7XXXXXXXXXX)
1353// - nonce: Nonce, полученный ранее
1354// - options: Объект с настройками
1355//   - statusElementSelector: Селектор элемента для отображения промежуточных сообщений (например, '#phonePollingStatus' или '#phonePollingStatusAuth')
1356//   - modalContentSelector: Селектор контейнера модального окна для обновления заголовка/описания/скрытия полей (например, '#paymentModal' или '.auth-container')
1357//   - phoneInputSelector: Селектор поля ввода телефона для скрытия/очистки (например, '#userPhone' или '#userPhoneAuth')
1358//   - buttonSelector: Селектор кнопки для скрытия/разблокировки (например, '#sendPhoneBtn' или '#sendPhoneBtnAuth')
1359//   - maxPolls: (Опционально) Максимальное количество попыток (по умолчанию 20)
1360//   - pollIntervalTime: (Опционально) Интервал между попытками в мс (по умолчанию 3000)
1361//   - onMaxAttempts: (Опционально) Функция, вызываемая при превышении попыток
1362//   - onError: (Опционально) Функция, вызываемая при ошибке AJAX
1363function pollPhoneAuthStatus(phone, nonce, options) {
1364    // Значения по умолчанию
1365    const defaults = {
1366        statusElementSelector: '#phonePollingStatus',
1367        modalContentSelector: '#paymentModal',
1368        phoneInputSelector: '#userPhone',
1369        buttonSelector: '#sendPhoneBtn',
1370        maxPolls: 120, // Можно сделать 60, если хотите больше времени, как в #sendPhoneBtnAuth
1371        pollIntervalTime: 2000, // Можно сделать 5000, как в #sendPhoneBtnAuth
1372        onMaxAttempts: function () {
1373            console.log('Универсальный опрос: Превышено максимальное количество попыток.');
1374        },
1375        onError: function (xhr, status, error) {
1376            console.error('Универсальный опрос: Ошибка AJAX:', status, error);
1377        }
1378    };
1379    const settings = Object.assign({}, defaults, options);
1380
1381    let pollCount = 0;
1382    let pollInterval;
1383    const $statusElement = $(settings.statusElementSelector);
1384    const $modalContent = $(settings.modalContentSelector);
1385    const $phoneInput = $(settings.phoneInputSelector);
1386    const $btn = $(settings.buttonSelector);
1387
1388    console.log(`Запуск универсального опроса статуса авторизации для ${phone}...`);
1389
1390    function internalCheckStatus() {
1391        if (pollCount >= settings.maxPolls) {
1392            clearInterval(pollInterval);
1393            console.log(`Универсальный опрос: Превышено максимальное количество попыток (${settings.maxPolls}).`);
1394            if ($statusElement.length) {
1395                $statusElement.text('Превышено время ожидания подтверждения. Пожалуйста, попробуйте еще раз.').css('color', 'red');
1396            }
1397            // Вызываем пользовательский колбэк при превышении попыток
1398            settings.onMaxAttempts();
1399            return;
1400        }
1401
1402        console.log(`Универсальный опрос: Попытка ${pollCount + 1}/${settings.maxPolls}...`);
1403        pollCount++;
1404
1405        $.ajax({
1406            url: mains_ajax_object.ajax_url,
1407            type: 'POST',
1408            data: {
1409                action: 'check_phone_registration_status',
1410                phone: phone,
1411                nonce: nonce
1412            },
1413            success: function (statusResponse) {
1414                console.log('Универсальный опрос: Ответ от check_phone_registration_status:', statusResponse);
1415                try {
1416                    // --- УНИВЕРСАЛЬНАЯ ПРОВЕРКА УСПЕХА ---
1417                    // Успех определяется по statusResponse.success === true И наличию user_id в data
1418                    if (statusResponse.success && statusResponse.data && statusResponse.data.user_id
1418) {
1419                        console.log('Универсальный опрос: Авторизация/регистрация подтверждена! Подготовка к перезагрузке...');
1420                        clearInterval(pollInterval);
1421                        if ($statusElement.length) {
1422                            $statusElement.text('Авторизация подтверждена! Перезагрузка...').css('color', 'green');
1423                        }
1424                        // --- ЕДИНОЕ ДЕЙСТВИЕ ПРИ УСПЕХЕ ---
1425                        // 1. Установка флага в sessionStorage
1426                        sessionStorage.setItem('phoneAuthJustCompleted', '1');
1427                        // 2. Установка ID пользователя
1428                        sessionStorage.setItem('phoneAuthUserId', statusResponse.data.user_id);
1429                        // 3. Перезагрузка страницы
1430						
1431						$modalContent.find('.modal-title').html(`<h2 class="modal-title">Авторизуемся</h2>`);
1432                        $modalContent.find('.modal-description').text('Ожидаем авторизацию...');
1433						$modalContent.find('.close').hide();
1434						$modalContent.find('#phonePollingStatus, #phonePollingStatusAuth').first().hide().text('').removeAttr('style');
1435						
1436						setTimeout(function () {
1437                            window.location.reload();
1438                        }, 5000);
1439                        // --- КОНЕЦ ЕДИНОГО ДЕЙСТВИЯ ---
1440                    } else if (statusResponse.success) {
1441                        // success: true, но user_id отсутствует (например, "Ожидание подтверждения...")
1442                        // Это промежуточный статус, продолжаем опрос
1443                        console.log('Универсальный опрос: Промежуточный статус (success=true, no user_id):', statusResponse.data?.message || 'Ожидание...');
1444                        if ($statusElement.length) {
1445                            $statusElement.text(statusResponse.data?.message || 'Ожидание подтверждения звонка...').css('color', 'orange');
1446                        }
1447                    } else if (statusResponse.data && statusResponse.data.message) {
1448                        // success: false, но есть сообщение об ошибке (например, "Пользователь найден, но не авторизован")
1449                        console.warn('Универсальный опрос: Ошибка от сервера (success=false):', statusResponse.data.message);
1450                        if ($statusElement.length) {
1451                            $statusElement.text(statusResponse.data.message).css('color', 'red');
1452                        }
1453                    } else {
1454                        // Неожиданный формат ответа
1455                        console.warn('Универсальный опрос: Неожиданный формат ответа:', statusResponse);
1456                        if ($statusElement.length) {
1457                           // $statusElement.text('Неожиданный ответ от сервера. Повтор...').css('color', 'orange');
1458                        }
1459                    }
1460                    // --- КОНЕЦ УНИВЕРСАЛЬНОЙ ПРОВЕРКИ УСПЕХА ---
1461                } catch (e) {
1462                    console.error('Универсальный опрос: Ошибка обработки ответа:', e);
1463                }
1464            },
1465            error: function (xhr, status, error) {
1466                console.error('Универсальный опрос: AJAX ошибка при опросе статуса:', status, error);
1467                // Вызываем пользовательский колбэк ошибки
1468                settings.onError(xhr, status, error);
1469                // Не останавливаем опрос, продолжаем
1470                if ($statusElement.length) {
1471                    var originalText = $statusElement.text();
1472                    var originalColor = $statusElement.css('color');
1473                    $statusElement.text('Ошибка соединения при опросе статуса. Повтор...').css('color', 'red');
1474                    setTimeout(() => {
1475                        if ($statusElement.length && $statusElement.text().includes('Ошибка соединения')) {
1476                            $statusElement.text(originalText).css('color', originalColor);
1477                        }
1478                    }, 1500);
1479                }
1480            }
1481        });
1482    }
1483
1484    // Начинаем опрос
1485    if ($statusElement.length) {
1486        //$statusElement.text('Ожидание подтверждения звонка...').css('color', '#007cba').show();
1487    }
1488    pollInterval = setInterval(internalCheckStatus, settings.pollIntervalTime);
1489    setTimeout(internalCheckStatus, 500); // Первая проверка чуть позже
1490
1491    // Возвращаем функцию для остановки опроса вручную, если нужно
1492    return function stopPolling() {
1493        if (pollInterval) {
1494            clearInterval(pollInterval);
1495            console.log('Универсальный опрос: Остановлен вручную.');
1496        }
1497    };
1498}
1499// --- Конец универсальной функции ---
1500
1501
1502// --- Универсальная функция для начальной подготовки (валидация, получение nonce) ---
1503// Параметры:
1504// - phoneInputSelector: селектор поля ввода телефона (например, '#userPhone' или '#userPhoneAuth')
1505// - errorContainerSelector: селектор контейнера для ошибок (например, '#phoneError' или '#ph
1505oneErrorAuth')
1506// - buttonSelector: селектор кнопки (например, '#sendPhoneBtn' или '#sendPhoneBtnAuth')
1507// - modalContentSelector: селектор контейнера модального окна или его части для обновления UI (например, '#paymentModal' или '.auth-container')
1508// - onSuccessCallback: функция, вызываемая при успешной подготовке (получении nonce).
1509//                      Принимает (formattedPhone, nonce, $modalContent)
1510// - onErrorCallback: функция, вызываемая при любой ошибке (валидация, nonce).
1511//                    Принимает (errorMessage)
1512function initiateZvonokCall(phoneInputSelector, errorContainerSelector, buttonSelector, modalContentSelector, onSuccessCallback, onErrorCallback) {
1513    const $phoneInput = $(phoneInputSelector);
1514    const $errorContainer = $(errorContainerSelector);
1515    const $btn = $(buttonSelector);
1516    const $modalContent = $(modalContentSelector);
1517
1518    if (!$phoneInput.length || !$btn.length) {
1519        console.error('initiateZvonokCall: Не найдены обязательные элементы DOM.');
1520        if (typeof onErrorCallback === 'function') {
1521             onErrorCallback('Ошибка интерфейса: элементы не найдены.');
1522        }
1523        return;
1524    }
1525
1526    let phone = $phoneInput.val().trim();
1527    const originalBtnText = $btn.text();
1528
1529    // --- Скрыть предыдущие ошибки ---
1530    if ($errorContainer.length) $errorContainer.hide();
1531
1532    // --- Валидация ---
1533    if (typeof validatePhone !== 'function' || !validatePhone(phone)) {
1534        const errorMsg = 'Пожалуйста, введите полный номер телефона.';
1535        if ($errorContainer.length) {
1536            $errorContainer.text(errorMsg).show();
1537        } else {
1538            alert(errorMsg);
1539        }
1540        if (typeof onErrorCallback === 'function') {
1541             onErrorCallback(errorMsg);
1542        }
1543        return;
1544    }
1545
1546    // --- Форматирование ---
1547    const formattedPhone = '+7' + phone.replace(/\D/g, '').substring(1);
1548
1549    // --- Блокировка кнопки ---
1550    $btn.prop('disabled', true).text('Проверка...');
1551
1552    console.log("Начинаем процесс подготовки для звонка для телефона:", formattedPhone);
1553
1554    // --- Шаг 1: Получить nonce ---
1555    $.ajax({
1556        url: mains_ajax_object.ajax_url,
1557        type: 'POST',
1558        data: {
1559            action: 'get_phone_registration_nonce' // Используем существующий action
1560        },
1561        success: function(nonceResponse) {
1562            if (nonceResponse.success && nonceResponse.data.nonce) {
1563                console.log("Nonce для операции получен.");
1564                // --- УСПЕХ: Передаем управление колбэку ---
1565                // НЕ отправляем звонок здесь!
1566                $btn.prop('disabled', false).text(originalBtnText); // Разблокируем кнопку, так как основная работа перешла вызывающей стороне
1567                if (typeof onSuccessCallback === 'function') {
1568                    onSuccessCallback(formattedPhone, nonceResponse.data.nonce, $modalContent);
1569                }
1570            } else {
1571                // --- Ошибка от сервера при получении nonce ---
1572                const errorMsg = nonceResponse.data.message || 'Ошибка безопасности при проверке пользователя.';
1573                console.error('Не удалось получить nonce:', errorMsg);
1574                if ($errorContainer.length) {
1575                    $errorContainer.text(errorMsg).show();
1576                } else {
1577                    alert(errorMsg);
1578                }
1579                $btn.prop('disabled', false).text(originalBtnText);
1580                 if (typeof onErrorCallback === 'function') {
1581                    onErrorCallback(errorMsg);
1582                }
1583            }
1584        },
1585        error: function (nonceXhr, nonceStatus, nonceError) {
1586            // --- Ошибка AJAX при получении nonce ---
1587            const errorMsg = 'Ошибка соединения (получение nonce).';
1588            console.error('Ошибка получения nonce:', nonceXhr, nonceStatus, nonceError);
1589            if ($errorContainer.length) {
1590                $errorContainer.text(errorMsg).show();
1591            } else {
1592                alert(errorMsg);
1593            }
1594            $btn.prop('disabled', false).text(originalBtnText);
1595            if (typeof onErrorCallback === 'function') {
1596                onErrorCallback(errorMsg);
1597            }
1598        }
1599    });
1600}
1601
1602
1603    // Валидация email (может понадобиться где-то ещё)
1604   /* function validateEmail(email) {
1605        const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1606        return re.test(email);
1607    }
1608*/
1609    // Показ ошибки (для email, если используется где-то ещё)
1610    function showError(message) {
1611        $('#emailError').text(message).show(); // Предполагается, что элемент с id="emailError" существует
1612    }
1613
1614
1615  function sendPaymentRequest(email, nonce, $btn) {
1616     $.ajax({
1617        url: mains_ajax_object.ajax_url,
1618        type: 'POST',
1619        data: {
1620            action: 'handle_payment_user',
1621            package_id: currentPackage.id,
1622            price: currentPackage.price,
1623            amount: currentPackage.amount,
1624            nonce: nonce // Используем новый nonce
1625        },
1626        success: function(response) {
1627			
1628            console.log('Ответ сервера (оплата):', response);
1629            if (response.success) {
1630                // Показываем форму оплаты с правильными параметрами
1631                showPaymentForm(
1632                    response.data.user_id,
1633                    response.data.price,
1634                    response.data.amount,
1635					response.data.package_id
1636                );
1637            } else {
1638                showError(response.data.message || 'Произошла ошибка');
1639            }
1640        },
1641        error: function(xhr, status, error) {
1642            console.log('Ошибка AJAX (оплата):', xhr, status, error);
1643            showError('Произошла ошибка при обработке запроса');
1644        },
1645        complete: function() {
1646            // Убедитесь, что кнопка разблокируется только после основного запроса
1647            // или обработайте это внутри success/error выше
1648             if($btn) { // Проверка, если $btn передан
1649                 $btn.prop('disabled', false).text('Оплатить');
1650             }
1651        }
1652    });
1653}
1654
1655
1656// --- Обновленная функция showPaymentForm с логированием ---
1657function showPaymentForm(userId, price, amount, packId) {
1658    console.log('showPaymentForm called with args:', {userId, price, amount});
1659
1660    var displayAmount, displayPrice;
1661
1662    if (price !== undefined && amount !== undefined && price > 0 && amount > 0) {
1663        displayAmount = amount;
1664        displayPrice = price;
1665        console.log("Используем переданные price и amount:", {displayPrice, displayAmount});
1666    } else if (typeof currentPackage !== 'undefined' && currentPackage && currentPackage.price > 0 && currentPackage.amount > 0) {
1667        displayAmount = currentPackage.amount;
1668        displayPrice = currentPackage.price;
1669        console.log("Используем данные из currentPackage:", {displayPrice, displayAmount});
1670    } else {
1671        displayAmount = 0;
1672        displayPrice = 0;
1673        console.warn("Не удалось определить price и amount. Используются дефолтные значения 0.");
1674    }
1675
1676    $('#paymentModal').hide();
1677
1678    console.log('Display values to be used:', {displayAmount, displayPrice});
1679
1680    var widget = new cp.CloudPayments();
1681
1682    var receipt = {
1683        "Items": [
1684            {
1685                label: 'Оплата за ' + displayAmount + ' алмазов',
1686                price: parseFloat(displayPrice),
1687                quantity: 1.00,
1688                amount: parseFloat(displayPrice),
1689                vat: 0, // 0 - без НДС
1690                method: 0, // необязательно
1691                object: 0, // необязательно
1692            }
1693        ],
1694        calculationPlace: "sozd.ai",
1695        taxationSystem: 1,
1696        isBso: false,
1697        amounts: {
1698            electronic: parseFloat(displayPrice),
1699            advancePayment: 0.00,
1700            credit: 0.00,
1701            provision: 0.00
1702        }
1703    };
1704
1705    widget.pay("charge", {
1706        publicId: mains_ajax_object.cloudpayments_public_id,
1707        description: 'Оплата за ' + displayAmount + ' алмазов',
1708        amount: displayPrice,
1709        currency: 'RUB',
1710        accountId: userId,
1711        data: {
1712            CloudPayments: {
1713                CustomerReceipt: receipt,
1714            },
1715            userId: userId,
1716            amount: displayAmount,
1717            packageId: packId
1718        },
1719     }).then(function(result) {
1720        // logToServer('Payment Result Object: ' + JSON.stringify(result), 'detailed', userId); // Логируем детали
1721
1722         if (result.type === 'cancel') {
1723             //logToServer('Payment Cancelled.', 'cancel', userId); // Передаем тип 'cancel'
1724             console.log('Пользователь закрыл окно оплаты без проведения платежа');
1725             return;
1726         } else if (result.type === 'payment' || result.type === 'installment') {
1727             if (result.status === 'success') {
1728                 //logToServer('Payment Success! Transaction ID: ' + result.data?.transactionId, 'payment',userId); // Передаем тип 'payment'
1729                 //ym(104015232,'reachGoal','oplata');
1730                 console.log('Оплата прошла успешно');
1731                 console.log('Transaction ID:', result.data?.transactionId);
1732
1733                 setTimeout(function() {
1734                     window.location.href = '/?payment_success=1&user_id=' + userId + '&t=' + Date.now();
1735                 }, 2000);
1736             } else if (result.status === 'fail') {
1737                 //logToServer('Payment Failed! Message: ' + result.message + ', Transaction ID: ' + result.data?.transactionId, 'fail',userId); // Передаем тип 'fail'
1738                 console.error('Оплата не прошла:', result.message);
1739                 console.log('Transaction ID:', result.data?.transactionId);
1740                 alert('Оплата не прошла. ' + (result.message || 'Пожалуйста, попробуйте еще раз или свяжитесь с поддержкой.'));
1741             }
1742         } else if (result.type === 'error') {
1743            // logToServer('Payment Error! Message: ' + result.message + ', Transaction ID: ' + result.data?.transactionId, 'error',userId); // Передаем тип 'error'
1744             console.error('Ошибка оплаты CloudPayments:', result.message);
1745             console.log('Transaction ID:', result.data?.transactionId);
1746             alert('Ошибка при проведении оплаты. ' + (result.message || 'Пожалуйста, попробуйте еще раз или свяжитесь с поддержкой.'));
1747         } else {
1748            // logToServer('Payment Unhandled Result Type: ' + result.type + ', Full Result: ' + JSON.stringify(result), 'unhandled',userId); // Передаем тип 'unhandled'
1749			// ym(104015232,'reachGoal','oplata');
1750             console.warn('Необработанный тип результата оплаты:', result);
1751			 setTimeout(function() {
1752                     window.location.href = '/?payment_success=1&user_id=' + userId + '&t=' + Date.now();
1753                 }, 2000);
1754         }
1755    }).catch(function(reason) {
1756        //logToServer('Payment Promise Rejected! Reason: ' + reason, 'promise_error',userId); // Передаем тип 'promise_error'
1757        console.error('Ошибка оплаты CloudPayments (Promise):', reason);
1758        alert('Ошибка при проведении оплаты. Пожалуйста, попробуйте еще раз или свяжитесь с поддержкой.');
1759    });
1760}
1761
1762/**
1763 * Функция для отправки сообщения в лог на сервере
1764 * @param {string} message - Сообщение для логирования
1765 * @param {string} log_type - Тип лога ('payment', 'cancel', 'fail', 'error', 'unhandled', 'promise_error', 'detailed')
1766 */
1767function logToServer(message, log_type, userids) {
1768    jQuery.ajax({
1769        url: mains_ajax_object.ajax_url,
1770        type: 'POST',
1771        data: {
1772            action: 'log_payment_debug',
1773            security: mains_ajax_object.nonce, // Убедитесь, что nonce используется и проверяется в PHP
1774            log_message: message,
1775            log_type: log_type, // Передаем тип лога
1776            timestamp: new Date().toISOString(),
1777			user_id: userids
1778            //user_id: mains_ajax_object.current_user_id // Если нужно логировать ID пользователя
1779        },
1780        success: function(response) {
1781            // console.log('Log sent to server:', response);
1782        },
1783        error: function(xhr, status, error) {
1784            console.error('Failed to send log to server:', error);
1785            console.log('Local log fallback:', message);
1786        }
1787    });
1788}
1789// --- КОНЕЦ Обновленной функции showPaymentForm с логированием ---
1790// --- КОНЕЦ Обновленной функции showPaymentForm ---
1791
1792// yandex auth
1793
1794  $('.yandex-login-btn').on('click', function(e) {
1795        e.preventDefault();
1796        window.location.href = ajax_object.ajax_url + '?action=yandex_auth';
1797  });
1798  
1799// vk auth
1800$('.vk-login-btn').on('click', function(e) {
1801        $('.vk-login-btn').on('click', function(e) {
1802        e.preventDefault();
1803
1804        // Отправляем AJAX-запрос на сервер WordPress для получения URL авторизации
1805        $.ajax({
1806            url: ajax_object.ajax_url, // Глобальная переменная, содержащая URL wp-admin/admin-ajax.php
1807            type: 'POST',
1808            dataType: 'json',
1809            data: {
1810                action: 'vk_auth_start' // Название экшена, соответствует add_action('wp_ajax_...')
1811            },
1812            success: function(response) {
1813                if (response.success && response.data.auth_url) {
1814                    // Перенаправляем пользователя на страницу авторизации ВК
1815                    window.location.href = response.data.auth_url;
1816                } else {
1817                    console.error('Ошибка получения URL авторизации:', response);
1818                    alert('Произошла ошибка при попытке входа через VK.');
1819                }
1820            },
1821            error: function(xhr, status, error) {
1822                console.error('AJAX Error:', status, error);
1823                alert('Произошла ошибка при попытке входа через VK.');
1824            }
1825        });
1826    });
1827
1828    // Проверяем, есть ли хэш в URL (после возврата из ВК)
1829    const hashParams = new URLSearchParams(window.location.hash.substring(1)); // Убираем '#' и парсим
1830    if (hashParams.has('access_token')) {
1831        // Получаем токен, срок действия, user_id, email из хэша
1832        const accessToken = hashParams.get('access_token');
1833        const expiresIn = hashParams.get('expires_in');
1834        const userId = hashParams.get('user_id');
1835        const email = hashParams.get('email'); // Может быть null, если пользователь скрыл его или не предоставил доступ
1836        const state = hashParams.get('state');
1837
1838        if (accessToken && userId && state) {
1839            // Проверяем nonce, если использовали
1840            if (!wp_verify_nonce(state, 'vk_auth_nonce')) {
1841                console.error('Неверный nonce.');
1842                return; // Прерываем выполнение
1843            }
1844
1845            // Отправляем полученные данные на сервер WordPress для завершения авторизации
1846            $.ajax({
1847                url: ajax_object.ajax_url, // Глобальная переменная
1848                type: 'POST',
1849                dataType: 'json',
1850                data: {
1851                    action: 'vk_complete_auth',
1852                    access_token: accessToken,
1853                    user_id: userId,
1854                    email: email // Может быть null
1855                },
1856                success: function(response) {
1857                    if (response.success) {
1858                        // Авторизация успешна, перезагружаем страницу или делаем другие действия
1859                        window.location.reload();
1860                    } else {
1861                        console.error('Ошибка завершения авторизации:', response.data.message || response);
1862                        alert(response.data.message || 'Произошла ошибка при завершении входа через VK.');
1863                    }
1864                },
1865                error: function(xhr, status, error) {
1866                    console.error('AJAX Error при завершении:', status, error);
1867                    alert('Произошла ошибка при завершении входа через VK.');
1868                }
1869            });
1870        }
1871    }
1872  });
1873
1874// При отправке формы
1875    $('.wpcf7').on('wpcf7invalid', function() {
1876        $(this).find('.wpcf7-not-valid').each(function() {
1877            var errorMessage = $(this).siblings('.wpcf7-not-valid-tip').text();
1878            var originalPlaceholder = $(this).data('original-placeholder') || $(this).attr('placeholder');
1879            
1880            // Сохраняем оригинальный placeholder
1881            if (!$(this).data('original-placeholder')) {
1882                $(this).data('original-placeholder', originalPlaceholder);
1883            }
1884            
1885            // Устанавливаем ошибку как placeholder
1886            $(this).attr('placeholder', errorMessage);
1887        });
1888    });
1889    
1890    // При фокусе восстанавливаем оригинальный placeholder
1891    $(document).on('focus', '.wpcf7-not-valid', function() {
1892        var originalPlaceholder = $(this).data('original-placeholder') || '';
1893        $(this).attr('placeholder', originalPlaceholder);
1894    });
1895    
1896    // При blur проверяем пустое значение
1897    $(document).on('blur', '.wpcf7-not-valid', function() {
1898        if ($(this).val() === '') {
1899            var errorMessage = $(this).siblings('.wpcf7-not-valid-tip').text();
1900            $(this).attr('placeholder', errorMessage);
1901        }
1902    });
1903	
1904
1905
1906}); 

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.