ultimate-jekyll-manager 0.0.119 → 0.0.121

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 (28) hide show
  1. package/CLAUDE.md +102 -2
  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/libs/auth/pages.js +64 -136
  6. package/dist/assets/js/libs/form-manager.js +643 -775
  7. package/dist/assets/js/pages/account/sections/api-keys.js +37 -52
  8. package/dist/assets/js/pages/account/sections/connections.js +37 -46
  9. package/dist/assets/js/pages/account/sections/delete.js +46 -66
  10. package/dist/assets/js/pages/account/sections/profile.js +37 -56
  11. package/dist/assets/js/pages/account/sections/security.js +100 -126
  12. package/dist/assets/js/pages/admin/notifications/new/index.js +72 -157
  13. package/dist/assets/js/pages/blog/index.js +29 -51
  14. package/dist/assets/js/pages/contact/index.js +110 -144
  15. package/dist/assets/js/pages/download/index.js +38 -86
  16. package/dist/assets/js/pages/oauth2/index.js +17 -17
  17. package/dist/assets/js/pages/payment/checkout/index.js +23 -36
  18. package/dist/assets/js/pages/test/libraries/form-manager/index.js +194 -0
  19. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -2
  20. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +2 -2
  21. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +10 -37
  22. package/dist/defaults/dist/pages/test/libraries/form-manager.html +181 -0
  23. package/dist/gulp/tasks/serve.js +18 -0
  24. package/dist/lib/logger.js +1 -1
  25. package/firebase-debug.log +420 -0
  26. package/package.json +11 -7
  27. package/.playwright-mcp/page-2025-10-22T19-11-27-666Z.png +0 -0
  28. package/.playwright-mcp/page-2025-10-22T19-11-57-357Z.png +0 -0
@@ -1,7 +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';
4
8
  import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
9
+
5
10
  let webManager = null;
6
11
 
7
12
  // Module
@@ -28,7 +33,7 @@ export default (Manager) => {
28
33
  let formManager = null;
29
34
  let stats = {
30
35
  totalUsers: 0,
31
- filteredUsers: 0
36
+ filteredUsers: 0,
32
37
  };
33
38
  let autoSubmitTimer = null;
34
39
  let isInitialized = false;
@@ -36,7 +41,9 @@ let isInitialized = false;
36
41
  // Main initialization
37
42
  async function initializeNotificationCreator() {
38
43
  // Prevent re-initialization
39
- if (isInitialized) return;
44
+ if (isInitialized) {
45
+ return;
46
+ }
40
47
  isInitialized = true;
41
48
 
42
49
  // Initialize FormManager
@@ -66,15 +73,39 @@ async function initializeNotificationCreator() {
66
73
  // Initialize FormManager
67
74
  function initializeFormManager() {
68
75
  formManager = new FormManager('#notification-form', {
69
- autoDisable: true,
70
- showSpinner: true,
71
- validateOnSubmit: true,
72
- allowMultipleSubmissions: false,
76
+ allowResubmit: false,
73
77
  });
74
78
 
75
- // Event listeners
76
- formManager.addEventListener('change', handleFormChange);
77
- 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
+ });
78
109
  }
79
110
 
80
111
  // Initialize UI elements
@@ -139,13 +170,6 @@ function initializeUI() {
139
170
  });
140
171
  }
141
172
 
142
- // Channel toggles - commented out since channels aren't currently supported
143
- // document.querySelectorAll('input[name^="channels."]').forEach(checkbox => {
144
- // checkbox.addEventListener('change', (e) => {
145
- // toggleChannelSettings(e.target);
146
- // });
147
- // });
148
-
149
173
  // Notification preview click handler
150
174
  const $notificationPreview = document.querySelector('#notification-preview-clickable');
