diff --git a/apps/pay/src/monitor.ts b/apps/pay/src/monitor.ts
index 695573a..5e96310 100644
--- a/apps/pay/src/monitor.ts
+++ b/apps/pay/src/monitor.ts
@@ -121,13 +121,20 @@ async function handleTxEvent(event: any) {
console.log(`SSE: tx ${txHash} for payment ${payment.id}: +${txValue} ${payment.coin}`);
// Insert into payment_txs (ignore duplicate)
- await sql`
+ const [inserted] = await sql`
INSERT INTO payment_txs (payment_id, txid, amount)
VALUES (${payment.id}, ${txHash}, ${txValue.toFixed(8)})
ON CONFLICT (payment_id, txid) DO NOTHING
+ RETURNING id
`;
txidToPayment.set(txHash, payment.id);
+ // Extend expiry to 24h on first tx detection
+ if (inserted) {
+ const newExpiry = new Date(Date.now() + 24 * 60 * 60 * 1000);
+ await sql`UPDATE payments SET expires_at = ${newExpiry.toISOString()} WHERE id = ${payment.id} AND expires_at < ${newExpiry.toISOString()}`;
+ }
+
// Recalculate total received
const [{ total }] = await sql`
SELECT COALESCE(SUM(amount::numeric), 0) as total FROM payment_txs WHERE payment_id = ${payment.id}
@@ -252,16 +259,24 @@ export async function checkPayments() {
const threshold = expected * THRESHOLD;
// Sync txs from address info into payment_txs
+ let newTxDetected = false;
if (info.in?.length) {
for (const tx of info.in) {
if (!tx.txid) continue;
- await sql`
+ const [ins] = await sql`
INSERT INTO payment_txs (payment_id, txid, amount, confirmed)
VALUES (${payment.id}, ${tx.txid}, ${String(tx.amount ?? 0)}, ${tx.block != null})
ON CONFLICT (payment_id, txid) DO UPDATE SET confirmed = EXCLUDED.confirmed
+ RETURNING id
`;
+ if (ins) newTxDetected = true;
}
}
+ // Extend expiry to 24h on first tx detection
+ if (newTxDetected) {
+ const newExpiry = new Date(Date.now() + 24 * 60 * 60 * 1000);
+ await sql`UPDATE payments SET expires_at = ${newExpiry.toISOString()} WHERE id = ${payment.id} AND expires_at < ${newExpiry.toISOString()}`;
+ }
if (payment.status === "pending" || payment.status === "underpaid") {
if (coin.confirmations === 0 && received >= threshold) {
diff --git a/apps/web/src/views/checkout.ejs b/apps/web/src/views/checkout.ejs
index f5877bc..83b9b78 100644
--- a/apps/web/src/views/checkout.ejs
+++ b/apps/web/src/views/checkout.ejs
@@ -298,8 +298,14 @@
} else if (status === 'confirming') {
document.getElementById('pay-status').innerHTML = `
- Transaction detected, waiting for confirmation...
+ Transaction received, waiting for 1 confirmation...
`;
+ // Replace QR with loading spinner
+ document.getElementById('pay-qr').replaceWith(Object.assign(document.createElement('div'), {
+ id: 'pay-qr',
+ className: 'w-48 h-48 mx-auto rounded-lg bg-gray-800 flex items-center justify-center',
+ innerHTML: '',
+ }));
syncTxids(data);
} else if (status === 'paid') {
clearInterval(pollInterval);