diff options
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 41 |
1 files changed, 38 insertions, 3 deletions
@@ -2199,6 +2199,7 @@ function loadWatchAccounts() { // a sign-up's Spending-only shape and its ways back in outlive the session ...(d.spendingOnly ? { kind: 'spending', savingsLater: true } : {}), ...(d.signupAt ? { signupAt: d.signupAt } : {}), + ...(d.waysBackPrompted ? { waysBackPrompted: d.waysBackPrompted } : {}), ...(Array.isArray(d.recovery) && d.recovery.length ? { recovery: d.recovery } : {}) })); } catch { return []; } } @@ -2219,6 +2220,7 @@ function saveDirectory() { return { id: a.id, label: a.label, xpub: a.xpub, autoLock: a.autoLock || 0, network: a.network, nostrPk: a.nostrPk, seedSeen: !!a.seedSeen, ...(a.kind === 'spending' && a.savingsLater ? { spendingOnly: true } : {}), ...(a.signupAt ? { signupAt: a.signupAt } : {}), + ...(a.waysBackPrompted ? { waysBackPrompted: a.waysBackPrompted } : {}), ...(a.recovery && a.recovery.length ? { recovery: a.recovery } : {}) }; }); localStorage.setItem(WATCH_KEY, JSON.stringify(dir)); @@ -5061,10 +5063,43 @@ function addRecoveryMethod(m) { } wallet.registerCacheExtension({ mergeAlways: true, - save: () => { const r = recoveryMethods(); return r.length ? { recovery: r } : {}; }, - load: (d) => { if (d && d.recovery) mergeRecovery(d.recovery); }, + save: () => { + const a = activeAccount(), r = recoveryMethods(); + return { ...(r.length ? { recovery: r } : {}), ...(a && a.waysBackPrompted ? { waysBackPrompted: a.waysBackPrompted } : {}) }; + }, + load: (d) => { + if (!d) return; + if (d.recovery) mergeRecovery(d.recovery); + // asked on another device: asked (only ever turns on) + const a = activeAccount(); + if (d.waysBackPrompted && a && !a.waysBackPrompted) { a.waysBackPrompted = d.waysBackPrompted; persistAccounts(); } + }, }); +// A sign-up is asked for a way back in ONCE, and only when there's something +// to lose (Adam, 2026-11-15: "only prompt to add a way back in after there's +// some balance and only if we haven't prompted before"). The ask is recorded +// the moment it first shows — on the account, the directory and the synced +// snapshot — and stays up for that visit until Add one or Not now. +function waysBackPrompt(a) { + if (recoveryMethods(a).length) { if (ui.waysBackPromptFor === a.id) ui.waysBackPromptFor = null; return null; } + if (ui.waysBackPromptFor !== a.id) { + if (a.waysBackPrompted || !wallet.loaded) return null; + const bal = (featureHook('spendingSat') || 0) + (wallet.spendable || 0) + (wallet.pendingIncoming || 0); + if (bal <= 0) return null; + a.waysBackPrompted = Date.now(); + persistAccounts(); + try { wallet.saveCache(); } catch {} + ui.waysBackPromptFor = a.id; + } + const done = () => { ui.waysBackPromptFor = null; }; + return h('div', { class: 'notice info col ways-back-prompt', style: 'margin:12px 0 0;gap:10px' }, + h('span', {}, t('waysBackPrompt')), + h('div', { class: 'row gap6' }, + h('button', { class: 'btn-sm btn-primary', onClick: () => { done(); ui.tab = 'settings'; ui.settingsPage = 'wallet'; render(); } }, t('waysBackReminderGo')), + h('button', { class: 'btn-sm btn-ghost', onClick: () => { done(); render(); } }, t('onbNotNow')))); +} + // A wallet whose recovery phrase has never been on screen keeps one quiet // line about it. "Later" is a real answer, so this is a row and not a modal — // but it doesn't dismiss, because the risk doesn't go away on its own. It @@ -5076,7 +5111,7 @@ function backupNotice() { // A sign-up never saw a phrase and wasn't asked to: what it needs is A way // back in, any one — and once it has one, nothing to nag about. const signup = !!a.signupAt; - if (signup && recoveryMethods(a).length) return null; + if (signup) return waysBackPrompt(a); return h('div', { class: 'small muted', style: 'margin:10px 0 0;text-align:center' }, t(signup ? 'waysBackReminder' : 'backupReminder'), ' ', |
