diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index 1aeb7743..dcb70b99 100644 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/public/assets/logo/apple-touch-icon.png b/public/assets/logo/apple-touch-icon.png index 1aeb7743..dcb70b99 100644 Binary files a/public/assets/logo/apple-touch-icon.png and b/public/assets/logo/apple-touch-icon.png differ diff --git a/public/assets/logo/favicon-16x16.png b/public/assets/logo/favicon-16x16.png index 7ab5a989..00310534 100644 Binary files a/public/assets/logo/favicon-16x16.png and b/public/assets/logo/favicon-16x16.png differ diff --git a/public/assets/logo/favicon-32x32.png b/public/assets/logo/favicon-32x32.png index 7ab5a989..00310534 100644 Binary files a/public/assets/logo/favicon-32x32.png and b/public/assets/logo/favicon-32x32.png differ diff --git a/public/assets/logo/favicon.ico b/public/assets/logo/favicon.ico index 7ab5a989..5cccad7a 100644 Binary files a/public/assets/logo/favicon.ico and b/public/assets/logo/favicon.ico differ diff --git a/public/assets/logo/logo-transparent.png b/public/assets/logo/logo-transparent.png index 3a174855..7965b497 100644 Binary files a/public/assets/logo/logo-transparent.png and b/public/assets/logo/logo-transparent.png differ diff --git a/public/electron-tray-icon.png b/public/electron-tray-icon.png index 1aeb7743..dcb70b99 100644 Binary files a/public/electron-tray-icon.png and b/public/electron-tray-icon.png differ diff --git a/public/favicon.ico b/public/favicon.ico index 7ab5a989..5cccad7a 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/icon.png b/public/icon.png index 6e018400..2198013a 100644 Binary files a/public/icon.png and b/public/icon.png differ diff --git a/public/manifest-icon-192x192.png b/public/manifest-icon-192x192.png index 7b0fc39c..b016bc12 100644 Binary files a/public/manifest-icon-192x192.png and b/public/manifest-icon-192x192.png differ diff --git a/public/manifest-icon-512x512.png b/public/manifest-icon-512x512.png index 6e018400..2198013a 100644 Binary files a/public/manifest-icon-512x512.png and b/public/manifest-icon-512x512.png differ diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index 9b09d7e0..8e001156 100755 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -145,7 +145,7 @@ const SettingsModal = ({ isOpen, closeModal }) => { clearTimeout(checkedENSTimeoutId); }; }, [copyStatus, checkedENS]); - + const handleSavePlebbitOptions = async () => { let gatewayUrls = gatewayRef.current.value.split('\n').filter((url) => url.trim()); @@ -165,9 +165,9 @@ const SettingsModal = ({ isOpen, closeModal }) => { } const invalidUrls = [ - ...gatewayUrls || defaultGatewayUrls, - ...(ipfsClientsOptions || []), - ...pubsubClientsOptions || defaultPubsubHttpClientsOptions, + ...(Array.isArray(gatewayUrls) ? gatewayUrls : (Array.isArray(defaultGatewayUrls) ? defaultGatewayUrls : [])), + ...(Array.isArray(ipfsClientsOptions) ? ipfsClientsOptions : []), + ...(Array.isArray(pubsubClientsOptions) ? pubsubClientsOptions : (Array.isArray(defaultPubsubHttpClientsOptions) ? defaultPubsubHttpClientsOptions : [])), ].filter((url) => !isValidURL(url)); if (invalidUrls.length > 0) { @@ -244,9 +244,9 @@ const SettingsModal = ({ isOpen, closeModal }) => { setNewErrorMessage(null); setNewSuccessMessage(null); - gatewayRef.current.value = defaultGatewayUrls.join('\n'); + gatewayRef.current.value = defaultGatewayUrls ? defaultGatewayUrls.join('\n') : ""; ipfsRef.current.value = ""; - pubsubRef.current.value = defaultPubsubHttpClientsOptions.join('\n'); + pubsubRef.current.value = defaultPubsubHttpClientsOptions ? defaultPubsubHttpClientsOptions.join('\n') : ""; dataPathRef.current.value = ""; try { diff --git a/src/components/views/All.jsx b/src/components/views/All.jsx index e9fc510b..47072883 100755 --- a/src/components/views/All.jsx +++ b/src/components/views/All.jsx @@ -97,6 +97,7 @@ const All = () => { const [prevScrollPos, setPrevScrollPos] = useState(0); const [visible, setVisible] = useState(true); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); + const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [commentCid, setCommentCid] = useState(null); const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); @@ -991,6 +992,32 @@ const All = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » + +
  • , document.body @@ -1294,6 +1321,32 @@ const All = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » + +
  • , document.body diff --git a/src/components/views/AllCatalog.jsx b/src/components/views/AllCatalog.jsx index e47ef8c9..8cace4a8 100755 --- a/src/components/views/AllCatalog.jsx +++ b/src/components/views/AllCatalog.jsx @@ -1,11 +1,11 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { Helmet } from 'react-helmet-async'; -import { Link, useNavigate } from 'react-router-dom'; +import { Link, useNavigate} from 'react-router-dom'; import { confirmAlert } from 'react-confirm-alert'; import { Tooltip } from 'react-tooltip'; import { Virtuoso } from 'react-virtuoso'; -import { useAccount, useFeed, usePublishCommentEdit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; +import { useAccount, useFeed, usePublishCommentEdit, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import { Container, NavBar, Header, Break, PostMenu, BoardForm } from '../styled/views/Board.styled'; import { Threads, PostMenuCatalog } from '../styled/views/Catalog.styled'; @@ -28,110 +28,139 @@ import useSuccess from '../../hooks/useSuccess'; import useWindowWidth from '../../hooks/useWindowWidth'; import useGeneralStore from '../../hooks/stores/useGeneralStore'; import packageJson from '../../../package.json' -const { version } = packageJson +const {version} = packageJson let lastVirtuosoStates = {} -const AllCatalog = () => { +const CatalogPost = ({post}) => { const { - setCaptchaResponse, - setChallengesArray, - defaultSubplebbits, editedComment, + setDeletePost, setIsAuthorDelete, + captchaResponse, setCaptchaResponse, + setIsModerationOpen, + setChallengesArray, setIsAuthorEdit, setIsCaptchaOpen, - isModerationOpen, setIsModerationOpen, - isSettingsOpen, setIsSettingsOpen, + setIsEditModalOpen, setModeratingCommentCid, + setOriginalCommentContent, + setPendingComment, setResolveCaptchaPromise, selectedAddress, setSelectedAddress, selectedStyle, setSelectedThread, - setSelectedTitle, } = useGeneralStore(state => state); + const thread = post; + const commentMediaInfo = getCommentMediaInfo(thread); + const linkCount = countLinks(thread); + const fallbackImgUrl = "assets/filedeleted-res.gif"; + const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); + const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); + const [openMenuCid, setOpenMenuCid] = useState(null); + const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); + const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); + const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); + const [commentCid, setCommentCid] = useState(null); + const [isModerator, setIsModerator] = useState(false); - const threadMenuRefs = useRef({}); - const postMenuRef = useRef(null); - const postMenuCatalogRef = useRef(null); - const virtuosoRef = useRef(); - - const account = useAccount(); - const navigate = useNavigate(); const [, setNewErrorMessage] = useError(); const [, setNewSuccessMessage] = useSuccess(); - const [prevScrollPos, setPrevScrollPos] = useState(0); - const [visible, setVisible] = useState(true); - - const [isEditModalOpen, setIsEditModalOpen] = useState(false); - const [originalCommentContent, setOriginalCommentContent] = useState(null); - const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); - const [deletePost, setDeletePost] = useState(false); - const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); - const [commentCid, setCommentCid] = useState(null); - const [moderatorPermissions, setModeratorPermissions] = useState({}); - const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); - - const addresses = defaultSubplebbits.map(subplebbit => subplebbit.address); - const { feed, hasMore, loadMore } = useFeed({ subplebbitAddresses: addresses, sortType: 'active' }); - const { subplebbits } = useSubplebbits({ subplebbitAddresses: addresses, sortType: 'active' }); - const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp)); - - const stateString = useFeedStateString(subplebbits); - - const columnWidth = 180; - const windowWidth = useWindowWidth(); - const columnCount = Math.floor(windowWidth / columnWidth); - const rows = useFeedRows(selectedFeed, columnCount); + const account = useAccount(); + const subplebbit = useSubplebbit({subplebbitAddress: thread.subplebbitAddress}); + const threadMenuRefs = useRef({}); + const postMenuRef = useRef(null); + const postMenuCatalogRef = useRef(null); useEffect(() => { - let permissions = {}; + if (subplebbit.roles !== undefined) { + const role = subplebbit.roles[account?.author.address]?.role; + + if (role === 'moderator' || role === 'admin' || role === 'owner') { + setIsModerator(true); + } else { + setIsModerator(false); + } + } + }, [account?.author.address, subplebbit.roles]); - selectedFeed.forEach(thread => { - const subplebbit = subplebbits.find(s => s && s.address === thread.subplebbitAddress); - if (subplebbit && subplebbit.roles) { - const role = subplebbit.roles[account?.author.address]?.role; + const handleOutsideClick = useCallback((e) => { + if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) { + setOpenMenuCid(null); + } + }, [openMenuCid]); - if (role === 'moderator' || role === 'admin' || role === 'owner') { - permissions[thread.subplebbitAddress] = true; - } else { - permissions[thread.subplebbitAddress] = false; - } + const handleOptionClick = () => { + setOpenMenuCid(null); + }; + + useEffect(() => { + if (openMenuCid !== null) { + document.addEventListener('click', handleOutsideClick); + } else { + document.removeEventListener('click', handleOutsideClick); + } + + return () => { + document.removeEventListener('click', handleOutsideClick); + }; + }, [openMenuCid, handleOutsideClick]); + + const handleAuthorDeleteClick = (comment) => { + handleOptionClick(comment.cid); + + confirmAlert({ + customUI: ({ onClose }) => { + return ( + +
    +

    Are you sure you want to delete this post?

    +
    + + +
    +
    +
    + ); } }); - - setModeratorPermissions(permissions); - }, [account?.author.address, selectedFeed, subplebbits]); - - - // mobile navbar scroll effect - useEffect(() => { - const debouncedHandleScroll = debounce(() => { - const currentScrollPos = window.pageYOffset; - setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10); - setPrevScrollPos(currentScrollPos); - }, 50); - - window.addEventListener('scroll', debouncedHandleScroll); - - return () => window.removeEventListener('scroll', debouncedHandleScroll); - }, [prevScrollPos, visible]); - - - const tryLoadMore = async () => { - try { loadMore() } - catch (e) { await new Promise(resolve => setTimeout(resolve, 1000)) } }; + const handleAuthorEditClick = (comment) => { + handleOptionClick(comment.cid); + setIsAuthorEdit(true); + setIsAuthorDelete(false); + setCommentCid(comment.cid); + setOriginalCommentContent(comment.content); + setIsEditModalOpen(true); + } + + + const onChallengeVerification = (challengeVerification) => { if (challengeVerification.challengeSuccess === true) { - setNewSuccessMessage('Challenge Success'); - } + setNewSuccessMessage('Challenge Success'); + } else if (challengeVerification.challengeSuccess === false) { setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`); console.log('challenge failed', challengeVerification); @@ -140,6 +169,7 @@ const AllCatalog = () => { const onChallenge = async (challenges, comment) => { + setPendingComment(comment); let challengeAnswers = []; try { challengeAnswers = await getChallengeAnswersFromUser(challenges) @@ -155,19 +185,19 @@ const AllCatalog = () => { const getChallengeAnswersFromUser = async (challenges) => { setChallengesArray(challenges); - + return new Promise((resolve, reject) => { const imageString = challenges?.challenges[0].challenge; const imageSource = `data:image/png;base64,${imageString}`; const challengeImg = new Image(); challengeImg.src = imageSource; - + challengeImg.onload = () => { setIsCaptchaOpen(true); - + const handleKeyDown = async (event) => { if (event.key === 'Enter') { - const currentCaptchaResponse = useGeneralStore.getState().captchaResponse; + const currentCaptchaResponse = captchaResponse; resolve(currentCaptchaResponse); setIsCaptchaOpen(false); document.removeEventListener('keydown', handleKeyDown); @@ -180,7 +210,7 @@ const AllCatalog = () => { setResolveCaptchaPromise(resolve); }; - + challengeImg.onerror = () => { reject(setNewErrorMessage('Could not load challenges')); }; @@ -197,8 +227,8 @@ const AllCatalog = () => { setNewErrorMessage(error.message); console.log(error); }, }); - - + + const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions); @@ -217,7 +247,7 @@ const AllCatalog = () => { } }, [editedComment, setIsAuthorEdit]); - + useEffect(() => { let isActive = true; if (publishCommentEditOptions && triggerPublishCommentEdit) { @@ -235,6 +265,276 @@ const AllCatalog = () => { }, [triggerPublishCommentEdit, publishCommentEdit, publishCommentEditOptions]); + return ( +
    {setIsHoveringOnThread(thread.cid)}} + onMouseLeave={() => {setIsHoveringOnThread('')}}> + {commentMediaInfo?.url ? ( + setSelectedThread(thread.cid)}> + {commentMediaInfo?.type === "webpage" ? ( + thread.thumbnailUrl ? ( + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null; + }} /> + ) : null + ) : null} + {commentMediaInfo?.type === "image" ? ( + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null;}} /> + ) : null} + {commentMediaInfo?.type === "video" ? ( +
    + ); +}; + + +const CatalogRow = ({row}) => { + const posts = [] + for (const post of row) { + posts.push() + } + return
    {posts}
    +} + + +const AllCatalog = () => { + const { + defaultSubplebbits, + isModerationOpen, setIsModerationOpen, + isSettingsOpen, setIsSettingsOpen, + originalCommentContent, + selectedAddress, setSelectedAddress, + selectedStyle, + setSelectedTitle, + } = useGeneralStore(state => state); + + const virtuosoRef = useRef(); + + const navigate = useNavigate(); + + const [prevScrollPos, setPrevScrollPos] = useState(0); + const [visible, setVisible] = useState(true); + + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + const [deletePost, setDeletePost] = useState(false); + const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); + + const addresses = defaultSubplebbits.map(subplebbit => subplebbit.address); + const { feed, hasMore, loadMore } = useFeed({subplebbitAddresses: addresses, sortType: 'active'}); + const {subplebbits} = useSubplebbits({subplebbitAddresses: addresses, sortType: 'active'}); + const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp)); + + const stateString = useFeedStateString(subplebbits); + + const columnWidth = 180; + const windowWidth = useWindowWidth(); + const columnCount = Math.floor(windowWidth / columnWidth); + const rows = useFeedRows(selectedFeed, columnCount); + + // mobile navbar scroll effect + useEffect(() => { + const debouncedHandleScroll = debounce(() => { + const currentScrollPos = window.pageYOffset; + setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10); + setPrevScrollPos(currentScrollPos); + }, 50); + + window.addEventListener('scroll', debouncedHandleScroll); + + return () => window.removeEventListener('scroll', debouncedHandleScroll); + }, [prevScrollPos, visible]); + // mobile navbar board select functionality const handleSelectChange = (event) => { const selected = event.target.value; @@ -261,284 +561,6 @@ const AllCatalog = () => { }; - const CatalogPost = ({ post }) => { - const thread = post; - const commentMediaInfo = getCommentMediaInfo(thread); - const linkCount = countLinks(thread); - const fallbackImgUrl = "assets/filedeleted-res.gif"; - const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); - const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 }); - const [openMenuCid, setOpenMenuCid] = useState(null); - const isModerator = moderatorPermissions[thread.subplebbitAddress]; - - const handleOutsideClick = useCallback((e) => { - if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) { - setOpenMenuCid(null); - } - }, [openMenuCid]); - - const handleOptionClick = () => { - setOpenMenuCid(null); - }; - - useEffect(() => { - if (openMenuCid !== null) { - document.addEventListener('click', handleOutsideClick); - } else { - document.removeEventListener('click', handleOutsideClick); - } - - return () => { - document.removeEventListener('click', handleOutsideClick); - }; - }, [openMenuCid, handleOutsideClick]); - - const handleAuthorDeleteClick = (comment) => { - handleOptionClick(comment.cid); - - confirmAlert({ - customUI: ({ onClose }) => { - return ( - -
    -

    Are you sure you want to delete this post?

    -
    - - -
    -
    -
    - ); - } - }); - }; - - - const handleAuthorEditClick = (comment) => { - handleOptionClick(comment.cid); - setIsAuthorEdit(true); - setIsAuthorDelete(false); - setCommentCid(comment.cid); - setOriginalCommentContent(comment.content); - setIsEditModalOpen(true); - } - - return ( -
    { setIsHoveringOnThread(thread.cid) }} - onMouseLeave={() => { setIsHoveringOnThread('') }}> - {commentMediaInfo?.url ? ( - setSelectedThread(thread.cid)}> - {commentMediaInfo?.type === "webpage" ? ( - thread.thumbnailUrl ? ( - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> - ) : null - ) : null} - {commentMediaInfo?.type === "image" ? ( - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> - ) : null} - {commentMediaInfo?.type === "video" ? ( -
    - ); - }; - - - const CatalogRow = ({ row }) => { - const posts = [] - for (const post of row) { - posts.push() - } - return
    {posts}
    - } - useEffect(() => { const setLastVirtuosoState = () => { virtuosoRef.current?.getState((snapshot) => { @@ -551,7 +573,7 @@ const AllCatalog = () => { return () => window.removeEventListener('scroll', setLastVirtuosoState); }, [selectedAddress]); - + const lastVirtuosoState = lastVirtuosoStates["allCatalog"]; @@ -559,60 +581,60 @@ const AllCatalog = () => { return ( <> - p/All - Catalog - plebchan + p/All - Catalog - plebchan setIsCreateBoardOpen(false)} /> + selectedStyle={selectedStyle} + isOpen={isCreateBoardOpen} + closeModal={() => setIsCreateBoardOpen(false)} /> setIsSettingsOpen(false)} /> - { setIsModerationOpen(false); setDeletePost(false) }} - deletePost={deletePost} /> + selectedStyle={selectedStyle} + isOpen={isSettingsOpen} + closeModal={() => setIsSettingsOpen(false)} /> + {setIsModerationOpen(false); setDeletePost(false)}} + deletePost={deletePost} /> setIsEditModalOpen(false)} - originalCommentContent={originalCommentContent} /> + selectedStyle={selectedStyle} + isOpen={isEditModalOpen} + closeModal={() => setIsEditModalOpen(false)} + originalCommentContent={originalCommentContent} /> <> - - [ + + [ window.scrollTo(0, 0)}>All - / +  /  window.scrollTo(0, 0)}>Subscriptions - ] [ - {defaultSubplebbits.map((subplebbit, index) => ( - - {index === 0 ? null : "\u00a0"} - { - setSelectedTitle(subplebbit.title); - setSelectedAddress(subplebbit.address); - }} - >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} - - ))} - ] - + ] [ + {defaultSubplebbits.map((subplebbit, index) => ( + + {index === 0 ? null : "\u00a0"} + { + setSelectedTitle(subplebbit.title); + setSelectedAddress(subplebbit.address); + }} + >{subplebbit.title ? subplebbit.title : subplebbit.address} + {index !== defaultSubplebbits.length - 1 ? " /" : null} + + ))} + ] + [ - { - window.electron && window.electron.isElectron ? ( - setIsCreateBoardOpen(true) - ) : ( - alert( - 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' - ) + { + window.electron && window.electron.isElectron ? ( + setIsCreateBoardOpen(true) + ) : ( + alert( + 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' ) - } + ) + } }>Create Board ] [ @@ -631,20 +653,20 @@ const AllCatalog = () => { {defaultSubplebbits.map(subplebbit => ( - - ))} - - alert( - 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' + + ))} +   + alert( + 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' ) }>Create Board
    setIsSettingsOpen(true)}>Settings   - { handleStyleChange({ target: { value: "Yotsuba" } }); window.scrollTo(0, 0); }}>Home + {handleStyleChange({target: {value: "Yotsuba"}}); window.scrollTo(0, 0);}}>Home
    @@ -666,7 +688,7 @@ const AllCatalog = () => {
    Style: - +   @@ -739,42 +761,42 @@ const AllCatalog = () => { - <> - - [ + <> + + [ window.scrollTo(0, 0)}>All - / +  /  window.scrollTo(0, 0)}>Subscriptions - ] [ - {defaultSubplebbits.map((subplebbit, index) => ( - - {index === 0 ? null : "\u00a0"} - handleClickTitle(subplebbit.title, subplebbit.address)} - >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} - - ))} - ] - + ] [ + {defaultSubplebbits.map((subplebbit, index) => ( + + {index === 0 ? null : "\u00a0"} + handleClickTitle(subplebbit.title, subplebbit.address)} + >{subplebbit.title ? subplebbit.title : subplebbit.address} + {index !== defaultSubplebbits.length - 1 ? " /" : null} + + ))} + ] + - [ - { - window.electron && window.electron.isElectron ? ( - setIsCreateBoardOpen(true) - ) : ( - alert( - 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' - ) - ) - } - }>Create Board - ] + [ + { + window.electron && window.electron.isElectron ? ( + setIsCreateBoardOpen(true) + ) : ( + alert( + 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' + ) + ) + } + }>Create Board + ] [ setIsSettingsOpen(true)}>Settings ] [ - handleStyleChange({ target: { value: "Yotsuba" } } + handleStyleChange({target: {value: "Yotsuba"}} )}>Home ] @@ -791,13 +813,13 @@ const AllCatalog = () => { marginTop: "5px", marginBottom: "15px", }}> - About + About +  •  + App  •  - App -  •  - Twitter -  •  - Telegram + Twitter +  •  + Telegram
    diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx index 23e7b945..749d37d8 100755 --- a/src/components/views/Board.jsx +++ b/src/components/views/Board.jsx @@ -125,6 +125,7 @@ const Board = () => { const [selectedFeed, setSelectedFeed] = useState(feed); const [deletePost, setDeletePost] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); + const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [isModerator, setIsModerator] = useState(false); const [commentCid, setCommentCid] = useState(null); const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); @@ -1651,6 +1652,32 @@ const Board = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » +
      +
    • handleOptionClick(thread.cid)}> + Plebbit +
    • + {/*
    • handleOptionClick(thread.cid)}> + Seedit +
    • */} +
    • handleOptionClick(thread.cid)}> + Plebones +
    • +
    +
  • , document.body @@ -1948,6 +1975,32 @@ const Board = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » +
      +
    • handleOptionClick(reply.cid)}> + Plebbit +
    • + {/*
    • handleOptionClick(reply.cid)}> + Seedit +
    • */} +
    • handleOptionClick(reply.cid)}> + Plebones +
    • +
    +
  • , document.body diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx index 3c6dd1d6..79a21001 100755 --- a/src/components/views/Catalog.jsx +++ b/src/components/views/Catalog.jsx @@ -35,24 +35,671 @@ const {version} = packageJson let lastVirtuosoStates = {} +const CatalogPost = ({post}) => { + const { + editedComment, + setDeletePost, + setIsAuthorDelete, + captchaResponse, setCaptchaResponse, + selectedAddress, + setIsModerationOpen, + setChallengesArray, + setIsAuthorEdit, + setIsCaptchaOpen, + setIsEditModalOpen, + isModerator, + setModeratingCommentCid, + setOriginalCommentContent, + setPendingComment, + setResolveCaptchaPromise, + selectedStyle, + setSelectedThread, + } = useGeneralStore(state => state); + + const thread = post; + const commentMediaInfo = getCommentMediaInfo(thread); + const linkCount = countLinks(thread); + const fallbackImgUrl = "assets/filedeleted-res.gif"; + const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); + const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); + const [openMenuCid, setOpenMenuCid] = useState(null); + const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); + const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); + const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); + const [commentCid, setCommentCid] = useState(null); + + const threadMenuRefs = useRef({}); + const postMenuRef = useRef(null); + const postMenuCatalogRef = useRef(null); + const { subplebbitAddress } = useParams(); + + const [, setNewErrorMessage] = useError(); + const [, setNewSuccessMessage] = useSuccess(); + + const subplebbit = useSubplebbit({subplebbitAddress: selectedAddress}); + + const account = useAccount(); + + + const handleOutsideClick = useCallback((e) => { + if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) { + setOpenMenuCid(null); + } + }, [openMenuCid]); + + const handleOptionClick = () => { + setOpenMenuCid(null); + }; + + + useEffect(() => { + if (openMenuCid !== null) { + document.addEventListener('click', handleOutsideClick); + } else { + document.removeEventListener('click', handleOutsideClick); + } + + return () => { + document.removeEventListener('click', handleOutsideClick); + }; + }, [openMenuCid, handleOutsideClick]); + + + const handleAuthorDeleteClick = (comment) => { + handleOptionClick(comment.cid); + + confirmAlert({ + customUI: ({ onClose }) => { + return ( + +
    +

    Are you sure you want to delete this post?

    +
    + + +
    +
    +
    + ); + } + }); + }; + + + const handleAuthorEditClick = (comment) => { + handleOptionClick(comment.cid); + setIsAuthorEdit(true); + setIsAuthorDelete(false); + setCommentCid(comment.cid); + setOriginalCommentContent(comment.content); + setIsEditModalOpen(true); + } + + + const onChallengeVerification = (challengeVerification) => { + if (challengeVerification.challengeSuccess === true) { + setNewSuccessMessage('Challenge Success'); + } + else if (challengeVerification.challengeSuccess === false) { + setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`); + console.log('challenge failed', challengeVerification); + } + }; + + + const onChallenge = async (challenges, comment) => { + setPendingComment(comment); + let challengeAnswers = []; + + try { + challengeAnswers = await getChallengeAnswersFromUser(challenges) + } + catch (error) { + setNewErrorMessage(error.message); console.log(error); + } + if (challengeAnswers) { + await comment.publishChallengeAnswers(challengeAnswers) + } + }; + + + const [publishCommentEditOptions, setPublishCommentEditOptions] = useState({ + commentCid: commentCid, + content: editedComment || undefined, + subplebbitAddress: selectedAddress || subplebbitAddress, + onChallenge, + onChallengeVerification, + onError: (error) => { + setNewErrorMessage(error.message); console.log(error); + }, + }); + + + const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions); + + + useEffect(() => { + setPublishCommentEditOptions((prevOptions) => ({ + ...prevOptions, + commentCid: commentCid, + content: editedComment || undefined, + })); + }, [commentCid, editedComment]); + + + useEffect(() => { + if (editedComment !== '') { + setTriggerPublishCommentEdit(true); + } + }, [editedComment]); + + + useEffect(() => { + if (publishCommentEditOptions && triggerPublishCommentEdit) { + (async () => { + await publishCommentEdit(); + setTriggerPublishCommentEdit(false); + })(); + } + }, [publishCommentEditOptions, triggerPublishCommentEdit, publishCommentEdit]); + + + const getChallengeAnswersFromUser = async (challenges) => { + setChallengesArray(challenges); + + return new Promise((resolve, reject) => { + const imageString = challenges?.challenges[0].challenge; + const imageSource = `data:image/png;base64,${imageString}`; + const challengeImg = new Image(); + challengeImg.src = imageSource; + + challengeImg.onload = () => { + setIsCaptchaOpen(true); + + const handleKeyDown = async (event) => { + if (event.key === 'Enter') { + const currentCaptchaResponse = captchaResponse; + resolve(currentCaptchaResponse); + setIsCaptchaOpen(false); + document.removeEventListener('keydown', handleKeyDown); + event.preventDefault(); + } + }; + + setCaptchaResponse(''); + document.addEventListener('keydown', handleKeyDown); + + setResolveCaptchaPromise(resolve); + }; + + challengeImg.onerror = () => { + reject(setNewErrorMessage('Could not load challenges')); + }; + }); + }; + + + + if (post.type === 'rules') { + return ( +
    setIsHoveringOnThread('rules')} + onMouseLeave={() => setIsHoveringOnThread('')}> + +
    + R: 0 / L: 0 +
    + + +
    + { + threadMenuRefs.current["rules"] = el; + postMenuRef.current = el; + }} + className='post-menu-button' + id='post-menu-button-catalog' + rotated={openMenuCid === "rules"} + onClick={(event) => { + event.stopPropagation(); + const rect = threadMenuRefs.current["rules"].getBoundingClientRect(); + setMenuPosition({top: rect.top + window.scrollY, left: rect.left}); + setOpenMenuCid(prevCid => (prevCid === "rules" ? null : "rules")); + }} + > + ▶ + +
    + {createPortal( + {postMenuCatalogRef.current = el}} + onClick={(event) => event.stopPropagation()} + style={{position: "absolute", + top: menuPosition.top + 7, + left: menuPosition.left}}> +
    +
      +
    • handleOptionClick("rules")}>Hide thread
    • + {/* {isModerator ? ( + <> + change rules + + ) : null} */} +
    +
    +
    , document.body + )} +
    + +
    + Rules + {": " + subplebbit.rules?.map((rule, index) => `${index + 1}. ${rule}`).join(' ')} +
    + +
    + ) + } else if (post.type === 'description') { + return ( + <> +
    setIsHoveringOnThread('description')} + onMouseLeave={() => setIsHoveringOnThread('')}> + + {subplebbit.suggested?.avatarUrl ? ( + board avatar + ) : null} + + {subplebbit.suggested?.avatarUrl ? ( +
    + + +
    + ) : null} + +
    + R: 0 / L: 0 + {subplebbit.suggested?.avatarUrl ? null : ( +
    + + +
    + )} + { + threadMenuRefs.current["description"] = el; + postMenuRef.current = el; + }} + className='post-menu-button' + id='post-menu-button-catalog' + rotated={openMenuCid === "description"} + onClick={(event) => { + event.stopPropagation(); + const rect = threadMenuRefs.current["description"].getBoundingClientRect(); + setMenuPosition({top: rect.top + window.scrollY, left: rect.left}); + setOpenMenuCid(prevCid => (prevCid === "description" ? null : "description")); + }} + > + ▶ + +
    + {createPortal( + {postMenuCatalogRef.current = el}} + onClick={(event) => event.stopPropagation()} + style={{position: "absolute", + top: menuPosition.top + 7, + left: menuPosition.left}}> +
    +
      +
    • handleOptionClick("description")}>Hide thread
    • + {/* {isModerator ? ( + <> + change description + + ) : null} */} + {subplebbit.suggested?.avatarUrl ? ( +
    • {setIsImageSearchOpen(true)}} + onMouseLeave={() => {setIsImageSearchOpen(false)}}> + Image search » +
        +
      • handleOptionClick("description")}> + Google +
      • +
      • handleOptionClick("description")}> + Yandex +
      • +
      • handleOptionClick("description")}> + SauceNAO +
      • +
      +
    • + ) : null} +
    +
    +
    , document.body + )} +
    + setSelectedThread("description")}> +
    + Welcome to {subplebbit.title || subplebbit.address} + {": " + subplebbit.description} +
    + +
    + + ) + } else { + return ( +
    {setIsHoveringOnThread(thread.cid)}} + onMouseLeave={() => {setIsHoveringOnThread('')}}> + {commentMediaInfo?.url ? ( + setSelectedThread(thread.cid)}> + {commentMediaInfo?.type === "webpage" ? ( + thread.thumbnailUrl ? ( + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null; + }} /> + ) : null + ) : null} + {commentMediaInfo?.type === "image" ? ( + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null;}} /> + ) : null} + {commentMediaInfo?.type === "video" ? ( +
    + ) + } +}; + + +const CatalogRow = ({row}) => { + const posts = [] + for (const post of row) { + posts.push() + } + return
    {posts}
    +} + + const Catalog = () => { const { captchaResponse, setCaptchaResponse, setChallengesArray, defaultSubplebbits, - editedComment, - setIsAuthorDelete, - setIsAuthorEdit, setIsCaptchaOpen, isModerationOpen, setIsModerationOpen, + setIsModerator, isSettingsOpen, setIsSettingsOpen, - setModeratingCommentCid, + originalCommentContent, setPendingComment, setPendingCommentIndex, setResolveCaptchaPromise, selectedAddress, setSelectedAddress, selectedStyle, - setSelectedThread, selectedTitle, setSelectedTitle, showPostForm, showPostFormLink, @@ -64,9 +711,6 @@ const Catalog = () => { const subjectRef = useRef(); const commentRef = useRef(); const linkRef = useRef(); - const threadMenuRefs = useRef({}); - const postMenuRef = useRef(null); - const postMenuCatalogRef = useRef(null); const selectedThreadCidRef = useRef(null); const virtuosoRef = useRef(); @@ -78,13 +722,8 @@ const Catalog = () => { const [triggerPublishComment, setTriggerPublishComment] = useState(false); const [prevScrollPos, setPrevScrollPos] = useState(0); const [visible, setVisible] = useState(true); - const [isModerator, setIsModerator] = useState(false); const [isEditModalOpen, setIsEditModalOpen] = useState(false); - const [originalCommentContent, setOriginalCommentContent] = useState(null); - const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); const [deletePost, setDeletePost] = useState(false); - const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); - const [commentCid, setCommentCid] = useState(null); const [executeAnonMode, setExecuteAnonMode] = useState(false); const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); @@ -97,13 +736,15 @@ const Catalog = () => { const stateString = useStateString(subplebbit); let feedWithDescriptionAndRules = [...feed]; + if (subplebbit.rules) { feedWithDescriptionAndRules.unshift({ type: 'rules', content: subplebbit.rules }); } - + if (subplebbit.description) { feedWithDescriptionAndRules.unshift({ type: 'description', content: subplebbit.description }); } + const columnWidth = 180; const windowWidth = useWindowWidth(); @@ -120,7 +761,7 @@ const Catalog = () => { setIsModerator(false); } } - }, [account?.author.address, subplebbit.roles]); + }, [account?.author.address, subplebbit.roles, setIsModerator]); useEffect(() => { @@ -232,7 +873,7 @@ const Catalog = () => { useEffect(() => { if (index !== undefined) { setPendingCommentIndex(index); - navigate(`/profile/c/`); + navigate(`/profile/c/${index}`); } }, [index, navigate, setPendingCommentIndex]); @@ -368,46 +1009,6 @@ const Catalog = () => { }; - const [publishCommentEditOptions, setPublishCommentEditOptions] = useState({ - commentCid: commentCid, - content: editedComment || undefined, - subplebbitAddress: selectedAddress || subplebbitAddress, - onChallenge, - onChallengeVerification, - onError: (error) => { - setNewErrorMessage(error.message); console.log(error); - }, - }); - - - const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions); - - - useEffect(() => { - setPublishCommentEditOptions((prevOptions) => ({ - ...prevOptions, - commentCid: commentCid, - content: editedComment || undefined, - })); - }, [commentCid, editedComment]); - - - useEffect(() => { - if (editedComment !== '') { - setTriggerPublishCommentEdit(true); - } - }, [editedComment]); - - - useEffect(() => { - if (publishCommentEditOptions && triggerPublishCommentEdit) { - (async () => { - await publishCommentEdit(); - setTriggerPublishCommentEdit(false); - })(); - } - }, [publishCommentEditOptions, triggerPublishCommentEdit, publishCommentEdit]); - // mobile navbar board select functionality const handleSelectChange = (event) => { const selected = event.target.value; @@ -439,486 +1040,6 @@ const Catalog = () => { }; - const CatalogPost = ({post}) => { - const thread = post; - const commentMediaInfo = getCommentMediaInfo(thread); - const linkCount = countLinks(thread); - const fallbackImgUrl = "assets/filedeleted-res.gif"; - const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); - const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); - const [openMenuCid, setOpenMenuCid] = useState(null); - - const handleOutsideClick = useCallback((e) => { - if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) { - setOpenMenuCid(null); - } - }, [openMenuCid]); - - const handleOptionClick = () => { - setOpenMenuCid(null); - }; - - useEffect(() => { - if (openMenuCid !== null) { - document.addEventListener('click', handleOutsideClick); - } else { - document.removeEventListener('click', handleOutsideClick); - } - - return () => { - document.removeEventListener('click', handleOutsideClick); - }; - }, [openMenuCid, handleOutsideClick]); - - const handleAuthorDeleteClick = (comment) => { - handleOptionClick(comment.cid); - - confirmAlert({ - customUI: ({ onClose }) => { - return ( - -
    -

    Are you sure you want to delete this post?

    -
    - - -
    -
    -
    - ); - } - }); - }; - - - const handleAuthorEditClick = (comment) => { - handleOptionClick(comment.cid); - setIsAuthorEdit(true); - setIsAuthorDelete(false); - setCommentCid(comment.cid); - setOriginalCommentContent(comment.content); - setIsEditModalOpen(true); - } - - - if (post.type === 'rules') { - return ( -
    setIsHoveringOnThread('rules')} - onMouseLeave={() => setIsHoveringOnThread('')}> - -
    - R: 0 / L: 0 -
    - - -
    - { - threadMenuRefs.current["rules"] = el; - postMenuRef.current = el; - }} - className='post-menu-button' - id='post-menu-button-catalog' - rotated={openMenuCid === "rules"} - onClick={(event) => { - event.stopPropagation(); - const rect = threadMenuRefs.current["rules"].getBoundingClientRect(); - setMenuPosition({top: rect.top + window.scrollY, left: rect.left}); - setOpenMenuCid(prevCid => (prevCid === "rules" ? null : "rules")); - }} - > - ▶ - -
    - {createPortal( - {postMenuCatalogRef.current = el}} - onClick={(event) => event.stopPropagation()} - style={{position: "absolute", - top: menuPosition.top + 7, - left: menuPosition.left}}> -
    -
      -
    • handleOptionClick("rules")}>Hide thread
    • - {/* {isModerator ? ( - <> - change rules - - ) : null} */} -
    -
    -
    , document.body - )} -
    - -
    - Rules - {": " + subplebbit.rules.map((rule, index) => `${index + 1}. ${rule}`).join(' ')} -
    - -
    - ) - } else if (post.type === 'description') { - return ( - <> -
    setIsHoveringOnThread('description')} - onMouseLeave={() => setIsHoveringOnThread('')}> - - {subplebbit.suggested?.avatarUrl ? ( - board avatar - ) : null} - - {subplebbit.suggested?.avatarUrl ? ( -
    - - -
    - ) : null} - -
    - R: 0 / L: 0 - {subplebbit.suggested?.avatarUrl ? null : ( -
    - - -
    - )} - { - threadMenuRefs.current["description"] = el; - postMenuRef.current = el; - }} - className='post-menu-button' - id='post-menu-button-catalog' - rotated={openMenuCid === "description"} - onClick={(event) => { - event.stopPropagation(); - const rect = threadMenuRefs.current["description"].getBoundingClientRect(); - setMenuPosition({top: rect.top + window.scrollY, left: rect.left}); - setOpenMenuCid(prevCid => (prevCid === "description" ? null : "description")); - }} - > - ▶ - -
    - {createPortal( - {postMenuCatalogRef.current = el}} - onClick={(event) => event.stopPropagation()} - style={{position: "absolute", - top: menuPosition.top + 7, - left: menuPosition.left}}> -
    -
      -
    • handleOptionClick("description")}>Hide thread
    • - {/* {isModerator ? ( - <> - change description - - ) : null} */} - {subplebbit.suggested?.avatarUrl ? ( -
    • {setIsImageSearchOpen(true)}} - onMouseLeave={() => {setIsImageSearchOpen(false)}}> - Image search » -
        -
      • handleOptionClick("description")}> - Google -
      • -
      • handleOptionClick("description")}> - Yandex -
      • -
      • handleOptionClick("description")}> - SauceNAO -
      • -
      -
    • - ) : null} -
    -
    -
    , document.body - )} -
    - setSelectedThread("description")}> -
    - Welcome to {subplebbit.title || subplebbit.address} - {": " + subplebbit.description} -
    - -
    - - ) - } else { - return ( -
    {setIsHoveringOnThread(thread.cid)}} - onMouseLeave={() => {setIsHoveringOnThread('')}}> - {commentMediaInfo?.url ? ( - setSelectedThread(thread.cid)}> - {commentMediaInfo?.type === "webpage" ? ( - thread.thumbnailUrl ? ( - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> - ) : null - ) : null} - {commentMediaInfo?.type === "image" ? ( - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null;}} /> - ) : null} - {commentMediaInfo?.type === "video" ? ( -
    - ) - } - }; - - - const CatalogRow = ({row}) => { - const posts = [] - for (const post of row) { - posts.push() - } - return
    {posts}
    - } - useEffect(() => { const setLastVirtuosoState = () => { virtuosoRef.current?.getState((snapshot) => { diff --git a/src/components/views/NotFound.jsx b/src/components/views/NotFound.jsx index 8cad9317..cbcc290a 100644 --- a/src/components/views/NotFound.jsx +++ b/src/components/views/NotFound.jsx @@ -1,6 +1,5 @@ -import React, { useEffect, useRef } from 'react'; +import React, { useEffect } from 'react'; import { Helmet } from 'react-helmet-async'; -import useGeneralStore from '../../hooks/stores/useGeneralStore'; import { Link } from "react-router-dom"; import { Container, Header, Logo, Page, Boards, BoardsTitle } from '../styled/views/Home.styled'; import packageJson from '../../../package.json' @@ -8,31 +7,28 @@ const {version} = packageJson const NotFound = () => { - const { - bodyStyle, setBodyStyle, - selectedStyle, setSelectedStyle, - } = useGeneralStore(state => state); - - const prevStyle = useRef(selectedStyle); - const prevBodyStyle = useRef(bodyStyle); - - // prevent dark mode useEffect(() => { - const currentPrevStyle = prevStyle.current; - const currentPrevBodyStyle = prevBodyStyle.current; - - setBodyStyle({ + const yotsubaBodyStyle = { background: "#ffe url(assets/fade.png) top repeat-x", color: "maroon", - fontFamily: "Helvetica, Arial, sans-serif" - }); - setSelectedStyle("Yotsuba"); + fontFamily: "Arial, Helvetica, sans-serif" + }; + const originalBodyStyles = { + background: document.body.style.background, + color: document.body.style.color, + fontFamily: document.body.style.fontFamily + }; + + for (const [key, value] of Object.entries(yotsubaBodyStyle)) { + document.body.style[key] = value; + } return () => { - setSelectedStyle(currentPrevStyle); - setBodyStyle(currentPrevBodyStyle); + for (const [key, value] of Object.entries(originalBodyStyles)) { + document.body.style[key] = value; + } }; - }, [setBodyStyle, setSelectedStyle]); + }, []); return ( <> diff --git a/src/components/views/Subscriptions.jsx b/src/components/views/Subscriptions.jsx index 7e380338..7ce31183 100755 --- a/src/components/views/Subscriptions.jsx +++ b/src/components/views/Subscriptions.jsx @@ -97,6 +97,7 @@ const Subscriptions = () => { const [prevScrollPos, setPrevScrollPos] = useState(0); const [visible, setVisible] = useState(true); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); + const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [commentCid, setCommentCid] = useState(null); const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); @@ -1002,6 +1003,32 @@ const Subscriptions = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » +
      +
    • handleOptionClick(thread.cid)}> + Plebbit +
    • + {/*
    • handleOptionClick(thread.cid)}> + Seedit +
    • */} +
    • handleOptionClick(thread.cid)}> + Plebones +
    • +
    +
  • , document.body @@ -1305,6 +1332,32 @@ const Subscriptions = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » +
      +
    • handleOptionClick(reply.cid)}> + Plebbit +
    • + {/*
    • handleOptionClick(reply.cid)}> + Seedit +
    • */} +
    • handleOptionClick(reply.cid)}> + Plebones +
    • +
    +
  • , document.body diff --git a/src/components/views/SubscriptionsCatalog.jsx b/src/components/views/SubscriptionsCatalog.jsx index 0ed1316a..ca8b70dc 100755 --- a/src/components/views/SubscriptionsCatalog.jsx +++ b/src/components/views/SubscriptionsCatalog.jsx @@ -1,11 +1,11 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import { createPortal } from 'react-dom'; import { Helmet } from 'react-helmet-async'; -import { Link, useNavigate } from 'react-router-dom'; +import { Link, useNavigate} from 'react-router-dom'; import { confirmAlert } from 'react-confirm-alert'; import { Tooltip } from 'react-tooltip'; import { Virtuoso } from 'react-virtuoso'; -import { useAccount, useFeed, usePublishCommentEdit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; +import { useAccount, useFeed, usePublishCommentEdit, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import { Container, NavBar, Header, Break, PostMenu, BoardForm } from '../styled/views/Board.styled'; import { Threads, PostMenuCatalog } from '../styled/views/Catalog.styled'; @@ -28,102 +28,139 @@ import useGeneralStore from '../../hooks/stores/useGeneralStore'; import useSuccess from '../../hooks/useSuccess'; import useWindowWidth from '../../hooks/useWindowWidth'; import packageJson from '../../../package.json'; -const { version } = packageJson +const {version} = packageJson let lastVirtuosoStates = {} -const SubscriptionsCatalog = () => { +const CatalogPost = ({post}) => { const { - setCaptchaResponse, - setChallengesArray, - defaultSubplebbits, editedComment, + setDeletePost, setIsAuthorDelete, + captchaResponse, setCaptchaResponse, + setIsModerationOpen, + setChallengesArray, setIsAuthorEdit, setIsCaptchaOpen, - isModerationOpen, setIsModerationOpen, - isSettingsOpen, setIsSettingsOpen, + setIsEditModalOpen, setModeratingCommentCid, + setOriginalCommentContent, + setPendingComment, setResolveCaptchaPromise, selectedAddress, setSelectedAddress, selectedStyle, setSelectedThread, - setSelectedTitle, } = useGeneralStore(state => state); - const threadMenuRefs = useRef({}); - const postMenuRef = useRef(null); - const postMenuCatalogRef = useRef(null); - const virtuosoRef = useRef(); + const thread = post; + const commentMediaInfo = getCommentMediaInfo(thread); + const linkCount = countLinks(thread); + const fallbackImgUrl = "assets/filedeleted-res.gif"; + const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); + const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); + const [openMenuCid, setOpenMenuCid] = useState(null); + const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); + const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); + const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); + const [commentCid, setCommentCid] = useState(null); + const [isModerator, setIsModerator] = useState(false); - const account = useAccount(); - const navigate = useNavigate(); const [, setNewErrorMessage] = useError(); const [, setNewSuccessMessage] = useSuccess(); - const [prevScrollPos, setPrevScrollPos] = useState(0); - const [visible, setVisible] = useState(true); - - const [isEditModalOpen, setIsEditModalOpen] = useState(false); - const [originalCommentContent, setOriginalCommentContent] = useState(null); - const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); - const [deletePost, setDeletePost] = useState(false); - const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); - const [commentCid, setCommentCid] = useState(null); - const [moderatorPermissions, setModeratorPermissions] = useState({}); - const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); - - const { feed, hasMore, loadMore } = useFeed({ subplebbitAddresses: account?.subscriptions, sortType: 'active' }); - const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp)); - const { subplebbits } = useSubplebbits({ subplebbitAddresses: account?.subscriptions, sortType: 'active' }); - - const stateString = useFeedStateString(subplebbits); - - const columnWidth = 180; - const windowWidth = useWindowWidth(); - const columnCount = Math.floor(windowWidth / columnWidth); - const rows = useFeedRows(feed, columnCount); + const account = useAccount(); + const subplebbit = useSubplebbit({subplebbitAddress: thread.subplebbitAddress}); + const threadMenuRefs = useRef({}); + const postMenuRef = useRef(null); + const postMenuCatalogRef = useRef(null); useEffect(() => { - let permissions = {}; + if (subplebbit.roles !== undefined) { + const role = subplebbit.roles[account?.author.address]?.role; + + if (role === 'moderator' || role === 'admin' || role === 'owner') { + setIsModerator(true); + } else { + setIsModerator(false); + } + } + }, [account?.author.address, subplebbit.roles]); - selectedFeed.forEach(thread => { - const subplebbit = subplebbits.find(s => s && s.address === thread.subplebbitAddress); - if (subplebbit && subplebbit.roles) { - const role = subplebbit.roles[account?.author.address]?.role; + const handleOutsideClick = useCallback((e) => { + if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) { + setOpenMenuCid(null); + } + }, [openMenuCid]); - if (role === 'moderator' || role === 'admin' || role === 'owner') { - permissions[thread.subplebbitAddress] = true; - } else { - permissions[thread.subplebbitAddress] = false; - } + const handleOptionClick = () => { + setOpenMenuCid(null); + }; + + useEffect(() => { + if (openMenuCid !== null) { + document.addEventListener('click', handleOutsideClick); + } else { + document.removeEventListener('click', handleOutsideClick); + } + + return () => { + document.removeEventListener('click', handleOutsideClick); + }; + }, [openMenuCid, handleOutsideClick]); + + const handleAuthorDeleteClick = (comment) => { + handleOptionClick(comment.cid); + + confirmAlert({ + customUI: ({ onClose }) => { + return ( + +
    +

    Are you sure you want to delete this post?

    +
    + + +
    +
    +
    + ); } }); - - setModeratorPermissions(permissions); - }, [account?.author.address, selectedFeed, subplebbits]); + }; - // mobile navbar scroll effect - useEffect(() => { - const debouncedHandleScroll = debounce(() => { - const currentScrollPos = window.pageYOffset; - setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10); - setPrevScrollPos(currentScrollPos); - }, 50); + const handleAuthorEditClick = (comment) => { + handleOptionClick(comment.cid); + setIsAuthorEdit(true); + setIsAuthorDelete(false); + setCommentCid(comment.cid); + setOriginalCommentContent(comment.content); + setIsEditModalOpen(true); + } - window.addEventListener('scroll', debouncedHandleScroll); - - return () => window.removeEventListener('scroll', debouncedHandleScroll); - }, [prevScrollPos, visible]); const onChallengeVerification = (challengeVerification) => { if (challengeVerification.challengeSuccess === true) { - setNewSuccessMessage('Challenge Success'); - } + setNewSuccessMessage('Challenge Success'); + } else if (challengeVerification.challengeSuccess === false) { setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`); console.log('challenge failed', challengeVerification); @@ -132,6 +169,7 @@ const SubscriptionsCatalog = () => { const onChallenge = async (challenges, comment) => { + setPendingComment(comment); let challengeAnswers = []; try { challengeAnswers = await getChallengeAnswersFromUser(challenges) @@ -147,19 +185,19 @@ const SubscriptionsCatalog = () => { const getChallengeAnswersFromUser = async (challenges) => { setChallengesArray(challenges); - + return new Promise((resolve, reject) => { const imageString = challenges?.challenges[0].challenge; const imageSource = `data:image/png;base64,${imageString}`; const challengeImg = new Image(); challengeImg.src = imageSource; - + challengeImg.onload = () => { setIsCaptchaOpen(true); - + const handleKeyDown = async (event) => { if (event.key === 'Enter') { - const currentCaptchaResponse = useGeneralStore.getState().captchaResponse; + const currentCaptchaResponse = captchaResponse; resolve(currentCaptchaResponse); setIsCaptchaOpen(false); document.removeEventListener('keydown', handleKeyDown); @@ -172,7 +210,7 @@ const SubscriptionsCatalog = () => { setResolveCaptchaPromise(resolve); }; - + challengeImg.onerror = () => { reject(setNewErrorMessage('Could not load challenges')); }; @@ -189,8 +227,8 @@ const SubscriptionsCatalog = () => { setNewErrorMessage(error.message); console.log(error); }, }); - - + + const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions); @@ -209,7 +247,7 @@ const SubscriptionsCatalog = () => { } }, [editedComment, setIsAuthorEdit]); - + useEffect(() => { let isActive = true; if (publishCommentEditOptions && triggerPublishCommentEdit) { @@ -226,6 +264,279 @@ const SubscriptionsCatalog = () => { }; }, [triggerPublishCommentEdit, publishCommentEdit, publishCommentEditOptions]); + + return ( +
    {setIsHoveringOnThread(thread.cid)}} + onMouseLeave={() => {setIsHoveringOnThread('')}}> + {commentMediaInfo?.url ? ( + setSelectedThread(thread.cid)}> + {commentMediaInfo?.type === "webpage" ? ( + thread.thumbnailUrl ? ( + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null; + }} /> + ) : null + ) : null} + {commentMediaInfo?.type === "image" ? ( + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null;}} /> + ) : null} + {commentMediaInfo?.type === "video" ? ( +
    + ); +}; + + +const CatalogRow = ({row}) => { + const posts = [] + for (const post of row) { + posts.push() + } + return
    {posts}
    +} + + +const SubscriptionsCatalog = () => { + const { + defaultSubplebbits, + isModerationOpen, setIsModerationOpen, + isSettingsOpen, setIsSettingsOpen, + originalCommentContent, + selectedAddress, setSelectedAddress, + selectedStyle, + setSelectedTitle, + } = useGeneralStore(state => state); + + const virtuosoRef = useRef(); + + const account = useAccount(); + const navigate = useNavigate(); + + const [prevScrollPos, setPrevScrollPos] = useState(0); + const [visible, setVisible] = useState(true); + + const [isEditModalOpen, setIsEditModalOpen] = useState(false); + const [deletePost, setDeletePost] = useState(false); + const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false); + + const { feed, hasMore, loadMore } = useFeed({subplebbitAddresses: account?.subscriptions, sortType: 'active'}); + const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp)); + const {subplebbits} = useSubplebbits({subplebbitAddresses: account?.subscriptions, sortType: 'active'}); + + const stateString = useFeedStateString(subplebbits); + + const columnWidth = 180; + const windowWidth = useWindowWidth(); + const columnCount = Math.floor(windowWidth / columnWidth); + const rows = useFeedRows(selectedFeed, columnCount); + + + // mobile navbar scroll effect + useEffect(() => { + const debouncedHandleScroll = debounce(() => { + const currentScrollPos = window.pageYOffset; + setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10); + setPrevScrollPos(currentScrollPos); + }, 50); + + window.addEventListener('scroll', debouncedHandleScroll); + + return () => window.removeEventListener('scroll', debouncedHandleScroll); + }, [prevScrollPos, visible]); + + // desktop navbar board select functionality const handleClickTitle = (title, address) => { setSelectedTitle(title); @@ -252,284 +563,6 @@ const SubscriptionsCatalog = () => { }; - const CatalogPost = ({ post }) => { - const thread = post; - const commentMediaInfo = getCommentMediaInfo(thread); - const linkCount = countLinks(thread); - const fallbackImgUrl = "assets/filedeleted-res.gif"; - const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); - const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 }); - const [openMenuCid, setOpenMenuCid] = useState(null); - const isModerator = moderatorPermissions[thread.subplebbitAddress]; - - const handleOutsideClick = useCallback((e) => { - if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) { - setOpenMenuCid(null); - } - }, [openMenuCid]); - - const handleOptionClick = () => { - setOpenMenuCid(null); - }; - - useEffect(() => { - if (openMenuCid !== null) { - document.addEventListener('click', handleOutsideClick); - } else { - document.removeEventListener('click', handleOutsideClick); - } - - return () => { - document.removeEventListener('click', handleOutsideClick); - }; - }, [openMenuCid, handleOutsideClick]); - - const handleAuthorDeleteClick = (comment) => { - handleOptionClick(comment.cid); - - confirmAlert({ - customUI: ({ onClose }) => { - return ( - -
    -

    Are you sure you want to delete this post?

    -
    - - -
    -
    -
    - ); - } - }); - }; - - - const handleAuthorEditClick = (comment) => { - handleOptionClick(comment.cid); - setIsAuthorEdit(true); - setIsAuthorDelete(false); - setCommentCid(comment.cid); - setOriginalCommentContent(comment.content); - setIsEditModalOpen(true); - } - - return ( -
    { setIsHoveringOnThread(thread.cid) }} - onMouseLeave={() => { setIsHoveringOnThread('') }}> - {commentMediaInfo?.url ? ( - setSelectedThread(thread.cid)}> - {commentMediaInfo?.type === "webpage" ? ( - thread.thumbnailUrl ? ( - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> - ) : null - ) : null} - {commentMediaInfo?.type === "image" ? ( - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> - ) : null} - {commentMediaInfo?.type === "video" ? ( -
    - ); - }; - - - const CatalogRow = ({ row }) => { - const posts = [] - for (const post of row) { - posts.push() - } - return
    {posts}
    - } - useEffect(() => { const setLastVirtuosoState = () => { virtuosoRef.current?.getState((snapshot) => { @@ -542,7 +575,7 @@ const SubscriptionsCatalog = () => { return () => window.removeEventListener('scroll', setLastVirtuosoState); }, [selectedAddress]); - + const lastVirtuosoState = lastVirtuosoStates["subscriptionsCatalog"]; @@ -550,60 +583,60 @@ const SubscriptionsCatalog = () => { return ( <> - Subscriptions - Catalog - plebchan + Subscriptions - Catalog - plebchan setIsCreateBoardOpen(false)} /> + selectedStyle={selectedStyle} + isOpen={isCreateBoardOpen} + closeModal={() => setIsCreateBoardOpen(false)} /> setIsSettingsOpen(false)} /> - { setIsModerationOpen(false); setDeletePost(false) }} - deletePost={deletePost} /> + selectedStyle={selectedStyle} + isOpen={isSettingsOpen} + closeModal={() => setIsSettingsOpen(false)} /> + {setIsModerationOpen(false); setDeletePost(false)}} + deletePost={deletePost} /> setIsEditModalOpen(false)} - originalCommentContent={originalCommentContent} /> + selectedStyle={selectedStyle} + isOpen={isEditModalOpen} + closeModal={() => setIsEditModalOpen(false)} + originalCommentContent={originalCommentContent} /> <> - - [ + + [ window.scrollTo(0, 0)}>All - / +  /  window.scrollTo(0, 0)}>Subscriptions - ] [ - {defaultSubplebbits.map((subplebbit, index) => ( - - {index === 0 ? null : "\u00a0"} - { - setSelectedTitle(subplebbit.title); - setSelectedAddress(subplebbit.address); - }} - >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} - - ))} - ] - + ] [ + {defaultSubplebbits.map((subplebbit, index) => ( + + {index === 0 ? null : "\u00a0"} + { + setSelectedTitle(subplebbit.title); + setSelectedAddress(subplebbit.address); + }} + >{subplebbit.title ? subplebbit.title : subplebbit.address} + {index !== defaultSubplebbits.length - 1 ? " /" : null} + + ))} + ] + [ - { - window.electron && window.electron.isElectron ? ( - setIsCreateBoardOpen(true) - ) : ( - alert( - 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' - ) + { + window.electron && window.electron.isElectron ? ( + setIsCreateBoardOpen(true) + ) : ( + alert( + 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' ) - } + ) + } }>Create Board ] [ @@ -622,20 +655,20 @@ const SubscriptionsCatalog = () => { {defaultSubplebbits.map(subplebbit => ( - - ))} - - alert( - 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' + + ))} +   + alert( + 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' ) }>Create Board
    setIsSettingsOpen(true)}>Settings   - { handleStyleChange({ target: { value: "Yotsuba" } }); window.scrollTo(0, 0); }}>Home + {handleStyleChange({target: {value: "Yotsuba"}}); window.scrollTo(0, 0);}}>Home
    @@ -648,7 +681,7 @@ const SubscriptionsCatalog = () => {
    - <> + <>
    Subscriptions
    {account?.subscriptions.length < 1 ? (
    You haven't subscribed to any board yet.
    @@ -657,7 +690,7 @@ const SubscriptionsCatalog = () => { You have subscribed to {account?.subscriptions.length} board{account?.subscriptions.length > 1 ? "s" : null}. )} - + @@ -665,7 +698,7 @@ const SubscriptionsCatalog = () => {
    Style: - +   @@ -738,40 +771,40 @@ const SubscriptionsCatalog = () => { - <> - - [ + <> + + [ window.scrollTo(0, 0)}>Subscriptions - ] [ - {defaultSubplebbits.map((subplebbit, index) => ( - - {index === 0 ? null : "\u00a0"} - handleClickTitle(subplebbit.title, subplebbit.address)} - >{subplebbit.title ? subplebbit.title : subplebbit.address} - {index !== defaultSubplebbits.length - 1 ? " /" : null} - - ))} - ] - + ] [ + {defaultSubplebbits.map((subplebbit, index) => ( + + {index === 0 ? null : "\u00a0"} + handleClickTitle(subplebbit.title, subplebbit.address)} + >{subplebbit.title ? subplebbit.title : subplebbit.address} + {index !== defaultSubplebbits.length - 1 ? " /" : null} + + ))} + ] + - [ - { - window.electron && window.electron.isElectron ? ( - setIsCreateBoardOpen(true) - ) : ( - alert( - 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' - ) - ) - } - }>Create Board - ] + [ + { + window.electron && window.electron.isElectron ? ( + setIsCreateBoardOpen(true) + ) : ( + alert( + 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n' + ) + ) + } + }>Create Board + ] [ setIsSettingsOpen(true)}>Settings ] [ - handleStyleChange({ target: { value: "Yotsuba" } } + handleStyleChange({target: {value: "Yotsuba"}} )}>Home ] @@ -788,13 +821,13 @@ const SubscriptionsCatalog = () => { marginTop: "5px", marginBottom: "15px", }}> - About + About +  •  + App  •  - App -  •  - Twitter -  •  - Telegram + Twitter +  •  + Telegram
    diff --git a/src/components/views/Thread.jsx b/src/components/views/Thread.jsx index 5ed440d0..a4a8bdc7 100755 --- a/src/components/views/Thread.jsx +++ b/src/components/views/Thread.jsx @@ -104,6 +104,7 @@ const Thread = () => { const [prevScrollPos, setPrevScrollPos] = useState(0); const [visible, setVisible] = useState(true); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); + const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [isModerator, setIsModerator] = useState(false); const [commentCid, setCommentCid] = useState(null); const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); @@ -1125,6 +1126,32 @@ const Thread = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » +
      +
    • handleOptionClick(comment.cid)}> + Plebbit +
    • + {/*
    • handleOptionClick(comment.cid)}> + Seedit +
    • */} +
    • handleOptionClick(comment.cid)}> + Plebones +
    • +
    +
  • , document.body @@ -1386,6 +1413,32 @@ const Thread = () => { ) : null } +
  • {setIsClientRedirectMenuOpen(true)}} + onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}> + View on » +
      +
    • handleOptionClick(reply.cid)}> + Plebbit +
    • + {/*
    • handleOptionClick(reply.cid)}> + Seedit +
    • */} +
    • handleOptionClick(reply.cid)}> + Plebones +
    • +
    +
  • , document.body diff --git a/src/hooks/stores/useGeneralStore.js b/src/hooks/stores/useGeneralStore.js index 789a112a..1fabcd4a 100644 --- a/src/hooks/stores/useGeneralStore.js +++ b/src/hooks/stores/useGeneralStore.js @@ -20,6 +20,9 @@ const useGeneralStore = create((set) => ({ defaultSubplebbits: [], setDefaultSubplebbits: (subplebbits) => set({ defaultSubplebbits: subplebbits }), + deletePost: false, + setDeletePost: (deletePost) => set({ deletePost }), + editedComment: '', setEditedComment: (comment) => set({ editedComment: comment }), @@ -40,6 +43,12 @@ const useGeneralStore = create((set) => ({ isCaptchaOpen: false, setIsCaptchaOpen: (isOpen) => set({ isCaptchaOpen: isOpen }), + isEditModalOpen: false, + setIsEditModalOpen: (isOpen) => set({ isEditModalOpen: isOpen }), + + isModerator: false, + setIsModerator: (isModerator) => set({ isModerator }), + isModerationOpen: false, setIsModerationOpen: (isOpen) => set({ isModerationOpen: isOpen }), @@ -52,6 +61,9 @@ const useGeneralStore = create((set) => ({ moderatingCommentCid: '', setModeratingCommentCid: (cid) => set({ moderatingCommentCid: cid }), + originalCommentContent: null, + setOriginalCommentContent: (content) => set({ originalCommentContent: content }), + pendingComment: '', setPendingComment: (comment) => set({ pendingComment: comment }), diff --git a/yarn.lock b/yarn.lock index 9ca9c88d..458c1da8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3410,9 +3410,9 @@ form-data "^3.0.0" "@types/node@*", "@types/node@>=13.7.0": - version "20.4.7" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.7.tgz#74d323a93f1391a63477b27b9aec56669c98b2ab" - integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g== + version "20.4.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.8.tgz#b5dda19adaa473a9bf0ab5cbd8f30ec7d43f5c85" + integrity sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg== "@types/node@18.15.13": version "18.15.13" @@ -6745,13 +6745,13 @@ eslint-config-react-app@7.0.1, eslint-config-react-app@^7.0.1: eslint-plugin-testing-library "^5.0.1" eslint-import-resolver-node@^0.3.7: - version "0.3.7" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== + version "0.3.8" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.8.tgz#be719e72f5e96dcef7a60f74147c842db0c74b06" + integrity sha512-tEe+Pok22qIGaK3KoMP+N96GVDS66B/zreoVVmiavLvRUEmGRtvb4B8wO9jwnb8d2lvHtrkhZ7UD73dWBVnf/Q== dependencies: debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" + is-core-module "^2.13.0" + resolve "^1.22.4" eslint-module-utils@^2.8.0: version "2.8.0" @@ -6848,9 +6848,9 @@ eslint-plugin-react@^7.27.1: string.prototype.matchall "^4.0.8" eslint-plugin-testing-library@^5.0.1: - version "5.11.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz#0bad7668e216e20dd12f8c3652ca353009163121" - integrity sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q== + version "5.11.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz#5b46cdae96d4a78918711c0b4792f90088e62d20" + integrity sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw== dependencies: "@typescript-eslint/utils" "^5.58.0" @@ -8592,10 +8592,10 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" -is-core-module@^2.11.0, is-core-module@^2.12.0, is-core-module@^2.12.1, is-core-module@^2.5.0, is-core-module@^2.9.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" - integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== +is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.9.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db" + integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ== dependencies: has "^1.0.3" @@ -12813,21 +12813,12 @@ resolve.exports@^1.1.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== -resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.2: - version "1.22.2" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== +resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.3, resolve@^1.22.4: + version "1.22.4" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" + integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== dependencies: - is-core-module "^2.11.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -resolve@^1.22.3: - version "1.22.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.3.tgz#4b4055349ffb962600972da1fdc33c46a4eb3283" - integrity sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw== - dependencies: - is-core-module "^2.12.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0"