From 14f3f04137148943e50dc584ed39a54a078103e5 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Tue, 3 Sep 2024 22:06:07 +0200 Subject: [PATCH] enable editing comments published in anon mode --- src/components/edit-menu/edit-menu.tsx | 93 +++++++++++++++++--------- src/hooks/use-anon-mode.ts | 24 ++++--- src/hooks/use-author-privileges.ts | 23 +++++-- 3 files changed, 92 insertions(+), 48 deletions(-) diff --git a/src/components/edit-menu/edit-menu.tsx b/src/components/edit-menu/edit-menu.tsx index 70c8464e..bfb051ae 100644 --- a/src/components/edit-menu/edit-menu.tsx +++ b/src/components/edit-menu/edit-menu.tsx @@ -1,12 +1,13 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useState, useMemo, useCallback } from 'react'; import { Trans, useTranslation } from 'react-i18next'; import { autoUpdate, FloatingFocusManager, offset, shift, useClick, useDismiss, useFloating, useId, useInteractions, useRole } from '@floating-ui/react'; -import { Comment, PublishCommentEditOptions, usePublishCommentEdit } from '@plebbit/plebbit-react-hooks'; +import { Comment, PublishCommentEditOptions, useAccount, usePublishCommentEdit } from '@plebbit/plebbit-react-hooks'; import styles from './edit-menu.module.css'; import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils'; import useChallengesStore from '../../stores/use-challenges-store'; import _ from 'lodash'; import useIsMobile from '../../hooks/use-is-mobile'; +import useAnonMode from '../../hooks/use-anon-mode'; const { addChallenge } = useChallengesStore.getState(); @@ -31,33 +32,66 @@ const timestampToDays = (timestamp: number) => { const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, post }: EditMenuProps) => { const { t } = useTranslation(); const isMobile = useIsMobile(); - const { cid, commentAuthor, content, deleted, locked, parentCid, pinned, reason, removed, spoiler, subplebbitAddress } = post || {}; + const { author, cid, commentAuthor, content, deleted, locked, parentCid, pinned, reason, removed, spoiler, subplebbitAddress } = post || {}; const isReply = parentCid; const [isEditMenuOpen, setIsEditMenuOpen] = useState(false); const [isContentEditorOpen, setIsContentEditorOpen] = useState(false); - const defaultPublishEditOptions: PublishCommentEditOptions = { - commentAuthor: isAccountMod && !isAccountCommentAuthor ? commentAuthor : undefined, - commentCid: cid, - content: isAccountCommentAuthor ? content : undefined, - deleted: isAccountCommentAuthor ? deleted : undefined, - locked: isAccountMod ? locked : undefined, - pinned: isAccountMod ? pinned : undefined, - reason, - removed: isAccountMod ? removed : undefined, - spoiler, - subplebbitAddress, - onChallenge: (...args: any) => addChallenge([...args, post]), - onChallengeVerification: alertChallengeVerificationFailed, - onError: (error: Error) => { - console.warn(error); - alert('Comment edit failed. ' + error.message); - }, - }; + const { getExistingSigner } = useAnonMode(post?.postCid); - const [publishCommentEditOptions, setPublishCommentEditOptions] = useState(defaultPublishEditOptions); + const account = useAccount(); + const [signer, setSigner] = useState(account?.signer); + + const checkSigner = useCallback(async () => { + if (isAccountCommentAuthor && post?.author?.address !== account?.author?.address) { + const existingSigner = getExistingSigner(post?.author?.address); + if (existingSigner) { + setSigner(existingSigner); + } + } else { + setSigner(null); + } + }, [isAccountCommentAuthor, post?.author?.address, getExistingSigner, account?.author?.address]); + + useEffect(() => { + checkSigner(); + }, [checkSigner]); + + const defaultPublishEditOptions = useMemo(() => { + return { + commentAuthor: isAccountMod && !isAccountCommentAuthor ? commentAuthor : undefined, + commentCid: cid, + content: isAccountCommentAuthor ? content : undefined, + deleted: isAccountCommentAuthor ? deleted ?? false : undefined, + locked: isAccountMod ? locked ?? false : undefined, + pinned: isAccountMod ? pinned ?? false : undefined, + reason, + removed: isAccountMod ? removed ?? false : undefined, + spoiler: spoiler ?? false, + subplebbitAddress, + signer: signer, + author: signer + ? { + address: signer.address, + displayName: post?.author?.displayName, + } + : author, + onChallenge: (...args: any) => addChallenge([...args, post]), + onChallengeVerification: alertChallengeVerificationFailed, + onError: (error: Error) => { + console.warn(error); + alert('Comment edit failed. ' + error.message); + }, + }; + }, [isAccountMod, isAccountCommentAuthor, commentAuthor, cid, content, deleted, locked, pinned, reason, removed, spoiler, subplebbitAddress, signer, post]); + + const [publishCommentEditOptions, setPublishCommentEditOptions] = useState(defaultPublishEditOptions); const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions); + useEffect(() => { + setPublishCommentEditOptions(defaultPublishEditOptions); + }, [defaultPublishEditOptions]); + const [banDuration, setBanDuration] = useState(() => publishCommentEditOptions.commentAuthor?.banExpiresAt ? timestampToDays(publishCommentEditOptions.commentAuthor.banExpiresAt) : 1, ); @@ -101,13 +135,6 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po const headingId = useId(); - useEffect(() => { - setPublishCommentEditOptions((prevOptions) => ({ - ...prevOptions, - commentCid: cid, - })); - }, [cid]); - const _publishCommentEdit = async () => { try { await publishCommentEdit(); @@ -161,7 +188,7 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po
@@ -169,7 +196,7 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po
[ ] @@ -178,7 +205,7 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po
[ ] @@ -186,7 +213,7 @@ const EditMenu = ({ isAccountMod, isAccountCommentAuthor, isCommentAuthorMod, po
[ ] diff --git a/src/hooks/use-anon-mode.ts b/src/hooks/use-anon-mode.ts index 22f0bc65..f9df88d3 100644 --- a/src/hooks/use-anon-mode.ts +++ b/src/hooks/use-anon-mode.ts @@ -1,5 +1,6 @@ import { useAccount } from '@plebbit/plebbit-react-hooks'; 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) => ({ @@ -11,11 +12,11 @@ const useAnonMode = (postCid?: string) => { setCurrentAnonSignerAddress: state.setCurrentAnonSignerAddress, })); - const threadSigner = postCid ? threadSigners[postCid] : undefined; + const threadSigner = useMemo(() => (postCid ? threadSigners[postCid] : undefined), [postCid, threadSigners]); const account = useAccount(); - const getNewSigner = async () => { + const getNewSigner = useCallback(async () => { if (anonMode) { if (!postCid || !threadSigner) { try { @@ -43,15 +44,18 @@ const useAnonMode = (postCid?: string) => { } } return null; - }; + }, [anonMode, postCid, threadSigner, account, setThreadSigner, setAddressSigner, setCurrentAnonSignerAddress]); - const getExistingSigner = (address: string) => { - const signer = getAddressSigner(address); - if (signer) { - setCurrentAnonSignerAddress(signer.address); - } - return signer; - }; + const getExistingSigner = useCallback( + (address: string) => { + const signer = getAddressSigner(address); + if (signer) { + setCurrentAnonSignerAddress(signer.address); + } + return signer; + }, + [getAddressSigner, setCurrentAnonSignerAddress], + ); return { anonMode, getNewSigner, getExistingSigner }; }; diff --git a/src/hooks/use-author-privileges.ts b/src/hooks/use-author-privileges.ts index 09b40d08..c4f8fbda 100644 --- a/src/hooks/use-author-privileges.ts +++ b/src/hooks/use-author-privileges.ts @@ -1,4 +1,6 @@ +import { useMemo } from 'react'; import { useAccount, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import useAnonModeStore from '../stores/use-anon-mode-store'; interface AuthorPrivilegesProps { commentAuthorAddress: string; @@ -8,12 +10,23 @@ interface AuthorPrivilegesProps { const useAuthorPrivileges = ({ commentAuthorAddress, subplebbitAddress }: AuthorPrivilegesProps) => { const accountAuthorAddress = useAccount()?.author?.address; const { roles } = useSubplebbit({ subplebbitAddress }) || {}; + const { getAddressSigner } = useAnonModeStore(); - const commentAuthorRole = roles?.[commentAuthorAddress]?.role; - const isCommentAuthorMod = commentAuthorRole === 'admin' || commentAuthorRole === 'owner' || commentAuthorRole === 'moderator'; - const accountAuthorRole = roles?.[accountAuthorAddress]?.role; - const isAccountMod = accountAuthorRole === 'admin' || accountAuthorRole === 'owner' || accountAuthorRole === 'moderator'; - const isAccountCommentAuthor = accountAuthorAddress === commentAuthorAddress; + const { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor, commentAuthorRole, accountAuthorRole } = useMemo(() => { + const commentAuthorRole = roles?.[commentAuthorAddress]?.role; + const isCommentAuthorMod = commentAuthorRole === 'admin' || commentAuthorRole === 'owner' || commentAuthorRole === 'moderator'; + const accountAuthorRole = roles?.[accountAuthorAddress]?.role; + const isAccountMod = accountAuthorRole === 'admin' || accountAuthorRole === 'owner' || accountAuthorRole === 'moderator'; + + let isAccountCommentAuthor = accountAuthorAddress === commentAuthorAddress; + + if (!isAccountCommentAuthor) { + const existingSigner = getAddressSigner(commentAuthorAddress); + isAccountCommentAuthor = !!existingSigner; + } + + return { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor, commentAuthorRole, accountAuthorRole }; + }, [roles, commentAuthorAddress, accountAuthorAddress, getAddressSigner]); return { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor, commentAuthorRole, accountAuthorRole }; };