feat(profile): add posts tab
This commit is contained in:
parent
79660f63ec
commit
b39f8a4a4c
@ -21,7 +21,7 @@ import { useState } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { appRoutes, getProfilePageRoute } from 'routes'
|
||||
import { FeedPostsFilter, NSFWFilter, UserProfile } from 'types'
|
||||
import { DEFAULT_FILTER_OPTIONS, hexToNpub } from 'utils'
|
||||
import { DEFAULT_FILTER_OPTIONS, hexToNpub, log, LogType } from 'utils'
|
||||
import { NoteRepostPopup } from './NoteRepostPopup'
|
||||
import { NoteQuoteRepostPopup } from './NoteQuoteRepostPopup'
|
||||
import { NsfwCommentWrapper } from 'components/NsfwCommentWrapper'
|
||||
@ -62,10 +62,26 @@ export const Note = ({ ndkEvent }: NoteProps) => {
|
||||
ndkEvent.author.fetchProfile().then((res) => setEventProfile(res))
|
||||
|
||||
if (isRepost) {
|
||||
const parsedEvent = JSON.parse(ndkEvent.content)
|
||||
const ndkRepostEvent = new NDKEvent(ndk, parsedEvent)
|
||||
setRepostEvent(ndkRepostEvent)
|
||||
ndkRepostEvent.author.fetchProfile().then((res) => setRepostProfile(res))
|
||||
try {
|
||||
const parsedEvent = JSON.parse(ndkEvent.content)
|
||||
const ndkRepostEvent = new NDKEvent(ndk, parsedEvent)
|
||||
setRepostEvent(ndkRepostEvent)
|
||||
ndkRepostEvent.author
|
||||
.fetchProfile()
|
||||
.then((res) => setRepostProfile(res))
|
||||
} catch (error) {
|
||||
if (error instanceof SyntaxError) {
|
||||
log(
|
||||
true,
|
||||
LogType.Error,
|
||||
'Event content malformed',
|
||||
error,
|
||||
ndkEvent.content
|
||||
)
|
||||
} else {
|
||||
log(true, LogType.Error, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const repostFilter: NDKFilter = {
|
||||
|
@ -7,7 +7,7 @@ import { CommentContent } from 'components/comment/CommentContent'
|
||||
import { getProfilePageRoute } from 'routes'
|
||||
import { nip19 } from 'nostr-tools'
|
||||
import { UserProfile } from 'types'
|
||||
import { hexToNpub } from 'utils'
|
||||
import { hexToNpub, log, LogType } from 'utils'
|
||||
import { formatDate } from 'date-fns'
|
||||
|
||||
interface NoteRepostProps {
|
||||
@ -28,8 +28,16 @@ export const NoteRepostPopup = ({
|
||||
|
||||
useDidMount(async () => {
|
||||
const repost = await ndkEvent.repost(false)
|
||||
setContent(JSON.parse(repost.content).content)
|
||||
ndkEvent.author.fetchProfile().then((res) => setProfile(res))
|
||||
try {
|
||||
setContent(JSON.parse(repost.content).content)
|
||||
} catch (error) {
|
||||
if (error instanceof SyntaxError) {
|
||||
log(true, LogType.Error, 'Repost event content malformed', error)
|
||||
} else {
|
||||
log(true, LogType.Error, error)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const profileRoute = getProfilePageRoute(
|
||||
|
@ -22,9 +22,9 @@ export const CommentContent = ({
|
||||
<p>Hide full post</p>
|
||||
</div>
|
||||
)}
|
||||
<p className='IBMSMSMBSSCL_CBText'>
|
||||
<div className='IBMSMSMBSSCL_CBText'>
|
||||
<NoteRender content={text} />
|
||||
</p>
|
||||
</div>
|
||||
{isTextOverflowing && !isExpanded && (
|
||||
<div className='IBMSMSMBSSCL_CBExpand' onClick={toggle}>
|
||||
<p>View full post</p>
|
||||
|
@ -1,4 +1,9 @@
|
||||
import { NDKFilter, NDKKind } from '@nostr-dev-kit/ndk'
|
||||
import {
|
||||
NDKEvent,
|
||||
NDKFilter,
|
||||
NDKKind,
|
||||
NDKSubscriptionCacheUsage
|
||||
} from '@nostr-dev-kit/ndk'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner'
|
||||
import { ModCard } from 'components/ModCard'
|
||||
import { ModFilter } from 'components/Filters/ModsFilter'
|
||||
@ -19,10 +24,12 @@ import { toast } from 'react-toastify'
|
||||
import { appRoutes } from 'routes'
|
||||
import {
|
||||
BlogCardDetails,
|
||||
FeedPostsFilter,
|
||||
FilterOptions,
|
||||
ModDetails,
|
||||
ModeratedFilter,
|
||||
NSFWFilter,
|
||||
RepostFilter,
|
||||
SortBy,
|
||||
UserRelaysType
|
||||
} from 'types'
|
||||
@ -42,6 +49,8 @@ import { CheckboxField } from 'components/Inputs'
|
||||
import { ProfilePageLoaderResult } from './loader'
|
||||
import { BlogCard } from 'components/BlogCard'
|
||||
import { BlogsFilter } from 'components/Filters/BlogsFilter'
|
||||
import { FeedFilter } from 'components/Filters/FeedFilter'
|
||||
import { Note } from 'components/Notes/Note'
|
||||
|
||||
export const ProfilePage = () => {
|
||||
const {
|
||||
@ -451,7 +460,7 @@ export const ProfilePage = () => {
|
||||
)}
|
||||
|
||||
{tab === 1 && <ProfileTabBlogs />}
|
||||
{tab === 2 && <>WIP</>}
|
||||
{tab === 2 && <ProfileTabPosts />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -870,3 +879,133 @@ const ProfileTabBlogs = () => {
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const ProfileTabPosts = () => {
|
||||
const SHOWING_STEP = 20
|
||||
const { profilePubkey } = useLoaderData() as ProfilePageLoaderResult
|
||||
const { ndk } = useNDKContext()
|
||||
const [notes, setNotes] = useState<NDKEvent[]>([])
|
||||
const [isFetching, setIsFetching] = useState(false)
|
||||
const [isLoadMoreVisible, setIsLoadMoreVisible] = useState(true)
|
||||
const [showing, setShowing] = useState(SHOWING_STEP)
|
||||
|
||||
const filterKey = 'filter-feed-2'
|
||||
const [filterOptions] = useLocalStorage<FeedPostsFilter>(
|
||||
filterKey,
|
||||
DEFAULT_FILTER_OPTIONS
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
setIsFetching(true)
|
||||
setIsLoadMoreVisible(true)
|
||||
|
||||
const filter: NDKFilter = {
|
||||
authors: [profilePubkey],
|
||||
kinds: [NDKKind.Text, NDKKind.Repost],
|
||||
limit: 50
|
||||
}
|
||||
|
||||
ndk
|
||||
.fetchEvents(filter, {
|
||||
closeOnEose: true,
|
||||
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
|
||||
})
|
||||
.then((ndkEventSet) => {
|
||||
const ndkEvents = Array.from(ndkEventSet)
|
||||
setNotes(ndkEvents)
|
||||
})
|
||||
.finally(() => {
|
||||
setIsFetching(false)
|
||||
})
|
||||
}, [ndk, profilePubkey])
|
||||
|
||||
const filteredNotes = useMemo(() => {
|
||||
let _notes = notes || []
|
||||
_notes = _notes.filter((n) => {
|
||||
if (n.kind === NDKKind.Text) {
|
||||
// Filter out the replies (Kind 1 events with e tags are replies to other kind 1 events)
|
||||
return n.getMatchingTags('e').length === 0
|
||||
}
|
||||
// Filter repost events if the option is set to hide reposts
|
||||
return !(
|
||||
n.kind === NDKKind.Repost &&
|
||||
filterOptions.repost === RepostFilter.Hide_Repost
|
||||
)
|
||||
})
|
||||
|
||||
_notes = _notes.sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0))
|
||||
|
||||
showing > 0 && _notes.splice(showing)
|
||||
return _notes
|
||||
}, [filterOptions.repost, notes, showing])
|
||||
|
||||
const handleLoadMore = () => {
|
||||
const LOAD_MORE_STEP = SHOWING_STEP * 2
|
||||
setShowing((prev) => prev + SHOWING_STEP)
|
||||
const lastNote = filteredNotes[filteredNotes.length - 1]
|
||||
const filter: NDKFilter = {
|
||||
authors: [profilePubkey],
|
||||
kinds: [NDKKind.Text, NDKKind.Repost],
|
||||
limit: LOAD_MORE_STEP
|
||||
}
|
||||
|
||||
filter.until = lastNote.created_at
|
||||
|
||||
setIsFetching(true)
|
||||
ndk
|
||||
.fetchEvents(filter, {
|
||||
closeOnEose: true,
|
||||
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
|
||||
})
|
||||
.then((ndkEventSet) => {
|
||||
setNotes((prevNotes) => {
|
||||
const newNotes = Array.from(ndkEventSet)
|
||||
const combinedNotes = [...prevNotes, ...newNotes]
|
||||
const uniqueBlogs = Array.from(
|
||||
new Set(combinedNotes.map((b) => b.id))
|
||||
)
|
||||
.map((id) => combinedNotes.find((b) => b.id === id))
|
||||
.filter((b) => b !== undefined)
|
||||
|
||||
if (newNotes.length < LOAD_MORE_STEP) {
|
||||
setIsLoadMoreVisible(false)
|
||||
}
|
||||
|
||||
return uniqueBlogs
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
setIsFetching(false)
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FeedFilter tab={2} />
|
||||
{isFetching && <LoadingSpinner desc='Fetching notes from relays' />}
|
||||
{filteredNotes.length === 0 && !isFetching && (
|
||||
<div className='IBMSMListFeedNoPosts'>
|
||||
<p>There are no posts to show</p>
|
||||
</div>
|
||||
)}
|
||||
<div className='IBMSMSplitMainFullSideSec IBMSMSMFSSContent'>
|
||||
<div className='IBMSMSMFSSContentPosts'>
|
||||
{filteredNotes.map((note) => (
|
||||
<Note key={note.id} ndkEvent={note} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{!isFetching && isLoadMoreVisible && filteredNotes.length > 0 && (
|
||||
<div className='IBMSMListFeedLoadMore'>
|
||||
<button
|
||||
className='btn btnMain IBMSMListFeedLoadMoreBtn'
|
||||
type='button'
|
||||
onClick={handleLoadMore}
|
||||
>
|
||||
Load More
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user