diff --git a/src/components/comment/Comment.tsx b/src/components/comment/Comment.tsx
index 46a2787..25cf56d 100644
--- a/src/components/comment/Comment.tsx
+++ b/src/components/comment/Comment.tsx
@@ -99,7 +99,7 @@ export const Comment = ({ comment }: CommentProps) => {
-
@@ -117,7 +117,7 @@ export const Comment = ({ comment }: CommentProps) => {
-
+
*/}
{typeof profile?.lud16 !== 'undefined' && profile.lud16 !== '' && (
)}
diff --git a/src/components/comment/CommentContent.tsx b/src/components/comment/CommentContent.tsx
index 292a93f..4b6db38 100644
--- a/src/components/comment/CommentContent.tsx
+++ b/src/components/comment/CommentContent.tsx
@@ -7,7 +7,7 @@ export const CommentContent = ({ content }: CommentContentProps) => {
return (
<>
-
{text}
+
{text}
{isTextOverflowing && (
{isExpanded ? 'Hide' : 'View'} full post
diff --git a/src/components/comment/CommentsPopup.tsx b/src/components/comment/CommentsPopup.tsx
index 8cb7d6d..527261d 100644
--- a/src/components/comment/CommentsPopup.tsx
+++ b/src/components/comment/CommentsPopup.tsx
@@ -1,5 +1,5 @@
import { formatDate } from 'date-fns'
-import { useBodyScrollDisable, useNDKContext } from 'hooks'
+import { useBodyScrollDisable, useNDKContext, useReplies } from 'hooks'
import { nip19 } from 'nostr-tools'
import { ChangeEvent, useCallback, useEffect, useMemo, useState } from 'react'
import {
@@ -10,7 +10,7 @@ import {
useParams
} from 'react-router-dom'
import { getBlogPageRoute, getModPageRoute, getProfilePageRoute } from 'routes'
-import { UserProfile } from 'types'
+import { CommentEvent, UserProfile } from 'types'
import { CommentsLoaderResult } from 'types/comments'
import { adjustTextareaHeight, handleCommentSubmit, hexToNpub } from 'utils'
import { Reactions } from './Reactions'
@@ -19,6 +19,7 @@ import { NDKKind } from '@nostr-dev-kit/ndk'
import { Comment } from './Comment'
import { useComments } from 'hooks/useComments'
import { CommentContent } from './CommentContent'
+import { Dots } from 'components/Spinner'
export const CommentsPopup = () => {
const { naddr } = useParams()
@@ -35,7 +36,13 @@ export const CommentsPopup = () => {
: undefined
: undefined
- const { event, parents } = useLoaderData() as CommentsLoaderResult
+ const { event } = useLoaderData() as CommentsLoaderResult
+ const {
+ size,
+ parent: replyEvent,
+ isComplete,
+ root: rootEvent
+ } = useReplies(event.tagValue('e'))
const isRoot = event.tagValue('a') === event.tagValue('A')
const [profile, setProfile] = useState
()
const { commentEvents, setCommentEvents } = useComments(
@@ -56,7 +63,6 @@ export const CommentsPopup = () => {
[event.pubkey]
)
- const replyEvent = parents.length > 0 ? parents[0] : undefined
const navigate = useNavigate()
const [isSubmitting, setIsSubmitting] = useState(false)
@@ -68,7 +74,30 @@ export const CommentsPopup = () => {
adjustTextareaHeight(e.currentTarget)
}, [])
- const handleSubmit = handleCommentSubmit(event, setCommentEvents, ndk)
+ const [visible, setVisible] = useState([])
+ 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 () => {
setIsSubmitting(true)
@@ -110,6 +139,9 @@ export const CommentsPopup = () => {
{replyEvent && (
@@ -126,16 +158,20 @@ export const CommentsPopup = () => {
)}
- Reply Depth: {parents.length}
+ Reply Depth: {size}
+ {!isComplete && }
- {!isRoot && (
+ {!isRoot && rootEvent && (
- Main Post
+ Main Post {!isComplete && }
)}
@@ -185,7 +221,7 @@ export const CommentsPopup = () => {
-
@@ -203,7 +239,7 @@ export const CommentsPopup = () => {
-
+
*/}
{typeof profile?.lud16 !== 'undefined' &&
profile.lud16 !== '' &&
}
@@ -262,6 +298,26 @@ export const CommentsPopup = () => {
<>
Replies
+
{commentEvents.map((reply) => (
diff --git a/src/components/comment/index.tsx b/src/components/comment/index.tsx
index 6edcdaf..7700e27 100644
--- a/src/components/comment/index.tsx
+++ b/src/components/comment/index.tsx
@@ -1,4 +1,4 @@
-import { Spinner } from 'components/Spinner'
+import { Dots } from 'components/Spinner'
import { useNDKContext } from 'hooks'
import { useComments } from 'hooks/useComments'
import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react'
@@ -48,12 +48,16 @@ export const Comments = ({ addressable, setCommentCount }: Props) => {
setCommentCount(commentEvents.length)
}, [commentEvents, setCommentCount])
- const handleSubmit = handleCommentSubmit(event, setCommentEvents, ndk)
-
const handleDiscoveredClick = () => {
setVisible(commentEvents)
}
const [visible, setVisible] = useState
([])
+ const handleSubmit = handleCommentSubmit(
+ event,
+ setCommentEvents,
+ setVisible,
+ ndk
+ )
useEffect(() => {
if (isLoading) {
setVisible(commentEvents)
@@ -93,17 +97,24 @@ export const Comments = ({ addressable, setCommentCount }: Props) => {
{/* Hide comment form if aTag is missing */}
{!!addressable.aTag && }
- {isLoading ? (
-
- ) : (
-
- )}
+
{
+ const { ndk } = useNDKContext()
+ const [replies, setReplies] = useState([])
+ const [isComplete, setIsComplete] = useState(false)
+
+ useDidMount(async () => {
+ if (!eTag) {
+ setIsComplete(true)
+ return
+ }
+
+ let eDepth: string | undefined = eTag
+ while (eDepth) {
+ const previousReply = await ndk.fetchEvent(
+ {
+ kinds: [NDKKind.Text, NDKKind.GenericReply],
+ ids: [eDepth]
+ },
+ {
+ cacheUsage: NDKSubscriptionCacheUsage.CACHE_FIRST
+ }
+ )
+ if (previousReply) {
+ setReplies((p) => {
+ if (p.findIndex((p) => p.id === previousReply.id) === -1) {
+ p.push(previousReply)
+ }
+ return p
+ })
+ eDepth = previousReply.tagValue('e')
+ } else {
+ eDepth = undefined
+ }
+ }
+ setIsComplete(true)
+ })
+
+ return {
+ size: replies.length,
+ isComplete,
+ parent: replies.length > 0 ? replies[0] : undefined,
+ root: isComplete ? replies[replies.length - 1] : undefined
+ }
+}
diff --git a/src/loaders/comment.ts b/src/loaders/comment.ts
index 829ae36..06fa85c 100644
--- a/src/loaders/comment.ts
+++ b/src/loaders/comment.ts
@@ -1,4 +1,3 @@
-import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'
import { NDKContextType } from 'contexts/NDKContext'
import { LoaderFunctionArgs, redirect } from 'react-router-dom'
import { CommentsLoaderResult } from 'types/comments'
@@ -21,23 +20,8 @@ export const commentsLoader =
throw new Error('We are unable to find the comment on the relays')
}
- const replies: NDKEvent[] = []
- let eTag: string | undefined = replyEvent.tagValue('e')
- while (eTag) {
- const prev = await ndkContext.ndk.fetchEvent({
- kinds: [NDKKind.Text, NDKKind.GenericReply],
- ids: [eTag]
- })
- if (prev) {
- replies.push(prev)
- eTag = prev.tagValue('e')
- } else {
- eTag = undefined
- }
- }
const result: Partial = {
- event: replyEvent,
- parents: replies
+ event: replyEvent
}
return result
} catch (error) {
diff --git a/src/styles/comments.css b/src/styles/comments.css
index e728c0f..d0dc7ea 100644
--- a/src/styles/comments.css
+++ b/src/styles/comments.css
@@ -59,6 +59,7 @@
}
.IBMSMSMBSSCL_CBText {
+ white-space: pre-line;
}
.IBMSMSMBSSCL_CBTextStatus {
@@ -478,6 +479,13 @@ hover {
width: 100%;
margin: 0 0 15px 0;
color: rgba(255, 255, 255, 0.5);
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
+
+.IBMSMSMBSSCL_CommentNoteRepliesTitleBtn {
+ font-size: 16px;
}
.IBMSMSMBSSCL_CAElementLoadWrapper {
diff --git a/src/types/comments.ts b/src/types/comments.ts
index bdde1e4..a14a7f0 100644
--- a/src/types/comments.ts
+++ b/src/types/comments.ts
@@ -2,7 +2,6 @@ import { NDKEvent } from '@nostr-dev-kit/ndk'
export interface CommentsLoaderResult {
event: NDKEvent
- parents: NDKEvent[]
}
export enum SortByEnum {
diff --git a/src/utils/comments.ts b/src/utils/comments.ts
index 5bc7987..74c4438 100644
--- a/src/utils/comments.ts
+++ b/src/utils/comments.ts
@@ -6,6 +6,7 @@ import { log, LogType } from './utils'
export function handleCommentSubmit(
event: NDKEvent | undefined,
setCommentEvents: React.Dispatch>,
+ setVisible: React.Dispatch>,
ndk: NDK
) {
return async (content: string): Promise => {
@@ -19,13 +20,18 @@ export function handleCommentSubmit(
const reply = event.reply()
reply.content = content.trim()
- setCommentEvents((prev) => [
- {
- event: reply,
- status: CommentEventStatus.Publishing
- },
- ...prev
- ])
+ setCommentEvents((prev) => {
+ const newCommentEvents = [
+ {
+ event: reply,
+ status: CommentEventStatus.Publishing
+ },
+ ...prev
+ ]
+ setVisible(newCommentEvents)
+ return newCommentEvents
+ })
+
if (!ndk.signer) {
ndk.signer = new NDKNip07Signer()
}
@@ -33,8 +39,8 @@ export function handleCommentSubmit(
id = reply.id
const relaySet = await reply.publish()
if (relaySet.size) {
- setCommentEvents((prev) =>
- prev.map((ce) => {
+ setCommentEvents((prev) => {
+ const newCommentEvents = prev.map((ce) => {
if (ce.event.id === reply.id) {
return {
event: ce.event,
@@ -43,23 +49,28 @@ export function handleCommentSubmit(
}
return ce
})
- )
+ setVisible(newCommentEvents)
+ return newCommentEvents
+ })
// when an event is successfully published remove the status from it after 15 seconds
setTimeout(() => {
- setCommentEvents((prev) =>
- prev.map((ce) => {
+ setCommentEvents((prev) => {
+ const newCommentEvents = prev.map((ce) => {
if (ce.event.id === reply.id) {
delete ce.status
}
return ce
})
- )
+ setVisible(newCommentEvents)
+ return newCommentEvents
+ })
}, 15000)
+ return true
} else {
log(true, LogType.Error, 'Publishing reply failed.')
- setCommentEvents((prev) =>
- prev.map((ce) => {
+ setCommentEvents((prev) => {
+ const newCommentEvents = prev.map((ce) => {
if (ce.event.id === reply.id) {
return {
event: ce.event,
@@ -68,14 +79,16 @@ export function handleCommentSubmit(
}
return ce
})
- )
+ setVisible(newCommentEvents)
+ return newCommentEvents
+ })
+ return false
}
- return false
} catch (error) {
toast.error('An error occurred in publishing reply.')
log(true, LogType.Error, 'An error occurred in publishing reply.', error)
- setCommentEvents((prev) =>
- prev.map((ce) => {
+ setCommentEvents((prev) => {
+ const newCommentEvents = prev.map((ce) => {
if (ce.event.id === id) {
return {
event: ce.event,
@@ -84,7 +97,9 @@ export function handleCommentSubmit(
}
return ce
})
- )
+ setVisible(newCommentEvents)
+ return newCommentEvents
+ })
return false
}
}