fix(comments): publish and discovery interaction, add discovery to popup

This commit is contained in:
en 2025-01-30 14:20:44 +01:00
parent a92d1da7ad
commit bf18d61f1f
3 changed files with 117 additions and 36 deletions

View File

@ -10,7 +10,7 @@ import {
useParams useParams
} from 'react-router-dom' } from 'react-router-dom'
import { getBlogPageRoute, getModPageRoute, getProfilePageRoute } from 'routes' import { getBlogPageRoute, getModPageRoute, getProfilePageRoute } from 'routes'
import { UserProfile } from 'types' import { CommentEvent, UserProfile } from 'types'
import { CommentsLoaderResult } from 'types/comments' import { CommentsLoaderResult } from 'types/comments'
import { adjustTextareaHeight, handleCommentSubmit, hexToNpub } from 'utils' import { adjustTextareaHeight, handleCommentSubmit, hexToNpub } from 'utils'
import { Reactions } from './Reactions' import { Reactions } from './Reactions'
@ -74,7 +74,30 @@ export const CommentsPopup = () => {
adjustTextareaHeight(e.currentTarget) adjustTextareaHeight(e.currentTarget)
}, []) }, [])
const handleSubmit = handleCommentSubmit(event, setCommentEvents, ndk) const [visible, setVisible] = useState<CommentEvent[]>([])
const discoveredCount = commentEvents.length - visible.length
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
// Initial loading to indicate comments fetching (stop after 5 seconds)
const t = window.setTimeout(() => setIsLoading(false), 5000)
return () => {
window.clearTimeout(t)
}
}, [])
useEffect(() => {
if (isLoading) {
setVisible(commentEvents)
}
}, [commentEvents, isLoading])
const handleDiscoveredClick = () => {
setVisible(commentEvents)
}
const handleSubmit = handleCommentSubmit(
event,
setCommentEvents,
setVisible,
ndk
)
const handleComment = async () => { const handleComment = async () => {
setIsSubmitting(true) setIsSubmitting(true)
@ -273,8 +296,41 @@ export const CommentsPopup = () => {
</div> </div>
{commentEvents.length > 0 && ( {commentEvents.length > 0 && (
<> <>
<h3 className='IBMSMSMBSSCL_CommentNoteRepliesTitle'> <h3
className='IBMSMSMBSSCL_CommentNoteRepliesTitle'
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between'
}}
>
Replies Replies
<div
style={{
fontSize: '16px'
}}
>
<button
type='button'
className='btnMain'
onClick={
discoveredCount ? handleDiscoveredClick : undefined
}
>
<span>
{isLoading ? (
<>
Discovering replies
<Dots />
</>
) : discoveredCount ? (
<>Load {discoveredCount} discovered replies</>
) : (
<>No new replies</>
)}
</span>
</button>
</div>
</h3> </h3>
<div className='pUMCB_RepliesToPrime'> <div className='pUMCB_RepliesToPrime'>
{commentEvents.map((reply) => ( {commentEvents.map((reply) => (

View File

@ -1,4 +1,4 @@
import { Spinner } from 'components/Spinner' import { Dots } from 'components/Spinner'
import { useNDKContext } from 'hooks' import { useNDKContext } from 'hooks'
import { useComments } from 'hooks/useComments' import { useComments } from 'hooks/useComments'
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react' import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react'
@ -48,12 +48,16 @@ export const Comments = ({ addressable, setCommentCount }: Props) => {
setCommentCount(commentEvents.length) setCommentCount(commentEvents.length)
}, [commentEvents, setCommentCount]) }, [commentEvents, setCommentCount])
const handleSubmit = handleCommentSubmit(event, setCommentEvents, ndk)
const handleDiscoveredClick = () => { const handleDiscoveredClick = () => {
setVisible(commentEvents) setVisible(commentEvents)
} }
const [visible, setVisible] = useState<CommentEvent[]>([]) const [visible, setVisible] = useState<CommentEvent[]>([])
const handleSubmit = handleCommentSubmit(
event,
setCommentEvents,
setVisible,
ndk
)
useEffect(() => { useEffect(() => {
if (isLoading) { if (isLoading) {
setVisible(commentEvents) setVisible(commentEvents)
@ -93,17 +97,24 @@ export const Comments = ({ addressable, setCommentCount }: Props) => {
{/* Hide comment form if aTag is missing */} {/* Hide comment form if aTag is missing */}
{!!addressable.aTag && <CommentForm handleSubmit={handleSubmit} />} {!!addressable.aTag && <CommentForm handleSubmit={handleSubmit} />}
<div> <div>
{isLoading ? ( <button
<Spinner /> type='button'
) : ( className='btnMain'
<button onClick={discoveredCount ? handleDiscoveredClick : undefined}
type='button' >
className='btnMain' <span>
onClick={discoveredCount ? handleDiscoveredClick : undefined} {isLoading ? (
> <>
<span>Load {discoveredCount} discovered comments</span> Discovering comments
</button> <Dots />
)} </>
) : discoveredCount ? (
<>Load {discoveredCount} discovered comments</>
) : (
<>No new comments</>
)}
</span>
</button>
</div> </div>
<Filter <Filter
filterOptions={filterOptions} filterOptions={filterOptions}

View File

@ -6,6 +6,7 @@ import { log, LogType } from './utils'
export function handleCommentSubmit( export function handleCommentSubmit(
event: NDKEvent | undefined, event: NDKEvent | undefined,
setCommentEvents: React.Dispatch<React.SetStateAction<CommentEvent[]>>, setCommentEvents: React.Dispatch<React.SetStateAction<CommentEvent[]>>,
setVisible: React.Dispatch<React.SetStateAction<CommentEvent[]>>,
ndk: NDK ndk: NDK
) { ) {
return async (content: string): Promise<boolean> => { return async (content: string): Promise<boolean> => {
@ -19,13 +20,18 @@ export function handleCommentSubmit(
const reply = event.reply() const reply = event.reply()
reply.content = content.trim() reply.content = content.trim()
setCommentEvents((prev) => [ setCommentEvents((prev) => {
{ const newCommentEvents = [
event: reply, {
status: CommentEventStatus.Publishing event: reply,
}, status: CommentEventStatus.Publishing
...prev },
]) ...prev
]
setVisible(newCommentEvents)
return newCommentEvents
})
if (!ndk.signer) { if (!ndk.signer) {
ndk.signer = new NDKNip07Signer() ndk.signer = new NDKNip07Signer()
} }
@ -33,8 +39,8 @@ export function handleCommentSubmit(
id = reply.id id = reply.id
const relaySet = await reply.publish() const relaySet = await reply.publish()
if (relaySet.size) { if (relaySet.size) {
setCommentEvents((prev) => setCommentEvents((prev) => {
prev.map((ce) => { const newCommentEvents = prev.map((ce) => {
if (ce.event.id === reply.id) { if (ce.event.id === reply.id) {
return { return {
event: ce.event, event: ce.event,
@ -43,23 +49,27 @@ export function handleCommentSubmit(
} }
return ce return ce
}) })
) setVisible(newCommentEvents)
return newCommentEvents
})
// when an event is successfully published remove the status from it after 15 seconds // when an event is successfully published remove the status from it after 15 seconds
setTimeout(() => { setTimeout(() => {
setCommentEvents((prev) => setCommentEvents((prev) => {
prev.map((ce) => { const newCommentEvents = prev.map((ce) => {
if (ce.event.id === reply.id) { if (ce.event.id === reply.id) {
delete ce.status delete ce.status
} }
return ce return ce
}) })
) setVisible(newCommentEvents)
return newCommentEvents
})
}, 15000) }, 15000)
} else { } else {
log(true, LogType.Error, 'Publishing reply failed.') log(true, LogType.Error, 'Publishing reply failed.')
setCommentEvents((prev) => setCommentEvents((prev) => {
prev.map((ce) => { const newCommentEvents = prev.map((ce) => {
if (ce.event.id === reply.id) { if (ce.event.id === reply.id) {
return { return {
event: ce.event, event: ce.event,
@ -68,14 +78,16 @@ export function handleCommentSubmit(
} }
return ce return ce
}) })
) setVisible(newCommentEvents)
return newCommentEvents
})
} }
return false return false
} catch (error) { } catch (error) {
toast.error('An error occurred in publishing reply.') toast.error('An error occurred in publishing reply.')
log(true, LogType.Error, 'An error occurred in publishing reply.', error) log(true, LogType.Error, 'An error occurred in publishing reply.', error)
setCommentEvents((prev) => setCommentEvents((prev) => {
prev.map((ce) => { const newCommentEvents = prev.map((ce) => {
if (ce.event.id === id) { if (ce.event.id === id) {
return { return {
event: ce.event, event: ce.event,
@ -84,7 +96,9 @@ export function handleCommentSubmit(
} }
return ce return ce
}) })
) setVisible(newCommentEvents)
return newCommentEvents
})
return false return false
} }
} }