refactor: 🏗️

This commit is contained in:
codytseng
2025-01-18 22:46:02 +08:00
parent fa455ba127
commit 34ff0cd314
5 changed files with 40 additions and 65 deletions

View File

@@ -17,14 +17,14 @@ export default function App(): JSX.Element {
<ScreenSizeProvider> <ScreenSizeProvider>
<NostrProvider> <NostrProvider>
<RelaySetsProvider> <RelaySetsProvider>
<FeedProvider>
<FollowListProvider> <FollowListProvider>
<FeedProvider>
<NoteStatsProvider> <NoteStatsProvider>
<PageManager /> <PageManager />
<Toaster /> <Toaster />
</NoteStatsProvider> </NoteStatsProvider>
</FollowListProvider>
</FeedProvider> </FeedProvider>
</FollowListProvider>
</RelaySetsProvider> </RelaySetsProvider>
</NostrProvider> </NostrProvider>
</ScreenSizeProvider> </ScreenSizeProvider>

View File

@@ -4,6 +4,7 @@ import storage from '@/services/storage.service'
import { TFeedType } from '@/types' import { TFeedType } from '@/types'
import { Filter } from 'nostr-tools' import { Filter } from 'nostr-tools'
import { createContext, useContext, useEffect, useState } from 'react' import { createContext, useContext, useEffect, useState } from 'react'
import { useFollowList } from './FollowListProvider'
import { useNostr } from './NostrProvider' import { useNostr } from './NostrProvider'
import { useRelaySets } from './RelaySetsProvider' import { useRelaySets } from './RelaySetsProvider'
@@ -31,7 +32,8 @@ export const useFeed = () => {
} }
export function FeedProvider({ children }: { children: React.ReactNode }) { export function FeedProvider({ children }: { children: React.ReactNode }) {
const { pubkey, getRelayList, getFollowings } = useNostr() const { pubkey, getRelayList } = useNostr()
const { getFollowings } = useFollowList()
const { relaySets } = useRelaySets() const { relaySets } = useRelaySets()
const [feedType, setFeedType] = useState<TFeedType>(storage.getFeedType()) const [feedType, setFeedType] = useState<TFeedType>(storage.getFeedType())
const [relayUrls, setRelayUrls] = useState<string[]>([]) const [relayUrls, setRelayUrls] = useState<string[]>([])

View File

@@ -1,6 +1,7 @@
import { createFollowListDraftEvent } from '@/lib/draft-event' import { createFollowListDraftEvent } from '@/lib/draft-event'
import { tagNameEquals } from '@/lib/tag' import { getFollowingsFromFollowListEvent } from '@/lib/event'
import client from '@/services/client.service' import client from '@/services/client.service'
import storage from '@/services/storage.service'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import { createContext, useContext, useEffect, useMemo, useState } from 'react' import { createContext, useContext, useEffect, useMemo, useState } from 'react'
import { useNostr } from './NostrProvider' import { useNostr } from './NostrProvider'
@@ -9,6 +10,7 @@ type TFollowListContext = {
followListEvent: Event | undefined followListEvent: Event | undefined
followings: string[] followings: string[]
isFetching: boolean isFetching: boolean
getFollowings: (pubkey: string) => Promise<string[]>
follow: (pubkey: string) => Promise<void> follow: (pubkey: string) => Promise<void>
unfollow: (pubkey: string) => Promise<void> unfollow: (pubkey: string) => Promise<void>
} }
@@ -24,20 +26,13 @@ export const useFollowList = () => {
} }
export function FollowListProvider({ children }: { children: React.ReactNode }) { export function FollowListProvider({ children }: { children: React.ReactNode }) {
const { pubkey: accountPubkey, publish, updateFollowListEvent } = useNostr() const { pubkey: accountPubkey, publish } = useNostr()
const [followListEvent, setFollowListEvent] = useState<Event | undefined>(undefined) const [followListEvent, setFollowListEvent] = useState<Event | undefined>(undefined)
const [isFetching, setIsFetching] = useState(true) const [isFetching, setIsFetching] = useState(true)
const followings = useMemo(() => { const followings = useMemo(
return Array.from( () => (followListEvent ? getFollowingsFromFollowListEvent(followListEvent) : []),
new Set( [followListEvent]
followListEvent?.tags
.filter(tagNameEquals('p'))
.map(([, pubkey]) => pubkey)
.filter(Boolean)
.reverse() ?? []
) )
)
}, [followListEvent])
useEffect(() => { useEffect(() => {
if (!accountPubkey) return if (!accountPubkey) return
@@ -45,14 +40,26 @@ export function FollowListProvider({ children }: { children: React.ReactNode })
const init = async () => { const init = async () => {
setIsFetching(true) setIsFetching(true)
setFollowListEvent(undefined) setFollowListEvent(undefined)
const storedFollowListEvent = storage.getAccountFollowListEvent(accountPubkey)
if (storedFollowListEvent) {
setFollowListEvent(storedFollowListEvent)
}
const event = await client.fetchFollowListEvent(accountPubkey) const event = await client.fetchFollowListEvent(accountPubkey)
setFollowListEvent(event) if (event) {
updateFollowListEvent(event)
}
setIsFetching(false) setIsFetching(false)
} }
init() init()
}, [accountPubkey]) }, [accountPubkey])
const updateFollowListEvent = (event: Event) => {
const isNew = storage.setAccountFollowListEvent(event)
if (!isNew) return
setFollowListEvent(event)
}
const follow = async (pubkey: string) => { const follow = async (pubkey: string) => {
if (isFetching || !accountPubkey) return if (isFetching || !accountPubkey) return
@@ -63,7 +70,6 @@ export function FollowListProvider({ children }: { children: React.ReactNode })
const newFollowListEvent = await publish(newFollowListDraftEvent) const newFollowListEvent = await publish(newFollowListDraftEvent)
client.updateFollowListCache(accountPubkey, newFollowListEvent) client.updateFollowListCache(accountPubkey, newFollowListEvent)
updateFollowListEvent(newFollowListEvent) updateFollowListEvent(newFollowListEvent)
setFollowListEvent(newFollowListEvent)
} }
const unfollow = async (pubkey: string) => { const unfollow = async (pubkey: string) => {
@@ -76,7 +82,14 @@ export function FollowListProvider({ children }: { children: React.ReactNode })
const newFollowListEvent = await publish(newFollowListDraftEvent) const newFollowListEvent = await publish(newFollowListDraftEvent)
client.updateFollowListCache(accountPubkey, newFollowListEvent) client.updateFollowListCache(accountPubkey, newFollowListEvent)
updateFollowListEvent(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 ( return (
@@ -85,6 +98,7 @@ export function FollowListProvider({ children }: { children: React.ReactNode })
followListEvent, followListEvent,
followings, followings,
isFetching, isFetching,
getFollowings,
follow, follow,
unfollow unfollow
}} }}

View File

@@ -1,11 +1,7 @@
import LoginDialog from '@/components/LoginDialog' import LoginDialog from '@/components/LoginDialog'
import { BIG_RELAY_URLS } from '@/constants' import { BIG_RELAY_URLS } from '@/constants'
import { useToast } from '@/hooks' import { useToast } from '@/hooks'
import { import { getProfileFromProfileEvent, getRelayListFromRelayListEvent } from '@/lib/event'
getFollowingsFromFollowListEvent,
getProfileFromProfileEvent,
getRelayListFromRelayListEvent
} from '@/lib/event'
import { formatPubkey } from '@/lib/pubkey' import { formatPubkey } from '@/lib/pubkey'
import client from '@/services/client.service' import client from '@/services/client.service'
import storage from '@/services/storage.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 nip19 from 'nostr-tools/nip19'
import * as nip49 from 'nostr-tools/nip49' import * as nip49 from 'nostr-tools/nip49'
import { createContext, useContext, useEffect, useState } from 'react' import { createContext, useContext, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { BunkerSigner } from './bunker.signer' import { BunkerSigner } from './bunker.signer'
import { Nip07Signer } from './nip-07.signer' import { Nip07Signer } from './nip-07.signer'
import { NsecSigner } from './nsec.signer' import { NsecSigner } from './nsec.signer'
import { useTranslation } from 'react-i18next'
type TNostrContext = { type TNostrContext = {
pubkey: string | null pubkey: string | null
profile: TProfile | null profile: TProfile | null
profileEvent: Event | null profileEvent: Event | null
relayList: TRelayList | null relayList: TRelayList | null
followings: string[] | null
account: TAccountPointer | null account: TAccountPointer | null
accounts: TAccountPointer[] accounts: TAccountPointer[]
nsec: string | null nsec: string | null
@@ -45,8 +40,6 @@ type TNostrContext = {
checkLogin: <T>(cb?: () => T) => Promise<T | void> checkLogin: <T>(cb?: () => T) => Promise<T | void>
getRelayList: (pubkey: string) => Promise<TRelayList> getRelayList: (pubkey: string) => Promise<TRelayList>
updateRelayListEvent: (relayListEvent: Event) => void updateRelayListEvent: (relayListEvent: Event) => void
getFollowings: (pubkey: string) => Promise<string[]>
updateFollowListEvent: (followListEvent: Event) => void
updateProfileEvent: (profileEvent: Event) => void updateProfileEvent: (profileEvent: Event) => void
} }
@@ -71,7 +64,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
const [profile, setProfile] = useState<TProfile | null>(null) const [profile, setProfile] = useState<TProfile | null>(null)
const [profileEvent, setProfileEvent] = useState<Event | null>(null) const [profileEvent, setProfileEvent] = useState<Event | null>(null)
const [relayList, setRelayList] = useState<TRelayList | null>(null) const [relayList, setRelayList] = useState<TRelayList | null>(null)
const [followings, setFollowings] = useState<string[] | null>(null)
useEffect(() => { useEffect(() => {
const init = async () => { const init = async () => {
@@ -86,7 +78,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
useEffect(() => { useEffect(() => {
setRelayList(null) setRelayList(null)
setFollowings(null)
setProfile(null) setProfile(null)
setProfileEvent(null) setProfileEvent(null)
setNsec(null) setNsec(null)
@@ -112,10 +103,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
storedRelayListEvent ? getRelayListFromRelayListEvent(storedRelayListEvent) : null storedRelayListEvent ? getRelayListFromRelayListEvent(storedRelayListEvent) : null
) )
} }
const storedFollowListEvent = storage.getAccountFollowListEvent(account.pubkey)
if (storedFollowListEvent) {
setFollowings(getFollowingsFromFollowListEvent(storedFollowListEvent))
}
const storedProfileEvent = storage.getAccountProfileEvent(account.pubkey) const storedProfileEvent = storage.getAccountProfileEvent(account.pubkey)
if (storedProfileEvent) { if (storedProfileEvent) {
setProfileEvent(storedProfileEvent) setProfileEvent(storedProfileEvent)
@@ -132,17 +119,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
if (!isNew) return if (!isNew) return
setRelayList(getRelayListFromRelayListEvent(relayListEvent)) 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) => { client.fetchProfileEvent(account.pubkey).then(async (profileEvent) => {
if (!profileEvent) { if (!profileEvent) {
if (storedProfileEvent) return if (storedProfileEvent) return
@@ -344,20 +320,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
setRelayList(getRelayListFromRelayListEvent(relayListEvent)) 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 updateProfileEvent = (profileEvent: Event) => {
const isNew = storage.setAccountProfileEvent(profileEvent) const isNew = storage.setAccountProfileEvent(profileEvent)
if (!isNew) return if (!isNew) return
@@ -373,7 +335,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
profile, profile,
profileEvent, profileEvent,
relayList, relayList,
followings,
account, account,
accounts: storage accounts: storage
.getAccounts() .getAccounts()
@@ -392,8 +353,6 @@ export function NostrProvider({ children }: { children: React.ReactNode }) {
signEvent, signEvent,
getRelayList, getRelayList,
updateRelayListEvent, updateRelayListEvent,
getFollowings,
updateFollowListEvent,
updateProfileEvent updateProfileEvent
}} }}
> >

View File

@@ -28,7 +28,7 @@ class StorageService {
private currentAccount: TAccount | null = null private currentAccount: TAccount | null = null
private accountRelayListEventMap: Record<string, Event | undefined> = {} // pubkey -> relayListEvent private accountRelayListEventMap: Record<string, Event | undefined> = {} // pubkey -> relayListEvent
private accountFollowListEventMap: Record<string, Event | undefined> = {} // pubkey -> followListEvent private accountFollowListEventMap: Record<string, Event | undefined> = {} // pubkey -> followListEvent
private accountProfileEventMap: Record<string, Event> = {} // pubkey -> profileEvent private accountProfileEventMap: Record<string, Event | undefined> = {} // pubkey -> profileEvent
constructor() { constructor() {
if (!StorageService.instance) { if (!StorageService.instance) {