11 changed files with 324 additions and 41 deletions
@ -0,0 +1,63 @@
@@ -0,0 +1,63 @@
|
||||
import { buildAccountListRelayUrlsForMerge } from '@/lib/account-list-relay-urls' |
||||
import { |
||||
buildPinListTagsAfterRemovingRef, |
||||
buildPinListTagsAfterToggle, |
||||
fetchNewestPinListForPubkey, |
||||
isEventInPinList |
||||
} from '@/lib/replaceable-list-latest' |
||||
import { decodePersonalListBech32Ref } from '@/lib/personal-list-mutations' |
||||
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider' |
||||
import { useNostr } from '@/providers/NostrProvider' |
||||
import indexedDb from '@/services/indexed-db.service' |
||||
import { useCallback } from 'react' |
||||
import type { Event } from 'nostr-tools' |
||||
|
||||
/** |
||||
* Publish an updated kind 10001 pin list without the given entry (by loaded event or NIP-19 ref). |
||||
*/ |
||||
export function useRemovePinListEntry(onSuccess?: () => void) { |
||||
const { publish, pubkey } = useNostr() |
||||
const { favoriteRelays, blockedRelays } = useFavoriteRelays() |
||||
|
||||
const removePinEntry = useCallback( |
||||
async (bech32Id: string, loadedEvent: Event | null): Promise<boolean> => { |
||||
if (!pubkey) return false |
||||
const comprehensiveRelays = await buildAccountListRelayUrlsForMerge({ |
||||
accountPubkey: pubkey, |
||||
favoriteRelays: favoriteRelays ?? [], |
||||
blockedRelays |
||||
}) |
||||
if (!comprehensiveRelays.length) return false |
||||
|
||||
const latest = await fetchNewestPinListForPubkey(pubkey, comprehensiveRelays) |
||||
if (!latest) return false |
||||
|
||||
let newTags: string[][] | null = null |
||||
if (loadedEvent) { |
||||
if (!isEventInPinList(latest, loadedEvent)) return false |
||||
newTags = buildPinListTagsAfterToggle(latest, loadedEvent, false) |
||||
} else { |
||||
const ref = decodePersonalListBech32Ref(bech32Id) |
||||
if (!ref) return false |
||||
newTags = buildPinListTagsAfterRemovingRef(latest.tags, ref) |
||||
} |
||||
if (!newTags) return false |
||||
|
||||
const published = await publish( |
||||
{ |
||||
kind: 10001, |
||||
tags: newTags, |
||||
content: '', |
||||
created_at: Math.floor(Date.now() / 1000) |
||||
}, |
||||
{ specifiedRelayUrls: comprehensiveRelays } |
||||
) |
||||
await indexedDb.putReplaceableEvent(published as Event) |
||||
onSuccess?.() |
||||
return true |
||||
}, |
||||
[blockedRelays, favoriteRelays, onSuccess, publish, pubkey] |
||||
) |
||||
|
||||
return removePinEntry |
||||
} |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
import { nip19 } from 'nostr-tools' |
||||
|
||||
/** Decoded target for one bookmark/pin list entry (NIP-19 nevent/note or naddr). */ |
||||
export type TPersonalListBech32Ref = { eIdLower?: string; aCoordLower?: string } |
||||
|
||||
export function decodePersonalListBech32Ref(bech32Id: string): TPersonalListBech32Ref | null { |
||||
try { |
||||
const dec = nip19.decode(bech32Id.trim()) |
||||
if (dec.type === 'nevent') { |
||||
return { eIdLower: dec.data.id.toLowerCase() } |
||||
} |
||||
if (dec.type === 'note') { |
||||
return { eIdLower: dec.data.toLowerCase() } |
||||
} |
||||
if (dec.type === 'naddr') { |
||||
const { kind, pubkey, identifier } = dec.data |
||||
return { aCoordLower: `${kind}:${pubkey}:${identifier}`.toLowerCase() } |
||||
} |
||||
} catch { |
||||
return null |
||||
} |
||||
return null |
||||
} |
||||
|
||||
/** |
||||
* Next bookmark list (kind 10003) tags after dropping one `e` or `a` ref. |
||||
* Returns null if nothing matched (list unchanged). |
||||
*/ |
||||
export function bookmarkListTagsAfterRemovingRef( |
||||
tags: string[][], |
||||
ref: TPersonalListBech32Ref |
||||
): string[][] | null { |
||||
if (!ref.eIdLower && !ref.aCoordLower) return null |
||||
const next = tags.filter((tag) => { |
||||
if (ref.eIdLower && tag[0] === 'e' && tag[1]?.toLowerCase() === ref.eIdLower) return false |
||||
if (ref.aCoordLower && tag[0] === 'a' && tag[1]?.toLowerCase() === ref.aCoordLower) return false |
||||
return true |
||||
}) |
||||
return next.length === tags.length ? null : next |
||||
} |
||||
Loading…
Reference in new issue