parent
4c72a563da
commit
8b3820fb28
17 changed files with 39 additions and 472 deletions
4
flow-typed/Comment.js
vendored
4
flow-typed/Comment.js
vendored
|
@ -111,14 +111,14 @@ declare type ReactionListResponse = {
|
||||||
declare type CommentListParams = {
|
declare type CommentListParams = {
|
||||||
page: number, // pagination: which page of results
|
page: number, // pagination: which page of results
|
||||||
page_size: number, // pagination: nr of comments to show in a page (max 200)
|
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_name?: string, // signing channel name of claim (enables 'commentsEnabled' check)
|
||||||
channel_id?: string, // signing channel claim id 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
|
author_claim_id?: string, // filters comments to just this author
|
||||||
parent_id?: string, // filters comments to those under this thread
|
parent_id?: string, // filters comments to those under this thread
|
||||||
top_level?: boolean, // filters to only top level comments
|
top_level?: boolean, // filters to only top level comments
|
||||||
hidden?: boolean, // if true, will show hidden comments as well
|
hidden?: boolean, // if true, will show hidden comments as well
|
||||||
sort_by?: number, // @see: ui/constants/comments.js::SORT_BY
|
sort_by?: number, // NEWEST=0, OLDEST=1, CONTROVERSY=2, POPULARITY=3,
|
||||||
};
|
};
|
||||||
|
|
||||||
declare type CommentListResponse = {
|
declare type CommentListResponse = {
|
||||||
|
|
|
@ -209,9 +209,6 @@
|
||||||
"Failed to copy.": "Failed to copy.",
|
"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%.",
|
"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...",
|
"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",
|
"Comments": "Comments",
|
||||||
"Comment": "Comment",
|
"Comment": "Comment",
|
||||||
"Comment --[button to submit something]--": "Comment",
|
"Comment --[button to submit something]--": "Comment",
|
||||||
|
@ -1463,7 +1460,6 @@
|
||||||
"Staked LBRY Credits": "Staked LBRY Credits",
|
"Staked LBRY Credits": "Staked LBRY Credits",
|
||||||
"1 comment": "1 comment",
|
"1 comment": "1 comment",
|
||||||
"%total_comments% comments": "%total_comments% comments",
|
"%total_comments% comments": "%total_comments% comments",
|
||||||
"No comments": "No comments",
|
|
||||||
"Upvote": "Upvote",
|
"Upvote": "Upvote",
|
||||||
"Downvote": "Downvote",
|
"Downvote": "Downvote",
|
||||||
"You loved this": "You loved this",
|
"You loved this": "You loved this",
|
||||||
|
|
|
@ -70,7 +70,6 @@ type Props = {
|
||||||
streamingUrl: ?string,
|
streamingUrl: ?string,
|
||||||
getFile: (string) => void,
|
getFile: (string) => void,
|
||||||
customShouldHide?: (Claim) => boolean,
|
customShouldHide?: (Claim) => boolean,
|
||||||
searchParams?: { [string]: string },
|
|
||||||
showUnresolvedClaim?: boolean,
|
showUnresolvedClaim?: boolean,
|
||||||
showNullPlaceholder?: boolean,
|
showNullPlaceholder?: boolean,
|
||||||
includeSupportAction?: boolean,
|
includeSupportAction?: boolean,
|
||||||
|
@ -126,7 +125,6 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
// modifiers
|
// modifiers
|
||||||
active,
|
active,
|
||||||
customShouldHide,
|
customShouldHide,
|
||||||
searchParams,
|
|
||||||
showNullPlaceholder,
|
showNullPlaceholder,
|
||||||
// value from show mature content user setting
|
// value from show mature content user setting
|
||||||
// true if the user doesn't wanna see nsfw content
|
// true if the user doesn't wanna see nsfw content
|
||||||
|
@ -223,11 +221,6 @@ const ClaimPreview = forwardRef<any, {}>((props: Props, ref: any) => {
|
||||||
if (listId) {
|
if (listId) {
|
||||||
navigateSearch.set(COLLECTIONS_CONSTS.COLLECTION_ID, listId);
|
navigateSearch.set(COLLECTIONS_CONSTS.COLLECTION_ID, listId);
|
||||||
}
|
}
|
||||||
if (searchParams) {
|
|
||||||
Object.keys(searchParams).forEach((key) => {
|
|
||||||
navigateSearch.set(key, searchParams[key]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleNavLinkClick = (e) => {
|
const handleNavLinkClick = (e) => {
|
||||||
if (onClick) {
|
if (onClick) {
|
||||||
|
|
|
@ -52,7 +52,6 @@ type Props = {
|
||||||
doToast: ({ message: string }) => void,
|
doToast: ({ message: string }) => void,
|
||||||
isTopLevel?: boolean,
|
isTopLevel?: boolean,
|
||||||
threadDepth: number,
|
threadDepth: number,
|
||||||
hideActions?: boolean,
|
|
||||||
isPinned: boolean,
|
isPinned: boolean,
|
||||||
othersReacts: ?{
|
othersReacts: ?{
|
||||||
like: number,
|
like: number,
|
||||||
|
@ -96,7 +95,6 @@ function Comment(props: Props) {
|
||||||
doToast,
|
doToast,
|
||||||
isTopLevel,
|
isTopLevel,
|
||||||
threadDepth,
|
threadDepth,
|
||||||
hideActions,
|
|
||||||
isPinned,
|
isPinned,
|
||||||
othersReacts,
|
othersReacts,
|
||||||
playingUri,
|
playingUri,
|
||||||
|
@ -350,20 +348,18 @@ function Comment(props: Props) {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{!hideActions && (
|
<div className="comment__actions">
|
||||||
<div className="comment__actions">
|
{threadDepth !== 0 && (
|
||||||
{threadDepth !== 0 && (
|
<Button
|
||||||
<Button
|
requiresAuth={IS_WEB}
|
||||||
requiresAuth={IS_WEB}
|
label={commentingEnabled ? __('Reply') : __('Log in to reply')}
|
||||||
label={commentingEnabled ? __('Reply') : __('Log in to reply')}
|
className="comment__action"
|
||||||
className="comment__action"
|
onClick={handleCommentReply}
|
||||||
onClick={handleCommentReply}
|
icon={ICONS.REPLY}
|
||||||
icon={ICONS.REPLY}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
{ENABLE_COMMENT_REACTIONS && <CommentReactions uri={uri} commentId={commentId} />}
|
||||||
{ENABLE_COMMENT_REACTIONS && <CommentReactions uri={uri} commentId={commentId} />}
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{numDirectReplies > 0 && !showReplies && (
|
{numDirectReplies > 0 && !showReplies && (
|
||||||
<div className="comment__actions">
|
<div className="comment__actions">
|
||||||
|
|
|
@ -48,7 +48,7 @@ const perform = (dispatch) => ({
|
||||||
fetchTopLevelComments: (uri, page, pageSize, sortBy) => dispatch(doCommentList(uri, '', page, pageSize, sortBy)),
|
fetchTopLevelComments: (uri, page, pageSize, sortBy) => dispatch(doCommentList(uri, '', page, pageSize, sortBy)),
|
||||||
fetchComment: (commentId) => dispatch(doCommentById(commentId)),
|
fetchComment: (commentId) => dispatch(doCommentById(commentId)),
|
||||||
fetchReacts: (commentIds) => dispatch(doCommentReactList(commentIds)),
|
fetchReacts: (commentIds) => dispatch(doCommentReactList(commentIds)),
|
||||||
resetComments: (claimId) => dispatch(doCommentReset(claimId)),
|
resetComments: (uri) => dispatch(doCommentReset(uri)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(select, perform)(CommentsList);
|
export default connect(select, perform)(CommentsList);
|
||||||
|
|
|
@ -151,13 +151,10 @@ function CommentList(props: Props) {
|
||||||
// Reset comments
|
// Reset comments
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (page === 0) {
|
if (page === 0) {
|
||||||
if (claim) {
|
resetComments(uri);
|
||||||
resetComments(claim.claim_id);
|
|
||||||
}
|
|
||||||
setPage(1);
|
setPage(1);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
}, [page, uri, resetComments]);
|
||||||
}, [page, uri, resetComments]); // 'claim' is derived from 'uri'
|
|
||||||
|
|
||||||
// Fetch top-level comments
|
// Fetch top-level comments
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
@ -59,7 +59,6 @@ const ListBlockedPage = lazyImport(() => import('page/listBlocked' /* webpackChu
|
||||||
const ListsPage = lazyImport(() => import('page/lists' /* webpackChunkName: "secondary" */));
|
const ListsPage = lazyImport(() => import('page/lists' /* webpackChunkName: "secondary" */));
|
||||||
const LiveStreamSetupPage = lazyImport(() => import('page/livestreamSetup' /* webpackChunkName: "secondary" */));
|
const LiveStreamSetupPage = lazyImport(() => import('page/livestreamSetup' /* webpackChunkName: "secondary" */));
|
||||||
const LivestreamCurrentPage = lazyImport(() => import('page/livestreamCurrent' /* 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 PasswordResetPage = lazyImport(() => import('page/passwordReset' /* webpackChunkName: "secondary" */));
|
||||||
const PasswordSetPage = lazyImport(() => import('page/passwordSet' /* webpackChunkName: "secondary" */));
|
const PasswordSetPage = lazyImport(() => import('page/passwordSet' /* webpackChunkName: "secondary" */));
|
||||||
const PublishPage = lazyImport(() => import('page/publish' /* webpackChunkName: "secondary" */));
|
const PublishPage = lazyImport(() => import('page/publish' /* webpackChunkName: "secondary" */));
|
||||||
|
@ -330,7 +329,6 @@ function AppRouter(props: Props) {
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.SWAP}`} component={SwapPage} />
|
<PrivateRoute {...props} path={`/$/${PAGES.SWAP}`} component={SwapPage} />
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.NOTIFICATIONS}`} component={NotificationsPage} />
|
<PrivateRoute {...props} path={`/$/${PAGES.NOTIFICATIONS}`} component={NotificationsPage} />
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.AUTH_WALLET_PASSWORD}`} component={SignInWalletPasswordPage} />
|
<PrivateRoute {...props} path={`/$/${PAGES.AUTH_WALLET_PASSWORD}`} component={SignInWalletPasswordPage} />
|
||||||
<PrivateRoute {...props} path={`/$/${PAGES.SETTINGS_OWN_COMMENTS}`} component={OwnComments} />
|
|
||||||
|
|
||||||
<Route path={`/$/${PAGES.EMBED}/:claimName`} exact component={EmbedWrapperPage} />
|
<Route path={`/$/${PAGES.EMBED}/:claimName`} exact component={EmbedWrapperPage} />
|
||||||
<Route path={`/$/${PAGES.EMBED}/:claimName/:claimId`} exact component={EmbedWrapperPage} />
|
<Route path={`/$/${PAGES.EMBED}/:claimName/:claimId`} exact component={EmbedWrapperPage} />
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { doWalletStatus, selectMyChannelClaims, selectWalletIsEncrypted } from 'lbry-redux';
|
import { doWalletStatus, selectWalletIsEncrypted } from 'lbry-redux';
|
||||||
import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user';
|
import { selectUser, selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||||
import { selectLanguage } from 'redux/selectors/settings';
|
import { selectLanguage } from 'redux/selectors/settings';
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ const select = (state) => ({
|
||||||
isAuthenticated: selectUserVerifiedEmail(state),
|
isAuthenticated: selectUserVerifiedEmail(state),
|
||||||
walletEncrypted: selectWalletIsEncrypted(state),
|
walletEncrypted: selectWalletIsEncrypted(state),
|
||||||
user: selectUser(state),
|
user: selectUser(state),
|
||||||
myChannels: selectMyChannelClaims(state),
|
|
||||||
language: selectLanguage(state),
|
language: selectLanguage(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,12 @@ type Props = {
|
||||||
isAuthenticated: boolean,
|
isAuthenticated: boolean,
|
||||||
walletEncrypted: boolean,
|
walletEncrypted: boolean,
|
||||||
user: User,
|
user: User,
|
||||||
myChannels: ?Array<ChannelClaim>,
|
|
||||||
// --- perform ---
|
// --- perform ---
|
||||||
doWalletStatus: () => void,
|
doWalletStatus: () => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function SettingAccount(props: Props) {
|
export default function SettingAccount(props: Props) {
|
||||||
const { isAuthenticated, walletEncrypted, user, myChannels, doWalletStatus } = props;
|
const { isAuthenticated, walletEncrypted, user, doWalletStatus } = props;
|
||||||
const [storedPassword, setStoredPassword] = React.useState(false);
|
const [storedPassword, setStoredPassword] = React.useState(false);
|
||||||
|
|
||||||
// Determine if password is stored.
|
// Determine if password is stored.
|
||||||
|
@ -93,17 +92,6 @@ export default function SettingAccount(props: Props) {
|
||||||
</SettingsRow>
|
</SettingsRow>
|
||||||
)}
|
)}
|
||||||
{/* @endif */}
|
{/* @endif */}
|
||||||
|
|
||||||
{myChannels && (
|
|
||||||
<SettingsRow title={__('Comments')} subtitle={__('View your past comments.')}>
|
|
||||||
<Button
|
|
||||||
button="inverse"
|
|
||||||
label={__('Manage')}
|
|
||||||
icon={ICONS.ARROW_RIGHT}
|
|
||||||
navigate={`/$/${PAGES.SETTINGS_OWN_COMMENTS}`}
|
|
||||||
/>
|
|
||||||
</SettingsRow>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -9,7 +9,6 @@ export const SORT_BY = {
|
||||||
OLDEST: 1,
|
OLDEST: 1,
|
||||||
CONTROVERSY: 2,
|
CONTROVERSY: 2,
|
||||||
POPULARITY: 3,
|
POPULARITY: 3,
|
||||||
NEWEST_NO_PINS: 4,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BLOCK_LEVEL = {
|
export const BLOCK_LEVEL = {
|
||||||
|
|
|
@ -52,7 +52,6 @@ export const PAGE_TITLE = {
|
||||||
[PAGES.SETTINGS_STRIPE_ACCOUNT]: 'Bank Accounts',
|
[PAGES.SETTINGS_STRIPE_ACCOUNT]: 'Bank Accounts',
|
||||||
[PAGES.SETTINGS_STRIPE_CARD]: 'Payment Methods',
|
[PAGES.SETTINGS_STRIPE_CARD]: 'Payment Methods',
|
||||||
[PAGES.SETTINGS_UPDATE_PWD]: 'Update password',
|
[PAGES.SETTINGS_UPDATE_PWD]: 'Update password',
|
||||||
[PAGES.SETTINGS_OWN_COMMENTS]: 'Your comments',
|
|
||||||
[PAGES.SWAP]: 'Swap Credits',
|
[PAGES.SWAP]: 'Swap Credits',
|
||||||
[PAGES.TAGS_FOLLOWING]: 'Tags',
|
[PAGES.TAGS_FOLLOWING]: 'Tags',
|
||||||
[PAGES.TAGS_FOLLOWING_MANAGE]: 'Manage tags',
|
[PAGES.TAGS_FOLLOWING_MANAGE]: 'Manage tags',
|
||||||
|
|
|
@ -46,7 +46,6 @@ exports.SETTINGS_NOTIFICATIONS = 'settings/notifications';
|
||||||
exports.SETTINGS_BLOCKED_MUTED = 'settings/block_and_mute';
|
exports.SETTINGS_BLOCKED_MUTED = 'settings/block_and_mute';
|
||||||
exports.SETTINGS_CREATOR = 'settings/creator';
|
exports.SETTINGS_CREATOR = 'settings/creator';
|
||||||
exports.SETTINGS_UPDATE_PWD = 'settings/update_password';
|
exports.SETTINGS_UPDATE_PWD = 'settings/update_password';
|
||||||
exports.SETTINGS_OWN_COMMENTS = 'settings/ownComments';
|
|
||||||
exports.SHOW = 'show';
|
exports.SHOW = 'show';
|
||||||
exports.ACCOUNT = 'account';
|
exports.ACCOUNT = 'account';
|
||||||
exports.SEARCH = 'search';
|
exports.SEARCH = 'search';
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { doCommentListOwn, doCommentReset } from 'redux/actions/comments';
|
|
||||||
import { selectActiveChannelClaim } from 'redux/selectors/app';
|
|
||||||
import {
|
|
||||||
selectIsFetchingComments,
|
|
||||||
makeSelectCommentsForUri,
|
|
||||||
makeSelectTotalCommentsCountForUri,
|
|
||||||
makeSelectTopLevelTotalPagesForUri,
|
|
||||||
} from 'redux/selectors/comments';
|
|
||||||
import { selectClaimsById } from 'lbry-redux';
|
|
||||||
|
|
||||||
import OwnComments from './view';
|
|
||||||
|
|
||||||
const select = (state) => {
|
|
||||||
const activeChannelClaim = selectActiveChannelClaim(state);
|
|
||||||
const uri = activeChannelClaim && activeChannelClaim.canonical_url;
|
|
||||||
|
|
||||||
return {
|
|
||||||
activeChannelClaim,
|
|
||||||
allComments: makeSelectCommentsForUri(uri)(state),
|
|
||||||
totalComments: makeSelectTotalCommentsCountForUri(uri)(state),
|
|
||||||
topLevelTotalPages: makeSelectTopLevelTotalPagesForUri(uri)(state),
|
|
||||||
isFetchingComments: selectIsFetchingComments(state),
|
|
||||||
claimsById: selectClaimsById(state),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
|
||||||
doCommentReset: (a) => dispatch(doCommentReset(a)),
|
|
||||||
doCommentListOwn: (a, b, c) => dispatch(doCommentListOwn(a, b, c)),
|
|
||||||
});
|
|
||||||
|
|
||||||
export default connect(select, perform)(OwnComments);
|
|
|
@ -1,210 +0,0 @@
|
||||||
// @flow
|
|
||||||
import React from 'react';
|
|
||||||
import Button from 'component/button';
|
|
||||||
import ChannelSelector from 'component/channelSelector';
|
|
||||||
import ClaimPreview from 'component/claimPreview';
|
|
||||||
import Comment from 'component/comment';
|
|
||||||
import Card from 'component/common/card';
|
|
||||||
import Empty from 'component/common/empty';
|
|
||||||
import Page from 'component/page';
|
|
||||||
import Spinner from 'component/spinner';
|
|
||||||
import { COMMENT_PAGE_SIZE_TOP_LEVEL } from 'constants/comment';
|
|
||||||
import * as ICONS from 'constants/icons';
|
|
||||||
import useFetched from 'effects/use-fetched';
|
|
||||||
import debounce from 'util/debounce';
|
|
||||||
|
|
||||||
function scaleToDevicePixelRatio(value) {
|
|
||||||
const devicePixelRatio = window.devicePixelRatio || 1.0;
|
|
||||||
if (devicePixelRatio < 1.0) {
|
|
||||||
return Math.ceil(value / devicePixelRatio);
|
|
||||||
}
|
|
||||||
return Math.ceil(value * devicePixelRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
activeChannelClaim: ?ChannelClaim,
|
|
||||||
allComments: Array<Comment>,
|
|
||||||
totalComments: number,
|
|
||||||
topLevelTotalPages: number,
|
|
||||||
isFetchingComments: boolean,
|
|
||||||
claimsById: any,
|
|
||||||
doCommentReset: (claimId: string) => void,
|
|
||||||
doCommentListOwn: (channelId: string, page: number, pageSize: number) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function OwnComments(props: Props) {
|
|
||||||
const {
|
|
||||||
activeChannelClaim,
|
|
||||||
allComments,
|
|
||||||
totalComments,
|
|
||||||
isFetchingComments,
|
|
||||||
claimsById,
|
|
||||||
doCommentReset,
|
|
||||||
doCommentListOwn,
|
|
||||||
} = props;
|
|
||||||
const spinnerRef = React.useRef();
|
|
||||||
const [page, setPage] = React.useState(0);
|
|
||||||
const [activeChannelId, setActiveChannelId] = React.useState('');
|
|
||||||
|
|
||||||
// Since we are sharing the key for Discussion and MyComments, don't show
|
|
||||||
// the list until we've gone through the initial reset.
|
|
||||||
const wasResetAndReady = useFetched(isFetchingComments);
|
|
||||||
|
|
||||||
const totalPages = Math.ceil(totalComments / COMMENT_PAGE_SIZE_TOP_LEVEL);
|
|
||||||
const moreBelow = page < totalPages;
|
|
||||||
|
|
||||||
function getCommentsElem(comments) {
|
|
||||||
return comments.map((comment) => {
|
|
||||||
const contentClaim = claimsById[comment.claim_id];
|
|
||||||
const isChannel = contentClaim && contentClaim.value_type === 'channel';
|
|
||||||
const isLivestream = Boolean(contentClaim && contentClaim.value_type === 'stream' && !contentClaim.value.source);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div key={comment.comment_id} className="comments-own card__main-actions">
|
|
||||||
<div className="section__actions">
|
|
||||||
<div className="comments-own--claim">
|
|
||||||
{contentClaim && (
|
|
||||||
<ClaimPreview
|
|
||||||
uri={contentClaim.canonical_url}
|
|
||||||
searchParams={{
|
|
||||||
...(isChannel ? { view: 'discussion' } : {}),
|
|
||||||
...(isLivestream ? {} : { lc: comment.comment_id }),
|
|
||||||
}}
|
|
||||||
hideActions
|
|
||||||
hideMenu
|
|
||||||
properties={() => null}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!contentClaim && <Empty text={__('Content or channel was deleted.')} />}
|
|
||||||
</div>
|
|
||||||
<Comment
|
|
||||||
isTopLevel
|
|
||||||
hideActions
|
|
||||||
authorUri={comment.channel_url}
|
|
||||||
author={comment.channel_name}
|
|
||||||
commentId={comment.comment_id}
|
|
||||||
message={comment.comment}
|
|
||||||
timePosted={comment.timestamp * 1000}
|
|
||||||
commentIsMine
|
|
||||||
supportAmount={comment.support_amount}
|
|
||||||
numDirectReplies={0} // Don't show replies here
|
|
||||||
isModerator={comment.is_moderator}
|
|
||||||
isGlobalMod={comment.is_global_mod}
|
|
||||||
isFiat={comment.is_fiat}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Active channel changed
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (activeChannelClaim && activeChannelClaim.claim_id !== activeChannelId) {
|
|
||||||
setActiveChannelId(activeChannelClaim.claim_id);
|
|
||||||
setPage(0);
|
|
||||||
}
|
|
||||||
}, [activeChannelClaim, activeChannelId]);
|
|
||||||
|
|
||||||
// Reset comments
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (page === 0 && activeChannelId) {
|
|
||||||
doCommentReset(activeChannelId);
|
|
||||||
setPage(1);
|
|
||||||
}
|
|
||||||
}, [page, activeChannelId]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
||||||
|
|
||||||
// Fetch own comments
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (page !== 0 && activeChannelId) {
|
|
||||||
doCommentListOwn(activeChannelId, page, COMMENT_PAGE_SIZE_TOP_LEVEL);
|
|
||||||
}
|
|
||||||
}, [page]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
||||||
|
|
||||||
// Infinite scroll
|
|
||||||
React.useEffect(() => {
|
|
||||||
function shouldFetchNextPage(page, topLevelTotalPages, window, document, yPrefetchPx = 1000) {
|
|
||||||
if (!spinnerRef || !spinnerRef.current) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rect = spinnerRef.current.getBoundingClientRect(); // $FlowFixMe
|
|
||||||
const windowH = window.innerHeight || document.documentElement.clientHeight; // $FlowFixMe
|
|
||||||
const windowW = window.innerWidth || document.documentElement.clientWidth; // $FlowFixMe
|
|
||||||
|
|
||||||
const isApproachingViewport = yPrefetchPx !== 0 && rect.top < windowH + scaleToDevicePixelRatio(yPrefetchPx);
|
|
||||||
|
|
||||||
const isInViewport =
|
|
||||||
rect.width > 0 &&
|
|
||||||
rect.height > 0 &&
|
|
||||||
rect.bottom >= 0 &&
|
|
||||||
rect.right >= 0 &&
|
|
||||||
// $FlowFixMe
|
|
||||||
rect.top <= windowH &&
|
|
||||||
// $FlowFixMe
|
|
||||||
rect.left <= windowW;
|
|
||||||
|
|
||||||
return (isInViewport || isApproachingViewport) && page < topLevelTotalPages;
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCommentScroll = debounce(() => {
|
|
||||||
if (shouldFetchNextPage(page, totalPages, window, document)) {
|
|
||||||
setPage(page + 1);
|
|
||||||
}
|
|
||||||
}, 200);
|
|
||||||
|
|
||||||
if (!isFetchingComments && moreBelow && spinnerRef && spinnerRef.current) {
|
|
||||||
if (shouldFetchNextPage(page, totalPages, window, document, 0)) {
|
|
||||||
setPage(page + 1);
|
|
||||||
} else {
|
|
||||||
window.addEventListener('scroll', handleCommentScroll);
|
|
||||||
return () => window.removeEventListener('scroll', handleCommentScroll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [page, spinnerRef, isFetchingComments, moreBelow, totalPages]);
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
if (!activeChannelClaim) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Page noFooter noSideNavigation settingsPage backout={{ title: __('Your comments'), backLabel: __('Back') }}>
|
|
||||||
<ChannelSelector hideAnon />
|
|
||||||
<Card
|
|
||||||
isBodyList
|
|
||||||
title={
|
|
||||||
totalComments > 0
|
|
||||||
? totalComments === 1
|
|
||||||
? __('1 comment')
|
|
||||||
: __('%total_comments% comments', { total_comments: totalComments })
|
|
||||||
: isFetchingComments
|
|
||||||
? ''
|
|
||||||
: __('No comments')
|
|
||||||
}
|
|
||||||
titleActions={
|
|
||||||
<Button
|
|
||||||
button="alt"
|
|
||||||
icon={ICONS.REFRESH}
|
|
||||||
title={__('Refresh')}
|
|
||||||
onClick={() => {
|
|
||||||
setPage(0);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
body={
|
|
||||||
<>
|
|
||||||
{wasResetAndReady && <ul className="comments">{allComments && getCommentsElem(allComments)}</ul>}
|
|
||||||
{(isFetchingComments || moreBelow) && (
|
|
||||||
<div className="main--empty" ref={spinnerRef}>
|
|
||||||
<Spinner type="small" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Page>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -3,15 +3,7 @@ import * as ACTIONS from 'constants/action_types';
|
||||||
import * as REACTION_TYPES from 'constants/reactions';
|
import * as REACTION_TYPES from 'constants/reactions';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
import { SORT_BY, BLOCK_LEVEL } from 'constants/comment';
|
import { SORT_BY, BLOCK_LEVEL } from 'constants/comment';
|
||||||
import {
|
import { Lbry, parseURI, buildURI, selectClaimsByUri, selectMyChannelClaims, isURIEqual } from 'lbry-redux';
|
||||||
Lbry,
|
|
||||||
parseURI,
|
|
||||||
buildURI,
|
|
||||||
selectClaimsByUri,
|
|
||||||
selectMyChannelClaims,
|
|
||||||
isURIEqual,
|
|
||||||
doClaimSearch,
|
|
||||||
} from 'lbry-redux';
|
|
||||||
import { doToast, doSeeNotifications } from 'redux/actions/notifications';
|
import { doToast, doSeeNotifications } from 'redux/actions/notifications';
|
||||||
import {
|
import {
|
||||||
makeSelectMyReactionsForComment,
|
makeSelectMyReactionsForComment,
|
||||||
|
@ -135,6 +127,7 @@ export function doCommentList(
|
||||||
type: ACTIONS.COMMENT_LIST_FAILED,
|
type: ACTIONS.COMMENT_LIST_FAILED,
|
||||||
data: 'unable to find claim for uri',
|
data: 'unable to find claim for uri',
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,7 +139,7 @@ export function doCommentList(
|
||||||
});
|
});
|
||||||
|
|
||||||
// Adding 'channel_id' and 'channel_name' enables "CreatorSettings > commentsEnabled".
|
// Adding 'channel_id' and 'channel_name' enables "CreatorSettings > commentsEnabled".
|
||||||
const creatorChannelClaim = claim.value_type === 'channel' ? claim : claim.signing_channel;
|
const authorChannelClaim = claim.value_type === 'channel' ? claim : claim.signing_channel;
|
||||||
|
|
||||||
return Comments.comment_list({
|
return Comments.comment_list({
|
||||||
page,
|
page,
|
||||||
|
@ -154,8 +147,8 @@ export function doCommentList(
|
||||||
page_size: pageSize,
|
page_size: pageSize,
|
||||||
parent_id: parentId || undefined,
|
parent_id: parentId || undefined,
|
||||||
top_level: !parentId,
|
top_level: !parentId,
|
||||||
channel_id: creatorChannelClaim ? creatorChannelClaim.claim_id : undefined,
|
channel_id: authorChannelClaim ? authorChannelClaim.claim_id : undefined,
|
||||||
channel_name: creatorChannelClaim ? creatorChannelClaim.name : undefined,
|
channel_name: authorChannelClaim ? authorChannelClaim.name : undefined,
|
||||||
sort_by: sortBy,
|
sort_by: sortBy,
|
||||||
})
|
})
|
||||||
.then((result: CommentListResponse) => {
|
.then((result: CommentListResponse) => {
|
||||||
|
@ -169,7 +162,7 @@ export function doCommentList(
|
||||||
totalFilteredItems: total_filtered_items,
|
totalFilteredItems: total_filtered_items,
|
||||||
totalPages: total_pages,
|
totalPages: total_pages,
|
||||||
claimId: claimId,
|
claimId: claimId,
|
||||||
creatorClaimId: creatorChannelClaim ? creatorChannelClaim.claim_id : undefined,
|
commenterClaimId: authorChannelClaim ? authorChannelClaim.claim_id : undefined,
|
||||||
uri: uri,
|
uri: uri,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -182,7 +175,7 @@ export function doCommentList(
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ACTIONS.COMMENT_LIST_COMPLETED,
|
type: ACTIONS.COMMENT_LIST_COMPLETED,
|
||||||
data: {
|
data: {
|
||||||
creatorClaimId: creatorChannelClaim ? creatorChannelClaim.claim_id : undefined,
|
authorClaimId: authorChannelClaim ? authorChannelClaim.claim_id : undefined,
|
||||||
disabled: true,
|
disabled: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -208,103 +201,6 @@ export function doCommentList(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doCommentListOwn(
|
|
||||||
channelId: string,
|
|
||||||
page: number = 1,
|
|
||||||
pageSize: number = 99999,
|
|
||||||
sortBy: number = SORT_BY.NEWEST_NO_PINS
|
|
||||||
) {
|
|
||||||
return async (dispatch: Dispatch, getState: GetState) => {
|
|
||||||
const state = getState();
|
|
||||||
const myChannelClaims = selectMyChannelClaims(state);
|
|
||||||
if (!myChannelClaims) {
|
|
||||||
console.error('Failed to fetch channel list.'); // eslint-disable-line
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const channelClaim = myChannelClaims.find((x) => x.claim_id === channelId);
|
|
||||||
if (!channelClaim) {
|
|
||||||
console.error('You do not own this channel.'); // eslint-disable-line
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const channelSignature = await channelSignName(channelClaim.claim_id, channelClaim.name);
|
|
||||||
if (!channelSignature) {
|
|
||||||
console.error('Failed to sign channel name.'); // eslint-disable-line
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.COMMENT_LIST_STARTED,
|
|
||||||
data: {},
|
|
||||||
});
|
|
||||||
|
|
||||||
return Comments.comment_list({
|
|
||||||
page,
|
|
||||||
page_size: pageSize,
|
|
||||||
sort_by: sortBy,
|
|
||||||
author_claim_id: channelId,
|
|
||||||
requestor_channel_name: channelClaim.name,
|
|
||||||
requestor_channel_id: channelClaim.claim_id,
|
|
||||||
signature: channelSignature.signature,
|
|
||||||
signing_ts: channelSignature.signing_ts,
|
|
||||||
})
|
|
||||||
.then((result: CommentListResponse) => {
|
|
||||||
const { items: comments, total_items, total_filtered_items, total_pages } = result;
|
|
||||||
|
|
||||||
if (!comments) {
|
|
||||||
dispatch({ type: ACTIONS.COMMENT_LIST_FAILED, data: 'No more comments.' });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatch(
|
|
||||||
doClaimSearch({
|
|
||||||
page: 1,
|
|
||||||
page_size: 20,
|
|
||||||
no_totals: true,
|
|
||||||
claim_ids: comments.map((c) => c.claim_id),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.then((result) => {
|
|
||||||
dispatch({
|
|
||||||
type: ACTIONS.COMMENT_LIST_COMPLETED,
|
|
||||||
data: {
|
|
||||||
comments,
|
|
||||||
totalItems: total_items,
|
|
||||||
totalFilteredItems: total_filtered_items,
|
|
||||||
totalPages: total_pages,
|
|
||||||
uri: channelClaim.canonical_url, // hijack "Discussion Page"
|
|
||||||
claimId: channelClaim.claim_id, // hijack "Discussion Page"
|
|
||||||
},
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
dispatch({ type: ACTIONS.COMMENT_LIST_FAILED, data: err });
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
switch (error.message) {
|
|
||||||
case FETCH_API_FAILED_TO_FETCH:
|
|
||||||
dispatch(
|
|
||||||
doToast({
|
|
||||||
isError: true,
|
|
||||||
message: Comments.isCustomServer
|
|
||||||
? __('Failed to fetch comments. Verify custom server settings.')
|
|
||||||
: __('Failed to fetch comments.'),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
dispatch(doToast({ isError: true, message: `${error.message}` }));
|
|
||||||
dispatch({ type: ACTIONS.COMMENT_LIST_FAILED, data: error });
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
dispatch(doToast({ isError: true, message: `${error.message}` }));
|
|
||||||
dispatch({ type: ACTIONS.COMMENT_LIST_FAILED, data: error });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function doCommentById(commentId: string, toastIfNotFound: boolean = true) {
|
export function doCommentById(commentId: string, toastIfNotFound: boolean = true) {
|
||||||
return (dispatch: Dispatch, getState: GetState) => {
|
return (dispatch: Dispatch, getState: GetState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -343,10 +239,17 @@ export function doCommentById(commentId: string, toastIfNotFound: boolean = true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function doCommentReset(claimId: string) {
|
export function doCommentReset(uri: string) {
|
||||||
return (dispatch: Dispatch) => {
|
return (dispatch: Dispatch, getState: GetState) => {
|
||||||
|
const state = getState();
|
||||||
|
const claim = selectClaimsByUri(state)[uri];
|
||||||
|
const claimId = claim ? claim.claim_id : null;
|
||||||
|
|
||||||
if (!claimId) {
|
if (!claimId) {
|
||||||
console.error(`Failed to reset comments`); //eslint-disable-line
|
dispatch({
|
||||||
|
type: ACTIONS.COMMENT_LIST_FAILED,
|
||||||
|
data: 'unable to find claim for uri',
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -246,7 +246,7 @@ export default handleActions(
|
||||||
claimId,
|
claimId,
|
||||||
uri,
|
uri,
|
||||||
disabled,
|
disabled,
|
||||||
creatorClaimId,
|
commenterClaimId,
|
||||||
} = action.data;
|
} = action.data;
|
||||||
|
|
||||||
const commentById = Object.assign({}, state.commentById);
|
const commentById = Object.assign({}, state.commentById);
|
||||||
|
@ -262,8 +262,8 @@ export default handleActions(
|
||||||
const isLoadingByParentId = Object.assign({}, state.isLoadingByParentId);
|
const isLoadingByParentId = Object.assign({}, state.isLoadingByParentId);
|
||||||
const settingsByChannelId = Object.assign({}, state.settingsByChannelId);
|
const settingsByChannelId = Object.assign({}, state.settingsByChannelId);
|
||||||
|
|
||||||
settingsByChannelId[creatorClaimId] = {
|
settingsByChannelId[commenterClaimId] = {
|
||||||
...(settingsByChannelId[creatorClaimId] || {}),
|
...(settingsByChannelId[commenterClaimId] || {}),
|
||||||
comments_enabled: !disabled,
|
comments_enabled: !disabled,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -487,60 +487,3 @@ $thumbnailWidthSmall: 1rem;
|
||||||
margin-bottom: -3px; // TODO fix few instances of these (find "-2px")
|
margin-bottom: -3px; // TODO fix few instances of these (find "-2px")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.comments-own {
|
|
||||||
.section__actions {
|
|
||||||
align-items: flex-start;
|
|
||||||
}
|
|
||||||
|
|
||||||
.comments-own--claim {
|
|
||||||
min-width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-medium) {
|
|
||||||
min-width: 40%;
|
|
||||||
max-width: 40%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media__thumb {
|
|
||||||
flex-shrink: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
$width: 5rem;
|
|
||||||
@include handleClaimListGifThumbnail($width);
|
|
||||||
width: $width;
|
|
||||||
height: calc(#{$width} * (9 / 16));
|
|
||||||
margin-right: var(--spacing-s);
|
|
||||||
}
|
|
||||||
|
|
||||||
.channel-thumbnail {
|
|
||||||
@include handleChannelGif(calc(5rem * 9 / 16));
|
|
||||||
margin-right: var(--spacing-xs);
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-small) {
|
|
||||||
@include handleChannelGif(calc(5rem * 9 / 16));
|
|
||||||
margin-right: var(--spacing-s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.claim-preview__wrapper {
|
|
||||||
margin: 0 0;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-medium) {
|
|
||||||
margin: 0 var(--spacing-xs);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.comment {
|
|
||||||
margin-top: var(--spacing-s);
|
|
||||||
margin-left: 0;
|
|
||||||
padding-left: var(--spacing-m);
|
|
||||||
border-left: 4px solid var(--color-border);
|
|
||||||
|
|
||||||
@media (min-width: $breakpoint-medium) {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-left: var(--spacing-s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue