index.tsx raw

   1  import client from '@/services/client.service'
   2  import storage from '@/services/local-storage.service'
   3  import dayjs from 'dayjs'
   4  import { useEffect, useRef, useState } from 'react'
   5  import UserItem, { UserItemSkeleton } from '../UserItem'
   6  
   7  const LIMIT = 50
   8  
   9  export function ProfileListBySearch({ search }: { search: string }) {
  10    const [until, setUntil] = useState<number>(() => dayjs().unix())
  11    const [hasMore, setHasMore] = useState<boolean>(true)
  12    const [pubkeySet, setPubkeySet] = useState(new Set<string>())
  13    const bottomRef = useRef<HTMLDivElement>(null)
  14  
  15    useEffect(() => {
  16      setUntil(dayjs().unix())
  17      setHasMore(true)
  18      setPubkeySet(new Set<string>())
  19      loadMore()
  20    }, [search])
  21  
  22    useEffect(() => {
  23      if (!hasMore) return
  24      const options = {
  25        root: null,
  26        rootMargin: '10px',
  27        threshold: 1
  28      }
  29  
  30      const observerInstance = new IntersectionObserver((entries) => {
  31        if (entries[0].isIntersecting && hasMore) {
  32          loadMore()
  33        }
  34      }, options)
  35  
  36      const currentBottomRef = bottomRef.current
  37  
  38      if (currentBottomRef) {
  39        observerInstance.observe(currentBottomRef)
  40      }
  41  
  42      return () => {
  43        if (observerInstance && currentBottomRef) {
  44          observerInstance.unobserve(currentBottomRef)
  45        }
  46      }
  47    }, [hasMore, search, until])
  48  
  49    const loadMore = async () => {
  50      const profiles = await client.searchProfiles(storage.getSearchRelays(), {
  51        search,
  52        until,
  53        limit: LIMIT
  54      })
  55      const newPubkeySet = new Set<string>()
  56      profiles.forEach((profile) => {
  57        if (!pubkeySet.has(profile.pubkey)) {
  58          newPubkeySet.add(profile.pubkey)
  59        }
  60      })
  61      setPubkeySet((prev) => new Set([...prev, ...newPubkeySet]))
  62      setHasMore(profiles.length >= LIMIT)
  63      const lastProfileCreatedAt = profiles[profiles.length - 1].created_at
  64      setUntil(lastProfileCreatedAt ? lastProfileCreatedAt - 1 : 0)
  65    }
  66  
  67    return (
  68      <div className="px-4">
  69        {Array.from(pubkeySet).map((pubkey, index) => (
  70          <UserItem key={`${index}-${pubkey}`} userId={pubkey} />
  71        ))}
  72        {hasMore && <UserItemSkeleton />}
  73        {hasMore && <div ref={bottomRef} />}
  74      </div>
  75    )
  76  }
  77