diff --git a/index.html b/index.html index e4174a1..294c2a3 100644 --- a/index.html +++ b/index.html @@ -639,7 +639,61 @@ window.addEventListener('popstate', () => { fetchMinAmount(); }); +// After an invoice is shown, ask the server page every 30 seconds whether the +// payment has been seen, so the visitor does not have to reload. The status only +// moves forward: unconfirmed_balance may go back to 0 before the deposit is +// credited, and that must not look as if the payment had disappeared. +const DEPOSIT_POLL_MS = 30000; +const DEPOSIT_POLL_MAX_MS = 24 * 60 * 60 * 1000; +let depositWatch = null; + +function stopDepositWatch() { + if (depositWatch) clearInterval(depositWatch.timer); + depositWatch = null; +} + +async function pollDeposit() { + const watch = depositWatch; + if (!watch) return; + if (Date.now() - watch.started > DEPOSIT_POLL_MAX_MS) return stopDepositWatch(); + let data; + try { + const response = await fetch(`/weinfodata/${watch.chain}/${watch.id}`); + if (!response.ok) return; + data = await response.json(); + } catch (err) { + return; // temporary network problem: try again at the next round + } + if (watch !== depositWatch || !data) return; + const expiry = data.expiry_date || null; + // The first answer is the reference: listing or renewal changes the expiry date. + if (watch.expiry === undefined) watch.expiry = expiry; + const status = document.getElementById('iv-status'); + const bal = data.balance != null ? fmt(data.balance) : null; + const unc = data.unconfirmed_balance != null ? fmt(data.unconfirmed_balance) : null; + if (bal) document.getElementById('iv-balance').textContent = unc ? bal + ' (' + unc + ')' : bal; + if (expiry && expiry !== watch.expiry) { + status.className = 'ok-line'; + status.textContent = '✓ Payment confirmed: your server is now listed.'; + stopDepositWatch(); + fetchData(); + } else if (Number(data.unconfirmed_balance) > 0 && !watch.detected) { + watch.detected = true; + status.className = 'ok-line'; + status.textContent = 'Payment detected: ' + fmt(data.unconfirmed_balance) + ' sats, waiting for 3 confirmations (about 30 minutes). This page updates by itself, or use the "Follow your payment" link below.'; + } +} + +function startDepositWatch(chain, id) { + stopDepositWatch(); + if (!id) return; + depositWatch = { chain, id, started: Date.now(), detected: false, expiry: undefined }; + depositWatch.timer = setInterval(pollDeposit, DEPOSIT_POLL_MS); + pollDeposit(); +} + document.getElementById('submit').addEventListener('click', async () => { + stopDepositWatch(); const urlInput = document.getElementById('url'); let url = urlInput.value.trim(); if (!url) return; @@ -739,6 +793,8 @@ document.getElementById('terms-accept').addEventListener('click', async function inv.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); return; } + // Fixed address: whoever pays can close this invoice and follow the deposit there. + if (weLink) weinfoEl.textContent = 'Follow your payment'; const amountSats = result.min_amount != null ? result.min_amount : minAmount; const amountBtc = (amountSats / 1e8).toFixed(8).replace(/\.?0+$/, ''); const invoiceuri = `bitcoin:${result.address}?amount=${amountBtc}&label=BAL&message=Order+For+url+%26+${encodeURIComponent(url)}`; @@ -773,6 +829,7 @@ document.getElementById('terms-accept').addEventListener('click', async function const inv = document.getElementById('invoice'); inv.classList.add('show'); inv.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); + startDepositWatch(result.chain || chain, result.id); } catch (err) { document.getElementById('iv-status').className = 'err-line'; document.getElementById('iv-status').textContent = 'Network error. Please try again.'; diff --git a/weinfo.html b/weinfo.html index 5b5da54..e95f059 100644 --- a/weinfo.html +++ b/weinfo.html @@ -36,6 +36,7 @@