PageSourceSearch

https://prometheus.org.ua/wp-content/themes/prometheus-new/assets/js/bundle-conflict.js?ver=2.1.30.1790850512

js prometheus.org.ua collected 2026-10-01 10:30:04 UTC 12,314 bytes, 335 lines download raw bytes

1/**
2 * Показує модалку із пропозицією замінити курс на бандл,
3 * якщо при додаванні бандлу виявлено конфлікт "Sold Individually".
4 */
5
6(function () {
7    'use strict';
8
9    /**
10     * Ін'єктуємо стилі модалки прямо з JS,
11     * щоб не залежати від окремого CSS-файлу.
12     */
13    function injectStyles() {
14        if (document.getElementById('prometheus-bundle-conflict-styles')) return;
15
16        var style = document.createElement('style');
17        style.id = 'prometheus-bundle-conflict-styles';
18        style.textContent = [
19            '.pbc-overlay {',
20            '  position: fixed;',
21            '  inset: 0;',
22            '  background: rgba(5, 5, 5, 0.5);',
23            '  backdrop-filter: blur(2px);',
24            '  z-index: 99998;',
25            '  display: flex;',
26            '  align-items: flex-end;',
27            '  justify-content: center;',
28            '  padding: 0;',
29            '  opacity: 0;',
30            '  transition: opacity 0.25s ease;',
31            '}',
32
33            '@media (min-width: 768px) {',
34            '  .pbc-overlay {',
35            '    align-items: center;',
36            '    padding: 20px;',
37            '  }',
38            '}',
39
40            '.pbc-overlay.pbc-visible {',
41            '  opacity: 1;',
42            '}',
43
44            '.pbc-modal {',
45            '  position: relative;',
46            '  background: #FFFFFF;',
47            '  border-radius: 24px 24px 0 0;',
48            '  padding: 32px 20px 28px;',
49            '  width: 100%;',
50            '  box-shadow: 0 20px 60px rgba(5, 5, 5, 0.18);',
51            '  transform: translateY(40px);',
52            '  transition: transform 0.3s cubic-bezier(0.34, 1.2, 0.64, 1);',
53            '  box-sizing: border-box;',
54            '}',
55
56            '@media (min-width: 768px) {',
57            '  .pbc-modal {',
58            '  max-width: 570px;',
59            '    border-radius: 24px;',
60            '    padding: 40px 36px 36px;',
61            '    transform: translateY(20px);',
62            '  }',
63            '}',
64
65            '.pbc-overlay.pbc-visible .pbc-modal {',
66            '  transform: translateY(0);',
67            '}',
68
69            '.pbc-title {',
70            '  font-size: 20px;',
71            '  text-transform: uppercase;',
72            '  font-family: MursGothic, ui-serif, serif;',
73            '  font-weight: 600;',
74            '  color: #050505;',
75            '  margin: 0;',
76            '  line-height: 1.3;',
77            '  margin-bottom: 20px;',
78            '}',
79
80            '@media (min-width: 768px) {',
81            '  .pbc-title { font-size: 28px; }',
82            '}',
83
84            '.pbc-desc {',
85            '  font-size: 15px;',
86            '  line-height: 1.6;',
87            '  color: #3D4552;',
88            '  margin: 0 0 24px;',
89            '}',
90
91            '.pbc-desc strong {',
92            '  color: #050505;',
93            '  font-weight: 600;',
94            '}',
95
96            '.pbc-highlight {',
97            '  background: #FFF4E5;',
98            '  border-radius: 8px;',
99            '  padding: 12px 16px;',
100            '  margin: 0 0 24px;',
101            '  font-size: 16px;',
102            '  line-height: 1.5;',
103            '  color: #FFA217;',
104            '  display: flex;',
105            '  align-items: flex-start;',
106            '  gap: 8px;',
107            '}',
108
109            '.pbc-highlight svg {',
110            '  flex-shrink: 0;',
111            '  color: #FFA217;',
112            '  margin-top: 2px;',
113            '}',
114
115            '.pbc-actions {',
116            '  display: flex;',
117            '  flex-direction: column;',
118            '  gap: 10px;',
119            '}',
120
121            '.pbc-btn-replace {',
122            '  display: flex;',
123            '  align-items: center;',
124            '  justify-content: center;',
125            '  height: 52px;',
126            '  border-radius: 48px;',
127            '  background: #050505;',
128            '  color: #FFFFFF;',
129            '  font-size: 16px;',
130            '  font-weight: 500;',
131            '  border: none;',
132            '  cursor: pointer;',
133            '  transition: background 0.2s, opacity 0.2s;',
134            '  width: 100%;',
135            '}',
136
137            '.pbc-btn-replace:hover:not(:disabled) {',
138            '  background: #281405;',
139            '}',
140
141            '.pbc-btn-replace:disabled {',
142            '  opacity: 0.6;',
143            '  cursor: not-allowed;',
144            '}',
145
146            '.pbc-btn-keep {',
147            '  display: flex;',
148            '  align-items: center;',
149            '  justify-content: center;',
150            '  height: 52px;',
151            '  border-radius: 48px;',
152            '  background: transparent;',
153            '  color: #050505;',
154            '  font-size: 16px;',
155            '  font-weight: 500;',
156            '  border: 1.5px solid #050505;',
157            '  cursor: pointer;',
158            '  transition: border-color 0.2s, background 0.2s;',
159            '  width: 100%;',
160            '}',
161
162            '.pbc-btn-keep:hover {',
163            '  border-color: #281405;',
164            '}',
165
166            '.pbc-spinner {',
167            '  width: 18px;',
168            '  height: 18px;',
169            '  border: 2px solid rgba(255,255,255,0.4);',
170            '  border-top-color: #fff;',
171            '  border-radius: 50%;',
172            '  animation: pbc-spin 0.7s linear infinite;',
173            '  margin-right: 8px;',
174            '  display: none;',
175            '}',
176
177            '@keyframes pbc-spin {',
178            '  to { transform: rotate(360deg); }',
179            '}',
180        ].join('\n');
181
182        document.head.appendChild(style);
183    }
184
185    /**
186     * Будує і показує модалку з даними конфлікту.
187     */
188    function showConflictModal(data) {
189        injectStyles();
190
191        // Overlay
192        var overlay = document.createElement('div');
193        overlay.className = 'pbc-overlay';
194        overlay.setAttribute('role', 'dialog');
195        overlay.setAttribute('aria-modal', 'true');
196        overlay.setAttribute('aria-labelledby', 'pbc-title');
197
198        overlay.innerHTML =
199            '<div class="pbc-modal">' +
200            '<h2 class="pbc-title" id="pbc-title">У кошику є курс із цього комплекту</h2>' +
201            '<p class="pbc-desc">' +
202            'Ви намагаєтесь додати комплект <strong>' + escapeHtml(data.bundleName) + '</strong>,' +
203            ' але у вашому кошику вже є курс <strong>' + escapeHtml(data.conflictName) + '</strong>,' +
204            ' який входить до нього.' +
205            '</p>' +
206            '<div class="pbc-highlight">' +
207            '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">' +
208            '<path d="M10.8 10.8H9.2V6H10.8M10.8 14H9.2V12.4H10.8M10 2C8.94943 2 7.90914 2.20693 6.93853 2.60896C5.96793 3.011 5.08601 3.60028 4.34315 4.34315C2.84285 5.84344 2 7.87827 2 10C2 12.1217 2.84285 14.1566 4.34315 15.6569C5.08601 16.3997 5.96793 16.989 6.93853 17.391C7.90914 17.7931 8.94943 18 10 18C12.1217 18 14.1566 17.1571 15.6569 15.6569C17.1571 14.1566 18 12.1217 18 10C18 8.94943 17.7931 7.90914 17.391 6.93853C16.989 5.96793 16.3997 5.08601 15.6569 4.34315C14.914 3.60028 14.0321 3.011 13.0615 2.60896C12.0909 2.20693 11.0506 2 10 2Z" fill="#FFA217"/>' +
209            '</svg>' +
210            '<span>Замінити окремий курс на комплект?</span>' +
211            '</div>' +
212            '<div class="pbc-actions">' +
213            '<button class="pbc-btn-replace" id="pbc-btn-replace">' +
214            '<span class="pbc-spinner" id="pbc-spinner"></span>' +
215            '<span id="pbc-btn-text">Замінити на комплект</span>' +
216            '</button>' +
217            '<button class="pbc-btn-keep" id="pbc-btn-keep">Залишити як є</button>' +
218            '</div>' +
219            '</div>';
220
221        document.body.appendChild(overlay);
222
223        // Animate in
224        requestAnimationFrame(function () {
225            requestAnimationFrame(function () {
226                overlay.classList.add('pbc-visible');
227            });
228        });
229
230        // Helpers
231        function closeModal() {
232            overlay.classList.remove('pbc-visible');
233            setTimeout(function () {
234                if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
235            }, 300);
236        }
237
238        function setLoading(isLoading) {
239            var btn = document.getElementById('pbc-btn-replace');
240            var spinner = document.getElementById('pbc-spinner');
241            var btnText = document.getElementById('pbc-btn-text');
242
243            btn.disabled = isLoading;
244            spinner.style.display = isLoading ? 'block' : 'none';
245            btnText.textContent = isLoading ? 'Зачекайте...' : 'Замінити на комплект';
246        }
247
248        // Зберігаємо факт відхилення — не показувати повторно до нової спроби купити бандл
249        var dismissKey = 'pbc_dismissed_' + data.bundleId;
250
251        function dismissModal() {
252            sessionStorage.setItem(dismissKey, '1');
253            closeModal();
254        }
255
256        // Close on overlay click
257        overlay.addEventListener('click', function (e) {
258            if (e.target === overlay) dismissModal();
259        });
260
261        // Keep button
262        document.getElementById('pbc-btn-keep').addEventListener('click', dismissModal);
263
264        // Replace button
265        document.getElementById('pbc-btn-replace').addEventListener('click', function () {
266            setLoading(true);
267
268            var formData = new FormData();
269            formData.append('action', 'prometheus_replace_with_bundle');
270            formData.append('nonce', data.nonce);
271            formData.append('bundle_id', data.bundleId);
272            formData.append('conflict_key', data.conflictKey);
273
274            fetch(data.ajaxUrl, {
275                method: 'POST',
276                body: formData,
277                credentials: 'same-origin',
278            })
279                .then(function (res) { return res.json(); })
280                .then(function (response) {
281                    if (response.success) {
282                        // Редирект на кошик — там вже буде бандл
283                        window.location.href = data.cartUrl;
284                    } else {
285                        setLoading(false);
286                        alert('Не вдалося виконати заміну. Спробуйте оновити сторінку.');
287                    }
288                })
289                .catch(function () {
290                    setLoading(false);
291                    alert('Сталася помилка. Перевірте з\'єднання і спробуйте ще раз.');
292                });
293        });
294
295        // ESC to close
296        function onKeyDown(e) {
297            if (e.key === 'Escape') {
298                closeModal();
299                document.removeEventListener('keydown', onKeyDown);
300            }
301        }
302        document.addEventListener('keydown', onKeyDown);
303    }
304
305    function escapeHtml(str) {
306        var div = document.createElement('div');
307        div.textContent = str;
308        return div.innerHTML;
309    }
310
311    /**
312     * Ініціалізація: перевіряємо window.prometheusBundleConflict,
313     * яке PHP виводить у wp_footer після невдалого додавання бандлу.
314     */
315    function init() {
316        var conflict = window.prometheusBundleConflict;
317        if ( ! conflict ) return;
318
319        // Не показуємо, якщо юзер вже відхилив цю модалку в поточній сесії браузера
320        var dismissKey = 'pbc_dismissed_' + conflict.bundleId;
321        if ( sessionStorage.getItem(dismissKey) ) {
322            window.prometheusBundleConflict = null;
323            return;
324        }
325
326        window.prometheusBundleConflict = null;
327        showConflictModal(conflict);
328    }
329
330    if (document.readyState === 'loading') {
331        document.addEventListener('DOMContentLoaded', init);
332    } else {
333        init();
334    }
335})();

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.