ultimate-jekyll-manager 0.0.118 → 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 (34) hide show
  1. package/CLAUDE.md +307 -21
  2. package/dist/assets/js/core/auth.js +5 -4
  3. package/dist/assets/js/core/cookieconsent.js +24 -17
  4. package/dist/assets/js/core/exit-popup.js +15 -12
  5. package/dist/assets/js/core/social-sharing.js +8 -4
  6. package/dist/assets/js/libs/auth/pages.js +14 -13
  7. package/dist/assets/js/libs/dev.js +192 -129
  8. package/dist/assets/js/pages/account/index.js +3 -2
  9. package/dist/assets/js/pages/account/sections/delete.js +83 -84
  10. package/dist/assets/js/pages/account/sections/security.js +4 -1
  11. package/dist/assets/js/pages/admin/notifications/new/index.js +17 -10
  12. package/dist/assets/js/pages/blog/index.js +7 -5
  13. package/dist/assets/js/pages/contact/index.js +6 -33
  14. package/dist/assets/js/pages/download/index.js +3 -2
  15. package/dist/assets/js/pages/pricing/index.js +5 -2
  16. package/dist/assets/themes/classy/css/components/_cards.scss +2 -2
  17. package/dist/defaults/_.env +6 -0
  18. package/dist/defaults/_.gitignore +7 -1
  19. package/dist/defaults/dist/_includes/core/body.html +5 -13
  20. package/dist/defaults/dist/_includes/core/foot.html +1 -0
  21. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +51 -36
  22. package/dist/defaults/dist/_layouts/blueprint/admin/notifications/new.html +13 -2
  23. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +84 -42
  24. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +26 -21
  25. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +72 -58
  26. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +46 -29
  27. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +36 -16
  28. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +111 -73
  29. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +111 -56
  30. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +127 -81
  31. package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +1 -1
  32. package/dist/gulp/tasks/defaults.js +210 -1
  33. package/firebase-debug.log +378 -0
  34. package/package.json +2 -2
@@ -121,159 +121,222 @@ function setupBreakpointLogger() {
121
121
  function setupTrackingInterceptors() {
122
122
  console.log('🔍 Setting up tracking interceptors...');
123
123
 
124
- // Intercept Google Analytics (gtag)
125
- if (typeof window.gtag !== 'undefined') {
126
- const originalGtag = window.gtag;
127
- window.gtag = function() {
128
- const args = Array.from(arguments);
129
- const command = args[0];
130
- const eventNameOrParams = args[1];
131
- const params = args[2];
132
-
133
- // Log the gtag call
134
- console.log('📊 gtag:', {
135
- command: command,
136
- event: eventNameOrParams,
137
- params: params || eventNameOrParams,
138
- fullArgs: args
139
- });
140
-
141
- // Call the original gtag function
142
- return originalGtag.apply(this, arguments);
143
- };
144
- console.log('✅ gtag interceptor installed');
145
- }
124
+ // Track which interceptors have been installed
125
+ const installed = {
126
+ gtag: false,
127
+ fbq: false,
128
+ ttq: false,
129
+ };
146
130
 
147
- // Intercept Facebook Pixel (fbq)
148
- if (typeof window.fbq !== 'undefined') {
149
- const originalFbq = window.fbq;
131
+ // Try to install interceptors
132
+ const tryInstallInterceptors = () => {
133
+ // Try installing gtag if not already installed
134
+ if (!installed.gtag && typeof window.gtag !== 'undefined') {
135
+ installGtagInterceptor();
136
+ installed.gtag = true;
137
+ }
150
138
 
151
- // Create wrapper function that preserves all properties
152
- const fbqWrapper = function() {
153
- const args = Array.from(arguments);
154
- const command = args[0];
155
- const event = args[1];
156
- const params = args[2];
157
-
158
- // Log the fbq call
159
- console.log('📘 fbq:', {
160
- command: command,
161
- event: event,
162
- params: params,
163
- fullArgs: args
164
- });
165
-
166
- // Call the original fbq function
167
- return originalFbq.apply(this, arguments);
168
- };
139
+ // Try installing fbq if not already installed
140
+ if (!installed.fbq && typeof window.fbq !== 'undefined') {
141
+ installFbqInterceptor();
142
+ installed.fbq = true;
143
+ }
169
144
 
170
- // Copy all properties from original fbq to wrapper
171
- Object.keys(originalFbq).forEach(key => {
172
- fbqWrapper[key] = originalFbq[key];
173
- });
145
+ // Try installing ttq if not already installed
146
+ if (!installed.ttq && typeof window.ttq !== 'undefined' && window.ttq.track) {
147
+ // Check if it's a stub (contains 'push' in the function)
148
+ const isStub = window.ttq.track.toString().includes('push');
174
149
 
175
- // If callMethod exists, wrap it too
176
- if (originalFbq.callMethod) {
177
- const originalCallMethod = originalFbq.callMethod;
178
- fbqWrapper.callMethod = function() {
179
- const args = Array.from(arguments);
180
- console.log('📘 fbq.callMethod:', args);
181
- return originalCallMethod.apply(originalFbq, arguments);
182
- };
150
+ if (!isStub) {
151
+ installTtqInterceptor();
152
+ installed.ttq = true;
153
+ }
183
154
  }
184
155
 
185
- // Preserve queue if it exists (for stub implementation)
186
- if (originalFbq.queue) {
187
- fbqWrapper.queue = originalFbq.queue;
156
+ // Return true if all interceptors are installed
157
+ return installed.gtag && installed.fbq && installed.ttq;
158
+ };
159
+
160
+ // Try installing immediately
161
+ if (tryInstallInterceptors()) {
162
+ return;
163
+ }
164
+
165
+ // Poll every 500ms to check if tracking libraries are ready
166
+ const pollInterval = setInterval(() => {
167
+ if (tryInstallInterceptors()) {
168
+ clearInterval(pollInterval);
188
169
  }
170
+ }, 500);
171
+
172
+ // Stop polling after 10 seconds regardless
173
+ setTimeout(() => {
174
+ clearInterval(pollInterval);
175
+ console.log('⏱️ Tracking interceptor polling stopped');
189
176
 
190
- // Preserve push method if it exists (for stub implementation)
191
- if (originalFbq.push) {
192
- fbqWrapper.push = originalFbq.push;
177
+ if (!installed.gtag) {
178
+ console.log('⚠️ gtag interceptor was never installed');
193
179
  }
180
+ if (!installed.fbq) {
181
+ console.log('⚠️ fbq interceptor was never installed');
182
+ }
183
+ if (!installed.ttq) {
184
+ console.log('⚠️ ttq interceptor was never installed');
185
+ }
186
+ }, 10000);
187
+ }
194
188
 
195
- window.fbq = fbqWrapper;
196
- console.log('✅ fbq interceptor installed');
189
+ function installGtagInterceptor() {
190
+ if (typeof window.gtag === 'undefined') {
191
+ return;
197
192
  }
198
193
 
199
- // Intercept TikTok Pixel (ttq)
200
- if (typeof window.ttq !== 'undefined' && window.ttq.track) {
201
- const originalTtq = window.ttq;
202
- const originalTrack = window.ttq.track;
203
- const originalPage = window.ttq.page;
204
- const originalIdentify = window.ttq.identify;
205
- const originalLoad = window.ttq.load;
194
+ const originalGtag = window.gtag;
206
195
 
207
- // Intercept track method
208
- window.ttq.track = function() {
209
- const args = Array.from(arguments);
210
- const event = args[0];
211
- const params = args[1];
212
-
213
- // Log the ttq.track call
214
- console.log('🎵 ttq.track:', {
215
- event: event,
216
- params: params,
217
- fullArgs: args
218
- });
219
-
220
- // Call the original track function
221
- return originalTrack.apply(originalTtq, arguments);
222
- };
196
+ window.gtag = function() {
197
+ const args = Array.from(arguments);
198
+ const command = args[0];
199
+ const eventNameOrParams = args[1];
200
+ const params = args[2];
223
201
 
224
- // Intercept page method
225
- window.ttq.page = function() {
226
- const args = Array.from(arguments);
202
+ // Log the gtag call
203
+ console.log('📊 gtag:', {
204
+ command: command,
205
+ event: eventNameOrParams,
206
+ params: params || eventNameOrParams,
207
+ fullArgs: args
208
+ });
227
209
 
228
- // Log the ttq.page call
229
- console.log('🎵 ttq.page:', {
230
- fullArgs: args
231
- });
210
+ // Call the original gtag function
211
+ return originalGtag.apply(this, arguments);
212
+ };
232
213
 
233
- // Call the original page function
234
- return originalPage.apply(originalTtq, arguments);
235
- };
214
+ console.log('✅ gtag interceptor installed');
215
+ }
236
216
 
237
- // Intercept identify method
238
- window.ttq.identify = function() {
239
- const args = Array.from(arguments);
217
+ function installFbqInterceptor() {
218
+ if (typeof window.fbq === 'undefined') {
219
+ return;
220
+ }
240
221
 
241
- // Log the ttq.identify call
242
- console.log('🎵 ttq.identify:', {
243
- fullArgs: args
244
- });
222
+ const originalFbq = window.fbq;
223
+
224
+ // Create wrapper function that preserves all properties
225
+ const fbqWrapper = function() {
226
+ const args = Array.from(arguments);
227
+ const command = args[0];
228
+ const event = args[1];
229
+ const params = args[2];
230
+
231
+ // Log the fbq call
232
+ console.log('📘 fbq:', {
233
+ command: command,
234
+ event: event,
235
+ params: params,
236
+ fullArgs: args
237
+ });
245
238
 
246
- // Call the original identify function
247
- return originalIdentify.apply(originalTtq, arguments);
248
- };
239
+ // Call the original fbq function
240
+ return originalFbq.apply(this, arguments);
241
+ };
249
242
 
250
- // Intercept load method
251
- window.ttq.load = function() {
243
+ // Copy all properties from original fbq to wrapper
244
+ Object.keys(originalFbq).forEach(key => {
245
+ fbqWrapper[key] = originalFbq[key];
246
+ });
247
+
248
+ // If callMethod exists, wrap it too
249
+ if (originalFbq.callMethod) {
250
+ const originalCallMethod = originalFbq.callMethod;
251
+ fbqWrapper.callMethod = function() {
252
252
  const args = Array.from(arguments);
253
+ console.log('📘 fbq.callMethod:', args);
254
+ return originalCallMethod.apply(originalFbq, arguments);
255
+ };
256
+ }
257
+
258
+ // Preserve queue if it exists (for stub implementation)
259
+ if (originalFbq.queue) {
260
+ fbqWrapper.queue = originalFbq.queue;
261
+ }
253
262
 
254
- // Log the ttq.load call
255
- console.log('🎵 ttq.load:', {
256
- pixelId: args[0],
257
- fullArgs: args
258
- });
263
+ // Preserve push method if it exists (for stub implementation)
264
+ if (originalFbq.push) {
265
+ fbqWrapper.push = originalFbq.push;
266
+ }
259
267
 
260
- // Call the original load function
261
- return originalLoad.apply(originalTtq, arguments);
262
- };
268
+ window.fbq = fbqWrapper;
269
+ console.log('✅ fbq interceptor installed');
270
+ }
263
271
 
264
- console.log('✅ ttq interceptor installed');
272
+ function installTtqInterceptor() {
273
+ if (typeof window.ttq === 'undefined' || !window.ttq.track) {
274
+ return;
265
275
  }
266
276
 
267
- // Check again after a delay in case tracking libraries load asynchronously
268
- setTimeout(() => {
269
- if (typeof window.gtag === 'undefined') {
270
- console.log('⚠️ gtag not found - may load later');
271
- }
272
- if (typeof window.fbq === 'undefined') {
273
- console.log('⚠️ fbq not found - may load later');
274
- }
275
- if (typeof window.ttq === 'undefined' || !window.ttq.track) {
276
- console.log('⚠️ ttq not found or is a stub - may load later');
277
- }
278
- }, 3000);
277
+ const originalTtq = window.ttq;
278
+ const originalTrack = window.ttq.track;
279
+ const originalPage = window.ttq.page;
280
+ const originalIdentify = window.ttq.identify;
281
+ const originalLoad = window.ttq.load;
282
+
283
+ // Intercept track method
284
+ window.ttq.track = function() {
285
+ const args = Array.from(arguments);
286
+ const event = args[0];
287
+ const params = args[1];
288
+
289
+ // Log the ttq.track call
290
+ console.log('🎵 ttq.track:', {
291
+ event: event,
292
+ params: params,
293
+ fullArgs: args
294
+ });
295
+
296
+ // Call the original track function
297
+ return originalTrack.apply(originalTtq, arguments);
298
+ };
299
+
300
+ // Intercept page method
301
+ window.ttq.page = function() {
302
+ const args = Array.from(arguments);
303
+
304
+ // Log the ttq.page call
305
+ console.log('🎵 ttq.page:', {
306
+ fullArgs: args
307
+ });
308
+
309
+ // Call the original page function
310
+ return originalPage.apply(originalTtq, arguments);
311
+ };
312
+
313
+ // Intercept identify method
314
+ window.ttq.identify = function() {
315
+ const args = Array.from(arguments);
316
+
317
+ // Log the ttq.identify call
318
+ console.log('🎵 ttq.identify:', {
319
+ userData: args[0],
320
+ fullArgs: args
321
+ });
322
+
323
+ // Call the original identify function
324
+ return originalIdentify.apply(originalTtq, arguments);
325
+ };
326
+
327
+ // Intercept load method
328
+ window.ttq.load = function() {
329
+ const args = Array.from(arguments);
330
+
331
+ // Log the ttq.load call
332
+ console.log('🎵 ttq.load:', {
333
+ pixelId: args[0],
334
+ fullArgs: args
335
+ });
336
+
337
+ // Call the original load function
338
+ return originalLoad.apply(originalTtq, arguments);
339
+ };
340
+
341
+ console.log('✅ ttq interceptor installed');
279
342
  }
@@ -338,7 +338,8 @@ function trackAccountSectionView(sectionId) {
338
338
  section: sectionId
339
339
  });
340
340
  ttq.track('ViewContent', {
341
- content_name: `Account ${sectionId}`,
342
- content_type: 'account_section'
341
+ content_id: `account-${sectionId}`,
342
+ content_type: 'product',
343
+ content_name: `Account ${sectionId}`
343
344
  });
344
345
  }
@@ -1,7 +1,9 @@
1
1
  // Delete account section module
2
- import fetch from 'wonderful-fetch';
2
+ import { FormManager } from '__main_assets__/js/libs/form-manager.js';
3
+ import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
3
4
 
4
5
  let webManager = null;
6
+ let formManager = null;
5
7
 
6
8
  // Initialize delete section
7
9
  export async function init(wm) {
@@ -15,9 +17,21 @@ function setupDeleteAccountForm() {
15
17
  const $checkbox = document.getElementById('delete-confirm-checkbox');
16
18
  const $deleteBtn = document.getElementById('delete-account-btn');
17
19
  const $cancelBtn = document.getElementById('cancel-delete-btn');
18
- const $reason = document.getElementById('delete-reason');
19
20
 
20
- if (!$form || !$checkbox || !$deleteBtn) return;
21
+ if (!$form || !$checkbox || !$deleteBtn) {
22
+ return;
23
+ }
24
+
25
+ // Initialize FormManager
26
+ formManager = new FormManager('#delete-account-form', {
27
+ autoDisable: true,
28
+ showSpinner: true,
29
+ validateOnSubmit: false, // We'll handle validation manually due to custom confirmation flow
30
+ allowMultipleSubmissions: false,
31
+ resetOnSuccess: false,
32
+ submitButtonLoadingText: 'Deleting account...',
33
+ initialState: 'ready',
34
+ });
21
35
 
22
36
  // Enable/disable delete button based on checkbox
23
37
  $checkbox.addEventListener('change', (e) => {
@@ -32,75 +46,80 @@ function setupDeleteAccountForm() {
32
46
  });
33
47
  }
34
48
 
35
- // Handle form submission
36
- $form.addEventListener('submit', async (e) => {
37
- e.preventDefault();
49
+ // Listen to FormManager submit event
50
+ formManager.addEventListener('submit', handleFormSubmit);
51
+ }
38
52
 
39
- // Check if checkbox is checked
40
- if (!$checkbox.checked) {
41
- alert('Please confirm that you understand this action is permanent.');
42
- return;
43
- }
53
+ // Handle form submission
54
+ async function handleFormSubmit(event) {
55
+ // Prevent default FormManager submission
56
+ event.preventDefault();
44
57
 
45
- // Show confirmation dialog
46
- const confirmMessage = `Are you absolutely sure you want to delete your account?\n\nThis action CANNOT be undone.\n\nType "DELETE" to confirm:`;
47
- const userInput = prompt(confirmMessage);
58
+ const formData = event.detail.data;
59
+ const $checkbox = document.getElementById('delete-confirm-checkbox');
48
60
 
49
- if (userInput !== 'DELETE') {
50
- alert('Account deletion cancelled. You must type "DELETE" exactly to confirm.');
51
- return;
52
- }
61
+ // Check if checkbox is checked
62
+ if (!$checkbox.checked) {
63
+ formManager.showError('Please confirm that you understand this action is permanent.');
64
+ formManager.setFormState('ready');
65
+ return;
66
+ }
53
67
 
54
- // Final confirmation
55
- const finalConfirm = confirm('This is your last chance to cancel.\n\nAre you sure you want to permanently delete your account?');
56
-
57
- if (!finalConfirm) {
58
- return;
59
- }
68
+ // Show confirmation dialog
69
+ const confirmMessage = `Are you absolutely sure you want to delete your account?\n\nThis action CANNOT be undone.\n\nType "DELETE" to confirm:`;
70
+ const userInput = prompt(confirmMessage);
60
71
 
61
- // Disable button and show loading
62
- $deleteBtn.disabled = true;
63
- $deleteBtn.innerHTML = `<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span><span class="button-text">Deleting account...</span>`;
64
-
65
- try {
66
- // Get API base URL
67
- const apiBaseUrl = webManager.isDevelopment()
68
- ? 'http://localhost:5002'
69
- : 'https://api.itwcreativeworks.com';
70
-
71
- // Send delete request to server
72
- const response = await fetch(`${apiBaseUrl}/account/delete`, {
73
- method: 'POST',
74
- response: 'json',
75
- body: {
76
- reason: $reason.value || '',
72
+ if (userInput !== 'DELETE') {
73
+ formManager.showError('Account deletion cancelled. You must type "DELETE" exactly to confirm.');
74
+ formManager.setFormState('ready');
75
+ return;
76
+ }
77
+
78
+ // Final confirmation
79
+ const finalConfirm = confirm('This is your last chance to cancel.\n\nAre you sure you want to permanently delete your account?');
80
+
81
+ if (!finalConfirm) {
82
+ formManager.setFormState('ready');
83
+ return;
84
+ }
85
+
86
+ try {
87
+ // Send delete request to server
88
+ const response = await authorizedFetch(webManager.getApiUrl(), {
89
+ method: 'POST',
90
+ timeout: 30000,
91
+ response: 'json',
92
+ tries: 2,
93
+ body: {
94
+ command: 'user:delete',
95
+ payload: {
96
+ reason: formData.reason || '',
77
97
  confirmed: true
78
98
  }
79
- });
80
-
81
- console.log('Delete account response:', response);
82
-
83
- if (response.success) {
84
- // Show success message
85
- alert('Your account has been successfully deleted. You will now be signed out.');
86
-
87
- // Sign out the user
88
- await webManager.auth().signOut();
89
-
90
- // Redirect to home page
91
- window.location.href = '/';
92
- } else {
93
- throw new Error(response.message || 'Failed to delete account');
94
99
  }
95
- } catch (error) {
96
- console.error('Failed to delete account:', error);
97
- alert(`Failed to delete account: ${error.message}`);
98
-
99
- // Re-enable button
100
- $deleteBtn.disabled = !$checkbox.checked;
101
- $deleteBtn.innerHTML = `<i class="fa-solid fa-trash fa-sm me-2"></i><span class="button-text">Delete My Account Permanently</span>`;
100
+ });
101
+
102
+ console.log('Delete account response:', response);
103
+
104
+ if (response.success) {
105
+ // Show success message
106
+ formManager.showSuccess('Your account has been successfully deleted. You will now be signed out.');
107
+
108
+ // Sign out the user
109
+ await webManager.auth().signOut();
110
+
111
+ // Redirect to home page
112
+ setTimeout(() => {
113
+ window.location.href = '/';
114
+ }, 1500);
115
+ } else {
116
+ throw new Error(response.message || 'Failed to delete account');
102
117
  }
103
- });
118
+ } catch (error) {
119
+ console.error('Failed to delete account:', error);
120
+ formManager.showError(`Failed to delete account: ${error.message}`);
121
+ formManager.setFormState('ready');
122
+ }
104
123
  }
105
124
 
106
125
  // Load delete section data (if needed)
@@ -111,25 +130,5 @@ export async function loadData(account) {
111
130
 
112
131
  // Called when section is shown
113
132
  export function onShow() {
114
- // Reset form when shown
115
- const $form = document.getElementById('delete-account-form');
116
- const $checkbox = document.getElementById('delete-confirm-checkbox');
117
- const $deleteBtn = document.getElementById('delete-account-btn');
118
- const $reason = document.getElementById('delete-reason');
119
133
 
120
- if ($form) {
121
- $form.reset();
122
- }
123
-
124
- if ($checkbox) {
125
- $checkbox.checked = false;
126
- }
127
-
128
- if ($deleteBtn) {
129
- $deleteBtn.disabled = true;
130
- }
131
-
132
- if ($reason) {
133
- $reason.value = '';
134
- }
135
- }
134
+ }
@@ -406,10 +406,13 @@ function initializeSignoutAllForm() {
406
406
  signoutAllForm.addEventListener('submit', async (event) => {
407
407
  event.preventDefault();
408
408
 
409
+ // 1ms wait to allow form state to update and show processing
410
+ await new Promise(resolve => setTimeout(resolve, 1));
411
+
409
412
  try {
410
413
  // Confirm sign out
411
414
  if (!confirm('Are you sure you want to sign out of all sessions? This will log you out everywhere, including this device.')) {
412
- throw new Error('Sign out cancelled');
415
+ return signoutAllForm.setFormState('ready');
413
416
  }
414
417
 
415
418
  // Sign out of all sessions
@@ -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
  }