You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
4.2 KiB
145 lines
4.2 KiB
import { isWebsocketUrl, normalizeUrl } from '@/lib/url' |
|
import client from '@/services/client.service' |
|
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 }) => 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 } = 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 tempRelays = searchParams |
|
.getAll('r') |
|
.map((url) => |
|
!url.startsWith('ws://') && !url.startsWith('wss://') ? `wss://${url}` : url |
|
) |
|
.filter((url) => isWebsocketUrl(url)) |
|
.map((url) => normalizeUrl(url)) |
|
if (tempRelays.length) { |
|
setTemporaryRelayUrls(tempRelays) |
|
return await switchFeed('temporary') |
|
} |
|
|
|
if (feedType === 'following') { |
|
return await switchFeed('following') |
|
} |
|
await switchFeed('relays', { activeRelaySetId }) |
|
} |
|
|
|
init() |
|
}, []) |
|
|
|
useEffect(() => { |
|
if (feedType !== 'following') return |
|
|
|
switchFeed('following') |
|
}, [pubkey]) |
|
|
|
useEffect(() => { |
|
if (feedType !== 'relays') return |
|
|
|
const relaySet = relaySets.find((set) => set.id === activeRelaySetId) |
|
if (!relaySet) return |
|
|
|
setRelayUrls(relaySet.relayUrls) |
|
}, [relaySets]) |
|
|
|
const switchFeed = async ( |
|
feedType: TFeedType, |
|
options: { activeRelaySetId?: string | null } = {} |
|
) => { |
|
setIsReady(false) |
|
if (feedType === 'relays') { |
|
const relaySetId = options.activeRelaySetId ?? (relaySets.length > 0 ? relaySets[0].id : null) |
|
if (!relaySetId) return |
|
|
|
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({}) |
|
setIsReady(true) |
|
storage.setActiveRelaySetId(relaySet.id) |
|
storage.setFeedType(feedType) |
|
} |
|
return |
|
} |
|
if (feedType === 'following') { |
|
if (!pubkey) return |
|
setFeedType(feedType) |
|
setActiveRelaySetId(null) |
|
const [relayList, followings] = await Promise.all([ |
|
client.fetchRelayList(pubkey), |
|
client.fetchFollowings(pubkey) |
|
]) |
|
setRelayUrls(relayList.read.slice(0, 4)) |
|
setFilter({ authors: followings.includes(pubkey) ? followings : [...followings, pubkey] }) |
|
setIsReady(true) |
|
storage.setFeedType(feedType) |
|
return |
|
} |
|
if (feedType === 'temporary') { |
|
setFeedType(feedType) |
|
setRelayUrls(temporaryRelayUrls) |
|
setActiveRelaySetId(null) |
|
setFilter({}) |
|
setIsReady(true) |
|
return |
|
} |
|
setIsReady(true) |
|
} |
|
|
|
return ( |
|
<FeedContext.Provider |
|
value={{ |
|
feedType, |
|
relayUrls, |
|
temporaryRelayUrls, |
|
filter, |
|
isReady, |
|
activeRelaySetId, |
|
switchFeed |
|
}} |
|
> |
|
{children} |
|
</FeedContext.Provider> |
|
) |
|
}
|
|
|