ultimate-jekyll-manager 0.0.278 → 0.0.280

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.
@@ -74,6 +74,10 @@
74
74
  user-select: none;
75
75
  }
76
76
 
77
+ .progress {
78
+ background-color: var(--bs-tertiary-bg);
79
+ }
80
+
77
81
  .cancel-trigger-link {
78
82
  font-size: 0.8125rem;
79
83
  opacity: 0.7;
@@ -5,7 +5,6 @@
5
5
  // Libraries
6
6
  import { FormManager } from '__main_assets__/js/libs/form-manager.js';
7
7
  import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
8
- import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
9
8
 
10
9
  let webManager = null;
11
10
  let appData = null;
@@ -23,6 +22,18 @@ const CANCEL_REASONS = [
23
22
  'Other',
24
23
  ];
25
24
 
25
+ // Status display configuration
26
+ const STATUS_CONFIG = {
27
+ free: { label: 'Free', badgeClass: 'badge bg-secondary' },
28
+ active: { label: 'Active', badgeClass: 'badge bg-success' },
29
+ trialing: { label: 'Active', badgeClass: 'badge bg-success' },
30
+ cancelling: { label: 'Active', badgeClass: 'badge bg-success' },
31
+ suspended: { label: 'Suspended', badgeClass: 'badge bg-danger' },
32
+ cancelled: { label: 'Cancelled', badgeClass: 'badge bg-secondary' },
33
+ };
34
+
35
+ const FREQUENCY_LABELS = { daily: 'day', weekly: 'week', monthly: 'month', annually: 'year' };
36
+
26
37
  // Initialize billing section
27
38
  export async function init(wm) {
28
39
  webManager = wm;
@@ -39,11 +50,7 @@ export async function loadData(account, sharedAppData) {
39
50
  appData = sharedAppData;
40
51
  currentAccount = account;
41
52
 
42
- updatePlanCard(account);
43
- updateAlerts(account);
44
- updateBillingDetails(account);
45
- updateActionButtons(account);
46
- updateUsageInfo(account);
53
+ updateUI(account);
47
54
  }
48
55
 
49
56
  // Called when section is shown
@@ -51,197 +58,89 @@ export function onShow() {
51
58
  // Nothing needed
52
59
  }
53
60
 
54
- // ─── Plan Card ───────────────────────────────────────────────
55
-
56
- function updatePlanCard(account) {
57
- const subscription = account.subscription || {};
58
- const $planStatus = document.getElementById('plan-status');
59
- const $planDescription = document.getElementById('plan-description');
60
-
61
- if (!$planStatus || !$planDescription) {
62
- return;
63
- }
64
-
65
- const productId = getProductId(subscription);
66
- const isPaid = productId !== 'basic';
67
- const displayName = getDisplayName(subscription);
68
- const status = getEffectiveStatus(subscription, isPaid);
61
+ // ─── UI Update ──────────────────────────────────────────────
69
62
 
70
- switch (status) {
71
- case 'free': {
72
- $planStatus.className = 'badge bg-secondary';
73
- $planStatus.textContent = 'Free';
74
- $planDescription.innerHTML = `You are currently on the <strong>${displayName}</strong> plan. Upgrade to unlock premium features.`;
75
- break;
76
- }
77
- case 'trialing':
78
- case 'cancelling':
79
- case 'active': {
80
- $planStatus.className = 'badge bg-success';
81
- $planStatus.textContent = 'Active';
82
- $planDescription.innerHTML = `You are currently on the <strong>${displayName}</strong> plan.`;
83
- break;
84
- }
85
- case 'suspended': {
86
- $planStatus.className = 'badge bg-danger';
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.`;
89
- break;
90
- }
91
- case 'cancelled': {
92
- $planStatus.className = 'badge bg-secondary';
93
- $planStatus.textContent = 'Cancelled';
94
- $planDescription.innerHTML = `Your <strong>${displayName}</strong> subscription has ended. Resubscribe to regain access to premium features.`;
95
- break;
96
- }
97
- default: {
98
- $planStatus.className = 'badge bg-secondary';
99
- $planStatus.textContent = 'Free';
100
- $planDescription.innerHTML = `You are currently on the <strong>Free</strong> plan.`;
101
- break;
102
- }
103
- }
63
+ /* @dev-only:start */
64
+ {
65
+ window._billing = {
66
+ test: (account) => updateUI(account),
67
+ state: () => buildBillingState(currentAccount),
68
+ restore: () => { if (currentAccount) updateUI(currentAccount); },
69
+ };
104
70
  }
71
+ /* @dev-only:end */
105
72
 
106
- // ─── Alerts ──────────────────────────────────────────────────
107
-
108
- function updateAlerts(account) {
109
- const $alerts = document.getElementById('billing-alerts');
110
- if (!$alerts) {
111
- return;
112
- }
113
-
114
- $alerts.innerHTML = '';
115
- const subscription = account.subscription || {};
116
- const productId = getProductId(subscription);
117
- const isPaid = productId !== 'basic';
118
- const status = getEffectiveStatus(subscription, isPaid);
119
-
120
- // Suspended (payment issue) alert
121
- if (status === 'suspended') {
122
- $alerts.innerHTML += `
123
- <div class="alert alert-danger d-flex align-items-start">
124
- <span class="me-2 flex-shrink-0">${getPrerenderedIcon('triangle-exclamation', 'fa-md')}</span>
125
- <div>
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>
128
- </div>
129
- </div>
130
- `;
131
- }
132
-
133
- // Cancellation pending alert
134
- if (status === 'cancelling') {
135
- const cancelTimestamp = subscription.cancellation?.date?.timestampUNIX;
136
- const dateStr = cancelTimestamp && cancelTimestamp > 0
137
- ? new Date(cancelTimestamp * 1000).toLocaleDateString()
138
- : 'the end of your billing period';
139
-
140
- $alerts.innerHTML += `
141
- <div class="alert alert-warning d-flex align-items-start">
142
- <span class="me-2 flex-shrink-0">${getPrerenderedIcon('clock', 'fa-md')}</span>
143
- <div>
144
- <strong>Cancellation scheduled</strong>
145
- <p class="mb-0 small">Your subscription will end on <strong>${dateStr}</strong>. You'll continue to have full access until then. If you change your mind, you can reactivate through billing management.</p>
146
- </div>
147
- </div>
148
- `;
149
- }
150
-
151
- // Free trial alert
152
- if (status === 'trialing') {
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>
164
- </div>
165
- </div>
166
- `;
167
- }
73
+ function updateUI(account) {
74
+ webManager.bindings().update(buildBillingState(account));
75
+ updateUsageInfo(account);
168
76
  }
169
77
 
170
- // ─── Billing Details ─────────────────────────────────────────
171
-
172
- function updateBillingDetails(account) {
173
- const subscription = account.subscription || {};
174
- const $details = document.getElementById('billing-details');
175
-
176
- if (!$details) {
177
- return;
178
- }
179
-
78
+ function buildBillingState(account) {
79
+ const subscription = account?.subscription || {};
180
80
  const productId = getProductId(subscription);
181
81
  const isPaid = productId !== 'basic';
182
82
  const status = getEffectiveStatus(subscription, isPaid);
83
+ const displayName = getDisplayName(subscription);
84
+ const config = STATUS_CONFIG[status] || STATUS_CONFIG.free;
183
85
 
184
- // Only show billing details for paid, non-suspended, non-cancelled subscriptions
185
- if (!isPaid || status === 'suspended' || status === 'cancelled') {
186
- $details.classList.add('d-none');
187
- return;
188
- }
86
+ // Pre-format alert dates
87
+ const cancelTimestamp = subscription.cancellation?.date?.timestampUNIX;
88
+ const cancelDate = (cancelTimestamp && cancelTimestamp > 0)
89
+ ? new Date(cancelTimestamp * 1000).toLocaleDateString()
90
+ : 'the end of your billing period';
91
+
92
+ const trialEndUnix = subscription.trial?.expires?.timestampUNIX;
93
+ const trialEndDate = (trialEndUnix && trialEndUnix > 0)
94
+ ? new Date(trialEndUnix * 1000).toLocaleDateString()
95
+ : null;
189
96
 
97
+ // Pre-format billing details
190
98
  const nextBillingUnix = subscription.expires?.timestampUNIX;
191
99
  const amount = subscription.payment?.price;
192
100
  const currency = appData?.payment?.currency || 'USD';
193
101
  const frequency = subscription.payment?.frequency;
102
+ const hasValidBilling = nextBillingUnix && nextBillingUnix > 0 && amount;
194
103
 
195
- if (!nextBillingUnix || nextBillingUnix <= 0 || !amount) {
196
- $details.classList.add('d-none');
197
- return;
198
- }
199
-
200
- const nextDate = new Date(nextBillingUnix * 1000).toLocaleDateString();
201
- const formattedAmount = formatCurrency(amount, currency);
202
- const FREQUENCY_LABELS = { daily: 'day', weekly: 'week', monthly: 'month', annually: 'year' };
203
- const frequencyLabel = FREQUENCY_LABELS[frequency] || 'month';
204
-
205
- $details.innerHTML = `
206
- <div class="row small text-muted">
207
- <div class="col-sm-6 mb-1">
208
- <strong>Next billing:</strong> ${nextDate}
209
- </div>
210
- <div class="col-sm-6 mb-1">
211
- <strong>Amount:</strong> ${formattedAmount} / ${frequencyLabel}
212
- </div>
213
- </div>
214
- `;
215
- $details.classList.remove('d-none');
104
+ return {
105
+ billing: {
106
+ plan: {
107
+ name: displayName,
108
+ },
109
+ status: {
110
+ label: config.label,
111
+ badgeClass: config.badgeClass,
112
+ },
113
+ description: {
114
+ free: status === 'free',
115
+ active: status === 'active' || status === 'trialing' || status === 'cancelling',
116
+ suspended: status === 'suspended',
117
+ cancelled: status === 'cancelled',
118
+ },
119
+ alerts: {
120
+ suspended: status === 'suspended',
121
+ cancelling: status === 'cancelling',
122
+ trialing: status === 'trialing',
123
+ cancelDate: cancelDate,
124
+ trialEndDate: trialEndDate || '',
125
+ trialHasEndDate: !!trialEndDate,
126
+ },
127
+ details: {
128
+ visible: isPaid && status !== 'suspended' && status !== 'cancelled' && !!hasValidBilling,
129
+ nextDate: hasValidBilling ? new Date(nextBillingUnix * 1000).toLocaleDateString() : '',
130
+ amount: hasValidBilling ? `${formatCurrency(amount, currency)} / ${FREQUENCY_LABELS[frequency] || 'month'}` : '',
131
+ },
132
+ buttons: {
133
+ upgrade: !isPaid || status === 'cancelled',
134
+ change: isPaid && status !== 'cancelled' && status !== 'suspended',
135
+ manage: isPaid && status !== 'cancelled',
136
+ cancel: isPaid && status !== 'cancelled' && status !== 'suspended',
137
+ },
138
+ },
139
+ };
216
140
  }
217
141
 
218
142
  // ─── Action Buttons ──────────────────────────────────────────
219
143
 
220
- function updateActionButtons(account) {
221
- // Bindings handle the primary show/hide based on product.id (basic vs paid).
222
- // JS only needs to refine for cancelled/suspended edge cases.
223
- const subscription = account.subscription || {};
224
- const productId = getProductId(subscription);
225
- const isPaid = productId !== 'basic';
226
- const status = getEffectiveStatus(subscription, isPaid);
227
-
228
- const $upgradeBtn = document.getElementById('upgrade-plan-btn');
229
- const $changeBtn = document.getElementById('change-plan-btn');
230
- const $manageBtn = document.getElementById('manage-billing-btn');
231
- const $cancelTrigger = document.getElementById('cancel-subscription-trigger');
232
-
233
- if (status === 'cancelled') {
234
- // Cancelled: show upgrade, hide change/manage/cancel
235
- if ($upgradeBtn) $upgradeBtn.removeAttribute('hidden');
236
- if ($changeBtn) $changeBtn.setAttribute('hidden', '');
237
- if ($manageBtn) $manageBtn.setAttribute('hidden', '');
238
- if ($cancelTrigger) $cancelTrigger.setAttribute('hidden', '');
239
- } else if (status === 'suspended') {
240
- // Suspended: hide change, keep manage + cancel visible (bindings handle)
241
- if ($changeBtn) $changeBtn.setAttribute('hidden', '');
242
- }
243
- }
244
-
245
144
  function setupActionButtons() {
246
145
  const $upgradeBtn = document.getElementById('upgrade-plan-btn');
247
146
  const $changeBtn = document.getElementById('change-plan-btn');
@@ -327,6 +226,16 @@ function setupCancellationForm() {
327
226
  const $selectedReason = document.querySelector('input[name="cancel_reason"]:checked');
328
227
  const reason = $selectedReason?.value || '';
329
228
 
229
+ // Capture status BEFORE the API call — the auth listener may update currentAccount
230
+ // with Firestore data (cancellation.pending=true) before we reach the post-cancel code
231
+ const sub = currentAccount?.subscription;
232
+ const productId = getProductId(sub || {});
233
+ const isPaid = productId !== 'basic';
234
+ const statusBeforeCancel = getEffectiveStatus(sub || {}, isPaid);
235
+ const isTrialCancel = statusBeforeCancel === 'trialing';
236
+
237
+ console.log('[Billing] Cancelling:', { statusBeforeCancel, isTrialCancel, productId });
238
+
330
239
  trackBilling('cancel_submit');
331
240
 
332
241
  const response = await authorizedFetch(`${webManager.getApiUrl()}/backend-manager/payments/cancel`, {
@@ -344,7 +253,13 @@ function setupCancellationForm() {
344
253
  throw new Error(response.message || 'Failed to cancel subscription. Please try again.');
345
254
  }
346
255
 
347
- cancelFormManager.showSuccess('Your subscription has been cancelled. You\'ll continue to have access until the end of your current billing period.');
256
+ console.log('[Billing] Cancel complete:', { isTrialCancel, productId });
257
+
258
+ if (isTrialCancel) {
259
+ cancelFormManager.showSuccess('Your trial has been cancelled. You\'ve been moved to the free plan. You can subscribe again anytime.');
260
+ } else {
261
+ cancelFormManager.showSuccess('Your subscription has been cancelled. You\'ll continue to have access until the end of your current billing period.');
262
+ }
348
263
 
349
264
  // Collapse the cancel form after a short delay
350
265
  setTimeout(() => {
@@ -353,22 +268,38 @@ function setupCancellationForm() {
353
268
  const bsCollapse = bootstrap.Collapse.getInstance($accordion);
354
269
  if (bsCollapse) bsCollapse.hide();
355
270
  }
356
- }, 3000);
357
-
358
- // Update the UI to reflect cancellation (using backend structure)
359
- if (currentAccount?.subscription) {
360
- const expiresUnix = currentAccount.subscription.expires?.timestampUNIX || 0;
361
- currentAccount.subscription.cancellation = {
362
- pending: true,
363
- date: {
364
- timestamp: new Date(expiresUnix * 1000).toISOString(),
365
- timestampUNIX: expiresUnix,
366
- },
367
- };
368
- updatePlanCard(currentAccount);
369
- updateAlerts(currentAccount);
370
- updateBillingDetails(currentAccount);
371
- updateActionButtons(currentAccount);
271
+ }, 1000);
272
+
273
+ // Update the UI to reflect cancellation
274
+ // Re-read currentAccount.subscription since the auth listener may have replaced it
275
+ const currentSub = currentAccount?.subscription;
276
+ if (currentSub) {
277
+ if (isTrialCancel) {
278
+ // Trial cancellations are immediate — downgrade to basic
279
+ currentSub.status = 'cancelled';
280
+ currentSub.product = { id: 'basic', name: 'Basic' };
281
+ currentSub.cancellation = {
282
+ pending: false,
283
+ date: {
284
+ timestamp: new Date().toISOString(),
285
+ timestampUNIX: Math.floor(Date.now() / 1000),
286
+ },
287
+ };
288
+ } else {
289
+ // Non-trial cancellations are pending until end of billing period
290
+ const expiresUnix = currentSub.expires?.timestampUNIX || 0;
291
+ currentSub.cancellation = {
292
+ pending: true,
293
+ date: {
294
+ timestamp: new Date(expiresUnix * 1000).toISOString(),
295
+ timestampUNIX: expiresUnix,
296
+ },
297
+ };
298
+ }
299
+
300
+ console.log('[Billing] UI update after cancel:', { status: currentSub.status, productId: currentSub.product?.id, cancellationPending: currentSub.cancellation?.pending });
301
+
302
+ updateUI(currentAccount);
372
303
  }
373
304
  });
374
305
  }
@@ -483,6 +414,9 @@ function getDisplayName(subscription) {
483
414
  return product?.name || 'Free';
484
415
  }
485
416
 
417
+ // Derives a UI-friendly status from the backend subscription object
418
+ // Backend only has 3 statuses: 'active', 'suspended', 'cancelled'
419
+ // This function adds 'free', 'trialing', and 'cancelling' for UI purposes
486
420
  function getEffectiveStatus(subscription, isPaid) {
487
421
  if (!isPaid) {
488
422
  return 'free';
@@ -492,21 +426,24 @@ function getEffectiveStatus(subscription, isPaid) {
492
426
  return 'suspended';
493
427
  }
494
428
 
495
- if (subscription.cancellation?.pending && subscription.status === 'active') {
496
- return 'cancelling';
497
- }
498
-
499
- if (subscription.status === 'active' && subscription.trial?.claimed
500
- && subscription.trial?.expires?.timestampUNIX > Math.floor(Date.now() / 1000)) {
501
- return 'trialing';
429
+ if (subscription.status === 'cancelled') {
430
+ return 'cancelled';
502
431
  }
503
432
 
433
+ // For active subscriptions, check trial and cancellation state
504
434
  if (subscription.status === 'active') {
505
- return 'active';
506
- }
435
+ // Trial check: claimed and not yet expired
436
+ if (subscription.trial?.claimed
437
+ && subscription.trial?.expires?.timestampUNIX > Math.floor(Date.now() / 1000)) {
438
+ return 'trialing';
439
+ }
507
440
 
508
- if (subscription.status === 'cancelled') {
509
- return 'cancelled';
441
+ // Pending cancellation check
442
+ if (subscription.cancellation?.pending) {
443
+ return 'cancelling';
444
+ }
445
+
446
+ return 'active';
510
447
  }
511
448
 
512
449
  return 'free';
@@ -970,30 +970,78 @@ badges:
970
970
  <div class="d-flex justify-content-between align-items-start mb-2">
971
971
  <div>
972
972
  <h5 class="card-title mb-1 d-flex align-items-center flex-wrap gap-2">
973
- <span><span data-wm-bind="@text auth.account.subscription.product.name">Current</span> plan</span>
974
- <span id="plan-status" class="badge bg-secondary">Loading...</span>
973
+ <span><span data-wm-bind="@text billing.plan.name" class="wm-binding-skeleton">Current</span> plan</span>
974
+ <span data-wm-bind="@attr class billing.status.badgeClass, @text billing.status.label" class="badge bg-secondary wm-binding-skeleton">&nbsp;</span>
975
975
  </h5>
976
- <p class="card-text mb-0" id="plan-description">Loading plan details...</p>
976
+ <p class="card-text mb-0" data-wm-bind="@show billing.description.free" hidden>
977
+ You are currently on the <strong data-wm-bind="@text billing.plan.name">Free</strong> plan. Upgrade to unlock premium features.
978
+ </p>
979
+ <p class="card-text mb-0" data-wm-bind="@show billing.description.active" hidden>
980
+ You are currently on the <strong data-wm-bind="@text billing.plan.name">Current</strong> plan.
981
+ </p>
982
+ <p class="card-text mb-0" data-wm-bind="@show billing.description.suspended" hidden>
983
+ Your <strong data-wm-bind="@text billing.plan.name">Current</strong> subscription has been suspended and access has been revoked due to a payment issue. Please update your payment method to restore access.
984
+ </p>
985
+ <p class="card-text mb-0" data-wm-bind="@show billing.description.cancelled" hidden>
986
+ Your <strong data-wm-bind="@text billing.plan.name">Current</strong> subscription has ended. Resubscribe to regain access to premium features.
987
+ </p>
977
988
  </div>
978
989
  </div>
979
990
 
980
991
  <!-- Billing details (next billing, amount) -->
981
- <div id="billing-details" class="mb-3 d-none"></div>
992
+ <div id="billing-details" class="mb-3" data-wm-bind="@show billing.details.visible" hidden>
993
+ <div class="row small text-muted">
994
+ <div class="col-sm-6 mb-1">
995
+ <strong>Next billing:</strong> <span data-wm-bind="@text billing.details.nextDate"></span>
996
+ </div>
997
+ <div class="col-sm-6 mb-1">
998
+ <strong>Amount:</strong> <span data-wm-bind="@text billing.details.amount"></span>
999
+ </div>
1000
+ </div>
1001
+ </div>
982
1002
 
983
1003
  <!-- State-specific alerts -->
984
- <div id="billing-alerts" class="mb-3"></div>
1004
+ <div class="mb-3">
1005
+ <!-- Suspended (payment issue) alert -->
1006
+ <div class="alert alert-danger d-flex align-items-start" data-wm-bind="@show billing.alerts.suspended" hidden>
1007
+ <span class="me-2 flex-shrink-0">{% uj_icon "triangle-exclamation", "fa-md" %}</span>
1008
+ <div>
1009
+ <strong>Payment failed</strong>
1010
+ <p class="mb-0 small">Your payment method was declined. Please update your payment method to keep your subscription active.</p>
1011
+ </div>
1012
+ </div>
1013
+
1014
+ <!-- Cancellation pending alert -->
1015
+ <div class="alert alert-warning d-flex align-items-start" data-wm-bind="@show billing.alerts.cancelling" hidden>
1016
+ <span class="me-2 flex-shrink-0">{% uj_icon "clock", "fa-md" %}</span>
1017
+ <div>
1018
+ <strong>Cancellation scheduled</strong>
1019
+ <p class="mb-0 small">Your subscription will end on <strong data-wm-bind="@text billing.alerts.cancelDate"></strong>. You'll continue to have full access until then. If you change your mind, you can reactivate through billing management.</p>
1020
+ </div>
1021
+ </div>
1022
+
1023
+ <!-- Free trial alert -->
1024
+ <div class="alert alert-success d-flex align-items-start" data-wm-bind="@show billing.alerts.trialing" hidden>
1025
+ <span class="me-2 flex-shrink-0">{% uj_icon "circle-check", "fa-md" %}</span>
1026
+ <div>
1027
+ <strong>Free trial</strong>
1028
+ <p class="mb-0 small" data-wm-bind="@show billing.alerts.trialHasEndDate" hidden>You're on a free trial that ends on <strong data-wm-bind="@text billing.alerts.trialEndDate"></strong>. You won't be charged until your trial ends.</p>
1029
+ <p class="mb-0 small" data-wm-bind="@hide billing.alerts.trialHasEndDate">You're on a free trial. You won't be charged until your trial ends.</p>
1030
+ </div>
1031
+ </div>
1032
+ </div>
985
1033
 
986
1034
  <!-- Action Buttons -->
987
1035
  <div class="d-grid d-sm-flex gap-2">
988
- <button id="upgrade-plan-btn" class="btn btn-success plan-action-btn" data-wm-bind="@show auth.account.subscription.product.id === basic" hidden>
1036
+ <button id="upgrade-plan-btn" class="btn btn-success plan-action-btn" data-wm-bind="@show billing.buttons.upgrade" hidden>
989
1037
  {% uj_icon "crown", "me-2" %}
990
1038
  <span class="button-text">Upgrade Plan</span>
991
1039
  </button>
992
- <button id="change-plan-btn" class="btn btn-outline-adaptive plan-action-btn" data-wm-bind="@show auth.account.subscription.product.id !== basic" hidden>
1040
+ <button id="change-plan-btn" class="btn btn-outline-adaptive plan-action-btn" data-wm-bind="@show billing.buttons.change" hidden>
993
1041
  {% uj_icon "arrow-right-arrow-left", "me-2" %}
994
1042
  <span class="button-text">Change Plan</span>
995
1043
  </button>
996
- <button id="manage-billing-btn" class="btn btn-primary plan-action-btn" data-wm-bind="@show auth.account.subscription.product.id !== basic" hidden>
1044
+ <button id="manage-billing-btn" class="btn btn-primary plan-action-btn" data-wm-bind="@show billing.buttons.manage" hidden>
997
1045
  {% uj_icon "credit-card", "me-2" %}
998
1046
  <span class="button-text">Manage Billing</span>
999
1047
  </button>
@@ -1012,7 +1060,7 @@ badges:
1012
1060
  </div>
1013
1061
 
1014
1062
  <!-- Cancel Subscription (only visible for paid users) -->
1015
- <div id="cancel-subscription-trigger" class="text-center" data-wm-bind="@show auth.account.subscription.product.id !== basic" hidden>
1063
+ <div id="cancel-subscription-trigger" class="text-center" data-wm-bind="@show billing.buttons.cancel" hidden>
1016
1064
  <button type="button" class="btn btn-link btn-sm text-muted text-decoration-underline cancel-trigger-link" data-bs-toggle="collapse" data-bs-target="#cancel-subscription-accordion" aria-expanded="false" aria-controls="cancel-subscription-accordion">
1017
1065
  Cancel subscription
1018
1066
  </button>
@@ -307,7 +307,7 @@ build_info:
307
307
  </div>
308
308
  <div>
309
309
  <div class="text-muted small mb-1">Last Build</div>
310
- <div class="fw-semibold"><span id="build-time">—</span> <span id="build-time-ago" class="text-muted small"></span></div>
310
+ <div class="fw-semibold"><span id="build-time">—</span> <span id="build-time-ago" class="text-muted small ms-1"></span></div>
311
311
  </div>
312
312
  </div>
313
313
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ultimate-jekyll-manager",
3
- "version": "0.0.278",
3
+ "version": "0.0.280",
4
4
  "description": "Ultimate Jekyll dependency manager",
5
5
  "main": "dist/index.js",
6
6
  "exports": {