Comments: enable 'enable_comments' flag
## Issue Closes 6159 "Support Comments Enabled/Disabled for comment.List API" ## New behavior - `disable-comments` tag will block the comments component entirely. - `settings.commentsEnabled`: - When false, will pause comment fetching, posting and replying. - Any already-fetched comments will stay on screen (unless user reloads/F5).
This commit is contained in:
parent
95fa01a952
commit
d6ac2c7954
9 changed files with 95 additions and 27 deletions
1
flow-typed/Comment.js
vendored
1
flow-typed/Comment.js
vendored
|
@ -41,6 +41,7 @@ declare type CommentsState = {
|
|||
fetchingModerationBlockList: boolean,
|
||||
blockingByUri: {},
|
||||
unBlockingByUri: {},
|
||||
commentsDisabledChannelIds: Array<string>,
|
||||
settingsByChannelId: { [string]: PerChannelSettings }, // ChannelID -> settings
|
||||
fetchingSettings: boolean,
|
||||
fetchingBlockedWords: boolean,
|
||||
|
|
|
@ -10,11 +10,13 @@ import { doOpenModal, doSetActiveChannel } from 'redux/actions/app';
|
|||
import { doCommentCreate } from 'redux/actions/comments';
|
||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
||||
import { makeSelectCommentsDisabledForUri } from 'redux/selectors/comments';
|
||||
import { doToast } from 'redux/actions/notifications';
|
||||
import { CommentCreate } from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
|
||||
commentsDisabledBySettings: makeSelectCommentsDisabledForUri(props.uri)(state),
|
||||
claim: makeSelectClaimForUri(props.uri)(state),
|
||||
channels: selectMyChannelClaims(state),
|
||||
isFetchingChannels: selectFetchingMyChannels(state),
|
||||
|
|
|
@ -15,6 +15,7 @@ import WalletTipAmountSelector from 'component/walletTipAmountSelector';
|
|||
import CreditAmount from 'component/common/credit-amount';
|
||||
import ChannelThumbnail from 'component/channelThumbnail';
|
||||
import UriIndicator from 'component/uriIndicator';
|
||||
import Empty from 'component/common/empty';
|
||||
|
||||
const COMMENT_SLOW_MODE_SECONDS = 5;
|
||||
|
||||
|
@ -22,6 +23,7 @@ type Props = {
|
|||
uri: string,
|
||||
claim: StreamClaim,
|
||||
createComment: (string, string, string, ?string) => Promise<any>,
|
||||
commentsDisabledBySettings: boolean,
|
||||
channels: ?Array<ChannelClaim>,
|
||||
onDoneReplying?: () => void,
|
||||
onCancelReplying?: () => void,
|
||||
|
@ -41,6 +43,7 @@ type Props = {
|
|||
export function CommentCreate(props: Props) {
|
||||
const {
|
||||
createComment,
|
||||
commentsDisabledBySettings,
|
||||
claim,
|
||||
channels,
|
||||
onDoneReplying,
|
||||
|
@ -181,6 +184,10 @@ export function CommentCreate(props: Props) {
|
|||
setAdvancedEditor(!advancedEditor);
|
||||
}
|
||||
|
||||
if (commentsDisabledBySettings) {
|
||||
return <Empty padded text={__('This channel has disabled comments on their page.')} />;
|
||||
}
|
||||
|
||||
if (!hasChannels) {
|
||||
return (
|
||||
<div
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
selectIsFetchingComments,
|
||||
makeSelectTotalCommentsCountForUri,
|
||||
selectOthersReactsById,
|
||||
makeSelectCommentsDisabledForUri,
|
||||
} from 'redux/selectors/comments';
|
||||
import { doCommentList, doCommentReactList } from 'redux/actions/comments';
|
||||
import { selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||
|
@ -18,14 +19,15 @@ const select = (state, props) => ({
|
|||
claimIsMine: makeSelectClaimIsMine(props.uri)(state),
|
||||
isFetchingComments: selectIsFetchingComments(state),
|
||||
commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true,
|
||||
commentsDisabledBySettings: makeSelectCommentsDisabledForUri(props.uri)(state),
|
||||
fetchingChannels: selectFetchingMyChannels(state),
|
||||
reactionsById: selectOthersReactsById(state),
|
||||
activeChannelId: selectActiveChannelId(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
fetchComments: uri => dispatch(doCommentList(uri)),
|
||||
fetchReacts: uri => dispatch(doCommentReactList(uri)),
|
||||
const perform = (dispatch) => ({
|
||||
fetchComments: (uri) => dispatch(doCommentList(uri)),
|
||||
fetchReacts: (uri) => dispatch(doCommentReactList(uri)),
|
||||
});
|
||||
|
||||
export default connect(select, perform)(CommentsList);
|
||||
|
|
|
@ -16,6 +16,7 @@ import Empty from 'component/common/empty';
|
|||
|
||||
type Props = {
|
||||
comments: Array<Comment>,
|
||||
commentsDisabledBySettings: boolean,
|
||||
fetchComments: (string) => void,
|
||||
fetchReacts: (string) => Promise<any>,
|
||||
uri: string,
|
||||
|
@ -35,6 +36,7 @@ function CommentList(props: Props) {
|
|||
fetchReacts,
|
||||
uri,
|
||||
comments,
|
||||
commentsDisabledBySettings,
|
||||
claimIsMine,
|
||||
myChannels,
|
||||
isFetchingComments,
|
||||
|
@ -147,7 +149,9 @@ function CommentList(props: Props) {
|
|||
}
|
||||
|
||||
// Default to newest first for apps that don't have comment reactions
|
||||
const sortedComments = reactionsById ? sortComments({ comments, reactionsById, sort, isMyComment, justCommented }) : [];
|
||||
const sortedComments = reactionsById
|
||||
? sortComments({ comments, reactionsById, sort, isMyComment, justCommented })
|
||||
: [];
|
||||
const displayedComments = readyToDisplayComments
|
||||
? prepareComments(sortedComments, linkedComment).slice(start, end)
|
||||
: [];
|
||||
|
@ -212,7 +216,7 @@ function CommentList(props: Props) {
|
|||
<>
|
||||
<CommentCreate uri={uri} justCommented={justCommented} />
|
||||
|
||||
{!isFetchingComments && hasNoComments && (
|
||||
{!commentsDisabledBySettings && !isFetchingComments && hasNoComments && (
|
||||
<Empty padded text={__('That was pretty deep. What do you think?')} />
|
||||
)}
|
||||
|
||||
|
|
|
@ -149,18 +149,18 @@ export default function SettingsCreatorPage(props: Props) {
|
|||
)}
|
||||
{!isBusy && !isDisabled && (
|
||||
<>
|
||||
{FEATURE_IS_READY && (
|
||||
<Card
|
||||
title={__('General')}
|
||||
actions={
|
||||
<>
|
||||
<FormField
|
||||
type="checkbox"
|
||||
name="comments_enabled"
|
||||
label={__('Enable comments for channel.')}
|
||||
checked={commentsEnabled}
|
||||
onChange={() => setSettings({ comments_enabled: !commentsEnabled })}
|
||||
/>
|
||||
<Card
|
||||
title={__('General')}
|
||||
actions={
|
||||
<>
|
||||
<FormField
|
||||
type="checkbox"
|
||||
name="comments_enabled"
|
||||
label={__('Enable comments for channel.')}
|
||||
checked={commentsEnabled}
|
||||
onChange={() => setSettings({ comments_enabled: !commentsEnabled })}
|
||||
/>
|
||||
{FEATURE_IS_READY && (
|
||||
<FormField
|
||||
name="slow_mode_min_gap"
|
||||
label={__('Minimum time gap in seconds for Slow Mode in livestream chat.')}
|
||||
|
@ -171,10 +171,10 @@ export default function SettingsCreatorPage(props: Props) {
|
|||
value={slowModeMinGap}
|
||||
onChange={(e) => setSettings({ slow_mode_min_gap: e.target.value })}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Card
|
||||
title={__('Filter')}
|
||||
actions={
|
||||
|
|
|
@ -34,10 +34,15 @@ export function doCommentList(uri: string, page: number = 1, pageSize: number =
|
|||
type: ACTIONS.COMMENT_LIST_STARTED,
|
||||
});
|
||||
|
||||
// Adding 'channel_id' and 'channel_name' enables "CreatorSettings > commentsEnabled".
|
||||
const authorChannelClaim = claim.value_type === 'channel' ? claim : claim.signing_channel;
|
||||
|
||||
return Comments.comment_list({
|
||||
page,
|
||||
claim_id: claimId,
|
||||
page_size: pageSize,
|
||||
channel_id: authorChannelClaim ? authorChannelClaim.claim_id : undefined,
|
||||
channel_name: authorChannelClaim ? authorChannelClaim.name : undefined,
|
||||
})
|
||||
.then((result: CommentListResponse) => {
|
||||
const { items: comments } = result;
|
||||
|
@ -46,16 +51,27 @@ export function doCommentList(uri: string, page: number = 1, pageSize: number =
|
|||
data: {
|
||||
comments,
|
||||
claimId: claimId,
|
||||
authorClaimId: authorChannelClaim ? authorChannelClaim.claim_id : undefined,
|
||||
uri: uri,
|
||||
},
|
||||
});
|
||||
return result;
|
||||
})
|
||||
.catch((error) => {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_LIST_FAILED,
|
||||
data: error,
|
||||
});
|
||||
if (error.message === 'comments are disabled by the creator') {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_LIST_COMPLETED,
|
||||
data: {
|
||||
authorClaimId: authorChannelClaim ? authorChannelClaim.claim_id : undefined,
|
||||
disabled: true,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
dispatch({
|
||||
type: ACTIONS.COMMENT_LIST_FAILED,
|
||||
data: error,
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ const defaultState: CommentsState = {
|
|||
fetchingModerationBlockList: false,
|
||||
blockingByUri: {},
|
||||
unBlockingByUri: {},
|
||||
commentsDisabledChannelIds: [],
|
||||
settingsByChannelId: {}, // ChannelId -> PerChannelSettings
|
||||
fetchingSettings: false,
|
||||
fetchingBlockedWords: false,
|
||||
|
@ -167,7 +168,25 @@ export default handleActions(
|
|||
[ACTIONS.COMMENT_LIST_STARTED]: (state) => ({ ...state, isLoading: true }),
|
||||
|
||||
[ACTIONS.COMMENT_LIST_COMPLETED]: (state: CommentsState, action: any) => {
|
||||
const { comments, claimId, uri } = action.data;
|
||||
const { comments, claimId, uri, disabled, authorClaimId } = action.data;
|
||||
const commentsDisabledChannelIds = [...state.commentsDisabledChannelIds];
|
||||
|
||||
if (disabled) {
|
||||
if (!commentsDisabledChannelIds.includes(authorClaimId)) {
|
||||
commentsDisabledChannelIds.push(authorClaimId);
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
commentsDisabledChannelIds,
|
||||
isLoading: false,
|
||||
};
|
||||
} else {
|
||||
const index = commentsDisabledChannelIds.indexOf(authorClaimId);
|
||||
if (index > -1) {
|
||||
commentsDisabledChannelIds.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
const commentById = Object.assign({}, state.commentById);
|
||||
const byId = Object.assign({}, state.byId);
|
||||
|
@ -213,6 +232,7 @@ export default handleActions(
|
|||
byId,
|
||||
commentById,
|
||||
commentsByUri,
|
||||
commentsDisabledChannelIds,
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ import { createSelector } from 'reselect';
|
|||
import { selectMutedChannels } from 'redux/selectors/blocked';
|
||||
import { selectShowMatureContent } from 'redux/selectors/settings';
|
||||
import { selectBlacklistedOutpointMap, selectFilteredOutpointMap } from 'lbryinc';
|
||||
import { selectClaimsById, isClaimNsfw, selectMyActiveClaims } from 'lbry-redux';
|
||||
import { selectClaimsById, isClaimNsfw, selectMyActiveClaims, makeSelectClaimForUri } from 'lbry-redux';
|
||||
|
||||
const selectState = (state) => state.comments || {};
|
||||
|
||||
|
@ -11,6 +11,10 @@ export const selectCommentsById = createSelector(selectState, (state) => state.c
|
|||
export const selectIsFetchingComments = createSelector(selectState, (state) => state.isLoading);
|
||||
export const selectIsPostingComment = createSelector(selectState, (state) => state.isCommenting);
|
||||
export const selectIsFetchingReacts = createSelector(selectState, (state) => state.isFetchingReacts);
|
||||
export const selectCommentsDisabledChannelIds = createSelector(
|
||||
selectState,
|
||||
(state) => state.commentsDisabledChannelIds
|
||||
);
|
||||
export const selectOthersReactsById = createSelector(selectState, (state) => state.othersReactsByCommentId);
|
||||
export const selectModerationBlockList = createSelector(selectState, (state) =>
|
||||
state.moderationBlockList ? state.moderationBlockList.reverse() : []
|
||||
|
@ -330,3 +334,15 @@ export const makeSelectSuperChatTotalAmountForUri = (uri: string) =>
|
|||
|
||||
return superChatData.totalAmount;
|
||||
});
|
||||
|
||||
export const makeSelectCommentsDisabledForUri = (uri: string) =>
|
||||
createSelector(selectCommentsDisabledChannelIds, makeSelectClaimForUri(uri), (commentsDisabledChannelIds, claim) => {
|
||||
const channelClaim = !claim
|
||||
? null
|
||||
: claim.value_type === 'channel'
|
||||
? claim
|
||||
: claim.signing_channel && claim.is_channel_signature_valid
|
||||
? claim.signing_channel
|
||||
: null;
|
||||
return channelClaim && channelClaim.claim_id && commentsDisabledChannelIds.includes(channelClaim.claim_id);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue