Files
5chan/src/components/modals/SettingsModal.jsx
T

403 lines
14 KiB
React
Raw Normal View History

2023-04-20 10:03:36 +02:00
import React, { useState, useEffect, useRef } from "react";
2023-03-15 15:25:09 +01:00
import { Link, useLocation, useNavigate } from "react-router-dom";
import Modal from "react-modal";
2023-05-10 14:55:06 +02:00
import { deleteCaches, exportAccount, importAccount, setAccount, setActiveAccount, useAccount, useAccounts } from "@plebbit/plebbit-react-hooks";
2023-05-24 12:15:43 +02:00
import { StyledModal } from "../styled/modals/SettingsModal.styled";
import useGeneralStore from "../../hooks/stores/useGeneralStore";
import useError from "../../hooks/useError";
import useSuccess from "../../hooks/useSuccess";
import packageJson from '../../../package.json'
2023-04-24 20:00:11 +00:00
const {version} = packageJson
2023-03-15 15:25:09 +01:00
const SettingsModal = ({ isOpen, closeModal }) => {
const {
selectedStyle,
} = useGeneralStore(state => state);
2023-03-15 15:25:09 +01:00
const navigate = useNavigate();
const location = useLocation();
2023-04-18 22:21:28 +02:00
const [expanded, setExpanded] = useState([]);
2023-05-10 14:17:24 +02:00
const [accountJson, setAccountJson] = useState(null);
2023-06-07 21:24:17 +02:00
const setErrorMessage = useError();
2023-06-09 10:49:36 +02:00
const [, setSuccessMessage] = useSuccess();
2023-03-15 15:25:09 +01:00
2023-04-20 10:03:36 +02:00
const account = useAccount();
2023-05-10 14:55:06 +02:00
const { accounts } = useAccounts();
2023-04-20 10:03:36 +02:00
const gatewayRef = useRef();
const ipfsRef = useRef();
const pubsubRef = useRef();
const dataPathRef = useRef();
2023-05-10 14:17:24 +02:00
const importRef = useRef();
const nameRef = useRef();
2023-04-20 10:03:36 +02:00
2023-04-20 13:59:04 +02:00
const isValidURL = (url) => {
try {
new URL(url);
return true;
} catch {
return false;
}
};
const handleSavePlebbitOptions = async () => {
const gatewayUrls = gatewayRef.current.value.split('\n').filter(url => url.trim());
const ipfsClientsOptions = ipfsRef.current.value.split('\n').filter(url => url.trim()) || undefined;
const pubsubClientsOptions = pubsubRef.current.value.split('\n').filter(url => url.trim());
const invalidUrls = [
...gatewayUrls,
...(ipfsClientsOptions || []),
...pubsubClientsOptions,
].filter((url) => !isValidURL(url));
if (invalidUrls.length > 0) {
setErrorMessage(`Invalid URL(s): ${invalidUrls.join(', ')}`);
return;
}
const plebbitOptions = {
ipfsGatewayUrls: gatewayUrls,
ipfsHttpClientsOptions: ipfsClientsOptions,
pubsubHttpClientsOptions: pubsubClientsOptions,
};
try {
await setAccount({ ...account, plebbitOptions });
2023-05-16 13:26:05 +02:00
localStorage.setItem("successToast", "Settings Saved");
2023-04-20 13:59:04 +02:00
window.location.reload();
} catch (error) {
setErrorMessage(error.message);
}
};
const handleResetPlebbitOptions = async () => {
setErrorMessage(null);
setSuccessMessage(null);
const defaultGatewayUrls = [
'https://ipfs.io',
'https://ipfsgateway.xyz',
'https://cloudflare-ipfs.com'
];
const defaultPubsubHttpClientsOptions = ['https://pubsubprovider.xyz/api/v0'];
gatewayRef.current.value = defaultGatewayUrls.join('\n');
ipfsRef.current.value = "";
pubsubRef.current.value = defaultPubsubHttpClientsOptions.join('\n');
dataPathRef.current.value = "";
try {
await setAccount({
...account,
plebbitOptions: {
ipfsGatewayUrls: defaultGatewayUrls,
ipfsHttpClientsOptions: undefined,
pubsubHttpClientsOptions: defaultPubsubHttpClientsOptions,
},
});
2023-05-16 13:26:05 +02:00
localStorage.setItem("successToast", "Settings Reset");
2023-04-20 13:59:04 +02:00
window.location.reload();
} catch (error) {
setErrorMessage(error.message);
}
};
2023-04-19 16:20:43 +02:00
2023-03-15 15:25:09 +01:00
const handleCloseModal = () => {
2023-05-10 14:17:24 +02:00
setAccountJson(null);
2023-05-03 17:35:38 +02:00
if (location.pathname.endsWith("/settings")) {
const newPath = location.pathname.slice(0, -9);
closeModal();
navigate(newPath, { replace: true });
2023-03-15 15:25:09 +01:00
} else {
2023-05-03 17:35:38 +02:00
closeModal();
2023-03-15 15:25:09 +01:00
}
2023-05-03 17:35:38 +02:00
};
2023-03-15 15:25:09 +01:00
2023-04-19 16:20:43 +02:00
2023-04-18 22:21:28 +02:00
const toggleExpanded = (index) => {
setExpanded((prevExpanded) => {
const newExpanded = [...prevExpanded];
if (newExpanded.includes(index)) {
newExpanded.splice(newExpanded.indexOf(index), 1);
} else {
newExpanded.push(index);
}
return newExpanded;
});
};
2023-04-19 16:20:43 +02:00
2023-04-18 22:21:28 +02:00
const expandAll = () => {
if (expanded.length === 3) {
setExpanded([]);
} else {
setExpanded([0, 1, 2]);
}
};
2023-04-19 16:20:43 +02:00
2023-04-19 16:00:31 +02:00
useEffect(() => {
if (localStorage.getItem("cacheCleared") === "true") {
setSuccessMessage("Cache Cleared");
localStorage.removeItem("cacheCleared");
}
2023-06-07 21:24:17 +02:00
}, [setSuccessMessage]);
2023-05-10 14:17:24 +02:00
const handleExport = async () => {
const activeAccountJson = await exportAccount();
setAccountJson(activeAccountJson);
};
const handleImport = async () => {
const accountJson = importRef.current.value;
try {
2023-05-16 13:26:05 +02:00
const parsedJson = JSON.parse(accountJson);
2023-05-10 14:17:24 +02:00
await importAccount(accountJson);
2023-05-16 13:26:05 +02:00
setActiveAccount(parsedJson.account?.name);
setSuccessMessage("Account Imported");
2023-05-10 14:17:24 +02:00
} catch (error) {
setErrorMessage(error.message);
}
};
2023-05-10 14:55:06 +02:00
const handleAccountChange = (e) => {
setActiveAccount(e.target.value);
};
const handleDisplayName = async () => {
const name = nameRef.current.value;
try {
await setAccount({
...account,
name: name || account.name,
author: {
...account.author,
displayName: name,
}});
setSuccessMessage("Account Name Saved");
} catch (error) {
setErrorMessage(error.message);
}
};
2023-04-18 22:21:28 +02:00
2023-03-15 15:25:09 +01:00
return (
<StyledModal
isOpen={isOpen}
2023-05-03 17:35:38 +02:00
onRequestClose={handleCloseModal}
2023-03-15 15:25:09 +01:00
contentLabel="Settings"
2023-05-10 14:17:24 +02:00
style={{ overlay: { backgroundColor: "rgba(0,0,0,.25)" }}}
2023-03-15 15:25:09 +01:00
selectedStyle={selectedStyle}
2023-04-18 22:21:28 +02:00
expanded={expanded}
2023-03-15 15:25:09 +01:00
>
<div className="panel">
<div className="panel-header">
2023-04-22 13:11:42 +02:00
<span id="version">
2023-04-24 20:00:11 +00:00
v{version}
2023-04-22 13:11:42 +02:00
</span>
2023-03-15 15:25:09 +01:00
Settings
<Link to="" onClick={handleCloseModal}>
<span className="icon" title="close" />
</Link>
</div>
2023-04-18 22:21:28 +02:00
<div className="all-div">
[
<button className="all-button"
onClick={expandAll} style={{all: "unset", cursor: "pointer"}}>
{expanded.length === 3 ? "Collapse All Settings" : "Expand All Settings"}
</button>
]
</div>
2023-04-20 10:03:36 +02:00
{/* <ul>
2023-04-18 22:21:28 +02:00
<li className="settings-cat-lbl">
<span className={`${expanded.includes(0) ? 'minus' : 'plus'}`}
onClick={() => toggleExpanded(0)}
/>
<span className="settings-pointer" style={{cursor: "pointer"}}
onClick={() => toggleExpanded(0)}
>Account</span>
</li>
<ul className="settings-cat" style={{ display: expanded.includes(0) ? 'block' : 'none' }}>
<li>
</li>
</ul>
</ul>*/}
2023-04-18 22:21:28 +02:00
<ul>
<li className="settings-cat-lbl">
<span className={`${expanded.includes(1) ? 'minus' : 'plus'}`}
onClick={() => toggleExpanded(1)}
/>
<span className="settings-pointer" style={{cursor: "pointer"}}
onClick={() => toggleExpanded(1)}
>Account</span>
<div className="plebbit-options-buttons"
style={{ display: expanded.includes(1) ? 'block' : 'none' }}
>
</div>
2023-04-18 22:21:28 +02:00
</li>
<ul className="settings-cat" style={{ display: expanded.includes(1) ? 'block' : 'none' }}>
2023-05-10 14:17:24 +02:00
<li className="settings-option disc">
Account Data
2023-05-10 14:55:06 +02:00
</li>
<div className="plebbit-options-buttons">
<button className="save-button"
onClick={handleExport}>Export</button>
<button className="reset-button"
onClick={handleImport}
>Import</button>
</div>
2023-05-10 14:17:24 +02:00
<li className="settings-tip">
To export, click "Export", then save your account data displayed below in a safe place. To import, paste your account data into the box below, then click "Import".
2023-04-18 22:21:28 +02:00
</li>
2023-05-10 14:17:24 +02:00
<div className="settings-input">
2023-05-30 19:08:21 +02:00
{accountJson ? (
<textarea value={accountJson} readOnly />
): (
<textarea ref={importRef} />
)}
2023-05-10 14:17:24 +02:00
</div>
<li className="settings-option disc" style={{marginTop: '15px'}}>
Account Address: u/{account?.author.shortAddress}
2023-05-10 14:55:06 +02:00
</li>
<li className="settings-tip">
Select a different account to use in the dropdown below.
</li>
<li>
<div className="settings-input">
<select className="settings-select"
value={account?.name}
onChange={handleAccountChange}
>
{accounts.map((account) => (
<option key={account?.name} value={account?.name}>
{account?.name}
</option>
))}
</select>
</div>
</li>
<li className="settings-option disc" style={{marginTop: '15px'}}>
Account Name
</li>
<li className="settings-tip">
Change both your account name (default "Account 1") and display name (default "Anonymous"). This will not change your address.
</li>
<li>
<div className="settings-input">
<input className="settings-input" style={{marginLeft: '20px'}}
type="text" ref={nameRef} defaultValue={account?.author.displayName}
placeholder="Anonymous"
/>
<button className="save-button" id="save-name"
onClick={handleDisplayName}>Save</button>
</div>
</li>
</ul>
2023-04-18 22:21:28 +02:00
</ul>
<ul>
<li className="settings-cat-lbl">
2023-04-19 16:33:49 +02:00
<span className={`${expanded.includes(2) ? 'minus' : 'plus'}`}
onClick={() => toggleExpanded(2)}
/>
<span className="settings-pointer" style={{cursor: "pointer"}}
onClick={() => toggleExpanded(2)}
>Plebbit Options</span>
<div className="plebbit-options-buttons"
style={{ display: expanded.includes(2) ? 'block' : 'none' }}
2023-04-19 16:33:49 +02:00
>
2023-05-10 14:17:24 +02:00
<button className="save-button"
onClick={handleSavePlebbitOptions}>Save</button>
<button className="reset-button"
onClick={handleResetPlebbitOptions}>Reset</button>
</div>
2023-04-18 22:21:28 +02:00
</li>
<ul className="settings-cat" style={{ display: expanded.includes(2) ? 'block' : 'none' }}>
<li className="settings-option disc">
2023-05-10 14:55:06 +02:00
IPFS Gateway URLs
</li>
<li className="settings-tip">
Optional URLs of IPFS gateways.
</li>
2023-04-18 22:21:28 +02:00
<div className="settings-input">
2023-04-19 14:00:45 +02:00
<textarea placeholder="IPFS Gateway URLs"
2023-04-20 13:59:04 +02:00
defaultValue={account?.plebbitOptions?.ipfsGatewayUrls.join("\n")}
2023-04-20 10:03:36 +02:00
ref={gatewayRef}
2023-04-19 13:56:38 +02:00
/>
2023-04-18 22:21:28 +02:00
</div>
</ul>
<ul className="settings-cat" style={{ display: expanded.includes(2) ? 'block' : 'none' }}>
<li className="settings-option disc">
2023-04-20 10:03:36 +02:00
IPFS HTTP Clients Options</li>
<li className="settings-tip">Optional URLs of IPFS APIs or IpfsHttpClientOptions, 'http://localhost:5001/api/v0' to use a local IPFS node.</li>
2023-04-18 22:21:28 +02:00
<div className="settings-input">
2023-04-21 10:00:01 +02:00
<textarea placeholder="IPFS HTTP Clients Options"
2023-04-20 13:59:04 +02:00
defaultValue={account?.plebbitOptions?.ipfsHttpClientsOptions ? account?.plebbitOptions?.ipfsHttpClientsOptions.join("\n") : ''}
2023-04-20 10:03:36 +02:00
ref={ipfsRef}
/>
2023-04-18 22:21:28 +02:00
</div>
</ul>
<ul className="settings-cat" style={{ display: expanded.includes(2) ? 'block' : 'none' }}>
<li className="settings-option disc">
2023-04-20 10:03:36 +02:00
PubSub HTTP Clients Options</li>
<li className="settings-tip">Optional URLs or IpfsHttpClientOptions used for pubsub publishing when ipfsHttpClientOptions isn't available, like in the browser.</li>
2023-04-18 22:21:28 +02:00
<div className="settings-input">
2023-04-21 10:00:01 +02:00
<textarea placeholder="PubSub HTTP Clients Options"
2023-04-20 13:59:04 +02:00
defaultValue={account?.plebbitOptions?.pubsubHttpClientsOptions.join("\n")}
2023-04-20 10:03:36 +02:00
ref={pubsubRef}
/>
2023-04-19 13:56:38 +02:00
</div>
</ul>
<ul className="settings-cat" style={{ display: expanded.includes(2) ? 'block' : 'none' }}>
<li className="settings-option disc">
Data Path (Node Only)</li>
2023-04-19 14:00:45 +02:00
<li className="settings-tip">Optional folder path to create/resume the user and subplebbit databases.</li>
2023-04-19 13:56:38 +02:00
<div className="settings-input">
2023-04-21 10:00:01 +02:00
<textarea placeholder="Data Path (Node Only)"
2023-04-20 10:03:36 +02:00
ref={dataPathRef}
/>
2023-04-18 22:21:28 +02:00
</div>
</ul>
2023-04-20 10:03:36 +02:00
{/* <ul className="settings-cat" style={{ display: expanded.includes(2) ? 'block' : 'none' }}>
<li className="settings-option disc">
Chain Providers</li>
<li className="settings-tip">Optional provider RPC URLs and chain IDs.</li>
<ul>
<li className="settings-option disc">Ethereum</li>
<li className="settings-option disc">Avalanche</li>
<li className="settings-option disc">Polygon</li>
</ul>
</ul> */}
2023-04-18 22:21:28 +02:00
</ul>
2023-04-19 13:56:38 +02:00
<div>
2023-04-19 16:00:31 +02:00
<button
className="cache-button"
onClick={async () => {
if (window.confirm("Are you sure you want to clear the cache?")) {
await deleteCaches();
localStorage.setItem("cacheCleared", "true");
window.location.reload();
}
}}
>
Clear Cache
</button>
2023-04-19 13:56:38 +02:00
</div>
2023-03-15 15:25:09 +01:00
</div>
</StyledModal>
);
}
Modal.setAppElement("#root");
export default SettingsModal;