diff --git a/src/hooks/use-reply.ts b/src/hooks/use-reply.ts new file mode 100644 index 00000000..a42d1fab --- /dev/null +++ b/src/hooks/use-reply.ts @@ -0,0 +1,85 @@ +import { useMemo } from 'react'; +import { ChallengeVerification, Comment, PublishCommentOptions, usePublishComment } from '@plebbit/plebbit-react-hooks'; +import { create } from 'zustand'; +import useChallengesStore from './use-challenges'; +import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils'; + +type SetReplyStoreData = { + subplebbitAddress: string; + parentCid: string; + content: string | undefined; + link: string | undefined; + spoiler: boolean; +}; + +type ReplyState = { + content: { [parentCid: string]: string | undefined }; + link: { [parentCid: string]: string | undefined }; + spoiler: { [parentCid: string]: boolean | undefined }; + publishCommentOptions: PublishCommentOptions; + setReplyStore: (data: SetReplyStoreData) => void; + resetReplyStore: (parentCid: string) => void; +}; + +const { addChallenge } = useChallengesStore.getState(); + +const useReplyStore = create((set) => ({ + content: {}, + link: {}, + spoiler: {}, + publishCommentOptions: {}, + setReplyStore: (data: SetReplyStoreData) => + set((state) => { + const { subplebbitAddress, parentCid, content, link, spoiler } = data; + const publishCommentOptions = { + subplebbitAddress, + parentCid, + content, + link, + spoiler, + onChallenge: (...args: any) => addChallenge(args), + onChallengeVerification: (challengeVerification: ChallengeVerification, comment: Comment) => { + alertChallengeVerificationFailed(challengeVerification, comment); + }, + onError: (error: Error) => { + console.error(error); + alert(error.message); + }, + }; + return { + content: { ...state.content, [parentCid]: content }, + link: { ...state.link, [parentCid]: link }, + spoiler: { ...state.spoiler, [parentCid]: spoiler }, + publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: publishCommentOptions }, + }; + }), + + resetReplyStore: (parentCid) => + set((state) => ({ + content: { ...state.content, [parentCid]: undefined }, + link: { ...state.link, [parentCid]: undefined }, + spoiler: { ...state.spoiler, [parentCid]: undefined }, + publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: undefined }, + })), +})); + +const useReply = (comment: Comment) => { + const subplebbitAddress = comment?.subplebbitAddress; + const parentCid = comment?.cid; + const publishCommentOptions = useReplyStore((state) => state.publishCommentOptions[parentCid]); + const setReplyStore = useReplyStore((state) => state.setReplyStore); + const resetReplyStore = useReplyStore((state) => state.resetReplyStore); + + const setContent = useMemo( + () => (content: string | undefined, link: string | undefined, spoiler: boolean) => setReplyStore({ subplebbitAddress, parentCid, content, link, spoiler }), + [subplebbitAddress, parentCid, setReplyStore, comment], + ); + + const resetContent = useMemo(() => () => resetReplyStore(parentCid), [parentCid, resetReplyStore]); + + const { index, publishComment } = usePublishComment(publishCommentOptions); + + return { setContent, resetContent, replyIndex: index, publishReply: publishComment }; +}; + +export default useReply; diff --git a/src/views/post/post.tsx b/src/views/post/post.tsx index 64842c52..9ca6aaa3 100644 --- a/src/views/post/post.tsx +++ b/src/views/post/post.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; import { useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import { useTranslation } from 'react-i18next'; @@ -7,19 +7,55 @@ import PostComponent from '../../components/post'; import useReplies from '../../hooks/use-replies'; import Reply from '../../components/reply'; import useStateString from '../../hooks/use-state-string'; +import useReply from '../../hooks/use-reply'; import { usePendingReplyCount } from '../../hooks/use-pending-replycount'; const Post = () => { + const { t } = useTranslation(); const { commentCid } = useParams(); const comment = useComment({ commentCid }); - const { content, replyCount, subplebbitAddress, title } = comment || {}; + const { replyCount, subplebbitAddress, title } = comment || {}; const subplebbit = useSubplebbit({ subplebbitAddress }); - const replies = useReplies(comment).map((reply, index) => ) || ''; - const postTitle = title?.slice(0, 40) || content?.slice(0, 40); - const subplebbitTitle = subplebbit?.title || subplebbit?.shortAddress; - const { t } = useTranslation(); const stateString = useStateString(comment); - const commentCount = replyCount === 0 ? t('no_comments') : replyCount === 1 ? t('one_comment') : t('all_comments', { count: replyCount }); + + const replies = useReplies(comment).map((reply, index) => ) || ''; + const { setContent, resetContent, replyIndex, publishReply } = useReply(comment); + + const postTitle = title?.slice(0, 40) || comment?.content?.slice(0, 40); + const subplebbitTitle = subplebbit?.title || subplebbit?.shortAddress; + + const textRef = useRef(null); + const urlRef = useRef(null); + const spoilerRef = useRef(null); + + const pendingReplyCount = usePendingReplyCount({ parentCommentCid: commentCid }); + const totalReplyCount = replyCount + pendingReplyCount; + const commentCount = totalReplyCount === 0 ? t('no_comments') : totalReplyCount === 1 ? t('one_comment') : t('all_comments', { count: totalReplyCount }); + + const [readyToPublish, setReadyToPublish] = useState(false); + + const onPublish = () => { + const currentContent = textRef.current?.value || ''; + if (!currentContent.trim()) { + alert(`missing content`); + return; + } + setContent(textRef.current?.value || undefined, urlRef.current?.value || undefined, spoilerRef.current?.checked || false); + setReadyToPublish(true); + }; + + useEffect(() => { + if (readyToPublish) { + publishReply(); + setReadyToPublish(false); + } + }, [readyToPublish, publishReply]); + + useEffect(() => { + if (typeof replyIndex === 'number') { + resetContent(); + } + }, [replyIndex, resetContent]); useEffect(() => { document.title = `${postTitle || ''}${postTitle && subplebbitTitle ? ' - ' : ''}${subplebbitTitle || ''}${postTitle || subplebbitTitle ? ' - seedit' : 'seedit'}`; @@ -45,14 +81,16 @@ const Post = () => {
- + - {t('spoiler')}: + {t('spoiler')}: -