Fix scroll re-rendering issues and improve superchats
This commit is contained in:
parent
c50cc422b7
commit
1578810013
2 changed files with 37 additions and 39 deletions
|
@ -9,6 +9,7 @@ type Props = {
|
||||||
className?: string,
|
className?: string,
|
||||||
customAmounts?: { amountFiat: number, amountLBC: number },
|
customAmounts?: { amountFiat: number, amountLBC: number },
|
||||||
fee?: boolean,
|
fee?: boolean,
|
||||||
|
hideTitle?: boolean,
|
||||||
isEstimate?: boolean,
|
isEstimate?: boolean,
|
||||||
isFiat?: boolean,
|
isFiat?: boolean,
|
||||||
noFormat?: boolean,
|
noFormat?: boolean,
|
||||||
|
@ -38,6 +39,7 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
className,
|
className,
|
||||||
customAmounts,
|
customAmounts,
|
||||||
fee,
|
fee,
|
||||||
|
hideTitle,
|
||||||
isEstimate,
|
isEstimate,
|
||||||
isFiat,
|
isFiat,
|
||||||
noFormat,
|
noFormat,
|
||||||
|
@ -94,7 +96,7 @@ class CreditAmount extends React.PureComponent<Props> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span
|
<span
|
||||||
title={amount ? formatFullPrice(amount, 2) : ''}
|
title={amount && !hideTitle ? formatFullPrice(amount, 2) : ''}
|
||||||
className={classnames(className, {
|
className={classnames(className, {
|
||||||
'super-chat': superChat,
|
'super-chat': superChat,
|
||||||
'super-chat--light': superChatLight,
|
'super-chat--light': superChatLight,
|
||||||
|
|
|
@ -27,8 +27,10 @@ type Props = {
|
||||||
doResolveUris: (Array<string>, boolean) => void,
|
doResolveUris: (Array<string>, boolean) => void,
|
||||||
};
|
};
|
||||||
|
|
||||||
const VIEW_MODE_CHAT = 'view_chat';
|
const VIEW_MODES = {
|
||||||
const VIEW_MODE_SUPER_CHAT = 'view_superchat';
|
CHAT: 'chat',
|
||||||
|
SUPERCHAT: 'sc',
|
||||||
|
};
|
||||||
const COMMENT_SCROLL_TIMEOUT = 25;
|
const COMMENT_SCROLL_TIMEOUT = 25;
|
||||||
const LARGE_SUPER_CHAT_LIST_THRESHOLD = 20;
|
const LARGE_SUPER_CHAT_LIST_THRESHOLD = 20;
|
||||||
|
|
||||||
|
@ -50,14 +52,14 @@ export default function LivestreamComments(props: Props) {
|
||||||
let superChatsFiatAmount, superChatsLBCAmount, superChatsTotalAmount, hasSuperChats;
|
let superChatsFiatAmount, superChatsLBCAmount, superChatsTotalAmount, hasSuperChats;
|
||||||
|
|
||||||
const commentsRef = React.createRef();
|
const commentsRef = React.createRef();
|
||||||
const [viewMode, setViewMode] = React.useState(VIEW_MODE_CHAT);
|
const [viewMode, setViewMode] = React.useState(VIEW_MODES.CHAT);
|
||||||
const [scrollPos, setScrollPos] = React.useState(0);
|
const [scrollPos, setScrollPos] = React.useState(0);
|
||||||
const [showPinned, setShowPinned] = React.useState(true);
|
const [showPinned, setShowPinned] = React.useState(true);
|
||||||
const [resolvingSuperChat, setResolvingSuperChat] = React.useState(false);
|
const [resolvingSuperChat, setResolvingSuperChat] = React.useState(false);
|
||||||
const claimId = claim && claim.claim_id;
|
const claimId = claim && claim.claim_id;
|
||||||
const commentsLength = commentsByChronologicalOrder && commentsByChronologicalOrder.length;
|
const commentsLength = commentsByChronologicalOrder && commentsByChronologicalOrder.length;
|
||||||
|
|
||||||
const commentsToDisplay = viewMode === VIEW_MODE_CHAT ? commentsByChronologicalOrder : superChatsByTipAmount;
|
const commentsToDisplay = viewMode === VIEW_MODES.CHAT ? commentsByChronologicalOrder : superChatsByTipAmount;
|
||||||
const stickerSuperChats =
|
const stickerSuperChats =
|
||||||
superChatsByTipAmount && superChatsByTipAmount.filter(({ comment }) => Boolean(parseSticker(comment)));
|
superChatsByTipAmount && superChatsByTipAmount.filter(({ comment }) => Boolean(parseSticker(comment)));
|
||||||
|
|
||||||
|
@ -101,7 +103,7 @@ export default function LivestreamComments(props: Props) {
|
||||||
// Register scroll handler (TODO: Should throttle/debounce)
|
// Register scroll handler (TODO: Should throttle/debounce)
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
function handleScroll() {
|
function handleScroll() {
|
||||||
if (discussionElement) {
|
if (discussionElement && viewMode === VIEW_MODES.CHAT) {
|
||||||
const scrollTop = discussionElement.scrollTop;
|
const scrollTop = discussionElement.scrollTop;
|
||||||
if (scrollTop !== scrollPos) {
|
if (scrollTop !== scrollPos) {
|
||||||
setScrollPos(scrollTop);
|
setScrollPos(scrollTop);
|
||||||
|
@ -109,11 +111,11 @@ export default function LivestreamComments(props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (discussionElement) {
|
if (discussionElement && viewMode === VIEW_MODES.CHAT) {
|
||||||
discussionElement.addEventListener('scroll', handleScroll);
|
discussionElement.addEventListener('scroll', handleScroll);
|
||||||
return () => discussionElement.removeEventListener('scroll', handleScroll);
|
return () => discussionElement.removeEventListener('scroll', handleScroll);
|
||||||
}
|
}
|
||||||
}, [discussionElement, scrollPos]);
|
}, [discussionElement, scrollPos, viewMode]);
|
||||||
|
|
||||||
// Retain scrollPos=0 when receiving new messages.
|
// Retain scrollPos=0 when receiving new messages.
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -201,12 +203,10 @@ export default function LivestreamComments(props: Props) {
|
||||||
<div className="recommended-content__toggles">
|
<div className="recommended-content__toggles">
|
||||||
{/* the superchats in chronological order button */}
|
{/* the superchats in chronological order button */}
|
||||||
<Button
|
<Button
|
||||||
className={classnames('button-toggle', {
|
className={classnames('button-toggle', { 'button-toggle--active': viewMode === VIEW_MODES.CHAT })}
|
||||||
'button-toggle--active': viewMode === VIEW_MODE_CHAT,
|
|
||||||
})}
|
|
||||||
label={__('Chat')}
|
label={__('Chat')}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setViewMode(VIEW_MODE_CHAT);
|
setViewMode(VIEW_MODES.CHAT);
|
||||||
const livestreamCommentsDiv = document.getElementsByClassName('livestream__comments')[0];
|
const livestreamCommentsDiv = document.getElementsByClassName('livestream__comments')[0];
|
||||||
livestreamCommentsDiv.scrollTop = livestreamCommentsDiv.scrollHeight;
|
livestreamCommentsDiv.scrollTop = livestreamCommentsDiv.scrollHeight;
|
||||||
}}
|
}}
|
||||||
|
@ -214,9 +214,7 @@ export default function LivestreamComments(props: Props) {
|
||||||
|
|
||||||
{/* the button to show superchats listed by most to least support amount */}
|
{/* the button to show superchats listed by most to least support amount */}
|
||||||
<Button
|
<Button
|
||||||
className={classnames('button-toggle', {
|
className={classnames('button-toggle', { 'button-toggle--active': viewMode === VIEW_MODES.SUPERCHAT })}
|
||||||
'button-toggle--active': viewMode === VIEW_MODE_SUPER_CHAT,
|
|
||||||
})}
|
|
||||||
label={
|
label={
|
||||||
<>
|
<>
|
||||||
<CreditAmount amount={superChatsLBCAmount || 0} size={8} /> /
|
<CreditAmount amount={superChatsLBCAmount || 0} size={8} /> /
|
||||||
|
@ -225,7 +223,7 @@ export default function LivestreamComments(props: Props) {
|
||||||
}
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
resolveSuperChat();
|
resolveSuperChat();
|
||||||
setViewMode(VIEW_MODE_SUPER_CHAT);
|
setViewMode(VIEW_MODES.SUPERCHAT);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -238,21 +236,19 @@ export default function LivestreamComments(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div ref={commentsRef} className="livestream__comments-wrapper">
|
<div ref={commentsRef} className="livestream__comments-wrapper">
|
||||||
{viewMode === VIEW_MODE_CHAT && superChatsByTipAmount && hasSuperChats && (
|
{viewMode === VIEW_MODES.CHAT && superChatsByTipAmount && hasSuperChats && (
|
||||||
<div className="livestream-superchats__wrapper">
|
<div className="livestream-superchats__wrapper">
|
||||||
<div className="livestream-superchats__inner">
|
<div className="livestream-superchats__inner">
|
||||||
{superChatTopTen.map((superChat: Comment) => {
|
{superChatTopTen.map((superChat: Comment) => {
|
||||||
|
const { comment, comment_id, channel_url, support_amount, is_fiat } = superChat;
|
||||||
const isSticker = stickerSuperChats && stickerSuperChats.includes(superChat);
|
const isSticker = stickerSuperChats && stickerSuperChats.includes(superChat);
|
||||||
|
const stickerImg = <OptimizedImage src={getStickerUrl(comment)} waitLoad loading="lazy" />;
|
||||||
const SuperChatWrapper = !isSticker
|
|
||||||
? ({ children }) => <Tooltip title={superChat.comment}>{children}</Tooltip>
|
|
||||||
: ({ children }) => <>{children}</>;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SuperChatWrapper key={superChat.comment_id}>
|
<Tooltip title={isSticker ? stickerImg : comment} key={comment_id}>
|
||||||
<div className="livestream-superchat">
|
<div className="livestream-superchat">
|
||||||
<div className="livestream-superchat__thumbnail">
|
<div className="livestream-superchat__thumbnail">
|
||||||
<ChannelThumbnail uri={superChat.channel_url} xsmall />
|
<ChannelThumbnail uri={channel_url} xsmall />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -262,41 +258,41 @@ export default function LivestreamComments(props: Props) {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className="livestream-superchat__info--user">
|
<div className="livestream-superchat__info--user">
|
||||||
<UriIndicator uri={superChat.channel_url} link />
|
<UriIndicator uri={channel_url} link />
|
||||||
<CreditAmount
|
<CreditAmount
|
||||||
|
hideTitle
|
||||||
size={10}
|
size={10}
|
||||||
className="livestream-superchat__amount-large"
|
className="livestream-superchat__amount-large"
|
||||||
amount={superChat.support_amount}
|
amount={support_amount}
|
||||||
isFiat={superChat.is_fiat}
|
isFiat={is_fiat}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{stickerSuperChats.includes(superChat) && getStickerUrl(superChat.comment) && (
|
|
||||||
<div className="livestream-superchat__info--image">
|
{isSticker && <div className="livestream-superchat__info--image">{stickerImg}</div>}
|
||||||
<OptimizedImage src={getStickerUrl(superChat.comment)} waitLoad loading="lazy" />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SuperChatWrapper>
|
</Tooltip>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{showMoreSuperChatsButton && (
|
{showMoreSuperChatsButton && (
|
||||||
<Button
|
<Button
|
||||||
title={__('Show More...')}
|
title={__('Show More...')}
|
||||||
|
label={__('Show More')}
|
||||||
button="inverse"
|
button="inverse"
|
||||||
className="close-button"
|
className="close-button"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
resolveSuperChat();
|
resolveSuperChat();
|
||||||
setViewMode(VIEW_MODE_SUPER_CHAT);
|
setViewMode(VIEW_MODES.SUPERCHAT);
|
||||||
}}
|
}}
|
||||||
icon={ICONS.MORE}
|
iconRight={ICONS.MORE}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{pinnedComment && showPinned && viewMode === VIEW_MODE_CHAT && (
|
{pinnedComment && showPinned && viewMode === VIEW_MODES.CHAT && (
|
||||||
<div className="livestream-pinned__wrapper">
|
<div className="livestream-pinned__wrapper">
|
||||||
<LivestreamComment
|
<LivestreamComment
|
||||||
key={pinnedComment.comment_id}
|
key={pinnedComment.comment_id}
|
||||||
|
@ -324,7 +320,7 @@ export default function LivestreamComments(props: Props) {
|
||||||
{/* top to bottom comment display */}
|
{/* top to bottom comment display */}
|
||||||
{!fetchingComments && commentsByChronologicalOrder.length > 0 ? (
|
{!fetchingComments && commentsByChronologicalOrder.length > 0 ? (
|
||||||
<div className="livestream__comments">
|
<div className="livestream__comments">
|
||||||
{viewMode === VIEW_MODE_CHAT &&
|
{viewMode === VIEW_MODES.CHAT &&
|
||||||
commentsToDisplay.map((comment) => (
|
commentsToDisplay.map((comment) => (
|
||||||
<LivestreamComment
|
<LivestreamComment
|
||||||
key={comment.comment_id}
|
key={comment.comment_id}
|
||||||
|
@ -340,13 +336,13 @@ export default function LivestreamComments(props: Props) {
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{viewMode === VIEW_MODE_SUPER_CHAT && resolvingSuperChat && (
|
{viewMode === VIEW_MODES.SUPERCHAT && resolvingSuperChat && (
|
||||||
<div className="main--empty">
|
<div className="main--empty">
|
||||||
<Spinner />
|
<Spinner />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{viewMode === VIEW_MODE_SUPER_CHAT &&
|
{viewMode === VIEW_MODES.SUPERCHAT &&
|
||||||
!resolvingSuperChat &&
|
!resolvingSuperChat &&
|
||||||
superChatsReversed &&
|
superChatsReversed &&
|
||||||
superChatsReversed.map((comment) => (
|
superChatsReversed.map((comment) => (
|
||||||
|
@ -368,7 +364,7 @@ export default function LivestreamComments(props: Props) {
|
||||||
<div className="main--empty" style={{ flex: 1 }} />
|
<div className="main--empty" style={{ flex: 1 }} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{scrollPos < 0 && viewMode === VIEW_MODE_CHAT && (
|
{scrollPos < 0 && viewMode === VIEW_MODES.CHAT && (
|
||||||
<Button
|
<Button
|
||||||
button="secondary"
|
button="secondary"
|
||||||
className="livestream__comments__scroll-to-recent"
|
className="livestream__comments__scroll-to-recent"
|
||||||
|
|
Loading…
Reference in a new issue