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.
- package/CLAUDE.md +409 -23
- package/README.md +171 -2
- package/TODO.md +10 -2
- package/_backup/form-manager.backup.js +1020 -0
- package/dist/assets/js/core/auth.js +5 -4
- package/dist/assets/js/core/cookieconsent.js +24 -17
- package/dist/assets/js/core/exit-popup.js +15 -12
- package/dist/assets/js/core/social-sharing.js +8 -4
- package/dist/assets/js/libs/auth/pages.js +78 -149
- package/dist/assets/js/libs/dev.js +192 -129
- package/dist/assets/js/libs/form-manager.js +643 -775
- package/dist/assets/js/pages/account/index.js +3 -2
- package/dist/assets/js/pages/account/sections/api-keys.js +37 -52
- package/dist/assets/js/pages/account/sections/connections.js +37 -46
- package/dist/assets/js/pages/account/sections/delete.js +57 -78
- package/dist/assets/js/pages/account/sections/profile.js +37 -56
- package/dist/assets/js/pages/account/sections/security.js +102 -125
- package/dist/assets/js/pages/admin/notifications/new/index.js +73 -151
- package/dist/assets/js/pages/blog/index.js +33 -53
- package/dist/assets/js/pages/contact/index.js +112 -173
- package/dist/assets/js/pages/download/index.js +39 -86
- package/dist/assets/js/pages/oauth2/index.js +17 -17
- package/dist/assets/js/pages/payment/checkout/index.js +23 -36
- package/dist/assets/js/pages/pricing/index.js +5 -2
- package/dist/assets/js/pages/test/libraries/form-manager/index.js +194 -0
- package/dist/assets/themes/classy/css/components/_cards.scss +2 -2
- package/dist/defaults/_.env +6 -0
- package/dist/defaults/_.gitignore +7 -1
- package/dist/defaults/dist/_includes/core/body.html +5 -13
- package/dist/defaults/dist/_includes/core/foot.html +1 -0
- package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +51 -36
- package/dist/defaults/dist/_layouts/blueprint/admin/notifications/new.html +13 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +84 -42
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +26 -21
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +2 -2
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +72 -58
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +46 -29
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +46 -53
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +111 -73
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +111 -56
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +127 -81
- package/dist/defaults/dist/pages/test/libraries/form-manager.html +181 -0
- package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +1 -1
- package/dist/gulp/tasks/defaults.js +210 -1
- package/dist/gulp/tasks/serve.js +18 -0
- package/dist/lib/logger.js +1 -1
- package/firebase-debug.log +770 -0
- package/package.json +6 -6
- package/.playwright-mcp/page-2025-10-22T19-11-27-666Z.png +0 -0
- package/.playwright-mcp/page-2025-10-22T19-11-57-357Z.png +0 -0
|
@@ -338,7 +338,8 @@ function trackAccountSectionView(sectionId) {
|
|
|
338
338
|
section: sectionId
|
|
339
339
|
});
|
|
340
340
|
ttq.track('ViewContent', {
|
|
341
|
-
|
|
342
|
-
content_type: '
|
|
341
|
+
content_id: `account-${sectionId}`,
|
|
342
|
+
content_type: 'product',
|
|
343
|
+
content_name: `Account ${sectionId}`
|
|
343
344
|
});
|
|
344
345
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* API Keys Section JavaScript
|
|
3
|
+
*/
|
|
4
|
+
|
|
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
|
|
|
5
9
|
let webManager = null;
|
|
6
|
-
let resetApiKeyFormManager = null;
|
|
7
10
|
|
|
8
11
|
// Initialize API Keys section
|
|
9
12
|
export function init(wm) {
|
|
@@ -14,7 +17,9 @@ export function init(wm) {
|
|
|
14
17
|
|
|
15
18
|
// Load API Keys data
|
|
16
19
|
export function loadData(account) {
|
|
17
|
-
if (!account)
|
|
20
|
+
if (!account) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
18
23
|
|
|
19
24
|
// Update API key display
|
|
20
25
|
updateApiKey(account.api?.privateKey);
|
|
@@ -44,35 +49,44 @@ function setupButtons() {
|
|
|
44
49
|
|
|
45
50
|
// Setup reset API key form
|
|
46
51
|
function setupResetApiKeyForm() {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
allowMultipleSubmissions: false,
|
|
52
|
-
submitButtonLoadingText: 'Resetting...'
|
|
52
|
+
const formManager = new FormManager('#reset-api-key-form', {
|
|
53
|
+
allowResubmit: false,
|
|
54
|
+
submittingText: 'Resetting...',
|
|
55
|
+
submittedText: 'Reset!',
|
|
53
56
|
});
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
event.preventDefault();
|
|
58
|
-
|
|
59
|
-
// 1ms wait
|
|
58
|
+
formManager.on('submit', async () => {
|
|
59
|
+
// 1ms wait for dialog to appear properly
|
|
60
60
|
await new Promise(resolve => setTimeout(resolve, 1));
|
|
61
61
|
|
|
62
62
|
// Show confirmation dialog
|
|
63
63
|
if (!confirm('Are you sure you want to reset your API key? This will invalidate your current key and any applications using it will stop working.')) {
|
|
64
|
-
|
|
64
|
+
throw new Error('API key reset cancelled.');
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
67
|
+
// Get server API URL
|
|
68
|
+
const serverApiURL = webManager.getApiUrl() + '/backend-manager';
|
|
69
|
+
|
|
70
|
+
// Make API call to reset API key
|
|
71
|
+
const response = await authorizedFetch(serverApiURL, {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
timeout: 30000,
|
|
74
|
+
response: 'json',
|
|
75
|
+
tries: 2,
|
|
76
|
+
body: {
|
|
77
|
+
command: 'user:regenerate-api-keys',
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (!response.privateKey) {
|
|
82
|
+
throw new Error(response.message || 'Failed to reset API key');
|
|
75
83
|
}
|
|
84
|
+
|
|
85
|
+
// Update the displayed API key
|
|
86
|
+
updateApiKey(response.privateKey);
|
|
87
|
+
|
|
88
|
+
// Show success message
|
|
89
|
+
formManager.showSuccess('API key has been reset successfully!');
|
|
76
90
|
});
|
|
77
91
|
}
|
|
78
92
|
|
|
@@ -104,37 +118,8 @@ async function handleCopyApiKey() {
|
|
|
104
118
|
$copyBtn.classList.remove('btn-success');
|
|
105
119
|
$copyBtn.classList.add('btn-outline-adaptive');
|
|
106
120
|
}, 2000);
|
|
107
|
-
|
|
108
121
|
} catch (err) {
|
|
109
122
|
console.error('Failed to copy API key:', err);
|
|
110
123
|
webManager.utilities().showNotification('Failed to copy API key', 'danger');
|
|
111
124
|
}
|
|
112
125
|
}
|
|
113
|
-
|
|
114
|
-
// Handle reset API key form submission
|
|
115
|
-
async function handleResetApiKeySubmit() {
|
|
116
|
-
// Get server API URL
|
|
117
|
-
const serverApiURL = webManager.getApiUrl() + '/backend-manager';
|
|
118
|
-
|
|
119
|
-
// Make API call to reset API key
|
|
120
|
-
const response = await authorizedFetch(serverApiURL, {
|
|
121
|
-
method: 'POST',
|
|
122
|
-
timeout: 30000,
|
|
123
|
-
response: 'json',
|
|
124
|
-
tries: 2,
|
|
125
|
-
body: {
|
|
126
|
-
command: 'user:regenerate-api-keys',
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
if (response.privateKey) {
|
|
131
|
-
// Update the displayed API key
|
|
132
|
-
updateApiKey(response.privateKey);
|
|
133
|
-
|
|
134
|
-
// Show success message
|
|
135
|
-
webManager.utilities().showNotification('API key has been reset successfully', 'success');
|
|
136
|
-
} else {
|
|
137
|
-
throw new Error(response.message || 'Failed to reset API key');
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Connections Section JavaScript - OAuth account linking
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Libraries
|
|
2
6
|
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
3
|
-
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js'
|
|
7
|
+
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
4
8
|
|
|
5
9
|
let webManager = null;
|
|
6
10
|
let appData = null;
|
|
@@ -22,7 +26,9 @@ export async function init(wm) {
|
|
|
22
26
|
|
|
23
27
|
// Load connections data
|
|
24
28
|
export async function loadData(account, sharedAppData) {
|
|
25
|
-
if (!account)
|
|
29
|
+
if (!account) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
26
32
|
|
|
27
33
|
accountData = account;
|
|
28
34
|
appData = sharedAppData;
|
|
@@ -133,7 +139,7 @@ function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
|
133
139
|
$description: !!$description,
|
|
134
140
|
$form: !!$form,
|
|
135
141
|
$connectButton: !!$connectButton,
|
|
136
|
-
$disconnectButton: !!$disconnectButton
|
|
142
|
+
$disconnectButton: !!$disconnectButton,
|
|
137
143
|
});
|
|
138
144
|
|
|
139
145
|
const isConnected = userConnection && userConnection.identity;
|
|
@@ -146,7 +152,7 @@ function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
|
146
152
|
discord: 'Connect to access Discord community features',
|
|
147
153
|
github: 'Link your GitHub account for repository access',
|
|
148
154
|
twitter: 'Share updates and connect with Twitter',
|
|
149
|
-
facebook: 'Connect your Facebook account for social features'
|
|
155
|
+
facebook: 'Connect your Facebook account for social features',
|
|
150
156
|
};
|
|
151
157
|
|
|
152
158
|
// Use provider description or fallback to default
|
|
@@ -167,7 +173,7 @@ function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
|
167
173
|
const dateStr = date.toLocaleDateString('en-US', {
|
|
168
174
|
month: 'short',
|
|
169
175
|
day: 'numeric',
|
|
170
|
-
year: 'numeric'
|
|
176
|
+
year: 'numeric',
|
|
171
177
|
});
|
|
172
178
|
statusText = `${displayName} • ${dateStr}`;
|
|
173
179
|
}
|
|
@@ -201,15 +207,17 @@ function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
|
201
207
|
|
|
202
208
|
// Get display name for connection
|
|
203
209
|
function getConnectionDisplayName(connection) {
|
|
204
|
-
if (!connection || !connection.identity)
|
|
210
|
+
if (!connection || !connection.identity) {
|
|
211
|
+
return 'Unknown';
|
|
212
|
+
}
|
|
205
213
|
|
|
206
214
|
// Try different fields based on provider
|
|
207
|
-
return connection.identity.global_name
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
215
|
+
return connection.identity.global_name
|
|
216
|
+
|| connection.identity.username
|
|
217
|
+
|| connection.identity.name
|
|
218
|
+
|| connection.identity.email
|
|
219
|
+
|| connection.identity.id
|
|
220
|
+
|| 'Connected';
|
|
213
221
|
}
|
|
214
222
|
|
|
215
223
|
// Initialize FormManager for a provider
|
|
@@ -230,22 +238,19 @@ function initializeProviderForm(providerId) {
|
|
|
230
238
|
|
|
231
239
|
console.log(`Initializing FormManager for ${providerId}`);
|
|
232
240
|
|
|
233
|
-
// Create new FormManager
|
|
234
241
|
const formManager = new FormManager(`#${formId}`, {
|
|
235
|
-
|
|
236
|
-
showSpinner: true
|
|
242
|
+
submittingText: 'Connecting...',
|
|
237
243
|
});
|
|
238
244
|
|
|
239
245
|
// Store the FormManager instance
|
|
240
246
|
connectionForms.set(providerId, formManager);
|
|
241
247
|
|
|
242
248
|
// Listen for state changes to update button after FormManager is ready
|
|
243
|
-
formManager.
|
|
244
|
-
|
|
245
|
-
console.log(`[DEBUG] ${providerId} - FormManager state changed to:`, status);
|
|
249
|
+
formManager.on('statechange', ({ state }) => {
|
|
250
|
+
console.log(`[DEBUG] ${providerId} - FormManager state changed to:`, state);
|
|
246
251
|
|
|
247
252
|
// When FormManager transitions to ready, update the button status
|
|
248
|
-
if (
|
|
253
|
+
if (state === 'ready') {
|
|
249
254
|
console.log(`[DEBUG] ${providerId} - FormManager is ready, updating button status`);
|
|
250
255
|
const userConnection = accountData?.oauth2?.[providerId];
|
|
251
256
|
const providerSettings = appData?.oauth2?.[providerId];
|
|
@@ -253,37 +258,23 @@ function initializeProviderForm(providerId) {
|
|
|
253
258
|
}
|
|
254
259
|
});
|
|
255
260
|
|
|
256
|
-
|
|
257
|
-
formManager.addEventListener('submit', async (event) => {
|
|
258
|
-
event.preventDefault();
|
|
259
|
-
|
|
260
|
-
const { data, submitButton } = event.detail;
|
|
261
|
+
formManager.on('submit', async ({ data, $submitButton }) => {
|
|
261
262
|
const provider = data.provider;
|
|
262
263
|
|
|
263
264
|
// Determine action from the clicked button's data-action attribute
|
|
264
|
-
const action = submitButton?.getAttribute('data-action');
|
|
265
|
+
const action = $submitButton?.getAttribute('data-action');
|
|
265
266
|
|
|
266
267
|
console.log(`[DEBUG] ${providerId} - Form submitted. Action:`, action, 'Provider:', provider);
|
|
267
268
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
// Get provider settings to pass for description display
|
|
277
|
-
const providerSettings = appData?.oauth2?.[provider];
|
|
278
|
-
updateProviderStatus(provider, null, providerSettings);
|
|
279
|
-
}
|
|
269
|
+
if (action === 'connect') {
|
|
270
|
+
await handleConnect(provider);
|
|
271
|
+
} else if (action === 'disconnect') {
|
|
272
|
+
const success = await handleDisconnect(provider);
|
|
273
|
+
if (success) {
|
|
274
|
+
// Get provider settings to pass for description display
|
|
275
|
+
const providerSettings = appData?.oauth2?.[provider];
|
|
276
|
+
updateProviderStatus(provider, null, providerSettings);
|
|
280
277
|
}
|
|
281
|
-
|
|
282
|
-
// Success - FormManager will handle state automatically
|
|
283
|
-
} catch (error) {
|
|
284
|
-
// Show error and reset form state
|
|
285
|
-
formManager.showError(error);
|
|
286
|
-
formManager.setFormState('ready');
|
|
287
278
|
}
|
|
288
279
|
});
|
|
289
280
|
}
|
|
@@ -311,7 +302,7 @@ async function handleConnect(providerId) {
|
|
|
311
302
|
state: 'authorize',
|
|
312
303
|
scope: scope,
|
|
313
304
|
referrer: window.location.href,
|
|
314
|
-
}
|
|
305
|
+
},
|
|
315
306
|
},
|
|
316
307
|
});
|
|
317
308
|
|
|
@@ -354,7 +345,7 @@ async function handleDisconnect(providerId) {
|
|
|
354
345
|
state: 'deauthorize',
|
|
355
346
|
scope: scope,
|
|
356
347
|
referrer: window.location.href,
|
|
357
|
-
}
|
|
348
|
+
},
|
|
358
349
|
},
|
|
359
350
|
});
|
|
360
351
|
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Delete Account Section JavaScript
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Libraries
|
|
6
|
+
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
7
|
+
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
3
8
|
|
|
4
9
|
let webManager = null;
|
|
10
|
+
let formManager = null;
|
|
5
11
|
|
|
6
12
|
// Initialize delete section
|
|
7
13
|
export async function init(wm) {
|
|
@@ -15,9 +21,16 @@ function setupDeleteAccountForm() {
|
|
|
15
21
|
const $checkbox = document.getElementById('delete-confirm-checkbox');
|
|
16
22
|
const $deleteBtn = document.getElementById('delete-account-btn');
|
|
17
23
|
const $cancelBtn = document.getElementById('cancel-delete-btn');
|
|
18
|
-
const $reason = document.getElementById('delete-reason');
|
|
19
24
|
|
|
20
|
-
if (!$form || !$checkbox || !$deleteBtn)
|
|
25
|
+
if (!$form || !$checkbox || !$deleteBtn) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
formManager = new FormManager('#delete-account-form', {
|
|
30
|
+
allowResubmit: false,
|
|
31
|
+
submittingText: 'Deleting account...',
|
|
32
|
+
submittedText: 'Account Deleted!',
|
|
33
|
+
});
|
|
21
34
|
|
|
22
35
|
// Enable/disable delete button based on checkbox
|
|
23
36
|
$checkbox.addEventListener('change', (e) => {
|
|
@@ -32,104 +45,70 @@ function setupDeleteAccountForm() {
|
|
|
32
45
|
});
|
|
33
46
|
}
|
|
34
47
|
|
|
35
|
-
|
|
36
|
-
$form.addEventListener('submit', async (e) => {
|
|
37
|
-
e.preventDefault();
|
|
38
|
-
|
|
48
|
+
formManager.on('submit', async ({ data }) => {
|
|
39
49
|
// Check if checkbox is checked
|
|
40
50
|
if (!$checkbox.checked) {
|
|
41
|
-
|
|
42
|
-
return;
|
|
51
|
+
throw new Error('Please confirm that you understand this action is permanent.');
|
|
43
52
|
}
|
|
44
53
|
|
|
54
|
+
// 1ms wait for dialog to appear properly
|
|
55
|
+
await new Promise(resolve => setTimeout(resolve, 1));
|
|
56
|
+
|
|
45
57
|
// Show confirmation dialog
|
|
46
58
|
const confirmMessage = `Are you absolutely sure you want to delete your account?\n\nThis action CANNOT be undone.\n\nType "DELETE" to confirm:`;
|
|
47
59
|
const userInput = prompt(confirmMessage);
|
|
48
60
|
|
|
49
61
|
if (userInput !== 'DELETE') {
|
|
50
|
-
|
|
51
|
-
return;
|
|
62
|
+
throw new Error('Account deletion cancelled. You must type "DELETE" exactly to confirm.');
|
|
52
63
|
}
|
|
53
64
|
|
|
54
65
|
// Final confirmation
|
|
55
66
|
const finalConfirm = confirm('This is your last chance to cancel.\n\nAre you sure you want to permanently delete your account?');
|
|
56
|
-
|
|
67
|
+
|
|
57
68
|
if (!finalConfirm) {
|
|
58
|
-
|
|
69
|
+
throw new Error('Account deletion cancelled.');
|
|
59
70
|
}
|
|
60
71
|
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
}
|
|
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>`;
|
|
72
|
+
// Send delete request to server
|
|
73
|
+
const response = await authorizedFetch(webManager.getApiUrl(), {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
timeout: 30000,
|
|
76
|
+
response: 'json',
|
|
77
|
+
tries: 2,
|
|
78
|
+
body: {
|
|
79
|
+
command: 'user:delete',
|
|
80
|
+
payload: {
|
|
81
|
+
reason: data.reason || '',
|
|
82
|
+
confirmed: true,
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
console.log('Delete account response:', response);
|
|
88
|
+
|
|
89
|
+
if (!response.success) {
|
|
90
|
+
throw new Error(response.message || 'Failed to delete account');
|
|
102
91
|
}
|
|
92
|
+
|
|
93
|
+
// Show success message
|
|
94
|
+
formManager.showSuccess('Your account has been successfully deleted. You will now be signed out.');
|
|
95
|
+
|
|
96
|
+
// Sign out the user
|
|
97
|
+
await webManager.auth().signOut();
|
|
98
|
+
|
|
99
|
+
// Redirect to home page
|
|
100
|
+
setTimeout(() => {
|
|
101
|
+
window.location.href = '/';
|
|
102
|
+
}, 1500);
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// Load delete section data (if needed)
|
|
107
|
-
export async function loadData(
|
|
107
|
+
export async function loadData() {
|
|
108
108
|
// No specific data to load for delete section
|
|
109
|
-
// Could potentially show account age or other info here
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
// Called when section is shown
|
|
113
112
|
export function onShow() {
|
|
114
|
-
//
|
|
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
|
-
|
|
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
|
-
}
|
|
113
|
+
// Nothing needed
|
|
135
114
|
}
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Profile Section JavaScript
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// Libraries
|
|
2
6
|
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
3
7
|
|
|
4
8
|
let formManager = null;
|
|
@@ -13,7 +17,9 @@ export function init(wm) {
|
|
|
13
17
|
|
|
14
18
|
// Load profile data
|
|
15
19
|
export function loadData(account, user) {
|
|
16
|
-
if (!account)
|
|
20
|
+
if (!account) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
17
23
|
|
|
18
24
|
// Format birthday if it exists
|
|
19
25
|
let birthdayValue = '';
|
|
@@ -33,34 +39,31 @@ export function loadData(account, user) {
|
|
|
33
39
|
const formData = {
|
|
34
40
|
auth: {
|
|
35
41
|
email: account.auth?.email || user?.email || '',
|
|
36
|
-
uid: user?.uid || account.auth?.uid || ''
|
|
42
|
+
uid: user?.uid || account.auth?.uid || '',
|
|
37
43
|
},
|
|
38
44
|
personal: {
|
|
39
45
|
name: {
|
|
40
46
|
first: account.personal?.name?.first || '',
|
|
41
|
-
last: account.personal?.name?.last || ''
|
|
47
|
+
last: account.personal?.name?.last || '',
|
|
42
48
|
},
|
|
43
49
|
birthday: birthdayValue,
|
|
44
50
|
gender: account.personal?.gender || '',
|
|
45
51
|
location: {
|
|
46
52
|
country: account.personal?.location?.country || '',
|
|
47
53
|
region: account.personal?.location?.region || '',
|
|
48
|
-
city: account.personal?.location?.city || ''
|
|
54
|
+
city: account.personal?.location?.city || '',
|
|
49
55
|
},
|
|
50
56
|
telephone: {
|
|
51
57
|
countryCode: phoneCountryCode,
|
|
52
|
-
national: account.personal?.telephone?.national?.toString() || ''
|
|
53
|
-
}
|
|
54
|
-
}
|
|
58
|
+
national: account.personal?.telephone?.national?.toString() || '',
|
|
59
|
+
},
|
|
60
|
+
},
|
|
55
61
|
};
|
|
56
62
|
|
|
57
|
-
formManager.
|
|
63
|
+
formManager.setData(formData);
|
|
58
64
|
|
|
59
65
|
// Set form to ready state now that data is loaded
|
|
60
|
-
formManager.
|
|
61
|
-
|
|
62
|
-
// Avatar and display name are now handled by data-wm-bind in HTML
|
|
63
|
-
// since photoURL and displayName are always available from getUser()
|
|
66
|
+
formManager.ready();
|
|
64
67
|
|
|
65
68
|
// Update join date
|
|
66
69
|
updateJoinDate(user);
|
|
@@ -72,29 +75,16 @@ export function loadData(account, user) {
|
|
|
72
75
|
// Setup profile form
|
|
73
76
|
function setupProfileForm() {
|
|
74
77
|
formManager = new FormManager('#profile-form', {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
allowMultipleSubmissions: true,
|
|
78
|
-
submitButtonLoadingText: 'Saving...',
|
|
79
|
-
initialState: 'loading' // Start in loading state until data loads
|
|
78
|
+
autoReady: false, // Start in initializing state until data loads
|
|
79
|
+
submittingText: 'Saving...',
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
try {
|
|
87
|
-
// Update user profile
|
|
88
|
-
await updateUserProfile(data);
|
|
82
|
+
formManager.on('submit', async ({ data }) => {
|
|
83
|
+
// Update user profile
|
|
84
|
+
await updateUserProfile(data);
|
|
89
85
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
} catch (error) {
|
|
94
|
-
console.error('Failed to update profile:', error);
|
|
95
|
-
webManager.utilities().showNotification('Failed to update profile. Please try again.', 'danger');
|
|
96
|
-
throw error; // Re-throw to trigger FormManager's error handling
|
|
97
|
-
}
|
|
86
|
+
// Show success message
|
|
87
|
+
formManager.showSuccess('Profile updated successfully!');
|
|
98
88
|
});
|
|
99
89
|
}
|
|
100
90
|
|
|
@@ -117,12 +107,12 @@ async function updateUserProfile(data) {
|
|
|
117
107
|
const date = new Date(data.personal.birthday);
|
|
118
108
|
data.personal.birthday = {
|
|
119
109
|
timestamp: date.toISOString(),
|
|
120
|
-
timestampUNIX: Math.floor(date.getTime() / 1000)
|
|
110
|
+
timestampUNIX: Math.floor(date.getTime() / 1000),
|
|
121
111
|
};
|
|
122
112
|
} else {
|
|
123
113
|
data.personal.birthday = {
|
|
124
|
-
timestamp:
|
|
125
|
-
timestampUNIX: 0
|
|
114
|
+
timestamp: '1970-01-01T00:00:00.000Z',
|
|
115
|
+
timestampUNIX: 0,
|
|
126
116
|
};
|
|
127
117
|
}
|
|
128
118
|
|
|
@@ -151,21 +141,16 @@ async function updateUserProfile(data) {
|
|
|
151
141
|
await userDocRef.set(data, { merge: true });
|
|
152
142
|
|
|
153
143
|
console.log('Profile successfully updated in Firestore');
|
|
154
|
-
|
|
155
|
-
// Avatar updates automatically via data-wm-bind
|
|
156
144
|
}
|
|
157
145
|
|
|
158
|
-
// Avatar functionality removed - photoURL is always available from getUser()
|
|
159
|
-
// and is handled via data-wm-bind in the HTML template
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
146
|
// Handle copy UID
|
|
164
147
|
async function handleCopyUid() {
|
|
165
148
|
const $uidInput = document.getElementById('uid-input');
|
|
166
149
|
const $copyBtn = document.getElementById('copy-uid-btn');
|
|
167
150
|
|
|
168
|
-
if (!$uidInput || !$uidInput.value)
|
|
151
|
+
if (!$uidInput || !$uidInput.value) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
169
154
|
|
|
170
155
|
try {
|
|
171
156
|
// Use webManager's clipboard utility
|
|
@@ -185,29 +170,26 @@ async function handleCopyUid() {
|
|
|
185
170
|
$copyBtn.classList.remove('btn-success');
|
|
186
171
|
$copyBtn.classList.add('btn-outline-adaptive');
|
|
187
172
|
}, 2000);
|
|
188
|
-
|
|
189
173
|
} catch (err) {
|
|
190
174
|
console.error('Failed to copy UID:', err);
|
|
191
175
|
}
|
|
192
176
|
}
|
|
193
177
|
|
|
194
|
-
// Display name functionality removed - displayName is always available from getUser()
|
|
195
|
-
// and is handled via data-wm-bind in the HTML template
|
|
196
|
-
|
|
197
178
|
// Update join date from Firebase user
|
|
198
179
|
function updateJoinDate(user) {
|
|
199
180
|
const $joinDate = document.getElementById('profile-join-date');
|
|
200
|
-
if (!$joinDate)
|
|
181
|
+
if (!$joinDate) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
201
184
|
|
|
202
185
|
// Get creation time from Firebase user metadata
|
|
203
|
-
// The metadata object has creationTime as a string timestamp
|
|
204
186
|
const creationTime = user?.metadata?.creationTime;
|
|
205
187
|
|
|
206
188
|
if (creationTime) {
|
|
207
189
|
const joinDate = new Date(creationTime);
|
|
208
190
|
const formattedDate = joinDate.toLocaleDateString('en-US', {
|
|
209
191
|
month: 'long',
|
|
210
|
-
year: 'numeric'
|
|
192
|
+
year: 'numeric',
|
|
211
193
|
});
|
|
212
194
|
|
|
213
195
|
$joinDate.textContent = `Member since ${formattedDate}`;
|
|
@@ -228,7 +210,7 @@ function updateRoleBadges(account) {
|
|
|
228
210
|
developer: 'badge-coder',
|
|
229
211
|
moderator: 'badge-moderator',
|
|
230
212
|
betaTester: 'badge-beta',
|
|
231
|
-
vip: 'badge-vip'
|
|
213
|
+
vip: 'badge-vip',
|
|
232
214
|
};
|
|
233
215
|
|
|
234
216
|
// Show/hide role badges
|
|
@@ -246,9 +228,9 @@ function updateRoleBadges(account) {
|
|
|
246
228
|
// Show premium badge if subscription is active
|
|
247
229
|
const $premiumBadge = document.getElementById('badge-premium');
|
|
248
230
|
if ($premiumBadge) {
|
|
249
|
-
const isActive = subscription?.status === 'active'
|
|
250
|
-
|
|
251
|
-
|
|
231
|
+
const isActive = subscription?.status === 'active'
|
|
232
|
+
|| subscription?.status === 'trialing'
|
|
233
|
+
|| subscription?.active === true;
|
|
252
234
|
|
|
253
235
|
if (isActive) {
|
|
254
236
|
$premiumBadge.classList.remove('d-none');
|
|
@@ -257,4 +239,3 @@ function updateRoleBadges(account) {
|
|
|
257
239
|
}
|
|
258
240
|
}
|
|
259
241
|
}
|
|
260
|
-
|