ultimate-jekyll-manager 0.0.117 → 0.0.118
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 +330 -138
- package/README.md +108 -0
- package/TODO.md +1 -1
- package/dist/assets/js/core/auth.js +3 -7
- package/dist/assets/js/libs/prerendered-icons.js +27 -0
- package/dist/assets/js/pages/account/index.js +1 -1
- package/dist/assets/js/pages/account/sections/api-keys.js +2 -6
- package/dist/assets/js/pages/account/sections/connections.js +101 -59
- package/dist/assets/js/pages/account/sections/referrals.js +29 -29
- package/dist/assets/js/pages/account/sections/security.js +47 -70
- package/dist/assets/js/pages/payment/checkout/index.js +6 -6
- package/dist/assets/js/pages/payment/checkout/modules/processors-main.js +2 -2
- package/dist/assets/js/pages/payment/checkout/modules/session.js +4 -4
- package/dist/defaults/dist/_includes/core/body.html +23 -0
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +41 -14
- package/dist/defaults/dist/pages/pricing.md +7 -0
- package/firebase-debug.log +126 -0
- package/package.json +5 -5
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
2
2
|
|
|
3
3
|
// Auth Module
|
|
4
4
|
export default function (Manager, options) {
|
|
@@ -166,9 +166,6 @@ function setAnalyticsUserId(user) {
|
|
|
166
166
|
// Send user metadata to server (affiliate, UTM params, etc.)
|
|
167
167
|
async function sendUserSignupMetadata(user, webManager) {
|
|
168
168
|
try {
|
|
169
|
-
// Get the auth token
|
|
170
|
-
const token = await webManager.auth().getIdToken();
|
|
171
|
-
|
|
172
169
|
// Get affiliate data from storage
|
|
173
170
|
const affiliateData = webManager.storage().get('marketing.affiliate', null);
|
|
174
171
|
const utmData = webManager.storage().get('marketing.utm', null);
|
|
@@ -193,11 +190,10 @@ async function sendUserSignupMetadata(user, webManager) {
|
|
|
193
190
|
// Get server API URL
|
|
194
191
|
const serverApiURL = webManager.getApiUrl() + '/backend-manager';
|
|
195
192
|
|
|
196
|
-
// Make API call to
|
|
197
|
-
const response = await
|
|
193
|
+
// Make API call to send signup metadata
|
|
194
|
+
const response = await authorizedFetch(serverApiURL, {
|
|
198
195
|
method: 'POST',
|
|
199
196
|
body: {
|
|
200
|
-
authenticationToken: token,
|
|
201
197
|
command: 'user:sign-up',
|
|
202
198
|
payload: payload
|
|
203
199
|
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prerendered Icons Library
|
|
3
|
+
* Retrieves pre-rendered icon HTML from the frontmatter icon system
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get pre-rendered icon by name from frontmatter icon system
|
|
8
|
+
* @param {string} iconName - Name of the icon to retrieve (matches data-icon attribute)
|
|
9
|
+
* @returns {string} Icon HTML or empty string if not found
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
|
|
13
|
+
*
|
|
14
|
+
* // Get an icon
|
|
15
|
+
* const appleIcon = getPrerenderedIcon('apple');
|
|
16
|
+
*/
|
|
17
|
+
export function getPrerenderedIcon(iconName) {
|
|
18
|
+
// Query the global prerendered icons container
|
|
19
|
+
const $iconTemplate = document.querySelector(`#prerendered-icons [data-icon="${iconName}"]`);
|
|
20
|
+
|
|
21
|
+
if ($iconTemplate) {
|
|
22
|
+
return $iconTemplate.innerHTML;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Return empty string if not found
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
@@ -82,7 +82,7 @@ async function initializeAccount() {
|
|
|
82
82
|
{
|
|
83
83
|
// Check for test subscription parameter
|
|
84
84
|
const urlParams = new URLSearchParams(window.location.search);
|
|
85
|
-
const testSubscription = urlParams.get('
|
|
85
|
+
const testSubscription = urlParams.get('_dev_subscription');
|
|
86
86
|
|
|
87
87
|
if (testSubscription && webManager.isDevelopment()) {
|
|
88
88
|
try {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// API Keys section module
|
|
2
2
|
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
3
|
-
import
|
|
3
|
+
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
|
|
4
4
|
|
|
5
5
|
let webManager = null;
|
|
6
6
|
let resetApiKeyFormManager = null;
|
|
@@ -113,20 +113,16 @@ async function handleCopyApiKey() {
|
|
|
113
113
|
|
|
114
114
|
// Handle reset API key form submission
|
|
115
115
|
async function handleResetApiKeySubmit() {
|
|
116
|
-
// Get authentication token
|
|
117
|
-
const token = await webManager.auth().getIdToken();
|
|
118
|
-
|
|
119
116
|
// Get server API URL
|
|
120
117
|
const serverApiURL = webManager.getApiUrl() + '/backend-manager';
|
|
121
118
|
|
|
122
119
|
// Make API call to reset API key
|
|
123
|
-
const response = await
|
|
120
|
+
const response = await authorizedFetch(serverApiURL, {
|
|
124
121
|
method: 'POST',
|
|
125
122
|
timeout: 30000,
|
|
126
123
|
response: 'json',
|
|
127
124
|
tries: 2,
|
|
128
125
|
body: {
|
|
129
|
-
authenticationToken: token,
|
|
130
126
|
command: 'user:regenerate-api-keys',
|
|
131
127
|
},
|
|
132
128
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Connections section module for OAuth account linking
|
|
2
2
|
import { FormManager } from '__main_assets__/js/libs/form-manager.js';
|
|
3
|
-
import
|
|
3
|
+
import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';;
|
|
4
4
|
|
|
5
5
|
let webManager = null;
|
|
6
6
|
let appData = null;
|
|
@@ -32,6 +32,8 @@ export async function loadData(account, sharedAppData) {
|
|
|
32
32
|
|
|
33
33
|
// Display available and connected OAuth providers
|
|
34
34
|
function displayConnections() {
|
|
35
|
+
console.log('[DEBUG] displayConnections() called');
|
|
36
|
+
|
|
35
37
|
// Hide loading state
|
|
36
38
|
const $loading = document.getElementById('connections-loading');
|
|
37
39
|
if ($loading) {
|
|
@@ -40,6 +42,7 @@ function displayConnections() {
|
|
|
40
42
|
|
|
41
43
|
// Check if appData is loaded
|
|
42
44
|
if (!appData) {
|
|
45
|
+
console.log('[DEBUG] No appData, showing loading state');
|
|
43
46
|
// Show loading if no app data yet
|
|
44
47
|
if ($loading) {
|
|
45
48
|
$loading.classList.remove('d-none');
|
|
@@ -51,36 +54,51 @@ function displayConnections() {
|
|
|
51
54
|
const availableProviders = appData?.oauth2 || {};
|
|
52
55
|
const userConnections = accountData?.oauth2 || {};
|
|
53
56
|
|
|
57
|
+
console.log('[DEBUG] Available OAuth providers:', availableProviders);
|
|
58
|
+
console.log('[DEBUG] User connections:', userConnections);
|
|
59
|
+
|
|
54
60
|
// Check if any providers are configured
|
|
55
61
|
let hasEnabledProviders = false;
|
|
56
62
|
|
|
57
63
|
// Process each supported provider
|
|
58
64
|
supportedProviders.forEach(providerId => {
|
|
65
|
+
console.log(`[DEBUG] Processing provider: ${providerId}`);
|
|
66
|
+
|
|
59
67
|
const providerSettings = availableProviders[providerId];
|
|
60
68
|
const $providerElement = document.getElementById(`connection-${providerId}`);
|
|
61
69
|
|
|
70
|
+
console.log(`[DEBUG] ${providerId} - providerSettings:`, providerSettings);
|
|
71
|
+
console.log(`[DEBUG] ${providerId} - providerSettings.enabled:`, providerSettings?.enabled);
|
|
72
|
+
console.log(`[DEBUG] ${providerId} - $providerElement exists:`, !!$providerElement);
|
|
73
|
+
|
|
62
74
|
if (!$providerElement) {
|
|
75
|
+
console.warn(`[DEBUG] ${providerId} - Provider element not found in DOM`);
|
|
63
76
|
return;
|
|
64
77
|
}
|
|
65
78
|
|
|
66
79
|
// Check if provider is enabled
|
|
67
80
|
const isEnabled = providerSettings && providerSettings.enabled !== false;
|
|
81
|
+
console.log(`[DEBUG] ${providerId} - isEnabled:`, isEnabled);
|
|
68
82
|
|
|
69
83
|
if (isEnabled) {
|
|
70
84
|
hasEnabledProviders = true;
|
|
71
85
|
|
|
72
|
-
// Show the provider element
|
|
86
|
+
// Show the provider element first
|
|
87
|
+
console.log(`[DEBUG] ${providerId} - Removing d-none class`);
|
|
73
88
|
$providerElement.classList.remove('d-none');
|
|
74
89
|
|
|
75
|
-
//
|
|
76
|
-
|
|
90
|
+
// Initialize FormManager for this provider before updating status
|
|
91
|
+
console.log(`[DEBUG] ${providerId} - About to initialize FormManager`);
|
|
92
|
+
initializeProviderForm(providerId);
|
|
93
|
+
|
|
94
|
+
// Update provider status based on user connection
|
|
77
95
|
const userConnection = userConnections[providerId];
|
|
96
|
+
console.log(`[DEBUG] ${providerId} - userConnection:`, userConnection);
|
|
97
|
+
console.log(`[DEBUG] ${providerId} - About to update provider status`);
|
|
78
98
|
updateProviderStatus(providerId, userConnection, providerSettings);
|
|
79
|
-
|
|
80
|
-
// Initialize FormManager AFTER setting correct button state
|
|
81
|
-
initializeProviderForm(providerId);
|
|
82
99
|
} else {
|
|
83
100
|
// Hide disabled providers
|
|
101
|
+
console.log(`[DEBUG] ${providerId} - Provider disabled, adding d-none class`);
|
|
84
102
|
$providerElement.classList.add('d-none');
|
|
85
103
|
}
|
|
86
104
|
});
|
|
@@ -98,14 +116,28 @@ function displayConnections() {
|
|
|
98
116
|
|
|
99
117
|
// Update provider status display
|
|
100
118
|
function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
119
|
+
console.log(`[DEBUG] updateProviderStatus() called for ${providerId}`);
|
|
120
|
+
console.log(`[DEBUG] ${providerId} - userConnection:`, userConnection);
|
|
121
|
+
console.log(`[DEBUG] ${providerId} - userConnection truthy:`, !!userConnection);
|
|
122
|
+
console.log(`[DEBUG] ${providerId} - userConnection.identity:`, userConnection?.identity);
|
|
123
|
+
console.log(`[DEBUG] ${providerId} - providerSettings:`, providerSettings);
|
|
124
|
+
|
|
101
125
|
const $status = document.getElementById(`${providerId}-connection-status`);
|
|
102
126
|
const $description = document.getElementById(`${providerId}-connection-description`);
|
|
103
127
|
const $form = document.getElementById(`connection-form-${providerId}`);
|
|
104
|
-
const $
|
|
105
|
-
const $
|
|
106
|
-
|
|
128
|
+
const $connectButton = $form?.querySelector('button[data-action="connect"]');
|
|
129
|
+
const $disconnectButton = $form?.querySelector('button[data-action="disconnect"]');
|
|
130
|
+
|
|
131
|
+
console.log(`[DEBUG] ${providerId} - DOM elements found:`, {
|
|
132
|
+
$status: !!$status,
|
|
133
|
+
$description: !!$description,
|
|
134
|
+
$form: !!$form,
|
|
135
|
+
$connectButton: !!$connectButton,
|
|
136
|
+
$disconnectButton: !!$disconnectButton
|
|
137
|
+
});
|
|
107
138
|
|
|
108
139
|
const isConnected = userConnection && userConnection.identity;
|
|
140
|
+
console.log(`[DEBUG] ${providerId} - isConnected:`, isConnected);
|
|
109
141
|
|
|
110
142
|
// Always show description on the left
|
|
111
143
|
if ($description) {
|
|
@@ -117,9 +149,8 @@ function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
|
117
149
|
facebook: 'Connect your Facebook account for social features'
|
|
118
150
|
};
|
|
119
151
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|| `Connect your ${providerId.charAt(0).toUpperCase() + providerId.slice(1)} account`;
|
|
152
|
+
// Use provider description or fallback to default
|
|
153
|
+
const descriptionText = providerSettings?.description || defaultDescriptions[providerId] || `Connect your ${providerId.charAt(0).toUpperCase() + providerId.slice(1)} account`;
|
|
123
154
|
$description.textContent = descriptionText;
|
|
124
155
|
$description.classList.remove('d-none');
|
|
125
156
|
}
|
|
@@ -144,39 +175,26 @@ function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
|
144
175
|
$status.textContent = statusText;
|
|
145
176
|
$status.classList.remove('d-none');
|
|
146
177
|
} else {
|
|
147
|
-
// Not connected - hide status
|
|
178
|
+
// Not connected - hide status text
|
|
148
179
|
$status.textContent = '';
|
|
149
180
|
$status.classList.add('d-none');
|
|
150
181
|
}
|
|
151
182
|
}
|
|
152
183
|
|
|
153
|
-
|
|
184
|
+
// Show/hide appropriate button
|
|
185
|
+
if ($connectButton && $disconnectButton) {
|
|
186
|
+
console.log(`[DEBUG] ${providerId} - Updating buttons. isConnected:`, isConnected);
|
|
187
|
+
|
|
154
188
|
if (isConnected) {
|
|
155
|
-
//
|
|
156
|
-
$
|
|
157
|
-
$
|
|
158
|
-
|
|
159
|
-
$action.value = 'disconnect';
|
|
160
|
-
|
|
161
|
-
// Replace icon
|
|
162
|
-
const $icon = $button.querySelector('.fa-icon');
|
|
163
|
-
if ($icon) {
|
|
164
|
-
$icon.classList.remove('fa-link');
|
|
165
|
-
$icon.classList.add('fa-unlink');
|
|
166
|
-
}
|
|
189
|
+
// Hide connect button, show disconnect button
|
|
190
|
+
$connectButton.classList.add('d-none');
|
|
191
|
+
$disconnectButton.classList.remove('d-none');
|
|
192
|
+
console.log(`[DEBUG] ${providerId} - Showing disconnect button`);
|
|
167
193
|
} else {
|
|
168
|
-
//
|
|
169
|
-
$
|
|
170
|
-
$
|
|
171
|
-
|
|
172
|
-
$action.value = 'connect';
|
|
173
|
-
|
|
174
|
-
// Replace icon
|
|
175
|
-
const $icon = $button.querySelector('.fa-icon');
|
|
176
|
-
if ($icon) {
|
|
177
|
-
$icon.classList.remove('fa-unlink');
|
|
178
|
-
$icon.classList.add('fa-link');
|
|
179
|
-
}
|
|
194
|
+
// Show connect button, hide disconnect button
|
|
195
|
+
$connectButton.classList.remove('d-none');
|
|
196
|
+
$disconnectButton.classList.add('d-none');
|
|
197
|
+
console.log(`[DEBUG] ${providerId} - Showing connect button`);
|
|
180
198
|
}
|
|
181
199
|
}
|
|
182
200
|
}
|
|
@@ -185,12 +203,13 @@ function updateProviderStatus(providerId, userConnection, providerSettings) {
|
|
|
185
203
|
function getConnectionDisplayName(connection) {
|
|
186
204
|
if (!connection || !connection.identity) return 'Unknown';
|
|
187
205
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
206
|
+
// Try different fields based on provider
|
|
207
|
+
return connection.identity.global_name ||
|
|
208
|
+
connection.identity.username ||
|
|
209
|
+
connection.identity.name ||
|
|
210
|
+
connection.identity.email ||
|
|
211
|
+
connection.identity.id ||
|
|
212
|
+
'Connected';
|
|
194
213
|
}
|
|
195
214
|
|
|
196
215
|
// Initialize FormManager for a provider
|
|
@@ -205,9 +224,12 @@ function initializeProviderForm(providerId) {
|
|
|
205
224
|
|
|
206
225
|
// Skip if already initialized
|
|
207
226
|
if (connectionForms.has(providerId)) {
|
|
227
|
+
console.log(`FormManager already initialized for ${providerId}`);
|
|
208
228
|
return;
|
|
209
229
|
}
|
|
210
230
|
|
|
231
|
+
console.log(`Initializing FormManager for ${providerId}`);
|
|
232
|
+
|
|
211
233
|
// Create new FormManager
|
|
212
234
|
const formManager = new FormManager(`#${formId}`, {
|
|
213
235
|
autoDisable: true,
|
|
@@ -217,14 +239,32 @@ function initializeProviderForm(providerId) {
|
|
|
217
239
|
// Store the FormManager instance
|
|
218
240
|
connectionForms.set(providerId, formManager);
|
|
219
241
|
|
|
242
|
+
// Listen for state changes to update button after FormManager is ready
|
|
243
|
+
formManager.addEventListener('statechange', (event) => {
|
|
244
|
+
const { status } = event.detail;
|
|
245
|
+
console.log(`[DEBUG] ${providerId} - FormManager state changed to:`, status);
|
|
246
|
+
|
|
247
|
+
// When FormManager transitions to ready, update the button status
|
|
248
|
+
if (status === 'ready') {
|
|
249
|
+
console.log(`[DEBUG] ${providerId} - FormManager is ready, updating button status`);
|
|
250
|
+
const userConnection = accountData?.oauth2?.[providerId];
|
|
251
|
+
const providerSettings = appData?.oauth2?.[providerId];
|
|
252
|
+
updateProviderStatus(providerId, userConnection, providerSettings);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
|
|
220
256
|
// Handle form submission
|
|
221
257
|
formManager.addEventListener('submit', async (event) => {
|
|
222
258
|
event.preventDefault();
|
|
223
259
|
|
|
224
|
-
const { data } = event.detail;
|
|
225
|
-
const action = data.action;
|
|
260
|
+
const { data, submitButton } = event.detail;
|
|
226
261
|
const provider = data.provider;
|
|
227
262
|
|
|
263
|
+
// Determine action from the clicked button's data-action attribute
|
|
264
|
+
const action = submitButton?.getAttribute('data-action');
|
|
265
|
+
|
|
266
|
+
console.log(`[DEBUG] ${providerId} - Form submitted. Action:`, action, 'Provider:', provider);
|
|
267
|
+
|
|
228
268
|
try {
|
|
229
269
|
if (action === 'connect') {
|
|
230
270
|
await handleConnect(provider);
|
|
@@ -233,10 +273,13 @@ function initializeProviderForm(providerId) {
|
|
|
233
273
|
if (success) {
|
|
234
274
|
// Reset form state and update UI after successful disconnect
|
|
235
275
|
formManager.setFormState('ready');
|
|
276
|
+
// Get provider settings to pass for description display
|
|
236
277
|
const providerSettings = appData?.oauth2?.[provider];
|
|
237
278
|
updateProviderStatus(provider, null, providerSettings);
|
|
238
279
|
}
|
|
239
280
|
}
|
|
281
|
+
|
|
282
|
+
// Success - FormManager will handle state automatically
|
|
240
283
|
} catch (error) {
|
|
241
284
|
// Show error and reset form state
|
|
242
285
|
formManager.showError(error);
|
|
@@ -252,19 +295,15 @@ async function handleConnect(providerId) {
|
|
|
252
295
|
throw new Error('This connection service is not available.');
|
|
253
296
|
}
|
|
254
297
|
|
|
255
|
-
// Get user token
|
|
256
|
-
const token = await webManager.auth().getIdToken();
|
|
257
|
-
|
|
258
298
|
// Get scope from provider settings (pass as array)
|
|
259
299
|
const scope = provider.scope || [];
|
|
260
300
|
|
|
261
|
-
const response = await
|
|
301
|
+
const response = await authorizedFetch(getApiUrl(), {
|
|
262
302
|
method: 'POST',
|
|
263
303
|
timeout: 30000,
|
|
264
304
|
response: 'json',
|
|
265
305
|
tries: 2,
|
|
266
306
|
body: {
|
|
267
|
-
authenticationToken: token,
|
|
268
307
|
command: 'user:oauth2',
|
|
269
308
|
payload: {
|
|
270
309
|
redirect: false,
|
|
@@ -276,6 +315,8 @@ async function handleConnect(providerId) {
|
|
|
276
315
|
},
|
|
277
316
|
});
|
|
278
317
|
|
|
318
|
+
console.log('OAuth connect response:', response);
|
|
319
|
+
|
|
279
320
|
// For authorize requests, server returns an object with URL to redirect to
|
|
280
321
|
if (response.url) {
|
|
281
322
|
window.location.href = response.url;
|
|
@@ -296,20 +337,16 @@ async function handleDisconnect(providerId) {
|
|
|
296
337
|
throw new Error('Disconnection cancelled');
|
|
297
338
|
}
|
|
298
339
|
|
|
299
|
-
// Get user token
|
|
300
|
-
const token = await webManager.auth().getIdToken();
|
|
301
|
-
|
|
302
340
|
// Get provider settings for scope (pass as array)
|
|
303
341
|
const provider = appData?.oauth2?.[providerId] || {};
|
|
304
342
|
const scope = provider.scope || [];
|
|
305
343
|
|
|
306
|
-
const response = await
|
|
344
|
+
const response = await authorizedFetch(getApiUrl(), {
|
|
307
345
|
method: 'POST',
|
|
308
346
|
timeout: 30000,
|
|
309
347
|
response: 'json',
|
|
310
348
|
tries: 2,
|
|
311
349
|
body: {
|
|
312
|
-
authenticationToken: token,
|
|
313
350
|
command: 'user:oauth2',
|
|
314
351
|
payload: {
|
|
315
352
|
redirect: false,
|
|
@@ -321,12 +358,15 @@ async function handleDisconnect(providerId) {
|
|
|
321
358
|
},
|
|
322
359
|
});
|
|
323
360
|
|
|
361
|
+
console.log('OAuth disconnect response:', response);
|
|
362
|
+
|
|
324
363
|
if (response.success) {
|
|
325
364
|
// Update local account data
|
|
326
365
|
if (accountData.oauth2 && accountData.oauth2[providerId]) {
|
|
327
366
|
delete accountData.oauth2[providerId];
|
|
328
367
|
}
|
|
329
368
|
|
|
369
|
+
// Return success
|
|
330
370
|
return true;
|
|
331
371
|
} else {
|
|
332
372
|
throw new Error(response.message || 'Failed to disconnect');
|
|
@@ -335,6 +375,8 @@ async function handleDisconnect(providerId) {
|
|
|
335
375
|
|
|
336
376
|
// Called when section is shown
|
|
337
377
|
export function onShow() {
|
|
338
|
-
//
|
|
339
|
-
|
|
378
|
+
// Refresh connections display when section is shown
|
|
379
|
+
if (accountData && appData) {
|
|
380
|
+
displayConnections();
|
|
381
|
+
}
|
|
340
382
|
}
|
|
@@ -11,10 +11,10 @@ export function init(wm) {
|
|
|
11
11
|
// Load referrals data
|
|
12
12
|
export function loadData(account) {
|
|
13
13
|
if (!account) return;
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
// Update referral code (real code only)
|
|
16
16
|
updateReferralCode(account.affiliate?.code);
|
|
17
|
-
|
|
17
|
+
|
|
18
18
|
// Update referrals list
|
|
19
19
|
updateReferralsList(account.affiliate?.referrals);
|
|
20
20
|
}
|
|
@@ -22,7 +22,7 @@ export function loadData(account) {
|
|
|
22
22
|
// Update referral code display
|
|
23
23
|
function updateReferralCode(code) {
|
|
24
24
|
const $codeInput = document.getElementById('referral-code-input');
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
if ($codeInput) {
|
|
27
27
|
if (code) {
|
|
28
28
|
const baseUrl = window.location.origin;
|
|
@@ -39,19 +39,19 @@ function updateReferralsList(referrals) {
|
|
|
39
39
|
const $recentReferrals = document.getElementById('recent-referrals');
|
|
40
40
|
const $referralsBadge = document.getElementById('referrals-badge');
|
|
41
41
|
const $referralsList = document.getElementById('referrals-list');
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
// Initialize referrals array
|
|
44
44
|
let referralData = referrals || [];
|
|
45
|
-
|
|
46
|
-
// Add fake data if
|
|
45
|
+
|
|
46
|
+
// Add fake data if _dev_prefill=true is in query string
|
|
47
47
|
const urlParams = new URLSearchParams(window.location.search);
|
|
48
|
-
if (urlParams.get('
|
|
48
|
+
if (urlParams.get('_dev_prefill') === 'true') {
|
|
49
49
|
console.log('Adding fake referral data for testing');
|
|
50
50
|
const fakeReferrals = generateFakeReferrals();
|
|
51
51
|
// Add fake referrals to existing data
|
|
52
52
|
referralData = [...referralData, ...fakeReferrals];
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
// Handle empty state
|
|
56
56
|
if (!referralData || !Array.isArray(referralData) || referralData.length === 0) {
|
|
57
57
|
// No referrals - show empty state
|
|
@@ -67,7 +67,7 @@ function updateReferralsList(referrals) {
|
|
|
67
67
|
}
|
|
68
68
|
return;
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
|
|
71
71
|
// Calculate stats
|
|
72
72
|
const totalCount = referralData.length;
|
|
73
73
|
const now = new Date();
|
|
@@ -76,19 +76,19 @@ function updateReferralsList(referrals) {
|
|
|
76
76
|
const timestamp = ref.timestamp || ref.timestampUNIX * 1000;
|
|
77
77
|
return timestamp >= thisMonth;
|
|
78
78
|
}).length;
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
// Update stats
|
|
81
81
|
if ($totalReferrals) $totalReferrals.textContent = totalCount.toString();
|
|
82
82
|
if ($recentReferrals) $recentReferrals.textContent = recentCount.toString();
|
|
83
83
|
if ($referralsBadge) $referralsBadge.textContent = totalCount.toString();
|
|
84
|
-
|
|
84
|
+
|
|
85
85
|
// Sort referrals by timestamp in reverse order (newest first)
|
|
86
86
|
const sortedReferrals = [...referralData].sort((a, b) => {
|
|
87
87
|
const timeA = a.timestamp || (a.timestampUNIX * 1000) || 0;
|
|
88
88
|
const timeB = b.timestamp || (b.timestampUNIX * 1000) || 0;
|
|
89
89
|
return timeB - timeA; // Reverse order
|
|
90
90
|
});
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
// Generate referral list HTML
|
|
93
93
|
if ($referralsList) {
|
|
94
94
|
if (sortedReferrals.length === 0) {
|
|
@@ -103,7 +103,7 @@ function updateReferralsList(referrals) {
|
|
|
103
103
|
const date = timestamp ? new Date(timestamp) : null;
|
|
104
104
|
const dateStr = date ? formatDate(date) : 'Unknown date';
|
|
105
105
|
const timeStr = date ? formatTime(date) : '';
|
|
106
|
-
|
|
106
|
+
|
|
107
107
|
return `
|
|
108
108
|
<div class="list-group-item px-0">
|
|
109
109
|
<div class="d-flex justify-content-between align-items-center">
|
|
@@ -123,7 +123,7 @@ function updateReferralsList(referrals) {
|
|
|
123
123
|
</div>
|
|
124
124
|
`;
|
|
125
125
|
}).join('');
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
$referralsList.innerHTML = referralHTML;
|
|
128
128
|
}
|
|
129
129
|
}
|
|
@@ -149,45 +149,45 @@ function formatTime(date) {
|
|
|
149
149
|
// Get time since string
|
|
150
150
|
function getTimeSince(timestamp) {
|
|
151
151
|
if (!timestamp) return '<small class="text-muted">Unknown</small>';
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
const now = Date.now();
|
|
154
154
|
const diff = now - timestamp;
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
// Less than 1 minute
|
|
157
157
|
if (diff < 60000) {
|
|
158
158
|
return '<small class="text-success">Just now</small>';
|
|
159
159
|
}
|
|
160
|
-
|
|
160
|
+
|
|
161
161
|
// Less than 1 hour
|
|
162
162
|
if (diff < 3600000) {
|
|
163
163
|
const minutes = Math.floor(diff / 60000);
|
|
164
164
|
return `<small class="text-muted">${minutes} min${minutes > 1 ? 's' : ''} ago</small>`;
|
|
165
165
|
}
|
|
166
|
-
|
|
166
|
+
|
|
167
167
|
// Less than 24 hours
|
|
168
168
|
if (diff < 86400000) {
|
|
169
169
|
const hours = Math.floor(diff / 3600000);
|
|
170
170
|
return `<small class="text-muted">${hours} hour${hours > 1 ? 's' : ''} ago</small>`;
|
|
171
171
|
}
|
|
172
|
-
|
|
172
|
+
|
|
173
173
|
// Less than 7 days
|
|
174
174
|
if (diff < 604800000) {
|
|
175
175
|
const days = Math.floor(diff / 86400000);
|
|
176
176
|
return `<small class="text-muted">${days} day${days > 1 ? 's' : ''} ago</small>`;
|
|
177
177
|
}
|
|
178
|
-
|
|
178
|
+
|
|
179
179
|
// Less than 30 days
|
|
180
180
|
if (diff < 2592000000) {
|
|
181
181
|
const weeks = Math.floor(diff / 604800000);
|
|
182
182
|
return `<small class="text-muted">${weeks} week${weeks > 1 ? 's' : ''} ago</small>`;
|
|
183
183
|
}
|
|
184
|
-
|
|
184
|
+
|
|
185
185
|
// More than 30 days
|
|
186
186
|
const months = Math.floor(diff / 2592000000);
|
|
187
187
|
if (months < 12) {
|
|
188
188
|
return `<small class="text-muted">${months} month${months > 1 ? 's' : ''} ago</small>`;
|
|
189
189
|
}
|
|
190
|
-
|
|
190
|
+
|
|
191
191
|
const years = Math.floor(months / 12);
|
|
192
192
|
return `<small class="text-muted">${years} year${years > 1 ? 's' : ''} ago</small>`;
|
|
193
193
|
}
|
|
@@ -205,31 +205,31 @@ function setupButtons() {
|
|
|
205
205
|
async function handleCopyReferralCode() {
|
|
206
206
|
const $codeInput = document.getElementById('referral-code-input');
|
|
207
207
|
const $copyBtn = document.getElementById('copy-referral-code-btn');
|
|
208
|
-
|
|
208
|
+
|
|
209
209
|
if (!$codeInput || !$codeInput.value || $codeInput.value === 'No referral link available') {
|
|
210
210
|
webManager.utilities().showNotification('No referral link to copy', 'warning');
|
|
211
211
|
return;
|
|
212
212
|
}
|
|
213
|
-
|
|
213
|
+
|
|
214
214
|
try {
|
|
215
215
|
// Copy the full URL directly from the input (it now contains the full URL)
|
|
216
216
|
await webManager.utilities().clipboardCopy($codeInput);
|
|
217
|
-
|
|
217
|
+
|
|
218
218
|
// Update button text temporarily
|
|
219
219
|
const $text = $copyBtn.querySelector('.button-text');
|
|
220
220
|
const originalText = $text.textContent;
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
$text.textContent = 'Copied!';
|
|
223
223
|
$copyBtn.classList.remove('btn-primary');
|
|
224
224
|
$copyBtn.classList.add('btn-success');
|
|
225
|
-
|
|
225
|
+
|
|
226
226
|
// Reset after 2 seconds
|
|
227
227
|
setTimeout(() => {
|
|
228
228
|
$text.textContent = originalText;
|
|
229
229
|
$copyBtn.classList.remove('btn-success');
|
|
230
230
|
$copyBtn.classList.add('btn-primary');
|
|
231
231
|
}, 2000);
|
|
232
|
-
|
|
232
|
+
|
|
233
233
|
} catch (err) {
|
|
234
234
|
console.error('Failed to copy referral link:', err);
|
|
235
235
|
webManager.utilities().showNotification('Failed to copy referral link', 'danger');
|
|
@@ -240,7 +240,7 @@ async function handleCopyReferralCode() {
|
|
|
240
240
|
function generateFakeReferrals() {
|
|
241
241
|
const now = Date.now();
|
|
242
242
|
const oneDay = 24 * 60 * 60 * 1000;
|
|
243
|
-
|
|
243
|
+
|
|
244
244
|
return [
|
|
245
245
|
{
|
|
246
246
|
uid: 'user_k9m2n8p4q1r7',
|