From bb976409ff425097187db3a9679a0b80464aa0c9 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Thu, 19 Sep 2024 17:33:00 +0200 Subject: [PATCH] fix(anon mode): user id could change for pending post, name field could bug out --- src/components/post-desktop/post-desktop.tsx | 20 ++------- src/components/post-form/post-form.tsx | 11 +++-- src/components/post-mobile/post-mobile.tsx | 21 +++------- src/components/reply-modal/reply-modal.tsx | 6 +-- src/hooks/use-anon-mode.ts | 12 ++---- src/hooks/use-post-cid.ts | 43 -------------------- src/hooks/use-publish-reply.ts | 28 +++++++++---- src/stores/use-anon-mode-store.ts | 9 ---- 8 files changed, 40 insertions(+), 110 deletions(-) delete mode 100644 src/hooks/use-post-cid.ts diff --git a/src/components/post-desktop/post-desktop.tsx b/src/components/post-desktop/post-desktop.tsx index b2926061..822c8b82 100644 --- a/src/components/post-desktop/post-desktop.tsx +++ b/src/components/post-desktop/post-desktop.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { Link, useLocation, useParams } from 'react-router-dom'; -import { Comment, useAccount, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import styles from '../../views/post/post.module.css'; import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils'; @@ -9,14 +9,11 @@ import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/po import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils'; import { isValidURL } from '../../lib/utils/url-utils'; import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils'; -import useAnonModeStore from '../../stores/use-anon-mode-store'; import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store'; -import useAnonMode from '../../hooks/use-anon-mode'; import useAuthorAddressClick from '../../hooks/use-author-address-click'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import useFetchGifFirstFrame from '../../hooks/use-fetch-gif-first-frame'; import useHide from '../../hooks/use-hide'; -import usePostCidForPendingPost from '../../hooks/use-post-cid'; import useReplies from '../../hooks/use-replies'; import useStateString from '../../hooks/use-state-string'; import CommentMedia from '../comment-media'; @@ -68,22 +65,13 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }: const isInPostPageView = isPostPageView(location.pathname, params); const isInSubscriptionsView = isSubscriptionsView(location.pathname, params); - // comment.author.shortAddress is undefined while the comment publishing state is pending, use account instead - // in anon mode, use the newly generated signer.address instead, which will be comment.author.address - const { anonMode } = useAnonMode(); - const { getThreadSigner, currentAnonSignerAddress } = useAnonModeStore(); - const postCidForSigner = usePostCidForPendingPost(parentCid); - const anonSignerAddress = postCidForSigner ? getThreadSigner(postCidForSigner)?.address || currentAnonSignerAddress : null; - const account = useAccount(); - const pendingShortAddress = anonMode ? anonSignerAddress && Plebbit.getShortAddress(anonSignerAddress) : account?.author?.shortAddress; + const userID = address && Plebbit.getShortAddress(address); + const userIDBackgroundColor = hashStringToColor(userID); + const userIDTextColor = getTextColorForBackground(userIDBackgroundColor); const handleUserAddressClick = useAuthorAddressClick(); const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length; - const userID = shortAddress || pendingShortAddress; - const userIDBackgroundColor = hashStringToColor(userID); - const userIDTextColor = getTextColorForBackground(userIDBackgroundColor); - const { hidden } = useHide(post); return ( diff --git a/src/components/post-form/post-form.tsx b/src/components/post-form/post-form.tsx index 29e367d6..57e13dee 100644 --- a/src/components/post-form/post-form.tsx +++ b/src/components/post-form/post-form.tsx @@ -55,9 +55,9 @@ const useSubmitStore = create((set) => ({ 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 (author !== undefined) nextState.author = author; + if (displayName !== undefined) nextState.displayName = displayName; if (signer !== undefined) nextState.signer = signer; if (subplebbitAddress !== undefined) nextState.subplebbitAddress = subplebbitAddress; if (title !== undefined) nextState.title = title || undefined; @@ -83,8 +83,11 @@ const useSubmitStore = create((set) => ({ publishCommentOptions.signer = nextState.signer; } - if (nextState.author) { - publishCommentOptions.author = nextState.author; + if (nextState.author || nextState.displayName) { + publishCommentOptions.author = { + ...nextState.author, + displayName: nextState.displayName, + }; } nextState.publishCommentOptions = publishCommentOptions; diff --git a/src/components/post-mobile/post-mobile.tsx b/src/components/post-mobile/post-mobile.tsx index 15f1f0a3..61dacc4d 100644 --- a/src/components/post-mobile/post-mobile.tsx +++ b/src/components/post-mobile/post-mobile.tsx @@ -1,20 +1,17 @@ import { useState } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { Link, useLocation, useParams } from 'react-router-dom'; -import { Comment, useAccount, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import { Comment, useAuthorAvatar, useComment, useEditedComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import styles from '../../views/post/post.module.css'; import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils'; import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils'; import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils'; import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils'; -import useAnonModeStore from '../../stores/use-anon-mode-store'; import useAvatarVisibilityStore from '../../stores/use-avatar-visibility-store'; -import useAnonMode from '../../hooks/use-anon-mode'; import useAuthorAddressClick from '../../hooks/use-author-address-click'; import useCountLinksInReplies from '../../hooks/use-count-links-in-replies'; import useHide from '../../hooks/use-hide'; -import usePostCidForPendingPost from '../../hooks/use-post-cid'; import useReplies from '../../hooks/use-replies'; import useStateString from '../../hooks/use-state-string'; import CommentMedia from '../comment-media'; @@ -49,21 +46,13 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P const isReply = parentCid; - // comment.author.shortAddress is undefined while the comment publishing state is pending, use account instead - // in anon mode, use the newly generated signer.address instead, which will be comment.author.address - const { anonMode } = useAnonMode(); - const { getThreadSigner, currentAnonSignerAddress } = useAnonModeStore(); - const postCidForSigner = usePostCidForPendingPost(parentCid); - const anonSignerAddress = postCidForSigner ? getThreadSigner(postCidForSigner)?.address || currentAnonSignerAddress : null; - const account = useAccount(); - const pendingShortAddress = anonMode ? anonSignerAddress && Plebbit.getShortAddress(anonSignerAddress) : account?.author?.shortAddress; - const stateString = useStateString(post); const handleUserAddressClick = useAuthorAddressClick(); const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length; - const userIDBackgroundColor = hashStringToColor(shortAddress || pendingShortAddress); + const userID = shortAddress; + const userIDBackgroundColor = hashStringToColor(userID); const userIDTextColor = getTextColorForBackground(userIDBackgroundColor); const { hidden } = useHide(post); @@ -113,10 +102,10 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P handleUserAddressClick(shortAddress || pendingShortAddress, postCid)} + onClick={() => handleUserAddressClick(userID, postCid)} style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }} > - {shortAddress || pendingShortAddress} + {userID} } content={`${numberOfPostsByAuthor === 1 ? t('1_post_by_this_id') : t('x_posts_by_this_id', { number: numberOfPostsByAuthor })}`} diff --git a/src/components/reply-modal/reply-modal.tsx b/src/components/reply-modal/reply-modal.tsx index f053f365..2a9f9f10 100644 --- a/src/components/reply-modal/reply-modal.tsx +++ b/src/components/reply-modal/reply-modal.tsx @@ -15,7 +15,6 @@ import styles from './reply-modal.module.css'; import { LinkTypePreviewer } from '../post-form'; import _ from 'lodash'; import useAnonMode from '../../hooks/use-anon-mode'; -import useAnonModeStore from '../../stores/use-anon-mode-store'; interface ReplyModalProps { closeModal: () => void; @@ -41,7 +40,6 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s const address = comment?.author?.address; const hasCalledAnonAddressRef = useRef(false); - const { setCurrentAnonSignerAddress } = useAnonModeStore(); const getAnonAddressForReply = useCallback(async () => { if (anonMode && !hasCalledAnonAddressRef.current) { @@ -55,7 +53,6 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s displayName: displayName || undefined, }, }); - setCurrentAnonSignerAddress(existingSigner.address); } else { const newSigner = await getNewSigner(); if (newSigner) { @@ -66,11 +63,10 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s displayName: displayName || undefined, }, }); - setCurrentAnonSignerAddress(newSigner.address); } } } - }, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, anonMode, displayName, setCurrentAnonSignerAddress]); + }, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, anonMode, displayName]); const onPublishReply = () => { const currentContent = textRef.current?.value.slice(contentPrefix.length).trim() || ''; diff --git a/src/hooks/use-anon-mode.ts b/src/hooks/use-anon-mode.ts index f9df88d3..2483b2a8 100644 --- a/src/hooks/use-anon-mode.ts +++ b/src/hooks/use-anon-mode.ts @@ -3,13 +3,12 @@ import useAnonModeStore from '../stores/use-anon-mode-store'; import { useCallback, useMemo } from 'react'; const useAnonMode = (postCid?: string) => { - const { anonMode, threadSigners, setThreadSigner, setAddressSigner, getAddressSigner, setCurrentAnonSignerAddress } = useAnonModeStore((state) => ({ + const { anonMode, threadSigners, setThreadSigner, setAddressSigner, getAddressSigner } = useAnonModeStore((state) => ({ anonMode: state.anonMode, threadSigners: state.threadSigners, setThreadSigner: state.setThreadSigner, setAddressSigner: state.setAddressSigner, getAddressSigner: state.getAddressSigner, - setCurrentAnonSignerAddress: state.setCurrentAnonSignerAddress, })); const threadSigner = useMemo(() => (postCid ? threadSigners[postCid] : undefined), [postCid, threadSigners]); @@ -27,7 +26,6 @@ const useAnonMode = (postCid?: string) => { } else { setAddressSigner(signer); } - setCurrentAnonSignerAddress(signer.address); } return signer; } catch (error) { @@ -36,7 +34,6 @@ const useAnonMode = (postCid?: string) => { } else { try { const signer = await account?.plebbit.createSigner({ type: 'ed25519', privateKey: threadSigner?.privateKey }); - setCurrentAnonSignerAddress(signer.address); return signer; } catch (error) { console.error('Failed to retrieve anonymous signer:', error); @@ -44,17 +41,14 @@ const useAnonMode = (postCid?: string) => { } } return null; - }, [anonMode, postCid, threadSigner, account, setThreadSigner, setAddressSigner, setCurrentAnonSignerAddress]); + }, [anonMode, postCid, threadSigner, account, setThreadSigner, setAddressSigner]); const getExistingSigner = useCallback( (address: string) => { const signer = getAddressSigner(address); - if (signer) { - setCurrentAnonSignerAddress(signer.address); - } return signer; }, - [getAddressSigner, setCurrentAnonSignerAddress], + [getAddressSigner], ); return { anonMode, getNewSigner, getExistingSigner }; diff --git a/src/hooks/use-post-cid.ts b/src/hooks/use-post-cid.ts deleted file mode 100644 index 075d1808..00000000 --- a/src/hooks/use-post-cid.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { useEffect, useReducer } from 'react'; -import { useComment } from '@plebbit/plebbit-react-hooks'; - -type State = { - resolvedPostCid: string | null; - currentParentCid: string | undefined; -}; - -type Action = { type: 'SET_POST_CID'; payload: string } | { type: 'SET_PARENT_CID'; payload: string }; - -const reducer = (state: State, action: Action): State => { - switch (action.type) { - case 'SET_POST_CID': - return { ...state, resolvedPostCid: action.payload }; - case 'SET_PARENT_CID': - return { ...state, currentParentCid: action.payload }; - default: - return state; - } -}; - -const usePostCidForPendingPost = (initialParentCid: string | undefined): string | null => { - const [state, dispatch] = useReducer(reducer, { - resolvedPostCid: null, - currentParentCid: initialParentCid, - }); - - const comment = useComment({ commentCid: state.currentParentCid }); - - useEffect(() => { - if (comment) { - if (comment.postCid) { - dispatch({ type: 'SET_POST_CID', payload: comment.postCid }); - } else if (comment.parentCid) { - dispatch({ type: 'SET_PARENT_CID', payload: comment.parentCid }); - } - } - }, [comment]); - - return state.resolvedPostCid; -}; - -export default usePostCidForPendingPost; diff --git a/src/hooks/use-publish-reply.ts b/src/hooks/use-publish-reply.ts index 5d1329ec..87f59aa0 100644 --- a/src/hooks/use-publish-reply.ts +++ b/src/hooks/use-publish-reply.ts @@ -1,5 +1,5 @@ import { useCallback } from 'react'; -import { ChallengeVerification, Comment, PublishCommentOptions, usePublishComment } from '@plebbit/plebbit-react-hooks'; +import { ChallengeVerification, Comment, PublishCommentOptions, useAccount, usePublishComment } from '@plebbit/plebbit-react-hooks'; import { create } from 'zustand'; import { alertChallengeVerificationFailed } from '../lib/utils/challenge-utils'; import useChallengesStore from '../stores/use-challenges-store'; @@ -50,8 +50,6 @@ const useReplyStore = create((set) => ({ content, link, spoiler, - ...(author && { author: updatedAuthor }), - ...(signer && { signer }), onChallenge: (...args: any) => addChallenge(args), onChallengeVerification: (challengeVerification: ChallengeVerification, comment: Comment) => { alertChallengeVerificationFailed(challengeVerification, comment); @@ -62,6 +60,14 @@ const useReplyStore = create((set) => ({ }, }; + if (updatedAuthor) { + publishCommentOptions.author = updatedAuthor; + } + + if (signer) { + publishCommentOptions.signer = signer; + } + return { author: { ...state.author, [parentCid]: updatedAuthor }, displayName: { ...state.displayName, [parentCid]: displayName }, @@ -102,6 +108,8 @@ const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: const setReplyStore = useReplyStore((state) => state.setReplyStore); const resetReplyStore = useReplyStore((state) => state.resetReplyStore); + const account = useAccount(); + const setPublishReplyOptions = useCallback( (options: Partial) => { const newOptions: Partial = { @@ -110,7 +118,6 @@ const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: content: options.content ?? content, link: options.link ?? link, spoiler: options.spoiler ?? spoiler, - signer: anonMode ? signer || options.signer : undefined, }; if ('displayName' in options) { @@ -118,18 +125,23 @@ const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: } if (anonMode) { - const currentAuthor = signer?.author || author || {}; + newOptions.signer = signer || options.signer; newOptions.author = { - ...currentAuthor, + ...(author || {}), + address: newOptions.signer?.address, ...('displayName' in options && { displayName: options.displayName }), }; } else { - newOptions.author = undefined; + newOptions.signer = undefined; + newOptions.author = { + address: account?.author?.address, + ...('displayName' in options && { displayName: options.displayName }), + }; } setReplyStore(newOptions as SetReplyStoreData); }, - [subplebbitAddress, parentCid, author, signer, content, link, spoiler, setReplyStore, anonMode], + [subplebbitAddress, parentCid, author, signer, content, link, spoiler, setReplyStore, anonMode, account], ); const resetPublishReplyOptions = useCallback(() => resetReplyStore(parentCid), [parentCid, resetReplyStore]); diff --git a/src/stores/use-anon-mode-store.ts b/src/stores/use-anon-mode-store.ts index e9448766..c94ddecb 100644 --- a/src/stores/use-anon-mode-store.ts +++ b/src/stores/use-anon-mode-store.ts @@ -10,8 +10,6 @@ interface AnonModeState { getThreadSigner: (postCid: string) => any | undefined; setAddressSigner: (signer: any) => void; getAddressSigner: (address: string) => any | undefined; - currentAnonSignerAddress: string | null; - setCurrentAnonSignerAddress: (address: string | null) => void; } const anonModeStore = localForageLru.createInstance({ @@ -42,10 +40,6 @@ const useAnonModeStore = create((set, get) => ({ }, getAddressSigner: (address: string) => get().addressSigners[address], currentAnonSignerAddress: null, - setCurrentAnonSignerAddress: (address: string | null) => { - set({ currentAnonSignerAddress: address }); - anonModeStore.setItem('currentAnonSignerAddress', address); - }, })); const initializeAnonModeStore = async () => { @@ -64,13 +58,10 @@ const initializeAnonModeStore = async () => { } }); - const currentAnonSignerAddress = await anonModeStore.getItem('currentAnonSignerAddress'); - useAnonModeStore.setState((state) => ({ anonMode, // Set the retrieved anonMode state threadSigners: { ...threadSigners, ...state.threadSigners }, addressSigners: { ...addressSigners, ...state.addressSigners }, - currentAnonSignerAddress: currentAnonSignerAddress || null, })); };