Comments: simplify blocked replies display
Previously, we decide when to display "Show More" based on the current fetched reply count vs. total replies in Commentron. It was already troublesome as `comment.List` and `comment.replies` give different values (one includes blocked content, while another does not). Now, we are further filtering the list with Commentron blocklists (personal, admin, moderator), so it is not feasible to run the logic based on reply count. ## Solution - Keep track of number of remaining pages instead and use that to determine when to display "Show More". - While it doesn't solve the "Show N replies" mismatch (YT has this problem too), it prevents the button from lingering. - In the event that all replies are blocked, just show an empty space (same as YT). I didn't like the previous version that cluttered the space with "comment(s) blocked".
This commit is contained in:
parent
e899a5de65
commit
74986a8b3a
7 changed files with 21 additions and 50 deletions
2
flow-typed/Comment.js
vendored
2
flow-typed/Comment.js
vendored
|
@ -35,7 +35,7 @@ declare type CommentsState = {
|
||||||
byId: { [string]: Array<string> }, // ClaimID -> list of fetched comment IDs.
|
byId: { [string]: Array<string> }, // ClaimID -> list of fetched comment IDs.
|
||||||
totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron.
|
totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron.
|
||||||
repliesByParentId: { [string]: Array<string> }, // ParentCommentID -> list of fetched replies.
|
repliesByParentId: { [string]: Array<string> }, // ParentCommentID -> list of fetched replies.
|
||||||
totalRepliesByParentId: {}, // ParentCommentID -> total replies in commentron.
|
repliesTotalPagesByParentId: {}, // ParentCommentID -> total number of reply pages for a parentId in commentron.
|
||||||
topLevelCommentsById: { [string]: Array<string> }, // ClaimID -> list of fetched top level comments.
|
topLevelCommentsById: { [string]: Array<string> }, // ClaimID -> list of fetched top level comments.
|
||||||
topLevelTotalPagesById: { [string]: number }, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL.
|
topLevelTotalPagesById: { [string]: number }, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL.
|
||||||
topLevelTotalCommentsById: { [string]: number }, // ClaimID -> total top level comments in commentron.
|
topLevelTotalCommentsById: { [string]: number }, // ClaimID -> total top level comments in commentron.
|
||||||
|
|
|
@ -10,7 +10,11 @@ import { makeSelectChannelIsMuted } from 'redux/selectors/blocked';
|
||||||
import { doToast } from 'redux/actions/notifications';
|
import { doToast } from 'redux/actions/notifications';
|
||||||
import { doSetPlayingUri } from 'redux/actions/content';
|
import { doSetPlayingUri } from 'redux/actions/content';
|
||||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||||
import { selectLinkedCommentAncestors, makeSelectOthersReactionsForComment } from 'redux/selectors/comments';
|
import {
|
||||||
|
selectLinkedCommentAncestors,
|
||||||
|
makeSelectOthersReactionsForComment,
|
||||||
|
makeSelectTotalReplyPagesForParentId,
|
||||||
|
} from 'redux/selectors/comments';
|
||||||
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
||||||
import { selectPlayingUri } from 'redux/selectors/content';
|
import { selectPlayingUri } from 'redux/selectors/content';
|
||||||
import Comment from './view';
|
import Comment from './view';
|
||||||
|
@ -31,6 +35,7 @@ const select = (state, props) => {
|
||||||
playingUri: selectPlayingUri(state),
|
playingUri: selectPlayingUri(state),
|
||||||
stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state),
|
stakedLevel: makeSelectStakedLevelForChannelUri(props.authorUri)(state),
|
||||||
linkedCommentAncestors: selectLinkedCommentAncestors(state),
|
linkedCommentAncestors: selectLinkedCommentAncestors(state),
|
||||||
|
totalReplyPages: makeSelectTotalReplyPagesForParentId(props.commentId)(state),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,7 @@ type Props = {
|
||||||
commentIsMine: boolean, // if this comment was signed by an owned channel
|
commentIsMine: boolean, // if this comment was signed by an owned channel
|
||||||
updateComment: (string, string) => void,
|
updateComment: (string, string) => void,
|
||||||
fetchReplies: (string, string, number, number, number) => void,
|
fetchReplies: (string, string, number, number, number) => void,
|
||||||
|
totalReplyPages: number,
|
||||||
commentModBlock: (string) => void,
|
commentModBlock: (string) => void,
|
||||||
linkedCommentId?: string,
|
linkedCommentId?: string,
|
||||||
linkedCommentAncestors: { [string]: Array<string> },
|
linkedCommentAncestors: { [string]: Array<string> },
|
||||||
|
@ -82,6 +83,7 @@ function Comment(props: Props) {
|
||||||
commentId,
|
commentId,
|
||||||
updateComment,
|
updateComment,
|
||||||
fetchReplies,
|
fetchReplies,
|
||||||
|
totalReplyPages,
|
||||||
linkedCommentId,
|
linkedCommentId,
|
||||||
linkedCommentAncestors,
|
linkedCommentAncestors,
|
||||||
commentingEnabled,
|
commentingEnabled,
|
||||||
|
@ -417,6 +419,7 @@ function Comment(props: Props) {
|
||||||
linkedCommentId={linkedCommentId}
|
linkedCommentId={linkedCommentId}
|
||||||
numDirectReplies={numDirectReplies}
|
numDirectReplies={numDirectReplies}
|
||||||
onShowMore={() => setPage(page + 1)}
|
onShowMore={() => setPage(page + 1)}
|
||||||
|
hasMore={page < totalReplyPages}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { makeSelectClaimIsMine, selectMyChannelClaims } from 'lbry-redux';
|
import { makeSelectClaimIsMine, selectMyChannelClaims } from 'lbry-redux';
|
||||||
import {
|
import { selectIsFetchingCommentsByParentId, makeSelectRepliesForParentId } from 'redux/selectors/comments';
|
||||||
selectIsFetchingCommentsByParentId,
|
|
||||||
makeSelectRepliesForParentId,
|
|
||||||
makeSelectTotalRepliesForParentId,
|
|
||||||
} from 'redux/selectors/comments';
|
|
||||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||||
import CommentsReplies from './view';
|
import CommentsReplies from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
fetchedReplies: makeSelectRepliesForParentId(props.parentId)(state),
|
fetchedReplies: makeSelectRepliesForParentId(props.parentId)(state),
|
||||||
totalReplies: makeSelectTotalRepliesForParentId(props.parentId)(state),
|
|
||||||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||||
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
|
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
|
||||||
myChannels: selectMyChannelClaims(state),
|
myChannels: selectMyChannelClaims(state),
|
||||||
|
|
|
@ -4,11 +4,9 @@ import React from 'react';
|
||||||
import Comment from 'component/comment';
|
import Comment from 'component/comment';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import Spinner from 'component/spinner';
|
import Spinner from 'component/spinner';
|
||||||
import ChannelThumbnail from 'component/channelThumbnail';
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
fetchedReplies: Array<any>,
|
fetchedReplies: Array<any>,
|
||||||
totalReplies: number,
|
|
||||||
uri: string,
|
uri: string,
|
||||||
parentId: string,
|
parentId: string,
|
||||||
claimIsMine: boolean,
|
claimIsMine: boolean,
|
||||||
|
@ -16,9 +14,10 @@ type Props = {
|
||||||
linkedCommentId?: string,
|
linkedCommentId?: string,
|
||||||
commentingEnabled: boolean,
|
commentingEnabled: boolean,
|
||||||
threadDepth: number,
|
threadDepth: number,
|
||||||
numDirectReplies: number,
|
numDirectReplies: number, // Total replies for parentId as reported by 'comment[replies]'. Includes blocked items.
|
||||||
isFetchingByParentId: { [string]: boolean },
|
isFetchingByParentId: { [string]: boolean },
|
||||||
onShowMore?: () => void,
|
onShowMore?: () => void,
|
||||||
|
hasMore: boolean,
|
||||||
};
|
};
|
||||||
|
|
||||||
function CommentsReplies(props: Props) {
|
function CommentsReplies(props: Props) {
|
||||||
|
@ -26,7 +25,6 @@ function CommentsReplies(props: Props) {
|
||||||
uri,
|
uri,
|
||||||
parentId,
|
parentId,
|
||||||
fetchedReplies,
|
fetchedReplies,
|
||||||
totalReplies,
|
|
||||||
claimIsMine,
|
claimIsMine,
|
||||||
myChannels,
|
myChannels,
|
||||||
linkedCommentId,
|
linkedCommentId,
|
||||||
|
@ -35,6 +33,7 @@ function CommentsReplies(props: Props) {
|
||||||
numDirectReplies,
|
numDirectReplies,
|
||||||
isFetchingByParentId,
|
isFetchingByParentId,
|
||||||
onShowMore,
|
onShowMore,
|
||||||
|
hasMore,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [isExpanded, setExpanded] = React.useState(true);
|
const [isExpanded, setExpanded] = React.useState(true);
|
||||||
|
@ -102,28 +101,11 @@ function CommentsReplies(props: Props) {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
{!isFetchingByParentId[parentId] && totalReplies < numDirectReplies && (
|
|
||||||
<li className="comment comment--reply">
|
|
||||||
<div className="comment__content">
|
|
||||||
<div className="comment__thumbnail-wrapper">
|
|
||||||
<ChannelThumbnail xsmall className="comment__author-thumbnail" />
|
|
||||||
</div>
|
|
||||||
<div className="comment__body-container comment--blocked">
|
|
||||||
<div className="comment__meta">
|
|
||||||
<em>---</em>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<em>{__('Comment(s) blocked.')}</em>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
)}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{isExpanded && fetchedReplies && displayedComments.length < totalReplies && (
|
{isExpanded && fetchedReplies && hasMore && (
|
||||||
<div className="comment__actions--nested">
|
<div className="comment__actions--nested">
|
||||||
<Button button="link" label={__('Show more')} onClick={showMore} className="button--uri-indicator" />
|
<Button button="link" label={__('Show more')} onClick={showMore} className="button--uri-indicator" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,7 +9,7 @@ const defaultState: CommentsState = {
|
||||||
byId: {}, // ClaimID -> list of fetched comment IDs.
|
byId: {}, // ClaimID -> list of fetched comment IDs.
|
||||||
totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron.
|
totalCommentsById: {}, // ClaimId -> ultimate total (including replies) in commentron.
|
||||||
repliesByParentId: {}, // ParentCommentID -> list of fetched replies.
|
repliesByParentId: {}, // ParentCommentID -> list of fetched replies.
|
||||||
totalRepliesByParentId: {}, // ParentCommentID -> total replies in commentron.
|
repliesTotalPagesByParentId: {}, // ParentCommentID -> total number of reply pages for a parentId in commentron.
|
||||||
topLevelCommentsById: {}, // ClaimID -> list of fetched top level comments.
|
topLevelCommentsById: {}, // ClaimID -> list of fetched top level comments.
|
||||||
topLevelTotalPagesById: {}, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL.
|
topLevelTotalPagesById: {}, // ClaimID -> total number of top-level pages in commentron. Based on COMMENT_PAGE_SIZE_TOP_LEVEL.
|
||||||
topLevelTotalCommentsById: {}, // ClaimID -> total top level comments in commentron.
|
topLevelTotalCommentsById: {}, // ClaimID -> total top level comments in commentron.
|
||||||
|
@ -79,7 +79,6 @@ export default handleActions(
|
||||||
const totalCommentsById = Object.assign({}, state.totalCommentsById);
|
const totalCommentsById = Object.assign({}, state.totalCommentsById);
|
||||||
const topLevelCommentsById = Object.assign({}, state.topLevelCommentsById); // was byId {ClaimId -> [commentIds...]}
|
const topLevelCommentsById = Object.assign({}, state.topLevelCommentsById); // was byId {ClaimId -> [commentIds...]}
|
||||||
const repliesByParentId = Object.assign({}, state.repliesByParentId); // {ParentCommentID -> [commentIds...] } list of reply comments
|
const repliesByParentId = Object.assign({}, state.repliesByParentId); // {ParentCommentID -> [commentIds...] } list of reply comments
|
||||||
const totalRepliesByParentId = Object.assign({}, state.totalRepliesByParentId);
|
|
||||||
const commentsByUri = Object.assign({}, state.commentsByUri);
|
const commentsByUri = Object.assign({}, state.commentsByUri);
|
||||||
const comments = byId[claimId] || [];
|
const comments = byId[claimId] || [];
|
||||||
const newCommentIds = comments.slice();
|
const newCommentIds = comments.slice();
|
||||||
|
@ -104,12 +103,6 @@ export default handleActions(
|
||||||
repliesByParentId[comment.parent_id].unshift(comment.comment_id);
|
repliesByParentId[comment.parent_id].unshift(comment.comment_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!totalRepliesByParentId[comment.parent_id]) {
|
|
||||||
totalRepliesByParentId[comment.parent_id] = 1;
|
|
||||||
} else {
|
|
||||||
totalRepliesByParentId[comment.parent_id] += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the parent's "replies" value
|
// Update the parent's "replies" value
|
||||||
if (commentById[comment.parent_id]) {
|
if (commentById[comment.parent_id]) {
|
||||||
commentById[comment.parent_id].replies = (commentById[comment.parent_id].replies || 0) + 1;
|
commentById[comment.parent_id].replies = (commentById[comment.parent_id].replies || 0) + 1;
|
||||||
|
@ -128,7 +121,6 @@ export default handleActions(
|
||||||
...state,
|
...state,
|
||||||
topLevelCommentsById,
|
topLevelCommentsById,
|
||||||
repliesByParentId,
|
repliesByParentId,
|
||||||
totalRepliesByParentId,
|
|
||||||
commentById,
|
commentById,
|
||||||
byId,
|
byId,
|
||||||
totalCommentsById,
|
totalCommentsById,
|
||||||
|
@ -262,7 +254,7 @@ export default handleActions(
|
||||||
const repliesByParentId = Object.assign({}, state.repliesByParentId);
|
const repliesByParentId = Object.assign({}, state.repliesByParentId);
|
||||||
const totalCommentsById = Object.assign({}, state.totalCommentsById);
|
const totalCommentsById = Object.assign({}, state.totalCommentsById);
|
||||||
const pinnedCommentsById = Object.assign({}, state.pinnedCommentsById);
|
const pinnedCommentsById = Object.assign({}, state.pinnedCommentsById);
|
||||||
const totalRepliesByParentId = Object.assign({}, state.totalRepliesByParentId);
|
const repliesTotalPagesByParentId = Object.assign({}, state.repliesTotalPagesByParentId);
|
||||||
const isLoadingByParentId = Object.assign({}, state.isLoadingByParentId);
|
const isLoadingByParentId = Object.assign({}, state.isLoadingByParentId);
|
||||||
const settingsByChannelId = Object.assign({}, state.settingsByChannelId);
|
const settingsByChannelId = Object.assign({}, state.settingsByChannelId);
|
||||||
|
|
||||||
|
@ -277,7 +269,7 @@ export default handleActions(
|
||||||
|
|
||||||
if (!disabled) {
|
if (!disabled) {
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
totalRepliesByParentId[parentId] = totalFilteredItems;
|
repliesTotalPagesByParentId[parentId] = totalPages;
|
||||||
} else {
|
} else {
|
||||||
totalCommentsById[claimId] = totalItems;
|
totalCommentsById[claimId] = totalItems;
|
||||||
topLevelTotalCommentsById[claimId] = totalFilteredItems;
|
topLevelTotalCommentsById[claimId] = totalFilteredItems;
|
||||||
|
@ -330,7 +322,7 @@ export default handleActions(
|
||||||
repliesByParentId,
|
repliesByParentId,
|
||||||
totalCommentsById,
|
totalCommentsById,
|
||||||
pinnedCommentsById,
|
pinnedCommentsById,
|
||||||
totalRepliesByParentId,
|
repliesTotalPagesByParentId,
|
||||||
byId,
|
byId,
|
||||||
commentById,
|
commentById,
|
||||||
commentsByUri,
|
commentsByUri,
|
||||||
|
@ -548,7 +540,6 @@ export default handleActions(
|
||||||
const commentById = Object.assign({}, state.commentById);
|
const commentById = Object.assign({}, state.commentById);
|
||||||
const byId = Object.assign({}, state.byId);
|
const byId = Object.assign({}, state.byId);
|
||||||
const repliesByParentId = Object.assign({}, state.repliesByParentId); // {ParentCommentID -> [commentIds...] } list of reply comments
|
const repliesByParentId = Object.assign({}, state.repliesByParentId); // {ParentCommentID -> [commentIds...] } list of reply comments
|
||||||
const totalRepliesByParentId = Object.assign({}, state.totalRepliesByParentId);
|
|
||||||
const totalCommentsById = Object.assign({}, state.totalCommentsById);
|
const totalCommentsById = Object.assign({}, state.totalCommentsById);
|
||||||
|
|
||||||
const comment = commentById[comment_id];
|
const comment = commentById[comment_id];
|
||||||
|
@ -571,10 +562,6 @@ export default handleActions(
|
||||||
if (commentById[comment.parent_id]) {
|
if (commentById[comment.parent_id]) {
|
||||||
commentById[comment.parent_id].replies = Math.max(0, (commentById[comment.parent_id].replies || 0) - 1);
|
commentById[comment.parent_id].replies = Math.max(0, (commentById[comment.parent_id].replies || 0) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalRepliesByParentId[comment.parent_id]) {
|
|
||||||
totalRepliesByParentId[comment.parent_id] = Math.max(0, totalRepliesByParentId[comment.parent_id] - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,7 +577,6 @@ export default handleActions(
|
||||||
byId,
|
byId,
|
||||||
totalCommentsById,
|
totalCommentsById,
|
||||||
repliesByParentId,
|
repliesByParentId,
|
||||||
totalRepliesByParentId,
|
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
@ -322,9 +322,9 @@ const makeSelectFilteredComments = (comments: Array<Comment>) =>
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const makeSelectTotalRepliesForParentId = (parentId: string) =>
|
export const makeSelectTotalReplyPagesForParentId = (parentId: string) =>
|
||||||
createSelector(selectState, (state) => {
|
createSelector(selectState, (state) => {
|
||||||
return state.totalRepliesByParentId[parentId] || 0;
|
return state.repliesTotalPagesByParentId[parentId] || 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const makeSelectTotalCommentsCountForUri = (uri: string) =>
|
export const makeSelectTotalCommentsCountForUri = (uri: string) =>
|
||||||
|
|
Loading…
Reference in a new issue