ultimate-jekyll-manager 0.0.118 → 0.0.120

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 (51) hide show
  1. package/CLAUDE.md +409 -23
  2. package/README.md +171 -2
  3. package/TODO.md +10 -2
  4. package/_backup/form-manager.backup.js +1020 -0
  5. package/dist/assets/js/core/auth.js +5 -4
  6. package/dist/assets/js/core/cookieconsent.js +24 -17
  7. package/dist/assets/js/core/exit-popup.js +15 -12
  8. package/dist/assets/js/core/social-sharing.js +8 -4
  9. package/dist/assets/js/libs/auth/pages.js +78 -149
  10. package/dist/assets/js/libs/dev.js +192 -129
  11. package/dist/assets/js/libs/form-manager.js +643 -775
  12. package/dist/assets/js/pages/account/index.js +3 -2
  13. package/dist/assets/js/pages/account/sections/api-keys.js +37 -52
  14. package/dist/assets/js/pages/account/sections/connections.js +37 -46
  15. package/dist/assets/js/pages/account/sections/delete.js +57 -78
  16. package/dist/assets/js/pages/account/sections/profile.js +37 -56
  17. package/dist/assets/js/pages/account/sections/security.js +102 -125
  18. package/dist/assets/js/pages/admin/notifications/new/index.js +73 -151
  19. package/dist/assets/js/pages/blog/index.js +33 -53
  20. package/dist/assets/js/pages/contact/index.js +112 -173
  21. package/dist/assets/js/pages/download/index.js +39 -86
  22. package/dist/assets/js/pages/oauth2/index.js +17 -17
  23. package/dist/assets/js/pages/payment/checkout/index.js +23 -36
  24. package/dist/assets/js/pages/pricing/index.js +5 -2
  25. package/dist/assets/js/pages/test/libraries/form-manager/index.js +194 -0
  26. package/dist/assets/themes/classy/css/components/_cards.scss +2 -2
  27. package/dist/defaults/_.env +6 -0
  28. package/dist/defaults/_.gitignore +7 -1
  29. package/dist/defaults/dist/_includes/core/body.html +5 -13
  30. package/dist/defaults/dist/_includes/core/foot.html +1 -0
  31. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +51 -36
  32. package/dist/defaults/dist/_layouts/blueprint/admin/notifications/new.html +13 -2
  33. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +84 -42
  34. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +26 -21
  35. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -2
  36. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +2 -2
  37. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +72 -58
  38. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +46 -29
  39. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +46 -53
  40. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +111 -73
  41. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +111 -56
  42. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +127 -81
  43. package/dist/defaults/dist/pages/test/libraries/form-manager.html +181 -0
  44. package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +1 -1
  45. package/dist/gulp/tasks/defaults.js +210 -1
  46. package/dist/gulp/tasks/serve.js +18 -0
  47. package/dist/lib/logger.js +1 -1
  48. package/firebase-debug.log +770 -0
  49. package/package.json +6 -6
  50. package/.playwright-mcp/page-2025-10-22T19-11-27-666Z.png +0 -0
  51. package/.playwright-mcp/page-2025-10-22T19-11-57-357Z.png +0 -0
@@ -1,6 +1,12 @@
1
+ /**
2
+ * Admin Notifications Page JavaScript
3
+ */
4
+
1
5
  // Libraries
2
6
  import { FormManager } from '__main_assets__/js/libs/form-manager.js';
3
7
  import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
8
+ import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
9
+
4
10
  let webManager = null;
5
11
 
6
12
  // Module
