aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.js28
-rw-r--r--src/features/ark.js6
-rw-r--r--src/i18n.js3
3 files changed, 34 insertions, 3 deletions
diff --git a/src/app.js b/src/app.js
index 8f5c622..b7892ea 100644
--- a/src/app.js
+++ b/src/app.js
@@ -2699,15 +2699,21 @@ function onboardScreen() {
if (addr && addr !== o.enterAddr && !/^npub1/.test(addr)) {
// The avatar ask is for brand-new profiles. An identity that already
// wears a face (a nostr login with a published picture) skips straight
- // to done — the punk picker restyling a real profile helps nobody.
+ // past the punk picker — restyling a real profile helps nobody.
const me = (featureHook('nostrLoginIdentity') || {}).pubkey || (wallet.nostrPubkey && wallet.nostrPubkey());
const prof = me ? featureHook('cachedProfile', me) : null;
- o.step = prof && prof.picture ? 'success' : 'avatar';
+ o.step = prof && prof.picture ? nextAfterAvatar() : 'avatar';
}
}
try { localStorage.setItem(ONB_STEP_KEY, o.step); } catch {}
const page = (kids) => h('div', { class: 'col onb', style: 'gap:20px' }, ...kids);
const title = (txt) => h('h2', { class: 'onb-title' }, txt);
+ // After the identity niceties: offer a first top-up when Savings can fund
+ // one and Spending is empty-handed — a spending account with nothing in it
+ // is a demo, not a wallet.
+ const nextAfterAvatar = () =>
+ (featureHook('arkReady') && wallet.spendable > 1000 && (featureHook('spendingSat') || 0) < 1000)
+ ? 'board' : 'success';
if (o.step === 'legacy') {
// The migrate link carries this wallet's payment address, which the
@@ -2852,7 +2858,7 @@ function onboardScreen() {
try { await featureHook('publishProfile', fields, { fillOnly: o.avatar ? ['name'] : ['name', 'picture'] }); }
catch (e) { toast(t('onbProfileSkipped')); console.warn('onboarding: profile publish failed —', e.message); }
}
- o.step = 'success';
+ o.step = nextAfterAvatar();
} catch (e) { ui.onbError = e.message; }
ui.onbBusy = false; render();
} }, ui.onbBusy ? h('span', { class: 'spinner sm' }) : (o.avatar ? t('onbContinue') : t('onbSkipAvatar'))),
@@ -2864,6 +2870,16 @@ function onboardScreen() {
} }, t('back')),
]);
}
+ if (o.step === 'board') {
+ return page([
+ title(t('onbBoardTitle')),
+ h('p', { class: 'muted', style: 'margin:0' }, t('onbBoardBody')),
+ featureHook('arkBoardForm')
+ || h('div', { class: 'row gap6', style: 'align-items:center;justify-content:center' },
+ h('span', { class: 'spinner sm' }), h('span', { class: 'small muted' }, t('arkConnecting'))),
+ h('button', { class: 'btn-primary btn-block', style: 'padding:14px', onClick: () => { o.step = 'success'; render(); } }, t('onbContinue')),
+ ]);
+ }
// success
return page([
h('div', { class: 'onb-confetti' }, ...Array.from({ length: 18 }, () => h('i'))),
@@ -3162,6 +3178,12 @@ function balanceCard() {
// of the niceties can't take it away — then walks the username + avatar
// steps, since a spending account is best enjoyed with a payment address.
// (Explicit latches carry a timestamp; self-heal only eats legacy booleans.)
+ // A Spending face running on fumes while Savings sits comfortable gets a
+ // one-tap top-up into the board panel.
+ hasSpending && isSpending && !ui.arkMoveOpen && spending < 1000 && wallet.spendable > 1000
+ && featureHook('arkReady') && !wallet.watchOnly
+ ? h('button', { class: 'btn-sm', style: 'margin-top:10px', onClick: () => { ui.arkMoveDir = 'toSpending'; ui.arkMoveOpen = true; render(); } }, t('topUpFromSavings'))
+ : null,
!hasSpending && !kindLocked && featureHook('arkReady') && !wallet.watchOnly && acc0 && acc0.type === 'full'
? h('button', { class: 'btn-sm', style: 'margin-top:10px', onClick: () => {
acc0.spendingSetup = Date.now();
diff --git a/src/features/ark.js b/src/features/ark.js
index 223fe3e..cdac6c4 100644
--- a/src/features/ark.js
+++ b/src/features/ark.js
@@ -2133,6 +2133,12 @@ export function arkFeature(ctx) {
canLnPay() { return arkAvailable() && !wallet.watchOnly && !!(ark && ark.info); },
lnSpendableSat() { const b = arkBalance(); return b ? b.spendableSat : 0; },
settingsCards() { return [autoWithdrawCard()]; },
+ // The onboarding wizard's top-up step borrows the board form wholesale.
+ arkBoardForm() {
+ if (!arkAvailable() || wallet.watchOnly) return null;
+ if (!ark) { connectArk().catch(() => {}); return null; }
+ return boardForm();
+ },
// A payment wants more Spending than exists: open the board panel with a
// prefill that nets out to the need (gross of the board fee, with a bit
// of routing headroom) — editable, so boarding extra is one keystroke.
diff --git a/src/i18n.js b/src/i18n.js
index 7be09ed..56da989 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -196,6 +196,9 @@ const STR = {
msgSearchPlaceholder: 'Name or npub…',
zapNoBalance: "There's not enough in Spending to send a zap — move some money into Spending first.",
zapBoardBtn: 'Move sats into Spending',
+ onbBoardTitle: 'Top up Spending',
+ onbBoardBody: 'Move some sats from Savings into Spending — payments there are instant, with no mining fees.',
+ topUpFromSavings: 'Top up from Savings',
msgPushOffer: 'Get notified when you receive payments and messages, even with coinos closed.',
msgPushEnable: 'Enable notifications',
msgPushOn: 'Notifications on',