151
175
  if ($notificationPreview) {
@@ -164,57 +188,14 @@ function initializeUI() {
164
188
  // Trigger initial form change to update character counts and preview with form data
165
189
  if (formManager) {
166
190
  setTimeout(() => {
167
- handleFormChange();
191
+ const data = formManager.getData();
192
+ updatePreview(data);
193
+ updateCharacterCounts(data);
194
+ checkAutoSubmit(data);
168
195
  }, 100);
169
196
  }
170
197
  }
171
198
 
172
- // Handle form changes
173
- function handleFormChange(event) {
174
- const formData = formManager.getData();
175
-
176
- // Update preview in real-time
177
- updatePreview(formData);
178
-
179
- // Update character counts
180
- updateCharacterCounts(formData);
181
-
182
- // Check auto-submit status
183
- checkAutoSubmit(formData);
184
- }
185
-
186
- // Handle form submission
187
- async function handleSubmit(event) {
188
- // Get data from event detail if available, otherwise from formManager
189
- const formData = event.detail?.data || formManager.getData();
190
-
191
- try {
192
- // Transform data for API
193
- const payload = transformDataForAPI(formData);
194
-
195
- // Add user stats
196
- payload.reach = {
197
- available: { total: stats.totalUsers },
198
- filtered: { total: stats.filteredUsers }
199
- };
200
-
201
-
202
- // Call API
203
- const response = await sendNotification(payload);
204
-
205
- // Track success
206
- trackNotificationSent(payload);
207
-
208
- // Success
209
- formManager.showSuccess(`Notification sent successfully to ${stats.filteredUsers.toLocaleString()} users!`);
210
-
211
- } catch (error) {
212
- console.error('Notification send error:', error);
213
- webManager.sentry().captureException(new Error('Failed to send notification', { cause: error }));
214
- formManager.showError(error.message || 'Failed to send notification');
215
- }
216
- }
217
-
218
199
  // Transform data for API
219
200
  function transformDataForAPI(formData) {
220
201
  console.log('[Debug] transformDataForAPI called');
@@ -248,12 +229,12 @@ function transformDataForAPI(formData) {
248
229
  icon: notification.icon || '',
249
230
  title: notification.title || '',
250
231
  body: notification.body || '',
251
- clickAction: redirectUrl.toString()
232
+ clickAction: redirectUrl.toString(),
252
233
  },
253
234
  created: now.toISOString(),
254
235
  channels: formData.channels || {},
255
236
  audience: formData.audience || {},
256
- schedule: formData.schedule || {}
237
+ schedule: formData.schedule || {},
257
238
  };
258
239
  }
259
240
 
@@ -269,8 +250,8 @@ async function sendNotification(payload) {
269
250
  log: true,
270
251
  body: {
271
252
  command: 'admin:send-notification',
272
- payload: payload
273
- }
253
+ payload: payload,
254
+ },
274
255
  });
275
256
  }
276
257
 
@@ -286,16 +267,15 @@ async function fetchUserStats() {
286
267
  body: {
287
268
  command: 'admin:firestore-read',
288
269
  payload: {
289
- path: 'meta/stats'
290
- }
291
- }
270
+ path: 'meta/stats',
271
+ },
272
+ },
292
273
  });
293
274
 
294
275
  // Extract user count from response
295
276
  const total = response?.notifications?.total || 0;
296
277
  stats.totalUsers = total;
297
278
  stats.filteredUsers = total; // Initially all users
298
-
299
279
  } catch (error) {
300
280
  console.error('Failed to fetch user stats:', error);
301
281
  webManager.sentry().captureException(new Error('Failed to fetch user stats', { cause: error }));
@@ -356,9 +336,6 @@ function updatePreview(formData = null) {
356
336
  if ($previewTime) {
357
337
  $previewTime.textContent = 'Now';
358
338
  }
359
-
360
- // Update channel badges - commented out since channels aren't currently supported
361
- // updateChannelBadges(formData);
362
339
  }
363
340
 
364
341
  // Update icon preview
@@ -397,64 +374,6 @@ function updateCharacterCounts(formData) {
397
374
  }
398
375
  }
399
376
 
400
- // Toggle channel-specific settings
401
- function toggleChannelSettings(checkbox) {
402
- const channelName = checkbox.name.replace('channels.', '').replace('.enabled', '');
403
- const $settingsEl = document.querySelector(`#${channelName}-channel-settings`);
404
-
405
- if ($settingsEl) {
406
- if (checkbox.checked) {
407
- $settingsEl.classList.remove('d-none');
408
- $settingsEl.classList.add('animate__animated', 'animate__fadeIn');
409
- } else {
410
- $settingsEl.classList.add('d-none');
411
- }
412
- }
413
- }
414
-
415
- // Update channel badges in preview
416
- function updateChannelBadges(formData) {
417
- const channels = formData.channels || {};
418
- const $badgesContainer = document.querySelector('.card .d-flex.gap-2.flex-wrap');
419
-
420
- if (!$badgesContainer) {
421
- return;
422
- }
423
-
424
- // Clear existing badges
425
- $badgesContainer.innerHTML = '';
426
-
427
- // Add badges for enabled channels
428
- const channelConfigs = {
429
- push: { icon: 'mobile', color: 'primary' },
430
- email: { icon: 'envelope', color: 'info' },
431
- sms: { icon: 'comment-sms', color: 'success' },
432
- inapp: { icon: 'bell', color: 'warning' }
433
- };
434
-
435
- Object.keys(channelConfigs).forEach(channel => {
436
- if (!channels[channel]?.enabled) {
437
- return;
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);
446
- });
447
-
448
- // Default to push if no channels selected
449
- if ($badgesContainer.children.length === 0) {
450
- const iconHTML = getPrerenderedIcon('mobile');
451
- const $badge = document.createElement('span');
452
- $badge.className = 'badge bg-primary';
453
- $badge.innerHTML = `${iconHTML}Push`;
454
- $badgesContainer.appendChild($badge);
455
- }
456
- }
457
-
458
377
  // Set auto-submit time
