index.tsx raw
1 import { useFetchRelayInfo } from '@/hooks'
2 import { toRelay } from '@/lib/link'
3 import { useSecondaryPage } from '@/PageManager'
4 import { useNostr } from '@/providers/NostrProvider'
5 import client from '@/services/client.service'
6 import { useEffect, useRef, useState } from 'react'
7 import { useTranslation } from 'react-i18next'
8 import RelaySimpleInfo, { RelaySimpleInfoSkeleton } from '../RelaySimpleInfo'
9
10 const SHOW_COUNT = 10
11
12 export default function FollowingFavoriteRelayList() {
13 const { t } = useTranslation()
14 const { pubkey } = useNostr()
15 const [loading, setLoading] = useState(true)
16 const [relays, setRelays] = useState<[string, string[]][]>([])
17 const [showCount, setShowCount] = useState(SHOW_COUNT)
18 const bottomRef = useRef<HTMLDivElement>(null)
19
20 useEffect(() => {
21 setLoading(true)
22
23 const init = async () => {
24 if (!pubkey) return
25
26 const relays = (await client.fetchFollowingFavoriteRelays(pubkey)) ?? []
27 setRelays(relays)
28 }
29 init().finally(() => {
30 setLoading(false)
31 })
32 }, [pubkey])
33
34 useEffect(() => {
35 const options = {
36 root: null,
37 rootMargin: '10px',
38 threshold: 1
39 }
40
41 const observerInstance = new IntersectionObserver((entries) => {
42 if (entries[0].isIntersecting && showCount < relays.length) {
43 setShowCount((prev) => prev + SHOW_COUNT)
44 }
45 }, options)
46
47 const currentBottomRef = bottomRef.current
48 if (currentBottomRef) {
49 observerInstance.observe(currentBottomRef)
50 }
51
52 return () => {
53 if (observerInstance && currentBottomRef) {
54 observerInstance.unobserve(currentBottomRef)
55 }
56 }
57 }, [showCount, relays])
58
59 return (
60 <div>
61 {relays.slice(0, showCount).map(([url, users]) => (
62 <RelayItem key={url} url={url} users={users} />
63 ))}
64 {showCount < relays.length && <div ref={bottomRef} />}
65 {loading && <RelaySimpleInfoSkeleton className="p-4" />}
66 {!loading && (
67 <div className="text-center text-muted-foreground text-sm mt-2">
68 {relays.length === 0 ? t('no relays found') : t('no more relays')}
69 </div>
70 )}
71 </div>
72 )
73 }
74
75 function RelayItem({ url, users }: { url: string; users: string[] }) {
76 const { push } = useSecondaryPage()
77 const { relayInfo } = useFetchRelayInfo(url)
78
79 return (
80 <RelaySimpleInfo
81 key={url}
82 relayInfo={relayInfo}
83 users={users}
84 className="clickable p-4 border-b"
85 onClick={(e) => {
86 e.stopPropagation()
87 push(toRelay(url))
88 }}
89 />
90 )
91 }
92