diff --git a/src/App.tsx b/src/App.tsx index 50b7afc..7ad7c82 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,14 +17,14 @@ export default function App(): JSX.Element { - - + + - - + + diff --git a/src/providers/FeedProvider.tsx b/src/providers/FeedProvider.tsx index 5d13c0c..8e1b123 100644 --- a/src/providers/FeedProvider.tsx +++ b/src/providers/FeedProvider.tsx @@ -4,6 +4,7 @@ import storage from '@/services/storage.service' import { TFeedType } from '@/types' import { Filter } from 'nostr-tools' import { createContext, useContext, useEffect, useState } from 'react' +import { useFollowList } from './FollowListProvider' import { useNostr } from './NostrProvider' import { useRelaySets } from './RelaySetsProvider' @@ -31,7 +32,8 @@ export const useFeed = () => { } export function FeedProvider({ children }: { children: React.ReactNode }) { - const { pubkey, getRelayList, getFollowings } = useNostr() + const { pubkey, getRelayList } = useNostr() + const { getFollowings } = useFollowList() const { relaySets } = useRelaySets() const [feedType, setFeedType] = useState(storage.getFeedType()) const [relayUrls, setRelayUrls] = useState([]) diff --git a/src/providers/FollowListProvider.tsx b/src/providers/FollowListProvider.tsx index c9ab0bb..8625d1d 100644 --- a/src/providers/FollowListProvider.tsx +++ b/src/providers/FollowListProvider.tsx @@ -1,6 +1,7 @@ import { createFollowListDraftEvent } from '@/lib/draft-event' -import { tagNameEquals } from '@/lib/tag' +import { getFollowingsFromFollowListEvent } from '@/lib/event' import client from '@/services/client.service' +import storage from '@/services/storage.service' import { Event } from 'nostr-tools' import { createContext, useContext, useEffect, useMemo, useState } from 'react' import { useNostr } from './NostrProvider' @@ -9,6 +10,7 @@ type TFollowListContext = { followListEvent: Event | undefined followings: string[] isFetching: boolean + getFollowings: (pubkey: string) => Promise follow: (pubkey: string) => Promise unfollow: (pubkey: string) => Promise } @@ -24,20 +26,13 @@ export const useFollowList = () => { } export function FollowListProvider({ children }: { children: React.ReactNode }) { - const { pubkey: accountPubkey, publish, updateFollowListEvent } = useNostr() + const { pubkey: accountPubkey, publish } = useNostr() const [followListEvent, setFollowListEvent] = useState(undefined) const [isFetching, setIsFetching] = useState(true) - const followings = useMemo(() => { - return Array.from( - new Set( - followListEvent?.tags - .filter(tagNameEquals('p')) - .map(([, pubkey]) => pubkey) - .filter(Boolean) - .reverse() ?? [] - ) - ) - }, [followListEvent]) + const followings = useMemo( + () => (followListEvent ? getFollowingsFromFollowListEvent(followListEvent) : []), + [followListEvent] + ) useEffect(() => { if (!accountPubkey) return @@ -45,14 +40,26 @@ export function FollowListProvider({ children }: { children: React.ReactNode }) const init = async () => { setIsFetching(true) setFollowListEvent(undefined) + const storedFollowListEvent = storage.getAccountFollowListEvent(accountPubkey) + if (storedFollowListEvent) { + setFollowListEvent(storedFollowListEvent) + } const event = await client.fetchFollowListEvent(accountPubkey) - setFollowListEvent(event) + if (event) { + updateFollowListEvent(event) + } setIsFetching(false) } init() }, [accountPubkey]) + const updateFollowListEvent = (event: Event) => { + const isNew = storage.setAccountFollowListEvent(event) + if (!isNew) return + setFollowListEvent(event) + } + const follow = async (pubkey: string) => { if (isFetching || !accountPubkey) return @@ -63,7 +70,6 @@ export function FollowListProvider({ children }: { children: React.ReactNode }) const newFollowListEvent = await publish(newFollowListDraftEvent) client.updateFollowListCache(accountPubkey, newFollowListEvent) updateFollowListEvent(newFollowListEvent) - setFollowListEvent(newFollowListEvent) } const unfollow = async (pubkey: string) => { @@ -76,7 +82,14 @@ export function FollowListProvider({ children }: { children: React.ReactNode }) const newFollowListEvent = await publish(newFollowListDraftEvent) client.updateFollowListCache(accountPubkey, newFollowListEvent) updateFollowListEvent(newFollowListEvent) - setFollowListEvent(newFollowListEvent) + } + + const getFollowings = async (pubkey: string) => { + const followListEvent = storage.getAccountFollowListEvent(pubkey) + if (followListEvent) { + return getFollowingsFromFollowListEvent(followListEvent) + } + return await client.fetchFollowings(pubkey) } return ( @@ -85,6 +98,7 @@ export function FollowListProvider({ children }: { children: React.ReactNode }) followListEvent, followings, isFetching, + getFollowings, follow, unfollow }} diff --git a/src/providers/NostrProvider/index.tsx b/src/providers/NostrProvider/index.tsx index 24fd656..67bb39c 100644 --- a/src/providers/NostrProvider/index.tsx +++ b/src/providers/NostrProvider/index.tsx @@ -1,11 +1,7 @@ import LoginDialog from '@/components/LoginDialog' import { BIG_RELAY_URLS } from '@/constants' import { useToast } from '@/hooks' -import { - getFollowingsFromFollowListEvent, - getProfileFromProfileEvent, - getRelayListFromRelayListEvent -} from '@/lib/event' +import { getProfileFromProfileEvent, getRelayListFromRelayListEvent } from '@/lib/event' import { formatPubkey } from '@/lib/pubkey' import client from '@/services/client.service' import storage from '@/services/storage.service' @@ -15,17 +11,16 @@ import { Event, kinds } from 'nostr-tools' import * as nip19 from 'nostr-tools/nip19' import * as nip49 from 'nostr-tools/nip49' import { createContext, useContext, useEffect, useState } from 'react' +import { useTranslation } from 'react-i18next' import { BunkerSigner } from './bunker.signer' import { Nip07Signer } from './nip-07.signer' import { NsecSigner } from './nsec.signer' -import { useTranslation } from 'react-i18next' type TNostrContext = { pubkey: string | null profile: TProfile | null profileEvent: Event | null relayList: TRelayList | null - followings: string[] | null account: TAccountPointer | null accounts: TAccountPointer[] nsec: string | null @@ -45,8 +40,6 @@ type TNostrContext = { checkLogin: (cb?: () => T) => Promise getRelayList: (pubkey: string) => Promise updateRelayListEvent: (relayListEvent: Event) => void - getFollowings: (pubkey: string) => Promise - updateFollowListEvent: (followListEvent: Event) => void updateProfileEvent: (profileEvent: Event) => void } @@ -71,7 +64,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { const [profile, setProfile] = useState(null) const [profileEvent, setProfileEvent] = useState(null) const [relayList, setRelayList] = useState(null) - const [followings, setFollowings] = useState(null) useEffect(() => { const init = async () => { @@ -86,7 +78,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { useEffect(() => { setRelayList(null) - setFollowings(null) setProfile(null) setProfileEvent(null) setNsec(null) @@ -112,10 +103,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { storedRelayListEvent ? getRelayListFromRelayListEvent(storedRelayListEvent) : null ) } - const storedFollowListEvent = storage.getAccountFollowListEvent(account.pubkey) - if (storedFollowListEvent) { - setFollowings(getFollowingsFromFollowListEvent(storedFollowListEvent)) - } const storedProfileEvent = storage.getAccountProfileEvent(account.pubkey) if (storedProfileEvent) { setProfileEvent(storedProfileEvent) @@ -132,17 +119,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { if (!isNew) return setRelayList(getRelayListFromRelayListEvent(relayListEvent)) }) - client.fetchFollowListEvent(account.pubkey).then(async (followListEvent) => { - if (!followListEvent) { - if (storedFollowListEvent) return - - setFollowings([]) - return - } - const isNew = storage.setAccountFollowListEvent(followListEvent) - if (!isNew) return - setFollowings(getFollowingsFromFollowListEvent(followListEvent)) - }) client.fetchProfileEvent(account.pubkey).then(async (profileEvent) => { if (!profileEvent) { if (storedProfileEvent) return @@ -344,20 +320,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { setRelayList(getRelayListFromRelayListEvent(relayListEvent)) } - const getFollowings = async (pubkey: string) => { - const followListEvent = storage.getAccountFollowListEvent(pubkey) - if (followListEvent) { - return getFollowingsFromFollowListEvent(followListEvent) - } - return await client.fetchFollowings(pubkey) - } - - const updateFollowListEvent = (followListEvent: Event) => { - const isNew = storage.setAccountFollowListEvent(followListEvent) - if (!isNew) return - setFollowings(getFollowingsFromFollowListEvent(followListEvent)) - } - const updateProfileEvent = (profileEvent: Event) => { const isNew = storage.setAccountProfileEvent(profileEvent) if (!isNew) return @@ -373,7 +335,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { profile, profileEvent, relayList, - followings, account, accounts: storage .getAccounts() @@ -392,8 +353,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) { signEvent, getRelayList, updateRelayListEvent, - getFollowings, - updateFollowListEvent, updateProfileEvent }} > diff --git a/src/services/storage.service.ts b/src/services/storage.service.ts index 322de21..a168b59 100644 --- a/src/services/storage.service.ts +++ b/src/services/storage.service.ts @@ -28,7 +28,7 @@ class StorageService { private currentAccount: TAccount | null = null private accountRelayListEventMap: Record = {} // pubkey -> relayListEvent private accountFollowListEventMap: Record = {} // pubkey -> followListEvent - private accountProfileEventMap: Record = {} // pubkey -> profileEvent + private accountProfileEventMap: Record = {} // pubkey -> profileEvent constructor() { if (!StorageService.instance) {