Fix a few bugs, add zaps to alerts

This commit is contained in:
Jonathan Staab 2023-03-02 15:56:21 -06:00
parent 12201b7967
commit 71eaf25045
8 changed files with 53 additions and 15 deletions

View File

@ -1,6 +1,5 @@
# Current # Current
- [ ] Add zaps to notifications
- [ ] Try adding boxes/separation on feeds based on user feedback - [ ] Try adding boxes/separation on feeds based on user feedback
- [ ] Strip zero width spaces from compose - [ ] Strip zero width spaces from compose
- [ ] Fix iOS/safari/firefox - [ ] Fix iOS/safari/firefox

View File

@ -3,7 +3,7 @@ import {nip05} from 'nostr-tools'
import {getParams} from 'js-lnurl' import {getParams} from 'js-lnurl'
import {noop, createMap, ensurePlural, chunk, switcherFn} from 'hurdak/lib/hurdak' import {noop, createMap, ensurePlural, chunk, switcherFn} from 'hurdak/lib/hurdak'
import {log} from 'src/util/logger' import {log} from 'src/util/logger'
import {hexToBech32, now, sleep, tryJson, timedelta, shuffle, hash} from 'src/util/misc' import {hexToBech32, tryFetch, now, sleep, tryJson, timedelta, shuffle, hash} from 'src/util/misc'
import {Tags, roomAttrs, personKinds, isRelay, isShareableRelay, normalizeRelayUrl} from 'src/util/nostr' import {Tags, roomAttrs, personKinds, isRelay, isShareableRelay, normalizeRelayUrl} from 'src/util/nostr'
import database from 'src/agent/database' import database from 'src/agent/database'
@ -321,10 +321,12 @@ const verifyZapper = async (pubkey, address) => {
} }
const url = `https://${domain}/.well-known/lnurlp/${name}` const url = `https://${domain}/.well-known/lnurlp/${name}`
const res = await fetch(url) const res = await tryFetch(() => fetch(url))
zapper = await res.json() if (res) {
lnurl = hexToBech32('lnurl', url) zapper = await res.json()
lnurl = hexToBech32('lnurl', url)
}
} }
if (zapper?.allowsNostr && zapper?.nostrPubkey) { if (zapper?.allowsNostr && zapper?.nostrPubkey) {

View File

@ -1,3 +1,4 @@
import type {DisplayEvent} from 'src/util/types'
import {max, find, pluck, propEq, partition, uniq} from 'ramda' import {max, find, pluck, propEq, partition, uniq} from 'ramda'
import {derived} from 'svelte/store' import {derived} from 'svelte/store'
import {createMap} from 'hurdak/lib/hurdak' import {createMap} from 'hurdak/lib/hurdak'
@ -9,6 +10,13 @@ import network from 'src/agent/network'
let listener let listener
type AlertEvent = DisplayEvent & {
zappedBy?: Array<string>
likedBy: Array<string>
repliesFrom: Array<string>
isMention: boolean
}
// State // State
const seenAlertIds = synced('app/alerts/seenAlertIds', []) const seenAlertIds = synced('app/alerts/seenAlertIds', [])
@ -52,8 +60,8 @@ const processAlerts = async (pubkey, events) => {
const parents = createMap('id', await network.loadParents(events)) const parents = createMap('id', await network.loadParents(events))
const asAlert = e => const asAlert = (e): AlertEvent =>
asDisplayEvent({...e, repliesFrom: [], likedBy: [], isMention: false}) ({repliesFrom: [], likedBy: [], zappedBy: [], isMention: false, ...asDisplayEvent(e)})
const isPubkeyChild = e => { const isPubkeyChild = e => {
const parentId = findReplyId(e) const parentId = findReplyId(e)
@ -61,19 +69,27 @@ const processAlerts = async (pubkey, events) => {
return parents[parentId]?.pubkey === pubkey return parents[parentId]?.pubkey === pubkey
} }
const [likes, notes] = partition(propEq('kind', 7), events) const [replies, mentions] = partition(isPubkeyChild, events.filter(propEq('kind', 1)))
const [replies, mentions] = partition(isPubkeyChild, notes) const likes = events.filter(propEq('kind', 7))
const zaps = events.filter(propEq('kind', 9735))
zaps.filter(isPubkeyChild).forEach(e => {
const parent = parents[findReplyId(e)]
const note = asAlert(database.alerts.get(parent.id) || parent)
database.alerts.put({...note, zappedBy: uniq(note.zappedBy.concat(e.pubkey))})
})
likes.filter(isPubkeyChild).forEach(e => { likes.filter(isPubkeyChild).forEach(e => {
const parent = parents[findReplyId(e)] const parent = parents[findReplyId(e)]
const note = database.alerts.get(parent.id) || asAlert(parent) const note = asAlert(database.alerts.get(parent.id) || parent)
database.alerts.put({...note, likedBy: uniq(note.likedBy.concat(e.pubkey))}) database.alerts.put({...note, likedBy: uniq(note.likedBy.concat(e.pubkey))})
}) })
replies.forEach(e => { replies.forEach(e => {
const parent = parents[findReplyId(e)] const parent = parents[findReplyId(e)]
const note = database.alerts.get(parent.id) || asAlert(parent) const note = asAlert(database.alerts.get(parent.id) || parent)
database.alerts.put({...note, repliesFrom: uniq(note.repliesFrom.concat(e.pubkey))}) database.alerts.put({...note, repliesFrom: uniq(note.repliesFrom.concat(e.pubkey))})
}) })
@ -150,7 +166,7 @@ const listen = async pubkey => {
filter: [ filter: [
{kinds: personKinds, authors: [pubkey], since}, {kinds: personKinds, authors: [pubkey], since},
{kinds: [4], authors: [pubkey], since}, {kinds: [4], authors: [pubkey], since},
{kinds: [1, 7, 4], '#p': [pubkey], since}, {kinds: [1, 7, 4, 9735], '#p': [pubkey], since},
{kinds: [42], '#e': roomIds, since}, {kinds: [42], '#e': roomIds, since},
], ],
onChunk: async events => { onChunk: async events => {

View File

@ -271,6 +271,16 @@ export const tryJson = f => {
} }
} }
export const tryFetch = async f => {
try {
return await f()
} catch (e) {
if (!e.toString().includes('fetch')) {
warn(e)
}
}
}
export const union = (...sets) => export const union = (...sets) =>
new Set(sets.flatMap(s => Array.from(s))) new Set(sets.flatMap(s => Array.from(s)))

View File

@ -83,7 +83,7 @@ export const displayPerson = p => {
export const isLike = content => ['', '+', '🤙', '👍', '❤️'].includes(content) export const isLike = content => ['', '+', '🤙', '👍', '❤️'].includes(content)
export const isAlert = (e, pubkey) => { export const isAlert = (e, pubkey) => {
if (![1, 7].includes(e.kind)) { if (![1, 7, 9735].includes(e.kind)) {
return false return false
} }

View File

@ -13,11 +13,13 @@
const pubkeys = switcher(type, { const pubkeys = switcher(type, {
replies: note.repliesFrom, replies: note.repliesFrom,
likes: note.likedBy, likes: note.likedBy,
zaps: note.zappedBy,
}) })
const actionText = switcher(type, { const actionText = switcher(type, {
replies: 'replied to your note', replies: 'replied to your note',
likes: 'liked your note', likes: 'liked your note',
zaps: 'zapped your note',
}) })
let isOpen = false let isOpen = false

View File

@ -23,7 +23,12 @@
// Filter out alerts for which we failed to find the required context. The bug // Filter out alerts for which we failed to find the required context. The bug
// is really upstream of this, but it's an easy fix // is really upstream of this, but it's an easy fix
const events = user.mute(database.alerts.all()) const events = user.mute(database.alerts.all())
.filter(e => e.replies.length > 0 || e.likedBy.length > 0 || e.isMention) .filter(e => (
e.replies.length > 0
|| e.likedBy.length > 0
|| e.zappedBy?.length > 0
|| e.isMention
))
notes = sortBy(e => -e.created_at, events).slice(0, limit) notes = sortBy(e => -e.created_at, events).slice(0, limit)
}) })
@ -36,6 +41,8 @@
<div in:fly={{y: 20}}> <div in:fly={{y: 20}}>
{#if note.replies.length > 0} {#if note.replies.length > 0}
<Alert type="replies" {note} /> <Alert type="replies" {note} />
{:else if note.zappedBy?.length > 0}
<Alert type="zaps" {note} />
{:else if note.likedBy.length > 0} {:else if note.likedBy.length > 0}
<Alert type="likes" {note} /> <Alert type="likes" {note} />
{:else} {:else}

View File

@ -56,7 +56,9 @@
</div> </div>
{:else if note.pubkey} {:else if note.pubkey}
<div in:fly={{y: 20}}> <div in:fly={{y: 20}}>
<Note showContext invertColors depth={6} anchorId={note.id} note={asDisplayEvent(note)} /> <Content>
<Note showContext invertColors depth={6} anchorId={note.id} note={asDisplayEvent(note)} />
</Content>
</div> </div>
{/if} {/if}