ultimate-jekyll-manager 0.0.117 → 0.0.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +616 -138
- package/README.md +108 -0
- package/TODO.md +1 -1
- package/dist/assets/js/core/auth.js +8 -11
- package/dist/assets/js/core/cookieconsent.js +24 -17
- package/dist/assets/js/core/exit-popup.js +15 -12
- package/dist/assets/js/core/social-sharing.js +8 -4
- package/dist/assets/js/libs/auth/pages.js +14 -13
- package/dist/assets/js/libs/dev.js +192 -129
- package/dist/assets/js/libs/prerendered-icons.js +27 -0
- package/dist/assets/js/pages/account/index.js +4 -3
- package/dist/assets/js/pages/account/sections/api-keys.js +2 -6
- package/dist/assets/js/pages/account/sections/connections.js +101 -59
- package/dist/assets/js/pages/account/sections/delete.js +83 -84
- package/dist/assets/js/pages/account/sections/referrals.js +29 -29
- package/dist/assets/js/pages/account/sections/security.js +51 -71
- package/dist/assets/js/pages/admin/notifications/new/index.js +17 -10
- package/dist/assets/js/pages/blog/index.js +7 -5
- package/dist/assets/js/pages/contact/index.js +6 -33
- package/dist/assets/js/pages/download/index.js +3 -2
- package/dist/assets/js/pages/payment/checkout/index.js +6 -6
- package/dist/assets/js/pages/payment/checkout/modules/processors-main.js +2 -2
- package/dist/assets/js/pages/payment/checkout/modules/session.js +4 -4
- package/dist/assets/js/pages/pricing/index.js +5 -2
- package/dist/assets/themes/classy/css/components/_cards.scss +2 -2
- package/dist/defaults/_.env +6 -0
- package/dist/defaults/_.gitignore +7 -1
- package/dist/defaults/dist/_includes/core/body.html +18 -3
- package/dist/defaults/dist/_includes/core/foot.html +1 -0
- package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +51 -36
- package/dist/defaults/dist/_layouts/blueprint/admin/notifications/new.html +13 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +84 -42
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +67 -35
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +72 -58
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +46 -29
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +36 -16
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +111 -73
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +111 -56
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +127 -81
- package/dist/defaults/dist/pages/pricing.md +7 -0
- package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +1 -1
- package/dist/gulp/tasks/defaults.js +210 -1
- package/firebase-debug.log +504 -0
- package/package.json +5 -5
|
@@ -11,10 +11,10 @@ export function init(wm) {
|
|
|
11
11
|
// Load referrals data
|
|
12
12
|
export function loadData(account) {
|
|
13
13
|
if (!account) return;
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
// Update referral code (real code only)
|
|
16
16
|
updateReferralCode(account.affiliate?.code);
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
// Update referrals list
|
|
19
19
|
updateReferralsList(account.affiliate?.referrals);
|
|
20
20
|
}
|
|
@@ -22,7 +22,7 @@ export function loadData(account) {
|
|
|
22
22
|
// Update referral code display
|
|
23
23
|
function updateReferralCode(code) {
|
|
24
24
|
const $codeInput = document.getElementById('referral-code-input');
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
if ($codeInput) {
|
|
27
27
|
if (code) {
|
|
28
28
|
const baseUrl = window.location.origin;
|
|
@@ -39,19 +39,19 @@ function updateReferralsList(referrals) {
|
|
|
39
39
|
const $recentReferrals = document.getElementById('recent-referrals');
|
|
40
40
|
const $referralsBadge = document.getElementById('referrals-badge');
|
|
41
41
|
const $referralsList = document.getElementById('referrals-list');
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
// Initialize referrals array
|
|
44
44
|
let referralData = referrals || [];
|
|
45
|
-
|
|
46
|
-
// Add fake data if
|
|
45
|
+
|
|
46
|
+
// Add fake data if _dev_prefill=true is in query string
|
|
47
47
|
const urlParams = new URLSearchParams(window.location.search);
|
|
48
|
-
if (urlParams.get('
|
|
48
|
+
if (urlParams.get('_dev_prefill') === 'true') {
|
|
49
49
|
console.log('Adding fake referral data for testing');
|
|
50
50
|
const fakeReferrals = generateFakeReferrals();
|
|
51
51
|
// Add fake referrals to existing data
|
|
52
52
|
referralData = [...referralData, ...fakeReferrals];
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
// Handle empty state
|
|
56
56
|
if (!referralData || !Array.isArray(referralData) || referralData.length === 0) {
|
|
57
57
|
// No referrals - show empty state
|
|
@@ -67,7 +67,7 @@ function updateReferralsList(referrals) {
|
|
|
67
67
|
}
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
// Calculate stats
|
|
72
72
|
const totalCount = referralData.length;
|
|
73
73
|
const now = new Date();
|
|
@@ -76,19 +76,19 @@ function updateReferralsList(referrals) {
|
|
|
76
76
|
const timestamp = ref.timestamp || ref.timestampUNIX * 1000;
|
|
77
77
|
return timestamp >= thisMonth;
|
|
78
78
|
}).length;
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
// Update stats
|
|
81
81
|
if ($totalReferrals) $totalReferrals.textContent = totalCount.toString();
|
|
82
82
|
if ($recentReferrals) $recentReferrals.textContent = recentCount.toString();
|
|
83
83
|
if ($referralsBadge) $referralsBadge.textContent = totalCount.toString();
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
// Sort referrals by timestamp in reverse order (newest first)
|
|
86
86
|
const sortedReferrals = [...referralData].sort((a, b) => {
|
|
87
87
|
const timeA = a.timestamp || (a.timestampUNIX * 1000) || 0;
|
|
88
88
|
const timeB = b.timestamp || (b.timestampUNIX * 1000) || 0;
|
|
89
89
|
return timeB - timeA; // Reverse order
|
|
90
90
|
});
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
// Generate referral list HTML
|
|
93
93
|
if ($referralsList) {
|
|
94
94
|
if (sortedReferrals.length === 0) {
|
|
@@ -103,7 +103,7 @@ function updateReferralsList(referrals) {
|
|
|
103
103
|
const date = timestamp ? new Date(timestamp) : null;
|
|
104
104
|
const dateStr = date ? formatDate(date) : 'Unknown date';
|
|
105
105
|
const timeStr = date ? formatTime(date) : '';
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
return `
|
|
108
108
|
<div class="list-group-item px-0">
|
|
109
109
|
<div class="d-flex justify-content-between align-items-center">
|
|
@@ -123,7 +123,7 @@ function updateReferralsList(referrals) {
|
|
|
123
123
|
</div>
|
|
124
124
|
`;
|
|
125
125
|
}).join('');
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
$referralsList.innerHTML = referralHTML;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
@@ -149,45 +149,45 @@ function formatTime(date) {
|
|
|
149
149
|
// Get time since string
|
|
150
150
|
function getTimeSince(timestamp) {
|
|
151
151
|
if (!timestamp) return '<small class="text-muted">Unknown</small>';
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
const now = Date.now();
|
|
154
154
|
const diff = now - timestamp;
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
// Less than 1 minute
|
|
157
157
|
if (diff < 60000) {
|
|
158
158
|
return '<small class="text-success">Just now</small>';
|
|
159
159
|
}
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
// Less than 1 hour
|
|
162
162
|
if (diff < 3600000) {
|
|
163
163
|
const minutes = Math.floor(diff / 60000);
|
|
164
164
|
return `<small class="text-muted">${minutes} min${minutes > 1 ? 's' : ''} ago</small>`;
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
|
|
167
167
|
// Less than 24 hours
|
|
168
168
|
if (diff < 86400000) {
|
|
169
169
|
const hours = Math.floor(diff / 3600000);
|
|
170
170
|
return `<small class="text-muted">${hours} hour${hours > 1 ? 's' : ''} ago</small>`;
|
|
171
171
|
}
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
// Less than 7 days
|
|
174
174
|
if (diff < 604800000) {
|
|
175
175
|
const days = Math.floor(diff / 86400000);
|
|
176
176
|
return `<small class="text-muted">${days} day${days > 1 ? 's' : ''} ago</small>`;
|
|
177
177
|
}
|
|
178
|
-
|
|
178
|
+
|
|
179
179
|
// Less than 30 days
|
|
180
180
|
if (diff < 2592000000) {
|
|
181
181
|
const weeks = Math.floor(diff / 604800000);
|
|
182
182
|
return `<small class="text-muted">${weeks} week${weeks > 1 ? 's' : ''} ago</small>`;
|
|
183
183
|
}
|
|
184
|
-
|
|
184
|
+
|
|
185
185
|
// More than 30 days
|
|
186
186
|
const months = Math.floor(diff / 2592000000);
|
|
187
187
|
if (months < 12) {
|
|
188
188
|
return `<small class="text-muted">${months} month${months > 1 ? 's' : ''} ago</small>`;
|
|
189
189
|
}
|
|
190
|
-
|
|
190
|
+
|
|
191
191
|
const years = Math.floor(months / 12);
|
|
192
192
|
return `<small class="text-muted">${years} year${years > 1 ? 's' : ''} ago</small>`;
|
|
193
193
|
}
|
|
@@ -205,31 +205,31 @@ function setupButtons() {
|
|
|
205
205
|
async function handleCopyReferralCode() {
|
|
206
206
|
const $codeInput = document.getElementById('referral-code-input');
|
|
207
207
|
const $copyBtn = document.getElementById('copy-referral-code-btn');
|
|
208
|
-
|
|
208
|
+
|
|
209
209
|
if (!$codeInput || !$codeInput.value || $codeInput.value === 'No referral link available') {
|
|
210
210
|
webManager.utilities().showNotification('No referral link to copy', 'warning');
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
|
-
|
|
213
|
+
|
|
214
214
|
try {
|
|
215
215
|
// Copy the full URL directly from the input (it now contains the full URL)
|
|
216
216
|
await webManager.utilities().clipboardCopy($codeInput);
|
|
217
|
-
|
|
217
|
+
|
|
218
218
|
// Update button text temporarily
|
|
219
219
|
const $text = $copyBtn.querySelector('.button-text');
|
|
220
220
|
const originalText = $text.textContent;
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
$text.textContent = 'Copied!';
|
|
223
223
|
$copyBtn.classList.remove('btn-primary');
|
|
224
224
|
$copyBtn.classList.add('btn-success');
|
|
225
|
-
|
|
225
|
+
|
|
226
226
|
// Reset after 2 seconds
|
|
227
227
|
setTimeout(() => {
|
|
228
228
|
$text.textContent = originalText;
|
|
229
229
|
$copyBtn.classList.remove('btn-success');
|
|
230
230
|
$copyBtn.classList.add('btn-primary');
|
|
231
231
|
}, 2000);
|
|
232
|
-
|
|
232
|
+
|
|
233
233
|
} catch (err) {
|
|
234
234
|
console.error('Failed to copy referral link:', err);
|
|
235
235
|
webManager.utilities().showNotification('Failed to copy referral link', 'danger');
|
|
@@ -240,7 +240,7 @@ async function handleCopyReferralCode() {
|
|
|
240
240
|
function generateFakeReferrals() {
|
|
241
241
|
const now = Date.now();
|
|
242
242
|
const oneDay = 24 * 60 * 60 * 1000;
|
|
243
|
-
|
|
243
|
+
|
|
244
244
|
return [
|
|
245
245
|
{
|
|
246
246
|
uid: 'user_k9m2n8p4q1r7',
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Security section module
|
|
2
|
-
import
|
|
2
|
+
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
3
3
|
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
4
|
+
import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
|
|
4
5
|
|
|
5
6
|
let webManager = null;
|
|
6
7
|
let firebaseAuth = null;
|
|
@@ -98,20 +99,17 @@ async function updateSigninMethods() {
|
|
|
98
99
|
// Update Google signin display
|
|
99
100
|
const $googleEmail = document.getElementById('google-email');
|
|
100
101
|
const $googleForm = document.getElementById('signin-method-google-form');
|
|
101
|
-
const $
|
|
102
|
-
const $
|
|
103
|
-
const $googleAction = $googleForm?.querySelector('input[name="action"]');
|
|
104
|
-
const $googleIcon = $googleBtn?.querySelector('.fa-icon');
|
|
102
|
+
const $connectButton = $googleForm?.querySelector('button[data-action="connect"]');
|
|
103
|
+
const $disconnectButton = $googleForm?.querySelector('button[data-action="disconnect"]');
|
|
105
104
|
|
|
106
105
|
console.log('[DEBUG] security.js - Google DOM elements:', {
|
|
107
106
|
$googleEmail: !!$googleEmail,
|
|
108
|
-
$
|
|
109
|
-
$
|
|
110
|
-
$
|
|
111
|
-
$googleIcon: !!$googleIcon
|
|
107
|
+
$googleForm: !!$googleForm,
|
|
108
|
+
$connectButton: !!$connectButton,
|
|
109
|
+
$disconnectButton: !!$disconnectButton
|
|
112
110
|
});
|
|
113
111
|
|
|
114
|
-
if ($googleEmail && $
|
|
112
|
+
if ($googleEmail && $connectButton && $disconnectButton) {
|
|
115
113
|
// Check if user has Google provider using firebaseUser for most up-to-date data
|
|
116
114
|
const googleProvider = firebaseUser.providerData?.find(provider => provider.providerId === 'google.com');
|
|
117
115
|
|
|
@@ -119,45 +117,19 @@ async function updateSigninMethods() {
|
|
|
119
117
|
console.log('[DEBUG] security.js - googleProvider found:', !!googleProvider);
|
|
120
118
|
|
|
121
119
|
if (googleProvider) {
|
|
122
|
-
console.log('[DEBUG] security.js -
|
|
123
|
-
console.log('[DEBUG] security.js - Button text before:', $googleBtnText?.textContent);
|
|
124
|
-
console.log('[DEBUG] security.js - Button classes before:', $googleBtn.className);
|
|
120
|
+
console.log('[DEBUG] security.js - Showing disconnect button');
|
|
125
121
|
|
|
126
122
|
$googleEmail.textContent = googleProvider.email || 'Connected';
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
$
|
|
130
|
-
$googleBtn.classList.add('btn-outline-danger');
|
|
131
|
-
|
|
132
|
-
// Update icon from link to unlink
|
|
133
|
-
if ($googleIcon) {
|
|
134
|
-
$googleIcon.classList.remove('fa-link');
|
|
135
|
-
$googleIcon.classList.add('fa-unlink');
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
console.log('[DEBUG] security.js - Button text after:', $googleBtnText?.textContent);
|
|
139
|
-
console.log('[DEBUG] security.js - Button classes after:', $googleBtn.className);
|
|
140
|
-
console.log('[DEBUG] security.js - Action value:', $googleAction?.value);
|
|
123
|
+
// Hide connect button, show disconnect button
|
|
124
|
+
$connectButton.classList.add('d-none');
|
|
125
|
+
$disconnectButton.classList.remove('d-none');
|
|
141
126
|
} else {
|
|
142
|
-
console.log('[DEBUG] security.js -
|
|
143
|
-
console.log('[DEBUG] security.js - Button text before:', $googleBtnText?.textContent);
|
|
144
|
-
console.log('[DEBUG] security.js - Button classes before:', $googleBtn.className);
|
|
127
|
+
console.log('[DEBUG] security.js - Showing connect button');
|
|
145
128
|
|
|
146
129
|
$googleEmail.textContent = 'Not connected';
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
$
|
|
150
|
-
$googleBtn.classList.add('btn-primary');
|
|
151
|
-
|
|
152
|
-
// Update icon from unlink to link
|
|
153
|
-
if ($googleIcon) {
|
|
154
|
-
$googleIcon.classList.remove('fa-unlink');
|
|
155
|
-
$googleIcon.classList.add('fa-link');
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
console.log('[DEBUG] security.js - Button text after:', $googleBtnText?.textContent);
|
|
159
|
-
console.log('[DEBUG] security.js - Button classes after:', $googleBtn.className);
|
|
160
|
-
console.log('[DEBUG] security.js - Action value:', $googleAction?.value);
|
|
130
|
+
// Show connect button, hide disconnect button
|
|
131
|
+
$connectButton.classList.remove('d-none');
|
|
132
|
+
$disconnectButton.classList.add('d-none');
|
|
161
133
|
}
|
|
162
134
|
}
|
|
163
135
|
}
|
|
@@ -214,16 +186,14 @@ async function updateActiveSessions(account) {
|
|
|
214
186
|
|
|
215
187
|
// Fetch other active sessions from server
|
|
216
188
|
try {
|
|
217
|
-
const token = await webManager.auth().getIdToken();
|
|
218
189
|
const serverApiURL = webManager.getApiUrl() + '/backend-manager';
|
|
219
190
|
|
|
220
|
-
const data = await
|
|
191
|
+
const data = await authorizedFetch(serverApiURL, {
|
|
221
192
|
method: 'POST',
|
|
222
193
|
timeout: 60000,
|
|
223
194
|
response: 'json',
|
|
224
195
|
tries: 2,
|
|
225
196
|
body: {
|
|
226
|
-
authenticationToken: token,
|
|
227
197
|
command: 'user:get-active-sessions',
|
|
228
198
|
payload: {
|
|
229
199
|
// id: 'app',
|
|
@@ -231,14 +201,12 @@ async function updateActiveSessions(account) {
|
|
|
231
201
|
},
|
|
232
202
|
});
|
|
233
203
|
|
|
234
|
-
console.log('Active sessions data from server:', data);
|
|
235
|
-
|
|
236
204
|
// Process sessions from server response
|
|
237
205
|
let sessionData = data || {};
|
|
238
206
|
|
|
239
|
-
// Add fake data if
|
|
207
|
+
// Add fake data if _dev_prefill=true is in query string
|
|
240
208
|
const urlParams = new URLSearchParams(window.location.search);
|
|
241
|
-
if (urlParams.get('
|
|
209
|
+
if (urlParams.get('_dev_prefill') === 'true') {
|
|
242
210
|
console.log('Adding fake session data for testing');
|
|
243
211
|
const fakeSessions = generateFakeSessions();
|
|
244
212
|
// Merge fake sessions with existing data (fake sessions don't override real ones)
|
|
@@ -308,23 +276,24 @@ async function updateActiveSessions(account) {
|
|
|
308
276
|
return;
|
|
309
277
|
}
|
|
310
278
|
|
|
311
|
-
const sessionHTML = sessions.map(session => {
|
|
279
|
+
const sessionHTML = sessions.map((session, index) => {
|
|
312
280
|
const deviceName = session.device || 'Unknown Device';
|
|
313
281
|
const browserName = session.browser || 'Unknown Browser';
|
|
314
282
|
const location = formatSessionLocation(session);
|
|
283
|
+
const isLast = index === sessions.length - 1;
|
|
315
284
|
|
|
316
285
|
return `
|
|
317
|
-
<div class="
|
|
286
|
+
<div class="px-0 py-3${isLast ? '' : ' border-bottom'}">
|
|
318
287
|
<div class="d-flex justify-content-between align-items-start">
|
|
319
|
-
<div class="d-flex align-items-
|
|
320
|
-
<div class="me-3
|
|
288
|
+
<div class="d-flex align-items-center">
|
|
289
|
+
<div class="d-flex align-items-center justify-content-center me-3 flex-shrink-0 text-muted">
|
|
321
290
|
${getDeviceIcon(session.platform || deviceName)}
|
|
322
291
|
</div>
|
|
323
292
|
<div>
|
|
324
|
-
<
|
|
325
|
-
<
|
|
326
|
-
${location ? `<
|
|
327
|
-
${session.ip ? `<
|
|
293
|
+
<strong>${deviceName}</strong>
|
|
294
|
+
<div class="text-muted small">${browserName}${session.mobile !== undefined ? ` • ${session.mobile ? 'Mobile' : 'Desktop'}` : ''}</div>
|
|
295
|
+
${location ? `<div class="text-muted small">${location}</div>` : ''}
|
|
296
|
+
${session.ip ? `<div class="text-muted small">IP: ${session.ip}</div>` : ''}
|
|
328
297
|
</div>
|
|
329
298
|
</div>
|
|
330
299
|
<div class="text-end">
|
|
@@ -385,12 +354,15 @@ function initializeSigninMethodForms() {
|
|
|
385
354
|
|
|
386
355
|
formManager.addEventListener('submit', async (event) => {
|
|
387
356
|
event.preventDefault();
|
|
388
|
-
const {
|
|
357
|
+
const { submitButton } = event.detail;
|
|
358
|
+
|
|
359
|
+
// Determine action from the clicked button's data-action attribute
|
|
360
|
+
const action = submitButton?.getAttribute('data-action');
|
|
389
361
|
|
|
390
362
|
try {
|
|
391
|
-
if (
|
|
363
|
+
if (action === 'disconnect') {
|
|
392
364
|
await disconnectGoogleProvider();
|
|
393
|
-
} else {
|
|
365
|
+
} else if (action === 'connect') {
|
|
394
366
|
await connectGoogleProvider();
|
|
395
367
|
}
|
|
396
368
|
|
|
@@ -434,10 +406,13 @@ function initializeSignoutAllForm() {
|
|
|
434
406
|
signoutAllForm.addEventListener('submit', async (event) => {
|
|
435
407
|
event.preventDefault();
|
|
436
408
|
|
|
409
|
+
// 1ms wait to allow form state to update and show processing
|
|
410
|
+
await new Promise(resolve => setTimeout(resolve, 1));
|
|
411
|
+
|
|
437
412
|
try {
|
|
438
413
|
// Confirm sign out
|
|
439
414
|
if (!confirm('Are you sure you want to sign out of all sessions? This will log you out everywhere, including this device.')) {
|
|
440
|
-
|
|
415
|
+
return signoutAllForm.setFormState('ready');
|
|
441
416
|
}
|
|
442
417
|
|
|
443
418
|
// Sign out of all sessions
|
|
@@ -632,20 +607,25 @@ function getPlatformName(platform) {
|
|
|
632
607
|
// Get device icon based on device type
|
|
633
608
|
function getDeviceIcon(device) {
|
|
634
609
|
const deviceLower = (device || '').toLowerCase();
|
|
610
|
+
let iconName = 'desktop'; // default
|
|
635
611
|
|
|
636
|
-
if (deviceLower.includes('iphone')
|
|
637
|
-
|
|
612
|
+
if (deviceLower.includes('iphone')
|
|
613
|
+
|| deviceLower.includes('ipad')
|
|
614
|
+
|| deviceLower.includes('ios')
|
|
615
|
+
|| deviceLower.includes('mac')) {
|
|
616
|
+
iconName = 'apple';
|
|
638
617
|
} else if (deviceLower.includes('android')) {
|
|
639
|
-
|
|
618
|
+
iconName = 'android';
|
|
640
619
|
} else if (deviceLower.includes('windows')) {
|
|
641
|
-
|
|
620
|
+
iconName = 'windows';
|
|
642
621
|
} else if (deviceLower.includes('linux')) {
|
|
643
|
-
|
|
622
|
+
iconName = 'linux';
|
|
644
623
|
} else if (deviceLower.includes('chrome')) {
|
|
645
|
-
|
|
646
|
-
} else {
|
|
647
|
-
return '<i class="fa-solid fa-desktop fa-lg"></i>';
|
|
624
|
+
iconName = 'chrome';
|
|
648
625
|
}
|
|
626
|
+
|
|
627
|
+
// Get the pre-rendered icon
|
|
628
|
+
return getPrerenderedIcon(iconName);
|
|
649
629
|
}
|
|
650
630
|
|
|
651
631
|
// Format location from session data
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// Libraries
|
|
2
2
|
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
3
3
|
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
4
|
+
import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
|
|
4
5
|
let webManager = null;
|
|
5
6
|
|
|
6
7
|
// Module
|
|
@@ -416,7 +417,9 @@ function updateChannelBadges(formData) {
|
|
|
416
417
|
const channels = formData.channels || {};
|
|
417
418
|
const $badgesContainer = document.querySelector('.card .d-flex.gap-2.flex-wrap');
|
|
418
419
|
|
|
419
|
-
if (!$badgesContainer)
|
|
420
|
+
if (!$badgesContainer) {
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
420
423
|
|
|
421
424
|
// Clear existing badges
|
|
422
425
|
$badgesContainer.innerHTML = '';
|
|
@@ -430,20 +433,24 @@ function updateChannelBadges(formData) {
|
|
|
430
433
|
};
|
|
431
434
|
|
|
432
435
|
Object.keys(channelConfigs).forEach(channel => {
|
|
433
|
-
if (channels[channel]?.enabled) {
|
|
434
|
-
|
|
435
|
-
const $badge = document.createElement('span');
|
|
436
|
-
$badge.className = `badge bg-${config.color}`;
|
|
437
|
-
$badge.innerHTML = `<i class="bi bi-${config.icon} me-1"></i>${channel.charAt(0).toUpperCase() + channel.slice(1)}`;
|
|
438
|
-
$badgesContainer.appendChild($badge);
|
|
436
|
+
if (!channels[channel]?.enabled) {
|
|
437
|
+
return;
|
|
439
438
|
}
|
|
439
|
+
|
|
440
|
+
const config = channelConfigs[channel];
|
|
441
|
+
const iconHTML = getPrerenderedIcon(config.icon);
|
|
442
|
+
const $badge = document.createElement('span');
|
|
443
|
+
$badge.className = `badge bg-${config.color}`;
|
|
444
|
+
$badge.innerHTML = `${iconHTML}${channel.charAt(0).toUpperCase() + channel.slice(1)}`;
|
|
445
|
+
$badgesContainer.appendChild($badge);
|
|
440
446
|
});
|
|
441
447
|
|
|
442
448
|
// Default to push if no channels selected
|
|
443
449
|
if ($badgesContainer.children.length === 0) {
|
|
450
|
+
const iconHTML = getPrerenderedIcon('mobile');
|
|
444
451
|
const $badge = document.createElement('span');
|
|
445
452
|
$badge.className = 'badge bg-primary';
|
|
446
|
-
$badge.innerHTML =
|
|
453
|
+
$badge.innerHTML = `${iconHTML}Push`;
|
|
447
454
|
$badgesContainer.appendChild($badge);
|
|
448
455
|
}
|
|
449
456
|
}
|
|
@@ -573,9 +580,9 @@ function trackNotificationSent(payload) {
|
|
|
573
580
|
// TikTok Pixel
|
|
574
581
|
if (typeof ttq !== 'undefined') {
|
|
575
582
|
ttq.track('SubmitForm', {
|
|
583
|
+
content_id: 'admin-notification',
|
|
584
|
+
content_type: 'product',
|
|
576
585
|
content_name: 'Admin Notification',
|
|
577
|
-
content_type: 'notification',
|
|
578
|
-
value: stats.filteredUsers
|
|
579
586
|
});
|
|
580
587
|
}
|
|
581
588
|
}
|
|
@@ -156,13 +156,14 @@ function trackNewsletterSignup() {
|
|
|
156
156
|
event_label: 'blog_page',
|
|
157
157
|
value: 1
|
|
158
158
|
});
|
|
159
|
-
fbq('track', '
|
|
159
|
+
fbq('track', 'Lead', {
|
|
160
160
|
content_name: 'Newsletter',
|
|
161
161
|
status: 'success'
|
|
162
162
|
});
|
|
163
163
|
ttq.track('Subscribe', {
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
content_id: 'newsletter-blog',
|
|
165
|
+
content_type: 'product',
|
|
166
|
+
content_name: 'Newsletter'
|
|
166
167
|
});
|
|
167
168
|
}
|
|
168
169
|
|
|
@@ -177,7 +178,8 @@ function trackBlogSearch(query) {
|
|
|
177
178
|
content_category: 'blog'
|
|
178
179
|
});
|
|
179
180
|
ttq.track('Search', {
|
|
180
|
-
|
|
181
|
-
content_type: '
|
|
181
|
+
content_id: 'blog-search',
|
|
182
|
+
content_type: 'product',
|
|
183
|
+
search_string: query
|
|
182
184
|
});
|
|
183
185
|
}
|
|
@@ -55,8 +55,6 @@ function setupFormScrolling() {
|
|
|
55
55
|
const href = link.getAttribute('href');
|
|
56
56
|
|
|
57
57
|
if (href === '#chat') {
|
|
58
|
-
trackChatClick();
|
|
59
|
-
|
|
60
58
|
// Open chat window
|
|
61
59
|
try {
|
|
62
60
|
chatsy.open();
|
|
@@ -65,8 +63,6 @@ function setupFormScrolling() {
|
|
|
65
63
|
webManager.utilities().showNotification('Chat is currently unavailable. Please try again later.', 'danger');
|
|
66
64
|
}
|
|
67
65
|
} else if (href === '#form') {
|
|
68
|
-
trackFormClick();
|
|
69
|
-
|
|
70
66
|
// Find the form section by ID
|
|
71
67
|
const $formSection = document.getElementById('form');
|
|
72
68
|
|
|
@@ -193,31 +189,6 @@ function handleFieldChange(event) {
|
|
|
193
189
|
}
|
|
194
190
|
}
|
|
195
191
|
|
|
196
|
-
// Tracking functions
|
|
197
|
-
function trackChatClick() {
|
|
198
|
-
// gtag('event', 'contact_method_click', {
|
|
199
|
-
// method: 'chat'
|
|
200
|
-
// });
|
|
201
|
-
// fbq('track', 'Contact', {
|
|
202
|
-
// content_name: 'Chat'
|
|
203
|
-
// });
|
|
204
|
-
// ttq.track('ClickButton', {
|
|
205
|
-
// content_name: 'Chat'
|
|
206
|
-
// });
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
function trackFormClick() {
|
|
210
|
-
// gtag('event', 'contact_method_click', {
|
|
211
|
-
// method: 'form'
|
|
212
|
-
// });
|
|
213
|
-
// fbq('track', 'Contact', {
|
|
214
|
-
// content_name: 'Form'
|
|
215
|
-
// });
|
|
216
|
-
// ttq.track('ClickButton', {
|
|
217
|
-
// content_name: 'Contact Form'
|
|
218
|
-
// });
|
|
219
|
-
}
|
|
220
|
-
|
|
221
192
|
function trackContactSpam() {
|
|
222
193
|
gtag('event', 'contact_form_spam', {
|
|
223
194
|
content_type: 'honeypot'
|
|
@@ -225,15 +196,17 @@ function trackContactSpam() {
|
|
|
225
196
|
}
|
|
226
197
|
|
|
227
198
|
function trackContactFormSubmit(subject) {
|
|
228
|
-
gtag('event', '
|
|
199
|
+
gtag('event', 'generate_lead', {
|
|
200
|
+
lead_source: 'contact_form',
|
|
229
201
|
subject: subject
|
|
230
202
|
});
|
|
231
203
|
fbq('track', 'Lead', {
|
|
232
204
|
content_name: 'Contact Form',
|
|
233
205
|
content_category: subject
|
|
234
206
|
});
|
|
235
|
-
ttq.track('
|
|
236
|
-
|
|
237
|
-
content_type:
|
|
207
|
+
ttq.track('Contact', {
|
|
208
|
+
content_id: 'contact-form',
|
|
209
|
+
content_type: 'product',
|
|
210
|
+
content_name: 'Contact Form'
|
|
238
211
|
});
|
|
239
212
|
}
|
|
@@ -174,8 +174,9 @@ function trackDownloadClick(platform, downloadName, downloadUrl) {
|
|
|
174
174
|
});
|
|
175
175
|
|
|
176
176
|
ttq.track('Download', {
|
|
177
|
-
|
|
178
|
-
content_type:
|
|
177
|
+
content_id: `download-${platform}`,
|
|
178
|
+
content_type: 'product',
|
|
179
|
+
content_name: downloadName
|
|
179
180
|
});
|
|
180
181
|
}
|
|
181
182
|
|
|
@@ -298,8 +298,8 @@ async function initializeCheckout() {
|
|
|
298
298
|
const urlParams = new URLSearchParams(window.location.search);
|
|
299
299
|
const productId = urlParams.get('product');
|
|
300
300
|
const frequency = urlParams.get('frequency') || 'annually';
|
|
301
|
-
const
|
|
302
|
-
const
|
|
301
|
+
const _dev_appId = urlParams.get('_dev_appId');
|
|
302
|
+
const _dev_trialEligible = urlParams.get('_dev_trialEligible');
|
|
303
303
|
|
|
304
304
|
// Product ID is required
|
|
305
305
|
if (!productId) {
|
|
@@ -307,7 +307,7 @@ async function initializeCheckout() {
|
|
|
307
307
|
}
|
|
308
308
|
|
|
309
309
|
// Check for testing parameters
|
|
310
|
-
const appId =
|
|
310
|
+
const appId = _dev_appId || webManager.config.brand.id;
|
|
311
311
|
|
|
312
312
|
// Warmup server (fire and forget)
|
|
313
313
|
warmupServer(webManager);
|
|
@@ -331,10 +331,10 @@ async function initializeCheckout() {
|
|
|
331
331
|
let trialEligibilityResult = trialEligible;
|
|
332
332
|
|
|
333
333
|
// Override trial eligibility for testing (only in development)
|
|
334
|
-
if (
|
|
335
|
-
if (
|
|
334
|
+
if (_dev_trialEligible && webManager.isDevelopment()) {
|
|
335
|
+
if (_dev_trialEligible === 'false') {
|
|
336
336
|
trialEligibilityResult = { status: 'fulfilled', value: false };
|
|
337
|
-
} else if (
|
|
337
|
+
} else if (_dev_trialEligible === 'true') {
|
|
338
338
|
trialEligibilityResult = { status: 'fulfilled', value: true };
|
|
339
339
|
}
|
|
340
340
|
}
|
|
@@ -41,9 +41,9 @@ export class PaymentProcessorManager {
|
|
|
41
41
|
|
|
42
42
|
// Determine processor based on payment method and available API keys
|
|
43
43
|
if (paymentMethod === 'card') {
|
|
44
|
-
// Check for
|
|
44
|
+
// Check for _dev_cardProcessor override in URL params (for testing)
|
|
45
45
|
const urlParams = new URLSearchParams(window.location.search);
|
|
46
|
-
const forcedProcessor = urlParams.get('
|
|
46
|
+
const forcedProcessor = urlParams.get('_dev_cardProcessor');
|
|
47
47
|
|
|
48
48
|
if (forcedProcessor && this.processors[forcedProcessor]) {
|
|
49
49
|
processorName = forcedProcessor;
|