mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
show newly published account comments after pinned threads
This commit is contained in:
@@ -31,29 +31,38 @@ const useCatalogFeedRows = (columnCount: number, feed: any, isFeedLoaded: boolea
|
|||||||
|
|
||||||
const _feed = [...feed];
|
const _feed = [...feed];
|
||||||
|
|
||||||
// show account comments instantly in the feed instead of waiting for the next feed update, then hide them when they are in the feed
|
// show account comments instantly in the feed once published (cid defined), instead of waiting for the feed to update
|
||||||
accountComments.forEach((comment) => {
|
const filteredComments = accountComments.filter((comment) => {
|
||||||
const { cid, deleted, link, postCid, removed, state, subplebbitAddress } = comment || {};
|
const { cid, deleted, link, postCid, removed, state, subplebbitAddress } = comment || {};
|
||||||
const commentMediaInfo = getCommentMediaInfo(comment);
|
const commentMediaInfo = getCommentMediaInfo(comment);
|
||||||
const isMediaShowed = getHasThumbnail(commentMediaInfo, link);
|
const isMediaShowed = getHasThumbnail(commentMediaInfo, link);
|
||||||
|
|
||||||
if (
|
return (
|
||||||
!deleted &&
|
!deleted &&
|
||||||
!removed &&
|
!removed &&
|
||||||
state === 'succeeded' &&
|
state === 'succeeded' &&
|
||||||
(!showTextOnlyThreads || (showTextOnlyThreads && !isMediaShowed)) &&
|
(showTextOnlyThreads || (!showTextOnlyThreads && isMediaShowed)) &&
|
||||||
cid &&
|
cid &&
|
||||||
cid === postCid &&
|
cid === postCid &&
|
||||||
subplebbitAddress === address &&
|
subplebbitAddress === address &&
|
||||||
!_feed.some((feedItem) => feedItem.cid === cid)
|
!_feed.some((feedItem) => feedItem.cid === cid)
|
||||||
) {
|
);
|
||||||
_feed.unshift({
|
|
||||||
...comment,
|
|
||||||
isAccountComment: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// show newest account comment at the top of the feed but after pinned posts
|
||||||
|
const lastPinnedIndex = _feed.map((post) => post.pinned).lastIndexOf(true);
|
||||||
|
if (filteredComments.length > 0) {
|
||||||
|
_feed.splice(
|
||||||
|
lastPinnedIndex + 1,
|
||||||
|
0,
|
||||||
|
...filteredComments.map((comment) => ({
|
||||||
|
...comment,
|
||||||
|
isAccountComment: true,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add subplebbit description and rules as fake posts at the top of the feed
|
||||||
if ((description && description.length > 0 && (showTextOnlyThreads || (!showTextOnlyThreads && suggested?.avatarUrl))) || isInAllView) {
|
if ((description && description.length > 0 && (showTextOnlyThreads || (!showTextOnlyThreads && suggested?.avatarUrl))) || isInAllView) {
|
||||||
_feed.unshift({
|
_feed.unshift({
|
||||||
isDescription: true,
|
isDescription: true,
|
||||||
|
|||||||
+92
-85
@@ -20,28 +20,6 @@ import SubplebbitRules from '../../components/subplebbit-rules';
|
|||||||
|
|
||||||
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
const lastVirtuosoStates: { [key: string]: StateSnapshot } = {};
|
||||||
|
|
||||||
// show account comments instantly in the feed instead of waiting for the next feed update, then hide them when they are in the feed
|
|
||||||
const AccountCommentsNotYetInFeed = ({ subplebbitAddress, feed }: { subplebbitAddress: string; feed: any }) => {
|
|
||||||
const { accountComments } = useAccountComments();
|
|
||||||
|
|
||||||
const _feed = [...feed];
|
|
||||||
|
|
||||||
const filteredComments = accountComments.filter((comment) => {
|
|
||||||
const { cid, deleted, postCid, removed, state } = comment || {};
|
|
||||||
return (
|
|
||||||
!deleted &&
|
|
||||||
!removed &&
|
|
||||||
state === 'succeeded' &&
|
|
||||||
cid &&
|
|
||||||
cid === postCid &&
|
|
||||||
comment?.subplebbitAddress === subplebbitAddress &&
|
|
||||||
!_feed.some((post) => post.cid === cid)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return filteredComments.map((comment) => <Post key={comment.cid} post={comment} />);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Board = () => {
|
const Board = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -67,22 +45,60 @@ const Board = () => {
|
|||||||
const { sortType } = useSortingStore();
|
const { sortType } = useSortingStore();
|
||||||
const { timeFilterSeconds } = useTimeFilter();
|
const { timeFilterSeconds } = useTimeFilter();
|
||||||
|
|
||||||
const feedOptions: any = {
|
const feedOptions: any = useMemo(
|
||||||
subplebbitAddresses,
|
() => ({
|
||||||
sortType,
|
subplebbitAddresses,
|
||||||
postsPerPage: isInAllView || isInSubscriptionsView ? 5 : 25,
|
sortType,
|
||||||
};
|
postsPerPage: isInAllView || isInSubscriptionsView ? 5 : 25,
|
||||||
|
...(isInAllView || isInSubscriptionsView ? { newerThan: timeFilterSeconds } : {}),
|
||||||
if (isInAllView || isInSubscriptionsView) {
|
}),
|
||||||
feedOptions.newerThan = timeFilterSeconds;
|
[subplebbitAddresses, sortType, timeFilterSeconds, isInAllView, isInSubscriptionsView],
|
||||||
}
|
);
|
||||||
|
|
||||||
const { feed, hasMore, loadMore, reset } = useFeed(feedOptions);
|
const { feed, hasMore, loadMore, reset } = useFeed(feedOptions);
|
||||||
|
const { accountComments } = useAccountComments();
|
||||||
|
|
||||||
|
const resetTriggeredRef = useRef(false);
|
||||||
|
|
||||||
const setResetFunction = useFeedResetStore((state) => state.setResetFunction);
|
const setResetFunction = useFeedResetStore((state) => state.setResetFunction);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setResetFunction(reset);
|
setResetFunction(reset);
|
||||||
}, [reset, setResetFunction]);
|
}, [reset, setResetFunction, feed]);
|
||||||
|
|
||||||
|
// show account comments instantly in the feed once published (cid defined), instead of waiting for the feed to update
|
||||||
|
const filteredComments = useMemo(
|
||||||
|
() =>
|
||||||
|
accountComments.filter((comment) => {
|
||||||
|
const { cid, deleted, postCid, removed, state } = comment || {};
|
||||||
|
return (
|
||||||
|
!deleted &&
|
||||||
|
!removed &&
|
||||||
|
state === 'succeeded' &&
|
||||||
|
cid &&
|
||||||
|
cid === postCid &&
|
||||||
|
comment?.subplebbitAddress === subplebbitAddress &&
|
||||||
|
!feed.some((post) => post.cid === cid)
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
[accountComments, subplebbitAddress, feed],
|
||||||
|
);
|
||||||
|
|
||||||
|
// show newest account comment at the top of the feed but after pinned posts
|
||||||
|
const combinedFeed = useMemo(() => {
|
||||||
|
const newFeed = [...feed];
|
||||||
|
const lastPinnedIndex = newFeed.map((post) => post.pinned).lastIndexOf(true);
|
||||||
|
if (filteredComments.length > 0) {
|
||||||
|
newFeed.splice(lastPinnedIndex + 1, 0, ...filteredComments);
|
||||||
|
}
|
||||||
|
return newFeed;
|
||||||
|
}, [feed, filteredComments]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (filteredComments.length > 0 && !resetTriggeredRef.current) {
|
||||||
|
reset();
|
||||||
|
resetTriggeredRef.current = true;
|
||||||
|
}
|
||||||
|
}, [filteredComments, reset]);
|
||||||
|
|
||||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||||
const { createdAt, description, error, rules, shortAddress, state, suggested } = subplebbit || {};
|
const { createdAt, description, error, rules, shortAddress, state, suggested } = subplebbit || {};
|
||||||
@@ -90,6 +106,7 @@ const Board = () => {
|
|||||||
|
|
||||||
const { activeCid, closeModal, openReplyModal, showReplyModal, scrollY } = useReplyModal();
|
const { activeCid, closeModal, openReplyModal, showReplyModal, scrollY } = useReplyModal();
|
||||||
|
|
||||||
|
const { blocked, unblock } = useBlock({ address: subplebbitAddress });
|
||||||
const loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading');
|
const loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading');
|
||||||
const loadingString = (
|
const loadingString = (
|
||||||
<div className={styles.stateString}>
|
<div className={styles.stateString}>
|
||||||
@@ -97,6 +114,10 @@ const Board = () => {
|
|||||||
<span className='red'>{state}</span>
|
<span className='red'>{state}</span>
|
||||||
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
|
) : isInSubscriptionsView && subscriptions?.length === 0 ? (
|
||||||
t('not_subscribed_to_any_board')
|
t('not_subscribed_to_any_board')
|
||||||
|
) : blocked ? (
|
||||||
|
'you have blocked this board'
|
||||||
|
) : !hasMore && feed.length === 0 ? (
|
||||||
|
t('no_posts')
|
||||||
) : (
|
) : (
|
||||||
<LoadingEllipsis string={loadingStateString} />
|
<LoadingEllipsis string={loadingStateString} />
|
||||||
)}
|
)}
|
||||||
@@ -109,40 +130,8 @@ const Board = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const { blocked, unblock } = useBlock({ address: subplebbitAddress });
|
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
let footerContent;
|
return <div className={styles.footer}>{loadingString}</div>;
|
||||||
if (feed.length === 0) {
|
|
||||||
if (blocked) {
|
|
||||||
footerContent = 'you have blocked this board';
|
|
||||||
} else {
|
|
||||||
footerContent = t('no_posts');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (hasMore || subplebbitAddresses.length === 0) {
|
|
||||||
footerContent = loadingString;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className={styles.footer}>
|
|
||||||
{footerContent}
|
|
||||||
{blocked && (
|
|
||||||
<>
|
|
||||||
[
|
|
||||||
<span
|
|
||||||
className={styles.button}
|
|
||||||
onClick={() => {
|
|
||||||
unblock();
|
|
||||||
reset();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Unblock
|
|
||||||
</span>
|
|
||||||
]
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// save the last Virtuoso state to restore it when navigating back
|
// save the last Virtuoso state to restore it when navigating back
|
||||||
@@ -170,7 +159,7 @@ const Board = () => {
|
|||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
{location.pathname.endsWith('/settings') && <SettingsModal />}
|
{location.pathname.endsWith('/settings') && <SettingsModal />}
|
||||||
{showReplyModal && activeCid && <ReplyModal closeModal={closeModal} parentCid={activeCid} scrollY={scrollY} />}
|
{showReplyModal && activeCid && <ReplyModal closeModal={closeModal} parentCid={activeCid} scrollY={scrollY} />}
|
||||||
{feed.length > 0 && (
|
{feed.length !== 0 ? (
|
||||||
<>
|
<>
|
||||||
{rules && rules.length > 0 && <SubplebbitRules subplebbitAddress={subplebbitAddress} createdAt={createdAt} rules={rules} />}
|
{rules && rules.length > 0 && <SubplebbitRules subplebbitAddress={subplebbitAddress} createdAt={createdAt} rules={rules} />}
|
||||||
{((description && description.length > 0) || isInAllView) && (
|
{((description && description.length > 0) || isInAllView) && (
|
||||||
@@ -183,26 +172,44 @@ const Board = () => {
|
|||||||
title={title}
|
title={title}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{subplebbitAddress && <AccountCommentsNotYetInFeed subplebbitAddress={subplebbitAddress} feed={feed} />}
|
<Virtuoso
|
||||||
</>
|
increaseViewportBy={{ bottom: 1200, top: 1200 }}
|
||||||
)}
|
totalCount={combinedFeed.length}
|
||||||
<Virtuoso
|
data={combinedFeed}
|
||||||
increaseViewportBy={{ bottom: 1200, top: 1200 }}
|
itemContent={(index, post) => {
|
||||||
totalCount={feed?.length || 0}
|
const { deleted, locked, removed } = post || {};
|
||||||
data={feed}
|
const isThreadClosed = deleted || locked || removed;
|
||||||
itemContent={(index, post) => {
|
|
||||||
const { deleted, locked, removed } = post || {};
|
|
||||||
const isThreadClosed = deleted || locked || removed;
|
|
||||||
|
|
||||||
return <Post index={index} post={post} openReplyModal={isThreadClosed ? () => alert(t('thread_closed_alert')) : openReplyModal} />;
|
return <Post index={index} post={post} openReplyModal={isThreadClosed ? () => alert(t('thread_closed_alert')) : openReplyModal} />;
|
||||||
}}
|
}}
|
||||||
useWindowScroll={true}
|
useWindowScroll={true}
|
||||||
components={{ Footer }}
|
components={{ Footer }}
|
||||||
endReached={loadMore}
|
endReached={loadMore}
|
||||||
ref={virtuosoRef}
|
ref={virtuosoRef}
|
||||||
restoreStateFrom={lastVirtuosoState}
|
restoreStateFrom={lastVirtuosoState}
|
||||||
initialScrollTop={lastVirtuosoState?.scrollTop}
|
initialScrollTop={lastVirtuosoState?.scrollTop}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className={styles.footer}>
|
||||||
|
{loadingString}
|
||||||
|
{blocked && (
|
||||||
|
<>
|
||||||
|
[
|
||||||
|
<span
|
||||||
|
className={styles.button}
|
||||||
|
onClick={() => {
|
||||||
|
unblock();
|
||||||
|
reset();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Unblock
|
||||||
|
</span>
|
||||||
|
]
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user