PageSourceSearch

https://www.birdhot.ru/assets/js/subscribe-popup.js

js birdhot.ru collected 2026-10-05 23:53:14 UTC 8,167 bytes, 170 lines download raw bytes

1(function () {
2  var POPUP_DELAY_MS = 7000;
3  var SESSION_KEY = 'birdhot_subscribe_shown';
4  var SUBSCRIBED_KEY = 'birdhot_subscribed';
5  var API_URL = 'https://crm.birdhot.ru/api/subscribe';
6  var START_URL = 'https://crm.birdhot.ru/api/subscribe/start';
7
8  function cookieBannerHeight() {
9    var cookieBanner = document.getElementById('cookies-banner');
10    if (cookieBanner && getComputedStyle(cookieBanner).display !== 'none') {
11      return cookieBanner.offsetHeight;
12    }
13    return 0;
14  }
15
16  function buildBanner() {
17    var banner = document.createElement('div');
18    banner.id = 'subscribe-banner';
19    banner.style.bottom = cookieBannerHeight() + 'px';
20    banner.innerHTML =
21      '<button type="button" id="subscribe-banner-close" aria-label="Закрыть">&times;</button>' +
22      '<div id="subscribe-banner-teaser">' +
23        '<div id="subscribe-banner-text">' +
24          '<p class="subscribe-banner-title">Хотите получить скидку?</p>' +
25          '<p class="subscribe-banner-subtitle">Подпишитесь на новости и акции комплекса — вы узнаете о скидках и спецпредложениях первыми!</p>' +
26        '</div>' +
27        '<div class="subscribe-banner-actions">' +
28          '<button type="button" class="subscribe-banner-btn-primary" id="subscribe-banner-yes">Подписаться</button>' +
29        '</div>' +
30      '</div>' +
31      '<form id="subscribe-banner-form" style="display:none">' +
32        '<input type="hidden" name="subscriber_id" value="">' +
33        '<input type="text" name="name" placeholder="Ваше имя" required>' +
34        '<input type="tel" name="phone" placeholder="Телефон (для информирования)" required>' +
35        '<input type="email" name="email" placeholder="Email (необязательно)">' +
36        '<label class="subscribe-banner-checkbox">' +
37          '<input type="checkbox" name="consent_privacy" required>' +
38          '<span>Согласен с <a href="privacy.html" target="_blank">обработкой персональных данных</a></span>' +
39        '</label>' +
40        '<button type="submit" class="subscribe-banner-btn-primary" id="subscribe-banner-submit-btn" disabled>Получаем ссылки…</button>' +
41        '<p class="subscribe-banner-link-hint">Выберите мессенджер, перейдите в него и нажмите «Начать» для Вашей персональной подписки на скидки</p>' +
42        '<p id="subscribe-banner-error" class="subscribe-banner-error"></p>' +
43      '</form>' +
44      '<div id="subscribe-banner-success" style="display:none">' +
45        '<p id="subscribe-banner-success-text">✓ Спасибо! Вы подписались на новости и акции.</p>' +
46        '<div id="subscribe-banner-channels" class="subscribe-banner-channels" style="display:none">' +
47          '<a href="#" id="subscribe-banner-max-link" class="subscribe-banner-btn-primary" target="_blank" rel="noopener">Открыть в MAX</a>' +
48          '<a href="#" id="subscribe-banner-telegram-link" class="subscribe-banner-btn-primary" target="_blank" rel="noopener">Открыть в Telegram</a>' +
49        '</div>' +
50      '</div>';
51    document.body.appendChild(banner);
52
53    function close() {
54      banner.remove();
55      sessionStorage.setItem(SESSION_KEY, '1');
56    }
57
58    // Если кукис-банер закрылся уже после показа нашего — опускаемся к самому низу
59    var cookieAcceptBtn = document.querySelector('#cookies-banner .cookies-accept');
60    if (cookieAcceptBtn) {
61      cookieAcceptBtn.addEventListener('click', function () {
62        banner.style.bottom = '0';
63      }, { once: true });
64    }
65
66    banner.querySelector('#subscribe-banner-close').addEventListener('click', close);
67
68    var maxLink = null;
69    var telegramLink = null;
70
71    banner.querySelector('#subscribe-banner-yes').addEventListener('click', function () {
72      banner.querySelector('#subscribe-banner-teaser').style.display = 'none';
73      var form = banner.querySelector('#subscribe-banner-form');
74      form.style.display = 'flex';
75
76      var submitBtn = banner.querySelector('#subscribe-banner-submit-btn');
77
78      fetch(START_URL, { method: 'POST' })
79        .then(function (r) { return r.json(); })
80        .then(function (data) {
81          if (data) {
82            form.subscriber_id.value = data.subscriber_id;
83            maxLink = data.max_link || null;
84            telegramLink = data.telegram_link || null;
85          }
86          submitBtn.disabled = false;
87          submitBtn.textContent = 'Подписаться';
88        })
89        .catch(function () {
90          submitBtn.disabled = false;
91          submitBtn.textContent = 'Подписаться';
92        });
93    });
94
95    banner.querySelector('#subscribe-banner-form').addEventListener('submit', function (e) {
96      e.preventDefault();
97      var form = e.target;
98      var errorEl = banner.querySelector('#subscribe-banner-error');
99      errorEl.textContent = '';
100
101      if (!form.consent_privacy.checked) {
102        errorEl.textContent = 'Нужно согласие на обработку персональных данных.';
103        return;
104      }
105
106      var submitBtn = form.querySelector('button[type="submit"]');
107      submitBtn.disabled = true;
108
109      fetch(API_URL, {
110        method: 'POST',
111        headers: { 'Content-Type': 'application/json' },
112        body: JSON.stringify({
113          subscriber_id: form.subscriber_id.value || null,
114          name: form.name.value.trim(),
115          phone: form.phone.value.trim(),
116          email: form.email.value.trim(),
117          consent_privacy: true
118        })
119      })
120        .then(function (r) {
121          return r.json().then(function (data) { return { status: r.status, data: data }; });
122        })
123        .then(function (res) {
124          if (res.status !== 200) {
125            errorEl.textContent = (res.data && res.data.error) || 'Не удалось отправить, попробуйте позже.';
126            submitBtn.disabled = false;
127            return;
128          }
129
130          // Согласие и данные уже сохранены в базу — теперь переходим к боту.
131          if (maxLink) {
132            window.open(maxLink, '_blank', 'noopener');
133          }
134
135          form.style.display = 'none';
136          var successEl = banner.querySelector('#subscribe-banner-success');
137          var successText = banner.querySelector('#subscribe-banner-success-text');
138          successEl.style.display = 'block';
139          localStorage.setItem(SUBSCRIBED_KEY, '1');
140          sessionStorage.setItem(SESSION_KEY, '1');
141
142          var channelsEl = banner.querySelector('#subscribe-banner-channels');
143          var maxLinkEl = banner.querySelector('#subscribe-banner-max-link');
144          var telegramLinkEl = banner.querySelector('#subscribe-banner-telegram-link');
145          if (maxLink || telegramLink) {
146            if (maxLink) { maxLinkEl.href = maxLink; } else { maxLinkEl.style.display = 'none'; }
147            if (telegramLink) { telegramLinkEl.href = telegramLink; } else { telegramLinkEl.style.display = 'none'; }
148            channelsEl.style.display = 'flex';
149          }
150
151          if (maxLink) {
152            successText.textContent = '✓ Спасибо! Открыли бота МАКС в новой вкладке — подтвердите там запуск. Нет MAX? Откройте Telegram ниже.';
153          } else {
154            successText.textContent = '✓ Спасибо! Вы подписались на новости и акции.';
155          }
156          setTimeout(close, 15000);
157        })
158        .catch(function () {
159          errorEl.textContent = 'Ошибка сети, попробуйте позже.';
160          submitBtn.disabled = false;
161        });
162    });
163  }
164
165  setTimeout(function () {
166    if (!sessionStorage.getItem(SESSION_KEY) && !localStorage.getItem(SUBSCRIBED_KEY)) {
167      buildBanner();
168    }
169  }, POPUP_DELAY_MS);
170})();

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.