index.tsx raw
1 import { useFetchEvent } from '@/hooks'
2 import { generateBech32IdFromATag } from '@/lib/tag'
3 import { useNostr } from '@/providers/NostrProvider'
4 import { useEffect, useMemo, useRef, useState } from 'react'
5 import { useTranslation } from 'react-i18next'
6 import NoteCard, { NoteCardLoadingSkeleton } from '../NoteCard'
7
8 const SHOW_COUNT = 10
9
10 export default function EmojiPackList() {
11 const { t } = useTranslation()
12 const { userEmojiListEvent } = useNostr()
13 const eventIds = useMemo(() => {
14 if (!userEmojiListEvent) return []
15
16 return (
17 userEmojiListEvent.tags
18 .map((tag) => (tag[0] === 'a' ? generateBech32IdFromATag(tag) : null))
19 .filter(Boolean) as `naddr1${string}`[]
20 ).reverse()
21 }, [userEmojiListEvent])
22 const [showCount, setShowCount] = useState(SHOW_COUNT)
23 const bottomRef = useRef<HTMLDivElement | null>(null)
24
25 useEffect(() => {
26 const options = {
27 root: null,
28 rootMargin: '10px',
29 threshold: 0.1
30 }
31
32 const loadMore = () => {
33 if (showCount < eventIds.length) {
34 setShowCount((prev) => prev + SHOW_COUNT)
35 }
36 }
37
38 const observerInstance = new IntersectionObserver((entries) => {
39 if (entries[0].isIntersecting) {
40 loadMore()
41 }
42 }, options)
43
44 const currentBottomRef = bottomRef.current
45
46 if (currentBottomRef) {
47 observerInstance.observe(currentBottomRef)
48 }
49
50 return () => {
51 if (observerInstance && currentBottomRef) {
52 observerInstance.unobserve(currentBottomRef)
53 }
54 }
55 }, [showCount, eventIds])
56
57 if (eventIds.length === 0) {
58 return (
59 <div className="mt-2 text-sm text-center text-muted-foreground">
60 {t('no emoji packs found')}
61 </div>
62 )
63 }
64
65 return (
66 <div>
67 {eventIds.slice(0, showCount).map((eventId) => (
68 <EmojiPackNote key={eventId} eventId={eventId} />
69 ))}
70 </div>
71 )
72 }
73
74 function EmojiPackNote({ eventId }: { eventId: string }) {
75 const { event, isFetching } = useFetchEvent(eventId)
76
77 if (isFetching) {
78 return <NoteCardLoadingSkeleton className="border-b" />
79 }
80
81 if (!event) {
82 return null
83 }
84
85 return <NoteCard event={event} className="w-full" />
86 }
87