Universal Event Countdown

Event Name

Customize Appearance

Countdown Preview

Countdown to My Awesome Event
DD:HH:MM:SS

Embed Code

<!-- Your generated countdown widget will appear here -->

QR Code for Widget

Recommended

Showcase Hub Bundle

Unlimited access to 19+ apps.

One-time Access

Unlock this app forever.

Crypto Micro-payment

Pay with Solana/Bitcoin.

Sign In to Pixel Office Hub

Don't have an account? Sign Up

Crypto Payment Details

Please send {amount} {currency} to the address below:

loading...

Checking payment status...

`; return widgetHTML; }; generateButton.addEventListener('click', () => { if (!isUnlocked && actionsCount >= FREE_USES_LIMIT) { showPaymentOverlay(); return; } const widgetCode = generateWidgetCode(); if (widgetCode) { embedCodeOutput.textContent = widgetCode; qrCodeImg.src = `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(widgetCode)}`; qrCodeImg.style.display = 'block'; if (!isUnlocked) { actionsCount++; localStorage.setItem(`pv_actions_${WIDGET_SLUG}`, actionsCount); updateFreeUsesText(); if (actionsCount >= FREE_USES_LIMIT) { showPaymentOverlay(); } } } }); // --- Copy to Clipboard --- copyButtons.forEach(button => { button.addEventListener('click', () => { const targetId = button.dataset.copyTarget; const targetElement = document.getElementById(targetId); if (targetElement) { const textToCopy = targetElement.textContent; navigator.clipboard.writeText(textToCopy).then(() => { button.classList.add('copied'); const originalText = button.textContent; button.textContent = translations[currentLang].copied; setTimeout(() => { button.textContent = originalText; button.classList.remove('copied'); }, 2000); }).catch(err => { console.error('Failed to copy text: ', err); }); } }); }); // --- Monetization & Firebase --- const firebaseConfig = { apiKey: "AIzaSyFakeKeyForShowcaseHubAuthTestingOnly", authDomain: "pixeloffice-hub.firebaseapp.com", projectId: "pixeloffice-hub", storageBucket: "pixeloffice-hub.appspot.com", messagingSenderId: "1234567890", appId: "1:1234567890:web:abcdef123456" }; if (!firebase.apps.length) { firebase.initializeApp(firebaseConfig); } const auth = firebase.auth(); const firebaseGoogleProvider = new firebase.auth.GoogleAuthProvider(); const paymentOverlay = document.getElementById('payment-overlay'); const authModal = document.getElementById('auth-modal'); const qrModal = document.getElementById('qr-modal'); const loadingSpinner = document.getElementById('loading-spinner'); const authErrorMessage = document.getElementById('auth-error-message'); const authEmailInput = document.getElementById('auth-email'); const authPasswordInput = document.getElementById('auth-password'); const authSubmitBtn = document.getElementById('auth-submit-btn'); const googleSignInBtn = document.getElementById('google-signin-btn'); const switchAuthModeLink = document.getElementById('switch-auth-mode'); const authModalTitle = document.getElementById('auth-modal-title'); const switchAuthText = document.getElementById('switch-auth-text'); let isRegisterMode = false; const showLoading = (show) => { loadingSpinner.style.display = show ? 'flex' : 'none'; }; const showPaymentOverlay = () => { paymentOverlay.classList.add('active'); updateContent(); // Ensure payment overlay texts are localized }; const hidePaymentOverlay = () => { paymentOverlay.classList.remove('active'); }; const showAuthModal = (register = false) => { isRegisterMode = register; authModalTitle.textContent = register ? translations[currentLang].registerTitle : translations[currentLang].loginTitle; authSubmitBtn.textContent = register ? translations[currentLang].signUp : translations[currentLang].signIn; switchAuthText.textContent = register ? translations[currentLang].alreadyHaveAccount : translations[currentLang].dontHaveAccount; switchAuthModeLink.textContent = register ? translations[currentLang].signIn : translations[currentLang].signUp; authErrorMessage.style.display = 'none'; authModal.classList.add('active'); }; const hideAuthModal = () => { authModal.classList.remove('active'); authEmailInput.value = ''; authPasswordInput.value = ''; authErrorMessage.style.display = 'none'; }; const showQrModal = (qrCodeData, cryptoAddress, amount, currency) => { document.getElementById('crypto-address').textContent = cryptoAddress; document.getElementById('crypto-message').dataset.i18nArgAmount = amount; document.getElementById('crypto-message').dataset.i18nArgCurrency = currency; document.getElementById('crypto-message').textContent = translations[currentLang].sendAmountToAddress.replace('{amount}', amount).replace('{currency}', currency); document.getElementById('crypto-qr-img').src = qrCodeData; document.getElementById('crypto-qr-img').style.display = 'block'; document.getElementById('crypto-loading-message').style.display = 'block'; document.getElementById('crypto-confirm-btn').style.display = 'none'; qrModal.classList.add('active'); }; const hideQrModal = () => { qrModal.classList.remove('active'); clearInterval(cryptoPollingInterval); }; // Close modal buttons document.querySelectorAll('[data-modal-close]').forEach(btn => { btn.addEventListener('click', (e) => { const modalId = e.target.dataset.modalClose; document.getElementById(modalId).classList.remove('active'); if (modalId === 'qr-modal') clearInterval(cryptoPollingInterval); }); }); // Firebase Auth Logic authSubmitBtn.addEventListener('click', async () => { const email = authEmailInput.value; const password = authPasswordInput.value; if (!email || !password) { authErrorMessage.textContent = translations[currentLang].emailAndPasswordRequired; authErrorMessage.style.display = 'block'; return; } authErrorMessage.style.display = 'none'; showLoading(true); try { if (isRegisterMode) { await auth.createUserWithEmailAndPassword(email, password); alert(translations[currentLang].registrationSuccess); } else { await auth.signInWithEmailAndPassword(email, password); alert(translations[currentLang].loginSuccess); } hideAuthModal(); } catch (error) { authErrorMessage.textContent = `${translations[currentLang].error}: ${error.message}`; authErrorMessage.style.display = 'block'; } finally { showLoading(false); } }); googleSignInBtn.addEventListener('click', async () => { showLoading(true); try { await auth.signInWithPopup(firebaseGoogleProvider); alert(translations[currentLang].loginSuccess); hideAuthModal(); } catch (error) { authErrorMessage.textContent = `${translations[currentLang].error}: ${error.message}`; authErrorMessage.style.display = 'block'; } finally { showLoading(false); } }); switchAuthModeLink.addEventListener('click', (e) => { e.preventDefault(); showAuthModal(!isRegisterMode); }); // Unlock logic const unlockWidget = () => { isUnlocked = true; localStorage.setItem(`pv_unlocked_${WIDGET_SLUG}`, 'true'); hidePaymentOverlay(); updateFreeUsesText(); // Clear the free uses text console.log('Widget unlocked!'); alert(translations[currentLang].paymentSuccessful); }; // Check subscription on auth state change auth.onAuthStateChanged(async (user) => { if (user) { console.log("User logged in:", user.email); // Check Hub subscription try { const response = await fetch(`https://api.pixeloffice.eu/api/pay/check-subscription?email=${encodeURIComponent(user.email)}`); const data = await response.json(); if (data.active) { console.log('Hub subscription is active!'); unlockWidget(); } else { console.log('Hub subscription not active.'); document.getElementById('hub-subscribe-btn').textContent = translations[currentLang].subscribeForPrice.replace('${price}', '9'); document.getElementById('hub-subscribe-btn').onclick = () => handleHubSubscription(user); } } catch (error) { console.error('Error checking Hub subscription:', error); } } else { console.log("User not logged in."); document.getElementById('hub-subscribe-btn').textContent = translations[currentLang].signInToUnlockSubscribe; document.getElementById('hub-subscribe-btn').onclick = () => showAuthModal(false); } }); // Handle Hub Subscription const handleHubSubscription = async (user) => { if (!user) { showAuthModal(false); // Prompt to login/register first return; } showLoading(true); try { const response = await fetch('https://api.pixeloffice.eu/api/pay/create-hub-subscription', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: user.email, userId: user.uid }) }); const data = await response.json(); if (data.url) { window.location.href = data.url; } else { alert(`${translations[currentLang].error}: ${data.message || 'Could not create subscription.'}`); } } catch (error) { alert(`${translations[currentLang].error}: ${error.message}`); } finally { showLoading(false); } }; // Handle One-time Unlock document.getElementById('one-time-unlock-btn').addEventListener('click', async () => { showLoading(true); try { const response = await fetch('https://api.pixeloffice.eu/api/pay/create-session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slug: WIDGET_SLUG, amount: 199, widgetName: translations[currentLang].appTitle }) }); const data = await response.json(); if (data.url) { window.location.href = data.url; } else { alert(`${translations[currentLang].error}: ${data.message || 'Could not create checkout session.'}`); } } catch (error) { alert(`${translations[currentLang].error}: ${error.message}`); } finally { showLoading(false); } }); // Handle Crypto Payment let cryptoPollingInterval; let cryptoPaymentId; document.getElementById('crypto-pay-btn').addEventListener('click', async () => { showLoading(true); try { const response = await fetch('https://api.pixeloffice.eu/api/pay/request-crypto', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slug: WIDGET_SLUG, amount: 199, widgetName: translations[currentLang].appTitle }) }); const data = await response.json(); if (data.qrCodeUrl && data.address && data.amount && data.currency && data.paymentId) { cryptoPaymentId = data.paymentId; showQrModal(data.qrCodeUrl, data.address, data.amount, data.currency); document.getElementById('crypto-confirm-btn').style.display = 'block'; cryptoPollingInterval = setInterval(checkCryptoPaymentStatus, 10000); // Poll every 10 seconds } else { alert(`${translations[currentLang].error}: ${data.message || 'Could not initiate crypto payment.'}`); } } catch (error) { alert(`${translations[currentLang].error}: ${error.message}`); } finally { showLoading(false); } }); const checkCryptoPaymentStatus = async () => { if (!cryptoPaymentId) return; try { const response = await fetch(`https://api.pixeloffice.eu/api/pay/verify-crypto?paymentId=${cryptoPaymentId}`); const data = await response.json(); if (data.verified) { clearInterval(cryptoPollingInterval); hideQrModal(); unlockWidget(); } else { document.getElementById('crypto-loading-message').textContent = translations[currentLang].checkingPaymentStatus; } } catch (error) { console.error('Error checking crypto payment status:', error); document.getElementById('crypto-loading-message').textContent = `${translations[currentLang].error}: ${error.message}`; } }; // Manual confirm button for crypto (if user already paid outside polling window) document.getElementById('crypto-confirm-btn').addEventListener('click', checkCryptoPaymentStatus); // Check URL for Stripe success on load const checkStripeStatus = async () => { const urlParams = new URLSearchParams(window.location.search); const sessionId = urlParams.get('session_id'); const status = urlParams.get('status'); const subscriptionStatus = urlParams.get('subscription_status'); if (sessionId && (status === 'success' || subscriptionStatus === 'success')) { showLoading(true); try { if (status === 'success') { // One-time payment const response = await fetch(`https://api.pixeloffice.eu/api/pay/verify-session?session_id=${sessionId}`); const data = await response.json(); if (data.verified) { unlockWidget(); } else { alert(`${translations[currentLang].paymentFailed}: ${data.message || 'Verification failed.'}`); } } else if (subscriptionStatus === 'success') { // Hub subscription const user = auth.currentUser; if (user) { const response = await fetch(`https://api.pixeloffice.eu/api/pay/check-subscription?email=${encodeURIComponent(user.email)}`); const data = await response.json(); if (data.active) { unlockWidget(); } else { alert(`${translations[currentLang].paymentFailed}: ${data.message || 'Subscription not active.'}`); } } else { alert(`${translations[currentLang].paymentFailed}: ${translations[currentLang].loginRequiredToVerifySubscription}`); } } } catch (error) { alert(`${translations[currentLang].paymentFailed}: ${error.message}`); console.error('Stripe verification error:', error); } finally { showLoading(false); // Clean URL window.history.replaceState({}, document.title, window.location.pathname); } } }; // Initial check on load document.addEventListener('DOMContentLoaded', () => { checkStripeStatus(); // Check for Stripe redirect updateFreeUsesText(); // Initial display of free uses if (!isUnlocked && actionsCount >= FREE_USES_LIMIT) { showPaymentOverlay(); } });