provide tags for disabling comments
This commit is contained in:
parent
d47d55098e
commit
a85c9a1f48
8 changed files with 126 additions and 60 deletions
|
@ -3,6 +3,7 @@ import { withRouter } from 'react-router';
|
|||
import { makeSelectCommentForCommentId } from 'redux/selectors/comments';
|
||||
|
||||
import ChannelDiscussion from './view';
|
||||
import { makeSelectTagsForUri } from 'lbry-redux';
|
||||
|
||||
const select = (state, props) => {
|
||||
const { search } = props.location;
|
||||
|
@ -11,6 +12,7 @@ const select = (state, props) => {
|
|||
|
||||
return {
|
||||
linkedComment: makeSelectCommentForCommentId(linkedCommentId)(state),
|
||||
tags: makeSelectTagsForUri(props.uri)(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import CommentsList from 'component/commentsList';
|
||||
import Empty from 'component/common/empty';
|
||||
|
||||
type Props = {
|
||||
uri: string,
|
||||
linkedComment: ?any,
|
||||
tags: Array<string>,
|
||||
};
|
||||
|
||||
function ChannelDiscussion(props: Props) {
|
||||
const { uri, linkedComment } = props;
|
||||
const { uri, linkedComment, tags } = props;
|
||||
|
||||
if (tags.includes('disable_comments')) {
|
||||
return <Empty text={__('Comments are disabled here.')} />;
|
||||
}
|
||||
return (
|
||||
<section className="section">
|
||||
<CommentsList uri={uri} linkedComment={linkedComment} />
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { selectUnfollowedTags, selectFollowedTags } from 'redux/selectors/tags';
|
||||
import { doToggleTagFollowDesktop, doAddTag, doDeleteTag } from 'redux/actions/tags';
|
||||
import { selectUser } from 'redux/selectors/user';
|
||||
import DiscoveryFirstRun from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
unfollowedTags: selectUnfollowedTags(state),
|
||||
followedTags: selectFollowedTags(state),
|
||||
user: selectUser(state),
|
||||
});
|
||||
|
||||
export default connect(select, {
|
||||
|
|
|
@ -5,6 +5,7 @@ import Tag from 'component/tag';
|
|||
import { setUnion, setDifference } from 'util/set-operations';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import analytics from 'analytics';
|
||||
import { UTILITY_TAGS } from 'constants/tags';
|
||||
|
||||
type Props = {
|
||||
tagsPassedIn: Array<Tag>,
|
||||
|
@ -21,6 +22,7 @@ type Props = {
|
|||
disabled?: boolean,
|
||||
limitSelect?: number,
|
||||
limitShow?: number,
|
||||
user: User,
|
||||
};
|
||||
|
||||
const UNALLOWED_TAGS = ['lbry-first'];
|
||||
|
@ -49,6 +51,7 @@ export default function TagsSearch(props: Props) {
|
|||
disabled,
|
||||
limitSelect = TAG_FOLLOW_MAX,
|
||||
limitShow = 5,
|
||||
user,
|
||||
} = props;
|
||||
const [newTag, setNewTag] = useState('');
|
||||
const doesTagMatch = name => {
|
||||
|
@ -58,7 +61,7 @@ export default function TagsSearch(props: Props) {
|
|||
|
||||
// Make sure there are no duplicates, then trim
|
||||
// suggestedTags = (followedTags - tagsPassedIn) + unfollowedTags
|
||||
|
||||
const experimentalFeature = user && user.experimental_ui;
|
||||
const followedTagsSet = new Set(followedTags.map(tag => tag.name));
|
||||
const selectedTagsSet = new Set(tagsPassedIn.map(tag => tag.name));
|
||||
const unfollowedTagsSet = new Set(unfollowedTags.map(tag => tag.name));
|
||||
|
@ -71,6 +74,12 @@ export default function TagsSearch(props: Props) {
|
|||
countWithoutSpecialTags = countWithoutSpecialTags - 1;
|
||||
}
|
||||
|
||||
UTILITY_TAGS.forEach(t => {
|
||||
if (selectedTagsSet.has(t)) {
|
||||
countWithoutSpecialTags--;
|
||||
}
|
||||
});
|
||||
|
||||
// const countWithoutLbryFirst = selectedTagsSet.has('lbry-first') ? selectedTagsSet.size - 1 : selectedTagsSet.size;
|
||||
const maxed = Boolean(limitSelect && countWithoutSpecialTags >= limitSelect);
|
||||
const suggestedTags = Array.from(suggestedTagsSet)
|
||||
|
@ -134,70 +143,103 @@ export default function TagsSearch(props: Props) {
|
|||
analytics.tagFollowEvent(tag, !wasFollowing);
|
||||
}
|
||||
}
|
||||
function handleUtilityTagCheckbox(tag: string) {
|
||||
const selectedTag = tagsPassedIn.find(te => te.name === tag);
|
||||
if (selectedTag) {
|
||||
onRemove(selectedTag);
|
||||
} else if (onSelect) {
|
||||
onSelect([{ name: tag }]);
|
||||
// call an api
|
||||
}
|
||||
}
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Form className="tags__input-wrapper" onSubmit={handleSubmit}>
|
||||
<label>
|
||||
{limitSelect < TAG_FOLLOW_MAX ? (
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
number: limitSelect - countWithoutSpecialTags,
|
||||
selectTagsLabel: label,
|
||||
}}
|
||||
>
|
||||
%selectTagsLabel% (%number% left)
|
||||
</I18nMessage>
|
||||
) : (
|
||||
label || __('Following --[button label indicating a channel has been followed]--')
|
||||
)}
|
||||
</label>
|
||||
<ul className="tags--remove">
|
||||
{!tagsPassedIn.length && <Tag key={`placeholder-tag`} name={'example'} disabled type={'remove'} />}
|
||||
{Boolean(tagsPassedIn.length) &&
|
||||
tagsPassedIn.map(tag => (
|
||||
<Tag
|
||||
key={`passed${tag.name}`}
|
||||
name={tag.name}
|
||||
type="remove"
|
||||
onClick={() => {
|
||||
onRemove(tag);
|
||||
<fieldset-section>
|
||||
<label>
|
||||
{limitSelect < TAG_FOLLOW_MAX ? (
|
||||
<I18nMessage
|
||||
tokens={{
|
||||
number: limitSelect - countWithoutSpecialTags,
|
||||
selectTagsLabel: label,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
<FormField
|
||||
autoFocus={!disableAutoFocus}
|
||||
className="tag__input"
|
||||
onChange={onChange}
|
||||
placeholder={placeholder || __('gaming, crypto')}
|
||||
type="text"
|
||||
value={newTag}
|
||||
disabled={disabled}
|
||||
label={__('Add Tags')}
|
||||
/>
|
||||
<section>
|
||||
<label>{newTag.length ? __('Matching') : __('Known Tags')}</label>
|
||||
<ul className="tags">
|
||||
{Boolean(newTag.length) && !suggestedTags.includes(newTag) && (
|
||||
<Tag
|
||||
disabled={newTag !== 'mature' && maxed}
|
||||
key={`entered${newTag}`}
|
||||
name={newTag}
|
||||
type="add"
|
||||
onClick={newTag.includes('') ? e => handleSubmit(e) : e => handleTagClick(newTag)}
|
||||
/>
|
||||
>
|
||||
%selectTagsLabel% (%number% left)
|
||||
</I18nMessage>
|
||||
) : (
|
||||
label || __('Following --[button label indicating a channel has been followed]--')
|
||||
)}
|
||||
{suggestedTags.map(tag => (
|
||||
<Tag
|
||||
disabled={tag !== 'mature' && maxed}
|
||||
key={`suggested${tag}`}
|
||||
name={tag}
|
||||
type="add"
|
||||
onClick={() => handleTagClick(tag)}
|
||||
</label>
|
||||
<ul className="tags--remove">
|
||||
{!tagsPassedIn.length && <Tag key={`placeholder-tag`} name={'example'} disabled type={'remove'} />}
|
||||
{Boolean(tagsPassedIn.length) &&
|
||||
// .filter(t => !UTILITY_TAGS.includes(t.name))
|
||||
tagsPassedIn.map(tag => (
|
||||
<Tag
|
||||
key={`passed${tag.name}`}
|
||||
name={tag.name}
|
||||
type="remove"
|
||||
onClick={() => {
|
||||
onRemove(tag);
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
<FormField
|
||||
autoFocus={!disableAutoFocus}
|
||||
className="tag__input"
|
||||
onChange={onChange}
|
||||
placeholder={placeholder || __('gaming, crypto')}
|
||||
type="text"
|
||||
value={newTag}
|
||||
disabled={disabled}
|
||||
label={__('Add Tags')}
|
||||
/>
|
||||
<section>
|
||||
<label>{newTag.length ? __('Matching') : __('Known Tags')}</label>
|
||||
<ul className="tags">
|
||||
{Boolean(newTag.length) && !suggestedTags.includes(newTag) && (
|
||||
<Tag
|
||||
disabled={newTag !== 'mature' && maxed}
|
||||
key={`entered${newTag}`}
|
||||
name={newTag}
|
||||
type="add"
|
||||
onClick={newTag.includes('') ? e => handleSubmit(e) : e => handleTagClick(newTag)}
|
||||
/>
|
||||
)}
|
||||
{suggestedTags.map(tag => (
|
||||
<Tag
|
||||
disabled={tag !== 'mature' && maxed}
|
||||
key={`suggested${tag}`}
|
||||
name={tag}
|
||||
type="add"
|
||||
onClick={() => handleTagClick(tag)}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
</fieldset-section>
|
||||
{experimentalFeature && onSelect && (
|
||||
<fieldset-section>
|
||||
<label>{__('Control Tags')}</label>
|
||||
{UTILITY_TAGS.map(t => (
|
||||
<FormField
|
||||
key={t}
|
||||
name={t}
|
||||
type="checkbox"
|
||||
blockWrap={false}
|
||||
label={__(
|
||||
t
|
||||
.split('_')
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(' ')
|
||||
)}
|
||||
checked={tagsPassedIn.some(te => te.name === t)}
|
||||
onChange={() => handleUtilityTagCheckbox(t)}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
</fieldset-section>
|
||||
)}
|
||||
</Form>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
|
|
@ -13,6 +13,12 @@ export const DEFAULT_FOLLOWED_TAGS = [
|
|||
'technology',
|
||||
];
|
||||
|
||||
export const UTILITY_TAGS = [
|
||||
// 'disable_supports',
|
||||
'disable_comments',
|
||||
// 'disable_reactions',
|
||||
];
|
||||
|
||||
export const MATURE_TAGS = [
|
||||
'porn',
|
||||
'porno',
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
selectCurrentChannelPage,
|
||||
makeSelectClaimForUri,
|
||||
makeSelectClaimIsPending,
|
||||
makeSelectTagsForUri,
|
||||
} from 'lbry-redux';
|
||||
import { selectChannelIsBlocked } from 'redux/selectors/blocked';
|
||||
import { selectBlackListedOutpoints, doFetchSubCount, makeSelectSubCountForUri } from 'lbryinc';
|
||||
|
@ -28,6 +29,7 @@ const select = (state, props) => ({
|
|||
subCount: makeSelectSubCountForUri(props.uri)(state),
|
||||
pending: makeSelectClaimIsPending(props.uri)(state),
|
||||
youtubeChannels: selectYoutubeChannels(state),
|
||||
tags: makeSelectTagsForUri(props.uri)(state),
|
||||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
|
|
|
@ -7,6 +7,7 @@ import {
|
|||
makeSelectMetadataForUri,
|
||||
makeSelectClaimIsNsfw,
|
||||
SETTINGS,
|
||||
makeSelectTagInClaimOrChannelForUri,
|
||||
} from 'lbry-redux';
|
||||
import { makeSelectCostInfoForUri, doFetchCostInfoForUri } from 'lbryinc';
|
||||
import { selectShowMatureContent, makeSelectClientSetting } from 'redux/selectors/settings';
|
||||
|
@ -18,6 +19,7 @@ const select = (state, props) => {
|
|||
const { search } = props.location;
|
||||
const urlParams = new URLSearchParams(search);
|
||||
const linkedCommentId = urlParams.get('lc');
|
||||
const DISABLE_COMMENTS_TAG = 'disable_comments';
|
||||
|
||||
return {
|
||||
linkedComment: makeSelectCommentForCommentId(linkedCommentId)(state),
|
||||
|
@ -28,6 +30,7 @@ const select = (state, props) => {
|
|||
fileInfo: makeSelectFileInfoForUri(props.uri)(state),
|
||||
renderMode: makeSelectFileRenderModeForUri(props.uri)(state),
|
||||
videoTheaterMode: makeSelectClientSetting(SETTINGS.VIDEO_THEATER_MODE)(state),
|
||||
disableComments: makeSelectTagInClaimOrChannelForUri(props.uri, DISABLE_COMMENTS_TAG)(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import FileRenderInline from 'component/fileRenderInline';
|
|||
import FileRenderDownload from 'component/fileRenderDownload';
|
||||
import RecommendedContent from 'component/recommendedContent';
|
||||
import CommentsList from 'component/commentsList';
|
||||
import Empty from 'component/common/empty';
|
||||
|
||||
export const PRIMARY_PLAYER_WRAPPER_CLASS = 'file-page__video-container';
|
||||
|
||||
|
@ -25,6 +26,7 @@ type Props = {
|
|||
linkedComment: any,
|
||||
setPrimaryUri: (?string) => void,
|
||||
videoTheaterMode: boolean,
|
||||
disableComments: boolean,
|
||||
};
|
||||
|
||||
function FilePage(props: Props) {
|
||||
|
@ -41,6 +43,7 @@ function FilePage(props: Props) {
|
|||
linkedComment,
|
||||
setPrimaryUri,
|
||||
videoTheaterMode,
|
||||
disableComments,
|
||||
} = props;
|
||||
const cost = costInfo ? costInfo.cost : null;
|
||||
const hasFileInfo = fileInfo !== undefined;
|
||||
|
@ -120,7 +123,8 @@ function FilePage(props: Props) {
|
|||
<div className="file-page__secondary-content">
|
||||
<div>
|
||||
{RENDER_MODES.FLOATING_MODES.includes(renderMode) && <FileTitle uri={uri} />}
|
||||
<CommentsList uri={uri} linkedComment={linkedComment} />
|
||||
{disableComments && <Empty text={__('Comments are disabled here.')} />}
|
||||
{!disableComments && <CommentsList uri={uri} linkedComment={linkedComment} />}
|
||||
</div>
|
||||
{videoTheaterMode && <RecommendedContent uri={uri} />}
|
||||
</div>
|
||||
|
|
Loading…
Add table
Reference in a new issue