151 lines
4.3 KiB
TypeScript
151 lines
4.3 KiB
TypeScript
import { BIG_RELAY_URLS } from '@/constants'
|
|
import { isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
|
import storage from '@/services/storage.service'
|
|
import { TFeedType } from '@/types'
|
|
import { Filter } from 'nostr-tools'
|
|
import { createContext, useContext, useEffect, useState } from 'react'
|
|
import { useNostr } from './NostrProvider'
|
|
import { useRelaySets } from './RelaySetsProvider'
|
|
|
|
type TFeedContext = {
|
|
feedType: TFeedType
|
|
relayUrls: string[]
|
|
temporaryRelayUrls: string[]
|
|
filter: Filter
|
|
isReady: boolean
|
|
activeRelaySetId: string | null
|
|
switchFeed: (
|
|
feedType: TFeedType,
|
|
options?: { activeRelaySetId?: string; pubkey?: string }
|
|
) => Promise<void>
|
|
}
|
|
|
|
const FeedContext = createContext<TFeedContext | undefined>(undefined)
|
|
|
|
export const useFeed = () => {
|
|
const context = useContext(FeedContext)
|
|
if (!context) {
|
|
throw new Error('useFeed must be used within a FeedProvider')
|
|
}
|
|
return context
|
|
}
|
|
|
|
export function FeedProvider({ children }: { children: React.ReactNode }) {
|
|
const { pubkey, getRelayList, getFollowings } = useNostr()
|
|
const { relaySets } = useRelaySets()
|
|
const [feedType, setFeedType] = useState<TFeedType>(storage.getFeedType())
|
|
const [relayUrls, setRelayUrls] = useState<string[]>([])
|
|
const [temporaryRelayUrls, setTemporaryRelayUrls] = useState<string[]>([])
|
|
const [filter, setFilter] = useState<Filter>({})
|
|
const [isReady, setIsReady] = useState(false)
|
|
const [activeRelaySetId, setActiveRelaySetId] = useState<string | null>(
|
|
storage.getActiveRelaySetId()
|
|
)
|
|
|
|
useEffect(() => {
|
|
const init = async () => {
|
|
// temporary relay urls from query params
|
|
const searchParams = new URLSearchParams(window.location.search)
|
|
const temporaryRelayUrls = searchParams
|
|
.getAll('r')
|
|
.map((url) => normalizeUrl(url))
|
|
.filter((url) => isWebsocketUrl(url))
|
|
if (temporaryRelayUrls.length) {
|
|
return await switchFeed('temporary', { temporaryRelayUrls })
|
|
}
|
|
|
|
if (feedType === 'following') {
|
|
return await switchFeed('following', { pubkey })
|
|
} else {
|
|
console.log('activeRelaySetId', activeRelaySetId)
|
|
await switchFeed('relays', { activeRelaySetId })
|
|
}
|
|
}
|
|
|
|
init()
|
|
}, [])
|
|
|
|
useEffect(() => {
|
|
if (pubkey && feedType === 'following') {
|
|
switchFeed('following', { pubkey })
|
|
}
|
|
}, [feedType, pubkey])
|
|
|
|
const switchFeed = async (
|
|
feedType: TFeedType,
|
|
options: {
|
|
activeRelaySetId?: string | null
|
|
temporaryRelayUrls?: string[] | null
|
|
pubkey?: string | null
|
|
} = {}
|
|
) => {
|
|
setIsReady(false)
|
|
if (feedType === 'relays') {
|
|
const relaySetId = options.activeRelaySetId ?? (relaySets.length > 0 ? relaySets[0].id : null)
|
|
if (!relaySetId) {
|
|
return setIsReady(true)
|
|
}
|
|
|
|
const relaySet =
|
|
relaySets.find((set) => set.id === options.activeRelaySetId) ??
|
|
(relaySets.length > 0 ? relaySets[0] : null)
|
|
if (relaySet) {
|
|
setFeedType(feedType)
|
|
setRelayUrls(relaySet.relayUrls)
|
|
setActiveRelaySetId(relaySet.id)
|
|
setFilter({})
|
|
storage.setActiveRelaySetId(relaySet.id)
|
|
storage.setFeedType(feedType)
|
|
}
|
|
return setIsReady(true)
|
|
}
|
|
if (feedType === 'following') {
|
|
if (!options.pubkey) {
|
|
return setIsReady(true)
|
|
}
|
|
setFeedType(feedType)
|
|
setActiveRelaySetId(null)
|
|
const [relayList, followings] = await Promise.all([
|
|
getRelayList(options.pubkey),
|
|
getFollowings(options.pubkey)
|
|
])
|
|
setRelayUrls(relayList.read.concat(BIG_RELAY_URLS).slice(0, 4))
|
|
setFilter({
|
|
authors: followings.includes(options.pubkey) ? followings : [...followings, options.pubkey]
|
|
})
|
|
storage.setFeedType(feedType)
|
|
return setIsReady(true)
|
|
}
|
|
if (feedType === 'temporary') {
|
|
const urls = options.temporaryRelayUrls ?? temporaryRelayUrls
|
|
if (!urls.length) {
|
|
return setIsReady(true)
|
|
}
|
|
|
|
setFeedType(feedType)
|
|
setTemporaryRelayUrls(urls)
|
|
setRelayUrls(urls)
|
|
setActiveRelaySetId(null)
|
|
setFilter({})
|
|
return setIsReady(true)
|
|
}
|
|
setIsReady(true)
|
|
}
|
|
|
|
return (
|
|
<FeedContext.Provider
|
|
value={{
|
|
feedType,
|
|
relayUrls,
|
|
temporaryRelayUrls,
|
|
filter,
|
|
isReady,
|
|
activeRelaySetId,
|
|
switchFeed
|
|
}}
|
|
>
|
|
{children}
|
|
</FeedContext.Provider>
|
|
)
|
|
}
|