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,11 @@
1
+ /**
2
+ * Contact Page JavaScript
3
+ */
4
+
1
5
  // Libraries
2
6
  import { FormManager } from '__main_assets__/js/libs/form-manager.js';
3
7
  import fetch from 'wonderful-fetch';
8
+
4
9
  let webManager = null;
5
10
 
6
11
  // Module
@@ -13,50 +18,98 @@ export default (Manager) => {
13
18
  await webManager.dom().ready();
14
19
 
15
20
  setupForm();
21
+ setupFormScrolling();
16
22
 
17
23
  // Resolve after initialization
18
24
  return resolve();
19
25
  });
20
26
  };
21
27
 
22
- // Global variables
23
- let formManager = null;
24
-
25
28
  // Setup form handling
26
29
  function setupForm() {
27
- // Initialize FormManager with proper configuration
28
- formManager = new FormManager('#contact-form', {
29
- autoDisable: true,
30
- showSpinner: true,
31
- validateOnSubmit: true,
32
- allowMultipleSubmissions: false,
30
+ const formManager = new FormManager('#contact-form', {
31
+ allowResubmit: false,
33
32
  resetOnSuccess: true,
34
- submitButtonLoadingText: 'Sending...',
35
- submitButtonSuccessText: 'Message Sent!',
36
33
  });
37
34
 
38
- // Listen to FormManager events
39
- formManager.addEventListener('submit', handleFormSubmit);
40
- formManager.addEventListener('change', handleFieldChange);
35
+ formManager.on('submit', async ({ data }) => {
36
+ const slapformId = webManager.config.brand.contact['slapform-form-id'];
37
+
38
+ console.log('Contact form submission:', data);
39
+
40
+ // Check honeypot fields (anti-spam)
41
+ if (data.url_check || data.slap_honey) {
42
+ console.warn('Honeypot field filled - potential spam');
43
+ trackContactSpam();
44
+ return;
45
+ }
46
+
47
+ // Check if slapformId is missing
48
+ if (!slapformId) {
49
+ webManager.sentry().captureException(new Error('Contact form is not configured - missing slapform ID'));
50
+ throw new Error('Contact form is not configured properly. Please try again later.');
51
+ }
52
+
53
+ trackContactFormSubmit(data.subject || 'general');
54
+
55
+ // Prepare data for API
56
+ const requestData = {
57
+ first_name: data.first_name,
58
+ last_name: data.last_name,
59
+ email: data.email,
60
+ company: data.company || '',
61
+ subject: data.subject,
62
+ message: data.message,
63
+ };
64
+
65
+ // Get API endpoint from site config or use default
66
+ const apiEndpoint = `https://api.slapform.com/${slapformId}`;
67
+
68
+ try {
69
+ // Send request using wonderful-fetch
70
+ await fetch(apiEndpoint, {
71
+ method: 'POST',
72
+ body: requestData,
73
+ response: 'json',
74
+ timeout: 30000,
75
+ });
76
+
77
+ formManager.showSuccess('Thank you for your message! We\'ll get back to you within 24 hours.');
78
+ } catch (error) {
79
+ // Only capture technical errors to Sentry (network, timeout, API errors)
80
+ if (error.message?.includes('network') || error.message?.includes('timeout') || !error.message?.includes('Failed')) {
81
+ webManager.sentry().captureException(new Error('Contact form submission error', { cause: error }));
82
+ }
41
83
 
42
- // Setup smooth scroll to form
43
- setupFormScrolling();
84
+ // Show user-friendly error message
85
+ let errorMessage = 'An error occurred while sending your message. ';
86
+
87
+ if (error.message?.includes('network')) {
88
+ errorMessage += 'Please check your internet connection and try again.';
89
+ } else if (error.message?.includes('timeout')) {
90
+ errorMessage += 'The request timed out. Please try again.';
91
+ } else if (error.message?.includes('Failed')) {
92
+ errorMessage = error.message;
93
+ } else {
94
+ errorMessage += 'Please try again or contact us directly.';
95
+ }
96
+
97
+ throw new Error(errorMessage);
98
+ }
99
+ });
44
100
  }
45
101
 
46
102
  // Setup smooth scrolling to form and chat handler
47
103
  function setupFormScrolling() {
48
- // Find all contact method links
49
104
  const $contactLinks = document.querySelectorAll('a[href="#form"], a[href="#chat"]');
50
105
 
51
- $contactLinks.forEach(link => {
52
- link.addEventListener('click', (e) => {
106
+ $contactLinks.forEach($link => {
107
+ $link.addEventListener('click', (e) => {
53
108
  e.preventDefault();
54
109
 
55
- const href = link.getAttribute('href');
110
+ const href = $link.getAttribute('href');
56
111
 
57
112
  if (href === '#chat') {
58
- trackChatClick();
59
-
60
113
  // Open chat window
61
114
  try {
62
115
  chatsy.open();
@@ -64,176 +117,62 @@ function setupFormScrolling() {
64
117
  webManager.sentry().captureException(new Error('Error opening chat', { cause: error }));
65
118
  webManager.utilities().showNotification('Chat is currently unavailable. Please try again later.', 'danger');
66
119
  }
67
- } else if (href === '#form') {
68
- trackFormClick();
120
+ return;
121
+ }
69
122
 
70
- // Find the form section by ID
123
+ if (href === '#form') {
71
124
  const $formSection = document.getElementById('form');
72
-
73
- if ($formSection) {
74
- // Smooth scroll to the form section
75
- $formSection.scrollIntoView({
76
- behavior: 'smooth',
77
- block: 'start'
78
- });
79
-
80
- // Focus the first input immediately and after scroll completes
81
- const focusFirstInput = () => {
82
- // Find the first input field in the form
83
- const $firstInput = document.querySelector('#contact-form input');
84
- if (!$firstInput) {
85
- return;
86
- }
87
-
88
- $firstInput.focus();
89
- // Don't select text on mobile devices
90
- if (!('ontouchstart' in window) && $firstInput.select) {
91
- $firstInput.select();
92
- }
93
- };
94
-
95
- // Try focusing immediately
96
- focusFirstInput();
97
-
98
- // Also try after scroll animation completes
99
- setTimeout(focusFirstInput, 800);
125
+ if (!$formSection) {
126
+ return;
100
127
  }
128
+
129
+ // Smooth scroll to the form section
130
+ $formSection.scrollIntoView({
131
+ behavior: 'smooth',
132
+ block: 'start',
133
+ });
134
+
135
+ // Focus the first input after scroll completes
136
+ const focusFirstInput = () => {
137
+ const $firstInput = document.querySelector('#contact-form input');
138
+ if (!$firstInput) {
139
+ return;
140
+ }
141
+
142
+ $firstInput.focus();
143
+ // Don't select text on mobile devices
144
+ if (!('ontouchstart' in window) && $firstInput.select) {
145
+ $firstInput.select();
146
+ }
147
+ };
148
+
149
+ // Try focusing immediately and after scroll animation
150
+ focusFirstInput();
151
+ setTimeout(focusFirstInput, 800);
101
152
  }
102
153
  });
103
154
  });
104
155
  }
105
156
 
106
- // Handle form submission event from FormManager
107
- async function handleFormSubmit(event) {
108
- // Prevent default FormManager submission
109
- event.preventDefault();
110
-
111
- const formData = event.detail.data;
112
- const slapformId = webManager.config.brand.contact['slapform-form-id'];
113
-
114
- console.log('Contact form submission:', formData);
115
-
116
- // Check honeypot field (anti-spam)
117
- if (formData.url_check) {
118
- console.warn('Honeypot field filled - potential spam');
119
- trackContactSpam();
120
- formManager.setFormState('ready');
121
- return;
122
- }
123
-
124
- // Check if slapformId is missing
125
- if (!slapformId) {
126
- webManager.sentry().captureException(new Error('Contact form is not configured - missing slapform ID'));
127
- formManager.showError('Contact form is not configured properly. Please try again later.');
128
- formManager.setFormState('ready');
129
- return;
130
- }
131
-
132
- trackContactFormSubmit(formData.subject || 'general');
133
-
134
- try {
135
- // Prepare data for API
136
- const requestData = {
137
- first_name: formData.first_name,
138
- last_name: formData.last_name,
139
- email: formData.email,
140
- company: formData.company || '',
141
- subject: formData.subject,
142
- message: formData.message,
143
- };
144
-
145
- // Get API endpoint from site config or use default
146
- const apiEndpoint = `https://api.slapform.com/${slapformId}`;
147
-
148
- // Send request using wonderful-fetch
149
- await fetch(apiEndpoint, {
150
- method: 'POST',
151
- body: requestData,
152
- response: 'json',
153
- timeout: 30000 // 30 second timeout
154
- });
155
-
156
- // Handle successful response
157
- formManager.showSuccess('Thank you for your message! We\'ll get back to you within 24 hours.');
158
- formManager.setFormState('submitted');
159
- } catch (error) {
160
- // Only capture technical errors to Sentry (network, timeout, API errors)
161
- if (error.message?.includes('network') || error.message?.includes('timeout') || !error.message?.includes('Failed')) {
162
- webManager.sentry().captureException(new Error('Contact form submission error', { cause: error }));
163
- }
164
-
165
- // Show user-friendly error message
166
- let errorMessage = 'An error occurred while sending your message. ';
167
-
168
- if (error.message?.includes('network')) {
169
- errorMessage += 'Please check your internet connection and try again.';
170
- } else if (error.message?.includes('timeout')) {
171
- errorMessage += 'The request timed out. Please try again.';
172
- } else if (error.message?.includes('Failed')) {
173
- errorMessage = error.message;
174
- } else {
175
- errorMessage += 'Please try again or contact us directly.';
176
- }
177
-
178
- formManager.showError(errorMessage);
179
- formManager.setFormState('ready');
180
- }
181
- }
182
-
183
- // Handle field changes
184
- function handleFieldChange(event) {
185
- const { field, fieldName } = event.detail;
186
-
187
- // Clear field-specific error message if it exists
188
- if (field.dataset.invalidField) {
189
- const $feedback = field.parentElement.querySelector('.invalid-feedback');
190
- if ($feedback) {
191
- $feedback.textContent = '';
192
- }
193
- }
194
- }
195
-
196
157
  // 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
158
  function trackContactSpam() {
222
159
  gtag('event', 'contact_form_spam', {
223
- content_type: 'honeypot'
160
+ content_type: 'honeypot',
224
161
  });
225
162
  }
226
163
 
227
164
  function trackContactFormSubmit(subject) {
228
- gtag('event', 'contact_form_submit', {
229
- subject: subject
165
+ gtag('event', 'generate_lead', {
166
+ lead_source: 'contact_form',
167
+ subject: subject,
230
168
  });
231
169
  fbq('track', 'Lead', {
232
170
  content_name: 'Contact Form',
233
- content_category: subject
171
+ content_category: subject,
234
172
  });
235
- ttq.track('FormSubmit', {
173
+ ttq.track('Contact', {
174
+ content_id: 'contact-form',
175
+ content_type: 'product',
236
176
  content_name: 'Contact Form',
237
- content_type: subject
238
177
  });
239
178
  }
@@ -1,8 +1,12 @@
1
+ /**
2
+ * Download Page JavaScript
3
+ */
4
+
1
5
  // Libraries
2
6
  import { FormManager } from '__main_assets__/js/libs/form-manager.js';
3
7
  import fetch from 'wonderful-fetch';
8
+
4
9
  let webManager = null;
5
- let mobileEmailForms = {};
6
10
 
7
11
  // Module
8
12
  export default (Manager) => {
@@ -37,8 +41,8 @@ const config = {
37
41
  selectors: {
38
42
  platformButtons: '.platform-btn',
39
43
  platformDownloads: '[data-platform]',
40
- downloadButtons: '.tab-pane[data-platform] .btn-primary:not([type="submit"])'
41
- }
44
+ downloadButtons: '.tab-pane[data-platform] .btn-primary:not([type="submit"])',
45
+ },
42
46
  };
43
47
 
44
48
  // Setup platform detection and auto-select
@@ -128,54 +132,26 @@ function showOnboardingModal(platform) {
128
132
  modal.show();
129
133
  }
130
134
 
131
-
132
135
  // Tracking functions
133
- // function trackPlatformDetection(platform) {
134
- // gtag('event', 'platform_detected', {
135
- // platform: platform
136
- // });
137
- // fbq('track', 'ViewContent', {
138
- // content_name: 'Download Page',
139
- // content_category: platform
140
- // });
141
- // ttq.track('ViewContent', {
142
- // content_name: 'Download Page',
143
- // content_type: platform
144
- // });
145
- // }
146
-
147
- // function trackPlatformSwitch(platform) {
148
- // gtag('event', 'platform_switch', {
149
- // platform: platform
150
- // });
151
- // fbq('track', 'CustomizeProduct', {
152
- // content_name: 'Platform Selection',
153
- // content_category: platform
154
- // });
155
- // ttq.track('ClickButton', {
156
- // content_name: 'Platform Switch',
157
- // content_type: platform
158
- // });
159
- // }
160
-
161
136
  function trackDownloadClick(platform, downloadName, downloadUrl) {
162
137
  console.log('Download clicked:', platform, downloadName, downloadUrl);
163
138
 
164
139
  gtag('event', 'download', {
165
140
  platform: platform,
166
141
  download_name: downloadName,
167
- download_url: downloadUrl
142
+ download_url: downloadUrl,
168
143
  });
169
144
 
170
145
  fbq('trackCustom', 'Download', {
171
146
  content_name: downloadName,
172
147
  content_category: platform,
173
- content_type: 'download'
148
+ content_type: 'download',
174
149
  });
175
150
 
176
151
  ttq.track('Download', {
152
+ content_id: `download-${platform}`,
153
+ content_type: 'product',
177
154
  content_name: downloadName,
178
- content_type: platform
179
155
  });
180
156
  }
181
157
 
@@ -187,7 +163,9 @@ function setupCopyButtons() {
187
163
  $button.addEventListener('click', async function() {
188
164
  const $input = this.closest('.input-group').querySelector('input');
189
165
 
190
- if (!$input || !$input.value) return;
166
+ if (!$input || !$input.value) {
167
+ return;
168
+ }
191
169
 
192
170
  try {
193
171
  await webManager.utilities().clipboardCopy($input);
@@ -220,57 +198,32 @@ function setupMobileEmailForms() {
220
198
  const formId = `#mobile-email-form-${platform}`;
221
199
 
222
200
  const formManager = new FormManager(formId, {
223
- autoDisable: true,
224
- showSpinner: true,
225
- validateOnSubmit: true,
226
- allowMultipleSubmissions: false,
227
- submitButtonLoadingText: 'Sending...',
228
- submitButtonSuccessText: 'Sent!',
201
+ allowResubmit: false,
202
+ submittingText: 'Sending...',
203
+ submittedText: 'Email Sent!',
229
204
  });
230
205
 
231
- formManager.addEventListener('submit', (e) => handleMobileEmailSubmit(e, platform));
232
-
233
- mobileEmailForms[platform] = formManager;
234
- });
235
- }
236
-
237
- // Handle mobile email form submission
238
- async function handleMobileEmailSubmit(event, platform) {
239
- event.preventDefault();
240
-
241
- const formData = event.detail.data;
242
- const email = formData.email;
243
- const formManager = mobileEmailForms[platform];
244
-
245
- console.log('Mobile email form submitted:', {
246
- platform: platform,
247
- email: email
248
- });
249
-
250
- try {
251
- // Get API endpoint
252
- const apiEndpoint = webManager.getApiUrl() + '/backend-manager';
253
-
254
- // Send request using wonderful-fetch
255
- await fetch(apiEndpoint, {
256
- method: 'POST',
257
- body: {
258
- command: 'general:send-email',
259
- payload: {
260
- id: 'general:download-app-link',
261
- email: email,
262
- }
263
- },
264
- response: 'json',
265
- timeout: 30000
206
+ formManager.on('submit', async ({ data }) => {
207
+ console.log('Mobile email form submitted:', { platform, email: data.email });
208
+
209
+ // Get API endpoint
210
+ const apiEndpoint = webManager.getApiUrl() + '/backend-manager';
211
+
212
+ // Send request using wonderful-fetch
213
+ await fetch(apiEndpoint, {
214
+ method: 'POST',
215
+ body: {
216
+ command: 'general:send-email',
217
+ payload: {
218
+ id: 'general:download-app-link',
219
+ email: data.email,
220
+ },
221
+ },
222
+ response: 'json',
223
+ timeout: 30000,
224
+ });
225
+
226
+ formManager.showSuccess('Success! Please check your email for the download link.');
266
227
  });
267
-
268
- // Handle successful response
269
- formManager.showSuccess('Success! Please check your email for the download link.');
270
- formManager.setFormState('submitted');
271
- } catch (error) {
272
- webManager.sentry().captureException(new Error('Mobile email form submission error', { cause: error }));
273
- formManager.showError(error.message || 'Failed to send email');
274
- formManager.setFormState('ready');
275
- }
228
+ });
276
229
  }
@@ -33,7 +33,7 @@ async function handleOAuthCallback() {
33
33
  // Get URL parameters
34
34
  const urlParams = new URLSearchParams(window.location.search);
35
35
  const code = urlParams.get('code');
36
- const stateParam = urlParams.get('state');
36
+ const state = urlParams.get('state');
37
37
  const error = urlParams.get('error');
38
38
  const errorDescription = urlParams.get('error_description');
39
39
 
@@ -47,47 +47,47 @@ async function handleOAuthCallback() {
47
47
  throw new Error('Missing authorization code');
48
48
  }
49
49
 
50
- if (!stateParam) {
50
+ if (!state) {
51
51
  throw new Error('Missing state parameter');
52
52
  }
53
53
 
54
54
  // Parse state
55
- let state;
55
+ let stateParsed;
56
56
  try {
57
- state = JSON.parse(decodeURIComponent(stateParam));
57
+ stateParsed = JSON.parse(decodeURIComponent(state));
58
58
  } catch (e) {
59
59
  console.error('Failed to parse state:', e);
60
60
  throw new Error('Invalid state parameter');
61
61
  }
62
62
 
63
- console.log('OAuth callback state:', state);
63
+ console.log('OAuth callback state:', stateParsed);
64
64
 
65
65
  // Validate state
66
- if (!state.provider) {
66
+ if (!stateParsed.provider) {
67
67
  throw new Error('Missing provider in state');
68
68
  }
69
69
 
70
- if (!state.authenticationToken) {
70
+ if (!stateParsed.authenticationToken) {
71
71
  throw new Error('Missing authentication token');
72
72
  }
73
73
 
74
- if (!state.serverUrl) {
74
+ if (!stateParsed.serverUrl) {
75
75
  throw new Error('Missing server URL');
76
76
  }
77
77
 
78
78
  // Update provider name
79
- const providerName = capitalizeFirstLetter(state.provider);
79
+ const providerName = capitalizeFirstLetter(stateParsed.provider);
80
80
  $provider.textContent = providerName;
81
81
 
82
82
  // Validate redirect URL
83
- if (state.redirectUrl && !isValidRedirectUrl(state.redirectUrl)) {
83
+ if (stateParsed.redirectUrl && !isValidRedirectUrl(stateParsed.redirectUrl)) {
84
84
  throw new Error('Invalid redirect URL');
85
85
  }
86
86
 
87
87
  // Build tokenize payload
88
88
  const payload = {
89
89
  state: 'tokenize',
90
- provider: state.provider,
90
+ provider: stateParsed.provider,
91
91
  code: code
92
92
  };
93
93
 
@@ -101,13 +101,13 @@ async function handleOAuthCallback() {
101
101
  console.log('Tokenize payload:', payload);
102
102
 
103
103
  // Call server to complete OAuth flow
104
- const response = await fetch(state.serverUrl, {
104
+ const response = await fetch(stateParsed.serverUrl, {
105
105
  method: 'POST',
106
106
  timeout: 60000,
107
107
  response: 'json',
108
108
  tries: 2,
109
109
  body: {
110
- authenticationToken: state.authenticationToken,
110
+ authenticationToken: stateParsed.authenticationToken,
111
111
  command: 'user:oauth2',
112
112
  payload: payload
113
113
  }
@@ -120,7 +120,7 @@ async function handleOAuthCallback() {
120
120
  }
121
121
 
122
122
  // Show success
123
- showSuccess(state.redirectUrl || state.referrer || '/account#connections');
123
+ showSuccess(stateParsed.redirectUrl || stateParsed.referrer || '/account#connections');
124
124
 
125
125
  } catch (error) {
126
126
  console.error('OAuth callback error:', error);
@@ -163,11 +163,11 @@ function showError(message) {
163
163
 
164
164
  // Set return button href
165
165
  const urlParams = new URLSearchParams(window.location.search);
166
- const stateParam = urlParams.get('state');
166
+ const state = urlParams.get('state');
167
167
 
168
- if (stateParam) {
168
+ if (state) {
169
169
  try {
170
- const state = JSON.parse(decodeURIComponent(stateParam));
170
+ const state = JSON.parse(decodeURIComponent(state));
171
171
  if (state.referrer) {
172
172
  $returnButton.href = state.referrer;
173
173
  }