diff --git a/src/components/post-desktop/post-desktop.tsx b/src/components/post-desktop/post-desktop.tsx index 77860263..556c9860 100644 --- a/src/components/post-desktop/post-desktop.tsx +++ b/src/components/post-desktop/post-desktop.tsx @@ -138,7 +138,7 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }: !cid && e.preventDefault()}> c/ - openReplyModal && openReplyModal(cid)}> + openReplyModal && openReplyModal(cid, postCid)}> {shortCid} diff --git a/src/components/post-form/post-form.tsx b/src/components/post-form/post-form.tsx index 67291a5d..fb749158 100644 --- a/src/components/post-form/post-form.tsx +++ b/src/components/post-form/post-form.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { @@ -24,8 +24,11 @@ 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; + signer: any | undefined; subplebbitAddress: string | undefined; title: string | undefined; content: string | undefined; @@ -39,15 +42,19 @@ type SubmitState = { const { addChallenge } = useChallengesStore.getState(); const useSubmitStore = create((set) => ({ + author: undefined, + signer: undefined, subplebbitAddress: undefined, title: undefined, content: undefined, link: undefined, spoiler: undefined, publishCommentOptions: {}, - setSubmitStore: ({ subplebbitAddress, title, content, link, spoiler }) => + setSubmitStore: ({ author, signer, subplebbitAddress, title, content, link, spoiler }) => set((state) => { const nextState = { ...state }; + if (author !== undefined) nextState.author = author; + 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; @@ -55,7 +62,13 @@ const useSubmitStore = create((set) => ({ if (spoiler !== undefined) nextState.spoiler = spoiler || undefined; nextState.publishCommentOptions = { - ...nextState, + author: nextState.author, + signer: nextState.signer, + 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) => { @@ -66,7 +79,17 @@ const useSubmitStore = create((set) => ({ }; return nextState; }), - resetSubmitStore: () => set({ subplebbitAddress: undefined, title: undefined, content: undefined, link: undefined, spoiler: undefined, publishCommentOptions: {} }), + resetSubmitStore: () => + set({ + author: undefined, + signer: undefined, + subplebbitAddress: undefined, + title: undefined, + content: undefined, + link: undefined, + spoiler: undefined, + publishCommentOptions: {}, + }), })); export const LinkTypePreviewer = ({ link }: { link: string }) => { @@ -84,10 +107,11 @@ export const LinkTypePreviewer = ({ link }: { link: string }) => { return isValidURL(link) ? type : t('invalid_url'); }; -const PostFormTable = ({ closeForm }: { closeForm: () => void }) => { +const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid: string }) => { const { t } = useTranslation(); const account = useAccount(); - const { displayName } = account?.author || {}; + const author = account?.author || {}; + const { displayName } = author || {}; const [url, setUrl] = useState(''); const { title, content, link, publishCommentOptions, setSubmitStore, resetSubmitStore } = useSubmitStore(); const { index, publishComment } = usePublishComment(publishCommentOptions); @@ -102,6 +126,10 @@ const PostFormTable = ({ closeForm }: { closeForm: () => void }) => { 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 = ''; @@ -114,17 +142,32 @@ const PostFormTable = ({ closeForm }: { closeForm: () => void }) => { } }; - const onPublishPost = () => { + const getAnonAddressForPost = async () => { + if (anonMode) { + const newSigner = (await getNewSigner()) || {}; + setSubmitStore({ + signer: newSigner, + author: { + displayName, + address: newSigner.address, + }, + }); + } + }; + + const onPublishPost = async () => { if (!title && !content && !link) { alert(`Cannot post empty comment`); return; } if (link && !isValidURL(link)) { - alert(`Invalid link`); + alert('The provided link is not a valid URL.'); return; } - publishComment(); + getAnonAddressForPost().then(() => { + publishComment(); + }); }; const params = useParams(); @@ -149,7 +192,32 @@ const PostFormTable = ({ closeForm }: { closeForm: () => void }) => { // in post page, publish a reply to the post const isInPostView = isPostPageView(location.pathname, params); const cid = params?.commentCid as string; - const { setContent, resetContent, replyIndex, publishReply } = useReply({ cid, subplebbitAddress }); + const { setPublishReplyOptions, resetPublishReplyOptions, replyIndex, publishReply } = useReply({ cid, subplebbitAddress }); + + const getAnonAddressForReply = async () => { + if (anonMode) { + const existingSigner = getExistingSigner(address); + if (existingSigner) { + console.log('onPublishReply - existingSigner:', existingSigner); + setPublishReplyOptions({ + signer: existingSigner, + author: { + displayName, + address: existingSigner.address, + }, + }); + } else { + const newSigner = (await getNewSigner()) || {}; + setPublishReplyOptions({ + signer: newSigner, + author: { + displayName, + address: newSigner.address, + }, + }); + } + } + }; const onPublishReply = () => { const currentContent = textRef.current?.value || ''; @@ -164,16 +232,19 @@ const PostFormTable = ({ closeForm }: { closeForm: () => void }) => { alert('The provided link is not a valid URL.'); return; } - publishReply(); + + getAnonAddressForReply().then(() => { + publishReply(); + }); }; useEffect(() => { if (typeof replyIndex === 'number') { - resetContent(); + resetPublishReplyOptions(); resetFields(); closeForm(); } - }, [replyIndex, resetContent, closeForm]); + }, [replyIndex, resetPublishReplyOptions, closeForm]); return ( @@ -215,7 +286,7 @@ const PostFormTable = ({ closeForm }: { closeForm: () => void }) => { ref={textRef} onChange={(e) => { const content = e.target.value.replace(/\n/g, '\n\n'); - isInPostView ? setContent.content(content) : setSubmitStore({ content }); + isInPostView ? setPublishReplyOptions({ content }) : setSubmitStore({ content }); }} /> @@ -231,7 +302,7 @@ const PostFormTable = ({ closeForm }: { closeForm: () => void }) => { ref={urlRef} onChange={(e) => { setUrl(e.target.value); - isInPostView ? setContent.link(e.target.value) : setSubmitStore({ link: e.target.value }); + isInPostView ? setPublishReplyOptions({ link: e.target.value }) : setSubmitStore({ link: e.target.value }); }} /> {url && } @@ -242,7 +313,10 @@ const PostFormTable = ({ closeForm }: { closeForm: () => void }) => {
[ ] @@ -293,7 +367,7 @@ const PostForm = () => { comment = editedComment; } - const { deleted, locked, removed } = comment || {}; + const { deleted, locked, removed, postCid } = comment || {}; const isThreadClosed = deleted || locked || removed || isInDescriptionView || isInRulesView; const [showForm, setShowForm] = useState(false); @@ -320,7 +394,7 @@ const PostForm = () => { ] ) : ( - setShowForm(false)} /> + setShowForm(false)} postCid={postCid} /> )}
@@ -336,7 +410,7 @@ const PostForm = () => { - {showForm && setShowForm(false)} />} + {showForm && setShowForm(false)} postCid={postCid} />}
)} diff --git a/src/components/post-mobile/post-mobile.tsx b/src/components/post-mobile/post-mobile.tsx index 01e9c3af..025b65e5 100644 --- a/src/components/post-mobile/post-mobile.tsx +++ b/src/components/post-mobile/post-mobile.tsx @@ -127,7 +127,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P !cid && e.preventDefault()}> c/ - openReplyModal && openReplyModal(cid)}> + openReplyModal && openReplyModal(cid, postCid)}> {shortCid} diff --git a/src/components/reply-modal/reply-modal.tsx b/src/components/reply-modal/reply-modal.tsx index c8842b93..2020722d 100644 --- a/src/components/reply-modal/reply-modal.tsx +++ b/src/components/reply-modal/reply-modal.tsx @@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'; import { useLocation, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import Draggable from 'react-draggable'; -import { setAccount, useAccount, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import { setAccount, useAccount, useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import { getFormattedTimeAgo } from '../../lib/utils/time-utils'; import { isValidURL } from '../../lib/utils/url-utils'; @@ -13,17 +13,19 @@ import useIsMobile from '../../hooks/use-is-mobile'; import styles from './reply-modal.module.css'; import { LinkTypePreviewer } from '../post-form'; import _ from 'lodash'; +import useAnonMode from '../../hooks/use-anon-mode'; interface ReplyModalProps { closeModal: () => void; parentCid: string; + postCid: string; scrollY: number; } -const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { +const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps) => { const { t } = useTranslation(); const { subplebbitAddress } = useParams() as { subplebbitAddress: string }; - const { setContent, publishReply } = useReply({ cid: parentCid, subplebbitAddress }); + const { setPublishReplyOptions, publishReply } = useReply({ cid: parentCid, subplebbitAddress }); const account = useAccount(); const { displayName } = account?.author || {}; const [url, setUrl] = useState(''); @@ -31,7 +33,35 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { const urlRef = useRef(null); const { selectedText } = useSelectedTextStore(); - const onPublishReply = () => { + const { anonMode, getNewSigner, getExistingSigner } = useAnonMode(postCid); + const comment = useComment({ commentCid: postCid }); + const address = comment?.author?.address; + + const getAnonAddressForReply = async () => { + if (anonMode) { + const existingSigner = getExistingSigner(address); + if (existingSigner) { + setPublishReplyOptions({ + signer: existingSigner, + author: { + displayName, + address: existingSigner.address, + }, + }); + } else { + const newSigner = (await getNewSigner()) || {}; + setPublishReplyOptions({ + signer: newSigner, + author: { + displayName, + address: newSigner.address, + }, + }); + } + } + }; + + const onPublishReply = async () => { const currentContent = textRef.current?.value || ''; const currentUrl = urlRef.current?.value || ''; @@ -44,8 +74,11 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { alert('The provided link is not a valid URL.'); return; } - publishReply(); - closeModal(); + + getAnonAddressForReply().then(() => { + publishReply(); + closeModal(); + }); }; const nodeRef = useRef(null); @@ -109,7 +142,7 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { // remove the prefix from the content to publish, and also add newlines for markdown const contentWithoutPrefix = e.target.value.slice(contentPrefix.length).replace(/\n/g, '\n\n'); if (textRef.current && textRef.current.value !== contentWithoutPrefix) { - setContent.content(contentWithoutPrefix); + setPublishReplyOptions({ content: contentWithoutPrefix }); } }; @@ -142,7 +175,7 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { placeholder={_.capitalize(t('link'))} onChange={(e) => { setUrl(e.target.value); - setContent.link(e.target.value); + setPublishReplyOptions({ link: e.target.value }); }} />
@@ -169,7 +202,7 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { [ ] diff --git a/src/components/settings-modal/account-settings/account-settings.module.css b/src/components/settings-modal/account-settings/account-settings.module.css index 2371bb88..1fd66e37 100644 --- a/src/components/settings-modal/account-settings/account-settings.module.css +++ b/src/components/settings-modal/account-settings/account-settings.module.css @@ -36,11 +36,32 @@ } .deleteAccount { - color: red; display: block; - margin-top: 10px; +} + +.deleteAccount:not(:disabled) { + color: red; } .setting .createAccount { margin-left: 5px; +} + +.settingTip { + display: block; + font-size: 0.85em; + margin: 2px 0 10px 0; + padding-left: 19px; +} + +.anonMode { + padding: 10px 0; +} + +.anonMode label { + text-transform: capitalize; +} + +.anonMode input[type="checkbox"] { + margin-right: 3px; } \ No newline at end of file diff --git a/src/components/settings-modal/account-settings/account-settings.tsx b/src/components/settings-modal/account-settings/account-settings.tsx index df7e74b6..c8a48dc8 100644 --- a/src/components/settings-modal/account-settings/account-settings.tsx +++ b/src/components/settings-modal/account-settings/account-settings.tsx @@ -3,6 +3,21 @@ import { useTranslation } from 'react-i18next'; import { createAccount, deleteAccount, exportAccount, importAccount, setAccount, setActiveAccount, useAccount, useAccounts } from '@plebbit/plebbit-react-hooks'; import stringify from 'json-stringify-pretty-compact'; import styles from './account-settings.module.css'; +import useAnonModeStore from '../../../stores/use-anon-mode-store'; + +const AnonMode = () => { + const anonMode = useAnonModeStore((state) => state.anonMode); + const setAnonMode = useAnonModeStore((state) => state.setAnonMode); + + return ( +
+ + Automatically use a different user ID in each thread +
+ ); +}; const AccountSettings = () => { const { t } = useTranslation(); @@ -167,7 +182,7 @@ const AccountSettings = () => {