From 33a0b063c439ec8586ef3d5bf27b86ed6dd73bb6 Mon Sep 17 00:00:00 2001 From: Sean Yesmunt Date: Thu, 25 Feb 2021 12:43:56 -0500 Subject: [PATCH 1/9] initial support for block/mute --- flow-typed/Comment.js | 4 + package.json | 4 +- ui/comments.js | 6 +- ui/component/abandonedChannelPreview/index.js | 12 +- ui/component/abandonedChannelPreview/view.jsx | 45 +---- ui/component/app/index.js | 10 +- ui/component/app/view.jsx | 22 ++- ui/component/blockButton/index.js | 18 -- ui/component/blockButton/view.jsx | 49 ----- ui/component/channelBlockButton/index.js | 14 ++ ui/component/channelBlockButton/view.jsx | 41 ++++ ui/component/channelContent/index.js | 4 +- ui/component/channelMuteButton/index.js | 12 ++ ui/component/channelMuteButton/view.jsx | 24 +++ ui/component/channelStakedIndicator/view.jsx | 4 +- ui/component/claimList/view.jsx | 6 +- ui/component/claimListDiscover/index.js | 6 +- ui/component/claimListDiscover/view.jsx | 45 ++--- .../claimMenuList/claim-preview-loading.jsx | 30 +++ .../claim-preview-no-content.jsx | 32 ++++ .../claimMenuList/claim-preview-no-mature.jsx | 33 ++++ ui/component/claimMenuList/index.js | 20 ++ ui/component/claimMenuList/view.jsx | 86 +++++++++ ui/component/claimPreview/index.js | 12 +- ui/component/claimPreview/view.jsx | 28 +-- ui/component/claimPreviewTile/index.js | 10 +- ui/component/claimPreviewTile/view.jsx | 3 + ui/component/claimTilesDiscover/index.js | 6 +- ui/component/comment/index.js | 4 +- ui/component/comment/view.jsx | 2 +- ui/component/commentMenuList/index.js | 17 +- ui/component/commentMenuList/view.jsx | 52 ++--- ui/component/common/icon-custom.jsx | 7 + ui/component/fileAuthor/view.jsx | 2 +- ui/component/notification/view.jsx | 6 +- ui/component/router/view.jsx | 2 +- ui/constants/action_types.js | 9 + ui/constants/icons.js | 1 + ui/constants/modal_types.js | 1 - ui/constants/pages.js | 2 +- ui/modal/modalRemoveBlocked/index.js | 16 -- ui/modal/modalRemoveBlocked/view.jsx | 46 ----- ui/modal/modalRouter/view.jsx | 3 - ui/page/channel/index.js | 8 +- ui/page/channel/view.jsx | 4 +- ui/page/channelsFollowingDiscover/index.js | 6 +- ui/page/listBlocked/index.js | 11 +- ui/page/listBlocked/view.jsx | 123 ++++++++++-- ui/page/settings/index.js | 12 +- ui/page/settings/view.jsx | 35 ++-- ui/redux/actions/blocked.js | 2 +- ui/redux/actions/comments.js | 181 +++++++++++++++--- ui/redux/reducers/blocked.js | 6 +- ui/redux/reducers/comments.js | 107 +++++++++-- ui/redux/selectors/blocked.js | 20 +- ui/redux/selectors/comments.js | 79 +++++--- ui/redux/selectors/content.js | 4 +- ui/scss/component/_channel.scss | 10 + ui/scss/component/_claim-list.scss | 67 +++++-- ui/scss/component/menu-button.scss | 27 ++- ui/scss/init/_color.scss | 2 +- ui/store.js | 9 +- ui/util/hex.js | 48 ++++- 63 files changed, 1015 insertions(+), 502 deletions(-) delete mode 100644 ui/component/blockButton/index.js delete mode 100644 ui/component/blockButton/view.jsx create mode 100644 ui/component/channelBlockButton/index.js create mode 100644 ui/component/channelBlockButton/view.jsx create mode 100644 ui/component/channelMuteButton/index.js create mode 100644 ui/component/channelMuteButton/view.jsx create mode 100644 ui/component/claimMenuList/claim-preview-loading.jsx create mode 100644 ui/component/claimMenuList/claim-preview-no-content.jsx create mode 100644 ui/component/claimMenuList/claim-preview-no-mature.jsx create mode 100644 ui/component/claimMenuList/index.js create mode 100644 ui/component/claimMenuList/view.jsx delete mode 100644 ui/modal/modalRemoveBlocked/index.js delete mode 100644 ui/modal/modalRemoveBlocked/view.jsx diff --git a/flow-typed/Comment.js b/flow-typed/Comment.js index 1ee6e4916..816b9123f 100644 --- a/flow-typed/Comment.js +++ b/flow-typed/Comment.js @@ -27,6 +27,10 @@ declare type CommentsState = { myReactsByCommentId: any, othersReactsByCommentId: any, pendingCommentReactions: Array, + moderationBlockList: ?Array, + fetchingModerationBlockList: boolean, + blockingByUri: {}, + unBlockingByUri: {}, }; declare type CommentReactParams = { diff --git a/package.json b/package.json index 957c9e160..138c933da 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "electron-updater": "^4.2.4", "express": "^4.17.1", "if-env": "^1.0.4", - "remove-markdown": "^0.3.0", + "remove-markdown": "^0.3.0", "tempy": "^0.6.0", "videojs-logo": "^2.1.4" }, @@ -184,7 +184,7 @@ "redux-thunk": "^2.2.0", "remark": "^9.0.0", "remark-attr": "^0.8.3", - "remark-breaks": "^1.0.5", + "remark-breaks": "^1.0.5", "remark-emoji": "^2.0.1", "remark-frontmatter": "^2.0.0", "remark-react": "^8.0.0", diff --git a/ui/comments.js b/ui/comments.js index 0bd342256..fe7ed5b16 100644 --- a/ui/comments.js +++ b/ui/comments.js @@ -6,6 +6,8 @@ const Comments = { enabled: Boolean(COMMENT_SERVER_API), moderation_block: (params: ModerationBlockParams) => fetchCommentsApi('moderation.Block', params), + moderation_unblock: (params: ModerationBlockParams) => fetchCommentsApi('moderation.UnBlock', params), + moderation_block_list: (params: ModerationBlockParams) => fetchCommentsApi('moderation.BlockedList', params), comment_list: (params: CommentListParams) => fetchCommentsApi('comment.List', params), comment_abandon: (params: CommentAbandonParams) => fetchCommentsApi('comment.Abandon', params), }; @@ -30,8 +32,8 @@ function fetchCommentsApi(method: string, params: {}) { }; return fetch(url, options) - .then(res => res.json()) - .then(res => res.result); + .then((res) => res.json()) + .then((res) => res.result); } export default Comments; diff --git a/ui/component/abandonedChannelPreview/index.js b/ui/component/abandonedChannelPreview/index.js index a401da12f..669f6602e 100644 --- a/ui/component/abandonedChannelPreview/index.js +++ b/ui/component/abandonedChannelPreview/index.js @@ -1,14 +1,6 @@ import { connect } from 'react-redux'; -import { selectBlockedChannels } from 'redux/selectors/blocked'; -import { doChannelUnsubscribe } from 'redux/actions/subscriptions'; -import { doOpenModal } from 'redux/actions/app'; import AbandonedChannelPreview from './view'; -const select = (state, props) => ({ - blockedChannelUris: selectBlockedChannels(state), -}); +const select = (state, props) => ({}); -export default connect(select, { - doChannelUnsubscribe, - doOpenModal, -})(AbandonedChannelPreview); +export default connect(select)(AbandonedChannelPreview); diff --git a/ui/component/abandonedChannelPreview/view.jsx b/ui/component/abandonedChannelPreview/view.jsx index 11ee632b9..755e015ee 100644 --- a/ui/component/abandonedChannelPreview/view.jsx +++ b/ui/component/abandonedChannelPreview/view.jsx @@ -2,28 +2,18 @@ import React from 'react'; import classnames from 'classnames'; import ChannelThumbnail from 'component/channelThumbnail'; -import Button from 'component/button'; import { parseURI } from 'lbry-redux'; -import * as ICONS from '../../constants/icons'; -import * as MODALS from 'constants/modal_types'; - -type SubscriptionArgs = { - channelName: string, - uri: string, -}; +import ChannelBlockButton from 'component/channelBlockButton'; +import ChannelMuteButton from 'component/channelMuteButton'; type Props = { uri: string, - doChannelUnsubscribe: SubscriptionArgs => void, type: string, - blockedChannelUris: Array, - doOpenModal: (string, {}) => void, }; function AbandonedChannelPreview(props: Props) { - const { uri, doChannelUnsubscribe, type, blockedChannelUris, doOpenModal } = props; + const { uri, type } = props; const { channelName } = parseURI(uri); - const isBlockedChannel = blockedChannelUris.includes(uri); return (
  • @@ -37,31 +27,10 @@ function AbandonedChannelPreview(props: Props) {
    {__(`This channel may have been unpublished.`)}
    - {isBlockedChannel && ( -
    diff --git a/ui/component/app/index.js b/ui/component/app/index.js index ba179d3fd..84b62c9f9 100644 --- a/ui/component/app/index.js +++ b/ui/component/app/index.js @@ -27,9 +27,10 @@ import { doSetActiveChannel, doSetIncognito, } from 'redux/actions/app'; +import { doFetchModBlockedList } from 'redux/actions/comments'; import App from './view'; -const select = state => ({ +const select = (state) => ({ user: selectUser(state), accessToken: selectAccessToken(state), theme: selectThemePath(state), @@ -48,18 +49,19 @@ const select = state => ({ myChannelUrls: selectMyChannelUrls(state), }); -const perform = dispatch => ({ +const perform = (dispatch) => ({ fetchAccessToken: () => dispatch(doFetchAccessToken()), fetchChannelListMine: () => dispatch(doFetchChannelListMine()), - setLanguage: language => dispatch(doSetLanguage(language)), + setLanguage: (language) => dispatch(doSetLanguage(language)), signIn: () => dispatch(doSignIn()), requestDownloadUpgrade: () => dispatch(doDownloadUpgradeRequested()), updatePreferences: () => dispatch(doGetAndPopulatePreferences()), getWalletSyncPref: () => dispatch(doGetWalletSyncPreference()), - syncLoop: noInterval => dispatch(doSyncLoop(noInterval)), + syncLoop: (noInterval) => dispatch(doSyncLoop(noInterval)), setReferrer: (referrer, doClaim) => dispatch(doUserSetReferrer(referrer, doClaim)), setActiveChannelIfNotSet: () => dispatch(doSetActiveChannel()), setIncognito: () => dispatch(doSetIncognito()), + fetchModBlockedList: () => dispatch(doFetchModBlockedList()), }); export default hot(connect(select, perform)(App)); diff --git a/ui/component/app/view.jsx b/ui/component/app/view.jsx index 2324e58c6..d29542f79 100644 --- a/ui/component/app/view.jsx +++ b/ui/component/app/view.jsx @@ -56,14 +56,14 @@ type Props = { goForward: () => void, index: number, length: number, - push: string => void, + push: (string) => void, }, fetchAccessToken: () => void, fetchChannelListMine: () => void, signIn: () => void, requestDownloadUpgrade: () => void, onSignedIn: () => void, - setLanguage: string => void, + setLanguage: (string) => void, isUpgradeAvailable: boolean, autoUpdateDownloaded: boolean, updatePreferences: () => Promise, @@ -83,7 +83,8 @@ type Props = { activeChannelClaim: ?ChannelClaim, myChannelUrls: ?Array, setActiveChannelIfNotSet: () => void, - setIncognito: boolean => void, + setIncognito: (boolean) => void, + fetchModBlockedList: () => void, }; function App(props: Props) { @@ -114,6 +115,7 @@ function App(props: Props) { activeChannelClaim, setActiveChannelIfNotSet, setIncognito, + fetchModBlockedList, } = props; const appRef = useRef(); @@ -134,7 +136,7 @@ function App(props: Props) { const showUpgradeButton = (autoUpdateDownloaded || (process.platform === 'linux' && isUpgradeAvailable)) && !upgradeNagClosed; // referral claiming - const referredRewardAvailable = rewards && rewards.some(reward => reward.reward_type === REWARDS.TYPE_REFEREE); + const referredRewardAvailable = rewards && rewards.some((reward) => reward.reward_type === REWARDS.TYPE_REFEREE); const urlParams = new URLSearchParams(search); const rawReferrerParam = urlParams.get('r'); const sanitizedReferrerParam = rawReferrerParam && rawReferrerParam.replace(':', '#'); @@ -166,7 +168,7 @@ function App(props: Props) { useEffect(() => { if (!uploadCount) return; - const handleBeforeUnload = event => { + const handleBeforeUnload = (event) => { event.preventDefault(); event.returnValue = 'magic'; // without setting this to something it doesn't work }; @@ -176,7 +178,7 @@ function App(props: Props) { // allows user to navigate history using the forward and backward buttons on a mouse useEffect(() => { - const handleForwardAndBackButtons = e => { + const handleForwardAndBackButtons = (e) => { switch (e.button) { case MOUSE_BACK_BTN: history.index > 0 && history.goBack(); @@ -192,7 +194,7 @@ function App(props: Props) { // allows user to pause miniplayer using the spacebar without the page scrolling down useEffect(() => { - const handleKeyPress = e => { + const handleKeyPress = (e) => { if (e.key === ' ' && e.target === document.body) { e.preventDefault(); } @@ -244,6 +246,10 @@ function App(props: Props) { } else if (hasNoChannels) { setIncognito(true); } + + if (hasMyChannels) { + fetchModBlockedList(); + } }, [hasMyChannels, hasNoChannels, hasActiveChannelClaim, setActiveChannelIfNotSet, setIncognito]); useEffect(() => { @@ -358,7 +364,7 @@ function App(props: Props) { [`${MAIN_WRAPPER_CLASS}--scrollbar`]: useCustomScrollbar, })} ref={appRef} - onContextMenu={IS_WEB ? undefined : e => openContextMenu(e)} + onContextMenu={IS_WEB ? undefined : (e) => openContextMenu(e)} > {IS_WEB && lbryTvApiStatus === STATUS_DOWN ? ( ({ - channelIsBlocked: selectChannelIsBlocked(props.uri)(state), - claimIsMine: makeSelectClaimIsMine(props.uri)(state), - shortUrl: makeSelectShortUrlForUri(props.uri)(state), - permanentUrl: makeSelectPermanentUrlForUri(props.uri)(state), -}); - -export default connect(select, { - toggleBlockChannel: doToggleBlockChannel, - doToast, -})(BlockButton); diff --git a/ui/component/blockButton/view.jsx b/ui/component/blockButton/view.jsx deleted file mode 100644 index a749f0cfa..000000000 --- a/ui/component/blockButton/view.jsx +++ /dev/null @@ -1,49 +0,0 @@ -// @flow -import * as ICONS from 'constants/icons'; -import * as PAGES from 'constants/pages'; -import React, { useRef } from 'react'; -import Button from 'component/button'; -import useHover from 'effects/use-hover'; - -type Props = { - permanentUrl: ?string, - shortUrl: string, - isSubscribed: boolean, - toggleBlockChannel: (uri: string) => void, - channelIsBlocked: boolean, - claimIsMine: boolean, - doToast: ({ message: string, linkText: string, linkTarget: string }) => void, -}; - -export default function BlockButton(props: Props) { - const { permanentUrl, shortUrl, toggleBlockChannel, channelIsBlocked, claimIsMine, doToast } = props; - - const blockRef = useRef(); - const isHovering = useHover(blockRef); - const blockLabel = channelIsBlocked ? __('Blocked') : __('Block'); - const blockTitlePrefix = channelIsBlocked ? __('Unblock this channel') : __('Block this channel'); - const blockedOverride = channelIsBlocked && isHovering && __('Unblock'); - - return permanentUrl && (!claimIsMine || channelIsBlocked) ? ( -