459
378
  function setAutoSubmitTime() {
460
379
  // Set to tomorrow at 10 AM
@@ -509,7 +428,9 @@ function startAutoSubmitCountdown(targetDate) {
509
428
  clearAutoSubmitCountdown();
510
429
 
511
430
  const $countdownEl = document.querySelector('#auto-submit-countdown');
512
- if (!$countdownEl) return;
431
+ if (!$countdownEl) {
432
+ return;
433
+ }
513
434
 
514
435
  $countdownEl.classList.remove('d-none');
515
436
 
@@ -524,7 +445,10 @@ function startAutoSubmitCountdown(targetDate) {
524
445
  // Fetch updated stats before submitting
525
446
  fetchUserStats()
526
447
  .then(() => updateUserCount())
527
- .finally(() => formManager.submit());
448
+ .finally(() => {
449
+ // Programmatically submit the form
450
+ formManager.$form.requestSubmit();
451
+ });
528
452
 
529
453
  return;
530
454
  }
@@ -560,29 +484,20 @@ function getAPIFunctionsUrl() {
560
484
 
561
485
  // Tracking functions
562
486
  function trackNotificationSent(payload) {
563
- // Google Analytics
564
- if (typeof gtag !== 'undefined') {
565
- gtag('event', 'notification_sent', {
566
- notification_type: 'admin',
567
- user_count: stats.filteredUsers,
568
- channels: Object.keys(payload.channels || {}).filter(c => payload.channels[c]?.enabled).join(',')
569
- });
570
- }
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
+ });
571
492
 
572
- // Facebook Pixel
573
- if (typeof fbq !== 'undefined') {
574
- fbq('trackCustom', 'AdminNotificationSent', {
575
- users: stats.filteredUsers,
576
- channels: Object.keys(payload.channels || {}).filter(c => payload.channels[c]?.enabled)
577
- });
578
- }
493
+ fbq('trackCustom', 'AdminNotificationSent', {
494
+ users: stats.filteredUsers,
495
+ channels: Object.keys(payload.channels || {}).filter(c => payload.channels[c]?.enabled),
496
+ });
579
497
 
580
- // TikTok Pixel
581
- if (typeof ttq !== 'undefined') {
582
- ttq.track('SubmitForm', {
583
- content_id: 'admin-notification',
584
- content_type: 'product',
585
- content_name: 'Admin Notification',
586
- });
587
- }
498
+ ttq.track('SubmitForm', {
499
+ content_id: 'admin-notification',
500
+ content_type: 'product',
501
+ content_name: 'Admin Notification',
502
+ });
588
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,48 +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
137
  fbq('track', 'Lead', {
160
138
  content_name: 'Newsletter',
161
- status: 'success'
139
+ status: 'success',
162
140
  });
163
141
  ttq.track('Subscribe', {
164
142
  content_id: 'newsletter-blog',
165
143
  content_type: 'product',
166
- content_name: 'Newsletter'
144
+ content_name: 'Newsletter',
167
145
  });
168
146
  }
169
147
 
@@ -171,15 +149,15 @@ function trackBlogSearch(query) {
171
149
  gtag('event', 'search', {
172
150
  search_term: query,
173
151
  event_category: 'engagement',
174
- event_label: 'blog_page'
152
+ event_label: 'blog_page',
175
153
  });
176
154
  fbq('track', 'Search', {
177
155
  search_string: query,
178
- content_category: 'blog'
156
+ content_category: 'blog',
179
157
  });
180
158
  ttq.track('Search', {
181
159
  content_id: 'blog-search',
182
160
  content_type: 'product',
183
- search_string: query
161
+ search_string: query,
184
162
  });
185
163
  }