diff options
| author | Adam Soltys <[email protected]> | 2026-08-02 18:43:56 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-02 18:43:56 -0700 |
| commit | 375bec5f2ee22b1f69bb9f4a963efb12a68aef05 (patch) | |
| tree | 3b8f3fe0c9c78a82996ad08375760c7281111fcb /src/features/ark.js | |
| parent | 8da44392be513929802a5f4329b29bfa125aaa04 (diff) | |
| download | coinosv3-375bec5f2ee22b1f69bb9f4a963efb12a68aef05.tar.gz coinosv3-375bec5f2ee22b1f69bb9f4a963efb12a68aef05.zip | |
Profiles: view pages, editable own kind 0, zap recipients in history
Tapping any avatar or author name (chat rooms, DM threads, the chat
home) opens a profile page: avatar, name, nip05, lightning address,
about, npub, with Message and Pay actions (Pay runs the npub payment
cascade). Your own profile — reachable from your avatar on the chat
home — gets an editor for name, about, picture, and lightning address
(prefilled with your coinos address); saving merges over the newest
published kind 0 so fields we don't understand survive the round trip.
Zaps now remember who they went to: the ark feature keys the recipient
by what the movement already records (destination address or invoice)
and history rows wear a clickable avatar chip that opens the profile.
The messages feature exposes showProfile/profileChip seams so any
feature can do the same.
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
Diffstat (limited to 'src/features/ark.js')
| -rw-r--r-- | src/features/ark.js | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/src/features/ark.js b/src/features/ark.js index 3613b02..c81faa5 100644 --- a/src/features/ark.js +++ b/src/features/ark.js @@ -645,6 +645,7 @@ export function arkFeature(ctx) { const settle = (a) => { if (a.step === 'done') { ui.arkLnPaid = { amountSat: a.amountSat, meta: p.meta }; + if (p.meta && p.meta.pk) noteZap('inv:' + p.invoice, p.meta.pk); ui.arkLnPay = null; } else if (ui.arkLnPay) { ui.arkLnPay.status = 'ready'; @@ -732,6 +733,22 @@ export function arkFeature(ctx) { } + // Who a zap went to, keyed by what the movement records (the ark address + // for direct zaps, the invoice for Lightning ones) — enough to put a face + // on history rows without touching the manager's movement schema. + const zapNotes = () => wallet.loadFeatureState('zapnotes', {}); + function noteZap(key, pk) { + const s = zapNotes(); + s[key] = pk; + const keys = Object.keys(s); + if (keys.length > 200) for (const k of keys.slice(0, keys.length - 200)) delete s[k]; + wallet.saveFeatureState('zapnotes', s); + } + const zapNoteFor = (m) => + m.type === 'send' && m.to ? zapNotes()['to:' + m.to] + : m.type === 'ln-send' && m.invoice ? zapNotes()['inv:' + m.invoice] + : null; + function arkHistoryItem(m) { const incoming = !['send', 'offboard', 'exit', 'ln-send'].includes(m.type); const label = m.type === 'receive' ? t('received') : m.type === 'board' ? t('arkBoarded') @@ -746,8 +763,9 @@ export function arkFeature(ctx) { ? h('div', { class: `ico ${incoming ? 'in' : 'out'}` }, '⚡') : h('div', { class: `ico ${incoming ? 'in' : 'out'}`, html: ARK_MARK(15) }), h('div', { class: 'grow' }, - h('div', { class: 'row gap6' }, + h('div', { class: 'row gap6', style: 'align-items:center' }, label, + (() => { const pk = zapNoteFor(m); return pk ? ctx.hook('profileChip', pk) : null; })(), m.status !== 'complete' ? h('span', { class: 'tag pending' }, m.status) : null), h('div', { class: 'small faint' }, timeAgo(m.ts / 1000))), h('div', { style: 'text-align:right' }, @@ -973,6 +991,7 @@ export function arkFeature(ctx) { const action = mgr.state.actions.find((a) => a.id === actionId); if (!action || action.step === 'failed') throw new Error(action?.error || t('claimFailed')); const vtxoId = decodeVtxo(hex.decode((action.destBytesList || [action.destBytes])[0])).id; + noteZap('to:' + z.address, z.pk); // the receipt is best-effort: the sats are already delivered via mailbox await wallet.nostrPublish({ kind: ARK_ZAP_KIND, |
