feat(notes): sub for new notes and discovery button

This commit is contained in:
en 2025-02-21 12:17:37 +01:00
parent fbd9b7e527
commit be9488a752
2 changed files with 76 additions and 6 deletions

View File

@ -7,12 +7,14 @@ import {
NDKEvent, NDKEvent,
NDKFilter, NDKFilter,
NDKKind, NDKKind,
NDKSubscription,
NDKSubscriptionCacheUsage NDKSubscriptionCacheUsage
} from '@nostr-dev-kit/ndk' } from '@nostr-dev-kit/ndk'
import { NoteSubmit } from 'components/Notes/NoteSubmit' import { NoteSubmit } from 'components/Notes/NoteSubmit'
import { Note } from 'components/Notes/Note' import { Note } from 'components/Notes/Note'
import { FeedPostsFilter, RepostFilter } from 'types' import { FeedPostsFilter, RepostFilter } from 'types'
import { DEFAULT_FILTER_OPTIONS } from 'utils' import { DEFAULT_FILTER_OPTIONS } from 'utils'
import { Dots } from 'components/Spinner'
export const FeedTabPosts = () => { export const FeedTabPosts = () => {
const SHOWING_STEP = 20 const SHOWING_STEP = 20
@ -22,6 +24,7 @@ export const FeedTabPosts = () => {
const { ndk } = useNDKContext() const { ndk } = useNDKContext()
const [notes, setNotes] = useState<NDKEvent[]>([]) const [notes, setNotes] = useState<NDKEvent[]>([])
const [discoveredNotes, setDiscoveredNotes] = useState<NDKEvent[]>([])
const [isFetching, setIsFetching] = useState(false) const [isFetching, setIsFetching] = useState(false)
const [isLoadMoreVisible, setIsLoadMoreVisible] = useState(true) const [isLoadMoreVisible, setIsLoadMoreVisible] = useState(true)
const [showing, setShowing] = useState(SHOWING_STEP) const [showing, setShowing] = useState(SHOWING_STEP)
@ -38,6 +41,8 @@ export const FeedTabPosts = () => {
setIsFetching(true) setIsFetching(true)
setIsLoadMoreVisible(true) setIsLoadMoreVisible(true)
let sub: NDKSubscription
const filter: NDKFilter = { const filter: NDKFilter = {
authors: [...followList, userPubkey], authors: [...followList, userPubkey],
kinds: [NDKKind.Text, NDKKind.Repost], kinds: [NDKKind.Text, NDKKind.Repost],
@ -50,12 +55,45 @@ export const FeedTabPosts = () => {
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
}) })
.then((ndkEventSet) => { .then((ndkEventSet) => {
const ndkEvents = Array.from(ndkEventSet) const ndkEvents = Array.from(ndkEventSet).sort(
(a, b) => (b.created_at ?? 0) - (a.created_at ?? 0)
)
setNotes(ndkEvents) setNotes(ndkEvents)
const firstNote = ndkEvents[0]
const filter: NDKFilter = {
authors: [...followList, userPubkey],
kinds: [NDKKind.Text, NDKKind.Repost],
since: firstNote.created_at
}
sub = ndk.subscribe(filter, {
closeOnEose: false,
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
})
sub.on('event', (ndkEvent) => {
setDiscoveredNotes((prev) => {
// Skip existing
if (
prev.find(
(e) =>
e.id === ndkEvent.id ||
ndkEvents.findIndex((n) => n.id === ndkEvent.id) === -1
)
) {
return [...prev]
}
return [...prev, ndkEvent]
})
})
sub.start()
}) })
.finally(() => { .finally(() => {
setIsFetching(false) setIsFetching(false)
}) })
return () => {
if (sub) sub.stop()
}
}, [followList, ndk, userPubkey]) }, [followList, ndk, userPubkey])
const filteredNotes = useMemo(() => { const filteredNotes = useMemo(() => {
@ -96,15 +134,14 @@ export const FeedTabPosts = () => {
const handleLoadMore = () => { const handleLoadMore = () => {
const LOAD_MORE_STEP = SHOWING_STEP * 2 const LOAD_MORE_STEP = SHOWING_STEP * 2
setShowing((prev) => prev + SHOWING_STEP) setShowing((prev) => prev + SHOWING_STEP)
const lastNote = filteredNotes[filteredNotes.length - 1] const lastNote = notes[notes.length - 1]
const filter: NDKFilter = { const filter: NDKFilter = {
authors: [...followList, userPubkey], authors: [...followList, userPubkey],
kinds: [NDKKind.Text, NDKKind.Repost], kinds: [NDKKind.Text, NDKKind.Repost],
limit: LOAD_MORE_STEP limit: LOAD_MORE_STEP,
until: lastNote.created_at
} }
filter.until = lastNote.created_at
setIsFetching(true) setIsFetching(true)
ndk ndk
.fetchEvents(filter, { .fetchEvents(filter, {
@ -133,9 +170,42 @@ export const FeedTabPosts = () => {
}) })
} }
const discoveredCount = discoveredNotes.length
const handleDiscoveredClick = () => {
// Combine newly discovred with the notes
// Skip events already in notes
setNotes((prev) => {
return Array.from(new Set([...discoveredNotes, ...prev]))
})
// Increase showing by the discovered count
setShowing((prev) => prev + discoveredNotes.length)
setDiscoveredNotes([])
}
return ( return (
<> <>
<NoteSubmit /> <NoteSubmit />
<div>
<button
className='btnMain'
type='button'
style={{ width: '100%' }}
onClick={discoveredCount ? handleDiscoveredClick : undefined}
>
<span>
{isFetching ? (
<>
Discovering notes
<Dots />
</>
) : discoveredCount ? (
<>Load {discoveredCount} discovered notes</>
) : (
<>No new notes</>
)}
</span>
</button>
</div>
{isFetching && <LoadingSpinner desc='Fetching notes from relays' />} {isFetching && <LoadingSpinner desc='Fetching notes from relays' />}
{filteredNotes.length === 0 && !isFetching && ( {filteredNotes.length === 0 && !isFetching && (
<div className='IBMSMListFeedNoPosts'> <div className='IBMSMListFeedNoPosts'>

View File

@ -942,7 +942,7 @@ const ProfileTabPosts = () => {
const handleLoadMore = () => { const handleLoadMore = () => {
const LOAD_MORE_STEP = SHOWING_STEP * 2 const LOAD_MORE_STEP = SHOWING_STEP * 2
setShowing((prev) => prev + SHOWING_STEP) setShowing((prev) => prev + SHOWING_STEP)
const lastNote = filteredNotes[filteredNotes.length - 1] const lastNote = notes[notes.length - 1]
const filter: NDKFilter = { const filter: NDKFilter = {
authors: [profilePubkey], authors: [profilePubkey],
kinds: [NDKKind.Text, NDKKind.Repost], kinds: [NDKKind.Text, NDKKind.Repost],