Improve comment selectors

This commit is contained in:
Rafael 2022-02-07 16:30:42 -03:00 committed by Thomas Zarebczan
parent 2b56ca8599
commit c758c59066
8 changed files with 121 additions and 61 deletions

View file

@ -9,20 +9,26 @@ import React from 'react';
import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'component/common/tabs';
import { FREE_GLOBAL_STICKERS, PAID_GLOBAL_STICKERS } from 'constants/stickers';
export const SELECTOR_TABS = {
EMOJI: 0,
STICKER: 1,
};
type Props = {
claimIsMine?: boolean,
openTab?: number,
addEmoteToComment: (string) => void,
handleSelectSticker: (any) => void,
closeSelector?: () => void,
};
export default function CommentSelectors(props: Props) {
const { claimIsMine, addEmoteToComment, handleSelectSticker, closeSelector } = props;
const { claimIsMine, openTab, addEmoteToComment, handleSelectSticker, closeSelector } = props;
const tabProps = { closeSelector };
return (
<Tabs>
<Tabs index={openTab}>
<TabList className="tabs__list--comment-selector">
<Tab>{__('Emojis')}</Tab>
<Tab>{__('Stickers')}</Tab>

View file

@ -50,10 +50,6 @@ export const StickerActionButton = (stickerButtonProps: StickerButtonProps) => {
const { isReviewingStickerComment, ...buttonProps } = stickerButtonProps;
return (
<Button
{...buttonProps}
title={__('Stickers')}
label={isReviewingStickerComment ? __('Different Sticker') : undefined}
/>
<Button {...buttonProps} title={__('Stickers')} label={isReviewingStickerComment ? __('Change') : undefined} />
);
};

View file

@ -15,10 +15,12 @@ type Props = {
tipAmount: number,
activeTab: string,
message: string,
isReviewingStickerComment?: boolean,
stickerPreviewComponent?: any,
};
export const TipReviewBox = (props: Props) => {
const { activeChannelUrl, tipAmount, activeTab, message } = props;
const { activeChannelUrl, tipAmount, activeTab, message, isReviewingStickerComment, stickerPreviewComponent } = props;
return (
<div className="commentCreate__supportCommentPreview">
@ -29,11 +31,18 @@ export const TipReviewBox = (props: Props) => {
size={activeTab === TAB_LBC ? 18 : 2}
/>
<ChannelThumbnail xsmall uri={activeChannelUrl} />
<div className="commentCreate__supportCommentBody">
<UriIndicator uri={activeChannelUrl} link />
<div>{message}</div>
</div>
{isReviewingStickerComment ? (
stickerPreviewComponent
) : (
<>
<ChannelThumbnail xsmall uri={activeChannelUrl} />
<div className="commentCreate__supportCommentBody">
<UriIndicator uri={activeChannelUrl} link />
<div>{message}</div>
</div>
</>
)}
</div>
);
};

View file

@ -14,7 +14,7 @@ import * as PAGES from 'constants/pages';
import * as MODALS from 'constants/modal_types';
import Button from 'component/button';
import classnames from 'classnames';
import CommentSelectors from './comment-selectors';
import CommentSelectors, { SELECTOR_TABS } from './comment-selectors';
import React from 'react';
import type { ElementRef } from 'react';
import usePersistedState from 'effects/use-persisted-state';
@ -34,7 +34,6 @@ type TipParams = { tipAmount: number, tipChannelName: string, channelClaimId: st
type UserParams = { activeChannelName: ?string, activeChannelId: ?string };
type Props = {
activeChannel: string,
activeChannelClaimId?: string,
activeChannelName?: string,
activeChannelUrl?: string,
@ -106,6 +105,7 @@ export function CommentCreate(props: Props) {
const formFieldRef: ElementRef<any> = React.useRef();
const buttonRef: ElementRef<any> = React.useRef();
const slimInputButtonRef: ElementRef<any> = React.useRef();
const {
push,
@ -126,7 +126,7 @@ export function CommentCreate(props: Props) {
const [activeTab, setActiveTab] = React.useState();
const [tipError, setTipError] = React.useState();
const [deletedComment, setDeletedComment] = React.useState(false);
const [showSelectors, setShowSelectors] = React.useState(false);
const [showSelectors, setShowSelectors] = React.useState({ tab: undefined, open: false });
const [disableReviewButton, setDisableReviewButton] = React.useState();
const [exchangeRate, setExchangeRate] = React.useState();
const [canReceiveFiatTip, setCanReceiveFiatTip] = React.useState(undefined);
@ -180,9 +180,15 @@ export function CommentCreate(props: Props) {
}
function handleStickerComment() {
if (selectedSticker) setReviewingStickerComment(false);
if (selectedSticker) {
setReviewingStickerComment(false);
setSelectedSticker(undefined);
setShowSelectors({ tab: SELECTOR_TABS.STICKER, open: true });
} else {
setShowSelectors({ tab: showSelectors.tab || undefined, open: !showSelectors.open });
}
setTipSelector(false);
setShowSelectors(!showSelectors);
}
function handleSelectSticker(sticker: any) {
@ -190,7 +196,7 @@ export function CommentCreate(props: Props) {
setSelectedSticker(sticker);
setReviewingStickerComment(true);
setTipAmount(sticker.price || 0);
setShowSelectors(false);
setShowSelectors({ tab: showSelectors.tab || undefined, open: false });
if (sticker.price && sticker.price > 0) {
setActiveTab(canReceiveFiatTip ? TAB_FIAT : TAB_LBC);
@ -209,7 +215,7 @@ export function CommentCreate(props: Props) {
if (stickerPrice) {
setReviewingStickerComment(false);
setShowSelectors(false);
setShowSelectors({ tab: showSelectors.tab || undefined, open: false });
setSelectedSticker(null);
}
}
@ -362,7 +368,7 @@ export function CommentCreate(props: Props) {
setSelectedSticker(null);
setReviewingStickerComment(false);
setShowSelectors(false);
setShowSelectors({ tab: showSelectors.tab || undefined, open: false });
setTipSelector(false);
}
@ -377,6 +383,13 @@ export function CommentCreate(props: Props) {
}
}, []); // eslint-disable-line react-hooks/exhaustive-deps
// change sticker selection
React.useEffect(() => {
if (isMobile && showSelectors.tab && slimInputButtonRef && slimInputButtonRef.current) {
slimInputButtonRef.current.click();
}
}, [isMobile, showSelectors.tab]);
// Notifications: Fetch top-level comments to identify if it has been deleted and can reply to it
React.useEffect(() => {
if (shouldFetchComment && doCommentById) {
@ -394,7 +407,7 @@ export function CommentCreate(props: Props) {
// Stickers: Check if creator has a tip account saved (on selector so that if a paid sticker is selected,
// it defaults to LBC tip instead of USD)
React.useEffect(() => {
if (!stripeEnvironment || !showSelectors || canReceiveFiatTip !== undefined || !tipChannelName) return;
if (!stripeEnvironment || canReceiveFiatTip !== undefined || !tipChannelName) return;
Lbryio.call(
'account',
@ -414,7 +427,7 @@ export function CommentCreate(props: Props) {
}
})
.catch(() => {});
}, [canReceiveFiatTip, channelClaimId, showSelectors, tipChannelName]);
}, [canReceiveFiatTip, channelClaimId, tipChannelName]);
// Handle keyboard shortcut comment creation
React.useEffect(() => {
@ -486,7 +499,12 @@ export function CommentCreate(props: Props) {
);
}
const commentSelectorsProps = { claimIsMine, addEmoteToComment, handleSelectSticker };
const commentSelectorsProps = {
claimIsMine,
addEmoteToComment,
handleSelectSticker,
openTab: showSelectors.tab || undefined,
};
const submitButtonProps = { button: 'primary', type: 'submit', requiresAuth: true };
const actionButtonProps = { button: 'alt' };
const tipButtonProps = {
@ -497,6 +515,12 @@ export function CommentCreate(props: Props) {
onClick: handleSelectTipComment,
};
const cancelButtonProps = { button: 'link', label: __('Cancel') };
const stickerReviewProps = {
activeChannelUrl,
src: selectedSticker ? selectedSticker.url : '',
price: selectedSticker ? selectedSticker.price : 0,
exchangeRate,
};
return (
<Form
@ -507,16 +531,7 @@ export function CommentCreate(props: Props) {
'commentCreate--bottom': bottom,
})}
>
{selectedSticker ? (
activeChannelUrl && (
<StickerReviewBox
activeChannelUrl={activeChannelUrl}
src={selectedSticker.url}
price={selectedSticker.price || 0}
exchangeRate={exchangeRate}
/>
)
) : isReviewingSupportComment ? (
{isReviewingSupportComment ? (
activeChannelUrl &&
activeTab && (
<TipReviewBox
@ -524,12 +539,19 @@ export function CommentCreate(props: Props) {
tipAmount={tipAmount}
activeTab={activeTab}
message={commentValue}
isReviewingStickerComment={isReviewingStickerComment}
stickerPreviewComponent={selectedSticker && <StickerReviewBox {...stickerReviewProps} />}
/>
)
) : selectedSticker ? (
activeChannelUrl && <StickerReviewBox {...stickerReviewProps} />
) : (
<>
{!isMobile && showSelectors && (
<CommentSelectors {...commentSelectorsProps} closeSelector={() => setShowSelectors(false)} />
{!isMobile && showSelectors.open && (
<CommentSelectors
{...commentSelectorsProps}
closeSelector={() => setShowSelectors({ tab: showSelectors.tab || undefined, open: false })}
/>
)}
<FormField
@ -548,7 +570,8 @@ export function CommentCreate(props: Props) {
onChange={(e) => setCommentValue(SIMPLE_SITE || !advancedEditor || isReply ? e.target.value : e)}
handleTip={(isLBC) => handleSelectTipComment(isLBC ? TAB_LBC : TAB_FIAT)}
handleSubmit={handleCreateComment}
slimInput={isMobile}
slimInput={isMobile && uri} // "uri": make sure it's on a file page
slimInputButtonRef={slimInputButtonRef}
commentSelectorsProps={commentSelectorsProps}
submitButtonRef={buttonRef}
setShowSelectors={setShowSelectors}
@ -631,21 +654,23 @@ export function CommentCreate(props: Props) {
)
)}
{!isMobile && (
<StickerActionButton
{...actionButtonProps}
isReviewingStickerComment={isReviewingStickerComment}
icon={ICONS.STICKER}
onClick={handleStickerComment}
/>
)}
{(!isMobile || isReviewingStickerComment) && !supportDisabled && (
{(!isMobile || isReviewingStickerComment) && (
<>
<TipActionButton {...tipButtonProps} name={__('Credits')} icon={ICONS.LBC} tab={TAB_LBC} />
<StickerActionButton
{...actionButtonProps}
isReviewingStickerComment={isReviewingStickerComment}
icon={ICONS.STICKER}
onClick={handleStickerComment}
/>
{stripeEnvironment && (
<TipActionButton {...tipButtonProps} name={__('Cash')} icon={ICONS.FINANCE} tab={TAB_FIAT} />
{!supportDisabled && !claimIsMine && (
<>
<TipActionButton {...tipButtonProps} name={__('Credits')} icon={ICONS.LBC} tab={TAB_LBC} />
{stripeEnvironment && (
<TipActionButton {...tipButtonProps} name={__('Cash')} icon={ICONS.FINANCE} tab={TAB_FIAT} />
)}
</>
)}
</>
)}

View file

@ -45,13 +45,14 @@ type Props = {
type?: string,
value?: string | number,
slimInput?: boolean,
slimInputButtonRef?: any,
commentSelectorsProps?: any,
showSelectors?: boolean,
showSelectors?: any,
submitButtonRef?: any,
tipModalOpen?: boolean,
noticeLabel?: any,
onChange?: (any) => any,
setShowSelectors?: (boolean) => void,
setShowSelectors?: ({ tab?: string, open: boolean }) => void,
quickActionHandler?: (any) => any,
render?: () => React$Node,
handleTip?: (isLBC: boolean) => any,
@ -88,7 +89,7 @@ export class FormField extends React.PureComponent<Props, State> {
const input = this.input.current;
// Opened selectors (emoji/sticker) -> blur input and hide keyboard
if (slimInput && showSelectors && input) input.blur();
if (slimInput && showSelectors && showSelectors.open && input) input.blur();
}
render() {
@ -114,6 +115,7 @@ export class FormField extends React.PureComponent<Props, State> {
textAreaMaxLength,
type,
slimInput,
slimInputButtonRef,
commentSelectorsProps,
showSelectors,
submitButtonRef,
@ -270,10 +272,15 @@ export class FormField extends React.PureComponent<Props, State> {
<TextareaWrapper
isDrawerOpen={Boolean(this.state.drawerOpen)}
toggleDrawer={() => this.setState({ drawerOpen: !this.state.drawerOpen })}
closeSelector={setShowSelectors ? () => setShowSelectors(false) : () => {}}
closeSelector={
setShowSelectors && showSelectors
? () => setShowSelectors({ tab: showSelectors.tab || undefined, open: false })
: () => {}
}
commentSelectorsProps={commentSelectorsProps}
showSelectors={Boolean(showSelectors)}
showSelectors={Boolean(showSelectors && showSelectors.open)}
slimInput={slimInput}
slimInputButtonRef={slimInputButtonRef}
tipModalOpen={tipModalOpen}
>
{(!slimInput || this.state.drawerOpen) && (label || quickAction) && (
@ -303,7 +310,11 @@ export class FormField extends React.PureComponent<Props, State> {
maxLength={textAreaMaxLength || FF_MAX_CHARS_DEFAULT}
inputRef={this.input}
isLivestream={isLivestream}
toggleSelectors={setShowSelectors ? () => setShowSelectors(!showSelectors) : undefined}
toggleSelectors={
setShowSelectors && showSelectors
? () => setShowSelectors({ tab: showSelectors.tab || undefined, open: !showSelectors.open })
: undefined
}
handleTip={handleTip}
handleSubmit={() => {
if (handleSubmit) handleSubmit();
@ -311,6 +322,7 @@ export class FormField extends React.PureComponent<Props, State> {
}}
claimIsMine={commentSelectorsProps && commentSelectorsProps.claimIsMine}
{...inputProps}
slimInput={slimInput}
handlePreventClick={
!this.state.drawerOpen ? () => this.setState({ drawerOpen: true }) : undefined
}
@ -360,6 +372,7 @@ export default FormField;
type TextareaWrapperProps = {
slimInput?: boolean,
slimInputButtonRef?: any,
children: Node,
isDrawerOpen: boolean,
showSelectors?: boolean,
@ -373,6 +386,7 @@ function TextareaWrapper(wrapperProps: TextareaWrapperProps) {
const {
children,
slimInput,
slimInputButtonRef,
isDrawerOpen,
commentSelectorsProps,
showSelectors,
@ -388,7 +402,7 @@ function TextareaWrapper(wrapperProps: TextareaWrapperProps) {
return slimInput ? (
!isDrawerOpen ? (
<div role="button" onClick={toggleDrawer}>
<div ref={slimInputButtonRef} role="button" onClick={toggleDrawer}>
{children}
</div>
) : (

View file

@ -1,5 +1,4 @@
// @flow
import { useIsMobile } from 'effects/use-screensize';
import * as ICONS from 'constants/icons';
import React from 'react';
import TextField from '@mui/material/TextField';
@ -13,6 +12,7 @@ type Props = {
inputRef: any,
submitButtonRef?: any,
claimIsMine?: boolean,
slimInput?: boolean,
toggleSelectors: () => any,
handleTip: (isLBC: boolean) => void,
handleSubmit: () => any,
@ -27,19 +27,18 @@ const TextareaSuggestionsInput = (props: Props) => {
inputDefaultProps,
submitButtonRef,
claimIsMine,
slimInput,
toggleSelectors,
handleTip,
handleSubmit,
handlePreventClick,
} = props;
const isMobile = useIsMobile();
const { InputProps, disabled, fullWidth, id, inputProps: autocompleteInputProps } = params;
const inputProps = { ...autocompleteInputProps, ...inputDefaultProps };
const autocompleteProps = { InputProps, disabled, fullWidth, id, inputProps };
if (isMobile) {
if (slimInput) {
InputProps.startAdornment = (
<Button
icon={ICONS.STICKER}

View file

@ -59,6 +59,7 @@ type Props = {
autoFocus?: boolean,
submitButtonRef?: any,
claimIsMine?: boolean,
slimInput?: boolean,
doResolveUris: (uris: Array<string>, cache: boolean) => void,
doSetMentionSearchResults: (query: string, uris: Array<string>) => void,
onBlur: (any) => any,
@ -92,6 +93,7 @@ export default function TextareaWithSuggestions(props: Props) {
autoFocus,
submitButtonRef,
claimIsMine,
slimInput,
doResolveUris,
doSetMentionSearchResults,
onBlur,
@ -421,6 +423,7 @@ export default function TextareaWithSuggestions(props: Props) {
handlePreventClick={handlePreventClick}
submitButtonRef={submitButtonRef}
claimIsMine={claimIsMine}
slimInput={slimInput}
/>
)}
renderOption={(optionProps, option) => (

View file

@ -171,6 +171,10 @@
@media (max-width: $breakpoint-small) {
margin-top: var(--spacing-xxs);
> *:not(:last-child) {
margin-right: var(--spacing-xxs);
}
button {
height: 2rem;
padding: 0px var(--spacing-s);
@ -183,6 +187,10 @@
}
}
}
.button--link {
padding: 0px !important;
}
}
}