ultimate-jekyll-manager 0.0.272 → 0.0.273

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/README.md CHANGED
@@ -374,7 +374,12 @@ Raw pixel values also accepted: `vert-size="300"` → 300px max-height. Omit `ve
374
374
  #### Testing Parameters
375
375
 
376
376
  ##### Account Page (`/account`)
377
- * `_dev_subscription`: Override subscription data for testing (e.g., `_dev_subscription=premium`)
377
+ * `_dev_subscription`: Override subscription data for testing billing states. The product ID is automatically patched to match a real product from the backend. Available values:
378
+ - `_dev_subscription=active`: Active paid subscription
379
+ - `_dev_subscription=trialing`: Free trial in progress
380
+ - `_dev_subscription=suspended`: Payment failed, access revoked
381
+ - `_dev_subscription=cancellation-requested`: Active but cancellation pending
382
+ - `_dev_subscription=cancelled`: Subscription ended
378
383
  * `_dev_prefill=true`: Adds fake test data for development:
379
384
  - Inserts fake referral data in the Referrals section
380
385
  - Inserts fake session data in the Security section (active sessions)
@@ -113,6 +113,17 @@ export class FormManager {
113
113
  // Initialize file drop zones
114
114
  this._initFileDropZones();
115
115
 
116
+ // Warn about fields missing name attributes (they will be invisible to validation and getData)
117
+ /* @dev-only:start */
118
+ {
119
+ this.$form.querySelectorAll('input, select, textarea').forEach(($field) => {
120
+ if (!$field.name && !$field.matches(HONEYPOT_SELECTOR) && $field.type !== 'hidden') {
121
+ console.warn('[Form-manager] Field missing "name" attribute — will be skipped by validation and getData():', $field);
122
+ }
123
+ });
124
+ }
125
+ /* @dev-only:end */
126
+
116
127
  // Auto-transition to initialState when DOM is ready
117
128
  if (this.config.autoReady) {
118
129
  domReady().then(() => this._setInitialState());
@@ -83,6 +83,10 @@ async function initializeAccount() {
83
83
  webManager.auth().listen({ account: true }, async (state) => {
84
84
  console.log('Auth state with account data:', state);
85
85
 
86
+ // Load user data with the account information
87
+ // Wait for app data to be fetched before loading section data
88
+ await fetchAppData();
89
+
86
90
  /* @dev-only:start */
87
91
  {
88
92
  // Check for test subscription parameter
@@ -94,10 +98,16 @@ async function initializeAccount() {
94
98
  console.log(`Loading test subscription: ${testSubscription}`);
95
99
  const testModule = await import(`./test-subscriptions/${testSubscription}.js`);
96
100
 
97
- // Override the account subscription with test data
101
+ // Merge test fields INTO the real subscription (preserves real product, payment, etc.)
98
102
  if (state.account) {
99
- state.account.subscription = testModule.default;
100
- console.log('Test subscription loaded:', testModule.default);
103
+ const real = state.account.subscription || {};
104
+ const test = testModule.default;
105
+ const merged = deepMerge(real, test);
106
+
107
+ // Write back so both JS and WM bindings see the same data
108
+ state.account.subscription = merged;
109
+
110
+ console.log('Test subscription merged:', merged);
101
111
  }
102
112
  } catch (error) {
103
113
  console.error(`Failed to load test subscription '${testSubscription}':`, error);
@@ -106,10 +116,6 @@ async function initializeAccount() {
106
116
  }
107
117
  /* @dev-only:end */
108
118
 
109
- // Load user data with the account information
110
- // Wait for app data to be fetched before loading section data
111
- await fetchAppData();
112
-
113
119
  loadAllSectionData(state);
114
120
 
115
121
  // Hide loading section and show the appropriate section
@@ -359,6 +365,25 @@ function showSection(sectionId) {
359
365
  }
360
366
  }
361
367
 
368
+ // Deep merge utility (target fields are overwritten by source fields)
369
+ function deepMerge(target, source) {
370
+ const result = { ...target };
371
+
372
+ Object.keys(source).forEach(key => {
373
+ const sourceVal = source[key];
374
+ const targetVal = target[key];
375
+
376
+ if (sourceVal && typeof sourceVal === 'object' && !Array.isArray(sourceVal)
377
+ && targetVal && typeof targetVal === 'object' && !Array.isArray(targetVal)) {
378
+ result[key] = deepMerge(targetVal, sourceVal);
379
+ } else {
380
+ result[key] = sourceVal;
381
+ }
382
+ });
383
+
384
+ return result;
385
+ }
386
+
362
387
  // Tracking functions
363
388
  function trackAccountSectionView(sectionId) {
364
389
  gtag('event', 'account_section_view', {
@@ -58,16 +58,13 @@ function updatePlanCard(account) {
58
58
  const $planStatus = document.getElementById('plan-status');
59
59
  const $planDescription = document.getElementById('plan-description');
60
60
 
61
- // Determine product info
62
- const productId = getProductId(subscription);
63
- const isPaid = productId !== 'basic';
64
- const displayName = getDisplayName(productId, isPaid);
65
-
66
- // Set status badge and description
67
61
  if (!$planStatus || !$planDescription) {
68
62
  return;
69
63
  }
70
64
 
65
+ const productId = getProductId(subscription);
66
+ const isPaid = productId !== 'basic';
67
+ const displayName = getDisplayName(subscription);
71
68
  const status = getEffectiveStatus(subscription, isPaid);
72
69
 
73
70
  switch (status) {
@@ -77,30 +74,18 @@ function updatePlanCard(account) {
77
74
  $planDescription.innerHTML = `You are currently on the <strong>${displayName}</strong> plan. Upgrade to unlock premium features.`;
78
75
  break;
79
76
  }
77
+ case 'trialing':
78
+ case 'cancelling':
80
79
  case 'active': {
81
80
  $planStatus.className = 'badge bg-success';
82
81
  $planStatus.textContent = 'Active';
83
82
  $planDescription.innerHTML = `You are currently on the <strong>${displayName}</strong> plan.`;
84
83
  break;
85
84
  }
86
- case 'trialing': {
87
- const daysLeft = getTrialDaysLeft(subscription);
88
- $planStatus.className = 'badge bg-info';
89
- $planStatus.textContent = daysLeft > 0 ? `Trial (${daysLeft} days left)` : 'Trial';
90
- $planDescription.innerHTML = `You're trialing the <strong>${displayName}</strong> plan.`;
91
- break;
92
- }
93
- case 'cancelling': {
94
- const daysLeft = getCancellationDaysLeft(subscription);
95
- $planStatus.className = 'badge bg-warning text-body';
96
- $planStatus.textContent = daysLeft > 0 ? `Cancelling (${daysLeft} days left)` : 'Cancelling';
97
- $planDescription.innerHTML = `Your <strong>${displayName}</strong> plan is set to cancel. You still have access until the end of your billing period.`;
98
- break;
99
- }
100
- case 'payment_issue': {
85
+ case 'suspended': {
101
86
  $planStatus.className = 'badge bg-danger';
102
- $planStatus.textContent = 'Payment Issue';
103
- $planDescription.innerHTML = `Your <strong>${displayName}</strong> plan has a payment issue. Please update your payment method to avoid losing access.`;
87
+ $planStatus.textContent = 'Suspended';
88
+ $planDescription.innerHTML = `Your <strong>${displayName}</strong> subscription has been suspended and access has been revoked due to a payment issue. Please update your payment method to restore access.`;
104
89
  break;
105
90
  }
106
91
  case 'cancelled': {
@@ -109,12 +94,6 @@ function updatePlanCard(account) {
109
94
  $planDescription.innerHTML = `Your <strong>${displayName}</strong> subscription has ended. Resubscribe to regain access to premium features.`;
110
95
  break;
111
96
  }
112
- case 'expired': {
113
- $planStatus.className = 'badge bg-secondary';
114
- $planStatus.textContent = 'Expired';
115
- $planDescription.innerHTML = `Your <strong>${displayName}</strong> subscription has expired. Subscribe again to regain access.`;
116
- break;
117
- }
118
97
  default: {
119
98
  $planStatus.className = 'badge bg-secondary';
120
99
  $planStatus.textContent = 'Free';
@@ -138,22 +117,14 @@ function updateAlerts(account) {
138
117
  const isPaid = productId !== 'basic';
139
118
  const status = getEffectiveStatus(subscription, isPaid);
140
119
 
141
- // Payment issue alert
142
- if (status === 'payment_issue') {
143
- const message = subscription.paymentIssue?.message || 'Your payment method was declined.';
144
- const attempts = subscription.paymentIssue?.attempts || 0;
145
- const nextRetry = subscription.paymentIssue?.nextRetry;
146
- let retryText = '';
147
- if (nextRetry) {
148
- retryText = ` Next retry: ${new Date(nextRetry).toLocaleDateString()}.`;
149
- }
150
-
120
+ // Suspended (payment issue) alert
121
+ if (status === 'suspended') {
151
122
  $alerts.innerHTML += `
152
123
  <div class="alert alert-danger d-flex align-items-start">
153
124
  <span class="me-2 flex-shrink-0">${getPrerenderedIcon('triangle-exclamation', 'fa-md')}</span>
154
125
  <div>
155
- <strong>Payment failed</strong> ${attempts > 1 ? `(${attempts} attempts)` : ''}
156
- <p class="mb-0 small">${message}${retryText} Please update your payment method to keep your subscription active.</p>
126
+ <strong>Payment failed</strong>
127
+ <p class="mb-0 small">Your payment method was declined. Please update your payment method to keep your subscription active.</p>
157
128
  </div>
158
129
  </div>
159
130
  `;
@@ -161,9 +132,9 @@ function updateAlerts(account) {
161
132
 
162
133
  // Cancellation pending alert
163
134
  if (status === 'cancelling') {
164
- const effectiveDate = subscription.cancellation?.effectiveAt;
165
- const dateStr = effectiveDate
166
- ? new Date(effectiveDate * 1000).toLocaleDateString()
135
+ const cancelTimestamp = subscription.cancellation?.date?.timestampUNIX;
136
+ const dateStr = cancelTimestamp && cancelTimestamp > 0
137
+ ? new Date(cancelTimestamp * 1000).toLocaleDateString()
167
138
  : 'the end of your billing period';
168
139
 
169
140
  $alerts.innerHTML += `
@@ -177,20 +148,22 @@ function updateAlerts(account) {
177
148
  `;
178
149
  }
179
150
 
180
- // Trial ending soon alert (last 3 days)
151
+ // Free trial alert
181
152
  if (status === 'trialing') {
182
- const daysLeft = getTrialDaysLeft(subscription);
183
- if (daysLeft > 0 && daysLeft <= 3) {
184
- $alerts.innerHTML += `
185
- <div class="alert alert-info d-flex align-items-start">
186
- <span class="me-2 flex-shrink-0">${getPrerenderedIcon('clock', 'fa-md')}</span>
187
- <div>
188
- <strong>Trial ending soon</strong>
189
- <p class="mb-0 small">Your free trial ends in ${daysLeft} day${daysLeft === 1 ? '' : 's'}. Upgrade now to keep access to premium features.</p>
190
- </div>
153
+ const trialEndUnix = subscription.trial?.expires?.timestampUNIX;
154
+ const endDate = trialEndUnix && trialEndUnix > 0
155
+ ? new Date(trialEndUnix * 1000).toLocaleDateString()
156
+ : null;
157
+
158
+ $alerts.innerHTML += `
159
+ <div class="alert alert-success d-flex align-items-start">
160
+ <span class="me-2 flex-shrink-0">${getPrerenderedIcon('circle-check', 'fa-md')}</span>
161
+ <div>
162
+ <strong>Free trial</strong>
163
+ <p class="mb-0 small">You're on a free trial${endDate ? ` that ends on <strong>${endDate}</strong>` : ''}. You won't be charged until your trial ends.</p>
191
164
  </div>
192
- `;
193
- }
165
+ </div>
166
+ `;
194
167
  }
195
168
  }
196
169
 
@@ -206,106 +179,65 @@ function updateBillingDetails(account) {
206
179
 
207
180
  const productId = getProductId(subscription);
208
181
  const isPaid = productId !== 'basic';
182
+ const status = getEffectiveStatus(subscription, isPaid);
209
183
 
210
- // Only show billing details for paid subscriptions with billing info
211
- if (!isPaid || !subscription.billing || subscription.paymentIssue?.hasIssue) {
184
+ // Only show billing details for paid, non-suspended, non-cancelled subscriptions
185
+ if (!isPaid || status === 'suspended' || status === 'cancelled') {
212
186
  $details.classList.add('d-none');
213
187
  return;
214
188
  }
215
189
 
216
- const nextBilling = subscription.billing.nextBillingDate;
217
- const amount = subscription.billing.amount;
218
- const currency = subscription.billing.currency || 'usd';
219
- const frequency = subscription.frequency || (subscription.billing.interval === 1 ? 'monthly' : 'annually');
190
+ const nextBillingUnix = subscription.expires?.timestampUNIX;
191
+ const amount = subscription.payment?.price;
192
+ const currency = appData?.payment?.currency || 'USD';
193
+ const frequency = subscription.payment?.frequency;
220
194
 
221
- if (!nextBilling || !amount) {
195
+ if (!nextBillingUnix || nextBillingUnix <= 0 || !amount) {
222
196
  $details.classList.add('d-none');
223
197
  return;
224
198
  }
225
199
 
226
- const nextDate = new Date(nextBilling * 1000).toLocaleDateString();
200
+ const nextDate = new Date(nextBillingUnix * 1000).toLocaleDateString();
227
201
  const formattedAmount = formatCurrency(amount, currency);
228
202
  const frequencyLabel = frequency === 'annually' || frequency === 'yearly' ? 'year' : 'month';
229
203
 
230
- let html = '';
231
-
232
- if (subscription.cancellation?.requested) {
233
- // Cancellation pending — don't show "next billing"
234
- html = '';
235
- } else {
236
- html = `
237
- <div class="row small text-muted">
238
- <div class="col-sm-6 mb-1">
239
- <strong>Next billing:</strong> ${nextDate}
240
- </div>
241
- <div class="col-sm-6 mb-1">
242
- <strong>Amount:</strong> ${formattedAmount} / ${frequencyLabel}
243
- </div>
204
+ $details.innerHTML = `
205
+ <div class="row small text-muted">
206
+ <div class="col-sm-6 mb-1">
207
+ <strong>Next billing:</strong> ${nextDate}
244
208
  </div>
245
- `;
246
- }
247
-
248
- if (html) {
249
- $details.innerHTML = html;
250
- $details.classList.remove('d-none');
251
- } else {
252
- $details.classList.add('d-none');
253
- }
209
+ <div class="col-sm-6 mb-1">
210
+ <strong>Amount:</strong> ${formattedAmount} / ${frequencyLabel}
211
+ </div>
212
+ </div>
213
+ `;
214
+ $details.classList.remove('d-none');
254
215
  }
255
216
 
256
217
  // ─── Action Buttons ──────────────────────────────────────────
257
218
 
258
219
  function updateActionButtons(account) {
220
+ // Bindings handle the primary show/hide based on product.id (basic vs paid).
221
+ // JS only needs to refine for cancelled/suspended edge cases.
259
222
  const subscription = account.subscription || {};
260
223
  const productId = getProductId(subscription);
261
224
  const isPaid = productId !== 'basic';
262
225
  const status = getEffectiveStatus(subscription, isPaid);
263
226
 
264
- // Hide all action buttons first
265
- document.querySelectorAll('.plan-action-btn').forEach(btn => btn.classList.add('d-none'));
266
-
267
227
  const $upgradeBtn = document.getElementById('upgrade-plan-btn');
268
228
  const $changeBtn = document.getElementById('change-plan-btn');
269
229
  const $manageBtn = document.getElementById('manage-billing-btn');
270
230
  const $cancelTrigger = document.getElementById('cancel-subscription-trigger');
271
231
 
272
- switch (status) {
273
- case 'free':
274
- if ($upgradeBtn) $upgradeBtn.classList.remove('d-none');
275
- if ($cancelTrigger) $cancelTrigger.classList.add('d-none');
276
- break;
277
-
278
- case 'active':
279
- if ($changeBtn) $changeBtn.classList.remove('d-none');
280
- if ($manageBtn) $manageBtn.classList.remove('d-none');
281
- if ($cancelTrigger) $cancelTrigger.classList.remove('d-none');
282
- break;
283
-
284
- case 'trialing':
285
- if ($upgradeBtn) $upgradeBtn.classList.remove('d-none');
286
- if ($cancelTrigger) $cancelTrigger.classList.remove('d-none');
287
- break;
288
-
289
- case 'cancelling':
290
- if ($manageBtn) $manageBtn.classList.remove('d-none');
291
- if ($cancelTrigger) $cancelTrigger.classList.add('d-none');
292
- break;
293
-
294
- case 'payment_issue':
295
- if ($manageBtn) $manageBtn.classList.remove('d-none');
296
- if ($cancelTrigger) $cancelTrigger.classList.remove('d-none');
297
- break;
298
-
299
- case 'cancelled':
300
- case 'expired':
301
- if ($upgradeBtn) $upgradeBtn.classList.remove('d-none');
302
- if ($cancelTrigger) $cancelTrigger.classList.add('d-none');
303
- break;
304
-
305
- default:
306
- if ($upgradeBtn) $upgradeBtn.classList.remove('d-none');
307
- if ($cancelTrigger) $cancelTrigger.classList.add('d-none');
308
- break;
232
+ if (status === 'cancelled') {
233
+ // Cancelled: show upgrade, hide change/manage/cancel
234
+ if ($upgradeBtn) $upgradeBtn.removeAttribute('hidden');
235
+ if ($changeBtn) $changeBtn.setAttribute('hidden', '');
236
+ if ($manageBtn) $manageBtn.setAttribute('hidden', '');
237
+ if ($cancelTrigger) $cancelTrigger.setAttribute('hidden', '');
238
+ } else if (status === 'suspended') {
239
+ // Suspended: hide change, keep manage + cancel visible (bindings handle)
240
+ if ($changeBtn) $changeBtn.setAttribute('hidden', '');
309
241
  }
310
242
  }
311
243
 
@@ -375,10 +307,7 @@ async function openStripePortal() {
375
307
 
376
308
  function setupCancellationForm() {
377
309
  const $form = document.getElementById('cancel-subscription-form');
378
- const $checkbox = document.getElementById('cancel-confirm-checkbox');
379
- const $submitBtn = document.getElementById('cancel-subscription-btn');
380
-
381
- if (!$form || !$checkbox || !$submitBtn) {
310
+ if (!$form) {
382
311
  return;
383
312
  }
384
313
 
@@ -392,16 +321,7 @@ function setupCancellationForm() {
392
321
  submittedText: 'Subscription Cancelled',
393
322
  });
394
323
 
395
- // Enable/disable submit based on checkbox
396
- $checkbox.addEventListener('change', () => {
397
- $submitBtn.disabled = !$checkbox.checked;
398
- });
399
-
400
324
  cancelFormManager.on('submit', async ({ data }) => {
401
- if (!$checkbox.checked) {
402
- throw new Error('Please confirm the cancellation terms before proceeding.');
403
- }
404
-
405
325
  // Get selected reason
406
326
  const $selectedReason = document.querySelector('input[name="cancel_reason"]:checked');
407
327
  const reason = $selectedReason?.value || '';
@@ -434,13 +354,15 @@ function setupCancellationForm() {
434
354
  }
435
355
  }, 3000);
436
356
 
437
- // Update the UI to reflect cancellation
357
+ // Update the UI to reflect cancellation (using backend structure)
438
358
  if (currentAccount?.subscription) {
359
+ const expiresUnix = currentAccount.subscription.expires?.timestampUNIX || 0;
439
360
  currentAccount.subscription.cancellation = {
440
- requested: true,
441
- requestedAt: Date.now(),
442
- effectiveAt: currentAccount.subscription.billing?.currentPeriodEnd || null,
443
- reason: reason,
361
+ pending: true,
362
+ date: {
363
+ timestamp: new Date(expiresUnix * 1000).toISOString(),
364
+ timestampUNIX: expiresUnix,
365
+ },
444
366
  };
445
367
  updatePlanCard(currentAccount);
446
368
  updateAlerts(currentAccount);
@@ -476,9 +398,14 @@ function updateUsageInfo(account) {
476
398
  return;
477
399
  }
478
400
 
479
- // Get the user's current plan/product
401
+ // Determine effective product for usage limits
402
+ // If subscription isn't actively paid, use basic plan limits
480
403
  const productId = getProductId(subscription);
481
- const product = appData?.payment?.products?.find(p => p.id === productId);
404
+ const isPaid = productId !== 'basic';
405
+ const status = getEffectiveStatus(subscription, isPaid);
406
+ const hasActiveAccess = status === 'active' || status === 'trialing' || status === 'cancelling';
407
+ const effectiveProductId = (isPaid && hasActiveAccess) ? productId : 'basic';
408
+ const product = appData?.payment?.products?.find(p => p.id === effectiveProductId);
482
409
  const limits = product?.limits || {};
483
410
 
484
411
  // Clear container
@@ -538,13 +465,19 @@ function updateUsageInfo(account) {
538
465
  // ─── Helpers ─────────────────────────────────────────────────
539
466
 
540
467
  function getProductId(subscription) {
541
- return subscription.product?.id || subscription.product || 'basic';
468
+ return subscription.product?.id || 'basic';
542
469
  }
543
470
 
544
- function getDisplayName(productId, isPaid) {
471
+ function getDisplayName(subscription) {
472
+ // Use backend-provided product name first
473
+ if (subscription.product?.name && subscription.product.name !== 'Basic') {
474
+ return subscription.product.name;
475
+ }
476
+
477
+ // Fall back to appData product name
478
+ const productId = subscription.product?.id || 'basic';
545
479
  const product = appData?.payment?.products?.find(p => p.id === productId);
546
- return product?.name
547
- || (isPaid ? productId.charAt(0).toUpperCase() + productId.slice(1) : 'Free');
480
+ return product?.name || 'Free';
548
481
  }
549
482
 
550
483
  function getEffectiveStatus(subscription, isPaid) {
@@ -552,55 +485,35 @@ function getEffectiveStatus(subscription, isPaid) {
552
485
  return 'free';
553
486
  }
554
487
 
555
- if (subscription.status === 'suspended' || subscription.paymentIssue?.hasIssue) {
556
- return 'payment_issue';
488
+ if (subscription.status === 'suspended') {
489
+ return 'suspended';
557
490
  }
558
491
 
559
- if (subscription.cancellation?.requested && subscription.status === 'active') {
492
+ if (subscription.cancellation?.pending && subscription.status === 'active') {
560
493
  return 'cancelling';
561
494
  }
562
495
 
563
- if (subscription.status === 'active' || subscription.access === true) {
564
- return 'active';
496
+ if (subscription.status === 'active' && subscription.trial?.claimed
497
+ && subscription.trial?.expires?.timestampUNIX > Math.floor(Date.now() / 1000)) {
498
+ return 'trialing';
565
499
  }
566
500
 
567
- if (subscription.status === 'trialing') {
568
- return 'trialing';
501
+ if (subscription.status === 'active') {
502
+ return 'active';
569
503
  }
570
504
 
571
505
  if (subscription.status === 'cancelled') {
572
506
  return 'cancelled';
573
507
  }
574
508
 
575
- if (subscription.status === 'expired') {
576
- return 'expired';
577
- }
578
-
579
509
  return 'free';
580
510
  }
581
511
 
582
- function getTrialDaysLeft(subscription) {
583
- const trialEnd = subscription.trial?.endedAt || subscription.trial?.expires?.timestamp;
584
- if (!trialEnd) {
585
- return 0;
586
- }
587
- return Math.max(0, Math.ceil((new Date(trialEnd) - new Date()) / (1000 * 60 * 60 * 24)));
588
- }
589
-
590
- function getCancellationDaysLeft(subscription) {
591
- const effectiveAt = subscription.cancellation?.effectiveAt;
592
- if (!effectiveAt) {
593
- return 0;
594
- }
595
- // effectiveAt is in Unix seconds
596
- return Math.max(0, Math.ceil((effectiveAt * 1000 - Date.now()) / (1000 * 60 * 60 * 24)));
597
- }
598
-
599
- function formatCurrency(amountInCents, currency) {
512
+ function formatCurrency(amount, currency) {
600
513
  return new Intl.NumberFormat('en-US', {
601
514
  style: 'currency',
602
- currency: currency.toUpperCase(),
603
- }).format(amountInCents / 100);
515
+ currency: (currency || 'USD').toUpperCase(),
516
+ }).format(amount); // amount is already in display dollars
604
517
  }
605
518
 
606
519
  function formatMetricName(metricId) {
@@ -22,11 +22,7 @@ export async function init(wm) {
22
22
  // Setup data request form
23
23
  function setupDataRequestForm() {
24
24
  const $form = document.getElementById('data-request-form');
25
- const $checkbox1 = document.getElementById('data-request-confirm-checkbox');
26
- const $checkbox2 = document.getElementById('data-request-deletion-checkbox');
27
- const $submitBtn = document.getElementById('data-request-submit-btn');
28
-
29
- if (!$form || !$checkbox1 || !$checkbox2 || !$submitBtn) {
25
+ if (!$form) {
30
26
  return;
31
27
  }
32
28
 
@@ -37,19 +33,7 @@ function setupDataRequestForm() {
37
33
  submittedText: 'Request Submitted',
38
34
  });
39
35
 
40
- // Enable/disable submit button based on both checkboxes
41
- function updateSubmitState() {
42
- $submitBtn.disabled = !($checkbox1.checked && $checkbox2.checked);
43
- }
44
-
45
- $checkbox1.addEventListener('change', updateSubmitState);
46
- $checkbox2.addEventListener('change', updateSubmitState);
47
-
48
36
  formManager.on('submit', async ({ data }) => {
49
- if (!$checkbox1.checked || !$checkbox2.checked) {
50
- throw new Error('Please confirm all acknowledgments before submitting.');
51
- }
52
-
53
37
  trackDataRequest('submit');
54
38
 
55
39
  const response = await authorizedFetch(`${webManager.getApiUrl()}/backend-manager/user/data-request`, {
@@ -18,11 +18,7 @@ export async function init(wm) {
18
18
  // Setup delete account form
19
19
  function setupDeleteAccountForm() {
20
20
  const $form = document.getElementById('delete-account-form');
21
- const $checkbox1 = document.getElementById('delete-confirm-checkbox');
22
- const $checkbox2 = document.getElementById('delete-data-request-checkbox');
23
- const $deleteBtn = document.getElementById('delete-account-btn');
24
-
25
- if (!$form || !$checkbox1 || !$checkbox2 || !$deleteBtn) {
21
+ if (!$form) {
26
22
  return;
27
23
  }
28
24
 
@@ -33,20 +29,7 @@ function setupDeleteAccountForm() {
33
29
  submittedText: 'Account Deleted!',
34
30
  });
35
31
 
36
- // Enable/disable delete button based on both checkboxes
37
- function updateDeleteState() {
38
- $deleteBtn.disabled = !($checkbox1.checked && $checkbox2.checked);
39
- }
40
-
41
- $checkbox1.addEventListener('change', updateDeleteState);
42
- $checkbox2.addEventListener('change', updateDeleteState);
43
-
44
32
  formManager.on('submit', async ({ data }) => {
45
- // Check if both checkboxes are checked
46
- if (!$checkbox1.checked || !$checkbox2.checked) {
47
- throw new Error('Please confirm all acknowledgments before proceeding.');
48
- }
49
-
50
33
  // 1ms wait for dialog to appear properly
51
34
  await new Promise(resolve => setTimeout(resolve, 1));
52
35
 
@@ -228,11 +228,9 @@ function updateRoleBadges(account) {
228
228
  // Show premium badge if subscription is active AND on a paid plan
229
229
  const $premiumBadge = document.getElementById('badge-premium');
230
230
  if ($premiumBadge) {
231
- const productId = subscription?.product?.id || subscription?.product || 'basic';
231
+ const productId = subscription?.product?.id || 'basic';
232
232
  const isPaid = productId !== 'basic';
233
- const isActive = subscription?.status === 'active'
234
- || subscription?.status === 'trialing'
235
- || subscription?.access === true;
233
+ const isActive = subscription?.status === 'active';
236
234
 
237
235
  if (isActive && isPaid) {
238
236
  $premiumBadge.classList.remove('d-none');