mirror of
https://github.com/plebbit/seedit.git
synced 2026-04-20 23:28:52 -04:00
BIN
public/assets/buttons/droparrowblue.gif
Normal file
BIN
public/assets/buttons/droparrowblue.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 73 B |
@@ -18,7 +18,7 @@
|
||||
|
||||
.userDropdownButton {
|
||||
background: none no-repeat scroll center right;
|
||||
background-image: url("/public/assets/buttons/droparrowgray.gif");
|
||||
background-image: var(--blue-dropdown-arrow);
|
||||
padding-right: 21px;
|
||||
margin-right: -5px;
|
||||
cursor: pointer;
|
||||
@@ -75,5 +75,32 @@
|
||||
}
|
||||
|
||||
.selectedTextButton {
|
||||
color: var(--text-secondary);
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.dropChoices {
|
||||
top: 16px;
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
border: 1px solid var(--border-text);
|
||||
background-color: var(--background);
|
||||
color: var(--text-primary) ;
|
||||
white-space: nowrap;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.dropdownChoice {
|
||||
cursor: pointer;
|
||||
padding: 2px 3px 1px 3px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.dropdownChoice:hover {
|
||||
background-color: var(--background-primary);
|
||||
}
|
||||
@@ -22,9 +22,11 @@ const AccountBar = () => {
|
||||
const searchBarRef = useRef<HTMLDivElement>(null);
|
||||
const searchBarButtonRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const [accountSelectVisible, setAccountSelectVisible] = useState(false);
|
||||
const toggleAccountSelectVisible = () => setAccountSelectVisible(!accountSelectVisible);
|
||||
const accountSelectRef = useRef<HTMLDivElement>(null);
|
||||
const [isAccountDropdownOpen, setIsAccountDropdownOpen] = useState(false);
|
||||
const toggleAccountDropdown = () => setIsAccountDropdownOpen(!isAccountDropdownOpen);
|
||||
const accountDropdownRef = useRef<HTMLDivElement>(null);
|
||||
const accountDropdownChoicesRef = useRef<HTMLDivElement>(null);
|
||||
const accountDropdownClass = isAccountDropdownOpen ? styles.visible : styles.hidden;
|
||||
const accountSelectButtonRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
let submitLink;
|
||||
@@ -41,17 +43,22 @@ const AccountBar = () => {
|
||||
|
||||
const isOutsideSearchBar =
|
||||
searchBarRef.current && !searchBarRef.current.contains(target) && searchBarButtonRef.current && !searchBarButtonRef.current.contains(target);
|
||||
const isOutsideAccountSelect =
|
||||
accountSelectRef.current && !accountSelectRef.current.contains(target) && accountSelectButtonRef.current && !accountSelectButtonRef.current.contains(target);
|
||||
const isOutsideAccountDropdown =
|
||||
accountDropdownRef.current &&
|
||||
!accountDropdownRef.current.contains(target) &&
|
||||
accountDropdownChoicesRef.current &&
|
||||
!accountDropdownChoicesRef.current.contains(target);
|
||||
const isOutsideAccountSelectButton = accountSelectButtonRef.current && !accountSelectButtonRef.current.contains(target);
|
||||
|
||||
if (isOutsideAccountSelectButton && isOutsideAccountDropdown) {
|
||||
setIsAccountDropdownOpen(false);
|
||||
}
|
||||
|
||||
if (isOutsideSearchBar) {
|
||||
setSearchVisible(false);
|
||||
}
|
||||
if (isOutsideAccountSelect) {
|
||||
setAccountSelectVisible(false);
|
||||
}
|
||||
},
|
||||
[searchBarRef, accountSelectRef],
|
||||
[searchBarRef, accountSelectButtonRef, accountDropdownRef, accountDropdownChoicesRef],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -61,39 +68,31 @@ const AccountBar = () => {
|
||||
};
|
||||
}, [handleClickOutside]);
|
||||
|
||||
const accountsOptions = accounts.map((account) => (
|
||||
<option key={account?.id} value={account?.name}>
|
||||
u/{account?.author?.shortAddress?.toLowerCase?.().substring(0, 8) || ''}
|
||||
</option>
|
||||
const accountDropdownOptions = accounts.map((account, index) => (
|
||||
<span key={index} className={styles.dropdownChoice} onClick={() => setActiveAccount(account?.name)}>
|
||||
{`u/${account?.author?.shortAddress}`}
|
||||
</span>
|
||||
));
|
||||
|
||||
accountsOptions[accountsOptions.length] = (
|
||||
<option key='create' value='createAccount'>
|
||||
accountDropdownOptions.push(
|
||||
<Link key='create' to='#' className={styles.dropdownChoice} onClick={() => createAccount()}>
|
||||
+create
|
||||
</option>
|
||||
</Link>,
|
||||
);
|
||||
|
||||
const onAccountSelectChange = async (e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
if (e.target.value === 'createAccount') {
|
||||
createAccount();
|
||||
} else {
|
||||
setActiveAccount(e.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<span className={styles.user}>
|
||||
<Link to='/user.eth' onClick={(e) => e.preventDefault()}>
|
||||
{account?.author?.shortAddress}
|
||||
</Link>
|
||||
<span className={styles.userDropdownButton} ref={accountSelectButtonRef} onClick={toggleAccountSelectVisible} />
|
||||
{accountSelectVisible && (
|
||||
<span className={styles.accountSelect} ref={accountSelectRef}>
|
||||
<select className={styles.select} onChange={onAccountSelectChange} value={account?.name}>
|
||||
{accountsOptions}
|
||||
</select>
|
||||
</span>
|
||||
<span className={styles.userDropdownButton} ref={accountSelectButtonRef} onClick={toggleAccountDropdown} />
|
||||
{isAccountDropdownOpen && (
|
||||
<div className={`${styles.dropdown} ${accountDropdownClass}`} ref={accountDropdownRef}>
|
||||
<div className={`${styles.dropChoices} ${styles.accountDropChoices}`} ref={accountDropdownChoicesRef}>
|
||||
{accountDropdownOptions}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</span>
|
||||
<span className={styles.submitButton}>
|
||||
|
||||
@@ -118,13 +118,13 @@
|
||||
.tabMenu li a {
|
||||
padding: 2px 6px 0 6px;
|
||||
text-decoration: none;
|
||||
color: var(--text-secondary);
|
||||
color: var(--green);
|
||||
background-color: var(--background);
|
||||
border-bottom: 1px solid var(--background);
|
||||
}
|
||||
|
||||
.tabMenu li .selected {
|
||||
color: var(--text-secondary);
|
||||
color: var(--green);
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--border-primary);
|
||||
border-bottom: 2px solid var(--background);
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
}
|
||||
|
||||
.stampPending {
|
||||
color: var(--label-pending);
|
||||
border-color: var(--label-pending);
|
||||
color: var(--yellow);
|
||||
border-color: var(--yellow);
|
||||
}
|
||||
|
||||
.stampFailed {
|
||||
|
||||
@@ -94,12 +94,12 @@
|
||||
}
|
||||
|
||||
.pinnedLink {
|
||||
color: var(--text-secondary) !important;
|
||||
color: var(--green) !important;
|
||||
font-weight: bold !important;
|
||||
}
|
||||
|
||||
.announcement {
|
||||
color: var(--text-secondary) !important;
|
||||
color: var(--green) !important;
|
||||
}
|
||||
|
||||
.domain {
|
||||
@@ -171,10 +171,10 @@
|
||||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
.moderator {
|
||||
color: var(--text-secondary) !important;
|
||||
.moderator, .admin, .owner {
|
||||
color: var(--green) !important;
|
||||
}
|
||||
|
||||
.admin, .owner {
|
||||
color: var(--red) !important;
|
||||
.displayName {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
@@ -120,16 +120,20 @@ const Post = ({ post, index }: PostProps) => {
|
||||
)}
|
||||
<p className={styles.tagline}>
|
||||
{t('post_submitted')} {getFormattedTimeAgo(timestamp)} {t('post_by')}{' '}
|
||||
{post?.author?.displayName && (
|
||||
<span className={`${styles.displayName} ${moderatorClass}`}>{post?.author?.displayName} </span>
|
||||
)}
|
||||
<Link className={`${styles.authorAddressWrapper} ${moderatorClass}`} to={`u/${shortAuthorAddress}`} onClick={(e) => e.preventDefault()}>
|
||||
<span className={styles.authorAddressHidden}>u/{post?.author?.shortAddress || shortAuthorAddress}</span>
|
||||
<span className={`${styles.authorAddressVisible} ${authorAddressChanged && styles.authorAddressChanged}`}>u/{shortAuthorAddress}</span>
|
||||
</Link>
|
||||
{(isAuthorOwner || isAuthorAdmin || isAuthorModerator) && (
|
||||
<span>
|
||||
{' '}[
|
||||
<span className={moderatorClass} title={subplebbit?.roles?.[post.author.address]?.role}>
|
||||
{(isAuthorOwner && 'O') || (isAuthorAdmin && 'A') || (isAuthorModerator && 'M')}
|
||||
</span>
|
||||
{' '}
|
||||
[
|
||||
<span className={moderatorClass} title={subplebbit?.roles?.[post.author.address]?.role}>
|
||||
{(isAuthorOwner && 'O') || (isAuthorAdmin && 'A') || (isAuthorModerator && 'M')}
|
||||
</span>
|
||||
]
|
||||
</span>
|
||||
)}
|
||||
@@ -140,11 +144,9 @@ const Post = ({ post, index }: PostProps) => {
|
||||
{' '}
|
||||
p/{subplebbit?.shortAddress || subplebbitAddress}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
{pinned && (
|
||||
<span className={styles.announcement}> - {t('announcement')}</span>
|
||||
</>
|
||||
)}
|
||||
{pinned && <span className={styles.announcement}> - {t('announcement')}</span>}
|
||||
</p>
|
||||
<PostTools cid={cid} failed={state === 'failed'} replyCount={totalReplyCount} subplebbitAddress={subplebbitAddress} />
|
||||
</div>
|
||||
|
||||
@@ -125,10 +125,6 @@
|
||||
color: var(--text-info);
|
||||
}
|
||||
|
||||
.moderator {
|
||||
color: var(--text-secondary) !important;
|
||||
}
|
||||
|
||||
.admin, .owner {
|
||||
color: var(--red) !important;
|
||||
.moderator, .admin, .owner {
|
||||
color: var(--green) !important;
|
||||
}
|
||||
@@ -71,7 +71,7 @@ const ReplyMedia = ({ commentMediaInfo, content, expanded, hasThumbnail, link, l
|
||||
|
||||
const Reply = ({ reply, depth }: ReplyProps) => {
|
||||
const { cid, content, downvoteCount, flair, link, linkHeight, linkWidth, removed, spoiler, subplebbitAddress, timestamp, upvoteCount } = reply || {};
|
||||
const subplebbit = useSubplebbit({subplebbitAddress});
|
||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||
|
||||
const isAuthorOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
|
||||
const isAuthorAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
|
||||
@@ -147,6 +147,9 @@ const Reply = ({ reply, depth }: ReplyProps) => {
|
||||
<div className={styles.entry}>
|
||||
<p className={styles.tagline}>
|
||||
<span className={styles.expand}>[–]</span>
|
||||
{reply?.author?.displayName && (
|
||||
<span className={`${styles.author} ${moderatorClass}`}>{reply?.author?.displayName} </span>
|
||||
)}
|
||||
<Link
|
||||
to={`/u/${shortAuthorAddress}`}
|
||||
onClick={(e) => {
|
||||
@@ -154,14 +157,14 @@ const Reply = ({ reply, depth }: ReplyProps) => {
|
||||
}}
|
||||
className={`${styles.author} ${moderatorClass}`}
|
||||
>
|
||||
{shortAuthorAddress}
|
||||
{reply?.author?.displayName ? `u/${shortAuthorAddress}` : shortAuthorAddress}
|
||||
</Link>
|
||||
{(isAuthorOwner || isAuthorAdmin || isAuthorModerator) && (
|
||||
<span className={styles.moderatorBrackets}>
|
||||
[
|
||||
<span className={moderatorClass} title={subplebbit?.roles?.[reply.author.address]?.role}>
|
||||
{(isAuthorOwner && 'O') || (isAuthorAdmin && 'A') || (isAuthorModerator && 'M')}
|
||||
</span>
|
||||
<span className={moderatorClass} title={subplebbit?.roles?.[reply.author.address]?.role}>
|
||||
{(isAuthorOwner && 'O') || (isAuthorAdmin && 'A') || (isAuthorModerator && 'M')}
|
||||
</span>
|
||||
]{' '}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -48,11 +48,7 @@ const Sidebar = ({ address, cid, createdAt, description, downvoteCount = 0, role
|
||||
const rulesList = (
|
||||
<div className={styles.rules}>
|
||||
<strong>Rules</strong>
|
||||
<ol className={styles.rulesList}>
|
||||
{rules?.map((rule, index) => (
|
||||
<li key={index}>{rule}</li>
|
||||
))}
|
||||
</ol>
|
||||
<ol className={styles.rulesList}>{rules?.map((rule, index) => <li key={index}>{rule}</li>)}</ol>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
|
||||
.dropdown {
|
||||
float: left;
|
||||
padding-left: 5px;
|
||||
cursor: pointer;
|
||||
display: inline;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.subsDropdown {
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.dropChoices {
|
||||
top: 18px;
|
||||
margin-top: 0;
|
||||
@@ -106,7 +109,7 @@
|
||||
}
|
||||
|
||||
.srList .srBar li .selected {
|
||||
color: var(--text-secondary) !important;
|
||||
color: var(--green) !important;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ const TopBar = () => {
|
||||
return (
|
||||
<div className={styles.headerArea}>
|
||||
<div className={styles.widthClip}>
|
||||
<div className={styles.dropdown} ref={subsDropdownRef} onClick={toggleSubsDropdown}>
|
||||
<div className={`${styles.dropdown} ${styles.subsDropdown}`} ref={subsDropdownRef} onClick={toggleSubsDropdown}>
|
||||
<span className={styles.selectedTitle}>{t('topbar_my_subs')}</span>
|
||||
<div className={`${styles.dropChoices} ${styles.subsDropChoices} ${subsDropdownClass}`} ref={subsDropdownChoicesRef}>
|
||||
{subscriptions?.map((subscription: string, index: number) => (
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
--text-primary: #369;
|
||||
--button-border-primary: #c4dbf1;
|
||||
--button-border-primary-hover: #879eb4;
|
||||
--text-secondary: #228822;
|
||||
--green: #228822;
|
||||
--text-info: #888;
|
||||
--border-primary: #5f99cf;
|
||||
--border-text: gray;
|
||||
@@ -27,13 +27,14 @@
|
||||
--play-button-hover: url("/public/assets/buttons/play-button-hover.png");
|
||||
--close-button: url("/public/assets/buttons/close-button.png");
|
||||
--close-button-hover: url("/public/assets/buttons/close-button-hover.png");
|
||||
--label-pending: goldenrod;
|
||||
--yellow: goldenrod;
|
||||
--red: red;
|
||||
--button-large: url('/public/assets/buttons/button-large.png');
|
||||
--button-large-hover: url('/public/assets/buttons/button-large-hover.png');
|
||||
--button-large-nub: url('/public/assets/buttons/button-large-nub.png');
|
||||
--button-large-hover-nub: url('/public/assets/buttons/button-large-nub-hover.png');
|
||||
--box-shadow: inset 0px 1px 1px rgba(0,0,0,0.3),0px 1px 0px rgba(255,255,255,0.6);
|
||||
--blue-dropdown-arrow: url("/public/assets/buttons/droparrowblue.gif");
|
||||
}
|
||||
|
||||
:root .dark {
|
||||
@@ -51,7 +52,7 @@
|
||||
--text-primary: #c7c7c7;
|
||||
--button-border-primary: #1f1f1f;
|
||||
--button-border-primary-hover: #3e3e3e;
|
||||
--text-secondary: #228822;
|
||||
--green: #228822;
|
||||
--text-info: #757575;
|
||||
--border-primary: #1f1f1f;
|
||||
--border-text: #3e3e3e;
|
||||
@@ -65,11 +66,12 @@
|
||||
--play-button-hover: url("/public/assets/buttons/play-button-hover.png");
|
||||
--close-button: url("/public/assets/buttons/close-button-dark.png");
|
||||
--close-button-hover: url("/public/assets/buttons/close-button-hover.png");
|
||||
--label-pending: rgb(200, 171, 0);
|
||||
--yellow: rgb(200, 171, 0);
|
||||
--red: rgb(200, 0, 0);
|
||||
--button-large: url('/public/assets/buttons/button-large-dark.png');
|
||||
--button-large-hover: url('/public/assets/buttons/button-large-hover-dark.png');
|
||||
--button-large-nub: url('/public/assets/buttons/button-large-nub-dark.png');
|
||||
--button-large-hover-nub: url('/public/assets/buttons/button-large-nub-hover-dark.png');
|
||||
--box-shadow: none;
|
||||
--blue-dropdown-arrow: url("/public/assets/buttons/droparrowgray.gif");
|
||||
}
|
||||
@@ -60,12 +60,22 @@
|
||||
padding-left: 5px;
|
||||
font-style: italic;
|
||||
text-transform: capitalize;
|
||||
color: var(--text-secondary);
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
button {
|
||||
.checkCryptoAddress {
|
||||
margin-top: 5px;
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.categorySettings button {
|
||||
text-transform: capitalize;
|
||||
margin-left: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.categorySettings select {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.accountButtons button {
|
||||
@@ -102,8 +112,8 @@ button {
|
||||
max-height: 60vh;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 35vw !important;
|
||||
.categorySettings input {
|
||||
width: 35vw;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,4 +123,16 @@ button {
|
||||
position: relative;
|
||||
bottom: 2px;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
.resolvedMessageSuccess {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.resolvedMessageFailed {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.resolvedMessageResolving {
|
||||
color: var(--yellow);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { createAccount, deleteAccount, importAccount, setAccount, setActiveAccount, useAccount, useAccounts } from '@plebbit/plebbit-react-hooks';
|
||||
import { createAccount, deleteAccount, importAccount, setAccount, setActiveAccount, useAccount, useAccounts, useResolvedAuthorAddress } from '@plebbit/plebbit-react-hooks';
|
||||
import stringify from 'json-stringify-pretty-compact';
|
||||
import useTheme from '../../hooks/use-theme';
|
||||
import styles from './settings.module.css';
|
||||
@@ -44,31 +44,120 @@ const ThemeSettings = () => {
|
||||
};
|
||||
|
||||
const ProfileSettings = () => {
|
||||
const cryptoAddressInfo = () => {
|
||||
alert('A crypto address is more readable than a long string of characters. It can be used to send you crypto directly.\n\nChange your account address to an ENS name you own: in your ENS name page on ens.domains, click on "Records", "Edit Records", "Add record", add "plebbit-author-address" as record name, add your full address as value (you can copy it from your account data) and save.');
|
||||
const account = useAccount();
|
||||
|
||||
const [username, setUsername] = useState(account?.author.displayName || '');
|
||||
const [savedUsername, setSavedUsername] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (savedUsername) {
|
||||
setTimeout(() => {
|
||||
setSavedUsername(false);
|
||||
}, 2000);
|
||||
}
|
||||
}, [savedUsername]);
|
||||
|
||||
const saveUsername = async () => {
|
||||
try {
|
||||
await setAccount({ ...account, author: { ...account?.author, displayName: username } });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message);
|
||||
console.log(error);
|
||||
} else {
|
||||
console.error('An unknown error occurred:', error);
|
||||
}
|
||||
}
|
||||
setSavedUsername(true);
|
||||
};
|
||||
|
||||
const [cryptoAddress, setCryptoAddress] = useState(account?.author.displayName || '');
|
||||
const [savedCryptoAddress, setSavedCryptoAddress] = useState(false);
|
||||
const [checkCryptoAddress, setCheckCryptoAddress] = useState(false);
|
||||
const author = { ...account?.author, address: cryptoAddress };
|
||||
const { state, error, chainProvider } = useResolvedAuthorAddress({ author, cache: false });
|
||||
const resolvedAddressInfoMessageClass = `${state === 'succeeded' ? styles.resolvedMessageSuccess : state === 'failed' ? styles.resolvedMessageFailed : state === 'resolving' ? styles.resolvedMessageResolving : ''}`
|
||||
|
||||
const resolvedAddressInfoMessage = useMemo(() => {
|
||||
if (state === 'succeeded') {
|
||||
return 'crypto address resolved successfully';
|
||||
} else if (state === 'failed') {
|
||||
if (error instanceof Error) {
|
||||
return `failed to resolve crypto address, ${error.message}`;
|
||||
} else {
|
||||
return 'cannot resolve crypto address';
|
||||
}
|
||||
} else if (state === 'resolving') {
|
||||
return `resolving from ${chainProvider?.urls}`;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}, [state, error, chainProvider]);
|
||||
|
||||
const cryptoAddressInfo = () => {
|
||||
alert(
|
||||
'Change your account address to an ENS name you own: in your ENS name page on ens.domains, click on "Records", "Edit Records", "Add record", add "plebbit-author-address" as record name, add your full address as value (you can copy it from your account data) and save.',
|
||||
);
|
||||
};
|
||||
|
||||
const saveCryptoAddress = async () => {
|
||||
if (state !== 'succeeded') {
|
||||
alert('Cannot save crypto address, it is not resolved');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await setAccount({ ...account, author: { ...account?.author, address: cryptoAddress } });
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message);
|
||||
console.log(error);
|
||||
} else {
|
||||
console.error('An unknown error occurred:', error);
|
||||
}
|
||||
}
|
||||
setSavedCryptoAddress(true);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (savedCryptoAddress) {
|
||||
setTimeout(() => {
|
||||
setSavedCryptoAddress(false);
|
||||
}, 2000);
|
||||
}
|
||||
}, [savedCryptoAddress]);
|
||||
|
||||
return (
|
||||
<span className={styles.categorySettings}>
|
||||
<span className={styles.settingTitle}>username</span>
|
||||
<span className={styles.settingTitle}>display name</span>
|
||||
<div className={styles.usernameInput}>
|
||||
<input type='text' placeholder='My Name' />
|
||||
<button className={styles.button}>save</button>
|
||||
<span className={styles.saved}>Saved.</span>
|
||||
<input type='text' placeholder='My Name' value={username} onChange={(e) => setUsername(e.target.value)} />
|
||||
<button className={styles.button} onClick={saveUsername}>
|
||||
save
|
||||
</button>
|
||||
{savedUsername && <span className={styles.saved}>Saved.</span>}
|
||||
</div>
|
||||
<div className={styles.cryptoAddressSetting}>
|
||||
<span className={styles.settingTitle}>crypto address</span>
|
||||
<button className={styles.infoButton} onClick={cryptoAddressInfo}>?</button>
|
||||
<button className={styles.infoButton} onClick={cryptoAddressInfo}>
|
||||
?
|
||||
</button>
|
||||
<div className={styles.usernameInput}>
|
||||
<input type='text' placeholder='address.eth' />
|
||||
<button className={styles.button}>save</button>
|
||||
<button className={styles.button}>check</button>
|
||||
<span className={styles.saved}>Saved.</span>
|
||||
<input type='text' placeholder='address.eth' onChange={(e) => setCryptoAddress(e.target.value)} />
|
||||
<button className={styles.button} onClick={saveCryptoAddress}>save</button>
|
||||
{savedCryptoAddress && <span className={styles.saved}>Saved.</span>}
|
||||
</div>
|
||||
<div className={styles.checkCryptoAddress}>
|
||||
<button className={styles.button} onClick={() => setCheckCryptoAddress(true)}>check</button>{' '}
|
||||
{checkCryptoAddress ? (
|
||||
<span className={resolvedAddressInfoMessageClass}>{resolvedAddressInfoMessage}</span>
|
||||
) : 'if the crypto address is resolved p2p'}
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const AccountSettings = () => {
|
||||
const account = useAccount();
|
||||
@@ -76,17 +165,17 @@ const AccountSettings = () => {
|
||||
const [text, setText] = useState('');
|
||||
const [switchToLastAccount, setSwitchToLastAccount] = useState(false);
|
||||
|
||||
const accountJson = useMemo(() => stringify({account: {...account, plebbit: undefined, karma: undefined, unreadNotificationCount: undefined}}), [account])
|
||||
const accountJson = useMemo(() => stringify({ account: { ...account, plebbit: undefined, karma: undefined, unreadNotificationCount: undefined } }), [account]);
|
||||
|
||||
const accountsOptions = accounts.map((account) => (
|
||||
<option key={account?.id} value={account?.name}>
|
||||
u/{account?.author?.shortAddress?.toLowerCase?.().substring(0, 8) || ''}
|
||||
u/{account?.author?.shortAddress}
|
||||
</option>
|
||||
));
|
||||
|
||||
useEffect(() => {
|
||||
setText(accountJson)
|
||||
}, [accountJson])
|
||||
setText(accountJson);
|
||||
}, [accountJson]);
|
||||
|
||||
useEffect(() => {
|
||||
if (switchToLastAccount && accounts.length > 0) {
|
||||
@@ -108,25 +197,25 @@ const AccountSettings = () => {
|
||||
}
|
||||
}
|
||||
setSwitchToLastAccount(true);
|
||||
}
|
||||
};
|
||||
|
||||
const _deleteAccount = (accountName: string) => {
|
||||
if (!accountName) {
|
||||
return
|
||||
return;
|
||||
} else if (window.confirm(`Are you sure you want to delete ${accountName}?`)) {
|
||||
deleteAccount(accountName);
|
||||
setSwitchToLastAccount(true);
|
||||
} else {
|
||||
return
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const saveAccount = async () => {
|
||||
try {
|
||||
const newAccount = JSON.parse(text).account
|
||||
const newAccount = JSON.parse(text).account;
|
||||
// force keeping the same id, makes it easier to copy paste
|
||||
await setAccount({...newAccount, id: account?.id})
|
||||
alert(`Saved ${newAccount.name}`)
|
||||
await setAccount({ ...newAccount, id: account?.id });
|
||||
alert(`Saved ${newAccount.name}`);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message);
|
||||
@@ -135,14 +224,14 @@ const AccountSettings = () => {
|
||||
console.error('An unknown error occurred:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _importAccount = async () => {
|
||||
try {
|
||||
const newAccount = JSON.parse(text)
|
||||
await importAccount(text)
|
||||
const newAccount = JSON.parse(text);
|
||||
await importAccount(text);
|
||||
setSwitchToLastAccount(true);
|
||||
alert(`Imported ${newAccount.account?.name}`)
|
||||
alert(`Imported ${newAccount.account?.name}`);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
alert(error.message);
|
||||
@@ -151,16 +240,19 @@ const AccountSettings = () => {
|
||||
console.error('An unknown error occurred:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<span className={styles.categorySettings}>
|
||||
<div className={styles.accountAddress}>
|
||||
<select value={account?.name} onChange={(e) => setActiveAccount(e.target.value)}>{accountsOptions}</select> is the current account
|
||||
<select value={account?.name} onChange={(e) => setActiveAccount(e.target.value)}>
|
||||
{accountsOptions}
|
||||
</select>{' '}
|
||||
is the current account
|
||||
</div>
|
||||
<span className={styles.settingTitle}>account data</span>
|
||||
<div className={styles.accountData}>
|
||||
<textarea className={styles.textarea} value={text} onChange={(e) => setText(e.target.value)} autoCorrect="off" autoComplete='off' spellCheck='false' />
|
||||
<textarea className={styles.textarea} value={text} onChange={(e) => setText(e.target.value)} autoCorrect='off' autoComplete='off' spellCheck='false' />
|
||||
<div className={styles.accountButtons}>
|
||||
<div>
|
||||
<button onClick={saveAccount}>Save</button> or <button onClick={() => setText(accountJson)}>Reset</button> changes
|
||||
@@ -169,7 +261,7 @@ const AccountSettings = () => {
|
||||
<button onClick={() => _deleteAccount(account?.name)}>Delete</button> this account
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={_importAccount}>Import</button> another account by pasting its data above
|
||||
<button onClick={_importAccount}>Import</button> other account data
|
||||
</div>
|
||||
<div>
|
||||
<button onClick={_createAccount}>Create</button> a new account
|
||||
|
||||
Reference in New Issue
Block a user