From fc054510669f1e1017f985df11f603f0efe47b9b Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Tue, 16 Jun 2026 00:20:52 -0700 Subject: Persist payment-received ack across reloads; footer + README - The "Payment received!" celebration now persists: the acknowledged fresh index is stored (per seed) in localStorage, so a received payment keeps showing the dialog until you tap past it, even after a refresh. - Footer: only "GitHub" is the link now. - README rewritten for the current state (mainnet-only, realtime, Nostr sync, multi-recipient, sats default, explorer resilience, etc.). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app.js | 17 ++++++++++++----- src/wallet.js | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/app.js b/src/app.js index 3f24c1c..7a931b3 100644 --- a/src/app.js +++ b/src/app.js @@ -83,7 +83,8 @@ function footer() { ' by ', h('a', { href: 'https://adamsoltys.com', target: '_blank', rel: 'noopener' }, 'Adam Soltys'), h('span', { class: 'faint' }, ' · '), - h('a', { href: 'https://github.com/asoltys/cold', target: '_blank', rel: 'noopener' }, 'source available on GitHub') + 'source available on ', + h('a', { href: 'https://github.com/asoltys/cold', target: '_blank', rel: 'noopener' }, 'GitHub') ); } @@ -412,9 +413,15 @@ async function enterWallet(mnemonic, passphrase) { // a brand-new wallet does one full scan. if (hadCache || hadNostr) await wallet.refreshLive(); else await wallet.scan(); - // Align the acknowledged index after load so we only celebrate payments - // that land while watching (not historical reconciliation). - ui.receiveSeenIndex = wallet.nextReceiveIndex; + // Persisted acknowledgement: first time, baseline to the current index so we + // don't celebrate historical payments. After that, any advance beyond the + // acknowledged index shows the celebration (and survives refreshes). + let ack = wallet.getReceiveAck(); + if (ack == null) { + ack = wallet.nextReceiveIndex; + wallet.setReceiveAck(ack); + } + ui.receiveSeenIndex = ack; wallet.startRealtime(); } catch { enterOfflineFallback(); @@ -658,7 +665,7 @@ function receiveTab() { { class: 'card col', style: 'align-items:center;text-align:center;gap:14px;cursor:pointer;padding:48px 20px', - onClick: () => { ui.receiveSeenIndex = wallet.nextReceiveIndex; render(); }, + onClick: () => { ui.receiveSeenIndex = wallet.nextReceiveIndex; wallet.setReceiveAck(wallet.nextReceiveIndex); render(); }, }, h('div', { class: 'check-badge' }, '✓'), h('h2', { style: 'margin:0' }, 'Payment received!'), diff --git a/src/wallet.js b/src/wallet.js index c57149f..f47d2f1 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -767,6 +767,24 @@ export class Wallet { return 'btc-wallet-cache:' + hex.encode(sha256(bytes)).slice(0, 32); } + // The fresh receive index the user has acknowledged (tapped past the + // "payment received" screen for). Persisted so a received payment keeps + // showing the celebration until acknowledged, even across refreshes. + getReceiveAck() { + try { + const v = localStorage.getItem(this._cacheKey() + ':ack'); + return v == null ? null : Number(v); + } catch { + return null; + } + } + + setReceiveAck(i) { + try { + localStorage.setItem(this._cacheKey() + ':ack', String(i)); + } catch {} + } + // The serializable wallet state, shared by the localStorage cache and the // Nostr sync. savedAt lets us pick the newest copy across devices. _snapshot() { -- cgit v1.2.3