ultimate-jekyll-manager 0.0.97 → 0.0.98

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/CLAUDE.md +42 -0
  2. package/README.md +66 -0
  3. package/_backup/checkout copy 2.html +392 -0
  4. package/_backup/checkout copy 3.html +376 -0
  5. package/_backup/checkout copy 4.html +365 -0
  6. package/_backup/checkout copy.html +331 -0
  7. package/_backup/checkout-semi.html +331 -0
  8. package/dist/assets/css/core/bindings.scss +7 -2
  9. package/dist/assets/css/core/utilities.scss +8 -2
  10. package/dist/assets/css/pages/payment/checkout/index.scss +52 -7
  11. package/dist/assets/js/core/complete.js +56 -0
  12. package/dist/assets/js/core/initialize.js +11 -0
  13. package/dist/assets/js/pages/app/index.js +72 -17
  14. package/dist/assets/js/pages/download/index.js +0 -6
  15. package/dist/assets/js/pages/payment/checkout/index.js +58 -52
  16. package/dist/assets/js/pages/payment/checkout/modules/discount-bindings.js +51 -0
  17. package/dist/assets/js/pages/payment/checkout/modules/pricing.js +55 -30
  18. package/dist/assets/js/pages/payment/checkout/modules/state.js +68 -14
  19. package/dist/assets/js/pages/payment/checkout/modules/ui-bindings.js +160 -0
  20. package/dist/assets/js/pages/payment/checkout/modules/ui.js +27 -42
  21. package/dist/assets/js/pages/payment/confirmation/index.js +58 -53
  22. package/dist/assets/js/pages/payment/confirmation/modules/bindings.js +28 -0
  23. package/dist/assets/js/pages/payment/confirmation/modules/state.js +19 -0
  24. package/dist/assets/js/ultimate-jekyll-manager.js +6 -2
  25. package/dist/assets/themes/classy/css/base/_spacing.scss +27 -0
  26. package/dist/defaults/dist/_includes/core/body.html +31 -0
  27. package/dist/defaults/dist/_includes/core/foot.html +35 -0
  28. package/dist/defaults/dist/_layouts/blueprint/payment/checkout.html +6 -1
  29. package/dist/defaults/dist/_layouts/blueprint/payment/confirmation.html +6 -1
  30. package/dist/defaults/dist/_layouts/core/root.html +1 -0
  31. package/dist/defaults/dist/_layouts/modules/utilities/redirect.html +43 -32
  32. package/dist/defaults/dist/_layouts/themes/classy/backend/core/base.html +0 -35
  33. package/dist/defaults/dist/_layouts/themes/classy/frontend/core/base.html +0 -34
  34. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/404.html +35 -44
  35. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +1 -1
  36. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/app.html +3 -3
  37. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/oauth2.html +37 -37
  38. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/reset.html +45 -45
  39. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -1
  40. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +58 -58
  41. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +1 -4
  42. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/checkout.html +291 -240
  43. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/confirmation.html +43 -47
  44. package/dist/defaults/dist/pages/test/libraries/cover.html +1 -1
  45. package/firebase-debug.log +380 -0
  46. package/package.json +1 -1
  47. package/dist/assets/js/core/init.js +0 -36
@@ -1,47 +1,72 @@
1
1
  // Pricing calculations for checkout
