2019-06-27 01:59:27 +02:00
|
|
|
// @flow
|
2020-07-24 16:13:42 +02:00
|
|
|
import * as ICONS from 'constants/icons';
|
2020-09-11 19:51:31 +02:00
|
|
|
import * as PAGES from 'constants/pages';
|
2021-08-31 09:05:42 +02:00
|
|
|
import * as KEYCODES from 'constants/keycodes';
|
2021-09-01 09:55:00 +02:00
|
|
|
import { COMMENT_HIGHLIGHTED } from 'constants/classnames';
|
2021-07-15 16:43:28 +02:00
|
|
|
import { SORT_BY, COMMENT_PAGE_SIZE_REPLIES } from 'constants/comment';
|
2020-07-24 16:13:42 +02:00
|
|
|
import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
|
2021-10-19 01:37:58 +02:00
|
|
|
import { SITE_NAME, ENABLE_COMMENT_REACTIONS } from 'config';
|
2020-01-30 02:02:21 +01:00
|
|
|
import React, { useEffect, useState } from 'react';
|
2021-10-08 05:47:39 +02:00
|
|
|
import { parseURI } from 'util/lbryURI';
|
2020-05-11 09:57:03 +02:00
|
|
|
import DateTime from 'component/dateTime';
|
2019-07-21 22:46:30 +02:00
|
|
|
import Button from 'component/button';
|
2020-09-11 19:51:31 +02:00
|
|
|
import Expandable from 'component/expandable';
|
2019-10-13 06:04:16 +02:00
|
|
|
import MarkdownPreview from 'component/common/markdown-preview';
|
2022-02-09 16:27:11 +01:00
|
|
|
import CommentBadge from 'component/common/comment-badge'; // have this?
|
2019-10-23 09:04:40 +02:00
|
|
|
import ChannelThumbnail from 'component/channelThumbnail';
|
2021-02-11 06:12:41 +01:00
|
|
|
import { Menu, MenuButton } from '@reach/menu-button';
|
2020-01-30 02:02:21 +01:00
|
|
|
import Icon from 'component/common/icon';
|
|
|
|
import { FormField, Form } from 'component/common/form';
|
2020-02-05 04:55:00 +01:00
|
|
|
import classnames from 'classnames';
|
2020-05-21 10:53:21 +02:00
|
|
|
import usePersistedState from 'effects/use-persisted-state';
|
2020-09-11 19:51:31 +02:00
|
|
|
import CommentReactions from 'component/commentReactions';
|
|
|
|
import CommentsReplies from 'component/commentsReplies';
|
|
|
|
import { useHistory } from 'react-router';
|
2020-10-07 21:14:52 +02:00
|
|
|
import CommentCreate from 'component/commentCreate';
|
2021-02-11 06:12:41 +01:00
|
|
|
import CommentMenuList from 'component/commentMenuList';
|
2021-02-16 22:09:20 +01:00
|
|
|
import UriIndicator from 'component/uriIndicator';
|
2021-04-23 21:59:48 +02:00
|
|
|
import CreditAmount from 'component/common/credit-amount';
|
2022-01-24 17:07:09 +01:00
|
|
|
import OptimizedImage from 'component/optimizedImage';
|
2022-02-09 16:27:11 +01:00
|
|
|
import { getChannelFromClaim } from 'util/claim';
|
2022-01-24 17:07:09 +01:00
|
|
|
import { parseSticker } from 'util/comments';
|
2022-02-09 16:27:11 +01:00
|
|
|
import { useIsMobile } from 'effects/use-screensize';
|
2019-06-27 01:59:27 +02:00
|
|
|
|
2021-07-15 16:43:28 +02:00
|
|
|
const AUTO_EXPAND_ALL_REPLIES = false;
|
|
|
|
|
2019-06-27 01:59:27 +02:00
|
|
|
type Props = {
|
2022-02-09 16:27:11 +01:00
|
|
|
comment: Comment,
|
|
|
|
myChannelIds: ?Array<string>,
|
2021-03-02 11:12:54 +01:00
|
|
|
clearPlayingUri: () => void,
|
2020-02-05 04:55:00 +01:00
|
|
|
uri: string,
|
2021-04-02 21:14:53 +02:00
|
|
|
claim: StreamClaim,
|
2020-01-30 02:02:21 +01:00
|
|
|
channelIsBlocked: boolean, // if the channel is blacklisted in the app
|
|
|
|
claimIsMine: boolean, // if you control the claim which this comment was posted on
|
2022-02-09 16:27:11 +01:00
|
|
|
doCommentUpdate: (string, string) => void,
|
2021-07-15 16:43:28 +02:00
|
|
|
fetchReplies: (string, string, number, number, number) => void,
|
2021-08-04 17:01:31 +02:00
|
|
|
totalReplyPages: number,
|
2021-02-16 22:09:20 +01:00
|
|
|
commentModBlock: (string) => void,
|
2021-07-15 16:43:28 +02:00
|
|
|
linkedCommentId?: string,
|
|
|
|
linkedCommentAncestors: { [string]: Array<string> },
|
2022-01-21 18:38:11 +01:00
|
|
|
hasChannels: boolean,
|
2020-09-11 19:51:31 +02:00
|
|
|
commentingEnabled: boolean,
|
|
|
|
doToast: ({ message: string }) => void,
|
|
|
|
isTopLevel?: boolean,
|
2020-10-07 21:14:52 +02:00
|
|
|
threadDepth: number,
|
2021-10-01 14:10:27 +02:00
|
|
|
hideActions?: boolean,
|
2020-10-08 21:55:16 +02:00
|
|
|
othersReacts: ?{
|
|
|
|
like: number,
|
|
|
|
dislike: number,
|
|
|
|
},
|
2020-10-20 05:20:38 +02:00
|
|
|
commentIdentityChannel: any,
|
2021-02-09 17:05:56 +01:00
|
|
|
activeChannelClaim: ?ChannelClaim,
|
2021-03-02 11:12:54 +01:00
|
|
|
playingUri: ?PlayingUri,
|
2021-03-09 10:33:42 +01:00
|
|
|
stakedLevel: number,
|
2021-08-27 12:29:58 +02:00
|
|
|
supportDisabled: boolean,
|
|
|
|
setQuickReply: (any) => void,
|
|
|
|
quickReply: any,
|
2019-06-27 01:59:27 +02:00
|
|
|
};
|
|
|
|
|
2019-11-27 22:08:43 +01:00
|
|
|
const LENGTH_TO_COLLAPSE = 300;
|
|
|
|
|
2022-02-09 16:27:11 +01:00
|
|
|
function CommentView(props: Props) {
|
2019-10-23 09:04:40 +02:00
|
|
|
const {
|
2022-02-09 16:27:11 +01:00
|
|
|
comment,
|
|
|
|
myChannelIds,
|
2021-03-02 11:12:54 +01:00
|
|
|
clearPlayingUri,
|
2021-04-02 21:14:53 +02:00
|
|
|
claim,
|
2020-02-05 04:55:00 +01:00
|
|
|
uri,
|
2019-10-23 09:04:40 +02:00
|
|
|
channelIsBlocked,
|
2022-02-09 16:27:11 +01:00
|
|
|
doCommentUpdate,
|
2021-07-15 16:43:28 +02:00
|
|
|
fetchReplies,
|
2021-08-04 17:01:31 +02:00
|
|
|
totalReplyPages,
|
2021-07-15 16:43:28 +02:00
|
|
|
linkedCommentId,
|
|
|
|
linkedCommentAncestors,
|
2020-09-11 19:51:31 +02:00
|
|
|
commentingEnabled,
|
2022-01-21 18:38:11 +01:00
|
|
|
hasChannels,
|
2020-09-11 19:51:31 +02:00
|
|
|
doToast,
|
|
|
|
isTopLevel,
|
2020-10-07 21:14:52 +02:00
|
|
|
threadDepth,
|
2021-10-01 14:10:27 +02:00
|
|
|
hideActions,
|
2020-10-08 21:55:16 +02:00
|
|
|
othersReacts,
|
2021-03-02 11:12:54 +01:00
|
|
|
playingUri,
|
2021-03-09 10:33:42 +01:00
|
|
|
stakedLevel,
|
2021-08-27 12:29:58 +02:00
|
|
|
supportDisabled,
|
|
|
|
setQuickReply,
|
|
|
|
quickReply,
|
2019-10-23 09:04:40 +02:00
|
|
|
} = props;
|
2021-07-15 16:43:28 +02:00
|
|
|
|
2022-02-09 16:27:11 +01:00
|
|
|
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();
|
|
|
|
|
2020-09-11 19:51:31 +02:00
|
|
|
const {
|
|
|
|
push,
|
2020-10-08 17:31:36 +02:00
|
|
|
replace,
|
|
|
|
location: { pathname, search },
|
2020-09-11 19:51:31 +02:00
|
|
|
} = useHistory();
|
2021-07-15 16:43:28 +02:00
|
|
|
|
2022-02-09 16:27:11 +01:00
|
|
|
const isLinkedComment = linkedCommentId && linkedCommentId === commentId;
|
|
|
|
const isInLinkedCommentChain =
|
|
|
|
linkedCommentId &&
|
|
|
|
linkedCommentAncestors[linkedCommentId] &&
|
|
|
|
linkedCommentAncestors[linkedCommentId].includes(commentId);
|
|
|
|
const showRepliesOnMount = isInLinkedCommentChain || AUTO_EXPAND_ALL_REPLIES;
|
|
|
|
|
2020-09-11 19:51:31 +02:00
|
|
|
const [isReplying, setReplying] = React.useState(false);
|
2020-01-30 02:02:21 +01:00
|
|
|
const [isEditing, setEditing] = useState(false);
|
|
|
|
const [editedMessage, setCommentValue] = useState(message);
|
|
|
|
const [charCount, setCharCount] = useState(editedMessage.length);
|
2022-02-09 16:27:11 +01:00
|
|
|
const [showReplies, setShowReplies] = useState(showRepliesOnMount); // on mount
|
|
|
|
const [page, setPage] = useState(showRepliesOnMount ? 1 : 0);
|
2020-08-24 19:35:21 +02:00
|
|
|
const [advancedEditor] = usePersistedState('comment-editor-mode', false);
|
2020-10-08 21:55:16 +02:00
|
|
|
const [displayDeadComment, setDisplayDeadComment] = React.useState(false);
|
|
|
|
const likesCount = (othersReacts && othersReacts.like) || 0;
|
|
|
|
const dislikesCount = (othersReacts && othersReacts.dislike) || 0;
|
|
|
|
const totalLikesAndDislikes = likesCount + dislikesCount;
|
2020-10-26 19:06:33 +01:00
|
|
|
const slimedToDeath = totalLikesAndDislikes >= 5 && dislikesCount / totalLikesAndDislikes > 0.8;
|
2022-02-09 16:27:11 +01:00
|
|
|
const contentChannelClaim = getChannelFromClaim(claim);
|
|
|
|
const commentByOwnerOfContent = contentChannelClaim && contentChannelClaim.permanent_url === authorUri;
|
2022-01-24 17:07:09 +01:00
|
|
|
const stickerFromMessage = parseSticker(message);
|
2021-02-09 17:05:56 +01:00
|
|
|
|
2020-10-08 17:31:36 +02:00
|
|
|
let channelOwnerOfContent;
|
|
|
|
try {
|
|
|
|
const { channelName } = parseURI(uri);
|
|
|
|
if (channelName) {
|
|
|
|
channelOwnerOfContent = channelName;
|
|
|
|
}
|
|
|
|
} catch (e) {}
|
2019-12-04 19:07:40 +01:00
|
|
|
|
2019-10-23 09:04:40 +02:00
|
|
|
useEffect(() => {
|
2020-01-30 02:02:21 +01:00
|
|
|
if (isEditing) {
|
|
|
|
setCharCount(editedMessage.length);
|
|
|
|
|
|
|
|
// a user will try and press the escape key to cancel editing their comment
|
2021-02-16 22:09:20 +01:00
|
|
|
const handleEscape = (event) => {
|
2021-08-31 09:05:42 +02:00
|
|
|
if (event.keyCode === KEYCODES.ESCAPE) {
|
2020-01-30 02:02:21 +01:00
|
|
|
setEditing(false);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
window.addEventListener('keydown', handleEscape);
|
|
|
|
|
|
|
|
// removes the listener so it doesn't cause problems elsewhere in the app
|
|
|
|
return () => {
|
|
|
|
window.removeEventListener('keydown', handleEscape);
|
|
|
|
};
|
|
|
|
}
|
2021-02-09 17:05:56 +01:00
|
|
|
}, [author, authorUri, editedMessage, isEditing, setEditing]);
|
2020-01-30 02:02:21 +01:00
|
|
|
|
2021-07-15 16:43:28 +02:00
|
|
|
useEffect(() => {
|
|
|
|
if (page > 0) {
|
|
|
|
fetchReplies(uri, commentId, page, COMMENT_PAGE_SIZE_REPLIES, SORT_BY.OLDEST);
|
|
|
|
}
|
|
|
|
}, [page, uri, commentId, fetchReplies]);
|
|
|
|
|
2020-01-30 02:02:21 +01:00
|
|
|
function handleEditMessageChanged(event) {
|
2021-10-19 01:37:58 +02:00
|
|
|
setCommentValue(advancedEditor ? event : event.target.value);
|
2020-01-30 02:02:21 +01:00
|
|
|
}
|
|
|
|
|
2021-01-26 20:50:44 +01:00
|
|
|
function handleEditComment() {
|
2021-03-02 11:12:54 +01:00
|
|
|
if (playingUri && playingUri.source === 'comment') {
|
|
|
|
clearPlayingUri();
|
|
|
|
}
|
2021-01-26 20:50:44 +01:00
|
|
|
setEditing(true);
|
|
|
|
}
|
|
|
|
|
2020-01-30 02:02:21 +01:00
|
|
|
function handleSubmit() {
|
2022-02-09 16:27:11 +01:00
|
|
|
doCommentUpdate(commentId, editedMessage);
|
2021-08-27 12:29:58 +02:00
|
|
|
if (setQuickReply) setQuickReply({ ...quickReply, comment_id: commentId, comment: editedMessage });
|
2020-01-30 02:02:21 +01:00
|
|
|
setEditing(false);
|
|
|
|
}
|
|
|
|
|
2020-09-11 19:51:31 +02:00
|
|
|
function handleCommentReply() {
|
|
|
|
if (!hasChannels) {
|
|
|
|
push(`/$/${PAGES.CHANNEL_NEW}?redirect=${pathname}`);
|
|
|
|
doToast({ message: __('A channel is required to comment on %SITE_NAME%', { SITE_NAME }) });
|
|
|
|
} else {
|
2020-10-07 21:14:52 +02:00
|
|
|
setReplying(!isReplying);
|
2020-09-11 19:51:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-08 17:31:36 +02:00
|
|
|
function handleTimeClick() {
|
|
|
|
const urlParams = new URLSearchParams(search);
|
|
|
|
urlParams.delete('lc');
|
|
|
|
urlParams.append('lc', commentId);
|
|
|
|
replace(`${pathname}?${urlParams.toString()}`);
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:27:11 +01:00
|
|
|
// find a way to enable linked comments - probably use share url.
|
|
|
|
// const linkedCommentRef = React.useCallback(
|
|
|
|
// (node) => {
|
|
|
|
// if (node !== null && window.pendingLinkedCommentScroll) {
|
|
|
|
// const ROUGH_HEADER_HEIGHT = 125; // @see: --header-height
|
|
|
|
// delete window.pendingLinkedCommentScroll;
|
|
|
|
//
|
|
|
|
// const mobileChatElem = document.querySelector('.MuiPaper-root .card--enable-overflow');
|
|
|
|
// const drawerElem = document.querySelector('.MuiDrawer-root');
|
|
|
|
// const elem = (isMobile && mobileChatElem) || window;
|
|
|
|
//
|
|
|
|
// if (elem) {
|
|
|
|
// // $FlowFixMe
|
|
|
|
// elem.scrollTo({
|
|
|
|
// top:
|
|
|
|
// node.getBoundingClientRect().top +
|
|
|
|
// // $FlowFixMe
|
|
|
|
// (mobileChatElem && drawerElem ? drawerElem.getBoundingClientRect().top * -1 : elem.scrollY) -
|
|
|
|
// ROUGH_HEADER_HEIGHT,
|
|
|
|
// left: 0,
|
|
|
|
// behavior: 'smooth',
|
|
|
|
// });
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// },
|
|
|
|
// [isMobile]
|
|
|
|
// );
|
|
|
|
|
2019-06-27 01:59:27 +02:00
|
|
|
return (
|
2020-02-05 04:55:00 +01:00
|
|
|
<li
|
2020-08-24 19:35:21 +02:00
|
|
|
className={classnames('comment', {
|
2020-10-07 21:14:52 +02:00
|
|
|
'comment--top-level': isTopLevel,
|
2020-09-11 19:51:31 +02:00
|
|
|
'comment--reply': !isTopLevel,
|
2021-04-23 21:59:48 +02:00
|
|
|
'comment--superchat': supportAmount > 0,
|
2020-08-24 19:35:21 +02:00
|
|
|
})}
|
|
|
|
id={commentId}
|
2020-02-05 04:55:00 +01:00
|
|
|
>
|
2020-10-08 17:31:36 +02:00
|
|
|
<div
|
|
|
|
className={classnames('comment__content', {
|
2022-02-09 16:27:11 +01:00
|
|
|
[COMMENT_HIGHLIGHTED]: isLinkedComment,
|
2020-10-08 21:55:16 +02:00
|
|
|
'comment--slimed': slimedToDeath && !displayDeadComment,
|
2020-10-08 17:31:36 +02:00
|
|
|
})}
|
|
|
|
>
|
2021-04-23 21:59:48 +02:00
|
|
|
<div className="comment__thumbnail-wrapper">
|
|
|
|
{authorUri ? (
|
ChannelThumbnail improvements
- [x] (6332) The IntersectionObserver method of lazy-loading loads cached images visibly late on slower devices. Previously, it was also showing the "broken image" icon briefly, which we mended by placing a dummy transparent image as the initial src.
- Reverted that ugly transparent image fix.
- Use the browser's built-in `loading="lazy"` instead. Sorry, Safari.
- [x] Size-optimization did not take "device pixel ratio" into account.
- When resizing an image through the CDN, we can't just take the dimensions of the tag in pixels directly -- we need to take zooming into account, otherwise the image ends up blurry.
- Previously, we quickly disabled optimization for the channel avatar in the Channel Page because of this. Now that we know the root-cause, the change was reverted and we now go through the CDN with appropriate sizes. This also improves our Web Vital scores.
- [x] Size-optimization wasn't really implemented for all ChannelThumbnail instances.
- The CDN-optimized size was hardcoded to the largest instance, so small images like sidebar thumbnails are still loading images that are unnecessarily larger.
- There's a little-bit of hardcoding of values from CSS here, but I think it's a ok compromise (not something we change often). It also doesn't need to be exact -- the "device pixel ratio" calculate will ensure it's slightly larger than what we need.
- [x] Set `width` and `height` of `<img>` to improve CLS.
- Addresses Ligthhouse complaints, although technically the shifting was addressed at the `ClaimPreviewTile` level (sub-container dimensions are well defined).
- Notes: the values don't need to be the final CSS-adjusted sizes. It just needs to be in the right aspect ratio to help the browser pre-allocate space to avoid shifts.
- [x] Add option to disable lazy-load Channel Thumbnails
- The guidelines mentioned that items that are already in the viewport should not enable `loading="lazy"`.
- We have a few areas where it doesn't make sense to lazy-load (e.g. thumbnail in Header, channel selector dropdown, publish preview, etc.).
2021-07-05 07:20:40 +02:00
|
|
|
<ChannelThumbnail uri={authorUri} obscure={channelIsBlocked} xsmall className="comment__author-thumbnail" />
|
2021-04-23 21:59:48 +02:00
|
|
|
) : (
|
ChannelThumbnail improvements
- [x] (6332) The IntersectionObserver method of lazy-loading loads cached images visibly late on slower devices. Previously, it was also showing the "broken image" icon briefly, which we mended by placing a dummy transparent image as the initial src.
- Reverted that ugly transparent image fix.
- Use the browser's built-in `loading="lazy"` instead. Sorry, Safari.
- [x] Size-optimization did not take "device pixel ratio" into account.
- When resizing an image through the CDN, we can't just take the dimensions of the tag in pixels directly -- we need to take zooming into account, otherwise the image ends up blurry.
- Previously, we quickly disabled optimization for the channel avatar in the Channel Page because of this. Now that we know the root-cause, the change was reverted and we now go through the CDN with appropriate sizes. This also improves our Web Vital scores.
- [x] Size-optimization wasn't really implemented for all ChannelThumbnail instances.
- The CDN-optimized size was hardcoded to the largest instance, so small images like sidebar thumbnails are still loading images that are unnecessarily larger.
- There's a little-bit of hardcoding of values from CSS here, but I think it's a ok compromise (not something we change often). It also doesn't need to be exact -- the "device pixel ratio" calculate will ensure it's slightly larger than what we need.
- [x] Set `width` and `height` of `<img>` to improve CLS.
- Addresses Ligthhouse complaints, although technically the shifting was addressed at the `ClaimPreviewTile` level (sub-container dimensions are well defined).
- Notes: the values don't need to be the final CSS-adjusted sizes. It just needs to be in the right aspect ratio to help the browser pre-allocate space to avoid shifts.
- [x] Add option to disable lazy-load Channel Thumbnails
- The guidelines mentioned that items that are already in the viewport should not enable `loading="lazy"`.
- We have a few areas where it doesn't make sense to lazy-load (e.g. thumbnail in Header, channel selector dropdown, publish preview, etc.).
2021-07-05 07:20:40 +02:00
|
|
|
<ChannelThumbnail xsmall className="comment__author-thumbnail" />
|
2021-04-23 21:59:48 +02:00
|
|
|
)}
|
|
|
|
</div>
|
2019-10-24 19:24:53 +02:00
|
|
|
|
2021-04-23 21:59:48 +02:00
|
|
|
<div className="comment__body-container">
|
2020-09-11 19:51:31 +02:00
|
|
|
<div className="comment__meta">
|
|
|
|
<div className="comment__meta-information">
|
2022-02-09 16:27:11 +01:00
|
|
|
{isGlobalMod && <CommentBadge label={__('Admin')} icon={ICONS.BADGE_MOD} />}
|
|
|
|
{isModerator && <CommentBadge label={__('Moderator')} icon={ICONS.BADGE_MOD} />}
|
2021-07-23 12:26:16 +02:00
|
|
|
|
2020-09-11 19:51:31 +02:00
|
|
|
{!author ? (
|
|
|
|
<span className="comment__author">{__('Anonymous')}</span>
|
|
|
|
) : (
|
2021-04-02 21:14:53 +02:00
|
|
|
<UriIndicator
|
|
|
|
className={classnames('comment__author', {
|
|
|
|
'comment__author--creator': commentByOwnerOfContent,
|
|
|
|
})}
|
|
|
|
link
|
|
|
|
uri={authorUri}
|
|
|
|
/>
|
2021-03-24 03:53:33 +01:00
|
|
|
)}
|
2021-04-23 21:59:48 +02:00
|
|
|
<Button
|
|
|
|
className="comment__time"
|
|
|
|
onClick={handleTimeClick}
|
|
|
|
label={<DateTime date={timePosted} timeAgo />}
|
|
|
|
/>
|
|
|
|
|
2021-07-06 22:28:29 +02:00
|
|
|
{supportAmount > 0 && <CreditAmount isFiat={isFiat} amount={supportAmount} superChatLight size={12} />}
|
2020-10-08 17:31:36 +02:00
|
|
|
|
|
|
|
{isPinned && (
|
|
|
|
<span className="comment__pin">
|
2020-10-20 05:20:38 +02:00
|
|
|
<Icon icon={ICONS.PIN} size={14} />
|
2020-10-08 17:31:36 +02:00
|
|
|
{channelOwnerOfContent
|
|
|
|
? __('Pinned by @%channel%', { channel: channelOwnerOfContent })
|
|
|
|
: __('Pinned by creator')}
|
|
|
|
</span>
|
|
|
|
)}
|
2020-09-11 19:51:31 +02:00
|
|
|
</div>
|
|
|
|
<div className="comment__menu">
|
|
|
|
<Menu>
|
2021-03-03 19:50:16 +01:00
|
|
|
<MenuButton className="menu__button">
|
2021-09-01 07:58:48 +02:00
|
|
|
<Icon size={18} icon={ICONS.MORE_VERTICAL} />
|
2020-09-11 19:51:31 +02:00
|
|
|
</MenuButton>
|
2021-02-11 06:12:41 +01:00
|
|
|
<CommentMenuList
|
|
|
|
uri={uri}
|
|
|
|
isTopLevel={isTopLevel}
|
|
|
|
isPinned={isPinned}
|
|
|
|
commentId={commentId}
|
|
|
|
authorUri={authorUri}
|
|
|
|
commentIsMine={commentIsMine}
|
|
|
|
handleEditComment={handleEditComment}
|
2021-07-19 23:22:39 +02:00
|
|
|
supportAmount={supportAmount}
|
2021-08-27 12:29:58 +02:00
|
|
|
setQuickReply={setQuickReply}
|
2021-02-11 06:12:41 +01:00
|
|
|
/>
|
2020-09-11 19:51:31 +02:00
|
|
|
</Menu>
|
|
|
|
</div>
|
2020-01-30 02:02:21 +01:00
|
|
|
</div>
|
2020-09-11 19:51:31 +02:00
|
|
|
<div>
|
|
|
|
{isEditing ? (
|
|
|
|
<Form onSubmit={handleSubmit}>
|
|
|
|
<FormField
|
2021-04-23 21:59:48 +02:00
|
|
|
className="comment__edit-input"
|
2021-10-19 01:37:58 +02:00
|
|
|
type={advancedEditor ? 'markdown' : 'textarea'}
|
2020-09-11 19:51:31 +02:00
|
|
|
name="editing_comment"
|
|
|
|
value={editedMessage}
|
|
|
|
charCount={charCount}
|
|
|
|
onChange={handleEditMessageChanged}
|
|
|
|
textAreaMaxLength={FF_MAX_CHARS_IN_COMMENT}
|
2022-02-09 16:27:11 +01:00
|
|
|
handleSubmit={handleSubmit}
|
2020-01-30 02:02:21 +01:00
|
|
|
/>
|
2021-04-23 21:59:48 +02:00
|
|
|
<div className="section__actions section__actions--no-margin">
|
2022-01-07 20:02:33 +01:00
|
|
|
<Button button="primary" type="submit" label={__('Done')} disabled={message === editedMessage} />
|
2020-09-11 19:51:31 +02:00
|
|
|
<Button button="link" label={__('Cancel')} onClick={() => setEditing(false)} />
|
|
|
|
</div>
|
|
|
|
</Form>
|
|
|
|
) : (
|
|
|
|
<>
|
|
|
|
<div className="comment__message">
|
2020-10-08 21:55:16 +02:00
|
|
|
{slimedToDeath && !displayDeadComment ? (
|
|
|
|
<div onClick={() => setDisplayDeadComment(true)} className="comment__dead">
|
2020-10-09 17:38:50 +02:00
|
|
|
{__('This comment was slimed to death.')} <Icon icon={ICONS.SLIME_ACTIVE} />
|
2020-10-08 21:55:16 +02:00
|
|
|
</div>
|
2022-01-24 17:07:09 +01:00
|
|
|
) : stickerFromMessage ? (
|
|
|
|
<div className="sticker__comment">
|
|
|
|
<OptimizedImage src={stickerFromMessage.url} waitLoad loading="lazy" />
|
|
|
|
</div>
|
2020-10-08 21:55:16 +02:00
|
|
|
) : editedMessage.length >= LENGTH_TO_COLLAPSE ? (
|
2020-09-11 19:51:31 +02:00
|
|
|
<Expandable>
|
2021-03-09 10:33:42 +01:00
|
|
|
<MarkdownPreview
|
|
|
|
content={message}
|
|
|
|
promptLinks
|
|
|
|
parentCommentId={commentId}
|
|
|
|
stakedLevel={stakedLevel}
|
|
|
|
/>
|
2020-09-11 19:51:31 +02:00
|
|
|
</Expandable>
|
|
|
|
) : (
|
2021-03-09 10:33:42 +01:00
|
|
|
<MarkdownPreview
|
|
|
|
content={message}
|
|
|
|
promptLinks
|
|
|
|
parentCommentId={commentId}
|
|
|
|
stakedLevel={stakedLevel}
|
|
|
|
/>
|
2020-09-11 19:51:31 +02:00
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
|
2021-10-01 14:10:27 +02:00
|
|
|
{!hideActions && (
|
|
|
|
<div className="comment__actions">
|
|
|
|
{threadDepth !== 0 && (
|
|
|
|
<Button
|
|
|
|
label={commentingEnabled ? __('Reply') : __('Log in to reply')}
|
|
|
|
className="comment__action"
|
|
|
|
onClick={handleCommentReply}
|
|
|
|
icon={ICONS.REPLY}
|
2022-02-09 16:27:11 +01:00
|
|
|
iconSize={isMobile && 12}
|
2021-10-01 14:10:27 +02:00
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{ENABLE_COMMENT_REACTIONS && <CommentReactions uri={uri} commentId={commentId} />}
|
|
|
|
</div>
|
|
|
|
)}
|
2020-10-07 21:14:52 +02:00
|
|
|
|
2021-07-15 16:43:28 +02:00
|
|
|
{numDirectReplies > 0 && !showReplies && (
|
|
|
|
<div className="comment__actions">
|
|
|
|
<Button
|
|
|
|
label={
|
|
|
|
numDirectReplies < 2
|
|
|
|
? __('Show reply')
|
|
|
|
: __('Show %count% replies', { count: numDirectReplies })
|
|
|
|
}
|
|
|
|
button="link"
|
|
|
|
onClick={() => {
|
|
|
|
setShowReplies(true);
|
|
|
|
if (page === 0) {
|
|
|
|
setPage(1);
|
|
|
|
}
|
|
|
|
}}
|
2021-08-23 09:19:23 +02:00
|
|
|
icon={ICONS.DOWN}
|
2021-07-15 16:43:28 +02:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
|
|
|
{numDirectReplies > 0 && showReplies && (
|
|
|
|
<div className="comment__actions">
|
2021-08-23 09:19:23 +02:00
|
|
|
<Button
|
|
|
|
label={__('Hide replies')}
|
|
|
|
button="link"
|
|
|
|
onClick={() => setShowReplies(false)}
|
|
|
|
icon={ICONS.UP}
|
|
|
|
/>
|
2021-07-15 16:43:28 +02:00
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
2020-10-07 21:14:52 +02:00
|
|
|
{isReplying && (
|
|
|
|
<CommentCreate
|
|
|
|
isReply
|
|
|
|
uri={uri}
|
|
|
|
parentId={commentId}
|
2021-07-15 16:43:28 +02:00
|
|
|
onDoneReplying={() => {
|
|
|
|
setShowReplies(true);
|
|
|
|
setReplying(false);
|
|
|
|
}}
|
|
|
|
onCancelReplying={() => {
|
|
|
|
setReplying(false);
|
|
|
|
}}
|
2021-08-27 12:29:58 +02:00
|
|
|
supportDisabled={supportDisabled}
|
2020-10-07 21:14:52 +02:00
|
|
|
/>
|
|
|
|
)}
|
2020-09-11 19:51:31 +02:00
|
|
|
</>
|
|
|
|
)}
|
|
|
|
</div>
|
2019-10-24 19:24:53 +02:00
|
|
|
</div>
|
2019-07-24 23:02:35 +02:00
|
|
|
</div>
|
2020-09-11 19:51:31 +02:00
|
|
|
|
2021-07-15 16:43:28 +02:00
|
|
|
{showReplies && (
|
|
|
|
<CommentsReplies
|
|
|
|
threadDepth={threadDepth - 1}
|
|
|
|
uri={uri}
|
|
|
|
parentId={commentId}
|
|
|
|
linkedCommentId={linkedCommentId}
|
|
|
|
numDirectReplies={numDirectReplies}
|
|
|
|
onShowMore={() => setPage(page + 1)}
|
2021-08-04 17:01:31 +02:00
|
|
|
hasMore={page < totalReplyPages}
|
2021-07-15 16:43:28 +02:00
|
|
|
/>
|
|
|
|
)}
|
2019-06-27 01:59:27 +02:00
|
|
|
</li>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-02-09 16:27:11 +01:00
|
|
|
export default CommentView;
|