aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-06-27 19:36:54 -0700
committerAdam Soltys <[email protected]>2026-06-27 19:36:54 -0700
commit77a14981edc9b65bfce52a2e97ec99e6069e9c77 (patch)
tree2c1c7354e512f1fa3d33557c258323c56494db38
parent0a17635c93b1e7ec1b2937ece25000c518881f64 (diff)
downloadcoinosv3-77a14981edc9b65bfce52a2e97ec99e6069e9c77.tar.gz
coinosv3-77a14981edc9b65bfce52a2e97ec99e6069e9c77.zip
Wire in-app back buttons to pop browser history
The screen-changing back buttons (tx detail, gift sub-view, all-gifts, bump, account settings, accounts) now call goBack(), which does history.back() when there's an entry to pop — so they no longer push a duplicate entry. Falls back to an explicit parent-screen navigation when there's no in-app history (e.g. reloaded straight into a sub-screen). Modal-dismiss buttons (revoke, rename, password, draft) are unchanged — they don't touch nav state. Verified via CDP: detail (i=2) → in-app back → i=1 (popped) → Forward restores the detail. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
-rw-r--r--src/app.js21
1 files changed, 15 insertions, 6 deletions
diff --git a/src/app.js b/src/app.js
index 00bdbba..ce8ee13 100644
--- a/src/app.js
+++ b/src/app.js
@@ -302,6 +302,15 @@ window.addEventListener('popstate', (e) => {
}
});
+// In-app "back" buttons call this instead of mutating ui + render() directly, so
+// they POP the history entry they're leaving rather than pushing a duplicate.
+// When there's no in-app entry to pop (e.g. the page was reloaded straight into a
+// sub-screen), fall back to navigating to the explicit parent.
+function goBack(toParent) {
+ if (navIndex > 0) history.back();
+ else { toParent(); render(); }
+}
+
// ---------------------------------------------------------------- utilities
let toastTimer;
function toast(msg) {
@@ -1999,7 +2008,7 @@ function accountsScreen() {
hasVault() ? h('button', { class: 'btn-ghost btn-block', onClick: startChangePw }, t('changePassword')) : null,
h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.confirmClear = true; render(); } }, t('clearAll'))
),
- h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.screen = 'wallet'; render(); } }, t('back'))
+ h('button', { class: 'btn-ghost btn-block', onClick: () => goBack(() => { ui.screen = 'wallet'; }) }, t('back'))
);
}
@@ -2103,7 +2112,7 @@ function accountSettingsScreen() {
h('select', { onChange: (e) => { a.autoLock = Number(e.target.value) || 0; persistAccounts(); if (a.persisted) writeVault(); render(); } },
AUTOLOCK_OPTIONS.map((o) => h('option', { value: String(o.ms), selected: o.ms === accAutoLock(a) }, t(o.label))))
),
- h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.editLabel = null; ui.revealShown = false; ui.pubkeyShown = false; ui.loadSeed = null; ui.screen = 'accounts'; render(); } }, t('back'))
+ h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.editLabel = null; ui.revealShown = false; ui.pubkeyShown = false; ui.loadSeed = null; goBack(() => { ui.screen = 'accounts'; }); } }, t('back'))
);
}
@@ -2383,7 +2392,7 @@ function giftView() {
'div',
{ class: 'col', style: 'gap:12px' },
giftCard(),
- h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.giftMode = false; ui.giftCode = null; ui.giftError = ''; ui.giftMax = false; ui.giftSplitOffer = null; ui.revokeId = null; render(); } }, t('back'))
+ h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.giftCode = null; ui.giftError = ''; ui.giftMax = false; ui.giftSplitOffer = null; ui.revokeId = null; goBack(() => { ui.giftMode = false; }); } }, t('back'))
);
}
@@ -2563,7 +2572,7 @@ function bumpView() {
),
(ui.sendError || planErr) && h('div', { class: 'notice err' }, ui.sendError || planErr),
h('div', { class: 'row gap6' },
- h('button', { class: 'btn-ghost', onClick: () => { ui.bump = null; ui.sendError = ''; render(); } }, t('back')),
+ h('button', { class: 'btn-ghost', onClick: () => { ui.sendError = ''; goBack(() => { ui.bump = null; }); } }, t('back')),
ui.busy
? h('button', { class: 'btn-primary grow', disabled: true }, h('span', { class: 'spinner' }))
: h('button', { class: 'btn-primary grow', disabled: !newFee, onClick: doBump }, t('replaceTx'))
@@ -3050,7 +3059,7 @@ function giftsAllView(gifts) {
{ class: 'card col', style: 'gap:12px' },
h('div', { class: 'row between' },
h('h3', { style: 'margin:0' }, t('giftReserved', { n: gifts.length })),
- h('button', { class: 'btn-sm', onClick: () => { ui.giftsAll = false; ui.revokeId = null; render(); } }, t('back'))
+ h('button', { class: 'btn-sm', onClick: () => { ui.revokeId = null; goBack(() => { ui.giftsAll = false; }); } }, t('back'))
),
h('div', { class: 'list' }, ...slice.map(giftHistoryItem)),
pager(page, gifts.length, (p) => { ui.giftsPage = p; render(); })
@@ -3170,7 +3179,7 @@ function txDetailView(tx) {
? h('button', { class: 'btn-primary btn-block', disabled: true }, h('span', { class: 'spinner' }))
: h('button', { class: 'btn-primary btn-block', onClick: () => bumpFee(tx.txid) }, t('bumpFee')))
: null,
- h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.txDetail = null; render(); } }, t('backToHistory'))
+ h('button', { class: 'btn-ghost btn-block', onClick: () => goBack(() => { ui.txDetail = null; }) }, t('backToHistory'))
);
}