lbry-desktop/ui/component/livestreamComments/view.jsx

262 lines
8.9 KiB
React
Raw Normal View History

// @flow
import React from 'react';
import classnames from 'classnames';
import Spinner from 'component/spinner';
import CommentCreate from 'component/commentCreate';
2021-04-23 21:59:48 +02:00
import LivestreamComment from 'component/livestreamComment';
import Button from 'component/button';
import UriIndicator from 'component/uriIndicator';
import CreditAmount from 'component/common/credit-amount';
import ChannelThumbnail from 'component/channelThumbnail';
import Tooltip from 'component/common/tooltip';
type Props = {
uri: string,
claim: ?StreamClaim,
activeViewers: number,
embed?: boolean,
doCommentSocketConnect: (string, string) => void,
doCommentSocketDisconnect: (string) => void,
doCommentList: (string, string, number, number) => void,
comments: Array<Comment>,
fetchingComments: boolean,
2021-04-23 21:59:48 +02:00
doSuperChatList: (string) => void,
superChats: Array<Comment>,
2021-07-24 20:55:09 +02:00
superChatsReversed: Array,
2021-04-23 21:59:48 +02:00
superChatsTotalAmount: number,
myChannels: ?Array<ChannelClaim>,
};
2021-04-23 21:59:48 +02:00
const VIEW_MODE_CHAT = 'view_chat';
const VIEW_MODE_SUPER_CHAT = 'view_superchat';
2021-06-22 16:42:52 +02:00
const COMMENT_SCROLL_OFFSET = 100;
const COMMENT_SCROLL_TIMEOUT = 25;
2021-04-23 21:59:48 +02:00
export default function LivestreamComments(props: Props) {
const {
claim,
uri,
embed,
doCommentSocketConnect,
doCommentSocketDisconnect,
2021-07-24 20:55:09 +02:00
comments, // superchats in chronological format
doCommentList,
fetchingComments,
2021-04-23 21:59:48 +02:00
doSuperChatList,
superChatsTotalAmount,
myChannels,
2021-07-24 20:55:09 +02:00
superChats, // superchats organized by tip amount
} = props;
2021-07-24 20:55:09 +02:00
let { superChatsReversed } = props;
if (superChats) {
const clonedSuperchats = JSON.parse(JSON.stringify(superChats));
// sort by fiat first then by support amount
superChatsReversed = clonedSuperchats.sort(function(a,b) {
if (a.is_fiat === b.is_fiat) {
return b.support_amount - a.support_amount;
} else {
return (a.is_fiat === b.is_fiat) ? 0 : a.is_fiat ? -1 : 1;
}
}).reverse();
}
const commentsRef = React.createRef();
const [scrollBottom, setScrollBottom] = React.useState(true);
2021-04-23 21:59:48 +02:00
const [viewMode, setViewMode] = React.useState(VIEW_MODE_CHAT);
const [performedInitialScroll, setPerformedInitialScroll] = React.useState(false);
const claimId = claim && claim.claim_id;
const commentsLength = comments && comments.length;
2021-04-23 21:59:48 +02:00
const commentsToDisplay = viewMode === VIEW_MODE_CHAT ? comments : superChats;
const discussionElement = document.querySelector('.livestream__comments');
const commentElement = document.querySelector('.livestream-comment');
// todo: implement comment_list --mine in SDK so redux can grab with selectCommentIsMine
function isMyComment(channelId: string) {
if (myChannels != null && channelId != null) {
for (let i = 0; i < myChannels.length; i++) {
if (myChannels[i].claim_id === channelId) {
return true;
}
}
}
return false;
}
React.useEffect(() => {
2021-07-24 20:55:09 +02:00
if (claimId) {
doCommentList(uri, '', 1, 75);
2021-04-23 21:59:48 +02:00
doSuperChatList(uri);
doCommentSocketConnect(uri, claimId);
}
return () => {
if (claimId) {
doCommentSocketDisconnect(claimId);
}
};
2021-04-23 21:59:48 +02:00
}, [claimId, uri, doCommentList, doSuperChatList, doCommentSocketConnect, doCommentSocketDisconnect]);
const handleScroll = React.useCallback(() => {
if (discussionElement) {
const negativeCommentHeight = commentElement && -1 * commentElement.offsetHeight;
const isAtRecent = negativeCommentHeight && discussionElement.scrollTop >= negativeCommentHeight;
setScrollBottom(isAtRecent);
}
}, [commentElement, discussionElement]);
React.useEffect(() => {
if (discussionElement) {
discussionElement.addEventListener('scroll', handleScroll);
if (commentsLength > 0) {
// Only update comment scroll if the user hasn't scrolled up to view old comments
// If they have, do nothing
if (!performedInitialScroll) {
2021-06-22 16:42:52 +02:00
setTimeout(
() =>
(discussionElement.scrollTop =
discussionElement.scrollHeight - discussionElement.offsetHeight + COMMENT_SCROLL_OFFSET),
COMMENT_SCROLL_TIMEOUT
);
setPerformedInitialScroll(true);
}
}
return () => discussionElement.removeEventListener('scroll', handleScroll);
}
}, [commentsLength, discussionElement, handleScroll, performedInitialScroll, setPerformedInitialScroll]);
if (!claim) {
return null;
}
function scrollBack() {
if (discussionElement) {
discussionElement.scrollTop = 0;
setScrollBottom(true);
}
}
return (
2021-04-23 21:59:48 +02:00
<div className="card livestream__discussion">
<div className="card__header--between livestream-discussion__header">
<div className="livestream-discussion__title">{__('Live discussion')}</div>
{superChatsTotalAmount > 0 && (
<div className="recommended-content__toggles">
2021-07-24 20:55:09 +02:00
{/* the superchats in chronological order button */}
2021-04-23 21:59:48 +02:00
<Button
className={classnames('button-toggle', {
'button-toggle--active': viewMode === VIEW_MODE_CHAT,
})}
label={__('Chat')}
onClick={() => setViewMode(VIEW_MODE_CHAT)}
/>
2021-07-24 20:55:09 +02:00
{/* the list by tip amount value button */}
2021-04-23 21:59:48 +02:00
<Button
className={classnames('button-toggle', {
'button-toggle--active': viewMode === VIEW_MODE_SUPER_CHAT,
})}
label={
<>
2021-07-24 20:55:09 +02:00
<CreditAmount amount={superChatsTotalAmount} size={8} /> /
<CreditAmount amount={superChatsTotalAmount} size={8} isFiat={true} /> {' '}{__('Tipped')}
2021-04-23 21:59:48 +02:00
</>
}
onClick={() => setViewMode(VIEW_MODE_SUPER_CHAT)}
/>
</div>
)}
</div>
<>
{fetchingComments && !comments && (
<div className="main--empty">
<Spinner />
</div>
)}
<div ref={commentsRef} className="livestream__comments-wrapper">
2021-07-18 19:06:52 +02:00
{viewMode === VIEW_MODE_CHAT && superChatsTotalAmount > 0 && superChats && (
2021-04-23 21:59:48 +02:00
<div className="livestream-superchats__wrapper">
<div className="livestream-superchats__inner">
{superChats.map((superChat: Comment) => (
<Tooltip key={superChat.comment_id} label={superChat.comment}>
<div className="livestream-superchat">
<div className="livestream-superchat__thumbnail">
<ChannelThumbnail uri={superChat.channel_url} xsmall />
</div>
<div className="livestream-superchat__info">
<UriIndicator uri={superChat.channel_url} link />
<CreditAmount
size={10}
className="livestream-superchat__amount-large"
amount={superChat.support_amount}
isFiat={superChat.is_fiat}
2021-04-23 21:59:48 +02:00
/>
</div>
</div>
</Tooltip>
))}
</div>
2021-04-23 21:59:48 +02:00
</div>
)}
2021-07-24 20:55:09 +02:00
{/* top to bottom comment display */}
2021-04-23 21:59:48 +02:00
{!fetchingComments && comments.length > 0 ? (
<div className="livestream__comments">
2021-07-24 20:55:09 +02:00
{viewMode === VIEW_MODE_CHAT && commentsToDisplay.map((comment) => (
<LivestreamComment
key={comment.comment_id}
uri={uri}
authorUri={comment.channel_url}
commentId={comment.comment_id}
message={comment.comment}
supportAmount={comment.support_amount}
isFiat={comment.is_fiat}
commentIsMine={comment.channel_id && isMyComment(comment.channel_id)}
/>
))}
{viewMode === VIEW_MODE_SUPER_CHAT && superChatsReversed && superChatsReversed.map((comment) => (
2021-04-23 21:59:48 +02:00
<LivestreamComment
key={comment.comment_id}
uri={uri}
authorUri={comment.channel_url}
commentId={comment.comment_id}
message={comment.comment}
supportAmount={comment.support_amount}
isFiat={comment.is_fiat}
commentIsMine={comment.channel_id && isMyComment(comment.channel_id)}
2021-04-23 21:59:48 +02:00
/>
))}
2021-07-24 20:55:09 +02:00
2021-04-23 21:59:48 +02:00
</div>
) : (
<div className="main--empty" style={{ flex: 1 }} />
)}
{!scrollBottom && (
<Button
button="alt"
className="livestream__comments-scroll__down"
label={__('Recent Comments')}
onClick={scrollBack}
/>
)}
<div className="livestream__comment-create">
<CommentCreate livestream bottom embed={embed} uri={uri} />
</div>
2021-04-23 21:59:48 +02:00
</div>
</>
</div>
);
}