From c59bbb6f50e8b89e516255b947e23b8bfa6022f9 Mon Sep 17 00:00:00 2001 From: "plebeius.eth" Date: Sat, 23 Sep 2023 13:21:58 +0200 Subject: [PATCH] feat(SettingsModal): automatically disable anon mode and tell the user, detecting ENS name when importing account, saving account or saving ENS --- src/components/modals/SettingsModal.jsx | 561 +++++++++++------------- 1 file changed, 260 insertions(+), 301 deletions(-) diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx index a9a9a1fe..d6cd11d3 100755 --- a/src/components/modals/SettingsModal.jsx +++ b/src/components/modals/SettingsModal.jsx @@ -1,24 +1,32 @@ -import React, { useState, useEffect, useMemo, useRef } from "react"; -import { Link, useLocation, useNavigate } from "react-router-dom"; -import Modal from "react-modal"; -import { deleteAccount, deleteCaches, importAccount, setAccount, setActiveAccount, useAccount, useAccounts, useResolvedAuthorAddress } from "@plebbit/plebbit-react-hooks"; -import stringify from "json-stringify-pretty-compact" -import { StyledModal } from "../styled/modals/SettingsModal.styled"; -import useError from "../../hooks/useError"; -import useSuccess from "../../hooks/useSuccess"; +import React, { useState, useEffect, useMemo, useRef } from 'react'; +import { Link, useLocation, useNavigate } from 'react-router-dom'; +import Modal from 'react-modal'; +import { + deleteAccount, + deleteCaches, + importAccount, + setAccount, + setActiveAccount, + useAccount, + useAccounts, + useResolvedAuthorAddress, +} from '@plebbit/plebbit-react-hooks'; +import stringify from 'json-stringify-pretty-compact'; +import { StyledModal } from '../styled/modals/SettingsModal.styled'; +import useError from '../../hooks/useError'; +import useSuccess from '../../hooks/useSuccess'; import useAnonModeStore from '../../hooks/stores/useAnonModeStore'; import useGeneralStore from '../../hooks/stores/useGeneralStore'; import packageJson from '../../../package.json'; -const {version} = packageJson; +const { version } = packageJson; const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : ''; - const SettingsModal = ({ isOpen, closeModal }) => { - const { selectedStyle } = useGeneralStore(state => state); + const { selectedStyle } = useGeneralStore((state) => state); const { anonymousMode, setAnonymousMode } = useAnonModeStore(); const navigate = useNavigate(); const location = useLocation(); - + const [expanded, setExpanded] = useState([]); const [copyStatus, setCopyStatus] = useState(false); const [ensName, setEnsName] = useState(''); @@ -38,7 +46,9 @@ const SettingsModal = ({ isOpen, closeModal }) => { }, [account]); const [editedAccountJson, setEditedAccountJson] = useState(accountJson); - useEffect(() => { setEditedAccountJson(accountJson)}, [accountJson]) + useEffect(() => { + setEditedAccountJson(accountJson); + }, [accountJson]); const gatewayRef = useRef(); const ipfsRef = useRef(); @@ -51,39 +61,22 @@ const SettingsModal = ({ isOpen, closeModal }) => { const ensRef = useRef(); const isElectron = window.electron && window.electron.isElectron; - const author = {...account?.author, address: ensName}; + const author = { ...account?.author, address: ensName }; const { resolvedAddress, state } = useResolvedAuthorAddress({ author, cache: false }); - const defaultGatewayUrls = isElectron ? undefined : [ - 'https://ipfs.io', - 'https://ipfsgateway.xyz', - 'https://cloudflare-ipfs.com', - 'https://plebpubsub.live' - ]; + const defaultGatewayUrls = isElectron ? undefined : ['https://ipfs.io', 'https://ipfsgateway.xyz', 'https://cloudflare-ipfs.com', 'https://plebpubsub.live']; - const defaultPubsubHttpClientsOptions = isElectron ? undefined : [ - 'https://pubsubprovider.xyz/api/v0', - 'https://plebpubsub.live/api/v0' - ]; + const defaultPubsubHttpClientsOptions = isElectron ? undefined : ['https://pubsubprovider.xyz/api/v0', 'https://plebpubsub.live/api/v0']; - const defaultEthereumRpcUrls = [ - 'ethers.js', - 'https://ethrpc.xyz', - 'viem', - ]; - - const defaultPolygonRpcUrls = [ - 'https://polygon-rpc.com', - ]; + const defaultEthereumRpcUrls = ['ethers.js', 'https://ethrpc.xyz', 'viem']; + const defaultPolygonRpcUrls = ['https://polygon-rpc.com']; useEffect(() => { if (checkedENS && resolvedAddress && state === 'succeeded') { setCheckedENS(false); } }, [checkedENS, state, resolvedAddress]); - - const handleENSChange = () => { const newEnsName = ensRef.current.value; @@ -106,8 +99,8 @@ const SettingsModal = ({ isOpen, closeModal }) => { address: ensName, }, }); - setNewSuccessMessage("ENS name saved successfully."); - + setAnonymousMode(false); + setNewSuccessMessage('ENS name saved successfully. Anon mode has been disabled.'); } catch (error) { setNewErrorMessage(error.message); console.log(error); @@ -117,7 +110,6 @@ const SettingsModal = ({ isOpen, closeModal }) => { } }; - const isValidURL = (url) => { try { new URL(url); @@ -127,7 +119,6 @@ const SettingsModal = ({ isOpen, closeModal }) => { } }; - const handleCopyAddress = async () => { try { await navigator.clipboard.writeText(account?.author.address); @@ -135,8 +126,7 @@ const SettingsModal = ({ isOpen, closeModal }) => { } catch (err) { console.error('Failed to copy text: ', err); } - }; - + }; useEffect(() => { let copyStatusTimeoutId; @@ -148,17 +138,16 @@ const SettingsModal = ({ isOpen, closeModal }) => { checkedENSTimeoutId = setTimeout(() => setCheckedENS(false), 5000); } return () => { - clearTimeout(copyStatusTimeoutId); - clearTimeout(checkedENSTimeoutId); + clearTimeout(copyStatusTimeoutId); + clearTimeout(checkedENSTimeoutId); }; }, [copyStatus, checkedENS]); - const handleSavePlebbitOptions = async () => { let gatewayUrls = gatewayRef.current.value.split('\n').filter((url) => url.trim()); - let ipfsClientsOptions = ipfsRef.current.value.split('\n').filter(url => url.trim()); + let ipfsClientsOptions = ipfsRef.current.value.split('\n').filter((url) => url.trim()); let pubsubClientsOptions = pubsubRef.current.value.split('\n').filter((url) => url.trim()); - + if (!isElectron) { if (!gatewayUrls.length) gatewayUrls = defaultGatewayUrls; if (!pubsubClientsOptions.length) pubsubClientsOptions = defaultPubsubHttpClientsOptions; @@ -172,9 +161,9 @@ const SettingsModal = ({ isOpen, closeModal }) => { } const invalidUrls = [ - ...(Array.isArray(gatewayUrls) ? gatewayUrls : (Array.isArray(defaultGatewayUrls) ? defaultGatewayUrls : [])), + ...(Array.isArray(gatewayUrls) ? gatewayUrls : Array.isArray(defaultGatewayUrls) ? defaultGatewayUrls : []), ...(Array.isArray(ipfsClientsOptions) ? ipfsClientsOptions : []), - ...(Array.isArray(pubsubClientsOptions) ? pubsubClientsOptions : (Array.isArray(defaultPubsubHttpClientsOptions) ? defaultPubsubHttpClientsOptions : [])), + ...(Array.isArray(pubsubClientsOptions) ? pubsubClientsOptions : Array.isArray(defaultPubsubHttpClientsOptions) ? defaultPubsubHttpClientsOptions : []), ].filter((url) => !isValidURL(url)); if (invalidUrls.length > 0) { @@ -190,47 +179,44 @@ const SettingsModal = ({ isOpen, closeModal }) => { try { await setAccount({ ...account, plebbitOptions }); - localStorage.setItem("successToast", "Settings saved successfully."); + localStorage.setItem('successToast', 'Settings saved successfully.'); window.location.reload(); } catch (error) { - setNewErrorMessage(error.message); console.log(error); + setNewErrorMessage(error.message); + console.log(error); } }; - const handleSaveChainProviders = async () => { - let ethereumRpcUrls = ethereumRpcRef.current.value.split('\\n').filter(url => url.trim()); - let polygonRpcUrls = polygonRpcRef.current.value.split('\\n').filter(url => url.trim()); - + let ethereumRpcUrls = ethereumRpcRef.current.value.split('\\n').filter((url) => url.trim()); + let polygonRpcUrls = polygonRpcRef.current.value.split('\\n').filter((url) => url.trim()); + if (!ethereumRpcUrls.length) { ethereumRpcUrls = defaultEthereumRpcUrls; } - + if (!polygonRpcUrls.length) { polygonRpcUrls = defaultPolygonRpcUrls; } - - const invalidUrls = [ - ...ethereumRpcUrls || defaultEthereumRpcUrls, - ...polygonRpcUrls || defaultPolygonRpcUrls, - ].filter((url) => !isValidURL(url)); - + + const invalidUrls = [...(ethereumRpcUrls || defaultEthereumRpcUrls), ...(polygonRpcUrls || defaultPolygonRpcUrls)].filter((url) => !isValidURL(url)); + if (invalidUrls.length > 0) { setNewErrorMessage(`Invalid URL(s): ${invalidUrls.join(', ')}`); return; } - + const chainProviders = { - 'eth': { + eth: { urls: ethereumRpcUrls, chainId: 1, }, - 'matic': { + matic: { urls: polygonRpcUrls, chainId: 137, - } - } - + }, + }; + try { await setAccount({ ...account, @@ -239,22 +225,22 @@ const SettingsModal = ({ isOpen, closeModal }) => { chainProviders, }, }); - localStorage.setItem("successToast", "Blockchain options saved successfully."); + localStorage.setItem('successToast', 'Blockchain options saved successfully.'); window.location.reload(); } catch (error) { - setNewErrorMessage(error.message); console.log(error); + setNewErrorMessage(error.message); + console.log(error); } }; - const handleResetPlebbitOptions = async () => { setNewErrorMessage(null); setNewSuccessMessage(null); - gatewayRef.current.value = defaultGatewayUrls ? defaultGatewayUrls.join('\n') : ""; - ipfsRef.current.value = ""; - pubsubRef.current.value = defaultPubsubHttpClientsOptions ? defaultPubsubHttpClientsOptions.join('\n') : ""; - dataPathRef.current.value = ""; + gatewayRef.current.value = defaultGatewayUrls ? defaultGatewayUrls.join('\n') : ''; + ipfsRef.current.value = ''; + pubsubRef.current.value = defaultPubsubHttpClientsOptions ? defaultPubsubHttpClientsOptions.join('\n') : ''; + dataPathRef.current.value = ''; try { await setAccount({ @@ -265,32 +251,32 @@ const SettingsModal = ({ isOpen, closeModal }) => { pubsubHttpClientsOptions: defaultPubsubHttpClientsOptions, }, }); - localStorage.setItem("successToast", "Settings reset successfully."); + localStorage.setItem('successToast', 'Settings reset successfully.'); window.location.reload(); } catch (error) { - setNewErrorMessage(error.message); console.log(error); + setNewErrorMessage(error.message); + console.log(error); } }; - const handleResetChainProviders = async () => { setNewErrorMessage(null); setNewSuccessMessage(null); - + ethereumRpcRef.current.value = defaultEthereumRpcUrls.join('\n'); polygonRpcRef.current.value = defaultPolygonRpcUrls.join('\n'); - + const chainProviders = { - 'eth': { + eth: { urls: defaultEthereumRpcUrls, chainId: 1, }, - 'matic': { + matic: { urls: defaultPolygonRpcUrls, chainId: 137, - } - } - + }, + }; + try { await setAccount({ ...account, @@ -299,25 +285,23 @@ const SettingsModal = ({ isOpen, closeModal }) => { chainProviders, }, }); - localStorage.setItem("successToast", "Blockchain options reset successfully."); + localStorage.setItem('successToast', 'Blockchain options reset successfully.'); window.location.reload(); } catch (error) { - setNewErrorMessage(error.message); console.log(error); + setNewErrorMessage(error.message); + console.log(error); } }; - - const handleCloseModal = () => { - if (location.pathname.endsWith("/settings")) { + if (location.pathname.endsWith('/settings')) { const newPath = location.pathname.slice(0, -9); closeModal(); navigate(newPath, { replace: true }); } else { closeModal(); } - }; - + }; const toggleExpanded = (index) => { setExpanded((prevExpanded) => { @@ -331,7 +315,6 @@ const SettingsModal = ({ isOpen, closeModal }) => { }); }; - const expandAll = () => { if (expanded.length === 4) { setExpanded([]); @@ -339,29 +322,33 @@ const SettingsModal = ({ isOpen, closeModal }) => { setExpanded([0, 1, 2, 3]); } }; - - + useEffect(() => { - if (localStorage.getItem("cacheCleared") === "true") { - setNewSuccessMessage("Cache cleared successfully."); - localStorage.removeItem("cacheCleared"); + if (localStorage.getItem('cacheCleared') === 'true') { + setNewSuccessMessage('Cache cleared successfully.'); + localStorage.removeItem('cacheCleared'); } }, [setNewSuccessMessage]); - const handleSaveAccount = async () => { const data = importRef.current.value; + const oldData = accountJson; try { const parsedJson = JSON.parse(data); await setAccount(parsedJson.account); - setNewSuccessMessage("Account data saved successfully."); + + if (!oldData.account?.author?.address.endsWith('.eth') && parsedJson.account?.author?.address.endsWith('.eth') && anonymousMode === true) { + setAnonymousMode(false); + setNewSuccessMessage('Account data saved successfully. ENS address detected, Anon mode disabled.'); + } else { + setNewSuccessMessage('Account data saved successfully.'); + } } catch (error) { - setNewErrorMessage("Error saving account data: " + error.message); + setNewErrorMessage('Error saving account data: ' + error.message); console.error(error); } }; - const handleImportAccount = async () => { const data = importRef.current.value; @@ -369,28 +356,32 @@ const SettingsModal = ({ isOpen, closeModal }) => { const parsedJson = JSON.parse(data); await importAccount(data); setActiveAccount(parsedJson.account?.name); - setNewSuccessMessage("Account imported successfully."); - + + if (parsedJson.account?.author?.address.endsWith('.eth') && anonymousMode === true) { + setAnonymousMode(false); + setNewSuccessMessage('Account imported successfully. ENS address detected, Anon mode disabled.'); + } else { + setNewSuccessMessage('Account imported successfully.'); + } } catch (error) { - setNewErrorMessage(error.message); console.log(error); + setNewErrorMessage(error.message); + console.log(error); } }; - const handleDeleteAccount = async () => { - if (window.confirm("Are you sure you want to delete this account?")) { + if (window.confirm('Are you sure you want to delete this account?')) { try { await deleteAccount(account?.name); - localStorage.setItem("successToast", "Account deleted successfully."); + localStorage.setItem('successToast', 'Account deleted successfully.'); window.location.reload(); } catch (error) { - setNewErrorMessage("Error deleting account: " + error.message); + setNewErrorMessage('Error deleting account: ' + error.message); console.error(error); } } }; - const handleAccountChange = (e) => { setActiveAccount(e.target.value); }; @@ -399,181 +390,165 @@ const SettingsModal = ({ isOpen, closeModal }) => { const name = nameRef.current.value; try { - await setAccount({ - ...account, + await setAccount({ + ...account, name: name || account?.name, author: { ...account?.author, displayName: name, - }}); - setNewSuccessMessage("Account name saved successfully."); + }, + }); + setNewSuccessMessage('Account name saved successfully.'); } catch (error) { - setNewErrorMessage(error.message); console.log(error); + setNewErrorMessage(error.message); + console.log(error); } }; - return ( -
-
- - v{version}{commitRef} -  +
+
+ + v{version} + {commitRef} -  {window.electron && window.electron.isElectron ? ( - + full node - ) : (web) - } + ) : ( + web + )} Settings - - + +
-
+
[ - ]
    -
  • - toggleExpanded(1)} - /> - toggleExpanded(1)} - >Account +
  • + toggleExpanded(1)} /> + toggleExpanded(1)}> + Account +
  • -
      -
    • -