Merge pull request #280 from plebbit/development

Development
This commit is contained in:
plebeius.eth
2023-09-30 21:57:59 +02:00
committed by GitHub
21 changed files with 813 additions and 468 deletions
+142 -189
View File
@@ -28,209 +28,162 @@ import packageJson from '../package.json';
const commitRef = process?.env?.REACT_APP_COMMIT_REF || ''; const commitRef = process?.env?.REACT_APP_COMMIT_REF || '';
export default function App() { export default function App() {
const { const { bodyStyle, setBodyStyle, setDefaultSubplebbits, isCaptchaOpen, setIsCaptchaOpen, setIsSettingsOpen, selectedStyle, setShowPostForm, setShowPostFormLink } =
bodyStyle, useGeneralStore((state) => state);
setBodyStyle,
setDefaultSubplebbits,
isCaptchaOpen,
setIsCaptchaOpen,
setIsSettingsOpen,
selectedStyle,
setSelectedStyle,
setShowPostForm,
setShowPostFormLink,
} = useGeneralStore((state) => state);
const location = useLocation(); const location = useLocation();
const isHomeRoute = location.pathname === '/'; const isElectron = window.electron && window.electron.isElectron;
const isElectron = window.electron && window.electron.isElectron;
const [, setNewErrorMessage] = useError(); const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess(); const [, setNewSuccessMessage] = useSuccess();
const [, setNewInfoMessage] = useInfo(); const [, setNewInfoMessage] = useInfo();
const [infoMessageShown, setInfoMessageShown] = useState(false); const [infoMessageShown, setInfoMessageShown] = useState(false);
useEffect(() => { useEffect(() => {
const successToast = localStorage.getItem('successToast'); const successToast = localStorage.getItem('successToast');
const errorToast = localStorage.getItem('errorToast'); const errorToast = localStorage.getItem('errorToast');
if (successToast) { if (successToast) {
setNewSuccessMessage(successToast); setNewSuccessMessage(successToast);
localStorage.removeItem('successToast'); localStorage.removeItem('successToast');
} else if (errorToast) { } else if (errorToast) {
setNewErrorMessage(errorToast); setNewErrorMessage(errorToast);
localStorage.removeItem('errorToast'); localStorage.removeItem('errorToast');
} else { } else {
return; return;
} }
}, [setNewErrorMessage, setNewSuccessMessage]); }, [setNewErrorMessage, setNewSuccessMessage]);
// check for new version // check for new version
// TODO: delete this code and toast when v1.0.0 is released // TODO: delete this code and toast when v1.0.0 is released
useEffect(() => { useEffect(() => {
const fetchVersionInfo = async () => { const fetchVersionInfo = async () => {
try { try {
const packageRes = await fetch('https://raw.githubusercontent.com/plebbit/plebchan/master/package.json', { cache: 'no-cache' }); const packageRes = await fetch('https://raw.githubusercontent.com/plebbit/plebchan/master/package.json', { cache: 'no-cache' });
const packageData = await packageRes.json(); const packageData = await packageRes.json();
if (packageJson.version !== packageData.version && !infoMessageShown) { if (packageJson.version !== packageData.version && !infoMessageShown) {
const newVersionInfo = isElectron const newVersionInfo = isElectron
? `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Download the latest version here: https://github.com/plebbit/plebchan/releases/latest` ? `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Download the latest version here: https://github.com/plebbit/plebchan/releases/latest`
: `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Refresh to update.`; : `New version available, plebchan v${packageData.version}. You are using v${packageJson.version}. Refresh to update.`;
setNewInfoMessage(newVersionInfo); setNewInfoMessage(newVersionInfo);
setInfoMessageShown(true); setInfoMessageShown(true);
} }
if (commitRef.length > 0) { if (commitRef.length > 0) {
const commitRes = await fetch('https://api.github.com/repos/plebbit/plebchan/commits?per_page=1&sha=development', { cache: 'no-cache' }); const commitRes = await fetch('https://api.github.com/repos/plebbit/plebchan/commits?per_page=1&sha=development', { cache: 'no-cache' });
const commitData = await commitRes.json(); const commitData = await commitRes.json();
const latestCommitHash = commitData[0].sha; const latestCommitHash = commitData[0].sha;
if (latestCommitHash.trim() !== commitRef.trim() && !infoMessageShown) { if (latestCommitHash.trim() !== commitRef.trim() && !infoMessageShown) {
const newVersionInfo = `New dev version available, commit ${latestCommitHash.slice(0, 7)}. You are using commit ${commitRef.slice(0, 7)}. Refresh to update.`; const newVersionInfo = `New dev version available, commit ${latestCommitHash.slice(0, 7)}. You are using commit ${commitRef.slice(0, 7)}. Refresh to update.`;
setNewInfoMessage(newVersionInfo); setNewInfoMessage(newVersionInfo);
setInfoMessageShown(true); setInfoMessageShown(true);
} }
} }
} catch (error) { } catch (error) {
console.error('Failed to fetch latest version info:', error); console.error('Failed to fetch latest version info:', error);
} }
}; };
fetchVersionInfo(); fetchVersionInfo();
}, [setNewInfoMessage, isElectron, infoMessageShown]); }, [setNewInfoMessage, isElectron, infoMessageShown]);
// preload banners // preload banners
useEffect(() => { useEffect(() => {
const loadImages = async () => { const loadImages = async () => {
const images = await importAll(require.context('../public/assets', true, /\.(png|jpe?g|svg)$/)); const images = await importAll(require.context('../public/assets', true, /\.(png|jpe?g|svg)$/));
const imageUrls = images.map((image) => image.default); const imageUrls = images.map((image) => image.default);
preloadImages(imageUrls); preloadImages(imageUrls);
}; };
loadImages(); loadImages();
}, []); }, []);
// automatic dark mode without interefering with user's selected style // fetch default subplebbits
useEffect(() => { useEffect(() => {
if (isHomeRoute) return; let didCancel = false;
fetch('https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/subplebbits.json', { cache: 'no-cache' })
.then((res) => res.json())
.then((res) => {
if (!didCancel) {
setDefaultSubplebbits(res);
}
});
return () => {
didCancel = true;
};
}, [setDefaultSubplebbits]);
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); // handle nested routes
const isDarkMode = darkModeMediaQuery.matches; useEffect(() => {
const path = location.pathname;
if (path.endsWith('/post')) {
setShowPostFormLink(false);
setShowPostForm(true);
} else {
setShowPostFormLink(true);
setShowPostForm(false);
}
if (isDarkMode && !isHomeRoute) { if (path.endsWith('/settings')) {
setSelectedStyle('Tomorrow'); setIsSettingsOpen(true);
setBodyStyle({ } else {
background: '#1d1f21 none', setIsSettingsOpen(false);
color: '#c5c8c6', }
fontFamily: 'Arial, Helvetica, sans-serif', }, [location.pathname, setIsSettingsOpen, setShowPostForm, setShowPostFormLink]);
});
localStorage.setItem('selectedStyle', 'Tomorrow');
}
const darkModeListener = (e) => { return (
if (e.matches && !isHomeRoute) { <div>
setSelectedStyle('Tomorrow'); <Helmet>
setBodyStyle({ <link rel='apple-touch-icon' sizes='180x180' href='assets/logo/apple-touch-icon.png' />
background: '#1d1f21 none', <link rel='icon' type='image/png' sizes='32x32' href='assets/logo/favicon-32x32.png' />
color: '#c5c8c6', <link rel='icon' type='image/png' sizes='16x16' href='assets/logo/favicon-16x16.png' />
fontFamily: 'Arial, Helvetica, sans-serif', <link rel='manifest' href='site.webmanifest' />
}); <meta name='msapplication-TileColor' content='#fee9cd' />
localStorage.setItem('selectedStyle', 'Tomorrow'); <meta name='theme-color' content='#ffffff' />
} </Helmet>
}; <GlobalStyle background={bodyStyle.background} color={bodyStyle.color} fontFamily={bodyStyle.fontFamily} />
<Routes>
darkModeMediaQuery.addEventListener('change', darkModeListener); <Route exact path='/' element={<Home setBodyStyle={setBodyStyle} />} />
<Route path={`/p/:subplebbitAddress`} element={<Board setBodyStyle={setBodyStyle} />}>
return () => { <Route path='post' element={<Board />} />
darkModeMediaQuery.removeEventListener('change', darkModeListener); <Route path='settings' element={<Board />} />
}; </Route>
}, [isHomeRoute, setBodyStyle, setSelectedStyle]); <Route path={`/p/:subplebbitAddress/c/:threadCid`} element={<Thread setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Thread />} />
// fetch default subplebbits <Route path='settings' element={<Thread />} />
useEffect(() => { </Route>
let didCancel = false; <Route path={`/p/:subplebbitAddress/catalog`} element={<Catalog setBodyStyle={setBodyStyle} />}>
fetch('https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/subplebbits.json', { cache: 'no-cache' }) <Route path='post' element={<Catalog />} />
.then((res) => res.json()) <Route path='settings' element={<Catalog />} />
.then((res) => { </Route>
if (!didCancel) { <Route path={`/p/:subplebbitAddress/description`} element={<Description setBodyStyle={setBodyStyle} />}>
setDefaultSubplebbits(res); <Route path='settings' element={<Description />} />
} </Route>
}); <Route path={`/p/:subplebbitAddress/rules`} element={<Rules setBodyStyle={setBodyStyle} />}>
return () => { <Route path='settings' element={<Rules />} />
didCancel = true; </Route>
}; <Route path={`/profile/c/:index`} element={<Pending setBodyStyle={setBodyStyle} />}>
}, [setDefaultSubplebbits]); <Route path='settings' element={<Pending />} />
</Route>
// handle nested routes <Route path={`/p/subscriptions`} element={<Subscriptions setBodyStyle={setBodyStyle} />}>
useEffect(() => { <Route path='settings' element={<Subscriptions />} />
const path = location.pathname; </Route>
if (path.endsWith('/post')) { <Route path={`p/subscriptions/catalog`} element={<SubscriptionsCatalog setBodyStyle={setBodyStyle} />}>
setShowPostFormLink(false); <Route path='settings' element={<SubscriptionsCatalog />} />
setShowPostForm(true); </Route>
} else { <Route path={`p/all`} element={<All setBodyStyle={setBodyStyle} />}>
setShowPostFormLink(true); <Route path='settings' element={<All />} />
setShowPostForm(false); </Route>
} <Route path={`p/all/catalog`} element={<AllCatalog setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<AllCatalog />} />
if (path.endsWith('/settings')) { </Route>
setIsSettingsOpen(true); <Route path='*' element={<NotFound setBodyStyle={setBodyStyle} />} />
} else { </Routes>
setIsSettingsOpen(false); <Toast />
} <CaptchaModal selectedStyle={selectedStyle} isOpen={isCaptchaOpen} closeModal={() => setIsCaptchaOpen(false)} />
}, [location.pathname, setIsSettingsOpen, setShowPostForm, setShowPostFormLink]); </div>
);
return (
<div>
<Helmet>
<link rel='apple-touch-icon' sizes='180x180' href='assets/logo/apple-touch-icon.png' />
<link rel='icon' type='image/png' sizes='32x32' href='assets/logo/favicon-32x32.png' />
<link rel='icon' type='image/png' sizes='16x16' href='assets/logo/favicon-16x16.png' />
<link rel='manifest' href='site.webmanifest' />
<meta name='msapplication-TileColor' content='#fee9cd' />
<meta name='theme-color' content='#ffffff' />
</Helmet>
<GlobalStyle background={bodyStyle.background} color={bodyStyle.color} fontFamily={bodyStyle.fontFamily} />
<Routes>
<Route exact path='/' element={<Home setBodyStyle={setBodyStyle} />} />
<Route path={`/p/:subplebbitAddress`} element={<Board setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Board />} />
<Route path='settings' element={<Board />} />
</Route>
<Route path={`/p/:subplebbitAddress/c/:threadCid`} element={<Thread setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Thread />} />
<Route path='settings' element={<Thread />} />
</Route>
<Route path={`/p/:subplebbitAddress/catalog`} element={<Catalog setBodyStyle={setBodyStyle} />}>
<Route path='post' element={<Catalog />} />
<Route path='settings' element={<Catalog />} />
</Route>
<Route path={`/p/:subplebbitAddress/description`} element={<Description setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Description />} />
</Route>
<Route path={`/p/:subplebbitAddress/rules`} element={<Rules setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Rules />} />
</Route>
<Route path={`/profile/c/:index`} element={<Pending setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Pending />} />
</Route>
<Route path={`/p/subscriptions`} element={<Subscriptions setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<Subscriptions />} />
</Route>
<Route path={`p/subscriptions/catalog`} element={<SubscriptionsCatalog setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<SubscriptionsCatalog />} />
</Route>
<Route path={`p/all`} element={<All setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<All />} />
</Route>
<Route path={`p/all/catalog`} element={<AllCatalog setBodyStyle={setBodyStyle} />}>
<Route path='settings' element={<AllCatalog />} />
</Route>
<Route path='*' element={<NotFound setBodyStyle={setBodyStyle} />} />
</Routes>
<Toast />
<CaptchaModal selectedStyle={selectedStyle} isOpen={isCaptchaOpen} closeModal={() => setIsCaptchaOpen(false)} />
</div>
);
} }
-1
View File
@@ -81,7 +81,6 @@ const Post = ({ content, postQuoteOnClick, postQuoteOnOver, postQuoteOnLeave, po
parts.push( parts.push(
<ForwardRefLink <ForwardRefLink
key={`link-${i}-${matchedText}`}
className='quotelink' className='quotelink'
to={linkTo} to={linkTo}
target={linkTarget} target={linkTarget}
+15 -13
View File
@@ -43,10 +43,8 @@ const AdminListModal = ({ isOpen, closeModal, roles }) => {
maxHeight: '250px', maxHeight: '250px',
}} }}
> >
<button className='icon' onClick={() => closeModal()} title='close' /> <button className='icon' style={{ imageRendering: 'pixelated', margin: '1px 1px 0 0' }} onClick={() => closeModal()} title='close' />
<div className='modal-header' style={{ margin: '10px 10px 0px 10px' }}> <div className='modal-header'>   Moderators</div>
Moderators
</div>
<div <div
className='list' className='list'
style={{ style={{
@@ -60,15 +58,19 @@ const AdminListModal = ({ isOpen, closeModal, roles }) => {
}} }}
> >
<BoardForm selectedStyle={selectedStyle} style={{ all: 'unset' }}> <BoardForm selectedStyle={selectedStyle} style={{ all: 'unset' }}>
{rolesList.map(({ address, role }, index) => ( {roles ? (
<p key={index}> rolesList.map(({ address, role }, index) => (
{' '} <p key={index}>
<Link to={() => {}} className='quote-link'> {' '}
u/{address} <Link to={() => {}} className='quote-link'>
</Link> u/{address}
: {role} </Link>
</p> : {role}
))} </p>
))
) : (
<p>This board doesn't have moderators yet.</p>
)}
</BoardForm> </BoardForm>
</div> </div>
</div> </div>
@@ -2,94 +2,95 @@ import styled from 'styled-components';
import Modal from 'react-modal'; import Modal from 'react-modal';
export const StyledModal = styled(Modal)` export const StyledModal = styled(Modal)`
.hide-modal-overlay { .hide-modal-overlay {
display: none; display: none;
} }
.modal-content { .modal-content {
position: fixed; position: fixed;
top: calc(50% - 150px); top: calc(50% - 150px);
left: calc(50% - 150px); left: calc(50% - 150px);
display: block; display: block;
padding: 2px; padding: 2px;
font-size: 10pt; font-size: 10pt;
border-left: none; border-left: none;
border-top: none; border-top: none;
} }
.modal-header { .modal-header {
font-size: 10pt; font-size: 10pt;
text-align: center; text-align: center;
margin-bottom: 1px; margin-bottom: 1px;
padding: 0; padding: 0;
height: 18px; height: 18px;
line-height: 18px; line-height: 18px;
cursor: move; cursor: move;
font-weight: 700; font-weight: 700;
} }
.icon { .icon {
all: unset; all: unset;
float: right; float: right;
cursor: pointer; cursor: pointer;
margin-bottom: -4px; margin-bottom: -4px;
width: 18px; width: 18px;
height: 18px; height: 18px;
border: none; border: none;
} image-rendering: pixelated;
}
#field { #field {
border: 1px solid #aaa; border: 1px solid #aaa;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
font-size: 10pt; font-size: 10pt;
outline: medium none; outline: medium none;
width: 298px; width: 298px;
padding: 2px; padding: 2px;
} }
textarea { textarea {
min-width: 296px; min-width: 296px;
float: left; float: left;
font-size: 10pt; font-size: 10pt;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
} }
#captcha-container { #captcha-container {
position: relative; position: relative;
width: 302px; width: 302px;
height: 100px; height: 100px;
overflow: hidden; overflow: hidden;
margin-bottom: 17px; margin-bottom: 17px;
} }
#response { #response {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
font-size: 11px; font-size: 11px;
height: 18px; height: 18px;
margin: 0px; margin: 0px;
padding: 0px 2px; padding: 0px 2px;
font-family: monospace; font-family: monospace;
vertical-align: middle; vertical-align: middle;
} }
img { img {
height: 100%; height: 100%;
width: 100%; width: 100%;
position: relative; position: relative;
display: block; display: block;
} }
#nav { #nav {
float: right; float: right;
margin: 0; margin: 0;
width: auto; width: auto;
} }
${({ selectedStyle }) => { ${({ selectedStyle }) => {
switch (selectedStyle) { switch (selectedStyle) {
case 'Yotsuba': case 'Yotsuba':
return ` return `
.modal-content { .modal-content {
background-color: #f0e0d6; background-color: #f0e0d6;
border: 1px solid #d9bfb7; border: 1px solid #d9bfb7;
@@ -109,8 +110,8 @@ export const StyledModal = styled(Modal)`
color: maroon; color: maroon;
}`; }`;
case 'Yotsuba-B': case 'Yotsuba-B':
return ` return `
.modal-content { .modal-content {
background-color: #d6daf0; background-color: #d6daf0;
border: 1px solid #b7c5d9; border: 1px solid #b7c5d9;
@@ -130,8 +131,8 @@ export const StyledModal = styled(Modal)`
color: #000; color: #000;
}`; }`;
case 'Futaba': case 'Futaba':
return ` return `
.modal-content { .modal-content {
background-color: #f0e0d6; background-color: #f0e0d6;
border: 1px solid #d9bfb7; border: 1px solid #d9bfb7;
@@ -151,8 +152,8 @@ export const StyledModal = styled(Modal)`
color: maroon; color: maroon;
}`; }`;
case 'Burichan': case 'Burichan':
return ` return `
.modal-content { .modal-content {
background-color: #d6daf0; background-color: #d6daf0;
border: 1px solid #b7c5d9; border: 1px solid #b7c5d9;
@@ -172,8 +173,8 @@ export const StyledModal = styled(Modal)`
color: #000; color: #000;
}`; }`;
case 'Tomorrow': case 'Tomorrow':
return ` return `
.modal-content { .modal-content {
background-color: #282a2e; background-color: #282a2e;
border: 1px solid #111; border: 1px solid #111;
@@ -216,8 +217,8 @@ export const StyledModal = styled(Modal)`
filter: brightness(80%); filter: brightness(80%);
}`; }`;
case 'Photon': case 'Photon':
return ` return `
.modal-content { .modal-content {
background-color: #ddd; background-color: #ddd;
border: 1px solid #ccc; border: 1px solid #ccc;
@@ -236,8 +237,8 @@ export const StyledModal = styled(Modal)`
color: #333; color: #333;
}`; }`;
default: default:
return ''; return '';
} }
}} }}
`; `;
@@ -1,5 +1,5 @@
import styled from "styled-components"; import styled from 'styled-components';
import Modal from "react-modal"; import Modal from 'react-modal';
export const StyledModal = styled(Modal)` export const StyledModal = styled(Modal)`
.modal-content { .modal-content {
@@ -9,10 +9,10 @@ export const StyledModal = styled(Modal)`
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
width: 450px; width: 450px;
height: auto; height: auto;
max-height: calc(100vh - 2*50px); max-height: calc(100vh - 2 * 50px);
overflow-y: auto; overflow-y: auto;
padding: 5px; padding: 5px;
box-shadow: 0 0 5px rgba(0, 0, 0, .25); box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
} }
.modal-header { .modal-header {
@@ -33,9 +33,12 @@ export const StyledModal = styled(Modal)`
width: 18px; width: 18px;
height: 18px; height: 18px;
border: none; border: none;
image-rendering: pixelated;
} }
#name, #description, #rule { #name,
#description,
#rule {
border: 1px solid #aaa; border: 1px solid #aaa;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
font-size: 10pt; font-size: 10pt;
@@ -73,7 +76,6 @@ export const StyledModal = styled(Modal)`
} }
#rule { #rule {
} }
#rule-btn { #rule-btn {
@@ -326,8 +328,8 @@ export const StyledModal = styled(Modal)`
color: #000; color: #000;
}`; }`;
default: default:
return ''; return '';
} }
}} }}
`; `;
@@ -1,4 +1,4 @@
import styled from "styled-components"; import styled from 'styled-components';
import Modal from 'react-modal'; import Modal from 'react-modal';
export const StyledModal = styled(Modal)` export const StyledModal = styled(Modal)`
@@ -13,7 +13,7 @@ export const StyledModal = styled(Modal)`
position: absolute; position: absolute;
padding: 2px 5px 5px; padding: 2px 5px 5px;
font-size: 14px; font-size: 14px;
box-shadow: 0 0 5px rgba(0, 0, 0, .25); box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
@media (max-width: 480px) { @media (max-width: 480px) {
width: 320px !important; width: 320px !important;
@@ -32,7 +32,7 @@ export const StyledModal = styled(Modal)`
position: absolute; position: absolute;
padding: 2px 5px 5px; padding: 2px 5px 5px;
font-size: 14px; font-size: 14px;
box-shadow: 0 0 5px rgba(0, 0, 0, .25); box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
@media (max-width: 800px) { @media (max-width: 800px) {
width: 80%; width: 80%;
@@ -66,6 +66,7 @@ export const StyledModal = styled(Modal)`
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
top: 5px; top: 5px;
image-rendering: pixelated;
} }
h4 { h4 {
@@ -171,7 +172,8 @@ export const StyledModal = styled(Modal)`
margin-bottom: 10px; margin-bottom: 10px;
} }
#save-board-settings, #reset-board-settings { #save-board-settings,
#reset-board-settings {
text-align: center; text-align: center;
} }
@@ -184,7 +186,7 @@ export const StyledModal = styled(Modal)`
} }
.settings-info strong { .settings-info strong {
margin-bottom: 10px; margin-bottom: 10px;
} }
${({ selectedStyle }) => { ${({ selectedStyle }) => {
@@ -379,8 +381,8 @@ export const StyledModal = styled(Modal)`
} }
}`; }`;
default: default:
return ''; return '';
} }
}} }}
`; `;
@@ -1,5 +1,5 @@
import styled from "styled-components"; import styled from 'styled-components';
import Modal from "react-modal"; import Modal from 'react-modal';
export const StyledModal = styled(Modal)` export const StyledModal = styled(Modal)`
.modal-content { .modal-content {
@@ -32,6 +32,7 @@ export const StyledModal = styled(Modal)`
width: 18px; width: 18px;
height: 18px; height: 18px;
border: none; border: none;
image-rendering: pixelated;
} }
#name { #name {
@@ -251,8 +252,8 @@ export const StyledModal = styled(Modal)`
color: #000; color: #000;
}`; }`;
default: default:
return ''; return '';
} }
}} }}
`; `;
@@ -50,6 +50,7 @@ export const StyledModal = styled(Modal)`
cursor: pointer; cursor: pointer;
position: absolute; position: absolute;
top: 5px; top: 5px;
image-rendering: pixelated;
} }
h4 { h4 {
@@ -80,6 +81,7 @@ export const StyledModal = styled(Modal)`
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
display: inline-block; display: inline-block;
image-rendering: pixelated;
} }
.settings-cat { .settings-cat {
+72 -4
View File
@@ -1698,10 +1698,6 @@ export const BoardForm = styled.div`
margin-right: 14px; margin-right: 14px;
} }
.capcode-admin {
color: red !important;
}
.ellipsis:after { .ellipsis:after {
content: '\\2026'; content: '\\2026';
position: absolute; position: absolute;
@@ -1811,6 +1807,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
#post-menu { #post-menu {
@@ -1838,6 +1840,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
#post-menu { #post-menu {
@@ -1862,6 +1870,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
#post-menu { #post-menu {
@@ -1886,6 +1900,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
#post-menu { #post-menu {
@@ -1911,6 +1931,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: #81a2be !important; color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
} }
#post-menu { #post-menu {
@@ -1935,6 +1961,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: #f60 !important; color: #f60 !important;
cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
} }
#post-menu { #post-menu {
@@ -3367,6 +3399,12 @@ export const BoardForm = styled.div`
return ` return `
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
.op-container { .op-container {
background-color: #f5e9e1; background-color: #f5e9e1;
@@ -3487,6 +3525,12 @@ export const BoardForm = styled.div`
return ` return `
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
.op-container { .op-container {
background-color: #d6daf0; background-color: #d6daf0;
@@ -3603,6 +3647,12 @@ export const BoardForm = styled.div`
return ` return `
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
.op-container { .op-container {
background-color: #f5e9e1; background-color: #f5e9e1;
@@ -3722,6 +3772,12 @@ export const BoardForm = styled.div`
return ` return `
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
.op-container { .op-container {
background-color: #d6daf0; background-color: #d6daf0;
@@ -3837,6 +3893,12 @@ export const BoardForm = styled.div`
return ` return `
.capcode { .capcode {
color: #81a2be !important; color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
} }
.op-container { .op-container {
@@ -3963,6 +4025,12 @@ export const BoardForm = styled.div`
return ` return `
.capcode { .capcode {
color: #f60 !important; color: #f60 !important;
cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
} }
.op-container { .op-container {
background-color: #eee; background-color: #eee;
+33 -16
View File
@@ -17,12 +17,14 @@ export const Threads = styled.div`
padding: 5px 0 3px; padding: 5px 0 3px;
} }
video, audio, img { video,
audio,
img {
max-width: 150px; max-width: 150px;
max-height: 150px; max-height: 150px;
} }
.file-thumb { .file-thumb {
background-color: rgba(0, 0, 0, 0.05); background-color: rgba(0, 0, 0, 0.05);
display: inline-flex; display: inline-flex;
justify-content: center; justify-content: center;
@@ -31,8 +33,8 @@ export const Threads = styled.div`
} }
.card { .card {
box-shadow: 0 0 5px rgba(0, 0, 0, .25); box-shadow: 0 0 5px rgba(0, 0, 0, 0.25);
border: 0; border: 0;
} }
.thread-icons { .thread-icons {
@@ -64,7 +66,7 @@ export const Threads = styled.div`
} }
.offline-icon-no-link-hovered { .offline-icon-no-link-hovered {
transform: translate(16px,0); transform: translate(16px, 0);
} }
.sticky-icon { .sticky-icon {
background-image: url(assets/sticky.gif); background-image: url(assets/sticky.gif);
@@ -94,7 +96,6 @@ export const Threads = styled.div`
word-wrap: break-word; word-wrap: break-word;
} }
${({ selectedStyle }) => { ${({ selectedStyle }) => {
switch (selectedStyle) { switch (selectedStyle) {
case 'Yotsuba': case 'Yotsuba':
@@ -155,7 +156,6 @@ export const PostPreview = styled.div`
font-weight: 700; font-weight: 700;
} }
${({ selectedStyle }) => { ${({ selectedStyle }) => {
switch (selectedStyle) { switch (selectedStyle) {
case 'Yotsuba': case 'Yotsuba':
@@ -284,9 +284,27 @@ export const PostMenuCatalog = styled.div`
${({ selectedStyle }) => { ${({ selectedStyle }) => {
switch (selectedStyle) { switch (selectedStyle) {
case 'Yotsuba': case 'Yotsuba':
return `.post-subject{ return `.highlighted, .highlighted-click, .highlighted-address {
color:red; background-color: #f0c0b0 !important;
}`; border: 1px solid #d9bfb7 !important;
border-left: none !important;
border-top: none !important;
}
.post-menu-catalog {
border-right: 1px solid #d9bfb7;
border-bottom: 2px solid #d9bfb7;
li {
border: 1px solid #d9bfb7;
background-color: #f0e0d6;
border-bottom: none;
:hover {
background-color: #ffe;
}
}
}`;
case 'Yotsuba-B': case 'Yotsuba-B':
return `.highlighted, .highlighted-click, .highlighted-address { return `.highlighted, .highlighted-click, .highlighted-address {
@@ -395,9 +413,8 @@ export const PostMenuCatalog = styled.div`
} }
}`; }`;
default:
default: return '';
return ''; }
} }}
}}
`; `;
+95 -8
View File
@@ -906,10 +906,6 @@ export const BoardForm = styled.div`
margin-right: 14px; margin-right: 14px;
} }
.capcode-admin {
color: red !important;
}
.ellipsis:after { .ellipsis:after {
content: '\\2026'; content: '\\2026';
position: absolute; position: absolute;
@@ -1002,6 +998,16 @@ export const BoardForm = styled.div`
border-top: none !important; border-top: none !important;
} }
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu { #post-menu {
ul { ul {
background-color: #f0e0d6; background-color: #f0e0d6;
@@ -1027,6 +1033,16 @@ export const BoardForm = styled.div`
border-top: none !important; border-top: none !important;
} }
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu { #post-menu {
ul { ul {
background-color: #d6daf0; background-color: #d6daf0;
@@ -1048,6 +1064,16 @@ export const BoardForm = styled.div`
background-color: #f0c0b0 !important; background-color: #f0c0b0 !important;
} }
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu { #post-menu {
font-size: 13px !important; font-size: 13px !important;
@@ -1071,6 +1097,16 @@ export const BoardForm = styled.div`
background-color: #d6bad0 !important; background-color: #d6bad0 !important;
} }
.capcode {
color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
}
#post-menu { #post-menu {
font-size: 13px !important; font-size: 13px !important;
@@ -1095,6 +1131,16 @@ export const BoardForm = styled.div`
outline: 1px solid #111 !important; outline: 1px solid #111 !important;
} }
.capcode {
color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
}
#post-menu { #post-menu {
ul { ul {
background-color: #282a2e; background-color: #282a2e;
@@ -1117,6 +1163,16 @@ export const BoardForm = styled.div`
outline: 1px solid #ccc !important; outline: 1px solid #ccc !important;
} }
.capcode {
color: #f60 !important;
cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
}
#post-menu { #post-menu {
ul { ul {
background-color: #ddd; background-color: #ddd;
@@ -2506,6 +2562,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
.subject-mobile { .subject-mobile {
@@ -2627,6 +2689,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
.subject-mobile { .subject-mobile {
@@ -2744,11 +2812,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
} }
.subject-mobile { .capcode-admin {
color: #cc1105; color: red !important;
font-weight: 700; cursor: pointer;
} }
.date-time-mobile { .date-time-mobile {
@@ -2864,6 +2933,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: purple !important; color: purple !important;
cursor: pointer;
}
.capcode-admin {
color: red !important;
cursor: pointer;
} }
.subject-mobile { .subject-mobile {
@@ -2980,6 +3055,12 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: #81a2be !important; color: #81a2be !important;
cursor: pointer;
}
.capcode-admin {
color: #81a2be !important;
cursor: pointer;
} }
.poster-address-mobile { .poster-address-mobile {
@@ -3106,7 +3187,13 @@ export const BoardForm = styled.div`
.capcode { .capcode {
color: #f60 !important; color: #f60 !important;
} cursor: pointer;
}
.capcode-admin {
color: #f60 !important;
cursor: pointer;
}
.subject-mobile { .subject-mobile {
color: #111; color: #111;
+65 -17
View File
@@ -119,6 +119,7 @@ const All = () => {
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0); const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
const [deletePost, setDeletePost] = useState(false); const [deletePost, setDeletePost] = useState(false);
const [moderatorPermissions, setModeratorPermissions] = useState({}); const [moderatorPermissions, setModeratorPermissions] = useState({});
const [moderatorRole, setModeratorRole] = useState({});
const [executeAnonMode, setExecuteAnonMode] = useState(false); const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({}); const [cidTracker, setCidTracker] = useState({});
const [isThreadThumbnailClicked, setIsThreadThumbnailClicked] = useState({}); const [isThreadThumbnailClicked, setIsThreadThumbnailClicked] = useState({});
@@ -180,6 +181,7 @@ const All = () => {
useEffect(() => { useEffect(() => {
let permissions = {}; let permissions = {};
let roles = {};
selectedFeed.forEach((thread) => { selectedFeed.forEach((thread) => {
const subplebbit = subplebbits.find((s) => s && s.address === thread.subplebbitAddress); const subplebbit = subplebbits.find((s) => s && s.address === thread.subplebbitAddress);
@@ -192,10 +194,16 @@ const All = () => {
} else { } else {
permissions[thread.subplebbitAddress] = false; permissions[thread.subplebbitAddress] = false;
} }
if (!roles[thread.subplebbitAddress]) {
roles[thread.subplebbitAddress] = {};
}
roles[thread.subplebbitAddress][account?.author.address] = role;
} }
}); });
setModeratorPermissions(permissions); setModeratorPermissions(permissions);
setModeratorRole(roles);
}, [account?.author.address, selectedFeed, subplebbits]); }, [account?.author.address, selectedFeed, subplebbits]);
const handleOptionClick = () => { const handleOptionClick = () => {
@@ -717,7 +725,11 @@ const All = () => {
const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {}; const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {};
const commentMediaInfo = getCommentMediaInfo(thread); const commentMediaInfo = getCommentMediaInfo(thread);
const fallbackImgUrl = 'assets/filedeleted-res.gif'; const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isModerator = moderatorPermissions[thread.subplebbitAddress]; const canModerate = moderatorPermissions[thread.subplebbitAddress];
const userRole = moderatorRole[thread.subplebbitAddress]?.[thread?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile; let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile;
if (thread.linkWidth && thread.linkHeight) { if (thread.linkWidth && thread.linkHeight) {
let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight)); let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight));
@@ -897,7 +909,7 @@ const All = () => {
<Fragment key={`fragment3-${index}`}> <Fragment key={`fragment3-${index}`}>
<span <span
key={`n-${index}`} key={`n-${index}`}
className='name' className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName} data-tooltip-content={thread.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -906,15 +918,22 @@ const All = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`n-${index}`} className='name'> <span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName} {thread.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`n-${index}`} className='name'> <span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/ &nbsp;(u/
<span <span
key={`pa-${index}`} key={`pa-${index}`}
@@ -1037,7 +1056,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -1255,6 +1274,10 @@ const All = () => {
} }
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif'; const fallbackImgUrl = 'assets/filedeleted-res.gif';
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed); const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
@@ -1283,7 +1306,7 @@ const All = () => {
<Fragment key={`fragment6-${index}`}> <Fragment key={`fragment6-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name' className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName} data-tooltip-content={reply.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -1292,15 +1315,22 @@ const All = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName} {reply.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/ &nbsp;(u/
<span <span
key={`pa-${index}`} key={`pa-${index}`}
@@ -1434,7 +1464,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2019,7 +2049,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2085,7 +2115,7 @@ const All = () => {
<Fragment key={`fragment9-${index}`}> <Fragment key={`fragment9-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name-mobile' className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName} data-tooltip-content={thread.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -2094,15 +2124,22 @@ const All = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName} {thread.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp; &nbsp;
<span <span
key={`mob-pa-${index}`} key={`mob-pa-${index}`}
@@ -2454,6 +2491,10 @@ const All = () => {
} }
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed); const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
if (storedSigners[selectedThreadCidRef]) { if (storedSigners[selectedThreadCidRef]) {
@@ -2512,7 +2553,7 @@ const All = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2578,7 +2619,7 @@ const All = () => {
<Fragment key={`fragment13-${index}`}> <Fragment key={`fragment13-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name-mobile' className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName} data-tooltip-content={reply.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -2587,15 +2628,22 @@ const All = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName} {reply.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp; &nbsp;
<span <span
key={`mob-pa-${index}`} key={`mob-pa-${index}`}
+4 -4
View File
@@ -69,7 +69,7 @@ const CatalogPost = ({ post }) => {
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null); const [commentCid, setCommentCid] = useState(null);
const [isModerator, setIsModerator] = useState(false); const [canModerate, setCanModerate] = useState(false);
const [, setNewErrorMessage] = useError(); const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess(); const [, setNewSuccessMessage] = useSuccess();
@@ -161,9 +161,9 @@ const CatalogPost = ({ post }) => {
const role = subplebbit.roles[account?.author.address]?.role; const role = subplebbit.roles[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') { if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true); setCanModerate(true);
} else { } else {
setIsModerator(false); setCanModerate(false);
} }
} }
}, [account?.author.address, subplebbit.roles]); }, [account?.author.address, subplebbit.roles]);
@@ -573,7 +573,7 @@ const CatalogPost = ({ post }) => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
+85 -29
View File
@@ -145,7 +145,7 @@ const Board = () => {
const [deletePost, setDeletePost] = useState(false); const [deletePost, setDeletePost] = useState(false);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [isModerator, setIsModerator] = useState(false); const [canModerate, setCanModerate] = useState(false);
const [commentCid, setCommentCid] = useState(null); const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 }); const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
const [mobileMenuPosition, setMobileMenuPosition] = useState({ top: 0, left: 0 }); const [mobileMenuPosition, setMobileMenuPosition] = useState({ top: 0, left: 0 });
@@ -177,12 +177,12 @@ const Board = () => {
useEffect(() => { useEffect(() => {
if (subplebbit?.roles !== undefined) { if (subplebbit?.roles !== undefined) {
const role = subplebbit?.roles[account?.author.address]?.role; const role = subplebbit?.roles?.[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') { if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true); setCanModerate(true);
} else { } else {
setIsModerator(false); setCanModerate(false);
} }
} }
}, [account?.author.address, subplebbit?.roles]); }, [account?.author.address, subplebbit?.roles]);
@@ -463,11 +463,6 @@ const Board = () => {
const handleSubmit = async (event) => { const handleSubmit = async (event) => {
event.preventDefault(); event.preventDefault();
if (subjectRef.current.value === '') {
setNewErrorMessage('Subject field is mandatory');
return;
}
setPublishCommentOptions((prevPublishCommentOptions) => ({ setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions, ...prevPublishCommentOptions,
author: { author: {
@@ -933,7 +928,7 @@ const Board = () => {
> >
Catalog Catalog
</Link> </Link>
]{subplebbit.roles && subplebbit?.roles[account?.author?.address]?.role === 'admin' ? <BoardSettings subplebbit={subplebbit} /> : null} ]{subplebbit.roles && subplebbit?.roles?.[account?.author?.address]?.role === 'admin' ? <BoardSettings subplebbit={subplebbit} /> : null}
</div> </div>
{subplebbit?.state === 'succeeded' ? ( {subplebbit?.state === 'succeeded' ? (
<> <>
@@ -1039,7 +1034,7 @@ const Board = () => {
> >
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}> <div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'> <ul className='post-menu-catalog'>
{/* {isModerator ? ( {/* {canModerate ? (
<> <>
change rules change rules
</> </>
@@ -1264,7 +1259,7 @@ const Board = () => {
> >
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}> <div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'> <ul className='post-menu-catalog'>
{/* {isModerator ? ( {/* {canModerate ? (
<> <>
change rules change rules
</> </>
@@ -1509,7 +1504,7 @@ const Board = () => {
style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }} style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }}
> >
<ul className='post-menu-catalog'> <ul className='post-menu-catalog'>
{/* {isModerator ? ( {/* {canModerate ? (
<> <>
change description change description
</> </>
@@ -1744,6 +1739,9 @@ const Board = () => {
const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {}; const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {};
const commentMediaInfo = getCommentMediaInfo(thread); const commentMediaInfo = getCommentMediaInfo(thread);
const fallbackImgUrl = 'assets/filedeleted-res.gif'; const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isOwner = subplebbit?.roles?.[thread.author.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[thread.author.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[thread.author.address]?.role === 'moderator';
let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile; let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile;
if (thread.linkWidth && thread.linkHeight) { if (thread.linkWidth && thread.linkHeight) {
let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight)); let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight));
@@ -1923,7 +1921,7 @@ const Board = () => {
<Fragment key={`fragment3-${index}`}> <Fragment key={`fragment3-${index}`}>
<span <span
key={`n-${index}`} key={`n-${index}`}
className='name' className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName} data-tooltip-content={thread.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -1932,15 +1930,28 @@ const Board = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`n-${index}`} className='name'> <span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName} {thread.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`n-${index}`} className='name'> <span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;(u/ &nbsp;(u/
<span <span
key={`pa-${index}`} key={`pa-${index}`}
@@ -2080,7 +2091,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2299,6 +2310,9 @@ const Board = () => {
} }
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif'; const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed); const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
@@ -2328,7 +2342,7 @@ const Board = () => {
<Fragment key={`fragment6-${index}`}> <Fragment key={`fragment6-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name' className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName} data-tooltip-content={reply.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -2337,15 +2351,28 @@ const Board = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName} {reply.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;(u/ &nbsp;(u/
<span <span
key={`pa-${index}`} key={`pa-${index}`}
@@ -2465,7 +2492,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -3057,7 +3084,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -3139,7 +3166,7 @@ const Board = () => {
<Fragment key={`fragment9-${index}`}> <Fragment key={`fragment9-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name-mobile' className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName} data-tooltip-content={thread.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -3148,15 +3175,28 @@ const Board = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName} {thread.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp; &nbsp;
<span <span
key={`mob-pa-${index}`} key={`mob-pa-${index}`}
@@ -3504,6 +3544,9 @@ const Board = () => {
{displayedReplies?.map((reply, index) => { {displayedReplies?.map((reply, index) => {
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed); const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
const isOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
if (storedSigners[selectedThreadCidRef]) { if (storedSigners[selectedThreadCidRef]) {
@@ -3562,7 +3605,7 @@ const Board = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -3644,7 +3687,7 @@ const Board = () => {
<Fragment key={`fragment13-${index}`}> <Fragment key={`fragment13-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name-mobile' className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName} data-tooltip-content={reply.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -3653,15 +3696,28 @@ const Board = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName} {reply.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp; &nbsp;
<span <span
key={`mob-pa-${index}`} key={`mob-pa-${index}`}
+8 -13
View File
@@ -52,7 +52,7 @@ const CatalogPost = ({ post }) => {
setIsAuthorEdit, setIsAuthorEdit,
setIsCaptchaOpen, setIsCaptchaOpen,
setIsEditModalOpen, setIsEditModalOpen,
isModerator, canModerate,
setModeratingCommentCid, setModeratingCommentCid,
setOriginalCommentContent, setOriginalCommentContent,
setPendingComment, setPendingComment,
@@ -443,7 +443,7 @@ const CatalogPost = ({ post }) => {
> >
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}> <div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'> <ul className='post-menu-catalog'>
{/* {isModerator ? ( {/* {canModerate ? (
<> <>
change rules change rules
</> </>
@@ -647,7 +647,7 @@ const CatalogPost = ({ post }) => {
> >
<div className={`post-menu-thread post-menu-thread-${'description'}`} style={{ display: openMenuCid === 'description' ? 'block' : 'none' }}> <div className={`post-menu-thread post-menu-thread-${'description'}`} style={{ display: openMenuCid === 'description' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'> <ul className='post-menu-catalog'>
{/* {isModerator ? ( {/* {canModerate ? (
<> <>
change description change description
</> </>
@@ -999,7 +999,7 @@ const CatalogPost = ({ post }) => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -1133,7 +1133,7 @@ const Catalog = () => {
setIsCaptchaOpen, setIsCaptchaOpen,
isModerationOpen, isModerationOpen,
setIsModerationOpen, setIsModerationOpen,
setIsModerator, setCanModerate,
isSettingsOpen, isSettingsOpen,
setIsSettingsOpen, setIsSettingsOpen,
originalCommentContent, originalCommentContent,
@@ -1198,12 +1198,12 @@ const Catalog = () => {
const role = subplebbit.roles[account?.author.address]?.role; const role = subplebbit.roles[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') { if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true); setCanModerate(true);
} else { } else {
setIsModerator(false); setCanModerate(false);
} }
} }
}, [account?.author.address, subplebbit.roles, setIsModerator]); }, [account?.author.address, subplebbit.roles, setCanModerate]);
useEffect(() => { useEffect(() => {
setSelectedAddress(subplebbitAddress); setSelectedAddress(subplebbitAddress);
@@ -1328,11 +1328,6 @@ const Catalog = () => {
const handleSubmit = async (event) => { const handleSubmit = async (event) => {
event.preventDefault(); event.preventDefault();
if (subjectRef.current.value === '') {
setNewErrorMessage('Subject field is mandatory');
return;
}
setPublishCommentOptions((prevPublishCommentOptions) => ({ setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions, ...prevPublishCommentOptions,
author: { author: {
+1 -1
View File
@@ -427,7 +427,7 @@ const Description = () => {
style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }} style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }}
> >
<ul className='post-menu-catalog'> <ul className='post-menu-catalog'>
{/* {isModerator ? ( {/* {canModerate ? (
<> <>
change description change description
</> </>
+1 -1
View File
@@ -412,7 +412,7 @@ const Rules = () => {
> >
<div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}> <div className={`post-menu-thread post-menu-thread-${'rules'}`} style={{ display: openMenuCid === 'rules' ? 'block' : 'none' }}>
<ul className='post-menu-catalog'> <ul className='post-menu-catalog'>
{/* {isModerator ? ( {/* {canModerate ? (
<> <>
change rules change rules
</> </>
+65 -17
View File
@@ -119,6 +119,7 @@ const Subscriptions = () => {
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0); const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
const [deletePost, setDeletePost] = useState(false); const [deletePost, setDeletePost] = useState(false);
const [moderatorPermissions, setModeratorPermissions] = useState({}); const [moderatorPermissions, setModeratorPermissions] = useState({});
const [moderatorRole, setModeratorRole] = useState({});
const [executeAnonMode, setExecuteAnonMode] = useState(false); const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({}); const [cidTracker, setCidTracker] = useState({});
const [isThreadThumbnailClicked, setIsThreadThumbnailClicked] = useState({}); const [isThreadThumbnailClicked, setIsThreadThumbnailClicked] = useState({});
@@ -179,6 +180,7 @@ const Subscriptions = () => {
useEffect(() => { useEffect(() => {
let permissions = {}; let permissions = {};
let roles = {};
selectedFeed.forEach((thread) => { selectedFeed.forEach((thread) => {
const subplebbit = subplebbits.find((s) => s && s.address === thread.subplebbitAddress); const subplebbit = subplebbits.find((s) => s && s.address === thread.subplebbitAddress);
@@ -191,10 +193,16 @@ const Subscriptions = () => {
} else { } else {
permissions[thread.subplebbitAddress] = false; permissions[thread.subplebbitAddress] = false;
} }
if (!roles[thread.subplebbitAddress]) {
roles[thread.subplebbitAddress] = {};
}
roles[thread.subplebbitAddress][account?.author.address] = role;
} }
}); });
setModeratorPermissions(permissions); setModeratorPermissions(permissions);
setModeratorRole(roles);
}, [account?.author.address, selectedFeed, subplebbits]); }, [account?.author.address, selectedFeed, subplebbits]);
const handleOptionClick = () => { const handleOptionClick = () => {
@@ -721,7 +729,11 @@ const Subscriptions = () => {
const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {}; const { displayedReplies, omittedCount } = filteredRepliesByThread[thread.cid] || {};
const commentMediaInfo = getCommentMediaInfo(thread); const commentMediaInfo = getCommentMediaInfo(thread);
const fallbackImgUrl = 'assets/filedeleted-res.gif'; const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isModerator = moderatorPermissions[thread.subplebbitAddress]; const canModerate = moderatorPermissions[thread.subplebbitAddress];
const userRole = moderatorRole[thread.subplebbitAddress]?.[thread?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile; let displayWidth, displayHeight, displayWidthMobile, displayHeightMobile;
if (thread.linkWidth && thread.linkHeight) { if (thread.linkWidth && thread.linkHeight) {
let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight)); let scale = Math.min(1, 250 / Math.max(thread.linkWidth, thread.linkHeight));
@@ -901,7 +913,7 @@ const Subscriptions = () => {
<Fragment key={`fragment3-${index}`}> <Fragment key={`fragment3-${index}`}>
<span <span
key={`n-${index}`} key={`n-${index}`}
className='name' className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName} data-tooltip-content={thread.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -910,15 +922,22 @@ const Subscriptions = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`n-${index}`} className='name'> <span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName} {thread.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`n-${index}`} className='name'> <span key={`n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/ &nbsp;(u/
<span <span
key={`pa-${index}`} key={`pa-${index}`}
@@ -1047,7 +1066,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -1265,6 +1284,10 @@ const Subscriptions = () => {
} }
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif'; const fallbackImgUrl = 'assets/filedeleted-res.gif';
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed); const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
@@ -1293,7 +1316,7 @@ const Subscriptions = () => {
<Fragment key={`fragment6-${index}`}> <Fragment key={`fragment6-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name' className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName} data-tooltip-content={reply.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -1302,15 +1325,22 @@ const Subscriptions = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName} {reply.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp;(u/ &nbsp;(u/
<span <span
key={`pa-${index}`} key={`pa-${index}`}
@@ -1444,7 +1474,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2029,7 +2059,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2095,7 +2125,7 @@ const Subscriptions = () => {
<Fragment key={`fragment9-${index}`}> <Fragment key={`fragment9-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name-mobile' className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={thread.author.displayName} data-tooltip-content={thread.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -2104,15 +2134,22 @@ const Subscriptions = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{thread.author.displayName} {thread.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp; &nbsp;
<span <span
key={`mob-pa-${index}`} key={`mob-pa-${index}`}
@@ -2464,6 +2501,10 @@ const Subscriptions = () => {
} }
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed); const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
const userRole = moderatorRole[reply.subplebbitAddress]?.[reply?.author.address] || 'user';
const isOwner = userRole === 'owner';
const isAdmin = userRole === 'admin';
const isModerator = userRole === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
if (storedSigners[selectedThreadCidRef]) { if (storedSigners[selectedThreadCidRef]) {
@@ -2522,7 +2563,7 @@ const Subscriptions = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2588,7 +2629,7 @@ const Subscriptions = () => {
<Fragment key={`fragment13-${index}`}> <Fragment key={`fragment13-${index}`}>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name-mobile' className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={reply.author.displayName} data-tooltip-content={reply.author.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -2597,15 +2638,22 @@ const Subscriptions = () => {
</span> </span>
</Fragment> </Fragment>
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author.displayName} {reply.author.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name-mobile'> <span key={`mob-n-${index}`} className={`name-mobile ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span className='name capcode-admin'>&nbsp;## Board Owner</span>
) : isAdmin ? (
<span className='name capcode-admin'>&nbsp;## Board Admin</span>
) : isModerator ? (
<span className='name capcode'>&nbsp;## Board Mod</span>
) : null}
&nbsp; &nbsp;
<span <span
key={`mob-pa-${index}`} key={`mob-pa-${index}`}
@@ -69,7 +69,7 @@ const CatalogPost = ({ post }) => {
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null); const [commentCid, setCommentCid] = useState(null);
const [isModerator, setIsModerator] = useState(false); const [canModerate, setCanModerate] = useState(false);
const [, setNewErrorMessage] = useError(); const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess(); const [, setNewSuccessMessage] = useSuccess();
@@ -161,9 +161,9 @@ const CatalogPost = ({ post }) => {
const role = subplebbit.roles[account?.author.address]?.role; const role = subplebbit.roles[account?.author.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') { if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true); setCanModerate(true);
} else { } else {
setIsModerator(false); setCanModerate(false);
} }
} }
}, [account?.author.address, subplebbit.roles]); }, [account?.author.address, subplebbit.roles]);
@@ -573,7 +573,7 @@ const CatalogPost = ({ post }) => {
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
+77 -13
View File
@@ -23,6 +23,7 @@ import PostOnHover from '../PostOnHover';
import StateLabel from '../StateLabel'; import StateLabel from '../StateLabel';
import VerifiedAuthor from '../VerifiedAuthor'; import VerifiedAuthor from '../VerifiedAuthor';
import CreateBoardModal from '../modals/CreateBoardModal'; import CreateBoardModal from '../modals/CreateBoardModal';
import AdminListModal from '../modals/AdminListModal';
import EditModal from '../modals/EditModal'; import EditModal from '../modals/EditModal';
import ModerationModal from '../modals/ModerationModal'; import ModerationModal from '../modals/ModerationModal';
import ReplyModal from '../modals/ReplyModal'; import ReplyModal from '../modals/ReplyModal';
@@ -119,7 +120,7 @@ const Thread = () => {
const [visible, setVisible] = useState(true); const [visible, setVisible] = useState(true);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false); const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [isModerator, setIsModerator] = useState(false); const [canModerate, setCanModerate] = useState(false);
const [commentCid, setCommentCid] = useState(null); const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 }); const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
const [mobileMenuPosition, setMobileMenuPosition] = useState({ top: 0, left: 0 }); const [mobileMenuPosition, setMobileMenuPosition] = useState({ top: 0, left: 0 });
@@ -138,11 +139,15 @@ const Thread = () => {
useAnonMode(selectedThread, anonymousMode && executeAnonMode); useAnonMode(selectedThread, anonymousMode && executeAnonMode);
const [isAdminListOpen, setIsAdminListOpen] = useState(false);
const originalComment = useComment({ commentCid: selectedThread }); const originalComment = useComment({ commentCid: selectedThread });
const [comment, setComment] = useState(originalComment); const [comment, setComment] = useState(originalComment);
const { subplebbitAddress, threadCid } = useParams(); const { subplebbitAddress, threadCid } = useParams();
const subplebbit = useSubplebbit({ subplebbitAddress: originalComment.subplebbitAddress }); const subplebbit = useSubplebbit({ subplebbitAddress: originalComment.subplebbitAddress });
const selectedAddress = subplebbit.address; const selectedAddress = subplebbit.address;
const isOwner = subplebbit?.roles?.[comment.author?.address]?.role === 'owner';
const isAdmin = subplebbit?.roles?.[comment.author?.address]?.role === 'admin';
const isModerator = subplebbit?.roles?.[comment.author?.address]?.role === 'moderator';
const stateString = useStateString(comment); const stateString = useStateString(comment);
@@ -200,9 +205,9 @@ const Thread = () => {
const role = subplebbit.roles[account?.author?.address]?.role; const role = subplebbit.roles[account?.author?.address]?.role;
if (role === 'moderator' || role === 'admin' || role === 'owner') { if (role === 'moderator' || role === 'admin' || role === 'owner') {
setIsModerator(true); setCanModerate(true);
} else { } else {
setIsModerator(false); setCanModerate(false);
} }
} }
}, [account?.author.address, subplebbit.roles]); }, [account?.author.address, subplebbit.roles]);
@@ -642,6 +647,7 @@ const Thread = () => {
</title> </title>
</Helmet> </Helmet>
<Container> <Container>
<AdminListModal selectedStyle={selectedStyle} isOpen={isAdminListOpen} closeModal={() => setIsAdminListOpen(false)} roles={subplebbit?.roles} />
<CreateBoardModal selectedStyle={selectedStyle} isOpen={isCreateBoardOpen} closeModal={() => setIsCreateBoardOpen(false)} /> <CreateBoardModal selectedStyle={selectedStyle} isOpen={isCreateBoardOpen} closeModal={() => setIsCreateBoardOpen(false)} />
<ReplyModal selectedStyle={selectedStyle} isOpen={isReplyOpen} closeModal={() => setIsReplyOpen(false)} /> <ReplyModal selectedStyle={selectedStyle} isOpen={isReplyOpen} closeModal={() => setIsReplyOpen(false)} />
<SettingsModal selectedStyle={selectedStyle} isOpen={isSettingsOpen} closeModal={() => setIsSettingsOpen(false)} /> <SettingsModal selectedStyle={selectedStyle} isOpen={isSettingsOpen} closeModal={() => setIsSettingsOpen(false)} />
@@ -1078,7 +1084,7 @@ const Thread = () => {
<> <>
<span <span
key={`n-${comment.cid}`} key={`n-${comment.cid}`}
className='name' className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={comment?.author?.displayName} data-tooltip-content={comment?.author?.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -1087,15 +1093,28 @@ const Thread = () => {
</span> </span>
</> </>
) : ( ) : (
<span key={`n-${comment.cid}`} className='name'> <span key={`n-${comment.cid}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{comment?.author?.displayName} {comment?.author?.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`n-${comment.cid}`} className='name'> <span key={`n-${comment.cid}`} className={`name ${isAdmin || isOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp; &nbsp;
<span <span
className='poster-address address-desktop' className='poster-address address-desktop'
@@ -1205,7 +1224,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(comment)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(comment)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -1375,6 +1394,9 @@ const Thread = () => {
} }
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const fallbackImgUrl = 'assets/filedeleted-res.gif'; const fallbackImgUrl = 'assets/filedeleted-res.gif';
const isReplyOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isReplyAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isReplyModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
const shortParentCid = findShortParentCid(reply.parentCid, comment); const shortParentCid = findShortParentCid(reply.parentCid, comment);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
@@ -1404,7 +1426,7 @@ const Thread = () => {
<> <>
<span <span
key={`mob-n-${index}`} key={`mob-n-${index}`}
className='name' className={`name ${isReplyAdmin || isReplyOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}
data-tooltip-id='tooltip' data-tooltip-id='tooltip'
data-tooltip-content={reply.author?.displayName} data-tooltip-content={reply.author?.displayName}
data-tooltip-place='top' data-tooltip-place='top'
@@ -1413,15 +1435,28 @@ const Thread = () => {
</span> </span>
</> </>
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isReplyAdmin || isReplyOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
{reply.author?.displayName ?? reply.displayName} {reply.author?.displayName ?? reply.displayName}
</span> </span>
) )
) : ( ) : (
<span key={`mob-n-${index}`} className='name'> <span key={`mob-n-${index}`} className={`name ${isReplyAdmin || isReplyOwner ? 'capcode-admin' : isModerator ? 'capcode' : ''}`}>
Anonymous Anonymous
</span> </span>
)} )}
{isReplyOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isReplyAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isReplyModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp;(u/ &nbsp;(u/
<span <span
key={`pa-${index}`} key={`pa-${index}`}
@@ -1531,7 +1566,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -1986,7 +2021,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(comment)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(comment)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2086,6 +2121,19 @@ const Thread = () => {
Anonymous Anonymous
</span> </span>
)} )}
{isOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
&nbsp; &nbsp;
<span <span
key={`mob-pa-${comment.cid}`} key={`mob-pa-${comment.cid}`}
@@ -2340,6 +2388,9 @@ const Thread = () => {
{sortedReplies.map((reply, index) => { {sortedReplies.map((reply, index) => {
const replyMediaInfo = getCommentMediaInfo(reply); const replyMediaInfo = getCommentMediaInfo(reply);
const shortParentCid = findShortParentCid(reply.parentCid, comment); const shortParentCid = findShortParentCid(reply.parentCid, comment);
const isReplyOwner = subplebbit?.roles?.[reply.author.address]?.role === 'owner';
const isReplyAdmin = subplebbit?.roles?.[reply.author.address]?.role === 'admin';
const isReplyModerator = subplebbit?.roles?.[reply.author.address]?.role === 'moderator';
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {}; let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signerAddress; let signerAddress;
if (storedSigners[selectedThread]) { if (storedSigners[selectedThread]) {
@@ -2398,7 +2449,7 @@ const Thread = () => {
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li> <li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</> </>
) : null} ) : null}
{isModerator ? ( {canModerate ? (
<> <>
{authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : ( {authorAddress === account?.author.address || authorAddress === account?.signer.address ? null : (
<li <li
@@ -2498,6 +2549,19 @@ const Thread = () => {
Anonymous Anonymous
</span> </span>
)} )}
{isReplyOwner ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Owner
</span>
) : isReplyAdmin ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode-admin'>
&nbsp;## Board Admin
</span>
) : isReplyModerator ? (
<span onClick={() => setIsAdminListOpen(true)} className='name capcode'>
&nbsp;## Board Mod
</span>
) : null}
<span key={`fix1-ha-${index}`} className='poster-address-mobile'> <span key={`fix1-ha-${index}`} className='poster-address-mobile'>
&nbsp;(u/ &nbsp;(u/
</span> </span>
+9 -9
View File
@@ -30,12 +30,13 @@ const useGeneralStore = create((set) => ({
setEditedComments: (comments) => set({ editedComments: comments }), setEditedComments: (comments) => set({ editedComments: comments }),
feedCacheStates: {}, feedCacheStates: {},
setFeedCacheState: (address, isCached) => set((prev) => ({ setFeedCacheState: (address, isCached) =>
feedCacheStates: { set((prev) => ({
...prev.feedCacheStates, feedCacheStates: {
[address]: isCached, ...prev.feedCacheStates,
} [address]: isCached,
})), },
})),
isAuthorDelete: false, isAuthorDelete: false,
setIsAuthorDelete: (isAuthorDelete) => set({ isAuthorDelete }), setIsAuthorDelete: (isAuthorDelete) => set({ isAuthorDelete }),
@@ -49,8 +50,8 @@ const useGeneralStore = create((set) => ({
isEditModalOpen: false, isEditModalOpen: false,
setIsEditModalOpen: (isOpen) => set({ isEditModalOpen: isOpen }), setIsEditModalOpen: (isOpen) => set({ isEditModalOpen: isOpen }),
isModerator: false, canModerate: false,
setIsModerator: (isModerator) => set({ isModerator }), setCanModerate: (canModerate) => set({ canModerate }),
isModerationOpen: false, isModerationOpen: false,
setIsModerationOpen: (isOpen) => set({ isModerationOpen: isOpen }), setIsModerationOpen: (isOpen) => set({ isModerationOpen: isOpen }),
@@ -114,7 +115,6 @@ const useGeneralStore = create((set) => ({
triggerInsertion: 0, triggerInsertion: 0,
setTriggerInsertion: (trigger) => set({ triggerInsertion: trigger }), setTriggerInsertion: (trigger) => set({ triggerInsertion: trigger }),
})); }));
export default useGeneralStore; export default useGeneralStore;