import { NDKEvent } from '@nostr-dev-kit/ndk' import { ZapPopUp } from 'components/Zap' import { formatDate } from 'date-fns' import { useAppSelector, useBodyScrollDisable, useDidMount, useNDKContext, useReactions } from 'hooks' import { useComments } from 'hooks/useComments' import { Event, kinds, nip19, UnsignedEvent } from 'nostr-tools' import React, { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react' import { Link } from 'react-router-dom' import { toast } from 'react-toastify' import { getProfilePageRoute } from 'routes' import { Addressable, CommentEvent, CommentEventStatus, UserProfile } from 'types/index.ts' import { abbreviateNumber, hexToNpub, log, LogType, now } from 'utils' enum SortByEnum { Latest = 'Latest', Oldest = 'Oldest' } enum AuthorFilterEnum { All_Comments = 'All Comments', Creator_Comments = 'Creator Comments' } type FilterOptions = { sort: SortByEnum author: AuthorFilterEnum } type Props = { addressable: Addressable setCommentCount: Dispatch> } export const Comments = ({ addressable, setCommentCount }: Props) => { const { ndk, publish } = useNDKContext() const { commentEvents, setCommentEvents } = useComments( addressable.author, addressable.aTag ) const [filterOptions, setFilterOptions] = useState({ sort: SortByEnum.Latest, author: AuthorFilterEnum.All_Comments }) useEffect(() => { setCommentCount(commentEvents.length) }, [commentEvents, setCommentCount]) const userState = useAppSelector((state) => state.user) const handleSubmit = async (content: string): Promise => { if (content === '') return false let pubkey: string if (userState.auth && userState.user?.pubkey) { pubkey = userState.user.pubkey as string } else { pubkey = (await window.nostr?.getPublicKey()) as string } if (!pubkey) { toast.error('Could not get user pubkey') return false } const unsignedEvent: UnsignedEvent = { content: content, pubkey: pubkey, kind: kinds.ShortTextNote, created_at: now(), tags: [ ['e', addressable.id], ['a', addressable.aTag], ['p', addressable.author] ] } const signedEvent = await window.nostr ?.signEvent(unsignedEvent) .then((event) => event as Event) .catch((err) => { toast.error('Failed to sign the event!') log(true, LogType.Error, 'Failed to sign the event!', err) return null }) if (!signedEvent) return false setCommentEvents((prev) => [ { ...signedEvent, status: CommentEventStatus.Publishing }, ...prev ]) const ndkEvent = new NDKEvent(ndk, signedEvent) publish(ndkEvent) .then((publishedOnRelays) => { if (publishedOnRelays.length === 0) { setCommentEvents((prev) => prev.map((event) => { if (event.id === signedEvent.id) { return { ...event, status: CommentEventStatus.Failed } } return event }) ) } else { setCommentEvents((prev) => prev.map((event) => { if (event.id === signedEvent.id) { return { ...event, status: CommentEventStatus.Published } } return event }) ) } // when an event is successfully published remove the status from it after 15 seconds setTimeout(() => { setCommentEvents((prev) => prev.map((event) => { if (event.id === signedEvent.id) { delete event.status } return event }) ) }, 15000) }) .catch((err) => { console.error('An error occurred in publishing comment', err) setCommentEvents((prev) => prev.map((event) => { if (event.id === signedEvent.id) { return { ...event, status: CommentEventStatus.Failed } } return event }) ) }) return true } const comments = useMemo(() => { let filteredComments = commentEvents if (filterOptions.author === AuthorFilterEnum.Creator_Comments) { filteredComments = filteredComments.filter( (comment) => comment.pubkey === addressable.author ) } if (filterOptions.sort === SortByEnum.Latest) { filteredComments.sort((a, b) => b.created_at - a.created_at) } else if (filterOptions.sort === SortByEnum.Oldest) { filteredComments.sort((a, b) => a.created_at - b.created_at) } return filteredComments }, [commentEvents, filterOptions, addressable.author]) return (

Comments

{/* Hide comment form if aTag is missing */} {!!addressable.aTag && }
{comments.map((event) => ( ))}
) } type CommentFormProps = { handleSubmit: (content: string) => Promise } const CommentForm = ({ handleSubmit }: CommentFormProps) => { const [isSubmitting, setIsSubmitting] = useState(false) const [commentText, setCommentText] = useState('') const handleComment = async () => { setIsSubmitting(true) const submitted = await handleSubmit(commentText) if (submitted) setCommentText('') setIsSubmitting(false) } return (