diff --git a/src/app.tsx b/src/app.tsx index a22a7ab1..a8bdb425 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,6 +1,7 @@ import { useEffect, useState } from 'react'; -import { Outlet, Route, Routes, useLocation, useParams } from 'react-router-dom'; -import { useAccountComment } from '@plebbit/plebbit-react-hooks'; +import { Navigate, Outlet, Route, Routes, useLocation, useParams } from 'react-router-dom'; +import { useAccount, useAccountComment, useSubplebbit } from '@plebbit/plebbit-react-hooks'; +import useAccountsStore from '@plebbit/plebbit-react-hooks/dist/stores/accounts'; import { initSnow, removeSnow } from './lib/snow'; import { isAllView, isModView, isSubscriptionsView } from './lib/utils/view-utils'; import { preloadThemeAssets } from './lib/utils/preload-utils'; @@ -10,12 +11,14 @@ import useSpecialThemeStore from './stores/use-special-theme-store'; import useIsMobile from './hooks/use-is-mobile'; import useTheme from './hooks/use-theme'; import { useDirectories } from './hooks/use-directories'; +import { useResolvedSubplebbitAddress } from './hooks/use-resolved-subplebbit-address'; import { getSubplebbitAddress, isPostRoute, isPendingPostRoute, isModQueueRoute } from './lib/utils/route-utils'; import styles from './app.module.css'; import FAQ from './views/faq'; import Home from './views/home'; import Rules from './views/rules'; import NotFound from './views/not-found'; +import NotAllowed from './views/not-allowed'; import PendingPost from './views/pending-post'; import Post from './views/post'; import ModQueueView from './views/mod-queue'; @@ -37,6 +40,8 @@ import SettingsModal from './components/settings-modal'; // to prevent visible loading delays when switching themes preloadThemeAssets(); +const hasModQueueAccessRole = (role?: string): boolean => role === 'admin' || role === 'owner' || role === 'moderator'; + const BoardLayout = () => { const { accountCommentIndex, boardIdentifier } = useParams(); const location = useLocation(); @@ -147,6 +152,49 @@ const GlobalLayout = () => { ); }; +const ModQueueRoute = () => { + const { boardIdentifier } = useParams(); + const account = useAccount(); + const accountAddress = account?.author?.address; + const subplebbitAddress = useResolvedSubplebbitAddress(); + const subplebbit = useSubplebbit({ subplebbitAddress }); + + const accountSubplebbitAddresses = useAccountsStore( + (state) => { + const activeAccountId = state.activeAccountId; + const activeAccount = activeAccountId ? state.accounts[activeAccountId] : undefined; + const accountSubplebbits = activeAccount?.subplebbits || {}; + return Object.keys(accountSubplebbits); + }, + (prev, next) => { + if (prev.length !== next.length) return false; + return prev.every((val, idx) => val === next[idx]); + }, + ); + + if (!account) { + return null; + } + + if (!accountAddress) { + return ; + } + + if (!boardIdentifier) { + return accountSubplebbitAddresses.length > 0 ? : ; + } + + // Wait for board role metadata before enforcing access to avoid false redirects during initial load. + const boardState = subplebbit?.state; + const isBoardLoading = !subplebbit || !boardState || (boardState !== 'succeeded' && boardState !== 'failed'); + if (isBoardLoading) { + return null; + } + + const accountRole = subplebbit?.roles?.[accountAddress]?.role; + return hasModQueueAccessRole(accountRole) ? : ; +}; + const App = () => (
@@ -170,16 +218,16 @@ const App = () => ( - } /> - } /> + } /> + } /> - } /> - } /> + } /> + } /> } /> } /> @@ -187,6 +235,7 @@ const App = () => ( } /> } /> + } /> } /> } /> diff --git a/src/components/not-found-image/index.ts b/src/components/not-found-image/index.ts new file mode 100644 index 00000000..98637f42 --- /dev/null +++ b/src/components/not-found-image/index.ts @@ -0,0 +1 @@ +export { default } from './not-found-image'; diff --git a/src/components/not-found-image/not-found-image.tsx b/src/components/not-found-image/not-found-image.tsx new file mode 100644 index 00000000..05c5f46a --- /dev/null +++ b/src/components/not-found-image/not-found-image.tsx @@ -0,0 +1,10 @@ +import { useState } from 'react'; +import { NOT_FOUND_IMAGES } from '../../generated/asset-manifest'; + +const NotFoundImage = () => { + const [imagePath] = useState(() => NOT_FOUND_IMAGES[Math.floor(Math.random() * NOT_FOUND_IMAGES.length)]); + + return ; +}; + +export default NotFoundImage; diff --git a/src/views/not-allowed/index.ts b/src/views/not-allowed/index.ts new file mode 100644 index 00000000..4b780e62 --- /dev/null +++ b/src/views/not-allowed/index.ts @@ -0,0 +1 @@ +export { default } from './not-allowed'; diff --git a/src/views/not-allowed/not-allowed.tsx b/src/views/not-allowed/not-allowed.tsx new file mode 100644 index 00000000..032a9f22 --- /dev/null +++ b/src/views/not-allowed/not-allowed.tsx @@ -0,0 +1,30 @@ +import { Link } from 'react-router-dom'; +import { HomeLogo } from '../home'; +import NotFoundImage from '../../components/not-found-image'; +import styles from '../not-found/not-found.module.css'; + +const NotAllowed = () => { + return ( +
+
+ +
+
+
+

Not Allowed

+
+
+ +
+
+ [Back to home] +
+
+
+
+
+
+ ); +}; + +export default NotAllowed; diff --git a/src/views/not-found/not-found.tsx b/src/views/not-found/not-found.tsx index b2a471eb..f5a50173 100644 --- a/src/views/not-found/not-found.tsx +++ b/src/views/not-found/not-found.tsx @@ -1,17 +1,10 @@ -import { useState } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { useSubplebbitField } from '../../hooks/use-stable-subplebbit'; import { useDirectories } from '../../hooks/use-directories'; import { getSubplebbitAddress } from '../../lib/utils/route-utils'; import { HomeLogo } from '../home'; +import NotFoundImage from '../../components/not-found-image'; import styles from './not-found.module.css'; -import { NOT_FOUND_IMAGES } from '../../generated/asset-manifest'; - -const NotFoundImage = () => { - const [imagePath] = useState(() => NOT_FOUND_IMAGES[Math.floor(Math.random() * NOT_FOUND_IMAGES.length)]); - - return ; -}; const NotFound = () => { const location = useLocation(); @@ -31,7 +24,7 @@ const NotFound = () => {
-

404 Not Found

+

Not Found