Livestream: stop pinned comments from appearing as latest #6888
6 changed files with 101 additions and 74 deletions
|
@ -15,6 +15,7 @@ import {
|
||||||
selectMyReactionsByCommentId,
|
selectMyReactionsByCommentId,
|
||||||
makeSelectCommentIdsForUri,
|
makeSelectCommentIdsForUri,
|
||||||
selectSettingsByChannelId,
|
selectSettingsByChannelId,
|
||||||
|
makeSelectPinnedCommentsForUri,
|
||||||
} from 'redux/selectors/comments';
|
} from 'redux/selectors/comments';
|
||||||
import { doCommentReset, doCommentList, doCommentById, doCommentReactList } from 'redux/actions/comments';
|
import { doCommentReset, doCommentList, doCommentById, doCommentReactList } from 'redux/actions/comments';
|
||||||
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
||||||
|
@ -25,6 +26,7 @@ const select = (state, props) => {
|
||||||
return {
|
return {
|
||||||
myChannels: selectMyChannelClaims(state),
|
myChannels: selectMyChannelClaims(state),
|
||||||
allCommentIds: makeSelectCommentIdsForUri(props.uri)(state),
|
allCommentIds: makeSelectCommentIdsForUri(props.uri)(state),
|
||||||
|
pinnedComments: makeSelectPinnedCommentsForUri(props.uri)(state),
|
||||||
topLevelComments: makeSelectTopLevelCommentsForUri(props.uri)(state),
|
topLevelComments: makeSelectTopLevelCommentsForUri(props.uri)(state),
|
||||||
topLevelTotalPages: makeSelectTopLevelTotalPagesForUri(props.uri)(state),
|
topLevelTotalPages: makeSelectTopLevelTotalPagesForUri(props.uri)(state),
|
||||||
totalComments: makeSelectTotalCommentsCountForUri(props.uri)(state),
|
totalComments: makeSelectTotalCommentsCountForUri(props.uri)(state),
|
||||||
|
|
|
@ -28,6 +28,7 @@ function scaleToDevicePixelRatio(value) {
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
allCommentIds: any,
|
allCommentIds: any,
|
||||||
|
pinnedComments: Array<Comment>,
|
||||||
topLevelComments: Array<Comment>,
|
topLevelComments: Array<Comment>,
|
||||||
topLevelTotalPages: number,
|
topLevelTotalPages: number,
|
||||||
fetchTopLevelComments: (string, number, number, number) => void,
|
fetchTopLevelComments: (string, number, number, number) => void,
|
||||||
|
@ -57,6 +58,7 @@ function CommentList(props: Props) {
|
||||||
fetchReacts,
|
fetchReacts,
|
||||||
resetComments,
|
resetComments,
|
||||||
uri,
|
uri,
|
||||||
|
pinnedComments,
|
||||||
topLevelComments,
|
topLevelComments,
|
||||||
topLevelTotalPages,
|
topLevelTotalPages,
|
||||||
claim,
|
claim,
|
||||||
|
@ -111,6 +113,34 @@ function CommentList(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCommentElems(comments) {
|
||||||
|
return comments.map((comment) => {
|
||||||
|
return (
|
||||||
|
<CommentView
|
||||||
|
isTopLevel
|
||||||
|
threadDepth={3}
|
||||||
|
key={comment.comment_id}
|
||||||
|
uri={uri}
|
||||||
|
authorUri={comment.channel_url}
|
||||||
|
author={comment.channel_name}
|
||||||
|
claimId={comment.claim_id}
|
||||||
|
commentId={comment.comment_id}
|
||||||
|
message={comment.comment}
|
||||||
|
timePosted={comment.timestamp * 1000}
|
||||||
|
claimIsMine={claimIsMine}
|
||||||
|
commentIsMine={comment.channel_id && isMyComment(comment.channel_id)}
|
||||||
|
linkedCommentId={linkedCommentId}
|
||||||
|
isPinned={comment.is_pinned}
|
||||||
|
supportAmount={comment.support_amount}
|
||||||
|
numDirectReplies={comment.replies}
|
||||||
|
isModerator={comment.is_moderator}
|
||||||
|
isGlobalMod={comment.is_global_mod}
|
||||||
|
isFiat={comment.is_fiat}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Reset comments
|
// Reset comments
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (page === 0) {
|
if (page === 0) {
|
||||||
|
@ -223,8 +253,6 @@ function CommentList(props: Props) {
|
||||||
topLevelTotalPages,
|
topLevelTotalPages,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const displayedComments = readyToDisplayComments ? topLevelComments : [];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={
|
title={
|
||||||
|
@ -295,33 +323,8 @@ function CommentList(props: Props) {
|
||||||
})}
|
})}
|
||||||
ref={commentRef}
|
ref={commentRef}
|
||||||
>
|
>
|
||||||
{topLevelComments &&
|
{readyToDisplayComments && pinnedComments && getCommentElems(pinnedComments)}
|
||||||
displayedComments &&
|
{readyToDisplayComments && topLevelComments && getCommentElems(topLevelComments)}
|
||||||
displayedComments.map((comment) => {
|
|
||||||
return (
|
|
||||||
<CommentView
|
|
||||||
isTopLevel
|
|
||||||
threadDepth={3}
|
|
||||||
key={comment.comment_id}
|
|
||||||
uri={uri}
|
|
||||||
authorUri={comment.channel_url}
|
|
||||||
author={comment.channel_name}
|
|
||||||
claimId={comment.claim_id}
|
|
||||||
commentId={comment.comment_id}
|
|
||||||
message={comment.comment}
|
|
||||||
timePosted={comment.timestamp * 1000}
|
|
||||||
claimIsMine={claimIsMine}
|
|
||||||
commentIsMine={comment.channel_id && isMyComment(comment.channel_id)}
|
|
||||||
linkedCommentId={linkedCommentId}
|
|
||||||
isPinned={comment.is_pinned}
|
|
||||||
supportAmount={comment.support_amount}
|
|
||||||
numDirectReplies={comment.replies}
|
|
||||||
isModerator={comment.is_moderator}
|
|
||||||
isGlobalMod={comment.is_global_mod}
|
|
||||||
isFiat={comment.is_fiat}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{isMobile && (
|
{isMobile && (
|
||||||
|
|
|
@ -3,22 +3,22 @@ import { makeSelectClaimForUri, selectMyChannelClaims } from 'lbry-redux';
|
||||||
import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket';
|
import { doCommentSocketConnect, doCommentSocketDisconnect } from 'redux/actions/websocket';
|
||||||
import { doCommentList, doSuperChatList } from 'redux/actions/comments';
|
import { doCommentList, doSuperChatList } from 'redux/actions/comments';
|
||||||
import {
|
import {
|
||||||
selectPinnedCommentsById,
|
|
||||||
makeSelectTopLevelCommentsForUri,
|
makeSelectTopLevelCommentsForUri,
|
||||||
selectIsFetchingComments,
|
selectIsFetchingComments,
|
||||||
makeSelectSuperChatsForUri,
|
makeSelectSuperChatsForUri,
|
||||||
makeSelectSuperChatTotalAmountForUri,
|
makeSelectSuperChatTotalAmountForUri,
|
||||||
|
makeSelectPinnedCommentsForUri,
|
||||||
} from 'redux/selectors/comments';
|
} from 'redux/selectors/comments';
|
||||||
import LivestreamComments from './view';
|
import LivestreamComments from './view';
|
||||||
|
|
||||||
const select = (state, props) => ({
|
const select = (state, props) => ({
|
||||||
claim: makeSelectClaimForUri(props.uri)(state),
|
claim: makeSelectClaimForUri(props.uri)(state),
|
||||||
comments: makeSelectTopLevelCommentsForUri(props.uri)(state).slice(0, 75),
|
comments: makeSelectTopLevelCommentsForUri(props.uri)(state).slice(0, 75),
|
||||||
|
pinnedComments: makeSelectPinnedCommentsForUri(props.uri)(state),
|
||||||
fetchingComments: selectIsFetchingComments(state),
|
fetchingComments: selectIsFetchingComments(state),
|
||||||
superChats: makeSelectSuperChatsForUri(props.uri)(state),
|
superChats: makeSelectSuperChatsForUri(props.uri)(state),
|
||||||
superChatsTotalAmount: makeSelectSuperChatTotalAmountForUri(props.uri)(state),
|
superChatsTotalAmount: makeSelectSuperChatTotalAmountForUri(props.uri)(state),
|
||||||
myChannels: selectMyChannelClaims(state),
|
myChannels: selectMyChannelClaims(state),
|
||||||
pinnedCommentsById: selectPinnedCommentsById(state),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, {
|
export default connect(select, {
|
||||||
|
|
|
@ -19,11 +19,11 @@ type Props = {
|
||||||
doCommentSocketDisconnect: (string) => void,
|
doCommentSocketDisconnect: (string) => void,
|
||||||
doCommentList: (string, string, number, number) => void,
|
doCommentList: (string, string, number, number) => void,
|
||||||
comments: Array<Comment>,
|
comments: Array<Comment>,
|
||||||
|
pinnedComments: Array<Comment>,
|
||||||
fetchingComments: boolean,
|
fetchingComments: boolean,
|
||||||
doSuperChatList: (string) => void,
|
doSuperChatList: (string) => void,
|
||||||
superChats: Array<Comment>,
|
superChats: Array<Comment>,
|
||||||
myChannels: ?Array<ChannelClaim>,
|
myChannels: ?Array<ChannelClaim>,
|
||||||
pinnedCommentsById: { [claimId: string]: Array<string> },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const VIEW_MODE_CHAT = 'view_chat';
|
const VIEW_MODE_CHAT = 'view_chat';
|
||||||
|
@ -39,12 +39,12 @@ export default function LivestreamComments(props: Props) {
|
||||||
doCommentSocketConnect,
|
doCommentSocketConnect,
|
||||||
doCommentSocketDisconnect,
|
doCommentSocketDisconnect,
|
||||||
comments: commentsByChronologicalOrder,
|
comments: commentsByChronologicalOrder,
|
||||||
|
pinnedComments,
|
||||||
doCommentList,
|
doCommentList,
|
||||||
fetchingComments,
|
fetchingComments,
|
||||||
doSuperChatList,
|
doSuperChatList,
|
||||||
myChannels,
|
myChannels,
|
||||||
superChats: superChatsByTipAmount,
|
superChats: superChatsByTipAmount,
|
||||||
pinnedCommentsById,
|
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
let superChatsFiatAmount, superChatsTotalAmount;
|
let superChatsFiatAmount, superChatsTotalAmount;
|
||||||
|
@ -60,11 +60,7 @@ export default function LivestreamComments(props: Props) {
|
||||||
const discussionElement = document.querySelector('.livestream__comments');
|
const discussionElement = document.querySelector('.livestream__comments');
|
||||||
const commentElement = document.querySelector('.livestream-comment');
|
const commentElement = document.querySelector('.livestream-comment');
|
||||||
|
|
||||||
let pinnedComment;
|
const pinnedComment = pinnedComments.length > 0 ? pinnedComments[0] : null;
|
||||||
const pinnedCommentIds = (claimId && pinnedCommentsById[claimId]) || [];
|
|
||||||
if (pinnedCommentIds.length > 0) {
|
|
||||||
pinnedComment = commentsByChronologicalOrder.find((c) => c.comment_id === pinnedCommentIds[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (claimId) {
|
if (claimId) {
|
||||||
|
|
|
@ -301,9 +301,10 @@ export default handleActions(
|
||||||
for (let i = 0; i < comments.length; ++i) {
|
for (let i = 0; i < comments.length; ++i) {
|
||||||
const comment = comments[i];
|
const comment = comments[i];
|
||||||
commonUpdateAction(comment, commentById, commentIds, i);
|
commonUpdateAction(comment, commentById, commentIds, i);
|
||||||
pushToArrayInObject(topLevelCommentsById, claimId, comment.comment_id);
|
|
||||||
if (comment.is_pinned) {
|
if (comment.is_pinned) {
|
||||||
pushToArrayInObject(pinnedCommentsById, claimId, comment.comment_id);
|
pushToArrayInObject(pinnedCommentsById, claimId, comment.comment_id);
|
||||||
|
} else {
|
||||||
|
pushToArrayInObject(topLevelCommentsById, claimId, comment.comment_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -615,25 +616,31 @@ export default handleActions(
|
||||||
const topLevelCommentsById = Object.assign({}, state.topLevelCommentsById);
|
const topLevelCommentsById = Object.assign({}, state.topLevelCommentsById);
|
||||||
const pinnedCommentsById = Object.assign({}, state.pinnedCommentsById);
|
const pinnedCommentsById = Object.assign({}, state.pinnedCommentsById);
|
||||||
|
|
||||||
if (pinnedComment && topLevelCommentsById[claimId]) {
|
if (pinnedComment) {
|
||||||
|
if (topLevelCommentsById[claimId]) {
|
||||||
const index = topLevelCommentsById[claimId].indexOf(pinnedComment.comment_id);
|
const index = topLevelCommentsById[claimId].indexOf(pinnedComment.comment_id);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
topLevelCommentsById[claimId].splice(index, 1);
|
topLevelCommentsById[claimId].splice(index, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
topLevelCommentsById[claimId] = [];
|
||||||
|
}
|
||||||
|
|
||||||
if (pinnedCommentsById[claimId]) {
|
if (pinnedCommentsById[claimId]) {
|
||||||
// Remove here so that the 'unshift' below will be a unique entry.
|
const index = pinnedCommentsById[claimId].indexOf(pinnedComment.comment_id);
|
||||||
pinnedCommentsById[claimId] = pinnedCommentsById[claimId].filter((x) => x !== pinnedComment.comment_id);
|
if (index > -1) {
|
||||||
|
pinnedCommentsById[claimId].splice(index, 1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pinnedCommentsById[claimId] = [];
|
pinnedCommentsById[claimId] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unpin) {
|
if (unpin) {
|
||||||
// Without the sort score, I have no idea where to put it. Just
|
// Without the sort score, I have no idea where to put it. Just
|
||||||
// dump it at the bottom. Users can refresh if they want it back to
|
// dump it at the top. Users can refresh if they want it back to
|
||||||
// the correct sorted position.
|
// the correct sorted position.
|
||||||
topLevelCommentsById[claimId].push(pinnedComment.comment_id);
|
|
||||||
} else {
|
|
||||||
topLevelCommentsById[claimId].unshift(pinnedComment.comment_id);
|
topLevelCommentsById[claimId].unshift(pinnedComment.comment_id);
|
||||||
|
} else {
|
||||||
pinnedCommentsById[claimId].unshift(pinnedComment.comment_id);
|
pinnedCommentsById[claimId].unshift(pinnedComment.comment_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -655,7 +662,6 @@ export default handleActions(
|
||||||
commentById[pinnedComment.comment_id] = pinnedComment;
|
commentById[pinnedComment.comment_id] = pinnedComment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|
|
@ -13,7 +13,27 @@ export const selectIsFetchingCommentsByParentId = createSelector(selectState, (s
|
||||||
export const selectIsPostingComment = createSelector(selectState, (state) => state.isCommenting);
|
export const selectIsPostingComment = createSelector(selectState, (state) => state.isCommenting);
|
||||||
export const selectIsFetchingReacts = createSelector(selectState, (state) => state.isFetchingReacts);
|
export const selectIsFetchingReacts = createSelector(selectState, (state) => state.isFetchingReacts);
|
||||||
export const selectOthersReactsById = createSelector(selectState, (state) => state.othersReactsByCommentId);
|
export const selectOthersReactsById = createSelector(selectState, (state) => state.othersReactsByCommentId);
|
||||||
|
|
||||||
export const selectPinnedCommentsById = createSelector(selectState, (state) => state.pinnedCommentsById);
|
export const selectPinnedCommentsById = createSelector(selectState, (state) => state.pinnedCommentsById);
|
||||||
|
export const makeSelectPinnedCommentsForUri = (uri: string) =>
|
||||||
|
createSelector(
|
||||||
|
selectCommentsByUri,
|
||||||
|
selectCommentsById,
|
||||||
|
selectPinnedCommentsById,
|
||||||
|
(byUri, byId, pinnedCommentsById) => {
|
||||||
|
const claimId = byUri[uri];
|
||||||
|
const pinnedCommentIds = pinnedCommentsById && pinnedCommentsById[claimId];
|
||||||
|
const pinnedComments = [];
|
||||||
|
|
||||||
|
if (pinnedCommentIds) {
|
||||||
|
pinnedCommentIds.forEach((commentId) => {
|
||||||
|
pinnedComments.push(byId[commentId]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return pinnedComments;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export const selectModerationBlockList = createSelector(selectState, (state) =>
|
export const selectModerationBlockList = createSelector(selectState, (state) =>
|
||||||
state.moderationBlockList ? state.moderationBlockList.reverse() : []
|
state.moderationBlockList ? state.moderationBlockList.reverse() : []
|
||||||
|
|
Loading…
Add table
Reference in a new issue