refactor: 🏗️
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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[]>([])
|
||||||
|
|||||||
@@ -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
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -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
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user