mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix(mod-queue): preserve pending reject state after refresh
This commit is contained in:
@@ -8,6 +8,7 @@ import styles from '../../views/post/post.module.css';
|
||||
import { CommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail, getMediaDimensions } from '../../lib/utils/media-utils';
|
||||
import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/post-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { approvePendingCommentModeration, isPendingApprovalRejected, rejectPendingCommentModeration } from '../../lib/utils/pending-approval-moderation';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isModQueueView, isModView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { formatUserIDForDisplay, truncateWithEllipsisInMiddle } from '../../lib/utils/string-utils';
|
||||
@@ -131,7 +132,7 @@ const PostInfo = ({
|
||||
} = usePublishCommentModeration({
|
||||
commentCid: cid,
|
||||
subplebbitAddress: shouldShowPendingApprovalButtons ? subplebbitAddress : undefined,
|
||||
commentModeration: { approved: true },
|
||||
commentModeration: approvePendingCommentModeration,
|
||||
onChallenge: async (...args: any) => {
|
||||
addChallenge([...args, post]);
|
||||
},
|
||||
@@ -150,7 +151,7 @@ const PostInfo = ({
|
||||
} = usePublishCommentModeration({
|
||||
commentCid: cid,
|
||||
subplebbitAddress: shouldShowPendingApprovalButtons ? subplebbitAddress : undefined,
|
||||
commentModeration: { removed: true },
|
||||
commentModeration: rejectPendingCommentModeration,
|
||||
onChallenge: async (...args: any) => {
|
||||
addChallenge([...args, post]);
|
||||
},
|
||||
@@ -208,7 +209,7 @@ const PostInfo = ({
|
||||
// Check if post is awaiting approval and over threshold (for mod queue view)
|
||||
const approved = post?.approved;
|
||||
const alreadyApproved = approved === true;
|
||||
const alreadyRejected = removed === true;
|
||||
const alreadyRejected = isPendingApprovalRejected(post);
|
||||
const isAwaitingApproval = isInModQueueView && !alreadyApproved && !alreadyRejected;
|
||||
const timeWaiting = timestamp ? currentTime - timestamp : 0;
|
||||
const alertThresholdSeconds = getAlertThresholdSeconds();
|
||||
|
||||
@@ -9,6 +9,7 @@ import { shouldShowSnow } from '../../lib/snow';
|
||||
import { getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { approvePendingCommentModeration, isPendingApprovalRejected, rejectPendingCommentModeration } from '../../lib/utils/pending-approval-moderation';
|
||||
import { isAllView, isModQueueView, isModView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import { formatUserIDForDisplay } from '../../lib/utils/string-utils';
|
||||
import useModQueueStore from '../../stores/use-mod-queue-store';
|
||||
@@ -103,7 +104,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
|
||||
} = usePublishCommentModeration({
|
||||
commentCid: cid,
|
||||
subplebbitAddress: shouldShowPendingApprovalButtons ? subplebbitAddress : undefined,
|
||||
commentModeration: { approved: true },
|
||||
commentModeration: approvePendingCommentModeration,
|
||||
onChallenge: async (...args: any) => {
|
||||
addChallenge([...args, post]);
|
||||
},
|
||||
@@ -122,7 +123,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
|
||||
} = usePublishCommentModeration({
|
||||
commentCid: cid,
|
||||
subplebbitAddress: shouldShowPendingApprovalButtons ? subplebbitAddress : undefined,
|
||||
commentModeration: { removed: true },
|
||||
commentModeration: rejectPendingCommentModeration,
|
||||
onChallenge: async (...args: any) => {
|
||||
addChallenge([...args, post]);
|
||||
},
|
||||
@@ -182,7 +183,7 @@ const PostInfoAndMedia = ({ post, postReplyCount = 0, roles, threadNumber }: Pos
|
||||
// Check if post is awaiting approval and over threshold (for mod queue view)
|
||||
const approved = post?.approved;
|
||||
const alreadyApproved = approved === true;
|
||||
const alreadyRejected = removed === true;
|
||||
const alreadyRejected = isPendingApprovalRejected(post);
|
||||
const isAwaitingApproval = isInModQueueView && !alreadyApproved && !alreadyRejected;
|
||||
const timeWaiting = timestamp ? currentTime - timestamp : 0;
|
||||
const alertThresholdSeconds = getAlertThresholdSeconds();
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { approvePendingCommentModeration, isPendingApprovalAwaiting, isPendingApprovalRejected, rejectPendingCommentModeration } from '../pending-approval-moderation';
|
||||
|
||||
describe('pending approval moderation utils', () => {
|
||||
it('publishes approval with approved=true', () => {
|
||||
expect(approvePendingCommentModeration).toEqual({ approved: true });
|
||||
});
|
||||
|
||||
it('publishes rejection with approved=false and no removed flag', () => {
|
||||
expect(rejectPendingCommentModeration).toEqual({ approved: false });
|
||||
expect('removed' in rejectPendingCommentModeration).toBe(false);
|
||||
});
|
||||
|
||||
it('treats pending approved=false as rejected for display', () => {
|
||||
expect(isPendingApprovalRejected({ pendingApproval: true, approved: false })).toBe(true);
|
||||
expect(isPendingApprovalAwaiting({ pendingApproval: true, approved: false })).toBe(false);
|
||||
});
|
||||
|
||||
it('keeps pending approvals awaiting when no decision has been made', () => {
|
||||
expect(isPendingApprovalRejected({ pendingApproval: true })).toBe(false);
|
||||
expect(isPendingApprovalAwaiting({ pendingApproval: true })).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
export const approvePendingCommentModeration = { approved: true } as const;
|
||||
|
||||
// plebbit-js clears pendingApproval only when rejection is published as approved:false.
|
||||
// Sending removed:true marks the comment removed but can leave it in the mod queue.
|
||||
export const rejectPendingCommentModeration = { approved: false } as const;
|
||||
|
||||
type PendingApprovalDisplayState = {
|
||||
approved?: boolean;
|
||||
removed?: boolean;
|
||||
pendingApproval?: boolean;
|
||||
};
|
||||
|
||||
export const isPendingApprovalRejected = (comment?: PendingApprovalDisplayState) =>
|
||||
comment?.removed === true || (comment?.pendingApproval === true && comment?.approved === false);
|
||||
|
||||
export const isPendingApprovalAwaiting = (comment?: PendingApprovalDisplayState) =>
|
||||
comment?.pendingApproval === true && comment?.approved !== true && !isPendingApprovalRejected(comment);
|
||||
@@ -13,6 +13,12 @@ import { useDirectories, DirectoryCommunity } from '../../hooks/use-directories'
|
||||
import getShortAddress from '../../lib/get-short-address';
|
||||
import { BOARD_CODE_GROUPS } from '../../constants/board-codes';
|
||||
import { getHasThumbnail, getCommentMediaInfo } from '../../lib/utils/media-utils';
|
||||
import {
|
||||
approvePendingCommentModeration,
|
||||
isPendingApprovalAwaiting,
|
||||
isPendingApprovalRejected,
|
||||
rejectPendingCommentModeration,
|
||||
} from '../../lib/utils/pending-approval-moderation';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import useFeedResetStore from '../../stores/use-feed-reset-store';
|
||||
import useChallengesStore from '../../stores/use-challenges-store';
|
||||
@@ -148,11 +154,11 @@ const ModQueueActions = ({ status, errorMessage, isPublishing, handleApprove, ha
|
||||
|
||||
const useModQueueActions = (comment: Comment): ModQueueActionState => {
|
||||
const { t } = useTranslation();
|
||||
const { cid, subplebbitAddress, approved, removed } = comment || {};
|
||||
const { cid, subplebbitAddress, approved, removed, pendingApproval } = comment || {};
|
||||
const [initiatedAction, setInitiatedAction] = useState<ModerationAction>(null);
|
||||
|
||||
const alreadyApproved = approved === true;
|
||||
const alreadyRejected = removed === true;
|
||||
const alreadyRejected = isPendingApprovalRejected({ approved, removed, pendingApproval });
|
||||
|
||||
const {
|
||||
publishCommentModeration: approve,
|
||||
@@ -161,7 +167,7 @@ const useModQueueActions = (comment: Comment): ModQueueActionState => {
|
||||
} = usePublishCommentModeration({
|
||||
commentCid: cid,
|
||||
subplebbitAddress,
|
||||
commentModeration: { approved: true },
|
||||
commentModeration: approvePendingCommentModeration,
|
||||
onChallenge: async (...args: any) => {
|
||||
addChallenge([...args, comment]);
|
||||
},
|
||||
@@ -180,7 +186,7 @@ const useModQueueActions = (comment: Comment): ModQueueActionState => {
|
||||
} = usePublishCommentModeration({
|
||||
commentCid: cid,
|
||||
subplebbitAddress,
|
||||
commentModeration: { removed: true },
|
||||
commentModeration: rejectPendingCommentModeration,
|
||||
onChallenge: async (...args: any) => {
|
||||
addChallenge([...args, comment]);
|
||||
},
|
||||
@@ -245,21 +251,36 @@ const ModQueueRow = memo(({ comment, isOdd = false, showBoard = false, boardPath
|
||||
const { editedComment } = useEditedComment({ comment });
|
||||
const displayComment = editedComment || comment;
|
||||
|
||||
const { content, title, timestamp, subplebbitAddress, cid, threadCid, link, thumbnailUrl, linkWidth, linkHeight, removed, approved, number, parentCid } =
|
||||
displayComment;
|
||||
const {
|
||||
content,
|
||||
title,
|
||||
timestamp,
|
||||
subplebbitAddress,
|
||||
cid,
|
||||
threadCid,
|
||||
link,
|
||||
thumbnailUrl,
|
||||
linkWidth,
|
||||
linkHeight,
|
||||
removed,
|
||||
approved,
|
||||
pendingApproval,
|
||||
number,
|
||||
parentCid,
|
||||
} = displayComment;
|
||||
|
||||
// Check if already moderated (from previous session or API update)
|
||||
// Note: `approved` and `removed` are direct fields on the comment from CommentUpdate,
|
||||
// not nested under commentModeration (which is the options object for publishing moderation actions)
|
||||
const alreadyApproved = approved === true;
|
||||
const alreadyRejected = removed === true;
|
||||
const alreadyRejected = isPendingApprovalRejected({ approved, removed, pendingApproval });
|
||||
|
||||
const timeWaiting = currentTime - timestamp;
|
||||
const alertThresholdSeconds = getAlertThresholdSeconds();
|
||||
const isOverThreshold = timeWaiting > alertThresholdSeconds;
|
||||
|
||||
// Only show alert animation for comments awaiting approval (not approved or rejected)
|
||||
const isAwaitingApproval = !alreadyApproved && !alreadyRejected;
|
||||
const isAwaitingApproval = isPendingApprovalAwaiting(displayComment);
|
||||
|
||||
const { status, errorMessage, isPublishing, handleApprove, handleReject } = useModQueueActions(displayComment);
|
||||
const hasTitle = title && title.trim().length > 0;
|
||||
@@ -357,16 +378,31 @@ const ModQueueCard = memo(({ comment, showBoard = false, boardPath, boardDisplay
|
||||
const { editedComment } = useEditedComment({ comment });
|
||||
const displayComment = editedComment || comment;
|
||||
|
||||
const { content, title, timestamp, subplebbitAddress, cid, threadCid, link, thumbnailUrl, linkWidth, linkHeight, removed, approved, number, parentCid } =
|
||||
displayComment;
|
||||
const {
|
||||
content,
|
||||
title,
|
||||
timestamp,
|
||||
subplebbitAddress,
|
||||
cid,
|
||||
threadCid,
|
||||
link,
|
||||
thumbnailUrl,
|
||||
linkWidth,
|
||||
linkHeight,
|
||||
removed,
|
||||
approved,
|
||||
pendingApproval,
|
||||
number,
|
||||
parentCid,
|
||||
} = displayComment;
|
||||
|
||||
const alreadyApproved = approved === true;
|
||||
const alreadyRejected = removed === true;
|
||||
const alreadyRejected = isPendingApprovalRejected({ approved, removed, pendingApproval });
|
||||
|
||||
const timeWaiting = currentTime - timestamp;
|
||||
const alertThresholdSeconds = getAlertThresholdSeconds();
|
||||
const isOverThreshold = timeWaiting > alertThresholdSeconds;
|
||||
const isAwaitingApproval = !alreadyApproved && !alreadyRejected;
|
||||
const isAwaitingApproval = isPendingApprovalAwaiting(displayComment);
|
||||
|
||||
const { status, errorMessage, isPublishing, handleApprove, handleReject } = useModQueueActions(displayComment);
|
||||
const hasTitle = title && title.trim().length > 0;
|
||||
@@ -480,7 +516,7 @@ const ModQueueBoardSummary = ({ feed, directories, accountSubplebbitAddresses }:
|
||||
if (!addr) continue;
|
||||
const entry = counts.get(addr);
|
||||
if (!entry) continue;
|
||||
const isAwaiting = item.approved !== true && item.removed !== true;
|
||||
const isAwaiting = isPendingApprovalAwaiting(item);
|
||||
if (!isAwaiting) continue;
|
||||
const timeWaiting = currentTime - (item.timestamp ?? 0);
|
||||
const isUrgent = timeWaiting > alertThresholdSeconds;
|
||||
@@ -606,8 +642,8 @@ const ModQueueCountItem = ({ comment, alertThresholdSeconds, onStatusChange }: M
|
||||
const displayComment = editedComment || comment;
|
||||
const currentTime = useCurrentTime();
|
||||
|
||||
const { cid, approved, removed, timestamp } = displayComment;
|
||||
const isAwaiting = approved !== true && removed !== true;
|
||||
const { cid, timestamp } = displayComment;
|
||||
const isAwaiting = isPendingApprovalAwaiting(displayComment);
|
||||
const timeWaiting = currentTime - timestamp;
|
||||
const isUrgent = isAwaiting && timeWaiting > alertThresholdSeconds;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user