import { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { Comment, PublishCommentOptions, setAccount, useAccount, useAccountComment, useComment, useEditedComment, usePublishComment, useSubplebbit, } from '@plebbit/plebbit-react-hooks'; import { create } from 'zustand'; import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils'; import { getLinkMediaInfo } from '../../lib/utils/media-utils'; import { isValidURL } from '../../lib/utils/url-utils'; import { isAllView, isDescriptionView, isPostPageView, isRulesView, isSubscriptionsView } from '../../lib/utils/view-utils'; import { useDefaultSubplebbitAddresses } from '../../hooks/use-default-subplebbits'; import usePublishReply from '../../hooks/use-publish-reply'; import useChallengesStore from '../../stores/use-challenges-store'; import styles from './post-form.module.css'; import _ from 'lodash'; import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline'; import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame'; import useAnonMode from '../../hooks/use-anon-mode'; type SubmitState = { author?: any | undefined; displayName?: string | undefined; signer?: any | undefined; subplebbitAddress: string | undefined; title: string | undefined; content: string | undefined; link: string | undefined; spoiler: boolean | undefined; publishCommentOptions: PublishCommentOptions; setSubmitStore: (data: Partial) => void; resetSubmitStore: () => void; }; const { addChallenge } = useChallengesStore.getState(); const useSubmitStore = create((set) => ({ author: undefined, displayName: undefined, signer: undefined, subplebbitAddress: undefined, title: undefined, content: undefined, link: undefined, spoiler: undefined, publishCommentOptions: {}, setSubmitStore: ({ author, displayName, signer, subplebbitAddress, title, content, link, spoiler }) => set((state) => { const updatedAuthor = displayName ? { ...author, displayName } : author; const nextState = { ...state }; if (author !== undefined) nextState.author = updatedAuthor; if (signer !== undefined) nextState.signer = signer; if (subplebbitAddress !== undefined) nextState.subplebbitAddress = subplebbitAddress; if (title !== undefined) nextState.title = title || undefined; if (content !== undefined) nextState.content = content || undefined; if (link !== undefined) nextState.link = link || undefined; if (spoiler !== undefined) nextState.spoiler = spoiler || undefined; const publishCommentOptions: PublishCommentOptions = { subplebbitAddress: nextState.subplebbitAddress, title: nextState.title, content: nextState.content, link: nextState.link, spoiler: nextState.spoiler, onChallenge: (...args: any) => addChallenge(args), onChallengeVerification: alertChallengeVerificationFailed, onError: (error: Error) => { console.error(error); alert(error.message); }, }; if (nextState.signer) { publishCommentOptions.signer = nextState.signer; } if (nextState.author) { publishCommentOptions.author = nextState.author; } nextState.publishCommentOptions = publishCommentOptions; return nextState; }), resetSubmitStore: () => set({ author: undefined, displayName: undefined, signer: undefined, subplebbitAddress: undefined, title: undefined, content: undefined, link: undefined, spoiler: undefined, publishCommentOptions: {}, }), })); export const LinkTypePreviewer = ({ link }: { link: string }) => { const { t } = useTranslation(); const mediaInfo = getLinkMediaInfo(link); let type = mediaInfo?.type; const gifFrameUrl = useFetchGifFirstFrame(mediaInfo?.url); if (type === 'gif' && gifFrameUrl !== null) { type = t('animated_gif'); } else if (type === 'gif' && gifFrameUrl === null) { type = t('static_gif'); } return isValidURL(link) ? type : t('invalid_url'); }; const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid: string }) => { const { t } = useTranslation(); const account = useAccount(); const author = account?.author || {}; const { displayName } = author || {}; const [url, setUrl] = useState(''); const { title, content, link, publishCommentOptions, setSubmitStore, resetSubmitStore } = useSubmitStore(); const { index, publishComment } = usePublishComment(publishCommentOptions); const textRef = useRef(null); const urlRef = useRef(null); const subjectRef = useRef(null); const location = useLocation(); const isInAllView = isAllView(location.pathname, useParams()); const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams()); const subscriptions = account?.subscriptions || []; const defaultSubplebbitAddresses = useDefaultSubplebbitAddresses(); const { anonMode, getNewSigner, getExistingSigner } = useAnonMode(postCid); const comment = useComment({ commentCid: postCid }); const address = comment?.author?.address; const resetFields = () => { if (textRef.current) { textRef.current.value = ''; } if (urlRef.current) { urlRef.current.value = ''; } if (subjectRef.current) { subjectRef.current.value = ''; } }; const hasCalledAnonAddressRef = useRef(false); const getAnonAddressForPost = useCallback(async () => { if (anonMode) { if (!hasCalledAnonAddressRef.current) { hasCalledAnonAddressRef.current = true; const newSigner = (await getNewSigner()) || {}; setSubmitStore({ signer: newSigner, author: { address: newSigner.address, displayName: account?.author?.displayName, }, }); } } else { setSubmitStore({ signer: undefined, author: { address: account?.author?.address, displayName: account?.author?.displayName, }, }); } }, [anonMode, getNewSigner, account, setSubmitStore]); const onPublishPost = async () => { if (!title && !content && !link) { alert(`Cannot post empty comment`); return; } if (link && !isValidURL(link)) { alert('The provided link is not a valid URL.'); return; } if (!anonMode) { setSubmitStore({ signer: undefined, author: { address: account?.author?.address, displayName: account?.author?.displayName, }, }); } publishComment(); }; const params = useParams(); const accountComment = useAccountComment({ commentIndex: params?.accountCommentIndex as any }); const subplebbitAddress = params?.subplebbitAddress || accountComment?.subplebbitAddress; useEffect(() => { if (subplebbitAddress) { setSubmitStore({ subplebbitAddress }); } }, [subplebbitAddress, setSubmitStore]); // redirect to pending page when pending comment is created const navigate = useNavigate(); useEffect(() => { if (typeof index === 'number') { resetSubmitStore(); resetFields(); navigate(`/profile/${index}`); } }, [index, resetSubmitStore, navigate]); // in post page, publish a reply to the post const isInPostView = isPostPageView(location.pathname, params); const cid = params?.commentCid as string; const { setPublishReplyOptions, resetPublishReplyOptions, replyIndex, publishReply } = usePublishReply({ cid, subplebbitAddress }); const getAnonAddressForReply = useCallback(async () => { if (anonMode && !hasCalledAnonAddressRef.current) { hasCalledAnonAddressRef.current = true; const existingSigner = getExistingSigner(address); if (existingSigner) { setPublishReplyOptions({ signer: existingSigner, author: { address: existingSigner.address, }, }); } else { const newSigner = await getNewSigner(); setPublishReplyOptions({ signer: newSigner, author: { address: newSigner.address, }, }); } } }, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, anonMode]); const onPublishReply = () => { const currentContent = textRef.current?.value || ''; const currentUrl = urlRef.current?.value || ''; if (!currentContent.trim() && !currentUrl) { alert(`Cannot post empty comment`); return; } if (currentUrl && !isValidURL(currentUrl)) { alert('The provided link is not a valid URL.'); return; } publishReply(); }; const hasSetInitialDisplayName = useRef(false); useEffect(() => { if (!hasSetInitialDisplayName.current && displayName) { setPublishReplyOptions({ displayName }); hasSetInitialDisplayName.current = true; } }, [displayName, setPublishReplyOptions]); useEffect(() => { if (typeof replyIndex === 'number') { resetPublishReplyOptions(); resetFields(); closeForm(); } }, [replyIndex, resetPublishReplyOptions, closeForm]); useEffect(() => { if (anonMode) { if (isInPostView) { getAnonAddressForReply(); } else { getAnonAddressForPost(); } } }, [anonMode, getAnonAddressForPost, getAnonAddressForReply, isInPostView]); return ( {!isInPostView && ( )}
{t('name')} { setAccount({ ...account, author: { ...account?.author, displayName: e.target.value } }); if (isInPostView) { setPublishReplyOptions({ displayName: e.target.value }); } else { setSubmitStore({ displayName: e.target.value }); } }} /> {isInPostView && }
{t('subject')} { setSubmitStore({ title: e.target.value }); }} />
{t('comment')}