From de6c6f9bfd0383e9087a38f1f54e13bb54754945 Mon Sep 17 00:00:00 2001 From: infinite-persistence <64950861+infinite-persistence@users.noreply.github.com> Date: Fri, 1 Oct 2021 20:10:27 +0800 Subject: [PATCH] List own comments (#7171) * Add option to pass in url-search params. Impetus: allow linked comment ID and setting the discussion tab when clicking on the `ClaimPreview`. * comment.list: fix typos and renamed variables - Switch from 'author' to 'creator' to disambiguate between comment author and content author. For comment author, we'll use 'commenter' from now on. - Corrected 'commenterClaimId' to 'creatorClaimId' (just a typo, no functional change). * doCommentReset: change param from uri to claimId This reduces one lookup as clients will always have the claimID ready, but might not have the full URI. It was using URI previously just to match the other APIs. * Add doCommentListOwn -- command to fetch own comments Since the redux slice is set up based on content or channel ID (for Channel Discussion page), re-use the channel ID for the case of "own comments". We always clear each ID when fetching page-0, so no worries of conflict when actually browsing the Channel Discussion page. * Comment: add option to hide the actions section * Implement own-comments page * Use new param to remove sort-pins-first. comment.List currently always pushes pins to the top to support pagination. This new param removes this behavior. --- flow-typed/Comment.js | 4 +- static/app-strings.json | 4 + ui/component/claimPreview/view.jsx | 7 + ui/component/comment/view.jsx | 28 ++-- ui/component/commentsList/index.js | 2 +- ui/component/commentsList/view.jsx | 7 +- ui/component/router/view.jsx | 2 + ui/component/settingAccount/index.js | 3 +- ui/component/settingAccount/view.jsx | 14 +- ui/constants/comment.js | 1 + ui/constants/pageTitles.js | 1 + ui/constants/pages.js | 1 + ui/page/ownComments/index.js | 33 +++++ ui/page/ownComments/view.jsx | 210 +++++++++++++++++++++++++++ ui/redux/actions/comments.js | 131 ++++++++++++++--- ui/redux/reducers/comments.js | 6 +- ui/scss/component/_comments.scss | 57 ++++++++ 17 files changed, 472 insertions(+), 39 deletions(-) create mode 100644 ui/page/ownComments/index.js create mode 100644 ui/page/ownComments/view.jsx diff --git a/flow-typed/Comment.js b/flow-typed/Comment.js index 8b2ad570c..57a666683 100644 --- a/flow-typed/Comment.js +++ b/flow-typed/Comment.js @@ -111,14 +111,14 @@ declare type ReactionListResponse = { declare type CommentListParams = { page: number, // pagination: which page of results page_size: number, // pagination: nr of comments to show in a page (max 200) - claim_id: string, // claim id of claim being commented on + claim_id?: string, // claim id of claim being commented on channel_name?: string, // signing channel name of claim (enables 'commentsEnabled' check) channel_id?: string, // signing channel claim id of claim (enables 'commentsEnabled' check) author_claim_id?: string, // filters comments to just this author parent_id?: string, // filters comments to those under this thread top_level?: boolean, // filters to only top level comments hidden?: boolean, // if true, will show hidden comments as well - sort_by?: number, // NEWEST=0, OLDEST=1, CONTROVERSY=2, POPULARITY=3, + sort_by?: number, // @see: ui/constants/comments.js::SORT_BY }; declare type CommentListResponse = { diff --git a/static/app-strings.json b/static/app-strings.json index 36a82cd1a..5baa9217f 100644 --- a/static/app-strings.json +++ b/static/app-strings.json @@ -209,6 +209,9 @@ "Failed to copy.": "Failed to copy.", "The publisher has chosen to charge %lbc% to view this content. Your balance is currently too low to view it. Check out %reward_link% for free %lbc% or send more %lbc% to your wallet. You can also %buy_link% more %lbc%.": "The publisher has chosen to charge %lbc% to view this content. Your balance is currently too low to view it. Check out %reward_link% for free %lbc% or send more %lbc% to your wallet. You can also %buy_link% more %lbc%.", "Connecting...": "Connecting...", + "Your comments": "Your comments", + "View your past comments.": "View your past comments.", + "Content or channel was deleted.": "Content or channel was deleted.", "Comments": "Comments", "Comment": "Comment", "Comment --[button to submit something]--": "Comment", @@ -1460,6 +1463,7 @@ "Staked LBRY Credits": "Staked LBRY Credits", "1 comment": "1 comment", "%total_comments% comments": "%total_comments% comments", + "No comments": "No comments", "Upvote": "Upvote", "Downvote": "Downvote", "You loved this": "You loved this", diff --git a/ui/component/claimPreview/view.jsx b/ui/component/claimPreview/view.jsx index 343424d5f..34e7dc188 100644 --- a/ui/component/claimPreview/view.jsx +++ b/ui/component/claimPreview/view.jsx @@ -70,6 +70,7 @@ type Props = { streamingUrl: ?string, getFile: (string) => void, customShouldHide?: (Claim) => boolean, + searchParams?: { [string]: string }, showUnresolvedClaim?: boolean, showNullPlaceholder?: boolean, includeSupportAction?: boolean, @@ -125,6 +126,7 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { // modifiers active, customShouldHide, + searchParams, showNullPlaceholder, // value from show mature content user setting // true if the user doesn't wanna see nsfw content @@ -221,6 +223,11 @@ const ClaimPreview = forwardRef((props: Props, ref: any) => { if (listId) { navigateSearch.set(COLLECTIONS_CONSTS.COLLECTION_ID, listId); } + if (searchParams) { + Object.keys(searchParams).forEach((key) => { + navigateSearch.set(key, searchParams[key]); + }); + } const handleNavLinkClick = (e) => { if (onClick) { diff --git a/ui/component/comment/view.jsx b/ui/component/comment/view.jsx index b52003bcf..b4816303a 100644 --- a/ui/component/comment/view.jsx +++ b/ui/component/comment/view.jsx @@ -52,6 +52,7 @@ type Props = { doToast: ({ message: string }) => void, isTopLevel?: boolean, threadDepth: number, + hideActions?: boolean, isPinned: boolean, othersReacts: ?{ like: number, @@ -95,6 +96,7 @@ function Comment(props: Props) { doToast, isTopLevel, threadDepth, + hideActions, isPinned, othersReacts, playingUri, @@ -348,18 +350,20 @@ function Comment(props: Props) { )} -
- {threadDepth !== 0 && ( -
+ {!hideActions && ( +
+ {threadDepth !== 0 && ( +
+ )} {numDirectReplies > 0 && !showReplies && (
diff --git a/ui/component/commentsList/index.js b/ui/component/commentsList/index.js index 8d15ab707..c83dae73b 100644 --- a/ui/component/commentsList/index.js +++ b/ui/component/commentsList/index.js @@ -48,7 +48,7 @@ const perform = (dispatch) => ({ fetchTopLevelComments: (uri, page, pageSize, sortBy) => dispatch(doCommentList(uri, '', page, pageSize, sortBy)), fetchComment: (commentId) => dispatch(doCommentById(commentId)), fetchReacts: (commentIds) => dispatch(doCommentReactList(commentIds)), - resetComments: (uri) => dispatch(doCommentReset(uri)), + resetComments: (claimId) => dispatch(doCommentReset(claimId)), }); export default connect(select, perform)(CommentsList); diff --git a/ui/component/commentsList/view.jsx b/ui/component/commentsList/view.jsx index 6a51fd42c..35525d19a 100644 --- a/ui/component/commentsList/view.jsx +++ b/ui/component/commentsList/view.jsx @@ -151,10 +151,13 @@ function CommentList(props: Props) { // Reset comments useEffect(() => { if (page === 0) { - resetComments(uri); + if (claim) { + resetComments(claim.claim_id); + } setPage(1); } - }, [page, uri, resetComments]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [page, uri, resetComments]); // 'claim' is derived from 'uri' // Fetch top-level comments useEffect(() => { diff --git a/ui/component/router/view.jsx b/ui/component/router/view.jsx index 03db2b538..ad5234265 100644 --- a/ui/component/router/view.jsx +++ b/ui/component/router/view.jsx @@ -59,6 +59,7 @@ const ListBlockedPage = lazyImport(() => import('page/listBlocked' /* webpackChu const ListsPage = lazyImport(() => import('page/lists' /* webpackChunkName: "secondary" */)); const LiveStreamSetupPage = lazyImport(() => import('page/livestreamSetup' /* webpackChunkName: "secondary" */)); const LivestreamCurrentPage = lazyImport(() => import('page/livestreamCurrent' /* webpackChunkName: "secondary" */)); +const OwnComments = lazyImport(() => import('page/ownComments' /* webpackChunkName: "ownComments" */)); const PasswordResetPage = lazyImport(() => import('page/passwordReset' /* webpackChunkName: "secondary" */)); const PasswordSetPage = lazyImport(() => import('page/passwordSet' /* webpackChunkName: "secondary" */)); const PublishPage = lazyImport(() => import('page/publish' /* webpackChunkName: "secondary" */)); @@ -329,6 +330,7 @@ function AppRouter(props: Props) { + diff --git a/ui/component/settingAccount/index.js b/ui/component/settingAccount/index.js index 83d77af76..0644ceaf6 100644 --- a/ui/component/settingAccount/index.js +++ b/ui/component/settingAccount/index.js @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { doWalletStatus, selectWalletIsEncrypted } from 'lbry-redux'; +import { doWalletStatus, selectMyChannelClaims, selectWalletIsEncrypted } from 'lbry-redux'; import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectLanguage } from 'redux/selectors/settings'; @@ -9,6 +9,7 @@ const select = (state) => ({ isAuthenticated: selectUserVerifiedEmail(state), walletEncrypted: selectWalletIsEncrypted(state), user: selectUser(state), + myChannels: selectMyChannelClaims(state), language: selectLanguage(state), }); diff --git a/ui/component/settingAccount/view.jsx b/ui/component/settingAccount/view.jsx index f39262379..812e3818c 100644 --- a/ui/component/settingAccount/view.jsx +++ b/ui/component/settingAccount/view.jsx @@ -15,12 +15,13 @@ type Props = { isAuthenticated: boolean, walletEncrypted: boolean, user: User, + myChannels: ?Array, // --- perform --- doWalletStatus: () => void, }; export default function SettingAccount(props: Props) { - const { isAuthenticated, walletEncrypted, user, doWalletStatus } = props; + const { isAuthenticated, walletEncrypted, user, myChannels, doWalletStatus } = props; const [storedPassword, setStoredPassword] = React.useState(false); // Determine if password is stored. @@ -92,6 +93,17 @@ export default function SettingAccount(props: Props) { )} {/* @endif */} + + {myChannels && ( + +