Global Event Timezone Converter & Embed Widget

Input Event Details

`; embedCodeOutput.value = embedCode; outputArea.style.display = 'block'; qrCodeContainer.style.display = 'none'; // Hide QR code when generating new embed showSpinner(generateWidgetBtn, false); incrementUsage(); // Only increment on successful generation }); copyCodeBtn.addEventListener('click', () => { embedCodeOutput.select(); document.execCommand('copy'); showMessage(translations[currentLang].copiedToClipboard, 'success'); }); showQrCodeBtn.addEventListener('click', async () => { if (!checkFormValidity()) { showMessage(translations[currentLang].formValidationError, 'error'); return; } if (!isUnlocked && usageCount >= FREE_LIMIT) { showPaymentOverlay(); return; } showSpinner(showQrCodeBtn, true); showMessage(translations[currentLang].loadingQrCode, 'success'); const eventName = document.getElementById('eventName').value; const eventDateTime = document.getElementById('eventDateTime').value; const eventTimezone = document.getElementById('eventTimezone').value; const eventLink = document.getElementById('eventLink').value; const widgetDetails = { eventName, eventDateTime, eventTimezone, eventLink }; const widgetDetailsJson = JSON.stringify(widgetDetails); const dataUrl = `https://pixeloffice.eu/global-event-timezone-embedder?data=${encodeURIComponent(btoa(widgetDetailsJson))}`; // Example: a URL to pre-fill the form or display a preview const qrCodeApiUrl = `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(dataUrl)}`; qrCodeContainer.innerHTML = `QR Code for Event Widget`; qrCodeContainer.style.display = 'flex'; outputArea.style.display = 'block'; // Ensure output area is visible embedCodeOutput.value = translations[currentLang].qrCodeFailed; // Clear old embed code or show message if no embed generated yet showSpinner(showQrCodeBtn, false); incrementUsage(); // Increment usage for QR code generation }); sendWhatsappBtn.addEventListener('click', () => { if (!checkFormValidity()) { showMessage(translations[currentLang].formValidationError, 'error'); return; } if (!isUnlocked && usageCount >= FREE_LIMIT) { showPaymentOverlay(); return; } showSpinner(sendWhatsappBtn, true); showMessage(translations[currentLang].sendingWhatsapp, 'success'); const eventName = document.getElementById('eventName').value; const eventDateTime = document.getElementById('eventDateTime').value; const eventTimezone = document.getElementById('eventTimezone').value; const eventLink = document.getElementById('eventLink').value || 'N/A'; const message = translations[currentLang].whatsappMessageTemplate .replace('{eventName}', eventName) .replace('{eventDateTime}', eventDateTime) .replace('{eventTimezone}', eventTimezone) .replace('{eventLink}', eventLink); const whatsappUrl = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodeURIComponent(message)}`; window.open(whatsappUrl, '_blank'); showSpinner(sendWhatsappBtn, false); incrementUsage(); // Increment usage for WhatsApp send }); // --- Payment Button Handlers --- hubBundleBtn.addEventListener('click', async () => { showSpinner(hubBundleBtn, true); if (!currentUser) { hidePaymentOverlay(); showAuthModal('login'); // Prompt login showSpinner(hubBundleBtn, false); return; } // User is logged in, attempt to subscribe try { const response = await fetch(`${AUTH_API_BASE}create-hub-subscription`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: currentUser.email, userId: currentUser.uid }) }); const data = await response.json(); if (data.url) { window.location.href = data.url; // Redirect to Stripe Checkout } else { showMessage(translations[currentLang].paymentFailed, 'error'); } } catch (error) { console.error("Hub subscription error:", error); showMessage(translations[currentLang].paymentFailed, 'error'); } finally { showSpinner(hubBundleBtn, false); } }); oneTimePaymentBtn.addEventListener('click', async () => { showSpinner(oneTimePaymentBtn, true); try { const response = await fetch(`${AUTH_API_BASE}create-session`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slug: WIDGET_SLUG, amount: 199, // $1.99 widgetName: translations[currentLang].widgetTitle }) }); const data = await response.json(); if (data.url) { window.location.href = data.url; // Redirect to Stripe Checkout } else { showMessage(translations[currentLang].paymentFailed, 'error'); } } catch (error) { console.error("One-time payment error:", error); showMessage(translations[currentLang].paymentFailed, 'error'); } finally { showSpinner(oneTimePaymentBtn, false); } }); cryptoPaymentBtn.addEventListener('click', async () => { showSpinner(cryptoPaymentBtn, true); try { const response = await fetch(`${AUTH_API_BASE}request-crypto`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slug: WIDGET_SLUG, amount: 199, // $1.99 widgetName: translations[currentLang].widgetTitle }) }); const data = await response.json(); if (data.address && data.amount && data.paymentId) { showCryptoPaymentModal(data.qrCodeUrl, data.address, data.amount); // Start polling for payment verification cryptoPollingInterval = setInterval(async () => { try { const verifyResponse = await fetch(`${AUTH_API_BASE}verify-crypto?paymentId=${data.paymentId}`); const verifyData = await verifyResponse.json(); if (verifyData.status === 'paid') { clearInterval(cryptoPollingInterval); await unlockWidget(); showMessage(translations[currentLang].paymentSuccess, 'success'); hideCryptoPaymentModal(); } else if (verifyData.status === 'pending') { cryptoPaymentStatus.textContent = translations[currentLang].cryptoPaymentPolling; cryptoPaymentStatus.className = 'message success'; cryptoPaymentStatus.style.display = 'block'; } else { clearInterval(cryptoPollingInterval); showMessage(translations[currentLang].paymentVerificationFailed, 'error'); cryptoPaymentStatus.textContent = translations[currentLang].paymentVerificationFailed; cryptoPaymentStatus.className = 'message error'; cryptoPaymentStatus.style.display = 'block'; } } catch (error) { console.error("Crypto polling error:", error); clearInterval(cryptoPollingInterval); showMessage(translations[currentLang].paymentVerificationFailed, 'error'); } }, 5000); // Poll every 5 seconds } else { showMessage(translations[currentLang].paymentFailed, 'error'); } } catch (error) { console.error("Crypto request error:", error); showMessage(translations[currentLang].paymentFailed, 'error'); } finally { showSpinner(cryptoPaymentBtn, false); } }); cryptoCopyAddressBtn.addEventListener('click', () => { const address = cryptoAddress.textContent; navigator.clipboard.writeText(address).then(() => { showMessage(translations[currentLang].copiedAddressToClipboard, 'success'); }).catch(err => { console.error('Failed to copy address: ', err); }); }); // --- Auth Modal Logic --- authSubmitBtn.addEventListener('click', async () => { const email = authEmail.value; const password = authPassword.value; showSpinner(authSubmitBtn, true); try { if (isLoginMode) { await auth.signInWithEmailAndPassword(email, password); showMessage(translations[currentLang].authSuccess, 'success'); } else { await auth.createUserWithEmailAndPassword(email, password); showMessage(translations[currentLang].authRegisterSuccess, 'success'); } hideAuthModal(); } catch (error) { showMessage(translations[currentLang].authError + error.message, 'error'); } finally { showSpinner(authSubmitBtn, false); } }); googleSignInBtn.addEventListener('click', async () => { showSpinner(googleSignInBtn, true); try { const provider = new firebase.auth.GoogleAuthProvider(); await auth.signInWithPopup(provider); showMessage(translations[currentLang].authSuccess, 'success'); hideAuthModal(); } catch (error) { showMessage(translations[currentLang].authError + error.message, 'error'); } finally { showSpinner(googleSignInBtn, false); } }); // --- Initial setup --- document.addEventListener('DOMContentLoaded', () => { fillTimezones(); languageSwitcher.value = currentLang; updateTexts(); // Set current date/time as default in input const now = new Date(); now.setMinutes(now.getMinutes() - now.getTimezoneOffset()); document.getElementById('eventDateTime').value = now.toISOString().slice(0, 16); });