0b41fc041a
* [New Feature] Comment Emotes (#125) * Refactor form-field * Create new Emote Menu * Add Emotes * Add Emote Selector and Emote Comment creation ability * Fix and Split CSS * [New Feature] Stickers (#131) * Refactor filePrice * Refactor Wallet Tip Components * Add backend sticker support for comments * Add stickers * Refactor commentCreate * Add Sticker Selector and sticker comment creation * Add stickers display to comments and hyperchats * Fix wrong checks for total Super Chats * Stickers/emojis fall out / improvements (#220) * Fix error logs * Improve LBC sticker flow/clarity * Show inline error if custom sticker amount below min * Sort emojis alphabetically * Improve loading of Images * Improve quality and display of emojis and fix CSS * Display both USD and LBC prices * Default to LBC tip if creator can't receive USD * Don't clear text-field after sticker is sent * Refactor notification component * Handle notifications * Don't show profile pic on sticker livestream comments * Change Sticker icon * Fix wording and number rounding * Fix blurring emojis * Disable non functional emote buttons * new Stickers! (#248) * Add new stickers (#347) * Fix cancel sending sticker (#447) * Refactor scrollbar CSS for portal components outside of main Refactor channelMention suggestions into new textareaSuggestions component Install @mui/material packages Move channel mentioning to use @mui/Autocomplete combobox without search functionality Add support for suggesting Emotes while typing ':' Improve label to display matching term Add back and improved support for searching while mentioning Add support for suggesting emojis Fix non concatenated strings Add key to groups and options Fix dispatch props Fix Popper positioning to be consistent Fix and Improve searching Add back support for Winning Uri Filter default emojis with the same name as emotes Remove unused topSuggestion component Fix text color on darkmode Fix livestream updating state from both websocket and reducer and causing double of the same comments to appear Fix blur and focus commentCreate events Fix no name after @ error * desktop tweaks Co-authored-by: saltrafael <76502841+saltrafael@users.noreply.github.com> Co-authored-by: Thomas Zarebczan <tzarebczan@users.noreply.github.com> Co-authored-by: Rafael <rafael.saes@odysee.com>
680 lines
24 KiB
JavaScript
680 lines
24 KiB
JavaScript
// @flow
|
|
|
|
import 'scss/component/_comment-create.scss';
|
|
|
|
import { buildValidSticker } from 'util/comments';
|
|
import { FF_MAX_CHARS_IN_COMMENT } from 'constants/form-field';
|
|
import { FormField, Form } from 'component/common/form';
|
|
import { getChannelIdFromClaim } from 'util/claim';
|
|
import { Lbryio } from 'lbryinc';
|
|
import { useHistory } from 'react-router';
|
|
import * as ICONS from 'constants/icons';
|
|
import * as KEYCODES from 'constants/keycodes';
|
|
import * as PAGES from 'constants/pages';
|
|
import Button from 'component/button';
|
|
import ChannelThumbnail from 'component/channelThumbnail';
|
|
import classnames from 'classnames';
|
|
import CreditAmount from 'component/common/credit-amount';
|
|
import EmoteSelector from './emote-selector';
|
|
import Empty from 'component/common/empty';
|
|
import FilePrice from 'component/filePrice';
|
|
import I18nMessage from 'component/i18nMessage';
|
|
import Icon from 'component/common/icon';
|
|
import OptimizedImage from 'component/optimizedImage';
|
|
import React from 'react';
|
|
import SelectChannel from 'component/selectChannel';
|
|
import StickerSelector from './sticker-selector';
|
|
import type { ElementRef } from 'react';
|
|
import UriIndicator from 'component/uriIndicator';
|
|
import usePersistedState from 'effects/use-persisted-state';
|
|
import WalletTipAmountSelector from 'component/walletTipAmountSelector';
|
|
|
|
import { getStripeEnvironment } from 'util/stripe';
|
|
const stripeEnvironment = getStripeEnvironment();
|
|
|
|
const TAB_FIAT = 'TabFiat';
|
|
const TAB_LBC = 'TabLBC';
|
|
|
|
// for sendCashTip REMOVE
|
|
// type TipParams = { tipAmount: number, tipChannelName: string, channelClaimId: string };
|
|
// type UserParams = { activeChannelName: ?string, activeChannelId: ?string };
|
|
|
|
type Props = {
|
|
activeChannel: string,
|
|
activeChannelClaim: ?ChannelClaim,
|
|
bottom: boolean,
|
|
hasChannels: boolean,
|
|
claim: StreamClaim,
|
|
claimIsMine: boolean,
|
|
isFetchingChannels: boolean,
|
|
isNested: boolean,
|
|
isReply: boolean,
|
|
parentId: string,
|
|
settingsByChannelId: { [channelId: string]: PerChannelSettings },
|
|
shouldFetchComment: boolean,
|
|
supportDisabled: boolean,
|
|
uri: string,
|
|
createComment: (string, string, string, ?string, ?string, ?string, ?boolean) => Promise<any>,
|
|
doFetchCreatorSettings: (channelId: string) => Promise<any>,
|
|
doToast: ({ message: string }) => void,
|
|
fetchComment: (commentId: string) => Promise<any>,
|
|
onCancelReplying?: () => void,
|
|
onDoneReplying?: () => void,
|
|
sendTip: ({}, (any) => void, (any) => void) => void,
|
|
setQuickReply: (any) => void,
|
|
toast: (string) => void,
|
|
};
|
|
|
|
export function CommentCreate(props: Props) {
|
|
const {
|
|
activeChannelClaim,
|
|
bottom,
|
|
hasChannels,
|
|
claim,
|
|
claimIsMine,
|
|
isFetchingChannels,
|
|
isNested,
|
|
isReply,
|
|
parentId,
|
|
settingsByChannelId,
|
|
shouldFetchComment,
|
|
supportDisabled,
|
|
createComment,
|
|
doFetchCreatorSettings,
|
|
doToast,
|
|
fetchComment,
|
|
onCancelReplying,
|
|
onDoneReplying,
|
|
sendTip,
|
|
setQuickReply,
|
|
} = props;
|
|
|
|
const formFieldRef: ElementRef<any> = React.useRef();
|
|
const buttonRef: ElementRef<any> = React.useRef();
|
|
|
|
const {
|
|
push,
|
|
location: { pathname },
|
|
} = useHistory();
|
|
|
|
const [isSubmitting, setSubmitting] = React.useState(false);
|
|
const [commentFailure, setCommentFailure] = React.useState(false);
|
|
const [successTip, setSuccessTip] = React.useState({ txid: undefined, tipAmount: undefined });
|
|
const [isSupportComment, setIsSupportComment] = React.useState();
|
|
const [isReviewingSupportComment, setReviewingSupportComment] = React.useState();
|
|
const [isReviewingStickerComment, setReviewingStickerComment] = React.useState();
|
|
const [selectedSticker, setSelectedSticker] = React.useState();
|
|
const [tipAmount, setTipAmount] = React.useState(1);
|
|
const [convertedAmount, setConvertedAmount] = React.useState();
|
|
const [commentValue, setCommentValue] = React.useState('');
|
|
const [advancedEditor, setAdvancedEditor] = usePersistedState('comment-editor-mode', false);
|
|
const [stickerSelector, setStickerSelector] = React.useState();
|
|
const [activeTab, setActiveTab] = React.useState();
|
|
const [tipError, setTipError] = React.useState();
|
|
const [deletedComment, setDeletedComment] = React.useState(false);
|
|
const [showEmotes, setShowEmotes] = React.useState(false);
|
|
const [disableReviewButton, setDisableReviewButton] = React.useState();
|
|
const [exchangeRate, setExchangeRate] = React.useState();
|
|
const [canReceiveFiatTip, setCanReceiveFiatTip] = React.useState(undefined);
|
|
|
|
const claimId = claim && claim.claim_id;
|
|
const charCount = commentValue ? commentValue.length : 0;
|
|
const disabled = deletedComment || isSubmitting || isFetchingChannels || !commentValue.length;
|
|
const channelId = getChannelIdFromClaim(claim);
|
|
const channelSettings = channelId ? settingsByChannelId[channelId] : undefined;
|
|
const minSuper = (channelSettings && channelSettings.min_tip_amount_super_chat) || 0;
|
|
const minTip = (channelSettings && channelSettings.min_tip_amount_comment) || 0;
|
|
const minAmount = minTip || minSuper || 0;
|
|
const minAmountMet = minAmount === 0 || tipAmount >= minAmount;
|
|
const stickerPrice = selectedSticker && selectedSticker.price;
|
|
|
|
const minAmountRef = React.useRef(minAmount);
|
|
minAmountRef.current = minAmount;
|
|
|
|
// **************************************************************************
|
|
// Functions
|
|
// **************************************************************************
|
|
|
|
function handleSelectSticker(sticker: any) {
|
|
// $FlowFixMe
|
|
setSelectedSticker(sticker);
|
|
setReviewingStickerComment(true);
|
|
setTipAmount(sticker.price || 0);
|
|
setStickerSelector(false);
|
|
|
|
if (sticker.price && sticker.price > 0) {
|
|
setActiveTab(TAB_LBC);
|
|
setIsSupportComment(true);
|
|
}
|
|
}
|
|
|
|
function handleCommentChange(event) {
|
|
let commentValue;
|
|
if (isReply) {
|
|
commentValue = advancedEditor ? event : event.target.value;
|
|
} else {
|
|
commentValue = advancedEditor ? event : event.target.value;
|
|
}
|
|
|
|
setCommentValue(commentValue);
|
|
}
|
|
|
|
function altEnterListener(e: SyntheticKeyboardEvent<*>) {
|
|
if ((e.ctrlKey || e.metaKey) && e.keyCode === KEYCODES.ENTER) {
|
|
e.preventDefault();
|
|
buttonRef.current.click();
|
|
}
|
|
}
|
|
|
|
function onTextareaFocus() {
|
|
window.addEventListener('keydown', altEnterListener);
|
|
}
|
|
|
|
function onTextareaBlur() {
|
|
window.removeEventListener('keydown', altEnterListener);
|
|
}
|
|
|
|
function handleSupportComment() {
|
|
if (!activeChannelClaim) return;
|
|
|
|
if (!channelId) {
|
|
doToast({
|
|
message: __('Unable to verify channel settings. Try refreshing the page.'),
|
|
isError: true,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// if comment post didn't work, but tip was already made, try again to create comment
|
|
if (commentFailure && tipAmount === successTip.tipAmount) {
|
|
handleCreateComment(successTip.txid);
|
|
return;
|
|
} else {
|
|
setSuccessTip({ txid: undefined, tipAmount: undefined });
|
|
}
|
|
|
|
// !! Beware of stale closure when editing the then-block, including doSubmitTip().
|
|
doFetchCreatorSettings(channelId).then(() => {
|
|
const lockedMinAmount = minAmount; // value during closure.
|
|
const currentMinAmount = minAmountRef.current; // value from latest doFetchCreatorSettings().
|
|
|
|
if (lockedMinAmount !== currentMinAmount) {
|
|
doToast({
|
|
message: __('The creator just updated the minimum setting. Please revise or double-check your tip amount.'),
|
|
isError: true,
|
|
});
|
|
setReviewingSupportComment(false);
|
|
return;
|
|
}
|
|
|
|
doSubmitTip();
|
|
});
|
|
}
|
|
|
|
function doSubmitTip() {
|
|
if (!activeChannelClaim || isSubmitting) return;
|
|
|
|
setSubmitting(true);
|
|
|
|
const params = { amount: tipAmount, claim_id: claimId, channel_id: activeChannelClaim.claim_id };
|
|
// FIAT ONLY - REMOVE
|
|
// const activeChannelName = activeChannelClaim && activeChannelClaim.name;
|
|
// const activeChannelId = activeChannelClaim && activeChannelClaim.claim_id;
|
|
|
|
// setup variables for tip API
|
|
// const channelClaimId = claim.signing_channel ? claim.signing_channel.claim_id : claim.claim_id;
|
|
const tipChannelName = claim.signing_channel ? claim.signing_channel.name : claim.name;
|
|
|
|
if (activeTab === TAB_LBC) {
|
|
// call sendTip and then run the callback from the response
|
|
// second parameter is callback
|
|
sendTip(
|
|
params,
|
|
(response) => {
|
|
const { txid } = response;
|
|
// todo: why the setTimeout?
|
|
setTimeout(() => {
|
|
handleCreateComment(txid);
|
|
}, 1500);
|
|
|
|
doToast({
|
|
message: __("You sent %tipAmount% Credits as a tip to %tipChannelName%, I'm sure they appreciate it!", {
|
|
tipAmount: tipAmount, // force show decimal places
|
|
tipChannelName,
|
|
}),
|
|
});
|
|
|
|
setSuccessTip({ txid, tipAmount });
|
|
},
|
|
() => {
|
|
// reset the frontend so people can send a new comment
|
|
setSubmitting(false);
|
|
}
|
|
);
|
|
} else {
|
|
// No cash tips - REMOVE
|
|
// const tipParams: TipParams = { tipAmount: Math.round(tipAmount * 100) / 100, tipChannelName, channelClaimId };
|
|
// const userParams: UserParams = { activeChannelName, activeChannelId };
|
|
// sendCashTip(tipParams, userParams, claim.claim_id, stripeEnvironment, (customerTipResponse) => {
|
|
// const { payment_intent_id } = customerTipResponse;
|
|
//
|
|
// handleCreateComment(null, payment_intent_id, stripeEnvironment);
|
|
//
|
|
// setCommentValue('');
|
|
// setReviewingSupportComment(false);
|
|
// setIsSupportComment(false);
|
|
// setCommentFailure(false);
|
|
// setSubmitting(false);
|
|
// });
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} [txid] Optional transaction id generated by
|
|
* @param {string} [payment_intent_id] Optional payment_intent_id from Stripe payment
|
|
* @param {string} [environment] Optional environment for Stripe (test|live)
|
|
*/
|
|
function handleCreateComment(txid, payment_intent_id, environment) {
|
|
if (isSubmitting) return;
|
|
|
|
setShowEmotes(false);
|
|
setSubmitting(true);
|
|
|
|
const stickerValue = selectedSticker && buildValidSticker(selectedSticker.name);
|
|
|
|
createComment(stickerValue || commentValue, claimId, parentId, txid, payment_intent_id, environment, !!stickerValue)
|
|
.then((res) => {
|
|
setSubmitting(false);
|
|
if (setQuickReply) setQuickReply(res);
|
|
|
|
if (res && res.signature) {
|
|
if (!stickerValue) setCommentValue('');
|
|
setReviewingSupportComment(false);
|
|
setIsSupportComment(false);
|
|
setCommentFailure(false);
|
|
|
|
if (onDoneReplying) {
|
|
onDoneReplying();
|
|
}
|
|
}
|
|
})
|
|
.catch(() => {
|
|
setSubmitting(false);
|
|
setCommentFailure(true);
|
|
|
|
if (channelId) {
|
|
// It could be that the creator added a minimum tip setting.
|
|
// Manually update for now until a websocket msg is available.
|
|
doFetchCreatorSettings(channelId);
|
|
}
|
|
});
|
|
}
|
|
|
|
// **************************************************************************
|
|
// Effects
|
|
// **************************************************************************
|
|
|
|
// Fetch channel constraints if not already.
|
|
React.useEffect(() => {
|
|
if (!channelSettings && channelId) {
|
|
doFetchCreatorSettings(channelId);
|
|
}
|
|
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
// Notifications: Fetch top-level comments to identify if it has been deleted and can reply to it
|
|
React.useEffect(() => {
|
|
if (shouldFetchComment && fetchComment) {
|
|
fetchComment(parentId).then((result) => {
|
|
setDeletedComment(String(result).includes('Error'));
|
|
});
|
|
}
|
|
}, [fetchComment, shouldFetchComment, parentId]);
|
|
|
|
// Stickers: Get LBC-USD exchange rate if hasn't yet and selected a paid sticker
|
|
React.useEffect(() => {
|
|
if (stickerPrice && !exchangeRate) Lbryio.getExchangeRates().then(({ LBC_USD }) => setExchangeRate(LBC_USD));
|
|
}, [exchangeRate, stickerPrice]);
|
|
|
|
// 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 || !stickerSelector || canReceiveFiatTip !== undefined) return;
|
|
|
|
const channelClaimId = claim.signing_channel ? claim.signing_channel.claim_id : claim.claim_id;
|
|
const tipChannelName = claim.signing_channel ? claim.signing_channel.name : claim.name;
|
|
|
|
Lbryio.call(
|
|
'account',
|
|
'check',
|
|
{
|
|
channel_claim_id: channelClaimId,
|
|
channel_name: tipChannelName,
|
|
environment: stripeEnvironment,
|
|
},
|
|
'post'
|
|
)
|
|
.then((accountCheckResponse) => {
|
|
if (accountCheckResponse === true && canReceiveFiatTip !== true) {
|
|
setCanReceiveFiatTip(true);
|
|
} else {
|
|
setCanReceiveFiatTip(false);
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
}, [canReceiveFiatTip, claim.claim_id, claim.name, claim.signing_channel, stickerSelector]);
|
|
|
|
// LIVESTREAM ONLY - REMOVE
|
|
// Handle keyboard shortcut comment creation
|
|
// React.useEffect(() => {
|
|
// function altEnterListener(e: SyntheticKeyboardEvent<*>) {
|
|
// const inputRef = formFieldRef && formFieldRef.current && formFieldRef.current.input;
|
|
//
|
|
// if (inputRef && inputRef.current === document.activeElement) {
|
|
// // $FlowFixMe
|
|
// const isTyping = e.target.attributes['term'];
|
|
//
|
|
// if (((isLivestream && !isTyping) || e.ctrlKey || e.metaKey) && e.keyCode === KEYCODES.ENTER) {
|
|
// e.preventDefault();
|
|
// buttonRef.current.click();
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// window.addEventListener('keydown', altEnterListener);
|
|
//
|
|
// // removes the listener so it doesn't cause problems elsewhere in the app
|
|
// return () => {
|
|
// window.removeEventListener('keydown', altEnterListener);
|
|
// };
|
|
// }, [isLivestream]);
|
|
|
|
// **************************************************************************
|
|
// Render
|
|
// **************************************************************************
|
|
|
|
const getActionButton = (title: string, label?: string, icon: string, handleClick: () => void) => (
|
|
<Button title={title} label={label} button="alt" icon={icon} onClick={handleClick} />
|
|
);
|
|
|
|
if (channelSettings && !channelSettings.comments_enabled) {
|
|
return <Empty padded text={__('This channel has disabled comments on their page.')} />;
|
|
}
|
|
|
|
if (!isFetchingChannels && !hasChannels) {
|
|
return (
|
|
<div
|
|
role="button"
|
|
onClick={() => {
|
|
const pathPlusRedirect = `/$/${PAGES.CHANNEL_NEW}?redirect=${pathname}`;
|
|
push(pathPlusRedirect);
|
|
}}
|
|
>
|
|
<FormField type="textarea" name={'comment_signup_prompt'} placeholder={__('Say something about this...')} />
|
|
<div className="section__actions--no-margin">
|
|
<Button disabled button="primary" label={__('Post --[button to submit something]--')} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Form
|
|
onSubmit={() => {}}
|
|
className={classnames('commentCreate', {
|
|
'commentCreate--reply': isReply,
|
|
'commentCreate--nestedReply': isNested,
|
|
'commentCreate--bottom': bottom,
|
|
})}
|
|
>
|
|
{/* Input Box/Preview Box */}
|
|
{stickerSelector ? (
|
|
<StickerSelector onSelect={(sticker) => handleSelectSticker(sticker)} claimIsMine={claimIsMine} />
|
|
) : isReviewingStickerComment && activeChannelClaim && selectedSticker ? (
|
|
<div className="commentCreate__stickerPreview">
|
|
<div className="commentCreate__stickerPreviewInfo">
|
|
<ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} />
|
|
<UriIndicator uri={activeChannelClaim.canonical_url} link />
|
|
</div>
|
|
<div className="commentCreate__stickerPreviewImage">
|
|
<OptimizedImage src={selectedSticker && selectedSticker.url} waitLoad loading="lazy" />
|
|
</div>
|
|
{/* figure out lbc sticker prices */}
|
|
{selectedSticker.price && exchangeRate && (
|
|
<FilePrice
|
|
customPrices={{ priceFiat: selectedSticker.price, priceLBC: selectedSticker.price / exchangeRate }}
|
|
isFiat
|
|
/>
|
|
)}
|
|
</div>
|
|
) : isReviewingSupportComment && activeChannelClaim ? (
|
|
<div className="commentCreate__supportCommentPreview">
|
|
<CreditAmount
|
|
amount={tipAmount}
|
|
className="commentCreate__supportCommentPreviewAmount"
|
|
isFiat={activeTab === TAB_FIAT}
|
|
size={activeTab === TAB_LBC ? 18 : 2}
|
|
/>
|
|
<ChannelThumbnail xsmall uri={activeChannelClaim.canonical_url} />
|
|
<div className="commentCreate__supportCommentBody">
|
|
<UriIndicator uri={activeChannelClaim.canonical_url} link />
|
|
<div>{commentValue}</div>
|
|
</div>
|
|
</div>
|
|
) : (
|
|
<>
|
|
{showEmotes && (
|
|
<EmoteSelector
|
|
commentValue={commentValue}
|
|
setCommentValue={setCommentValue}
|
|
closeSelector={() => setShowEmotes(false)}
|
|
/>
|
|
)}
|
|
|
|
<FormField
|
|
autoFocus={isReply}
|
|
charCount={charCount}
|
|
className={isReply ? 'content_reply' : 'content_comment'}
|
|
disabled={isFetchingChannels}
|
|
label={
|
|
<div className="commentCreate__labelWrapper">
|
|
<span className="commentCreate__label">{(isReply ? __('Replying as') : __('Comment as')) + ' '}</span>
|
|
<SelectChannel tiny />
|
|
</div>
|
|
}
|
|
name={isReply ? 'content_reply' : 'content_description'}
|
|
quickActionLabel={isReply ? undefined : advancedEditor ? __('Simple Editor') : __('Advanced Editor')}
|
|
ref={formFieldRef}
|
|
onChange={handleCommentChange}
|
|
openEmoteMenu={() => setShowEmotes(!showEmotes)}
|
|
quickActionHandler={() => setAdvancedEditor(!advancedEditor)}
|
|
onFocus={onTextareaFocus}
|
|
onBlur={onTextareaBlur}
|
|
placeholder={__('Say something about this...')}
|
|
value={commentValue}
|
|
type={advancedEditor ? 'markdown' : 'textarea'}
|
|
textAreaMaxLength={FF_MAX_CHARS_IN_COMMENT}
|
|
/>
|
|
</>
|
|
)}
|
|
|
|
{(isSupportComment || (isReviewingStickerComment && stickerPrice)) && (
|
|
<WalletTipAmountSelector
|
|
activeTab={activeTab}
|
|
amount={tipAmount}
|
|
claim={claim}
|
|
convertedAmount={convertedAmount}
|
|
customTipAmount={stickerPrice}
|
|
exchangeRate={exchangeRate}
|
|
fiatConversion={selectedSticker && !!selectedSticker.price} // REMOVE / figure out
|
|
onChange={(amount) => setTipAmount(amount)}
|
|
setConvertedAmount={setConvertedAmount}
|
|
setDisableSubmitButton={setDisableReviewButton}
|
|
setTipError={setTipError}
|
|
tipError={tipError}
|
|
/>
|
|
)}
|
|
|
|
{/* Bottom Action Buttons */}
|
|
<div className="section__actions section__actions--no-margin">
|
|
{/* Submit Button */}
|
|
{isReviewingSupportComment ? (
|
|
<Button
|
|
autoFocus
|
|
button="primary"
|
|
disabled={disabled || !minAmountMet}
|
|
label={
|
|
isSubmitting
|
|
? __('Sending...')
|
|
: commentFailure && tipAmount === successTip.tipAmount
|
|
? __('Re-submit')
|
|
: __('Send')
|
|
}
|
|
onClick={handleSupportComment}
|
|
/>
|
|
) : isReviewingStickerComment && selectedSticker ? (
|
|
<Button
|
|
button="primary"
|
|
label={__('Send')}
|
|
disabled={isSupportComment && (tipError || disableReviewButton)}
|
|
onClick={() => {
|
|
if (isSupportComment) {
|
|
handleSupportComment();
|
|
} else {
|
|
handleCreateComment();
|
|
}
|
|
setSelectedSticker(null);
|
|
setReviewingStickerComment(false);
|
|
setStickerSelector(false);
|
|
setIsSupportComment(false);
|
|
}}
|
|
/>
|
|
) : isSupportComment ? (
|
|
<Button
|
|
disabled={disabled || tipError || disableReviewButton || !minAmountMet}
|
|
type="button"
|
|
button="primary"
|
|
icon={activeTab === TAB_LBC ? ICONS.LBC : ICONS.FINANCE} // only LBC
|
|
label={__('Review')}
|
|
onClick={() => setReviewingSupportComment(true)}
|
|
/>
|
|
) : (
|
|
(!minTip || claimIsMine) && (
|
|
<Button
|
|
ref={buttonRef}
|
|
button="primary"
|
|
disabled={disabled || stickerSelector}
|
|
type="submit"
|
|
label={
|
|
isReply
|
|
? isSubmitting
|
|
? __('Replying...')
|
|
: __('Reply')
|
|
: isSubmitting
|
|
? __('Commenting...')
|
|
: __('Comment --[button to submit something]--')
|
|
}
|
|
onClick={() => activeChannelClaim && commentValue.length && handleCreateComment()}
|
|
/>
|
|
)
|
|
)}
|
|
|
|
{/** Stickers/Support Buttons **/}
|
|
{!supportDisabled && !stickerSelector && (
|
|
<>
|
|
{getActionButton(
|
|
__('Stickers'),
|
|
isReviewingStickerComment ? __('Different Sticker') : undefined,
|
|
ICONS.STICKER,
|
|
() => {
|
|
if (isReviewingStickerComment) setReviewingStickerComment(false);
|
|
setIsSupportComment(false);
|
|
setStickerSelector(true);
|
|
}
|
|
)}
|
|
{/* below buttons are unnecessary - REMOVE */}
|
|
{!claimIsMine && (
|
|
<>
|
|
{(!isSupportComment || activeTab !== TAB_LBC) &&
|
|
getActionButton(
|
|
__('Credits'),
|
|
isSupportComment ? __('Switch to Credits') : undefined,
|
|
ICONS.LBC,
|
|
() => {
|
|
setIsSupportComment(true);
|
|
setActiveTab(TAB_LBC);
|
|
}
|
|
)}
|
|
|
|
{stripeEnvironment &&
|
|
(!isSupportComment || activeTab !== TAB_FIAT) &&
|
|
getActionButton(
|
|
__('Cash'),
|
|
isSupportComment ? __('Switch to Cash') : undefined,
|
|
ICONS.FINANCE,
|
|
() => {
|
|
setIsSupportComment(true);
|
|
setActiveTab(TAB_FIAT);
|
|
}
|
|
)}
|
|
</>
|
|
)}
|
|
</>
|
|
)}
|
|
|
|
{/* Cancel Button */}
|
|
{(isSupportComment ||
|
|
isReviewingSupportComment ||
|
|
stickerSelector ||
|
|
isReviewingStickerComment ||
|
|
(isReply && !minTip)) && (
|
|
<Button
|
|
disabled={isSupportComment && isSubmitting}
|
|
button="link"
|
|
label={__('Cancel')}
|
|
onClick={() => {
|
|
if (isSupportComment || isReviewingSupportComment) {
|
|
if (!isReviewingSupportComment) setIsSupportComment(false);
|
|
setReviewingSupportComment(false);
|
|
if (stickerPrice) {
|
|
setReviewingStickerComment(false);
|
|
setStickerSelector(false);
|
|
setSelectedSticker(null);
|
|
}
|
|
} else if (stickerSelector || isReviewingStickerComment) {
|
|
setReviewingStickerComment(false);
|
|
setStickerSelector(false);
|
|
setSelectedSticker(null);
|
|
} else if (isReply && !minTip && onCancelReplying) {
|
|
onCancelReplying();
|
|
}
|
|
}}
|
|
/>
|
|
)}
|
|
|
|
{/* Help Text */}
|
|
{deletedComment && <div className="error__text">{__('This comment has been deleted.')}</div>}
|
|
{!!minAmount && (
|
|
<div className="help--notice commentCreate__minAmountNotice">
|
|
<I18nMessage tokens={{ lbc: <CreditAmount noFormat amount={minAmount} /> }}>
|
|
{minTip ? 'Comment min: %lbc%' : minSuper ? 'HyperChat min: %lbc%' : ''}
|
|
</I18nMessage>
|
|
<Icon
|
|
customTooltipText={
|
|
minTip
|
|
? __('This channel requires a minimum tip for each comment.')
|
|
: minSuper
|
|
? __('This channel requires a minimum amount for HyperChats to be visible.')
|
|
: ''
|
|
}
|
|
className="icon--help"
|
|
icon={ICONS.HELP}
|
|
tooltip
|
|
size={16}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</Form>
|
|
);
|
|
}
|