From aaf36e88dd451e802b933e727bece7512a6a713d Mon Sep 17 00:00:00 2001 From: Rafael Date: Wed, 9 Feb 2022 12:27:11 -0300 Subject: [PATCH] Cleanup Comment and CommentsList and fix new pages - Fixes new pages not fetching at all inside a drawer component - Fixes fetching multiple pages at once some times --- ui/component/comment/index.js | 32 ++++---- ui/component/comment/view.jsx | 50 ++++++------ ui/component/commentsList/index.js | 36 +++++---- ui/component/commentsList/view.jsx | 105 +++++++++++++------------- ui/component/commentsReplies/index.js | 3 +- ui/component/commentsReplies/view.jsx | 16 +--- ui/page/ownComments/view.jsx | 10 +-- 7 files changed, 118 insertions(+), 134 deletions(-) diff --git a/ui/component/comment/index.js b/ui/component/comment/index.js index 9ad2c532c..4b04bac5a 100644 --- a/ui/component/comment/index.js +++ b/ui/component/comment/index.js @@ -4,11 +4,12 @@ import { makeSelectClaimForUri, selectThumbnailForUri, selectHasChannels, + selectMyClaimIdsRaw, } from 'redux/selectors/claims'; import { doCommentUpdate, doCommentList } from 'redux/actions/comments'; import { makeSelectChannelIsMuted } from 'redux/selectors/blocked'; import { doToast } from 'redux/actions/notifications'; -import { doSetPlayingUri } from 'redux/actions/content'; +import { doClearPlayingUri } from 'redux/actions/content'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import { selectLinkedCommentAncestors, @@ -20,31 +21,34 @@ import { selectPlayingUri } from 'redux/selectors/content'; import Comment from './view'; const select = (state, props) => { + const { comment, uri } = props; + const { comment_id, author_uri } = comment || {}; + const activeChannelClaim = selectActiveChannelClaim(state); const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id; - const reactionKey = activeChannelId ? `${props.commentId}:${activeChannelId}` : props.commentId; + const reactionKey = activeChannelId ? `${comment_id}:${activeChannelId}` : comment_id; return { - claim: makeSelectClaimForUri(props.uri)(state), - thumbnail: props.authorUri && selectThumbnailForUri(state, props.authorUri), - channelIsBlocked: props.authorUri && makeSelectChannelIsMuted(props.authorUri)(state), + myChannelIds: selectMyClaimIdsRaw(state), + claim: makeSelectClaimForUri(uri)(state), + thumbnail: author_uri && selectThumbnailForUri(state, author_uri), + channelIsBlocked: author_uri && makeSelectChannelIsMuted(author_uri)(state), commentingEnabled: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true, othersReacts: selectOthersReactsForComment(state, reactionKey), activeChannelClaim, hasChannels: selectHasChannels(state), playingUri: selectPlayingUri(state), - stakedLevel: selectStakedLevelForChannelUri(state, props.authorUri), + stakedLevel: selectStakedLevelForChannelUri(state, author_uri), linkedCommentAncestors: selectLinkedCommentAncestors(state), - totalReplyPages: makeSelectTotalReplyPagesForParentId(props.commentId)(state), + totalReplyPages: makeSelectTotalReplyPagesForParentId(comment_id)(state), }; }; -const perform = (dispatch) => ({ - clearPlayingUri: () => dispatch(doSetPlayingUri({ uri: null })), - updateComment: (commentId, comment) => dispatch(doCommentUpdate(commentId, comment)), - fetchReplies: (uri, parentId, page, pageSize, sortBy) => - dispatch(doCommentList(uri, parentId, page, pageSize, sortBy)), - doToast: (options) => dispatch(doToast(options)), -}); +const perform = { + doClearPlayingUri, + doCommentUpdate, + fetchReplies: doCommentList, + doToast, +}; export default connect(select, perform)(Comment); diff --git a/ui/component/comment/view.jsx b/ui/component/comment/view.jsx index f24e4e561..a046b56a1 100644 --- a/ui/component/comment/view.jsx +++ b/ui/component/comment/view.jsx @@ -34,17 +34,13 @@ import { useIsMobile } from 'effects/use-screensize'; const AUTO_EXPAND_ALL_REPLIES = false; type Props = { + comment: Comment, + myChannelIds: ?Array, clearPlayingUri: () => void, uri: string, claim: StreamClaim, - author: ?string, // LBRY Channel Name, e.g. @channel - authorUri: string, // full LBRY Channel URI: lbry://@channel#123... - commentId: string, // sha256 digest identifying the comment - message: string, // comment body - timePosted: number, // Comment timestamp channelIsBlocked: boolean, // if the channel is blacklisted in the app claimIsMine: boolean, // if you control the claim which this comment was posted on - commentIsMine: boolean, // if this comment was signed by an owned channel updateComment: (string, string) => void, fetchReplies: (string, string, number, number, number) => void, totalReplyPages: number, @@ -57,7 +53,6 @@ type Props = { isTopLevel?: boolean, threadDepth: number, hideActions?: boolean, - isPinned: boolean, othersReacts: ?{ like: number, dislike: number, @@ -66,11 +61,6 @@ type Props = { activeChannelClaim: ?ChannelClaim, playingUri: ?PlayingUri, stakedLevel: number, - supportAmount: number, - numDirectReplies: number, - isModerator: boolean, - isGlobalMod: boolean, - isFiat: boolean, supportDisabled: boolean, setQuickReply: (any) => void, quickReply: any, @@ -78,18 +68,14 @@ type Props = { const LENGTH_TO_COLLAPSE = 300; -function Comment(props: Props) { +function CommentView(props: Props) { const { + comment, + myChannelIds, clearPlayingUri, claim, uri, - author, - authorUri, - timePosted, - message, channelIsBlocked, - commentIsMine, - commentId, updateComment, fetchReplies, totalReplyPages, @@ -101,20 +87,32 @@ function Comment(props: Props) { isTopLevel, threadDepth, hideActions, - isPinned, othersReacts, playingUri, stakedLevel, - supportAmount, - numDirectReplies, - isModerator, - isGlobalMod, - isFiat, supportDisabled, setQuickReply, quickReply, } = props; + const { + channel_url: authorUri, + channel_name: author, + channel_id: channelId, + comment_id: commentId, + comment: message, + is_fiat: isFiat, + is_global_mod: isGlobalMod, + is_moderator: isModerator, + is_pinned: isPinned, + support_amount: supportAmount, + replies: numDirectReplies, + timestamp, + } = comment; + + const timePosted = timestamp * 1000; + const commentIsMine = channelId && myChannelIds && myChannelIds.includes(channelId); + const isMobile = useIsMobile(); const { @@ -454,4 +452,4 @@ function Comment(props: Props) { ); } -export default Comment; +export default CommentView; diff --git a/ui/component/commentsList/index.js b/ui/component/commentsList/index.js index 53712cf93..f8755219d 100644 --- a/ui/component/commentsList/index.js +++ b/ui/component/commentsList/index.js @@ -5,7 +5,6 @@ import { makeSelectClaimForUri, selectClaimIsMine, selectFetchingMyChannels, - selectMyClaimIdsRaw, } from 'redux/selectors/claims'; import { selectTopLevelCommentsForUri, @@ -22,12 +21,17 @@ import { } from 'redux/selectors/comments'; import { doCommentReset, doCommentList, doCommentById, doCommentReactList } from 'redux/actions/comments'; import { selectActiveChannelClaim } from 'redux/selectors/app'; +import { getChannelIdFromClaim } from 'util/claim'; import CommentsList from './view'; const select = (state, props) => { - const claim = selectClaimForUri(state, props.uri); + const { uri } = props; + + const claim = selectClaimForUri(state, uri); + const channelId = getChannelIdFromClaim(claim); + const activeChannelClaim = selectActiveChannelClaim(state); - const topLevelComments = selectTopLevelCommentsForUri(state, props.uri); + const topLevelComments = selectTopLevelCommentsForUri(state, uri); const resolvedComments = topLevelComments && topLevelComments.length > 0 @@ -37,12 +41,12 @@ const select = (state, props) => { return { topLevelComments, resolvedComments, - myChannelIds: selectMyClaimIdsRaw(state), - allCommentIds: selectCommentIdsForUri(state, props.uri), - pinnedComments: selectPinnedCommentsForUri(state, props.uri), - topLevelTotalPages: makeSelectTopLevelTotalPagesForUri(props.uri)(state), - totalComments: makeSelectTotalCommentsCountForUri(props.uri)(state), - claim, + allCommentIds: selectCommentIdsForUri(state, uri), + pinnedComments: selectPinnedCommentsForUri(state, uri), + topLevelTotalPages: makeSelectTopLevelTotalPagesForUri(uri)(state), + totalComments: makeSelectTotalCommentsCountForUri(uri)(state), + claimId: claim && claim.claim_id, + channelId, claimIsMine: selectClaimIsMine(state, claim), isFetchingComments: selectIsFetchingComments(state), isFetchingCommentsById: selectIsFetchingCommentsById(state), @@ -55,12 +59,12 @@ const select = (state, props) => { }; }; -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: (claimId) => dispatch(doCommentReset(claimId)), - doResolveUris: (uris) => dispatch(doResolveUris(uris, true)), -}); +const perform = { + fetchTopLevelComments: doCommentList, + fetchComment: doCommentById, + fetchReacts: doCommentReactList, + resetComments: doCommentReset, + doResolveUris, +}; export default connect(select, perform)(CommentsList); diff --git a/ui/component/commentsList/view.jsx b/ui/component/commentsList/view.jsx index 3d1c9366d..6f9a6eed8 100644 --- a/ui/component/commentsList/view.jsx +++ b/ui/component/commentsList/view.jsx @@ -1,7 +1,6 @@ // @flow import { COMMENT_PAGE_SIZE_TOP_LEVEL, SORT_BY } from 'constants/comment'; import { ENABLE_COMMENT_REACTIONS } from 'config'; -import { getChannelIdFromClaim } from 'util/claim'; import { useIsMobile, useIsMediumScreen } from 'effects/use-screensize'; import { getCommentsListTitle } from 'util/comments'; import * as ICONS from 'constants/icons'; @@ -34,9 +33,9 @@ type Props = { resolvedComments: Array, topLevelTotalPages: number, uri: string, - claim: ?Claim, + claimId?: string, + channelId?: string, claimIsMine: boolean, - myChannelIds: ?Array, isFetchingComments: boolean, isFetchingCommentsById: boolean, isFetchingReacts: boolean, @@ -48,14 +47,14 @@ type Props = { activeChannelId: ?string, settingsByChannelId: { [channelId: string]: PerChannelSettings }, commentsAreExpanded?: boolean, - fetchReacts: (Array) => Promise, - doResolveUris: (Array) => void, - fetchTopLevelComments: (string, number, number, number) => void, - fetchComment: (string) => void, - resetComments: (string) => void, + fetchTopLevelComments: (uri: string, parentId: string, page: number, pageSize: number, sortBy: number) => void, + fetchComment: (commentId: string) => void, + fetchReacts: (commentIds: Array) => Promise, + resetComments: (claimId: string) => void, + doResolveUris: (uris: Array, returnCachedClaims: boolean) => void, }; -function CommentList(props: Props) { +export default function CommentList(props: Props) { const { allCommentIds, uri, @@ -63,9 +62,9 @@ function CommentList(props: Props) { topLevelComments, resolvedComments, topLevelTotalPages, - claim, + claimId, + channelId, claimIsMine, - myChannelIds, isFetchingComments, isFetchingReacts, linkedCommentId, @@ -76,11 +75,11 @@ function CommentList(props: Props) { activeChannelId, settingsByChannelId, commentsAreExpanded, - fetchReacts, - doResolveUris, fetchTopLevelComments, fetchComment, + fetchReacts, resetComments, + doResolveUris, } = props; const isMobile = useIsMobile(); @@ -91,10 +90,11 @@ function CommentList(props: Props) { const [sort, setSort] = usePersistedState('comment-sort-by', DEFAULT_SORT); const [page, setPage] = React.useState(0); const [commentsToDisplay, setCommentsToDisplay] = React.useState(topLevelComments); + const [didInitialPageFetch, setInitialPageFetch] = React.useState(false); const hasDefaultExpansion = commentsAreExpanded || !isMediumScreen || isMobile; const [expandedComments, setExpandedComments] = React.useState(hasDefaultExpansion); + const totalFetchedComments = allCommentIds ? allCommentIds.length : 0; - const channelId = getChannelIdFromClaim(claim); const channelSettings = channelId ? settingsByChannelId[channelId] : undefined; const moreBelow = page < topLevelTotalPages; const isResolvingComments = topLevelComments && resolvedComments.length !== topLevelComments.length; @@ -118,8 +118,8 @@ function CommentList(props: Props) { // Reset comments useEffect(() => { if (page === 0) { - if (claim) { - resetComments(claim.claim_id); + if (claimId) { + resetComments(claimId); } setPage(1); } @@ -133,7 +133,7 @@ function CommentList(props: Props) { fetchComment(linkedCommentId); } - fetchTopLevelComments(uri, page, COMMENT_PAGE_SIZE_TOP_LEVEL, sort); + fetchTopLevelComments(uri, '', page, COMMENT_PAGE_SIZE_TOP_LEVEL, sort); } }, [fetchComment, fetchTopLevelComments, linkedCommentId, page, sort, uri]); @@ -182,7 +182,7 @@ function CommentList(props: Props) { // Infinite scroll useEffect(() => { - function shouldFetchNextPage(page, topLevelTotalPages, window, document, yPrefetchPx = 1000) { + function shouldFetchNextPage(page, topLevelTotalPages, yPrefetchPx = 1000) { if (!spinnerRef || !spinnerRef.current) return false; const rect = spinnerRef.current.getBoundingClientRect(); // $FlowFixMe @@ -205,23 +205,33 @@ function CommentList(props: Props) { } const handleCommentScroll = debounce(() => { - if (shouldFetchNextPage(page, topLevelTotalPages, window, document)) { + if (shouldFetchNextPage(page, topLevelTotalPages)) { setPage(page + 1); + setInitialPageFetch(true); } }, DEBOUNCE_SCROLL_HANDLER_MS); + if (!didInitialPageFetch) { + handleCommentScroll(); + setInitialPageFetch(true); + } + if (hasDefaultExpansion && !isFetchingComments && canDisplayComments && readyToDisplayComments && moreBelow) { - if (shouldFetchNextPage(page, topLevelTotalPages, window, document, 0)) { - setPage(page + 1); - } else { - window.addEventListener('scroll', handleCommentScroll); - return () => window.removeEventListener('scroll', handleCommentScroll); + const commentsInDrawer = Boolean(document.querySelector('.MuiDrawer-root .card--enable-overflow')); + const scrollingElement = commentsInDrawer ? document.querySelector('.card--enable-overflow') : window; + + if (scrollingElement) { + scrollingElement.addEventListener('scroll', handleCommentScroll); + + return () => scrollingElement.removeEventListener('scroll', handleCommentScroll); } } }, [ canDisplayComments, hasDefaultExpansion, + didInitialPageFetch, isFetchingComments, + isMobile, moreBelow, page, readyToDisplayComments, @@ -241,34 +251,10 @@ function CommentList(props: Props) { const urisToResolve = []; topLevelComments.map(({ channel_url }) => channel_url !== undefined && urisToResolve.push(channel_url)); - if (urisToResolve.length > 0) doResolveUris(urisToResolve); + if (urisToResolve.length > 0) doResolveUris(urisToResolve, true); }, [alreadyResolved, doResolveUris, topLevelComments]); - const getCommentElems = (comments) => - comments.map((comment) => ( - - )); - + const commentProps = { isTopLevel: true, threadDepth: 3, uri, claimIsMine, linkedCommentId }; const actionButtonsProps = { totalComments, sort, changeSort, setPage }; return ( @@ -292,8 +278,13 @@ function CommentList(props: Props) { 'comments--contracted': isMediumScreen && !expandedComments, })} > - {readyToDisplayComments && pinnedComments && getCommentElems(pinnedComments)} - {readyToDisplayComments && commentsToDisplay && getCommentElems(commentsToDisplay)} + {readyToDisplayComments && ( + <> + {pinnedComments && } + + {commentsToDisplay && } + + )} {!hasDefaultExpansion && ( @@ -328,7 +319,15 @@ function CommentList(props: Props) { ); } -export default CommentList; +type CommentProps = { + comments: Array, +}; + +const CommentElements = (commentProps: CommentProps) => { + const { comments, ...commentsProps } = commentProps; + + return comments.map((comment) => ); +}; type ActionButtonsProps = { totalComments: number, diff --git a/ui/component/commentsReplies/index.js b/ui/component/commentsReplies/index.js index 66e627e94..b287420dd 100644 --- a/ui/component/commentsReplies/index.js +++ b/ui/component/commentsReplies/index.js @@ -1,6 +1,6 @@ import { connect } from 'react-redux'; import { doResolveUris } from 'redux/actions/claims'; -import { selectClaimIsMineForUri, selectMyChannelClaimIds, makeSelectClaimForUri } from 'redux/selectors/claims'; +import { selectClaimIsMineForUri, makeSelectClaimForUri } from 'redux/selectors/claims'; import { selectIsFetchingCommentsByParentId, selectRepliesForParentId } from 'redux/selectors/comments'; import { selectUserVerifiedEmail } from 'redux/selectors/user'; import CommentsReplies from './view'; @@ -17,7 +17,6 @@ const select = (state, props) => { resolvedReplies, claimIsMine: selectClaimIsMineForUri(state, props.uri), userCanComment: IS_WEB ? Boolean(selectUserVerifiedEmail(state)) : true, - myChannelIds: selectMyChannelClaimIds(state), isFetchingByParentId: selectIsFetchingCommentsByParentId(state), }; }; diff --git a/ui/component/commentsReplies/view.jsx b/ui/component/commentsReplies/view.jsx index 1906a1a18..d1e0e0923 100644 --- a/ui/component/commentsReplies/view.jsx +++ b/ui/component/commentsReplies/view.jsx @@ -11,7 +11,6 @@ type Props = { uri: string, parentId: string, claimIsMine: boolean, - myChannelIds: ?Array, linkedCommentId?: string, userCanComment: boolean, threadDepth: number, @@ -30,7 +29,6 @@ function CommentsReplies(props: Props) { fetchedReplies, resolvedReplies, claimIsMine, - myChannelIds, linkedCommentId, userCanComment, threadDepth, @@ -85,23 +83,13 @@ function CommentsReplies(props: Props) { commentsToDisplay.length > 0 && commentsToDisplay.map((comment) => ( ))} diff --git a/ui/page/ownComments/view.jsx b/ui/page/ownComments/view.jsx index 5159221b1..7b7b20beb 100644 --- a/ui/page/ownComments/view.jsx +++ b/ui/page/ownComments/view.jsx @@ -83,17 +83,9 @@ export default function OwnComments(props: Props) {