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.
Files changed (44) hide show
  1. package/CLAUDE.md +616 -138
  2. package/README.md +108 -0
  3. package/TODO.md +1 -1
  4. package/dist/assets/js/core/auth.js +8 -11
  5. package/dist/assets/js/core/cookieconsent.js +24 -17
  6. package/dist/assets/js/core/exit-popup.js +15 -12
  7. package/dist/assets/js/core/social-sharing.js +8 -4
  8. package/dist/assets/js/libs/auth/pages.js +14 -13
  9. package/dist/assets/js/libs/dev.js +192 -129
  10. package/dist/assets/js/libs/prerendered-icons.js +27 -0
  11. package/dist/assets/js/pages/account/index.js +4 -3
  12. package/dist/assets/js/pages/account/sections/api-keys.js +2 -6
  13. package/dist/assets/js/pages/account/sections/connections.js +101 -59
  14. package/dist/assets/js/pages/account/sections/delete.js +83 -84
  15. package/dist/assets/js/pages/account/sections/referrals.js +29 -29
  16. package/dist/assets/js/pages/account/sections/security.js +51 -71
  17. package/dist/assets/js/pages/admin/notifications/new/index.js +17 -10
  18. package/dist/assets/js/pages/blog/index.js +7 -5
  19. package/dist/assets/js/pages/contact/index.js +6 -33
  20. package/dist/assets/js/pages/download/index.js +3 -2
  21. package/dist/assets/js/pages/payment/checkout/index.js +6 -6
  22. package/dist/assets/js/pages/payment/checkout/modules/processors-main.js +2 -2
  23. package/dist/assets/js/pages/payment/checkout/modules/session.js +4 -4
  24. package/dist/assets/js/pages/pricing/index.js +5 -2
  25. package/dist/assets/themes/classy/css/components/_cards.scss +2 -2
  26. package/dist/defaults/_.env +6 -0
  27. package/dist/defaults/_.gitignore +7 -1
  28. package/dist/defaults/dist/_includes/core/body.html +18 -3
  29. package/dist/defaults/dist/_includes/core/foot.html +1 -0
  30. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +51 -36
  31. package/dist/defaults/dist/_layouts/blueprint/admin/notifications/new.html +13 -2
  32. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +84 -42
  33. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +67 -35
  34. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +72 -58
  35. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +46 -29
  36. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +36 -16
  37. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +111 -73
  38. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +111 -56
  39. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +127 -81
  40. package/dist/defaults/dist/pages/pricing.md +7 -0
  41. package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +1 -1
  42. package/dist/gulp/tasks/defaults.js +210 -1
  43. package/firebase-debug.log +504 -0
  44. 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 _test_prefill=true is in query string
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('_test_prefill') === 'true') {
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 fetch from 'wonderful-fetch';
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 $googleBtn = $googleForm?.querySelector('button[type="submit"]');
102
- const $googleBtnText = $googleBtn?.querySelector('.button-text');
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
- $googleBtn: !!$googleBtn,
109
- $googleBtnText: !!$googleBtnText,
110
- $googleAction: !!$googleAction,
111
- $googleIcon: !!$googleIcon
107
+ $googleForm: !!$googleForm,
108
+ $connectButton: !!$connectButton,
109
+ $disconnectButton: !!$disconnectButton
112
110
  });
113
111
 
114
- if ($googleEmail && $googleBtn) {
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 - Setting button to DISCONNECT state');
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
- if ($googleBtnText) $googleBtnText.textContent = 'Disconnect';
128
- if ($googleAction) $googleAction.value = 'disconnect';
129
- $googleBtn.classList.remove('btn-primary');
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 - Setting button to CONNECT state');
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
- if ($googleBtnText) $googleBtnText.textContent = 'Connect';
148
- if ($googleAction) $googleAction.value = 'connect';
149
- $googleBtn.classList.remove('btn-outline-danger');
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 fetch(serverApiURL, {
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 _test_prefill=true is in query string
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('_test_prefill') === 'true') {
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="list-group-item px-0 bg-body-tertiary">
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-start">
320
- <div class="me-3 mt-1">
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
- <div class="fw-semibold">${deviceName}</div>
325
- <small class="text-muted d-block">${browserName}${session.mobile !== undefined ? ` • ${session.mobile ? 'Mobile' : 'Desktop'}` : ''}</small>
326
- ${location ? `<small class="text-muted d-block">${location}</small>` : ''}
327
- ${session.ip ? `<small class="text-muted d-block">IP: ${session.ip}</small>` : ''}
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 { data } = event.detail;
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 (data.action === 'disconnect') {
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
- throw new Error('Sign out cancelled');
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') || deviceLower.includes('ipad') || deviceLower.includes('ios') || deviceLower.includes('mac')) {
637
- return '<i class="fa-brands fa-apple fa-lg"></i>';
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
- return '<i class="fa-brands fa-android fa-lg"></i>';
618
+ iconName = 'android';
640
619
  } else if (deviceLower.includes('windows')) {
641
- return '<i class="fa-brands fa-windows fa-lg"></i>';
620
+ iconName = 'windows';
642
621
  } else if (deviceLower.includes('linux')) {
643
- return '<i class="fa-brands fa-linux fa-lg"></i>';
622
+ iconName = 'linux';
644
623
  } else if (deviceLower.includes('chrome')) {
645
- return '<i class="fa-brands fa-chrome fa-lg"></i>';
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) return;
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
- const config = channelConfigs[channel];
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 = '<i class="bi bi-mobile me-1"></i>Push';
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', 'CompleteRegistration', {
159
+ fbq('track', 'Lead', {
160
160
  content_name: 'Newsletter',
161
161
  status: 'success'
162
162
  });
163
163
  ttq.track('Subscribe', {
164
- content_name: 'Newsletter',
165
- status: 'success'
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
- query: query,
181
- content_type: 'blog'
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', 'contact_form_submit', {
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('FormSubmit', {
236
- content_name: 'Contact Form',
237
- content_type: subject
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
- content_name: downloadName,
178
- content_type: platform
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 _test_appId = urlParams.get('_test_appId');
302
- const _test_trialEligible = urlParams.get('_test_trialEligible');
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 = _test_appId || webManager.config.brand.id;
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 (_test_trialEligible && webManager.isDevelopment()) {
335
- if (_test_trialEligible === 'false') {
334
+ if (_dev_trialEligible && webManager.isDevelopment()) {
335
+ if (_dev_trialEligible === 'false') {
336
336
  trialEligibilityResult = { status: 'fulfilled', value: false };
337
- } else if (_test_trialEligible === 'true') {
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 _test_cardProcessor override in URL params (for testing)
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('_test_cardProcessor');
46
+ const forcedProcessor = urlParams.get('_dev_cardProcessor');
47
47
 
48
48
  if (forcedProcessor && this.processors[forcedProcessor]) {
49
49
  processorName = forcedProcessor;