2
- import { state } from './state.js';
2
+ import { raw } from './state.js';
3
+
4
+ // Calculate prices and return values for bindings
5
+ // Takes raw data and returns formatted values
6
+ export function calculatePrices(rawData = raw) {
7
+ // Return default values if product not loaded
8
+ if (!rawData.product) {
9
+ return {
10
+ subtotal: 0,
11
+ discountAmount: 0,
12
+ trialDiscountAmount: 0,
13
+ total: 0,
14
+ recurring: 0,
15
+ displayPrice: '$--'
16
+ };
17
+ }
3
18
 
4
- // Calculate prices
5
- export function calculatePrices() {
6
19
  let basePrice;
20
+ const isSubscription = rawData.product.is_subscription || false;
21
+ const hasFreeTrial = rawData.product.has_free_trial || false;
7
22
 
8
- if (state.isSubscription) {
9
- basePrice = state.billingCycle === 'monthly'
10
- ? state.product.price_monthly
11
- : state.product.price_annually;
23
+ if (isSubscription) {
24
+ basePrice = rawData.billingCycle === 'monthly'
25
+ ? (rawData.product.price_monthly || 0)
26
+ : (rawData.product.price_annually || 0);
12
27
  } else {
13
- basePrice = state.product.price || 0;
28
+ basePrice = rawData.product.price || 0;
14
29
  }
15
30
 
16
- state.subtotal = basePrice;
17
- const discountAmount = (state.subtotal * state.discountPercent) / 100;
31
+ // Calculate subtotal
32
+ const subtotal = basePrice;
33
+
34
+ // Calculate discount amount
35
+ const discountAmount = (subtotal * rawData.discountPercent) / 100;
18
36
 
19
37
  // Calculate total after discount
20
- const discountedTotal = state.subtotal - discountAmount;
38
+ const discountedTotal = subtotal - discountAmount;
21
39
 
22
- // Update UI
23
- document.getElementById('subtotal').textContent = `$${state.subtotal.toFixed(2)}`;
24
- document.getElementById('discount-amount').textContent = discountAmount.toFixed(2);
40
+ // Calculate trial discount amount and final total
41
+ let total;
42
+ let trialDiscountAmount = 0;
25
43
 
26
- // Show/hide discount row
27
- if (state.discountPercent > 0) {
28
- document.getElementById('discount-row').classList.remove('d-none');
44
+ if (hasFreeTrial && isSubscription) {
45
+ // Free trial means $0 due today
46
+ trialDiscountAmount = discountedTotal;
47
+ total = 0;
29
48
  } else {
30
- document.getElementById('discount-row').classList.add('d-none');
49
+ total = discountedTotal;
31
50
  }
32
51
 
33
- // Handle trial discount
34
- const $trialDiscountRow = document.getElementById('trial-discount-row');
35
- if (state.hasFreeTrial && state.isSubscription) {
36
- // Show trial discount (full discounted amount)
37
- $trialDiscountRow.classList.remove('d-none');
38
- document.getElementById('trial-discount-amount').textContent = discountedTotal.toFixed(2);
39
- state.total = 0; // Free trial means $0 due today
40
- document.getElementById('total-price').textContent = '$0.00';
52
+ // Calculate recurring amount (after discount but before trial)
53
+ const recurring = discountedTotal;
54
+
55
+ // Format display price for product
56
+ let displayPrice;
57
+ if (isSubscription) {
58
+ const period = rawData.billingCycle === 'monthly' ? '/mo' : '/yr';
59
+ displayPrice = `$${discountedTotal.toFixed(2)}${period}`;
41
60
  } else {
42
- // Hide trial discount
43
- $trialDiscountRow.classList.add('d-none');
44
- state.total = discountedTotal;
45
- document.getElementById('total-price').textContent = `$${discountedTotal.toFixed(2)}`;
61
+ displayPrice = `$${discountedTotal.toFixed(2)}`;
46
62
  }
63
+
64
+ return {
65
+ subtotal,
66
+ discountAmount,
67
+ trialDiscountAmount,
68
+ total,
69
+ recurring,
70
+ displayPrice
71
+ };
47
72
  }
@@ -8,27 +8,81 @@ export const config = {
8
8
  siteConfig: null // Will be populated from API
9
9
  };
10
10
 
11
- export const state = {
12
- product: null,
11
+ // Raw data storage (not exposed to bindings)
12
+ export const raw = {
13
+ product: null, // Full product object from API
13
14
  billingCycle: 'annually',
14
15
  discountPercent: 0,
15
- subtotal: 0,
16
- total: 0,
17
- isSubscription: false,
18
- hasFreeTrial: false,
19
- paymentMethod: 'card',
20
- apiKeys: null, // Will store API keys from site config
21
- checkoutId: null, // Unique checkout session ID
22
- formData: null // Form data collected from checkout form
16
+ apiKeys: null,
17
+ checkoutId: null,
18
+ formData: null,
19
+ paymentMethod: 'card'
20
+ };
21
+
22
+ // State structure matches bindings exactly - THIS is what gets passed to bindings
23
+ export const state = {
24
+ checkout: {
25
+ product: {
26
+ name: 'Loading...',
27
+ description: 'Loading product details...',
28
+ isSubscription: false
29
+ },
30
+ pricing: {
31
+ monthlyPrice: '$--',
32
+ annualMonthlyRate: '$--',
33
+ savingsBadge: '',
34
+ showSavingsBadge: false,
35
+ billingCyclePaymentText: '$-- monthly',
36
+ productPrice: '$--',
37
+ subtotal: '$--',
38
+ total: '$--',
39
+ recurringAmount: '$--',
40
+ recurringPeriod: 'annually',
41
+ showTerms: false,
42
+ termsText: ''
43
+ },
44
+ trial: {
45
+ show: false,
46
+ hasFreeTrial: false,
47
+ message: '',
48
+ discountAmount: '0.00'
49
+ },
50
+ discount: {
51
+ loading: false,
52
+ success: false,
53
+ error: false,
54
+ hasDiscount: false,
55
+ percent: '',
56
+ amount: '0.00',
57
+ successMessage: 'Discount applied',
58
+ errorMessage: 'Invalid discount code'
59
+ },
60
+ paymentMethods: {
61
+ card: false,
62
+ paypal: false,
63
+ applePay: false,
64
+ googlePay: false,
65
+ crypto: false
66
+ },
67
+ error: {
68
+ show: false,
69
+ message: ''
70
+ }
71
+ },
72
+ auth: {
73
+ user: {
74
+ email: ''
75
+ }
76
+ }
23
77
  };
24
78
 
25
79
  // Get payment provider IDs for current billing cycle
26
80
  export function getPaymentIds() {
27
- if (!state.product?._raw?.pricing) return {};
81
+ if (!raw.product?._raw?.pricing) return {};
28
82
 
29
- const pricing = state.billingCycle === 'monthly'
30
- ? state.product._raw.pricing.monthly
31
- : state.product._raw.pricing.annually;
83
+ const pricing = raw.billingCycle === 'monthly'
84
+ ? raw.product._raw.pricing.monthly
85
+ : raw.product._raw.pricing.annually;
32
86
 
33
87
  return {
34
88
  stripePriceId: pricing.stripePriceId,
@@ -0,0 +1,160 @@
1
+ // UI Bindings Module - Refactored to use webManager.bindings()
2
+ // This module replaces direct DOM manipulation with the bindings system
3
+
4
+ import { state, raw } from './state.js';
5
+ import { calculatePrices } from './pricing.js';
6
+
7
+ // Build state from raw data
8
+ // This is the ONLY place we transform raw data into the bindings structure
9
+ export function buildStateFromRaw(webManager) {
10
+ const prices = calculatePrices(raw);
11
+
12
+ // Calculate savings for annual plan
13
+ const monthlyAnnual = raw.product?.price_monthly ? raw.product.price_monthly * 12 : 0;
14
+ const annuallyPrice = raw.product?.price_annually || 0;
15
+ const savingsPercent = monthlyAnnual > 0 ? Math.round(((monthlyAnnual - annuallyPrice) / monthlyAnnual) * 100) : 0;
16
+
17
+ // Get billing cycle text
18
+ const billingCycleText = raw.billingCycle === 'monthly' ? 'monthly' : 'annually';
19
+
20
+ // Format renewal date for terms
21
+ const renewalDate = new Date();
22
+ const daysToAdd = raw.billingCycle === 'monthly' ? 30 : 365;
23
+ renewalDate.setDate(renewalDate.getDate() + daysToAdd);
24
+ const formattedRenewalDate = renewalDate.toLocaleDateString('en-US', {
25
+ month: 'short',
26
+ day: 'numeric',
27
+ year: 'numeric'
28
+ });
29
+
30
+ // Get auth data
31
+ const user = webManager.auth().getUser();
32
+
33
+ // Update state directly with formatted bindings data
34
+ state.checkout.product.name = raw.product?.name || 'Loading...';
35
+ state.checkout.product.description = raw.product?.description || 'Loading product details...';
36
+ state.checkout.product.isSubscription = raw.product?.is_subscription || false;
37
+
38
+ state.checkout.pricing.monthlyPrice = raw.product?.price_monthly ? `$${raw.product.price_monthly.toFixed(2)}` : '$--';
39
+ state.checkout.pricing.annualMonthlyRate = raw.product?.price_annually ? `$${(raw.product.price_annually / 12).toFixed(2)}` : '$--';
40
+ state.checkout.pricing.savingsBadge = savingsPercent > 0 ? `Save ${savingsPercent}%` : '';
41
+ state.checkout.pricing.showSavingsBadge = savingsPercent > 0;
42
+ state.checkout.pricing.billingCyclePaymentText = raw.product ?
43
+ (raw.billingCycle === 'monthly'
44
+ ? `$${raw.product.price_monthly?.toFixed(2) || '--'} monthly`
45
+ : `$${raw.product.price_annually?.toFixed(2) || '--'} annually`)
46
+ : '$-- monthly';
47
+ state.checkout.pricing.productPrice = prices.displayPrice || '$--';
48
+ state.checkout.pricing.subtotal = prices.subtotal ? `$${prices.subtotal.toFixed(2)}` : '$--';
49
+ state.checkout.pricing.total = prices.total !== null ? `$${prices.total.toFixed(2)}` : '$--';
50
+ state.checkout.pricing.recurringAmount = prices.recurring ? `$${prices.recurring.toFixed(2)}` : '$--';
51
+ state.checkout.pricing.recurringPeriod = billingCycleText;
52
+ state.checkout.pricing.showTerms = raw.product?.is_subscription || false;
53
+ state.checkout.pricing.termsText = (raw.product?.is_subscription && raw.product) ?
54
+ `Your ${billingCycleText} subscription will start today and renew on ${formattedRenewalDate} for $${prices.recurring?.toFixed(2) || '--'} plus applicable tax. Cancel anytime.`
55
+ : '';
56
+
57
+ const hasFreeTrial = raw.product?.has_free_trial || false;
58
+ state.checkout.trial.show = hasFreeTrial && (raw.product?.is_subscription || false);
59
+ state.checkout.trial.hasFreeTrial = hasFreeTrial && (raw.product?.is_subscription || false) && prices.total === 0;
60
+ state.checkout.trial.message = hasFreeTrial ?
61
+ `Start your ${raw.product?.trial_days || 7}-day free trial today!` : '';
62
+ state.checkout.trial.discountAmount = hasFreeTrial && prices.trialDiscountAmount ?
63
+ prices.trialDiscountAmount.toFixed(2) : '0.00';
64
+
65
+ state.checkout.discount.hasDiscount = raw.discountPercent > 0;
66
+ state.checkout.discount.percent = raw.discountPercent > 0 ? `${raw.discountPercent}%` : '';
67
+ state.checkout.discount.amount = prices.discountAmount ? prices.discountAmount.toFixed(2) : '0.00';
68
+
69
+ state.auth.user.email = user?.email || '';
70
+ }
71
+
72
+ // Update all UI through bindings
73
+ // Rebuilds state from raw data, then passes COMPLETE object
74
+ export function updateAllUI(webManager) {
75
+ // Build state from raw data first
76
+ buildStateFromRaw(webManager);
77
+
78
+ console.log('🔄 Updating checkout bindings with data:', state);
79
+
80
+ webManager.bindings().update(state);
81
+ }
82
+
83
+ // Handle billing cycle change
84
+ export function handleBillingCycleChange(newCycle, webManager) {
85
+ if (newCycle && newCycle !== raw.billingCycle) {
86
+ raw.billingCycle = newCycle;
87
+ }
88
+ updateAllUI(webManager);
89
+ }
90
+
91
+ // Show error message
92
+ export function showError(message, webManager) {
93
+ state.checkout.error.show = true;
94
+ state.checkout.error.message = message;
95
+ webManager.bindings().update(state);
96
+ }
97
+
98
+ // Hide error
99
+ export function hideError(webManager) {
100
+ state.checkout.error.show = false;
101
+ state.checkout.error.message = '';
102
+ webManager.bindings().update(state);
103
+ }
104
+
105
+ // Update payment button visibility based on processor availability
106
+ export function updatePaymentButtonVisibility(paymentManager) {
107
+ const availableMethods = paymentManager.getAvailablePaymentMethods();
108
+
109
+ // Update state with payment methods
110
+ state.checkout.paymentMethods.card = paymentManager.isPaymentMethodAvailable('card');
111
+ state.checkout.paymentMethods.paypal = paymentManager.isPaymentMethodAvailable('paypal');
112
+ state.checkout.paymentMethods.applePay = paymentManager.isPaymentMethodAvailable('apple-pay');
113
+ state.checkout.paymentMethods.googlePay = paymentManager.isPaymentMethodAvailable('google-pay');
114
+ state.checkout.paymentMethods.crypto = paymentManager.isPaymentMethodAvailable('crypto');
115
+
116
+ console.log('Payment methods set in state. Available methods:', availableMethods.map(m => m.id));
117
+ }
118
+
119
+ // Show/hide discount loading state
120
+ export function showDiscountLoading(show, webManager) {
121
+ state.checkout.discount.loading = show;
122
+ state.checkout.discount.success = false;
123
+ state.checkout.discount.error = false;
124
+ webManager.bindings().update(state);
125
+ }
126
+
127
+ // Show discount success
128
+ export function showDiscountSuccess(message, webManager) {
129
+ state.checkout.discount.loading = false;
130
+ state.checkout.discount.success = true;
131
+ state.checkout.discount.error = false;
132
+ state.checkout.discount.successMessage = message || 'Discount applied';
133
+
134
+ // Rebuild state from raw (to update pricing with discount)
135
+ buildStateFromRaw(webManager);
136
+ webManager.bindings().update(state);
137
+ }
138
+
139
+ // Show discount error
140
+ export function showDiscountError(message, webManager) {
141
+ state.checkout.discount.loading = false;
142
+ state.checkout.discount.success = false;
143
+ state.checkout.discount.error = true;
144
+ state.checkout.discount.errorMessage = message || 'Invalid discount code';
145
+ webManager.bindings().update(state);
146
+ }
147
+
148
+ // Hide all discount messages
149
+ export function hideDiscountMessages(webManager) {
150
+ state.checkout.discount.loading = false;
151
+ state.checkout.discount.success = false;
152
+ state.checkout.discount.error = false;
153
+ webManager.bindings().update(state);
154
+ }
155
+
156
+ // Initialize checkout UI
157
+ export function initializeCheckoutUI() {
158
+ console.log('🚀 Initializing checkout UI');
159
+ // State is already initialized with default values
160
+ }
@@ -74,34 +74,29 @@ export function updateAllUI() {
74
74
  // Update trial badge based on current state
75
75
  updateTrialBadge();
76
76
 
77
- // Get payment button elements once
78
- const $cardBtn = document.getElementById('pay-with-card');
79
- const $paypalBtn = document.getElementById('pay-with-paypal');
80
- const $applePayBtn = document.getElementById('pay-with-apple-pay');
81
- const $googlePayBtn = document.getElementById('pay-with-google-pay');
82
- const $cryptoBtn = document.getElementById('pay-with-crypto');
83
-
84
- // Get button text spans (PayPal uses logo, so no text span)
85
- const $cardBtnText = $cardBtn?.querySelector('span.fw-semibold');
86
- const $applePayBtnText = $applePayBtn?.querySelector('span.fw-semibold');
87
- const $googlePayBtnText = $googlePayBtn?.querySelector('span.fw-semibold');
88
- const $cryptoBtnText = $cryptoBtn?.querySelector('span.fw-semibold');
77
+ // Helper function to update button text for specific payment method
78
+ const updateButtonText = (paymentMethod, textContent) => {
79
+ const buttons = document.querySelectorAll(`.payment-button[data-payment-method="${paymentMethod}"] span.fw-semibold`);
80
+ buttons.forEach(span => {
81
+ span.textContent = textContent;
82
+ });
83
+ };
89
84
 
90
85
  // Update payment button text based on trial
91
86
  if (state.hasFreeTrial) {
92
87
  // Update all payment buttons for free trial (keeping logic for future customization)
93
- if ($cardBtnText) $cardBtnText.textContent = 'Credit/Debit Card';
88
+ updateButtonText('card', 'Credit/Debit Card');
94
89
  // PayPal uses logo - no text to update
95
- if ($applePayBtnText) $applePayBtnText.textContent = 'Apple Pay';
96
- if ($googlePayBtnText) $googlePayBtnText.textContent = 'Google Pay';
97
- if ($cryptoBtnText) $cryptoBtnText.textContent = 'Crypto';
90
+ updateButtonText('apple-pay', 'Apple Pay');
91
+ updateButtonText('google-pay', 'Google Pay');
92
+ updateButtonText('crypto', 'Crypto');
98
93
  } else {
99
94
  // Reset to normal payment text
100
- if ($cardBtnText) $cardBtnText.textContent = 'Credit/Debit Card';
95
+ updateButtonText('card', 'Credit/Debit Card');
101
96
  // PayPal uses logo - no text to update
102
- if ($applePayBtnText) $applePayBtnText.textContent = 'Apple Pay';
103
- if ($googlePayBtnText) $googlePayBtnText.textContent = 'Google Pay';
104
- if ($cryptoBtnText) $cryptoBtnText.textContent = 'Crypto';
97
+ updateButtonText('apple-pay', 'Apple Pay');
98
+ updateButtonText('google-pay', 'Google Pay');
99
+ updateButtonText('crypto', 'Crypto');
105
100
  }
106
101
 
107
102
  // Update subscription terms
@@ -255,28 +250,18 @@ export function hidePreloader() {
255
250
 
256
251
  // Update payment button visibility based on processor availability
257
252
  export function updatePaymentButtonVisibility(paymentManager) {
258
- // Define button mappings - all IDs use payment methods, not processors
259
- const buttonMappings = [
260
- { paymentMethod: 'card', buttonId: 'pay-with-card' },
261
- { paymentMethod: 'paypal', buttonId: 'pay-with-paypal' },
262
- { paymentMethod: 'crypto', buttonId: 'pay-with-crypto' },
263
- { paymentMethod: 'apple-pay', buttonId: 'pay-with-apple-pay' },
264
- { paymentMethod: 'google-pay', buttonId: 'pay-with-google-pay' }
265
- ];
266
-
267
- // Check each payment method and update button visibility
268
- buttonMappings.forEach(({ paymentMethod, buttonId }) => {
269
- const $button = document.getElementById(buttonId);
270
- if ($button) {
271
- const isAvailable = paymentManager.isPaymentMethodAvailable(paymentMethod);
272
-
273
- if (isAvailable) {
274
- // Show the button
275
- $button.classList.remove('d-none');
276
- } else {
277
- // Hide the button
278
- $button.classList.add('d-none');
279
- }
253
+ // Get all payment buttons
254
+ const paymentButtons = document.querySelectorAll('.payment-button');
255
+
256
+ // Update each button's visibility based on its payment method
257
+ paymentButtons.forEach(button => {
258
+ const paymentMethod = button.getAttribute('data-payment-method');
259
+ const isAvailable = paymentManager.isPaymentMethodAvailable(paymentMethod);
260
+
261
+ if (isAvailable) {
262
+ button.classList.remove('d-none');
263
+ } else {
264
+ button.classList.add('d-none');
280
265
  }
281
266
  });
282
267
 
@@ -1,4 +1,7 @@
1
1
  // Libraries
2
+ import { state } from './modules/state.js';
3
+ import { initializeConfirmationUI, updateAllUI } from './modules/bindings.js';
4
+
2
5
  let webManager = null;
3
6
 
4
7
  /* Test URL
@@ -13,10 +16,16 @@ export default (Manager, options) => {
13
16
 
14
17
  // Initialize when DOM is ready
15
18
  await webManager.dom().ready();
16
-
19
+
20
+ // Initialize UI with loading states
21
+ initializeConfirmationUI();
22
+
23
+ // Load order data and update bindings
17
24
  loadOrderData();
25
+
26
+ // Trigger celebration
18
27
  await triggerCelebration();
19
-
28
+
20
29
  // Resolve after initialization
21
30
  return resolve();
22
31
  });
@@ -26,59 +35,55 @@ export default (Manager, options) => {
26
35
  function loadOrderData() {
27
36
  const urlParams = new URLSearchParams(window.location.search);
28
37
 
29
- // Parse order data from URL
30
- const orderData = {
31
- orderId: urlParams.get('order_id') || urlParams.get('transaction_id'),
32
- productId: urlParams.get('product_id') || urlParams.get('product'),
33
- productName: urlParams.get('product_name'),
34
- total: parseFloat(urlParams.get('amount') || urlParams.get('total') || 0),
35
- currency: urlParams.get('currency') || 'USD',
36
- billingCycle: urlParams.get('frequency') || urlParams.get('billing_cycle'),
37
- paymentMethod: urlParams.get('payment_method'),
38
- hasFreeTrial: urlParams.get('trial') === 'true',
39
- email: urlParams.get('email')
40
- };
41
-
42
- // DOM elements
43
- const $orderNumber = document.getElementById('order-number');
44
- const $productName = document.getElementById('product-name');
45
- const $totalPaid = document.getElementById('total-paid');
46
- const $subscriptionInfo = document.getElementById('subscription-info');
47
- const $billingInfo = document.getElementById('billing-info');
48
-
49
- if (orderData.orderId) {
50
- // Populate order details
51
- if ($orderNumber) $orderNumber.textContent = orderData.orderId;
52
- if ($productName) $productName.textContent = orderData.productName || orderData.productId || 'Product';
53
- if ($totalPaid) $totalPaid.textContent = `$${orderData.total.toFixed(2)}`;
54
-
55
- // Handle subscription information
56
- if (orderData.billingCycle && $subscriptionInfo) {
57
- $subscriptionInfo.classList.remove('d-none');
58
-
59
- if ($billingInfo) {
60
- if (orderData.hasFreeTrial) {
61
- $billingInfo.innerHTML = `
62
- <strong>Free Trial Active!</strong> Your trial period has begun.
63
- You'll be charged ${orderData.billingCycle === 'monthly' ? 'monthly' : 'annually'} after the trial ends.
64
- `;
65
- } else {
66
- $billingInfo.innerHTML = `
67
- Your ${orderData.billingCycle} subscription is now active.
68
- You'll be charged automatically each ${orderData.billingCycle === 'monthly' ? 'month' : 'year'}.
69
- `;
70
- }
71
- }
38
+ // Parse raw data from URL
39
+ const orderId = urlParams.get('order_id') || urlParams.get('transaction_id') || generateOrderNumber();
40
+ const productId = urlParams.get('product_id') || urlParams.get('product');
41
+ const productName = urlParams.get('product_name');
42
+ const total = parseFloat(urlParams.get('amount') || urlParams.get('total') || 0);
43
+ const currency = urlParams.get('currency') || 'USD';
44
+ const billingCycle = urlParams.get('frequency') || urlParams.get('billing_cycle');
45
+ const paymentMethod = urlParams.get('payment_method');
46
+ const hasFreeTrial = urlParams.get('trial') === 'true';
47
+
48
+ // Build billing cycle text
49
+ const billingCycleText = billingCycle === 'monthly' ? 'monthly' : billingCycle === 'annually' ? 'annually' : '';
50
+ const billingPeriodText = billingCycle === 'monthly' ? 'month' : billingCycle === 'annually' ? 'year' : '';
51
+
52
+ // Build subscription info text
53
+ let subscriptionInfoText = '';
54
+ if (billingCycle) {
55
+ if (hasFreeTrial) {
56
+ subscriptionInfoText = `Free Trial Active! Your trial period has begun. You'll be charged ${billingCycleText} after the trial ends.`;
57
+ } else {
58
+ subscriptionInfoText = `Your ${billingCycleText} subscription is now active. You'll be charged automatically each ${billingPeriodText}.`;
72
59
  }
73
-
74
- // Track analytics only if not already tracked
75
- trackPurchaseIfNotTracked(orderData);
76
- } else {
77
- // Fallback for direct page access without params
78
- if ($orderNumber) $orderNumber.textContent = generateOrderNumber();
79
- if ($productName) $productName.textContent = 'Your Purchase';
80
- if ($totalPaid) $totalPaid.textContent = '$0.00';
81
60
  }
61
+
62
+ // Update state directly in bindings format
63
+ state.confirmation.order.id = orderId;
64
+ state.confirmation.order.productName = productName || productId || 'Product';
65
+ state.confirmation.order.total = `$${total.toFixed(2)}`;
66
+ state.confirmation.order.currency = currency;
67
+ state.confirmation.subscription.show = !!billingCycle;
68
+ state.confirmation.subscription.hasFreeTrial = hasFreeTrial;
69
+ state.confirmation.subscription.billingCycle = billingCycleText;
70
+ state.confirmation.subscription.infoText = subscriptionInfoText;
71
+ state.confirmation.loaded = true;
72
+
73
+ // Update UI with complete bindings
74
+ updateAllUI(webManager);
75
+
76
+ // Track analytics only if not already tracked
77
+ trackPurchaseIfNotTracked({
78
+ orderId,
79
+ productId,
80
+ productName,
81
+ total,
82
+ currency,
83
+ billingCycle,
84
+ paymentMethod,
85
+ hasFreeTrial
86
+ });
82
87
  }
83
88
 
84
89
  // Generate a mock order number
@@ -0,0 +1,28 @@
1
+ // Confirmation Bindings Module
2
+ import { state } from './state.js';
3
+
4
+ // Get the COMPLETE confirmation bindings object
5
+ // State IS the bindings - no transformation needed
6
+ export function getCompleteConfirmationBindings() {
7
+ // Just return state directly - it's already structured correctly
8
+ return state;
9
+ }
10
+
11
+ // Update all UI through bindings
12
+ // ALWAYS passes the COMPLETE confirmation object
13
+ export function updateAllUI(webManager) {
14
+ const bindingsData = getCompleteConfirmationBindings();
15
+
16
+ console.log('🔄 Updating confirmation bindings with data:', bindingsData);
17
+
18
+ webManager.bindings().update(bindingsData);
19
+ }
20
+
21
+ // Initialize confirmation UI with loading states
22
+ export function initializeConfirmationUI() {
23
+ console.log('🚀 Initializing confirmation UI');
24
+
25
+ // State is already initialized with default values
26
+ // We'll update bindings once after data is loaded
27
+ state.confirmation.loaded = false;
28
+ }
@@ -0,0 +1,19 @@
1
+ // Confirmation state management
2
+ // This is the SINGLE source of truth - structure matches bindings exactly
3
+ export const state = {
4
+ confirmation: {
5
+ order: {
6
+ id: 'Loading...',
7
+ productName: 'Product',
8
+ total: '$0.00',
9
+ currency: 'USD'
10
+ },
11
+ subscription: {
12
+ show: false,
13
+ hasFreeTrial: false,
14
+ billingCycle: '',
15
+ infoText: ''
16
+ },
17
+ loaded: false
18
+ }
19
+ };
@@ -1,9 +1,10 @@
1
1
  // Static imports for core modules (bundled together for efficiency)
2
- import initModule from '__main_assets__/js/core/init.js';
2
+ // import initializeModule from '__main_assets__/js/core/initialize.js';
3
3
  import authModule from '__main_assets__/js/core/auth.js';
4
4
  import lazyLoadingModule from '__main_assets__/js/core/lazy-loading.js';
5
5
  import queryStringsModule from '__main_assets__/js/core/query-strings.js';
6
6
  import serviceWorkerModule from '__main_assets__/js/core/service-worker.js';
7
+ import completeModule from '__main_assets__/js/core/complete.js';
7
8
 
8
9
  // Ultimate Jekyll Manager Module
9
10
  export default async function (Manager, options) {
@@ -17,7 +18,7 @@ export default async function (Manager, options) {
17
18
  console.log('Global module loaded successfully (assets/js/ultimate-jekyll-manager.js)');
18
19
 
19
20
  // Initialize fixed modules synchronously (already loaded via static imports)
20
- initModule(Manager, options);
21
+ // initializeModule(Manager, options);
21
22
  authModule(Manager, options);
22
23
  lazyLoadingModule(Manager, options);
23
24
  queryStringsModule(Manager, options);
@@ -56,4 +57,7 @@ export default async function (Manager, options) {
56
57
 
57
58
  // Wait for all conditional modules to load
58
59
  await Promise.all(modulePromises);
60
+
61
+ // Run the complete module to finalize page load state
62
+ completeModule(Manager, options);
59
63
  }