import { Dots } from 'components/Spinner' import { useNDKContext } from 'hooks' import { useComments } from 'hooks/useComments' import { Dispatch, SetStateAction, useEffect, useMemo, useState } from 'react' import { useLoaderData } from 'react-router-dom' import { Addressable, AuthorFilterEnum, BlogPageLoaderResult, CommentEvent, ModPageLoaderResult, SortByEnum } from 'types' import { handleCommentSubmit } from 'utils' import { Filter, FilterOptions } from './Filter' import { CommentForm } from './CommentForm' import { Comment } from './Comment' type Props = { addressable: Addressable setCommentCount: Dispatch<SetStateAction<number>> } export const Comments = ({ addressable, setCommentCount }: Props) => { const { ndk } = useNDKContext() const { commentEvents, setCommentEvents } = useComments( addressable.author, addressable.aTag ) const { event } = useLoaderData() as | ModPageLoaderResult | BlogPageLoaderResult const [filterOptions, setFilterOptions] = useState<FilterOptions>({ sort: SortByEnum.Latest, author: AuthorFilterEnum.All_Comments }) 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(() => { setCommentCount(commentEvents.length) }, [commentEvents, setCommentCount]) const handleDiscoveredClick = () => { setVisible(commentEvents) } const [visible, setVisible] = useState<CommentEvent[]>([]) const handleSubmit = handleCommentSubmit( event, setCommentEvents, setVisible, ndk ) useEffect(() => { if (isLoading) { setVisible(commentEvents) } }, [commentEvents, isLoading]) const comments = useMemo(() => { let filteredComments = visible if (filterOptions.author === AuthorFilterEnum.Creator_Comments) { filteredComments = filteredComments.filter( (comment) => comment.event.pubkey === addressable.author ) } if (filterOptions.sort === SortByEnum.Latest) { filteredComments.sort((a, b) => a.event.created_at && b.event.created_at ? b.event.created_at - a.event.created_at : 0 ) } else if (filterOptions.sort === SortByEnum.Oldest) { filteredComments.sort((a, b) => a.event.created_at && b.event.created_at ? a.event.created_at - b.event.created_at : 0 ) } return filteredComments }, [visible, filterOptions.author, filterOptions.sort, addressable.author]) const discoveredCount = commentEvents.length - visible.length return ( <div className='IBMSMSMBSSCommentsWrapper'> <h4 className='IBMSMSMBSSTitle'>Comments</h4> <div className='IBMSMSMBSSComments'> {/* Hide comment form if aTag is missing */} {!!addressable.aTag && <CommentForm handleSubmit={handleSubmit} />} <div> <button type='button' className='btnMain' onClick={discoveredCount ? handleDiscoveredClick : undefined} > <span> {isLoading ? ( <> Discovering comments <Dots /> </> ) : discoveredCount ? ( <>Load {discoveredCount} discovered comments</> ) : ( <>No new comments</> )} </span> </button> </div> <Filter filterOptions={filterOptions} setFilterOptions={setFilterOptions} /> <div className='IBMSMSMBSSCommentsList'> {comments.map((comment) => ( <Comment key={comment.event.id} comment={comment} /> ))} </div> </div> </div> ) }