feat: zap (#107)

This commit is contained in:
Cody Tseng
2025-03-01 23:52:05 +08:00
committed by GitHub
parent 407a6fb802
commit 249593d547
72 changed files with 2582 additions and 818 deletions

View File

@@ -1,16 +1,11 @@
import { createFollowListDraftEvent } from '@/lib/draft-event'
import { extractPubkeysFromEventTags } from '@/lib/tag'
import client from '@/services/client.service'
import indexedDb from '@/services/indexed-db.service'
import { Event, kinds } from 'nostr-tools'
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
import { createContext, useContext, useMemo } from 'react'
import { useNostr } from './NostrProvider'
type TFollowListContext = {
followListEvent: Event | undefined
followings: string[]
isFetching: boolean
getFollowings: (pubkey: string) => Promise<string[]>
follow: (pubkey: string) => Promise<void>
unfollow: (pubkey: string) => Promise<void>
}
@@ -26,81 +21,42 @@ export const useFollowList = () => {
}
export function FollowListProvider({ children }: { children: React.ReactNode }) {
const { pubkey: accountPubkey, publish } = useNostr()
const [followListEvent, setFollowListEvent] = useState<Event | undefined>(undefined)
const [isFetching, setIsFetching] = useState(true)
const { pubkey: accountPubkey, followListEvent, publish, updateFollowListEvent } = useNostr()
const followings = useMemo(
() => (followListEvent ? extractPubkeysFromEventTags(followListEvent.tags) : []),
[followListEvent]
)
useEffect(() => {
const follow = async (pubkey: string) => {
if (!accountPubkey) return
const init = async () => {
setIsFetching(true)
setFollowListEvent(undefined)
const storedFollowListEvent = await indexedDb.getReplaceableEvent(
accountPubkey,
kinds.Contacts
)
if (storedFollowListEvent) {
setFollowListEvent(storedFollowListEvent)
}
const event = await client.fetchFollowListEvent(accountPubkey, true)
if (event) {
await updateFollowListEvent(event)
}
setIsFetching(false)
}
init()
}, [accountPubkey])
const updateFollowListEvent = async (event: Event) => {
const newEvent = await indexedDb.putReplaceableEvent(event)
setFollowListEvent(newEvent)
}
const follow = async (pubkey: string) => {
if (isFetching || !accountPubkey) return
const followListEvent = await client.fetchFollowListEvent(accountPubkey)
const newFollowListDraftEvent = createFollowListDraftEvent(
(followListEvent?.tags ?? []).concat([['p', pubkey]]),
followListEvent?.content
)
const newFollowListEvent = await publish(newFollowListDraftEvent)
client.updateFollowListCache(accountPubkey, newFollowListEvent)
await updateFollowListEvent(newFollowListEvent)
}
const unfollow = async (pubkey: string) => {
if (isFetching || !accountPubkey || !followListEvent) return
if (!accountPubkey) return
const followListEvent = await client.fetchFollowListEvent(accountPubkey)
if (!followListEvent) return
const newFollowListDraftEvent = createFollowListDraftEvent(
followListEvent.tags.filter(([tagName, tagValue]) => tagName !== 'p' || tagValue !== pubkey),
followListEvent.content
)
const newFollowListEvent = await publish(newFollowListDraftEvent)
client.updateFollowListCache(accountPubkey, newFollowListEvent)
await updateFollowListEvent(newFollowListEvent)
}
const getFollowings = async (pubkey: string) => {
const followListEvent = await indexedDb.getReplaceableEvent(pubkey, kinds.Contacts)
if (followListEvent) {
return extractPubkeysFromEventTags(followListEvent.tags)
}
return await client.fetchFollowings(pubkey)
}
return (
<FollowListContext.Provider
value={{
followListEvent,
followings,
isFetching,
getFollowings,
follow,
unfollow
}}