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.
- package/CLAUDE.md +42 -0
- package/README.md +66 -0
- package/_backup/checkout copy 2.html +392 -0
- package/_backup/checkout copy 3.html +376 -0
- package/_backup/checkout copy 4.html +365 -0
- package/_backup/checkout copy.html +331 -0
- package/_backup/checkout-semi.html +331 -0
- package/dist/assets/css/core/bindings.scss +7 -2
- package/dist/assets/css/core/utilities.scss +8 -2
- package/dist/assets/css/pages/payment/checkout/index.scss +52 -7
- package/dist/assets/js/core/complete.js +56 -0
- package/dist/assets/js/core/initialize.js +11 -0
- package/dist/assets/js/pages/app/index.js +72 -17
- package/dist/assets/js/pages/download/index.js +0 -6
- package/dist/assets/js/pages/payment/checkout/index.js +58 -52
- package/dist/assets/js/pages/payment/checkout/modules/discount-bindings.js +51 -0
- package/dist/assets/js/pages/payment/checkout/modules/pricing.js +55 -30
- package/dist/assets/js/pages/payment/checkout/modules/state.js +68 -14
- package/dist/assets/js/pages/payment/checkout/modules/ui-bindings.js +160 -0
- package/dist/assets/js/pages/payment/checkout/modules/ui.js +27 -42
- package/dist/assets/js/pages/payment/confirmation/index.js +58 -53
- package/dist/assets/js/pages/payment/confirmation/modules/bindings.js +28 -0
- package/dist/assets/js/pages/payment/confirmation/modules/state.js +19 -0
- package/dist/assets/js/ultimate-jekyll-manager.js +6 -2
- package/dist/assets/themes/classy/css/base/_spacing.scss +27 -0
- package/dist/defaults/dist/_includes/core/body.html +31 -0
- package/dist/defaults/dist/_includes/core/foot.html +35 -0
- package/dist/defaults/dist/_layouts/blueprint/payment/checkout.html +6 -1
- package/dist/defaults/dist/_layouts/blueprint/payment/confirmation.html +6 -1
- package/dist/defaults/dist/_layouts/core/root.html +1 -0
- package/dist/defaults/dist/_layouts/modules/utilities/redirect.html +43 -32
- package/dist/defaults/dist/_layouts/themes/classy/backend/core/base.html +0 -35
- package/dist/defaults/dist/_layouts/themes/classy/frontend/core/base.html +0 -34
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/404.html +35 -44
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/app.html +3 -3
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/oauth2.html +37 -37
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/reset.html +45 -45
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +58 -58
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +1 -4
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/checkout.html +291 -240
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/payment/confirmation.html +43 -47
- package/dist/defaults/dist/pages/test/libraries/cover.html +1 -1
- package/firebase-debug.log +380 -0
- package/package.json +1 -1
- package/dist/assets/js/core/init.js +0 -36
|
@@ -1,47 +1,72 @@
|
|
|
1
1
|
// Pricing calculations for checkout
|
|
2
|
-
import {
|
|
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 (
|
|
9
|
-
basePrice =
|
|
10
|
-
?
|
|
11
|
-
:
|
|
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 =
|
|
28
|
+
basePrice = rawData.product.price || 0;
|
|
14
29
|
}
|
|
15
30
|
|
|
16
|
-
|
|
17
|
-
const
|
|
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 =
|
|
38
|
+
const discountedTotal = subtotal - discountAmount;
|
|
21
39
|
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
40
|
+
// Calculate trial discount amount and final total
|
|
41
|
+
let total;
|
|
42
|
+
let trialDiscountAmount = 0;
|
|
25
43
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
44
|
+
if (hasFreeTrial && isSubscription) {
|
|
45
|
+
// Free trial means $0 due today
|
|
46
|
+
trialDiscountAmount = discountedTotal;
|
|
47
|
+
total = 0;
|
|
29
48
|
} else {
|
|
30
|
-
|
|
49
|
+
total = discountedTotal;
|
|
31
50
|
}
|
|
32
51
|
|
|
33
|
-
//
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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 (!
|
|
81
|
+
if (!raw.product?._raw?.pricing) return {};
|
|
28
82
|
|
|
29
|
-
const pricing =
|
|
30
|
-
?
|
|
31
|
-
:
|
|
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
|
-
//
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
88
|
+
updateButtonText('card', 'Credit/Debit Card');
|
|
94
89
|
// PayPal uses logo - no text to update
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
95
|
+
updateButtonText('card', 'Credit/Debit Card');
|
|
101
96
|
// PayPal uses logo - no text to update
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
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
|
-
//
|
|
259
|
-
const
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
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
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
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
|
-
|
|
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
|
}
|