mirror of
https://github.com/plebbit/seedit.git
synced 2026-04-18 22:28:21 -04:00
feat: add better errors with button to display full error stack
This commit is contained in:
9
src/components/error-display/error-display.module.css
Normal file
9
src/components/error-display/error-display.module.css
Normal file
@@ -0,0 +1,9 @@
|
||||
.errorMessage {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
.showFullErrorButton {
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
padding: 5px 0;
|
||||
}
|
||||
39
src/components/error-display/error-display.tsx
Normal file
39
src/components/error-display/error-display.tsx
Normal file
@@ -0,0 +1,39 @@
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import styles from './error-display.module.css';
|
||||
|
||||
const ErrorDisplay = ({ error }: { error: Error | null }) => {
|
||||
const { t } = useTranslation();
|
||||
const [showFullError, setShowFullError] = useState(false);
|
||||
|
||||
return (
|
||||
(error?.message || error?.stack) && (
|
||||
<div className={styles.error}>
|
||||
<br />
|
||||
<span>
|
||||
{error?.message && (
|
||||
<span className={styles.errorMessage}>
|
||||
{t('error')}: {error.message}
|
||||
</span>
|
||||
)}
|
||||
{error?.stack && (
|
||||
<>
|
||||
{' — '}
|
||||
<span className={styles.showFullErrorButton} onClick={() => setShowFullError(!showFullError)}>
|
||||
{showFullError ? 'hide' : 'show'} full error
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
{showFullError && (
|
||||
<>
|
||||
<br />
|
||||
<div className={styles.errorStack}>{error.stack}</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ErrorDisplay;
|
||||
1
src/components/error-display/index.ts
Normal file
1
src/components/error-display/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default } from './error-display';
|
||||
24
src/stores/use-error-store.ts
Normal file
24
src/stores/use-error-store.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
interface ErrorStoreState {
|
||||
errors: Record<string, Error | null>;
|
||||
setError: (source: string, error: Error | null | undefined) => void;
|
||||
clearAllErrors: () => void;
|
||||
}
|
||||
|
||||
const useErrorStore = create<ErrorStoreState>((set) => ({
|
||||
errors: {},
|
||||
setError: (source, error) =>
|
||||
set((state) => {
|
||||
const newErrors = { ...state.errors };
|
||||
if (error) {
|
||||
newErrors[source] = error;
|
||||
} else {
|
||||
delete newErrors[source];
|
||||
}
|
||||
return { errors: newErrors };
|
||||
}),
|
||||
clearAllErrors: () => set({ errors: {} }),
|
||||
}));
|
||||
|
||||
export default useErrorStore;
|
||||
@@ -30,4 +30,11 @@ div[data-viewport-type="window"] {
|
||||
display: inline-block;
|
||||
padding: 10px 0 0px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.error {
|
||||
padding-left: 10px;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import Post from '../../components/post';
|
||||
import Reply from '../../components/reply/';
|
||||
import AuthorSidebar from '../../components/author-sidebar';
|
||||
import styles from './author.module.css';
|
||||
import ErrorDisplay from '../../components/error-display';
|
||||
|
||||
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
||||
|
||||
@@ -24,7 +25,13 @@ const Author = () => {
|
||||
const isInAuthorSubmittedView = isAuthorSubmittedView(location.pathname, params);
|
||||
const isMobile = useWindowWidth() < 640;
|
||||
|
||||
const { authorComments, lastCommentCid, hasMore, loadMore } = useAuthorComments({ commentCid, authorAddress });
|
||||
const { authorComments, error, lastCommentCid, hasMore, loadMore } = useAuthorComments({ commentCid, authorAddress });
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
const replyComments = useMemo(() => authorComments?.filter((comment) => comment && comment.parentCid) || [], [authorComments]);
|
||||
const postComments = useMemo(() => authorComments?.filter((comment) => comment && !comment.parentCid) || [], [authorComments]);
|
||||
@@ -82,6 +89,11 @@ const Author = () => {
|
||||
<div className={isMobile ? styles.sidebarMobile : styles.sidebarDesktop}>
|
||||
<AuthorSidebar />
|
||||
</div>
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
<Virtuoso
|
||||
increaseViewportBy={{ bottom: 1200, top: 600 }}
|
||||
totalCount={authorComments?.length || 0}
|
||||
|
||||
@@ -165,3 +165,10 @@
|
||||
background-color: var(--button-background-color-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
padding-left: 5px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import Reply from '../../components/reply/reply';
|
||||
import { isInboxCommentRepliesView, isInboxPostRepliesView, isInboxUnreadView } from '../../lib/utils/view-utils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import _ from 'lodash';
|
||||
import ErrorDisplay from '../../components/error-display';
|
||||
|
||||
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
||||
|
||||
@@ -43,7 +44,7 @@ const Inbox = () => {
|
||||
const { t } = useTranslation();
|
||||
const account = useAccount();
|
||||
const { unreadNotificationCount } = account || {};
|
||||
const { notifications, markAsRead } = useNotifications();
|
||||
const { error, notifications, markAsRead } = useNotifications();
|
||||
|
||||
const location = useLocation();
|
||||
const isInInboxCommentRepliesView = isInboxCommentRepliesView(location.pathname);
|
||||
@@ -97,6 +98,12 @@ const Inbox = () => {
|
||||
document.title = documentTitle;
|
||||
}, [documentTitle]);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<InboxTabs />
|
||||
@@ -109,6 +116,11 @@ const Inbox = () => {
|
||||
<div className={styles.noNotifications}>{t('nothing_found')}</div>
|
||||
)}
|
||||
</div>
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
<Virtuoso
|
||||
increaseViewportBy={{ bottom: 1200, top: 600 }}
|
||||
totalCount={notifications?.length || 0}
|
||||
|
||||
@@ -191,3 +191,10 @@
|
||||
padding-top: 19px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.fullError {
|
||||
padding-left: 10px;
|
||||
font-size: 12px;
|
||||
margin-top: -20px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
@@ -1,23 +1,24 @@
|
||||
import { useEffect, useState, useRef, useCallback, useMemo } from 'react';
|
||||
import { Link, useLocation, useNavigate, useParams } from 'react-router-dom';
|
||||
import { Comment, useAccount, useAccountComment, useAccountComments, useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Comment, useAccount, useAccountComment, useAccountComments, useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
|
||||
import findTopParentCidOfReply from '../../lib/utils/cid-utils';
|
||||
import { sortRepliesByBest } from '../../lib/utils/post-utils';
|
||||
import { isPendingPostView, isPostContextView } from '../../lib/utils/view-utils';
|
||||
import useContentOptionsStore from '../../stores/use-content-options-store';
|
||||
import useFeedResetStore from '../../stores/use-feed-reset-store';
|
||||
import { useIsBroadlyNsfwSubplebbit } from '../../hooks/use-is-broadly-nsfw-subplebbit';
|
||||
import useReplies from '../../hooks/use-replies';
|
||||
import useStateString from '../../hooks/use-state-string';
|
||||
import ErrorDisplay from '../../components/error-display';
|
||||
import LoadingEllipsis from '../../components/loading-ellipsis';
|
||||
import Over18Warning from '../../components/over-18-warning';
|
||||
import PostComponent from '../../components/post';
|
||||
import Reply from '../../components/reply';
|
||||
import ReplyForm from '../../components/reply-form';
|
||||
import PostComponent from '../../components/post';
|
||||
import Sidebar from '../../components/sidebar';
|
||||
import styles from './post-page.module.css';
|
||||
import _ from 'lodash';
|
||||
import Over18Warning from '../../components/over-18-warning';
|
||||
import { useIsBroadlyNsfwSubplebbit } from '../../hooks/use-is-broadly-nsfw-subplebbit';
|
||||
import useContentOptionsStore from '../../stores/use-content-options-store';
|
||||
import useFeedResetStore from '../../stores/use-feed-reset-store';
|
||||
|
||||
type SortDropdownProps = {
|
||||
sortBy: string;
|
||||
@@ -128,6 +129,12 @@ const Post = ({ post }: { post: Comment }) => {
|
||||
|
||||
const postComment = useComment({ commentCid: postCid });
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{(deleted || locked || removed) && (
|
||||
@@ -172,7 +179,7 @@ const Post = ({ post }: { post: Comment }) => {
|
||||
)}
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
{t('error')}: {error.message}
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
{isSingleComment ? (
|
||||
@@ -285,6 +292,12 @@ const PostPage = () => {
|
||||
const { hasAcceptedWarning } = useContentOptionsStore();
|
||||
const isBroadlyNsfwSubplebbit = useIsBroadlyNsfwSubplebbit(subplebbitAddress || '');
|
||||
|
||||
useEffect(() => {
|
||||
if (post?.error) {
|
||||
console.log(post.error);
|
||||
}
|
||||
}, [post?.error]);
|
||||
|
||||
const postTitle = post.title?.slice(0, 40) || post?.content?.slice(0, 40);
|
||||
const subplebbitTitle = subplebbit?.title || subplebbit?.shortAddress;
|
||||
useEffect(() => {
|
||||
@@ -303,6 +316,11 @@ const PostPage = () => {
|
||||
<Sidebar subplebbit={subplebbit} comment={post} settings={subplebbit?.settings} />
|
||||
</div>
|
||||
{isInPendingPostView && params?.accountCommentIndex ? <Post post={pendingPost} /> : isInPostContextView ? <PostWithContext post={post} /> : <Post post={post} />}
|
||||
{post?.error && (
|
||||
<div className={styles.fullError}>
|
||||
<ErrorDisplay error={post.error} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -147,3 +147,10 @@ div[data-viewport-type="window"] {
|
||||
margin-right: -3px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding-left: 10px;
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import AuthorSidebar from '../../components/author-sidebar';
|
||||
import Post from '../../components/post';
|
||||
import Reply from '../../components/reply';
|
||||
import styles from './profile.module.css';
|
||||
import ErrorDisplay from '../../components/error-display';
|
||||
|
||||
const pageSize = 10;
|
||||
const sortTypes: string[] = ['new', 'old'];
|
||||
@@ -135,15 +136,26 @@ const VirtualizedCommentList = ({ comments }: { comments: any[] }) => {
|
||||
|
||||
const Overview = () => {
|
||||
const { t } = useTranslation();
|
||||
const { accountComments } = useAccountComments();
|
||||
const { error, accountComments } = useAccountComments();
|
||||
const [sortType, setSortType] = useState('new');
|
||||
|
||||
const sortedComments = useMemo(() => {
|
||||
return [...accountComments].sort((a, b) => (sortType === 'new' ? b.timestamp - a.timestamp : a.timestamp - b.timestamp));
|
||||
}, [accountComments, sortType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
<SortDropdown onSortChange={setSortType} />
|
||||
{sortedComments.length === 0 ? <div className={styles.nothingFound}>{t('nothing_found')}</div> : <VirtualizedCommentList comments={sortedComments} />}
|
||||
</div>
|
||||
@@ -152,7 +164,7 @@ const Overview = () => {
|
||||
|
||||
const Comments = () => {
|
||||
const { t } = useTranslation();
|
||||
const { accountComments } = useAccountComments();
|
||||
const { error, accountComments } = useAccountComments();
|
||||
const [sortType, setSortType] = useState('new');
|
||||
|
||||
const replyComments = useMemo(() => accountComments?.filter((comment) => comment.parentCid) || [], [accountComments]);
|
||||
@@ -161,8 +173,19 @@ const Comments = () => {
|
||||
return [...replyComments].sort((a, b) => (sortType === 'new' ? b.timestamp - a.timestamp : a.timestamp - b.timestamp));
|
||||
}, [replyComments, sortType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
<SortDropdown onSortChange={setSortType} />
|
||||
{sortedComments.length === 0 ? <div className={styles.nothingFound}>{t('nothing_found')}</div> : <VirtualizedCommentList comments={sortedComments} />}
|
||||
</div>
|
||||
@@ -171,7 +194,7 @@ const Comments = () => {
|
||||
|
||||
const Submitted = () => {
|
||||
const { t } = useTranslation();
|
||||
const { accountComments } = useAccountComments();
|
||||
const { error, accountComments } = useAccountComments();
|
||||
const [sortType, setSortType] = useState('new');
|
||||
|
||||
const postComments = useMemo(() => accountComments?.filter((comment) => !comment.parentCid) || [], [accountComments]);
|
||||
@@ -180,8 +203,19 @@ const Submitted = () => {
|
||||
return [...postComments].sort((a, b) => (sortType === 'new' ? b.timestamp - a.timestamp : a.timestamp - b.timestamp));
|
||||
}, [postComments, sortType]);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
<SortDropdown onSortChange={setSortType} />
|
||||
{sortedComments.length === 0 ? <div className={styles.nothingFound}>{t('nothing_found')}</div> : <VirtualizedCommentList comments={sortedComments} />}
|
||||
</div>
|
||||
@@ -190,7 +224,7 @@ const Submitted = () => {
|
||||
|
||||
const VotedComments = ({ voteType }: { voteType: 1 | -1 }) => {
|
||||
const { t } = useTranslation();
|
||||
const { accountVotes } = useAccountVotes();
|
||||
const { error, accountVotes } = useAccountVotes();
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
const [sortType, setSortType] = useState('new');
|
||||
|
||||
@@ -203,8 +237,19 @@ const VotedComments = ({ voteType }: { voteType: 1 | -1 }) => {
|
||||
const paginatedCids = votedCommentCids.slice((currentPage - 1) * pageSize, currentPage * pageSize);
|
||||
const hasMore = currentPage * pageSize < votedCommentCids.length;
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
<SortDropdown onSortChange={setSortType} />
|
||||
{paginatedCids.length === 0 ? <div className={styles.nothingFound}>{t('nothing_found')}</div> : paginatedCids.map((cid) => <CommentItem key={cid} cid={cid} />)}
|
||||
<PaginationControls currentPage={currentPage} hasMore={hasMore} onPageChange={setCurrentPage} />
|
||||
|
||||
@@ -12,6 +12,7 @@ import useFeedResetStore from '../../stores/use-feed-reset-store';
|
||||
import { usePinnedPostsStore } from '../../stores/use-pinned-posts-store';
|
||||
import { useIsBroadlyNsfwSubplebbit } from '../../hooks/use-is-broadly-nsfw-subplebbit';
|
||||
import useTimeFilter, { isValidTimeFilterName } from '../../hooks/use-time-filter';
|
||||
import ErrorDisplay from '../../components/error-display';
|
||||
import LoadingEllipsis from '../../components/loading-ellipsis';
|
||||
import Over18Warning from '../../components/over-18-warning';
|
||||
import Post from '../../components/post';
|
||||
@@ -27,7 +28,6 @@ interface FooterProps {
|
||||
isOnline: boolean;
|
||||
started: boolean;
|
||||
isSubCreatedButNotYetPublished: boolean;
|
||||
error: Error | null;
|
||||
hasMore: boolean;
|
||||
timeFilterName: string;
|
||||
reset: () => void;
|
||||
@@ -43,7 +43,6 @@ const Footer = ({
|
||||
isOnline,
|
||||
started,
|
||||
isSubCreatedButNotYetPublished,
|
||||
error,
|
||||
hasMore,
|
||||
timeFilterName,
|
||||
reset,
|
||||
@@ -85,12 +84,6 @@ const Footer = ({
|
||||
const loadingString = (
|
||||
<>
|
||||
<div className={styles.stateString}>{loadingStateString === 'Failed' ? 'failed' : <LoadingEllipsis string={loadingStateString} />}</div>
|
||||
{error && (
|
||||
<div style={{ color: 'red' }}>
|
||||
<br />
|
||||
{t('error')}: {error.message}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -332,7 +325,6 @@ const Subplebbit = () => {
|
||||
isOnline,
|
||||
started,
|
||||
isSubCreatedButNotYetPublished,
|
||||
error: error || null,
|
||||
hasMore,
|
||||
timeFilterName: searchQuery ? 'all' : timeFilterName || '',
|
||||
reset,
|
||||
@@ -361,6 +353,12 @@ const Subplebbit = () => {
|
||||
const hasUnhiddenAnyNsfwCommunity = !hideAdultCommunities || !hideGoreCommunities || !hideAntiCommunities || !hideVulgarCommunities;
|
||||
const isBroadlyNsfwSubplebbit = useIsBroadlyNsfwSubplebbit(subplebbitAddress || '');
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [error]);
|
||||
|
||||
// page title
|
||||
useEffect(() => {
|
||||
document.title = title ? title : shortAddress || subplebbitAddress;
|
||||
@@ -373,6 +371,11 @@ const Subplebbit = () => {
|
||||
<div className={styles.sidebar}>
|
||||
<Sidebar subplebbit={subplebbit} isSubCreatedButNotYetPublished={started && isSubCreatedButNotYetPublished} settings={settings} reset={reset} />
|
||||
</div>
|
||||
{error && (
|
||||
<div className={styles.error}>
|
||||
<ErrorDisplay error={error} />
|
||||
</div>
|
||||
)}
|
||||
<div className={styles.feed}>
|
||||
<Virtuoso
|
||||
increaseViewportBy={{ bottom: 1200, top: 600 }}
|
||||
|
||||
@@ -340,3 +340,10 @@
|
||||
vertical-align: top;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.error {
|
||||
font-size: 12px;
|
||||
margin-top: -10px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
@@ -14,10 +14,12 @@ import {
|
||||
isSubplebbitsVotePassingView,
|
||||
isSubplebbitsVoteRejectingView,
|
||||
} from '../../lib/utils/view-utils';
|
||||
import useErrorStore from '../../stores/use-error-store';
|
||||
import { useDefaultSubplebbitAddresses, useDefaultSubplebbitTags } from '../../hooks/use-default-subplebbits';
|
||||
import { useDefaultSubplebbits } from '../../hooks/use-default-subplebbits';
|
||||
import useIsMobile from '../../hooks/use-is-mobile';
|
||||
import useIsSubplebbitOffline from '../../hooks/use-is-subplebbit-offline';
|
||||
import ErrorDisplay from '../../components/error-display';
|
||||
import Markdown from '../../components/markdown';
|
||||
import Label from '../../components/post/label';
|
||||
import Sidebar from '../../components/sidebar';
|
||||
@@ -108,7 +110,13 @@ const VoteTabs = () => {
|
||||
|
||||
const Infobar = () => {
|
||||
const account = useAccount();
|
||||
const { accountSubplebbits } = useAccountSubplebbits();
|
||||
const { accountSubplebbits, error: accountSubplebbitsError } = useAccountSubplebbits();
|
||||
const { setError } = useErrorStore();
|
||||
|
||||
useEffect(() => {
|
||||
setError('Infobar_useAccountSubplebbits', accountSubplebbitsError);
|
||||
}, [accountSubplebbitsError, setError]);
|
||||
|
||||
const subscriptions = account?.subscriptions || [];
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
@@ -285,7 +293,12 @@ const Subplebbit = ({ subplebbit, tags, index }: SubplebbitProps) => {
|
||||
|
||||
const AccountSubplebbits = ({ viewRole }: { viewRole: string }) => {
|
||||
const account = useAccount();
|
||||
const { accountSubplebbits } = useAccountSubplebbits();
|
||||
const { accountSubplebbits, error: accountSubplebbitsError } = useAccountSubplebbits();
|
||||
const { setError } = useErrorStore();
|
||||
|
||||
useEffect(() => {
|
||||
setError('AccountSubplebbits_useAccountSubplebbits', accountSubplebbitsError);
|
||||
}, [accountSubplebbitsError, setError, viewRole]);
|
||||
|
||||
const filteredSubplebbitsArray = useMemo(() => {
|
||||
return Object.values(accountSubplebbits).filter((subplebbit: any) => {
|
||||
@@ -300,7 +313,13 @@ const AccountSubplebbits = ({ viewRole }: { viewRole: string }) => {
|
||||
|
||||
const SubscriberSubplebbits = () => {
|
||||
const account = useAccount();
|
||||
const { subplebbits } = useSubplebbits({ subplebbitAddresses: account?.subscriptions });
|
||||
const { subplebbits, error: subplebbitsError } = useSubplebbits({ subplebbitAddresses: account?.subscriptions });
|
||||
const { setError } = useErrorStore();
|
||||
|
||||
useEffect(() => {
|
||||
setError('SubscriberSubplebbits_useSubplebbits', subplebbitsError);
|
||||
}, [subplebbitsError, setError]);
|
||||
|
||||
const subplebbitsArray = useMemo(() => Object.values(subplebbits), [subplebbits]);
|
||||
return subplebbitsArray?.map((subplebbit, index) => subplebbit && <Subplebbit key={index} subplebbit={subplebbit} index={index} />).filter(Boolean);
|
||||
};
|
||||
@@ -314,7 +333,13 @@ const AllDefaultSubplebbits = () => {
|
||||
const urlTag = pathname.includes('/tag/') ? pathname.split('/').pop() : undefined;
|
||||
const currentTag = urlTag && validTags.includes(urlTag) ? urlTag : undefined;
|
||||
|
||||
const { subplebbits } = useSubplebbits({ subplebbitAddresses });
|
||||
const { subplebbits, error: subplebbitsError } = useSubplebbits({ subplebbitAddresses });
|
||||
const { setError } = useErrorStore();
|
||||
|
||||
useEffect(() => {
|
||||
setError('AllDefaultSubplebbits_useSubplebbits', subplebbitsError);
|
||||
}, [subplebbitsError, setError]);
|
||||
|
||||
const subplebbitsArray = useMemo(() => Object.values(subplebbits), [subplebbits]);
|
||||
|
||||
return subplebbitsArray
|
||||
@@ -329,11 +354,21 @@ const AllDefaultSubplebbits = () => {
|
||||
|
||||
const AllAccountSubplebbits = () => {
|
||||
const account = useAccount();
|
||||
const { accountSubplebbits } = useAccountSubplebbits();
|
||||
const { accountSubplebbits, error: accountSubplebbitsError } = useAccountSubplebbits();
|
||||
const { setError } = useErrorStore();
|
||||
|
||||
useEffect(() => {
|
||||
setError('AllAccountSubplebbits_useAccountSubplebbits', accountSubplebbitsError);
|
||||
}, [accountSubplebbitsError, setError]);
|
||||
|
||||
const accountSubplebbitAddresses = Object.keys(accountSubplebbits);
|
||||
const subscriptionsArray = account?.subscriptions ?? [];
|
||||
const uniqueAddresses = Array.from(new Set([...accountSubplebbitAddresses, ...subscriptionsArray]));
|
||||
const { subplebbits } = useSubplebbits({ subplebbitAddresses: uniqueAddresses });
|
||||
const { subplebbits, error: subplebbitsError } = useSubplebbits({ subplebbitAddresses: uniqueAddresses });
|
||||
|
||||
useEffect(() => {
|
||||
setError('AllAccountSubplebbits_useSubplebbits', subplebbitsError);
|
||||
}, [subplebbitsError, setError]);
|
||||
const subplebbitsArray = useMemo(() => Object.values(subplebbits ?? {}), [subplebbits]);
|
||||
return subplebbitsArray?.map((subplebbit, index) => subplebbit && <Subplebbit key={index} subplebbit={subplebbit} index={index} />).filter(Boolean);
|
||||
};
|
||||
@@ -341,6 +376,24 @@ const AllAccountSubplebbits = () => {
|
||||
const Subplebbits = () => {
|
||||
const { t } = useTranslation();
|
||||
const location = useLocation();
|
||||
const { errors, clearAllErrors } = useErrorStore();
|
||||
|
||||
// Clear errors on component unmount or location change
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearAllErrors();
|
||||
};
|
||||
}, [location, clearAllErrors]);
|
||||
|
||||
// Console log errors
|
||||
useEffect(() => {
|
||||
Object.entries(errors).forEach(([source, errorObj]) => {
|
||||
if (errorObj) {
|
||||
console.error(`Error from ${source}:`, errorObj.message, errorObj.stack);
|
||||
}
|
||||
});
|
||||
}, [errors]);
|
||||
|
||||
const isInSubplebbitsSubscriberView = isSubplebbitsSubscriberView(location.pathname);
|
||||
const isInSubplebbitsModeratorView = isSubplebbitsModeratorView(location.pathname);
|
||||
const isInSubplebbitsAdminView = isSubplebbitsAdminView(location.pathname);
|
||||
@@ -385,6 +438,32 @@ const Subplebbits = () => {
|
||||
document.title = documentTitle;
|
||||
}, [documentTitle]);
|
||||
|
||||
const renderErrors = () => {
|
||||
const errorsToDisplay: JSX.Element[] = [];
|
||||
Object.entries(errors).forEach(([source, errorObj]) => {
|
||||
if (!errorObj) return;
|
||||
|
||||
if (
|
||||
source === 'Infobar_useAccountSubplebbits' &&
|
||||
(isInSubplebbitsView || isInSubplebbitsSubscriberView || isInSubplebbitsModeratorView || isInSubplebbitsAdminView || isInSubplebbitsOwnerView)
|
||||
) {
|
||||
errorsToDisplay.push(<ErrorDisplay key={source} error={errorObj} />);
|
||||
} else if (source === 'AccountSubplebbits_useAccountSubplebbits' && (isInSubplebbitsModeratorView || isInSubplebbitsAdminView || isInSubplebbitsOwnerView)) {
|
||||
errorsToDisplay.push(<ErrorDisplay key={source} error={errorObj} />);
|
||||
} else if (source === 'SubscriberSubplebbits_useSubplebbits' && isInSubplebbitsSubscriberView) {
|
||||
errorsToDisplay.push(<ErrorDisplay key={source} error={errorObj} />);
|
||||
} else if (source === 'AllDefaultSubplebbits_useSubplebbits' && isInSubplebbitsVoteView) {
|
||||
errorsToDisplay.push(<ErrorDisplay key={source} error={errorObj} />);
|
||||
} else if (source === 'AllAccountSubplebbits_useAccountSubplebbits' && isInSubplebbitsView) {
|
||||
errorsToDisplay.push(<ErrorDisplay key={source} error={errorObj} />);
|
||||
} else if (source === 'AllAccountSubplebbits_useSubplebbits' && isInSubplebbitsView) {
|
||||
// Avoid duplicate key if both errors from AllAccountSubplebbits are present
|
||||
errorsToDisplay.push(<ErrorDisplay key={`${source}_subplebbits`} error={errorObj} />);
|
||||
}
|
||||
});
|
||||
return errorsToDisplay;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<div className={styles.sidebar}>
|
||||
@@ -396,6 +475,7 @@ const Subplebbits = () => {
|
||||
<VoteTabs />
|
||||
)}
|
||||
<Infobar />
|
||||
<div className={styles.error}>{renderErrors()}</div>
|
||||
{isInSubplebbitsVoteView && <AllDefaultSubplebbits />}
|
||||
{(isInSubplebbitsModeratorView || isInSubplebbitsAdminView || isInSubplebbitsOwnerView) && <AccountSubplebbits viewRole={viewRole} />}
|
||||
{isInSubplebbitsSubscriberView && <SubscriberSubplebbits />}
|
||||
|
||||
Reference in New Issue
Block a user