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);