(async () => { const cfg = await fetch("/config").then(r => r.json()); const stripe = Stripe(cfg.publishableKey); const form = document.getElementById("donation-form"); const result = document.getElementById("result"); const amountInput = document.getElementById("amount"); const currencyInput = document.getElementById("currency"); let elements, expressCheckoutElement, cardElement, paymentIntent; // Initialize payment elements async function initializePayment() { const amount = parseFloat(amountInput.value) || 10; const currency = currencyInput.value; const supporterName = document.getElementById('supporter-name').value; // Create payment intent const res = await fetch("/create-payment-intent", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ amount, currency, supporterName }) }); const { clientSecret } = await res.json(); // Create elements with appearance customization elements = stripe.elements({ clientSecret, appearance: { theme: document.documentElement.getAttribute('data-theme') === 'dark' ? 'night' : 'stripe' } }); // Create and mount express checkout element (Google Pay, Apple Pay, etc.) expressCheckoutElement = elements.create("expressCheckout", { buttonType: { googlePay: "donate", applePay: "donate" }, paymentMethods: { link: "never" // Disable Link payment method } }); expressCheckoutElement.mount("#express-checkout-element"); // Listen for express checkout readiness expressCheckoutElement.on('ready', (event) => { const paymentDivider = document.querySelector('.payment-divider'); if (event.availablePaymentMethods && Object.keys(event.availablePaymentMethods).length > 0) { // Express methods are available, show the divider paymentDivider.style.display = 'block'; } else { // No express methods available, hide the divider on desktop but keep on mobile if (window.innerWidth <= 768) { paymentDivider.style.display = 'block'; paymentDivider.querySelector('span').textContent = 'Pay with card'; } else { paymentDivider.style.display = 'none'; } } }); // Create and mount card element cardElement = elements.create("card", { style: { base: { fontSize: '16px', color: getComputedStyle(document.documentElement).getPropertyValue('--text-primary'), '::placeholder': { color: getComputedStyle(document.documentElement).getPropertyValue('--text-secondary'), }, }, } }); cardElement.mount("#card-element"); return clientSecret; } // Handle express checkout (Google Pay, Apple Pay, etc.) async function handleExpressPayment() { result.textContent = "Processing..."; try { const { error } = await stripe.confirmPayment({ elements, confirmParams: { return_url: window.location.href, }, redirect: "if_required" }); if (error) { result.textContent = "❌ " + error.message; } else { result.textContent = "✅ Thank you! Support received successfully."; showSuccessAnimation(); addToSupporterWall(); } } catch (err) { result.textContent = "❌ Payment failed. Please try again."; } } // Handle card payment async function handleCardPayment(e) { e.preventDefault(); result.textContent = "Processing..."; try { const { error } = await stripe.confirmPayment({ elements, confirmParams: { return_url: window.location.href, }, redirect: "if_required" }); if (error) { result.textContent = "❌ " + error.message; } else { result.textContent = "✅ Thank you! Support received successfully."; showSuccessAnimation(); addToSupporterWall(); } } catch (err) { result.textContent = "❌ Payment failed. Please try again."; } } // Success animation function showSuccessAnimation() { result.style.background = 'linear-gradient(135deg, #28a745, #20c997)'; result.style.color = 'white'; result.style.padding = '12px'; result.style.borderRadius = '8px'; result.style.animation = 'bounce 0.6s ease-out'; } // Add to supporter wall async function addToSupporterWall() { const supporterName = document.getElementById('supporter-name').value.trim(); const amount = parseFloat(amountInput.value) || 0; const currency = currencyInput.value; if (supporterName && window.supporterWall) { await window.supporterWall.addSupporter(supporterName, amount * 100, currency); } } // Reinitialize when amount or currency changes async function reinitialize() { if (elements) { elements.destroy(); } const amount = parseFloat(amountInput.value); if (amount && amount > 0) { await initializePayment(); // Set up event listeners if (expressCheckoutElement) { expressCheckoutElement.on('click', handleExpressPayment); } } } // Event listeners form.addEventListener("submit", handleCardPayment); amountInput.addEventListener("blur", reinitialize); currencyInput.addEventListener("change", reinitialize); // Initialize on page load await initializePayment(); // Set up express checkout event listener if (expressCheckoutElement) { expressCheckoutElement.on('click', handleExpressPayment); } // Handle responsive payment divider visibility window.addEventListener('resize', () => { const paymentDivider = document.querySelector('.payment-divider'); if (window.innerWidth <= 768) { // Always show on mobile paymentDivider.style.display = 'block'; } }); // Update elements theme when theme changes if (window.themeManager) { const originalSetTheme = window.themeManager.setTheme; window.themeManager.setTheme = function(theme) { originalSetTheme.call(this, theme); // Reinitialize elements with new theme setTimeout(reinitialize, 100); }; } })();