From 0ebb9420efaef775080e63fbe4010ba091f326e5 Mon Sep 17 00:00:00 2001 From: infinite-persistence Date: Wed, 4 Aug 2021 16:54:20 +0800 Subject: [PATCH] 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. --- ui/component/commentCreate/view.jsx | 126 +++++++++++++++++++++++----- ui/scss/component/_comments.scss | 6 ++ 2 files changed, 111 insertions(+), 21 deletions(-) diff --git a/ui/component/commentCreate/view.jsx b/ui/component/commentCreate/view.jsx index 0d7646fc0..b6f02353f 100644 --- a/ui/component/commentCreate/view.jsx +++ b/ui/component/commentCreate/view.jsx @@ -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, 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 ? ( +
+ }}> + {minTip ? 'Comment min: %lbc%' : minSuper ? 'HyperChat min: %lbc%' : ''} + + +
+ ) : 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 ; } @@ -342,7 +422,7 @@ export function CommentCreate(props: Props) {