@@ -27,7 +33,7 @@ export default (Manager) => {
27
33
  let formManager = null;
28
34
  let stats = {
29
35
  totalUsers: 0,
30
- filteredUsers: 0
36
+ filteredUsers: 0,
31
37
  };
32
38
  let autoSubmitTimer = null;
33
39
  let isInitialized = false;
@@ -35,7 +41,9 @@ let isInitialized = false;
35
41
  // Main initialization
36
42
  async function initializeNotificationCreator() {
37
43
  // Prevent re-initialization
38
- if (isInitialized) return;
44
+ if (isInitialized) {
45
+ return;
46
+ }
39
47
  isInitialized = true;
40
48
 
41
49
  // Initialize FormManager
@@ -65,15 +73,39 @@ async function initializeNotificationCreator() {
65
73
  // Initialize FormManager
66
74
  function initializeFormManager() {
67
75
  formManager = new FormManager('#notification-form', {
68
- autoDisable: true,
69
- showSpinner: true,
70
- validateOnSubmit: true,
71
- allowMultipleSubmissions: false,
76
+ allowResubmit: false,
72
77
  });
73
78
 
74
- // Event listeners
75
- formManager.addEventListener('change', handleFormChange);
76
- formManager.addEventListener('submit', handleSubmit);
79
+ formManager.on('change', ({ data }) => {
80
+ // Update preview in real-time
81
+ updatePreview(data);
82
+
83
+ // Update character counts
84
+ updateCharacterCounts(data);
85
+
86
+ // Check auto-submit status
87
+ checkAutoSubmit(data);
88
+ });
89
+
90
+ formManager.on('submit', async ({ data }) => {
91
+ // Transform data for API
92
+ const payload = transformDataForAPI(data);
93
+
94
+ // Add user stats
95
+ payload.reach = {
96
+ available: { total: stats.totalUsers },
97
+ filtered: { total: stats.filteredUsers },
98
+ };
99
+
100
+ // Call API
101
+ await sendNotification(payload);
102
+
103
+ // Track success
104
+ trackNotificationSent(payload);
105
+
106
+ // Success
107
+ formManager.showSuccess(`Notification sent successfully to ${stats.filteredUsers.toLocaleString()} users!`);
108
+ });
77
109
  }
78
110
 
79
111
  // Initialize UI elements
@@ -138,13 +170,6 @@ function initializeUI() {
138
170
  });
139
171
  }
140
172
 
141
- // Channel toggles - commented out since channels aren't currently supported
142
- // document.querySelectorAll('input[name^="channels."]').forEach(checkbox => {
143
- // checkbox.addEventListener('change', (e) => {
144
- // toggleChannelSettings(e.target);
145
- // });
146
- // });
147
-
148
173
  // Notification preview click handler
149
174
  const $notificationPreview = document.querySelector('#notification-preview-clickable');
150
175
  if ($notificationPreview) {
@@ -163,57 +188,14 @@ function initializeUI() {
163
188
  // Trigger initial form change to update character counts and preview with form data
164
189
  if (formManager) {
165
190
  setTimeout(() => {
166
- handleFormChange();
191
+ const data = formManager.getData();
192
+ updatePreview(data);
193
+ updateCharacterCounts(data);
194
+ checkAutoSubmit(data);
167
195
  }, 100);
168
196
  }
169
197
  }
170
198
 
171
- // Handle form changes
172
- function handleFormChange(event) {
173
- const formData = formManager.getData();
174
-
175
- // Update preview in real-time
176
- updatePreview(formData);
177
-
178
- // Update character counts
179
- updateCharacterCounts(formData);
180
-
181
- // Check auto-submit status
182
- checkAutoSubmit(formData);
183
- }
184
-
185
- // Handle form submission
186
- async function handleSubmit(event) {
187
- // Get data from event detail if available, otherwise from formManager
188
- const formData = event.detail?.data || formManager.getData();
189
-
190
- try {
191
- // Transform data for API
192
- const payload = transformDataForAPI(formData);
193
-
194
- // Add user stats
195
- payload.reach = {
196
- available: { total: stats.totalUsers },
197
- filtered: { total: stats.filteredUsers }
198
- };
199
-
200
-
201
- // Call API
202
- const response = await sendNotification(payload);
203
-
204
- // Track success
205
- trackNotificationSent(payload);
206
-
207
- // Success
208
- formManager.showSuccess(`Notification sent successfully to ${stats.filteredUsers.toLocaleString()} users!`);
209
-
210
- } catch (error) {
211
- console.error('Notification send error:', error);
212
- webManager.sentry().captureException(new Error('Failed to send notification', { cause: error }));
213
- formManager.showError(error.message || 'Failed to send notification');
214
- }
215
- }
216
-
217
199
  // Transform data for API
218
200
  function transformDataForAPI(formData) {
219
201
  console.log('[Debug] transformDataForAPI called');
@@ -247,12 +229,12 @@ function transformDataForAPI(formData) {
247
229
  icon: notification.icon || '',
248
230
  title: notification.title || '',
249
231
  body: notification.body || '',
250
- clickAction: redirectUrl.toString()
232
+ clickAction: redirectUrl.toString(),
251
233
  },
252
234
  created: now.toISOString(),
253
235
  channels: formData.channels || {},
254
236
  audience: formData.audience || {},
255
- schedule: formData.schedule || {}
237
+ schedule: formData.schedule || {},
256
238
  };
257
239
  }
258
240
 
@@ -268,8 +250,8 @@ async function sendNotification(payload) {
268
250
  log: true,
269
251
  body: {
270
252
  command: 'admin:send-notification',
271
- payload: payload
272
- }
253
+ payload: payload,
254
+ },
273
255
  });
274
256
  }
275
257
 
@@ -285,16 +267,15 @@ async function fetchUserStats() {
285
267
  body: {
286
268
  command: 'admin:firestore-read',
287
269
  payload: {
288
- path: 'meta/stats'
289
- }
290
- }
270
+ path: 'meta/stats',
271
+ },
272
+ },
291
273
  });
292
274
 
293
275
  // Extract user count from response
294
276
  const total = response?.notifications?.total || 0;
295
277
  stats.totalUsers = total;
296
278
  stats.filteredUsers = total; // Initially all users
297
-
298
279
  } catch (error) {
299
280
  console.error('Failed to fetch user stats:', error);
300
281
  webManager.sentry().captureException(new Error('Failed to fetch user stats', { cause: error }));
@@ -355,9 +336,6 @@ function updatePreview(formData = null) {
355
336
  if ($previewTime) {
356
337
  $previewTime.textContent = 'Now';
357
338
  }
358
-
359
- // Update channel badges - commented out since channels aren't currently supported
360
- // updateChannelBadges(formData);
361
339
  }
362
340
 
363
341
  // Update icon preview
@@ -396,58 +374,6 @@ function updateCharacterCounts(formData) {
396
374
  }
397
375
  }
398
376
 
399
- // Toggle channel-specific settings
400
- function toggleChannelSettings(checkbox) {
401
- const channelName = checkbox.name.replace('channels.', '').replace('.enabled', '');
402
- const $settingsEl = document.querySelector(`#${channelName}-channel-settings`);
403
-
404
- if ($settingsEl) {
405
- if (checkbox.checked) {
406
- $settingsEl.classList.remove('d-none');
407
- $settingsEl.classList.add('animate__animated', 'animate__fadeIn');
408
- } else {
409
- $settingsEl.classList.add('d-none');
410
- }
411
- }
412
- }
413
-
414
- // Update channel badges in preview
415
- function updateChannelBadges(formData) {
416
- const channels = formData.channels || {};
417
- const $badgesContainer = document.querySelector('.card .d-flex.gap-2.flex-wrap');
418
-
419
- if (!$badgesContainer) return;
420
-
421
- // Clear existing badges
422
- $badgesContainer.innerHTML = '';
423
-
424
- // Add badges for enabled channels
425
- const channelConfigs = {
426
- push: { icon: 'mobile', color: 'primary' },
427
- email: { icon: 'envelope', color: 'info' },
428
- sms: { icon: 'comment-sms', color: 'success' },
429
- inapp: { icon: 'bell', color: 'warning' }
430
- };
431
-
432
- 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);
439
- }
440
- });
441
-
442
- // Default to push if no channels selected
443
- if ($badgesContainer.children.length === 0) {
444
- const $badge = document.createElement('span');
445
- $badge.className = 'badge bg-primary';
446
- $badge.innerHTML = '<i class="bi bi-mobile me-1"></i>Push';
447
- $badgesContainer.appendChild($badge);
448
- }
449
- }
450
-
451
377
  // Set auto-submit time
