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