mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(mod queue): stop resurfacing stale pending history (#1130)
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
import { describe, expect, it } from 'vitest';
|
import { describe, expect, it } from 'vitest';
|
||||||
import { filterVisibleModQueueFeed, getModQueueCommentRoute, getQueuedCommentRouteState } from '../mod-queue-utils';
|
import {
|
||||||
|
filterVisibleModQueueFeed,
|
||||||
|
getModQueueCommentRoute,
|
||||||
|
getQueuedCommentRouteState,
|
||||||
|
getVisibleQueuedCommentHistory,
|
||||||
|
shouldKeepQueuedCommentHistory,
|
||||||
|
} from '../mod-queue-utils';
|
||||||
|
|
||||||
describe('mod queue utils', () => {
|
describe('mod queue utils', () => {
|
||||||
it('keeps all queue comments unless they were locally dismissed', () => {
|
it('keeps all queue comments unless they were locally dismissed', () => {
|
||||||
@@ -31,6 +37,30 @@ describe('mod queue utils', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps only terminal local moderation states in queue history', () => {
|
||||||
|
expect(shouldKeepQueuedCommentHistory({ cid: 'pending', pendingApproval: true })).toBe(false);
|
||||||
|
expect(shouldKeepQueuedCommentHistory({ cid: 'published', pendingApproval: false })).toBe(false);
|
||||||
|
expect(shouldKeepQueuedCommentHistory({ cid: 'approved', approved: true, pendingApproval: false })).toBe(true);
|
||||||
|
expect(shouldKeepQueuedCommentHistory({ cid: 'rejected', approved: false, pendingApproval: false })).toBe(true);
|
||||||
|
expect(shouldKeepQueuedCommentHistory({ cid: 'removed', pendingApproval: true, removed: true })).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not resurface stale pending history after the live feed drops it', () => {
|
||||||
|
const feed = [{ cid: 'live-pending', communityAddress: 'tech.eth', pendingApproval: true }];
|
||||||
|
const history = [
|
||||||
|
{ cid: 'stale-pending', communityAddress: 'tech.eth', pendingApproval: true },
|
||||||
|
{ cid: 'live-pending', communityAddress: 'tech.eth', pendingApproval: true },
|
||||||
|
{ cid: 'approved', approved: true, communityAddress: 'tech.eth', pendingApproval: false },
|
||||||
|
{ cid: 'rejected', approved: false, communityAddress: 'tech.eth', pendingApproval: false },
|
||||||
|
{ cid: 'other-board-approved', approved: true, communityAddress: 'g.eth', pendingApproval: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(getVisibleQueuedCommentHistory(feed, history, ['tech.eth'])).toEqual([
|
||||||
|
{ cid: 'approved', approved: true, communityAddress: 'tech.eth', pendingApproval: false },
|
||||||
|
{ cid: 'rejected', approved: false, communityAddress: 'tech.eth', pendingApproval: false },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('builds excerpt routes from the comment permalink cid', () => {
|
it('builds excerpt routes from the comment permalink cid', () => {
|
||||||
expect(getModQueueCommentRoute('g', 'reply-cid')).toBe('/g/thread/reply-cid');
|
expect(getModQueueCommentRoute('g', 'reply-cid')).toBe('/g/thread/reply-cid');
|
||||||
expect(getModQueueCommentRoute('g', undefined)).toBeUndefined();
|
expect(getModQueueCommentRoute('g', undefined)).toBeUndefined();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { Comment } from '@bitsocial/bitsocial-react-hooks';
|
import type { Comment } from '@bitsocial/bitsocial-react-hooks';
|
||||||
import { getCommentCommunityAddress } from './comment-utils';
|
import { getCommentCommunityAddress } from './comment-utils';
|
||||||
|
import { isPendingApprovalRejected } from './pending-approval-moderation';
|
||||||
|
import { areSameBoardAddress } from './route-utils';
|
||||||
import { getThreadTopNavigationState } from './thread-scroll-utils';
|
import { getThreadTopNavigationState } from './thread-scroll-utils';
|
||||||
|
|
||||||
type ModQueueCommentLike = {
|
type ModQueueCommentLike = {
|
||||||
@@ -102,6 +104,27 @@ export const getQueuedCommentRouteState = (comment: ModQueueCommentLike | undefi
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const shouldKeepQueuedCommentHistory = (comment: ModQueueCommentLike | undefined): boolean => comment?.approved === true || isPendingApprovalRejected(comment);
|
||||||
|
|
||||||
|
export const getVisibleQueuedCommentHistory = <T extends ModQueueCommentLike>(
|
||||||
|
feed: readonly ModQueueCommentLike[],
|
||||||
|
queuedCommentHistory: readonly T[],
|
||||||
|
communityAddresses: readonly string[],
|
||||||
|
): T[] => {
|
||||||
|
const liveCids = feed.reduce<Set<string>>((cids, comment) => {
|
||||||
|
if (comment.cid) cids.add(comment.cid);
|
||||||
|
return cids;
|
||||||
|
}, new Set());
|
||||||
|
|
||||||
|
return queuedCommentHistory.filter((comment) => {
|
||||||
|
const commentCommunityAddress = getCommentCommunityAddress(comment);
|
||||||
|
if (!comment.cid || !shouldKeepQueuedCommentHistory(comment) || liveCids.has(comment.cid) || !commentCommunityAddress) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return communityAddresses.some((communityAddress) => areSameBoardAddress(communityAddress, commentCommunityAddress));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const filterVisibleModQueueFeed = <T extends ModQueueCommentLike>(
|
export const filterVisibleModQueueFeed = <T extends ModQueueCommentLike>(
|
||||||
feed: T[],
|
feed: T[],
|
||||||
selectedBoardFilter: string | null,
|
selectedBoardFilter: string | null,
|
||||||
|
|||||||
@@ -26,7 +26,14 @@ import useChallengesStore from '../../stores/use-challenges-store';
|
|||||||
import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils';
|
import { alertChallengeVerificationFailed } from '../../lib/utils/challenge-utils';
|
||||||
import { getCommentCommunityAddress } from '../../lib/utils/comment-utils';
|
import { getCommentCommunityAddress } from '../../lib/utils/comment-utils';
|
||||||
import { formatErrorForDisplay } from '../../lib/utils/error-utils';
|
import { formatErrorForDisplay } from '../../lib/utils/error-utils';
|
||||||
import { filterVisibleModQueueFeed, getModQueueCommentRoute, getQueuedCommentRouteState, getQueuedCommentSnapshot } from '../../lib/utils/mod-queue-utils';
|
import {
|
||||||
|
filterVisibleModQueueFeed,
|
||||||
|
getModQueueCommentRoute,
|
||||||
|
getQueuedCommentRouteState,
|
||||||
|
getQueuedCommentSnapshot,
|
||||||
|
getVisibleQueuedCommentHistory,
|
||||||
|
shouldKeepQueuedCommentHistory,
|
||||||
|
} from '../../lib/utils/mod-queue-utils';
|
||||||
import Tooltip from '../../components/tooltip';
|
import Tooltip from '../../components/tooltip';
|
||||||
import { useAccountCommunityAddresses } from '../../hooks/use-account-community-addresses';
|
import { useAccountCommunityAddresses } from '../../hooks/use-account-community-addresses';
|
||||||
import { useCommunityIdentifier, useCommunityIdentifiers } from '../../hooks/use-community-identifiers';
|
import { useCommunityIdentifier, useCommunityIdentifiers } from '../../hooks/use-community-identifiers';
|
||||||
@@ -908,7 +915,7 @@ const ModQueueView = ({ boardIdentifier: propBoardIdentifier }: ModQueueViewProp
|
|||||||
() =>
|
() =>
|
||||||
feed.flatMap((comment) => {
|
feed.flatMap((comment) => {
|
||||||
const snapshot = getQueuedCommentSnapshot(comment);
|
const snapshot = getQueuedCommentSnapshot(comment);
|
||||||
return snapshot ? [snapshot] : [];
|
return snapshot && shouldKeepQueuedCommentHistory(snapshot) ? [snapshot] : [];
|
||||||
}),
|
}),
|
||||||
[feed],
|
[feed],
|
||||||
);
|
);
|
||||||
@@ -918,24 +925,10 @@ const ModQueueView = ({ boardIdentifier: propBoardIdentifier }: ModQueueViewProp
|
|||||||
}
|
}
|
||||||
}, [queuedCommentSnapshots, rememberCommentsInQueue]);
|
}, [queuedCommentSnapshots, rememberCommentsInQueue]);
|
||||||
|
|
||||||
const feedWithHistory = useMemo(() => {
|
const feedWithHistory = useMemo(
|
||||||
const liveCids = feed.reduce<Set<string>>((cids, comment) => {
|
() => [...feed, ...(getVisibleQueuedCommentHistory(feed, queuedCommentHistory, communityAddresses) as Comment[])],
|
||||||
if (comment.cid) cids.add(comment.cid);
|
[communityAddresses, feed, queuedCommentHistory],
|
||||||
return cids;
|
);
|
||||||
}, new Set());
|
|
||||||
return [
|
|
||||||
...feed,
|
|
||||||
...(queuedCommentHistory.filter((comment) => {
|
|
||||||
const commentCommunityAddress = getCommentCommunityAddress(comment);
|
|
||||||
return (
|
|
||||||
comment.cid &&
|
|
||||||
!liveCids.has(comment.cid) &&
|
|
||||||
commentCommunityAddress &&
|
|
||||||
communityAddresses.some((communityAddress) => areSameBoardAddress(communityAddress, commentCommunityAddress))
|
|
||||||
);
|
|
||||||
}) as Comment[]),
|
|
||||||
];
|
|
||||||
}, [communityAddresses, feed, queuedCommentHistory]);
|
|
||||||
|
|
||||||
const dismissedCommentCidSet = useMemo(() => new Set(dismissedCommentCids), [dismissedCommentCids]);
|
const dismissedCommentCidSet = useMemo(() => new Set(dismissedCommentCids), [dismissedCommentCids]);
|
||||||
const filteredFeed = useMemo(
|
const filteredFeed = useMemo(
|
||||||
|
|||||||
Reference in New Issue
Block a user