452
378
  function setAutoSubmitTime() {
453
379
  // Set to tomorrow at 10 AM
@@ -502,7 +428,9 @@ function startAutoSubmitCountdown(targetDate) {
502
428
  clearAutoSubmitCountdown();
503
429
 
504
430
  const $countdownEl = document.querySelector('#auto-submit-countdown');
505
- if (!$countdownEl) return;
431
+ if (!$countdownEl) {
432
+ return;
433
+ }
506
434
 
507
435
  $countdownEl.classList.remove('d-none');
508
436
 
@@ -517,7 +445,10 @@ function startAutoSubmitCountdown(targetDate) {
517
445
  // Fetch updated stats before submitting
518
446
  fetchUserStats()
519
447
  .then(() => updateUserCount())
520
- .finally(() => formManager.submit());
448
+ .finally(() => {
449
+ // Programmatically submit the form
450
+ formManager.$form.requestSubmit();
451
+ });
521
452
 
522
453
  return;
523
454
  }
@@ -553,29 +484,20 @@ function getAPIFunctionsUrl() {
553
484
 
554
485
  // Tracking functions
555
486
  function trackNotificationSent(payload) {
556
- // Google Analytics
557
- if (typeof gtag !== 'undefined') {
558
- gtag('event', 'notification_sent', {
559
- notification_type: 'admin',
560
- user_count: stats.filteredUsers,
561
- channels: Object.keys(payload.channels || {}).filter(c => payload.channels[c]?.enabled).join(',')
562
- });
563
- }
487
+ gtag('event', 'notification_sent', {
488
+ notification_type: 'admin',
489
+ user_count: stats.filteredUsers,
490
+ channels: Object.keys(payload.channels || {}).filter(c => payload.channels[c]?.enabled).join(','),
491
+ });
564
492
 
565
- // Facebook Pixel
566
- if (typeof fbq !== 'undefined') {
567
- fbq('trackCustom', 'AdminNotificationSent', {
568
- users: stats.filteredUsers,
569
- channels: Object.keys(payload.channels || {}).filter(c => payload.channels[c]?.enabled)
570
- });
571
- }
493
+ fbq('trackCustom', 'AdminNotificationSent', {
494
+ users: stats.filteredUsers,
495
+ channels: Object.keys(payload.channels || {}).filter(c => payload.channels[c]?.enabled),
496
+ });
572
497
 
573
- // TikTok Pixel
574
- if (typeof ttq !== 'undefined') {
575
- ttq.track('SubmitForm', {
576
- content_name: 'Admin Notification',
577
- content_type: 'notification',
578
- value: stats.filteredUsers
579
- });
580
- }
498
+ ttq.track('SubmitForm', {
499
+ content_id: 'admin-notification',
500
+ content_type: 'product',
501
+ content_name: 'Admin Notification',
502
+ });
581
503
  }
@@ -1,5 +1,10 @@
1
+ /**
2
+ * Blog Page JavaScript
3
+ */
4
+
1
5
  // Libraries
2
6
  import { FormManager } from '__main_assets__/js/libs/form-manager.js';
7
+
3
8
  let webManager = null;
4
9
 
5
10
  // Module
@@ -19,9 +24,6 @@ export default (Manager) => {
19
24
  });
20
25
  };
21
26
 
22
- // Global variables
23
- let newsletterForm = null;
24
-
25
27
  // Setup newsletter form
26
28
  function setupNewsletterForm() {
27
29
  const $form = document.getElementById('newsletter-form');
@@ -30,19 +32,27 @@ function setupNewsletterForm() {
30
32
  return;
31
33
  }
32
34
 
33
- // Initialize FormManager
34
- newsletterForm = new FormManager('#newsletter-form', {
35
- autoDisable: true,
36
- showSpinner: true,
37
- validateOnSubmit: true,
38
- allowMultipleSubmissions: false,
35
+ const formManager = new FormManager('#newsletter-form', {
36
+ allowResubmit: false,
39
37
  resetOnSuccess: true,
40
- submitButtonLoadingText: 'Subscribing...',
41
- submitButtonSuccessText: 'Subscribed!',
38
+ submittingText: 'Subscribing...',
39
+ submittedText: 'Subscribed!',
42
40
  });
43
41
 
44
- // Listen to FormManager events
45
- newsletterForm.addEventListener('submit', handleNewsletterSubmit);
42
+ formManager.on('submit', async ({ data }) => {
43
+ console.log('Newsletter subscription:', data.email);
44
+
45
+ // Here you would integrate with your newsletter service
46
+ // For example: Mailchimp, SendGrid, ConvertKit, etc.
47
+
48
+ // Simulate API call
49
+ await new Promise(resolve => setTimeout(resolve, 1000));
50
+
51
+ // Track signup
52
+ trackNewsletterSignup();
53
+
54
+ formManager.showSuccess('Thank you for subscribing! Check your email to confirm.');
55
+ });
46
56
  }
47
57
 
48
58
  // Setup blog search functionality
@@ -90,7 +100,6 @@ function setupSearch() {
90
100
  // Perform search on blog posts
91
101
  function performSearch(query, $blogPosts, $searchResults) {
92
102
  let matchCount = 0;
93
- const results = [];
94
103
 
95
104
  $blogPosts.forEach(post => {
96
105
  const title = post.dataset.title?.toLowerCase() || '';
@@ -100,10 +109,6 @@ function performSearch(query, $blogPosts, $searchResults) {
100
109
  if (title.includes(query) || excerpt.includes(query) || tags.includes(query)) {
101
110
  post.classList.remove('d-none');
102
111
  matchCount++;
103
- results.push({
104
- title: post.dataset.title,
105
- url: post.querySelector('a')?.href
106
- });
107
112
  } else {
108
113
  post.classList.add('d-none');
109
114
  }
@@ -122,47 +127,21 @@ function performSearch(query, $blogPosts, $searchResults) {
122
127
  trackBlogSearch(query);
123
128
  }
124
129
 
125
- // Handle newsletter form submission
126
- async function handleNewsletterSubmit(event) {
127
- // Prevent default FormManager submission
128
- event.preventDefault();
129
-
130
- const formData = event.detail.data;
131
-
132
- console.log('Newsletter subscription:', formData.email);
133
-
134
- try {
135
- // Here you would integrate with your newsletter service
136
- // For example: Mailchimp, SendGrid, ConvertKit, etc.
137
-
138
- // Simulate API call
139
- await new Promise(resolve => setTimeout(resolve, 1000));
140
-
141
- // For demo purposes, just show success
142
- trackNewsletterSignup();
143
- newsletterForm.showSuccess('Thank you for subscribing! Check your email to confirm.');
144
- newsletterForm.setFormState('submitted');
145
- } catch (error) {
146
- webManager.sentry().captureException(new Error('Newsletter subscription failed', { cause: error }));
147
- newsletterForm.showError('An error occurred. Please try again.');
148
- newsletterForm.setFormState('ready');
149
- }
150
- }
151
-
152
130
  // Tracking functions
153
131
  function trackNewsletterSignup() {
154
132
  gtag('event', 'newsletter_signup', {
155
133
  event_category: 'engagement',
156
134
  event_label: 'blog_page',
157
- value: 1
135
+ value: 1,
158
136
  });
159
- fbq('track', 'CompleteRegistration', {
137
+ fbq('track', 'Lead', {
160
138
  content_name: 'Newsletter',
161
- status: 'success'
139
+ status: 'success',
162
140
  });
163
141
  ttq.track('Subscribe', {
142
+ content_id: 'newsletter-blog',
143
+ content_type: 'product',
164
144
  content_name: 'Newsletter',
165
- status: 'success'
166
145
  });
167
146
  }
168
147
 
@@ -170,14 +149,15 @@ function trackBlogSearch(query) {
170
149
  gtag('event', 'search', {
171
150
  search_term: query,
172
151
  event_category: 'engagement',
173
- event_label: 'blog_page'
152
+ event_label: 'blog_page',
174
153
  });
175
154
  fbq('track', 'Search', {
176
155
  search_string: query,
177
- content_category: 'blog'
156
+ content_category: 'blog',
178
157
  });
179
158
  ttq.track('Search', {
180
- query: query,
181
- content_type: 'blog'
159
+ content_id: 'blog-search',
160
+ content_type: 'product',
161
+ search_string: query,
182
162
  });
183
163
  }