Show deposit progress after the invoice

- The invoice checks the server every 30 seconds and shows the amount
  detected, then the confirmation once the server is listed.
- The server page gets the same banner, with a 24-hour limit on checks.
- The invoice link is now "Follow your payment", so the invoice can be
  closed and the deposit followed from a fixed address.
This commit is contained in:
2026-11-01 12:36:46 +01:00
parent aa723acbca
commit 956e133b7c
2 changed files with 121 additions and 0 deletions

View File

@@ -36,6 +36,7 @@
<h2 id="wename">&nbsp;</h2>
<h3 id="weinfo">&nbsp;</h3>
<h4 id="wechain">&nbsp;</h4>
<div id="wepayment" style="display:none;max-width:640px;margin:10px auto 18px;padding:10px 14px;border-radius:8px;font-weight:600"></div>
</div>
<div style="float:left;border:1;margin-right:50px;">
<div><span>Version:</span><span id="weversion">&nbsp;</span></div>
@@ -77,6 +78,69 @@
</div>
<a href="" id="download">Download</a>
<script type="text/javascript">
// Payment banner: this page has a fixed address, so whoever paid can close the
// invoice and follow the deposit here. It asks the server data every 30 seconds
// until the server is listed. The status only moves forward, because
// unconfirmed_balance may go back to 0 before the deposit is credited.
const PAYMENT_POLL_MS = 30000;
const PAYMENT_POLL_MAX_MS = 24 * 60 * 60 * 1000;
const paymentStarted = Date.now();
let paymentTimer = null, paymentSeen = false, paymentAmount = 0, firstExpiry;
function showPayment(text, ok) {
const box = document.getElementById('wepayment');
box.textContent = text;
box.style.display = 'block';
box.style.color = ok ? '#14703a' : '#7a5200';
box.style.background = ok ? '#e6f6ec' : '#fdf3dc';
}
function stopPayment() {
if (paymentTimer) clearInterval(paymentTimer);
paymentTimer = null;
}
async function pollPayment() {
if (Date.now() - paymentStarted > PAYMENT_POLL_MAX_MS) return stopPayment();
const path = window.location.pathname.split('/').filter(p => p !== '');
let data;
try {
const response = await fetch('/weinfodata/' + path[1] + '/' + path[2]);
if (!response.ok) return;
data = await response.json();
} catch (err) {
return; // temporary network problem: try again at the next round
}
if (!data) return;
const expiry = data.expiry_date || null;
if (firstExpiry === undefined) firstExpiry = expiry;
const unconfirmed = Number(data.unconfirmed_balance) > 0;
const active = expiry && new Date(expiry.replace(' ', 'T') + 'Z') > new Date();
const bal = data.balance != null ? data.balance : null;
const unc = data.unconfirmed_balance != null ? data.unconfirmed_balance : null;
document.getElementById('webalance').textContent = bal ? (unc ? bal + ' (' + unc + ')' : bal) : '—';
const expiryCell = document.createElement('b');
expiryCell.textContent = expiry || '—';
document.getElementById('weexpiry').replaceChildren(expiryCell);
if (expiry && expiry !== firstExpiry) {
showPayment('✓ Payment confirmed: this server is now listed.', true);
stopPayment();
} else if (unconfirmed || paymentSeen) {
paymentSeen = true;
if (unconfirmed) paymentAmount = Number(data.unconfirmed_balance);
showPayment('Payment detected: ' + paymentAmount.toLocaleString('en-US') + ' sats, waiting for 3 confirmations (about 30 minutes). This page updates by itself.', false);
} else if (active) {
stopPayment(); // already listed and nothing incoming: no banner, nothing to follow
} else {
showPayment('Waiting for payment. This page updates by itself.', false);
}
}
document.addEventListener('DOMContentLoaded', () => {
paymentTimer = setInterval(pollPayment, PAYMENT_POLL_MS);
pollPayment();
});
function getWeInfo(){
const path = window.location.pathname.split('/').filter(p => p !== '');
const we_id = path[2];