Factor out NoteZap from NoteActions

This commit is contained in:
Jonathan Staab 2023-04-21 11:12:36 -05:00
parent 66b16c4db4
commit fa1211a2fd
4 changed files with 124 additions and 116 deletions

View File

@ -11,6 +11,7 @@
import LoginPubKey from "src/app/views/LoginPubKey.svelte"
import Onboarding from "src/app/views/Onboarding.svelte"
import NoteCreate from "src/app/views/NoteCreate.svelte"
import NoteZap from "src/app/views/NoteZap.svelte"
import NoteDetail from "src/app/views/NoteDetail.svelte"
import PersonFeed from "src/app/views/PersonFeed.svelte"
import PersonList from "src/app/shared/PersonList.svelte"
@ -39,6 +40,8 @@
{/key}
{:else if m.type === "note/create"}
<NoteCreate pubkey={m.pubkey} nevent={m.nevent} />
{:else if m.type === "note/zap"}
<NoteZap note={m.note} />
{:else if m.type === "relay/add"}
<RelayAdd url={m.url} />
{:else if m.type === "onboarding"}

View File

@ -111,7 +111,6 @@
return () => {
clearInterval(interval)
actions.cleanupZap()
}
})
</script>

View File

@ -3,29 +3,22 @@
import {nip19} from "nostr-tools"
import {tweened} from "svelte/motion"
import {find, reject, identity, propEq, pathEq, sum, pluck, sortBy} from "ramda"
import {warn} from "src/util/logger"
import {copyToClipboard} from "src/util/html"
import {stringToHue, fetchJson, now, formatSats, hsl} from "src/util/misc"
import {displayRelay, isLike, displayPerson, processZaps} from "src/util/nostr"
import {stringToHue, formatSats, hsl} from "src/util/misc"
import {displayRelay, isLike, processZaps} from "src/util/nostr"
import {quantify, first} from "hurdak/lib/hurdak"
import {toast, modal} from "src/partials/state"
import Popover from "src/partials/Popover.svelte"
import QRCode from "src/partials/QRCode.svelte"
import Content from "src/partials/Content.svelte"
import Modal from "src/partials/Modal.svelte"
import Anchor from "src/partials/Anchor.svelte"
import OverflowMenu from "src/partials/OverflowMenu.svelte"
import CopyValue from "src/partials/CopyValue.svelte"
import PersonBadge from "src/app/shared/PersonBadge.svelte"
import Input from "src/partials/Input.svelte"
import Textarea from "src/partials/Textarea.svelte"
import RelayCard from "src/app/shared/RelayCard.svelte"
import {getEventPublishRelays} from "src/agent/relays"
import {getPersonWithFallback} from "src/agent/db"
import network from "src/agent/network"
import pool from "src/agent/pool"
import user from "src/agent/user"
import keys from "src/agent/keys"
import cmd from "src/agent/cmd"
export let note
@ -66,78 +59,11 @@
}
const startZap = () => {
draftZap = {
amount: user.getSetting("defaultZap"),
message: "",
invoice: null,
loading: false,
startedAt: now(),
confirmed: false,
}
}
const loadZapInvoice = async () => {
draftZap.loading = true
const {zapper, lnurl} = $author
const amount = draftZap.amount * 1000
const relays = getEventPublishRelays(note)
const urls = pluck("url", relays)
const publishable = cmd.requestZap(urls, draftZap.message, note.pubkey, note.id, amount, lnurl)
const event = encodeURI(JSON.stringify(await keys.sign(publishable.event)))
const res = await fetchJson(`${zapper.callback}?amount=${amount}&nostr=${event}&lnurl=${lnurl}`)
// If they closed the dialog before fetch resolved, we're done
if (!draftZap) {
return
}
if (!res.pr) {
throw new Error(JSON.stringify(res))
}
draftZap.invoice = res.pr
draftZap.loading = false
// Open up alby or whatever
const {webln} = window as {webln?: any}
if (webln) {
await webln.enable()
try {
webln.sendPayment(draftZap.invoice)
} catch (e) {
warn(e)
}
}
// Listen for the zap confirmation
draftZap.sub = network.listen({
relays,
filter: {
kinds: [9735],
authors: [zapper.nostrPubkey],
"#p": [$author.pubkey],
since: draftZap.startedAt - 10,
},
onChunk: chunk => {
zap = first(chunk)
draftZap.confirmed = true
setTimeout(cleanupZap, 1000)
},
})
}
export const cleanupZap = () => {
if (draftZap) {
draftZap.sub?.then(s => s.unsub())
draftZap = null
}
modal.push({type: "note/zap", note})
}
let like, likes, allLikes, zap, zaps, allZaps
let actions = []
let draftZap = null
let showDetails = false
$: disableActions = !$canPublish || muted
@ -250,44 +176,6 @@
</div>
</div>
{#if draftZap}
<Modal onEscape={cleanupZap}>
<Content size="lg">
<div class="text-center">
<h1 class="staatliches text-2xl">Send a zap</h1>
<p>to {displayPerson($author)}</p>
</div>
{#if draftZap.confirmed}
<div class="flex items-center justify-center gap-2 text-gray-1">
<i class="fa fa-champagne-glasses" />
<p>Success! Zap confirmed.</p>
</div>
{:else if draftZap.invoice}
<QRCode code={draftZap.invoice} />
<p class="text-center text-gray-1">
Copy or scan using a lightning wallet to pay your zap.
</p>
<div class="flex items-center justify-center gap-2 text-gray-1">
<i class="fa fa-circle-notch fa-spin" />
Waiting for confirmation...
</div>
{:else}
<Textarea bind:value={draftZap.message} placeholder="Add an optional message" />
<div class="flex items-center gap-2">
<label class="flex-grow">Custom amount:</label>
<Input bind:value={draftZap.amount}>
<i slot="before" class="fa fa-bolt" />
<span slot="after" class="-mt-1">sats</span>
</Input>
<Anchor loading={draftZap.loading} type="button-accent" on:click={loadZapInvoice}>
Zap!
</Anchor>
</div>
{/if}
</Content>
</Modal>
{/if}
{#if showDetails}
<Modal
onEscape={() => {

View File

@ -0,0 +1,118 @@
<script lang="ts">
import {onDestroy} from "svelte"
import {pluck} from "ramda"
import {warn} from "src/util/logger"
import {fetchJson, now} from "src/util/misc"
import {displayPerson} from "src/util/nostr"
import {modal} from "src/partials/state"
import QRCode from "src/partials/QRCode.svelte"
import Content from "src/partials/Content.svelte"
import Anchor from "src/partials/Anchor.svelte"
import Input from "src/partials/Input.svelte"
import Textarea from "src/partials/Textarea.svelte"
import {getEventPublishRelays} from "src/agent/relays"
import {getPersonWithFallback} from "src/agent/db"
import network from "src/agent/network"
import user from "src/agent/user"
import keys from "src/agent/keys"
import cmd from "src/agent/cmd"
export let note
let sub
let zap = {
amount: user.getSetting("defaultZap"),
message: "",
invoice: null,
loading: false,
startedAt: now(),
confirmed: false,
}
const author = getPersonWithFallback(note.pubkey)
const loadZapInvoice = async () => {
zap.loading = true
const {zapper, lnurl} = author
const amount = zap.amount * 1000
const relays = getEventPublishRelays(note)
const urls = pluck("url", relays)
const publishable = cmd.requestZap(urls, zap.message, note.pubkey, note.id, amount, lnurl)
const event = encodeURI(JSON.stringify(await keys.sign(publishable.event)))
const res = await fetchJson(`${zapper.callback}?amount=${amount}&nostr=${event}&lnurl=${lnurl}`)
// If they closed the dialog before fetch resolved, we're done
if (!zap) {
return
}
if (!res.pr) {
throw new Error(JSON.stringify(res))
}
zap.invoice = res.pr
zap.loading = false
// Open up alby or whatever
const {webln} = window as {webln?: any}
if (webln) {
await webln.enable()
try {
webln.sendPayment(zap.invoice)
} catch (e) {
warn(e)
}
}
// Listen for the zap confirmation
sub = network.listen({
relays,
filter: {
kinds: [9735],
authors: [zapper.nostrPubkey],
"#p": [note.pubkey],
since: zap.startedAt - 10,
},
onChunk: chunk => {
zap.confirmed = true
setTimeout(() => modal.pop(), 1000)
},
})
}
onDestroy(() => {
sub?.then(s => s.unsub())
})
</script>
<Content size="lg">
<div class="text-center">
<h1 class="staatliches text-2xl">Send a zap</h1>
<p>to {displayPerson(author)}</p>
</div>
{#if zap.confirmed}
<div class="flex items-center justify-center gap-2 text-gray-1">
<i class="fa fa-champagne-glasses" />
<p>Success! Zap confirmed.</p>
</div>
{:else if zap.invoice}
<QRCode code={zap.invoice} />
<p class="text-center text-gray-1">Copy or scan using a lightning wallet to pay your zap.</p>
<div class="flex items-center justify-center gap-2 text-gray-1">
<i class="fa fa-circle-notch fa-spin" />
Waiting for confirmation...
</div>
{:else}
<Textarea bind:value={zap.message} placeholder="Add an optional message" />
<div class="flex items-center gap-2">
<label class="flex-grow">Custom amount:</label>
<Input bind:value={zap.amount}>
<i slot="before" class="fa fa-bolt" />
<span slot="after" class="-mt-1">sats</span>
</Input>
<Anchor loading={zap.loading} type="button-accent" on:click={loadZapInvoice}>Zap!</Anchor>
</div>
{/if}
</Content>