diff options
| author | Adam Soltys <[email protected]> | 2026-06-24 14:01:39 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-06-24 14:01:39 -0700 |
| commit | 1a92d81b792f9e6d2ecb284aab979985a36d34c7 (patch) | |
| tree | e5b358bcad0ba648363f373f9aa87e4c2f65045a /src/app.js | |
| parent | b78b9a1c7e4e42b7f673b0e3f92424a762bd0986 (diff) | |
| download | coinosv3-1a92d81b792f9e6d2ecb284aab979985a36d34c7.tar.gz coinosv3-1a92d81b792f9e6d2ecb284aab979985a36d34c7.zip | |
Keep reclaimed gifts revocable until the coin is spent
Passive reclaim previously dropped the coin from tracking, so there was
no way to revoke afterward. Now reclaim moves the coin from "reserved"
to a "reclaimed" set: it becomes spendable, but its still-live link
stays listed (tagged "still claimable") with a Revoke option, until the
coin is actually spent (by a payment or by revoking), at which point it
drops off. revokeGift and outstandingGifts handle both sets; existing
reserved gifts are unaffected. Strings updated across all 19 locales.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Diffstat (limited to 'src/app.js')
| -rw-r--r-- | src/app.js | 18 |
1 files changed, 9 insertions, 9 deletions
@@ -722,7 +722,7 @@ function createGiftLink() { render(); } function giftCard() { - const active = wallet.activeGifts(); + const active = wallet.outstandingGifts(); return h( 'div', { class: 'card col' }, @@ -750,24 +750,24 @@ function giftCard() { active.length ? h('div', { class: 'col gap6', style: 'margin-top:4px' }, h('span', { class: 'small muted' }, t('giftReserved', { n: active.length })), - ...active.map((id) => { - const u = wallet.utxos.find((x) => utxoId(x) === id); - const label = u ? fmtAmount(u.value) + ' ' + unitLabel() : id.slice(0, 12) + '…'; - if (ui.revokeId === id) { + ...active.map((g) => { + const amt = g.value != null ? fmtAmount(g.value) + ' ' + unitLabel() : g.id.slice(0, 12) + '…'; + const label = amt + (g.reserved ? '' : ' · ' + t('giftReclaimedTag')); + if (ui.revokeId === g.id) { return h('div', { class: 'col gap6' }, - h('span', { class: 'small muted' }, t('giftReclaimPrompt')), + h('span', { class: 'small muted' }, g.reserved ? t('giftReclaimPrompt') : t('giftRevokeConfirm')), ui.busy ? h('button', { class: 'btn-primary btn-block', disabled: true }, h('span', { class: 'spinner' })) : h('div', { class: 'row gap6' }, - h('button', { class: 'btn-ghost grow', onClick: () => doReclaim(id) }, t('giftReclaim')), - h('button', { class: 'btn-primary grow', onClick: () => doRevoke(id) }, t('giftRevoke')) + g.reserved ? h('button', { class: 'btn-ghost grow', onClick: () => doReclaim(g.id) }, t('giftReclaim')) : null, + h('button', { class: 'btn-primary grow', onClick: () => doRevoke(g.id) }, t('giftRevoke')) ), ui.busy ? null : h('button', { class: 'btn-ghost btn-block', onClick: () => { ui.revokeId = null; render(); } }, t('back')) ); } return h('div', { class: 'row between' }, h('span', { class: 'small mono' }, label), - h('button', { class: 'btn-sm', onClick: () => { ui.revokeId = id; render(); } }, t('giftReclaim')) + h('button', { class: 'btn-sm', onClick: () => { ui.revokeId = g.id; render(); } }, g.reserved ? t('giftReclaim') : t('giftRevoke')) ); }) ) |
