7 changed files with 149 additions and 77 deletions
@ -0,0 +1,96 @@
@@ -0,0 +1,96 @@
|
||||
import { TDraftEvent } from '@common/types' |
||||
import { tagNameEquals } from '@renderer/lib/tag' |
||||
import client from '@renderer/services/client.service' |
||||
import dayjs from 'dayjs' |
||||
import { Event, kinds } from 'nostr-tools' |
||||
import { createContext, useContext, useEffect, useMemo, useState } from 'react' |
||||
import { useNostr } from './NostrProvider' |
||||
|
||||
type TFollowListContext = { |
||||
followListEvent: Event | undefined |
||||
followings: string[] |
||||
isReady: boolean |
||||
follow: (pubkey: string) => Promise<void> |
||||
unfollow: (pubkey: string) => Promise<void> |
||||
} |
||||
|
||||
const FollowListContext = createContext<TFollowListContext | undefined>(undefined) |
||||
|
||||
export const useFollowList = () => { |
||||
const context = useContext(FollowListContext) |
||||
if (!context) { |
||||
throw new Error('useFollowList must be used within a FollowListProvider') |
||||
} |
||||
return context |
||||
} |
||||
|
||||
export function FollowListProvider({ children }: { children: React.ReactNode }) { |
||||
const { pubkey: accountPubkey, publish } = useNostr() |
||||
const [followListEvent, setFollowListEvent] = useState<Event | undefined>(undefined) |
||||
const [isReady, setIsReady] = useState(false) |
||||
const followings = useMemo( |
||||
() => |
||||
followListEvent?.tags |
||||
.filter(tagNameEquals('p')) |
||||
.map(([, pubkey]) => pubkey) |
||||
.filter(Boolean) |
||||
.reverse() ?? [], |
||||
[followListEvent] |
||||
) |
||||
|
||||
useEffect(() => { |
||||
if (isReady || !accountPubkey) return |
||||
|
||||
const init = async () => { |
||||
const event = await client.fetchFollowListEvent(accountPubkey) |
||||
setFollowListEvent(event) |
||||
setIsReady(true) |
||||
} |
||||
|
||||
init() |
||||
}, [accountPubkey]) |
||||
|
||||
const follow = async (pubkey: string) => { |
||||
if (!isReady || !accountPubkey) return |
||||
|
||||
const newFollowListDraftEvent: TDraftEvent = { |
||||
kind: kinds.Contacts, |
||||
content: followListEvent?.content ?? '', |
||||
created_at: dayjs().unix(), |
||||
tags: (followListEvent?.tags ?? []).concat([['p', pubkey]]) |
||||
} |
||||
const newFollowListEvent = await publish(newFollowListDraftEvent) |
||||
client.updateFollowListCache(accountPubkey, newFollowListEvent) |
||||
setFollowListEvent(newFollowListEvent) |
||||
} |
||||
|
||||
const unfollow = async (pubkey: string) => { |
||||
if (!isReady || !accountPubkey || !followListEvent) return |
||||
|
||||
const newFollowListDraftEvent: TDraftEvent = { |
||||
kind: kinds.Contacts, |
||||
content: followListEvent.content ?? '', |
||||
created_at: dayjs().unix(), |
||||
tags: followListEvent.tags.filter( |
||||
([tagName, tagValue]) => tagName !== 'p' || tagValue !== pubkey |
||||
) |
||||
} |
||||
const newFollowListEvent = await publish(newFollowListDraftEvent) |
||||
client.updateFollowListCache(accountPubkey, newFollowListEvent) |
||||
setFollowListEvent(newFollowListEvent) |
||||
} |
||||
|
||||
return ( |
||||
<FollowListContext.Provider |
||||
value={{ |
||||
followListEvent, |
||||
followings, |
||||
isReady, |
||||
follow, |
||||
unfollow |
||||
}} |
||||
> |
||||
{children} |
||||
</FollowListContext.Provider> |
||||
) |
||||
} |
||||
Loading…
Reference in new issue