CommentCreate: handle minimum tips and hyperchat
To avoid calling `setting.Get` excessively, we'll fetch the latest settings one last time before sending a tip. We'll also fetch in several areas, like when a comment action fails (most likely creator just enforced a minimum). This will be easier when websocket send an update.
This commit is contained in:
parent
474da87c11
commit
0ebb9420ef
2 changed files with 111 additions and 21 deletions
|
@ -6,6 +6,7 @@ import * as ICONS from 'constants/icons';
|
|||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { FormField, Form } from 'component/common/form';
|
||||
import Icon from 'component/common/icon';
|
||||
import Button from 'component/button';
|
||||
import SelectChannel from 'component/selectChannel';
|
||||
import usePersistedState from 'effects/use-persisted-state';
|
||||
|
@ -14,10 +15,11 @@ import { useHistory } from 'react-router';
|
|||
import WalletTipAmountSelector from 'component/walletTipAmountSelector';
|
||||
import CreditAmount from 'component/common/credit-amount';
|
||||
import ChannelThumbnail from 'component/channelThumbnail';
|
||||
import I18nMessage from 'component/i18nMessage';
|
||||
import UriIndicator from 'component/uriIndicator';
|
||||
import Empty from 'component/common/empty';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
import { getChannelIdFromClaim } from 'util/claim';
|
||||
import { Lbryio } from 'lbryinc';
|
||||
|
||||
let stripeEnvironment = 'test';
|
||||
// if the key contains pk_live it's a live key
|
||||
|
@ -50,7 +52,7 @@ type Props = {
|
|||
sendTip: ({}, (any) => void, (any) => void) => void,
|
||||
doToast: ({ message: string }) => void,
|
||||
disabled: boolean,
|
||||
doFetchCreatorSettings: (channelId: string) => void,
|
||||
doFetchCreatorSettings: (channelId: string) => Promise<any>,
|
||||
settingsByChannelId: { [channelId: string]: PerChannelSettings },
|
||||
};
|
||||
|
||||
|
@ -97,6 +99,38 @@ export function CommentCreate(props: Props) {
|
|||
const [shouldDisableReviewButton, setShouldDisableReviewButton] = React.useState();
|
||||
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 minAmountRef = React.useRef(minAmount);
|
||||
minAmountRef.current = minAmount;
|
||||
|
||||
const MinAmountNotice = minAmount ? (
|
||||
<div className="help--notice comment--min-amount-notice">
|
||||
<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>
|
||||
) : null;
|
||||
|
||||
// **************************************************************************
|
||||
// Functions
|
||||
// **************************************************************************
|
||||
|
||||
function handleCommentChange(event) {
|
||||
let commentValue;
|
||||
|
@ -136,6 +170,14 @@ export function CommentCreate(props: Props) {
|
|||
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);
|
||||
|
@ -144,6 +186,29 @@ export function CommentCreate(props: Props) {
|
|||
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,
|
||||
});
|
||||
setIsReviewingSupportComment(false);
|
||||
return;
|
||||
}
|
||||
|
||||
doSubmitTip();
|
||||
});
|
||||
}
|
||||
|
||||
function doSubmitTip() {
|
||||
if (!activeChannelClaim) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
amount: tipAmount,
|
||||
claim_id: claimId,
|
||||
|
@ -273,6 +338,12 @@ export function CommentCreate(props: Props) {
|
|||
.catch(() => {
|
||||
setIsSubmitting(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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -280,12 +351,21 @@ export function CommentCreate(props: Props) {
|
|||
setAdvancedEditor(!advancedEditor);
|
||||
}
|
||||
|
||||
// **************************************************************************
|
||||
// Effects
|
||||
// **************************************************************************
|
||||
|
||||
// Fetch channel constraints if not already.
|
||||
React.useEffect(() => {
|
||||
if (!channelSettings && channelId) {
|
||||
doFetchCreatorSettings(channelId);
|
||||
}
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
// **************************************************************************
|
||||
// Render
|
||||
// **************************************************************************
|
||||
|
||||
if (channelSettings && !channelSettings.comments_enabled) {
|
||||
return <Empty padded text={__('This channel has disabled comments on their page.')} />;
|
||||
}
|
||||
|
@ -342,7 +422,7 @@ export function CommentCreate(props: Props) {
|
|||
<Button
|
||||
autoFocus
|
||||
button="primary"
|
||||
disabled={disabled}
|
||||
disabled={disabled || !minAmountMet}
|
||||
label={
|
||||
isSubmitting
|
||||
? __('Sending...')
|
||||
|
@ -358,6 +438,7 @@ export function CommentCreate(props: Props) {
|
|||
label={__('Cancel')}
|
||||
onClick={() => setIsReviewingSupportComment(false)}
|
||||
/>
|
||||
{MinAmountNotice}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -411,7 +492,7 @@ export function CommentCreate(props: Props) {
|
|||
{isSupportComment ? (
|
||||
<>
|
||||
<Button
|
||||
disabled={disabled || tipError || shouldDisableReviewButton}
|
||||
disabled={disabled || tipError || shouldDisableReviewButton || !minAmountMet}
|
||||
type="button"
|
||||
button="primary"
|
||||
icon={activeTab === TAB_LBC ? ICONS.LBC : ICONS.FINANCE}
|
||||
|
@ -423,22 +504,24 @@ export function CommentCreate(props: Props) {
|
|||
</>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
ref={buttonRef}
|
||||
button="primary"
|
||||
disabled={disabled}
|
||||
type="submit"
|
||||
label={
|
||||
isReply
|
||||
? isSubmitting
|
||||
? __('Replying...')
|
||||
: __('Reply')
|
||||
: isSubmitting
|
||||
? __('Commenting...')
|
||||
: __('Comment --[button to submit something]--')
|
||||
}
|
||||
requiresAuth={IS_WEB}
|
||||
/>
|
||||
{(!minTip || claimIsMine) && (
|
||||
<Button
|
||||
ref={buttonRef}
|
||||
button="primary"
|
||||
disabled={disabled}
|
||||
type="submit"
|
||||
label={
|
||||
isReply
|
||||
? isSubmitting
|
||||
? __('Replying...')
|
||||
: __('Reply')
|
||||
: isSubmitting
|
||||
? __('Commenting...')
|
||||
: __('Comment --[button to submit something]--')
|
||||
}
|
||||
requiresAuth={IS_WEB}
|
||||
/>
|
||||
)}
|
||||
{!claimIsMine && (
|
||||
<Button
|
||||
disabled={disabled}
|
||||
|
@ -463,7 +546,7 @@ export function CommentCreate(props: Props) {
|
|||
}}
|
||||
/>
|
||||
)}
|
||||
{isReply && (
|
||||
{isReply && !minTip && (
|
||||
<Button
|
||||
button="link"
|
||||
label={__('Cancel')}
|
||||
|
@ -476,6 +559,7 @@ export function CommentCreate(props: Props) {
|
|||
)}
|
||||
</>
|
||||
)}
|
||||
{MinAmountNotice}
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
|
|
|
@ -438,3 +438,9 @@ $thumbnailWidthSmall: 1rem;
|
|||
.comment--blocked {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.comment--min-amount-notice {
|
||||
.icon {
|
||||
margin-bottom: -3px; // TODO fix few instances of these (find "-2px")
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue